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 | } |