Commit 7d8abfcb50a33aed369bbd267852cf04009c49e9
Committed by
Anthony Liguori
1 parent
9c4bab26
qemu-io: fix memory leak
qemu-io leaks the request buffer whenever the read or write function isn't executed completely down the "normal" code path. [hch: also fix the aio and vectored variants the same way] Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
Showing
1 changed file
with
38 additions
and
22 deletions
qemu-io.c
| @@ -358,7 +358,7 @@ read_f(int argc, char **argv) | @@ -358,7 +358,7 @@ read_f(int argc, char **argv) | ||
| 358 | 358 | ||
| 359 | if (cnt < 0) { | 359 | if (cnt < 0) { |
| 360 | printf("read failed: %s\n", strerror(-cnt)); | 360 | printf("read failed: %s\n", strerror(-cnt)); |
| 361 | - return 0; | 361 | + goto out; |
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | if (Pflag) { | 364 | if (Pflag) { |
| @@ -373,7 +373,7 @@ read_f(int argc, char **argv) | @@ -373,7 +373,7 @@ read_f(int argc, char **argv) | ||
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | if (qflag) | 375 | if (qflag) |
| 376 | - return 0; | 376 | + goto out; |
| 377 | 377 | ||
| 378 | if (vflag) | 378 | if (vflag) |
| 379 | dump_buffer(buf, offset, count); | 379 | dump_buffer(buf, offset, count); |
| @@ -382,6 +382,7 @@ read_f(int argc, char **argv) | @@ -382,6 +382,7 @@ read_f(int argc, char **argv) | ||
| 382 | t2 = tsub(t2, t1); | 382 | t2 = tsub(t2, t1); |
| 383 | print_report("read", &t2, offset, count, total, cnt, Cflag); | 383 | print_report("read", &t2, offset, count, total, cnt, Cflag); |
| 384 | 384 | ||
| 385 | +out: | ||
| 385 | qemu_io_free(buf); | 386 | qemu_io_free(buf); |
| 386 | 387 | ||
| 387 | return 0; | 388 | return 0; |
| @@ -480,7 +481,7 @@ readv_f(int argc, char **argv) | @@ -480,7 +481,7 @@ readv_f(int argc, char **argv) | ||
| 480 | 481 | ||
| 481 | if (cnt < 0) { | 482 | if (cnt < 0) { |
| 482 | printf("readv failed: %s\n", strerror(-cnt)); | 483 | printf("readv failed: %s\n", strerror(-cnt)); |
| 483 | - return 0; | 484 | + goto out; |
| 484 | } | 485 | } |
| 485 | 486 | ||
| 486 | if (Pflag) { | 487 | if (Pflag) { |
| @@ -495,7 +496,7 @@ readv_f(int argc, char **argv) | @@ -495,7 +496,7 @@ readv_f(int argc, char **argv) | ||
| 495 | } | 496 | } |
| 496 | 497 | ||
| 497 | if (qflag) | 498 | if (qflag) |
| 498 | - return 0; | 499 | + goto out; |
| 499 | 500 | ||
| 500 | if (vflag) | 501 | if (vflag) |
| 501 | dump_buffer(buf, offset, qiov.size); | 502 | dump_buffer(buf, offset, qiov.size); |
| @@ -504,8 +505,8 @@ readv_f(int argc, char **argv) | @@ -504,8 +505,8 @@ readv_f(int argc, char **argv) | ||
| 504 | t2 = tsub(t2, t1); | 505 | t2 = tsub(t2, t1); |
| 505 | print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); | 506 | print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); |
| 506 | 507 | ||
| 508 | +out: | ||
| 507 | qemu_io_free(buf); | 509 | qemu_io_free(buf); |
| 508 | - | ||
| 509 | return 0; | 510 | return 0; |
| 510 | } | 511 | } |
| 511 | 512 | ||
| @@ -613,16 +614,17 @@ write_f(int argc, char **argv) | @@ -613,16 +614,17 @@ write_f(int argc, char **argv) | ||
| 613 | 614 | ||
| 614 | if (cnt < 0) { | 615 | if (cnt < 0) { |
| 615 | printf("write failed: %s\n", strerror(-cnt)); | 616 | printf("write failed: %s\n", strerror(-cnt)); |
| 616 | - return 0; | 617 | + goto out; |
| 617 | } | 618 | } |
| 618 | 619 | ||
| 619 | if (qflag) | 620 | if (qflag) |
| 620 | - return 0; | 621 | + goto out; |
| 621 | 622 | ||
| 622 | /* Finally, report back -- -C gives a parsable format */ | 623 | /* Finally, report back -- -C gives a parsable format */ |
| 623 | t2 = tsub(t2, t1); | 624 | t2 = tsub(t2, t1); |
| 624 | print_report("wrote", &t2, offset, count, total, cnt, Cflag); | 625 | print_report("wrote", &t2, offset, count, total, cnt, Cflag); |
| 625 | 626 | ||
| 627 | +out: | ||
| 626 | qemu_io_free(buf); | 628 | qemu_io_free(buf); |
| 627 | 629 | ||
| 628 | return 0; | 630 | return 0; |
| @@ -713,18 +715,17 @@ writev_f(int argc, char **argv) | @@ -713,18 +715,17 @@ writev_f(int argc, char **argv) | ||
| 713 | 715 | ||
| 714 | if (cnt < 0) { | 716 | if (cnt < 0) { |
| 715 | printf("writev failed: %s\n", strerror(-cnt)); | 717 | printf("writev failed: %s\n", strerror(-cnt)); |
| 716 | - return 0; | 718 | + goto out; |
| 717 | } | 719 | } |
| 718 | 720 | ||
| 719 | if (qflag) | 721 | if (qflag) |
| 720 | - return 0; | 722 | + goto out; |
| 721 | 723 | ||
| 722 | /* Finally, report back -- -C gives a parsable format */ | 724 | /* Finally, report back -- -C gives a parsable format */ |
| 723 | t2 = tsub(t2, t1); | 725 | t2 = tsub(t2, t1); |
| 724 | print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); | 726 | print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); |
| 725 | - | 727 | +out: |
| 726 | qemu_io_free(buf); | 728 | qemu_io_free(buf); |
| 727 | - | ||
| 728 | return 0; | 729 | return 0; |
| 729 | } | 730 | } |
| 730 | 731 | ||
| @@ -761,18 +762,18 @@ aio_write_done(void *opaque, int ret) | @@ -761,18 +762,18 @@ aio_write_done(void *opaque, int ret) | ||
| 761 | 762 | ||
| 762 | if (ret < 0) { | 763 | if (ret < 0) { |
| 763 | printf("aio_write failed: %s\n", strerror(-ret)); | 764 | printf("aio_write failed: %s\n", strerror(-ret)); |
| 764 | - return; | 765 | + goto out; |
| 765 | } | 766 | } |
| 766 | 767 | ||
| 767 | if (ctx->qflag) { | 768 | if (ctx->qflag) { |
| 768 | - return; | 769 | + goto out; |
| 769 | } | 770 | } |
| 770 | 771 | ||
| 771 | /* Finally, report back -- -C gives a parsable format */ | 772 | /* Finally, report back -- -C gives a parsable format */ |
| 772 | t2 = tsub(t2, ctx->t1); | 773 | t2 = tsub(t2, ctx->t1); |
| 773 | print_report("wrote", &t2, ctx->offset, ctx->qiov.size, | 774 | print_report("wrote", &t2, ctx->offset, ctx->qiov.size, |
| 774 | ctx->qiov.size, 1, ctx->Cflag); | 775 | ctx->qiov.size, 1, ctx->Cflag); |
| 775 | - | 776 | +out: |
| 776 | qemu_io_free(ctx->buf); | 777 | qemu_io_free(ctx->buf); |
| 777 | free(ctx); | 778 | free(ctx); |
| 778 | } | 779 | } |
| @@ -789,7 +790,7 @@ aio_read_done(void *opaque, int ret) | @@ -789,7 +790,7 @@ aio_read_done(void *opaque, int ret) | ||
| 789 | 790 | ||
| 790 | if (ret < 0) { | 791 | if (ret < 0) { |
| 791 | printf("readv failed: %s\n", strerror(-ret)); | 792 | printf("readv failed: %s\n", strerror(-ret)); |
| 792 | - return; | 793 | + goto out; |
| 793 | } | 794 | } |
| 794 | 795 | ||
| 795 | if (ctx->Pflag) { | 796 | if (ctx->Pflag) { |
| @@ -805,7 +806,7 @@ aio_read_done(void *opaque, int ret) | @@ -805,7 +806,7 @@ aio_read_done(void *opaque, int ret) | ||
| 805 | } | 806 | } |
| 806 | 807 | ||
| 807 | if (ctx->qflag) { | 808 | if (ctx->qflag) { |
| 808 | - return; | 809 | + goto out; |
| 809 | } | 810 | } |
| 810 | 811 | ||
| 811 | if (ctx->vflag) { | 812 | if (ctx->vflag) { |
| @@ -816,7 +817,7 @@ aio_read_done(void *opaque, int ret) | @@ -816,7 +817,7 @@ aio_read_done(void *opaque, int ret) | ||
| 816 | t2 = tsub(t2, ctx->t1); | 817 | t2 = tsub(t2, ctx->t1); |
| 817 | print_report("read", &t2, ctx->offset, ctx->qiov.size, | 818 | print_report("read", &t2, ctx->offset, ctx->qiov.size, |
| 818 | ctx->qiov.size, 1, ctx->Cflag); | 819 | ctx->qiov.size, 1, ctx->Cflag); |
| 819 | - | 820 | +out: |
| 820 | qemu_io_free(ctx->buf); | 821 | qemu_io_free(ctx->buf); |
| 821 | free(ctx); | 822 | free(ctx); |
| 822 | } | 823 | } |
| @@ -865,17 +866,20 @@ aio_read_f(int argc, char **argv) | @@ -865,17 +866,20 @@ aio_read_f(int argc, char **argv) | ||
| 865 | ctx->vflag = 1; | 866 | ctx->vflag = 1; |
| 866 | break; | 867 | break; |
| 867 | default: | 868 | default: |
| 869 | + free(ctx); | ||
| 868 | return command_usage(&aio_read_cmd); | 870 | return command_usage(&aio_read_cmd); |
| 869 | } | 871 | } |
| 870 | } | 872 | } |
| 871 | 873 | ||
| 872 | - if (optind > argc - 2) | 874 | + if (optind > argc - 2) { |
| 875 | + free(ctx); | ||
| 873 | return command_usage(&aio_read_cmd); | 876 | return command_usage(&aio_read_cmd); |
| 874 | - | 877 | + } |
| 875 | 878 | ||
| 876 | ctx->offset = cvtnum(argv[optind]); | 879 | ctx->offset = cvtnum(argv[optind]); |
| 877 | if (ctx->offset < 0) { | 880 | if (ctx->offset < 0) { |
| 878 | printf("non-numeric length argument -- %s\n", argv[optind]); | 881 | printf("non-numeric length argument -- %s\n", argv[optind]); |
| 882 | + free(ctx); | ||
| 879 | return 0; | 883 | return 0; |
| 880 | } | 884 | } |
| 881 | optind++; | 885 | optind++; |
| @@ -883,6 +887,7 @@ aio_read_f(int argc, char **argv) | @@ -883,6 +887,7 @@ aio_read_f(int argc, char **argv) | ||
| 883 | if (ctx->offset & 0x1ff) { | 887 | if (ctx->offset & 0x1ff) { |
| 884 | printf("offset %lld is not sector aligned\n", | 888 | printf("offset %lld is not sector aligned\n", |
| 885 | (long long)ctx->offset); | 889 | (long long)ctx->offset); |
| 890 | + free(ctx); | ||
| 886 | return 0; | 891 | return 0; |
| 887 | } | 892 | } |
| 888 | 893 | ||
| @@ -892,8 +897,11 @@ aio_read_f(int argc, char **argv) | @@ -892,8 +897,11 @@ aio_read_f(int argc, char **argv) | ||
| 892 | gettimeofday(&ctx->t1, NULL); | 897 | gettimeofday(&ctx->t1, NULL); |
| 893 | acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, | 898 | acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, |
| 894 | ctx->qiov.size >> 9, aio_read_done, ctx); | 899 | ctx->qiov.size >> 9, aio_read_done, ctx); |
| 895 | - if (!acb) | 900 | + if (!acb) { |
| 901 | + free(ctx->buf); | ||
| 902 | + free(ctx); | ||
| 896 | return -EIO; | 903 | return -EIO; |
| 904 | + } | ||
| 897 | 905 | ||
| 898 | return 0; | 906 | return 0; |
| 899 | } | 907 | } |
| @@ -952,16 +960,20 @@ aio_write_f(int argc, char **argv) | @@ -952,16 +960,20 @@ aio_write_f(int argc, char **argv) | ||
| 952 | pattern = atoi(optarg); | 960 | pattern = atoi(optarg); |
| 953 | break; | 961 | break; |
| 954 | default: | 962 | default: |
| 963 | + free(ctx); | ||
| 955 | return command_usage(&aio_write_cmd); | 964 | return command_usage(&aio_write_cmd); |
| 956 | } | 965 | } |
| 957 | } | 966 | } |
| 958 | 967 | ||
| 959 | - if (optind > argc - 2) | 968 | + if (optind > argc - 2) { |
| 969 | + free(ctx); | ||
| 960 | return command_usage(&aio_write_cmd); | 970 | return command_usage(&aio_write_cmd); |
| 971 | + } | ||
| 961 | 972 | ||
| 962 | ctx->offset = cvtnum(argv[optind]); | 973 | ctx->offset = cvtnum(argv[optind]); |
| 963 | if (ctx->offset < 0) { | 974 | if (ctx->offset < 0) { |
| 964 | printf("non-numeric length argument -- %s\n", argv[optind]); | 975 | printf("non-numeric length argument -- %s\n", argv[optind]); |
| 976 | + free(ctx); | ||
| 965 | return 0; | 977 | return 0; |
| 966 | } | 978 | } |
| 967 | optind++; | 979 | optind++; |
| @@ -969,6 +981,7 @@ aio_write_f(int argc, char **argv) | @@ -969,6 +981,7 @@ aio_write_f(int argc, char **argv) | ||
| 969 | if (ctx->offset & 0x1ff) { | 981 | if (ctx->offset & 0x1ff) { |
| 970 | printf("offset %lld is not sector aligned\n", | 982 | printf("offset %lld is not sector aligned\n", |
| 971 | (long long)ctx->offset); | 983 | (long long)ctx->offset); |
| 984 | + free(ctx); | ||
| 972 | return 0; | 985 | return 0; |
| 973 | } | 986 | } |
| 974 | 987 | ||
| @@ -978,8 +991,11 @@ aio_write_f(int argc, char **argv) | @@ -978,8 +991,11 @@ aio_write_f(int argc, char **argv) | ||
| 978 | gettimeofday(&ctx->t1, NULL); | 991 | gettimeofday(&ctx->t1, NULL); |
| 979 | acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, | 992 | acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, |
| 980 | ctx->qiov.size >> 9, aio_write_done, ctx); | 993 | ctx->qiov.size >> 9, aio_write_done, ctx); |
| 981 | - if (!acb) | 994 | + if (!acb) { |
| 995 | + free(ctx->buf); | ||
| 996 | + free(ctx); | ||
| 982 | return -EIO; | 997 | return -EIO; |
| 998 | + } | ||
| 983 | 999 | ||
| 984 | return 0; | 1000 | return 0; |
| 985 | } | 1001 | } |