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