Git fork

cat-file: fix a common "struct object_context" memory leak

Fix a memory leak where "cat-file" will leak the "path" member. See
e5fba602e59 (textconv: support for cat_file, 2010-06-15) for the code
that introduced the offending get_oid_with_context() call (called
get_sha1_with_context() at the time).

As a result we can mark several tests as passing with SANITIZE=leak
using "TEST_PASSES_SANITIZE_LEAK=true".

As noted in dc944b65f1d (get_sha1_with_context: dynamically allocate
oc->path, 2017-05-19) callers must free the "path" member. That same
commit added the relevant free() to this function, but we weren't
catching cases where we'd return early.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Ævar Arnfjörð Bjarmason and committed by
Junio C Hamano
27472b51 55916bba

+37 -14
+22 -10
builtin/cat-file.c
··· 71 static int cat_one_file(int opt, const char *exp_type, const char *obj_name, 72 int unknown_type) 73 { 74 struct object_id oid; 75 enum object_type type; 76 char *buf; ··· 106 if (sb.len) { 107 printf("%s\n", sb.buf); 108 strbuf_release(&sb); 109 - return 0; 110 } 111 break; 112 ··· 115 if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0) 116 die("git cat-file: could not get object info"); 117 printf("%"PRIuMAX"\n", (uintmax_t)size); 118 - return 0; 119 120 case 'e': 121 return !has_object_file(&oid); ··· 123 case 'w': 124 125 if (filter_object(path, obj_context.mode, 126 - &oid, &buf, &size)) 127 - return -1; 128 break; 129 130 case 'c': ··· 143 const char *ls_args[3] = { NULL }; 144 ls_args[0] = "ls-tree"; 145 ls_args[1] = obj_name; 146 - return cmd_ls_tree(2, ls_args, NULL); 147 } 148 149 - if (type == OBJ_BLOB) 150 - return stream_blob(&oid); 151 buf = read_object_file(&oid, &type, &size); 152 if (!buf) 153 die("Cannot read object %s", obj_name); ··· 172 } else 173 oidcpy(&blob_oid, &oid); 174 175 - if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB) 176 - return stream_blob(&blob_oid); 177 /* 178 * we attempted to dereference a tag to a blob 179 * and failed; there may be new dereference ··· 193 die("git cat-file %s: bad file", obj_name); 194 195 write_or_die(1, buf, size); 196 free(buf); 197 free(obj_context.path); 198 - return 0; 199 } 200 201 struct expand_data {
··· 71 static int cat_one_file(int opt, const char *exp_type, const char *obj_name, 72 int unknown_type) 73 { 74 + int ret; 75 struct object_id oid; 76 enum object_type type; 77 char *buf; ··· 107 if (sb.len) { 108 printf("%s\n", sb.buf); 109 strbuf_release(&sb); 110 + ret = 0; 111 + goto cleanup; 112 } 113 break; 114 ··· 117 if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0) 118 die("git cat-file: could not get object info"); 119 printf("%"PRIuMAX"\n", (uintmax_t)size); 120 + ret = 0; 121 + goto cleanup; 122 123 case 'e': 124 return !has_object_file(&oid); ··· 126 case 'w': 127 128 if (filter_object(path, obj_context.mode, 129 + &oid, &buf, &size)) { 130 + ret = -1; 131 + goto cleanup; 132 + } 133 break; 134 135 case 'c': ··· 148 const char *ls_args[3] = { NULL }; 149 ls_args[0] = "ls-tree"; 150 ls_args[1] = obj_name; 151 + ret = cmd_ls_tree(2, ls_args, NULL); 152 + goto cleanup; 153 } 154 155 + if (type == OBJ_BLOB) { 156 + ret = stream_blob(&oid); 157 + goto cleanup; 158 + } 159 buf = read_object_file(&oid, &type, &size); 160 if (!buf) 161 die("Cannot read object %s", obj_name); ··· 180 } else 181 oidcpy(&blob_oid, &oid); 182 183 + if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB) { 184 + ret = stream_blob(&blob_oid); 185 + goto cleanup; 186 + } 187 /* 188 * we attempted to dereference a tag to a blob 189 * and failed; there may be new dereference ··· 203 die("git cat-file %s: bad file", obj_name); 204 205 write_or_die(1, buf, size); 206 + ret = 0; 207 + cleanup: 208 free(buf); 209 free(obj_context.path); 210 + return ret; 211 } 212 213 struct expand_data {
+1
t/t0028-working-tree-encoding.sh
··· 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 8 . ./test-lib.sh 9 . "$TEST_DIRECTORY/lib-encoding.sh" 10
··· 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 8 + TEST_PASSES_SANITIZE_LEAK=true 9 . ./test-lib.sh 10 . "$TEST_DIRECTORY/lib-encoding.sh" 11
+2
t/t1051-large-conversion.sh
··· 1 #!/bin/sh 2 3 test_description='test conversion filters on large files' 4 . ./test-lib.sh 5 6 set_attr() {
··· 1 #!/bin/sh 2 3 test_description='test conversion filters on large files' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 6 . ./test-lib.sh 7 8 set_attr() {
+1
t/t3304-notes-mixed.sh
··· 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 8 . ./test-lib.sh 9 10 number_of_commits=100
··· 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 8 + TEST_PASSES_SANITIZE_LEAK=true 9 . ./test-lib.sh 10 11 number_of_commits=100
+2
t/t4044-diff-index-unique-abbrev.sh
··· 1 #!/bin/sh 2 3 test_description='test unique sha1 abbreviation on "index from..to" line' 4 . ./test-lib.sh 5 6 test_expect_success 'setup' '
··· 1 #!/bin/sh 2 3 test_description='test unique sha1 abbreviation on "index from..to" line' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 6 . ./test-lib.sh 7 8 test_expect_success 'setup' '
+1
t/t4140-apply-ita.sh
··· 2 3 test_description='git apply of i-t-a file' 4 5 . ./test-lib.sh 6 7 test_expect_success setup '
··· 2 3 test_description='git apply of i-t-a file' 4 5 + TEST_PASSES_SANITIZE_LEAK=true 6 . ./test-lib.sh 7 8 test_expect_success setup '
+2 -2
t/t5314-pack-cycle-detection.sh
··· 49 will always find a delta for "file", because its lookup will always come 50 immediately after the lookup for "dummy". 51 ' 52 - . ./test-lib.sh 53 - 54 55 56 # Create a pack containing the tree $1 and blob $1:file, with 57 # the latter stored as a delta against $2:file.
··· 49 will always find a delta for "file", because its lookup will always come 50 immediately after the lookup for "dummy". 51 ' 52 53 + TEST_PASSES_SANITIZE_LEAK=true 54 + . ./test-lib.sh 55 56 # Create a pack containing the tree $1 and blob $1:file, with 57 # the latter stored as a delta against $2:file.
+1
t/t6422-merge-rename-corner-cases.sh
··· 6 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 7 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 8 9 . ./test-lib.sh 10 . "$TEST_DIRECTORY"/lib-merge.sh 11
··· 6 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 7 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 8 9 + TEST_PASSES_SANITIZE_LEAK=true 10 . ./test-lib.sh 11 . "$TEST_DIRECTORY"/lib-merge.sh 12
+2
t/t8007-cat-file-textconv.sh
··· 1 #!/bin/sh 2 3 test_description='git cat-file textconv support' 4 . ./test-lib.sh 5 6 cat >helper <<'EOF'
··· 1 #!/bin/sh 2 3 test_description='git cat-file textconv support' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 6 . ./test-lib.sh 7 8 cat >helper <<'EOF'
+2
t/t8010-cat-file-filters.sh
··· 1 #!/bin/sh 2 3 test_description='git cat-file filters support' 4 . ./test-lib.sh 5 6 test_expect_success 'setup ' '
··· 1 #!/bin/sh 2 3 test_description='git cat-file filters support' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 6 . ./test-lib.sh 7 8 test_expect_success 'setup ' '
-1
t/t9104-git-svn-follow-parent.sh
··· 5 6 test_description='git svn fetching' 7 8 - TEST_FAILS_SANITIZE_LEAK=true 9 . ./lib-git-svn.sh 10 11 test_expect_success 'initialize repo' '
··· 5 6 test_description='git svn fetching' 7 8 . ./lib-git-svn.sh 9 10 test_expect_success 'initialize repo' '
-1
t/t9132-git-svn-broken-symlink.sh
··· 2 3 test_description='test that git handles an svn repository with empty symlinks' 4 5 - TEST_FAILS_SANITIZE_LEAK=true 6 . ./lib-git-svn.sh 7 test_expect_success 'load svn dumpfile' ' 8 svnadmin load "$rawsvnrepo" <<EOF
··· 2 3 test_description='test that git handles an svn repository with empty symlinks' 4 5 . ./lib-git-svn.sh 6 test_expect_success 'load svn dumpfile' ' 7 svnadmin load "$rawsvnrepo" <<EOF
+1
t/t9301-fast-import-notes.sh
··· 7 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 8 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 9 10 . ./test-lib.sh 11 12
··· 7 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 8 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 9 10 + TEST_PASSES_SANITIZE_LEAK=true 11 . ./test-lib.sh 12 13