fsck: handle NULL return of lookup_blob() and lookup_tree()

lookup_blob() and lookup_tree() can return NULL if they find an object of an unexpected type. Accessing the object member is undefined in that case. Cast the result to a struct object pointer instead; we can do that because object is the first member of all object types. This trick is already used in other places in the code. An error message is already shown by object_as_type(), which is called by the lookup functions. The walk callback functions are expected to handle NULL object pointers passed to them, but put_object_name() needs a valid object, so avoid calling it without one. Suggested-by: SZEDER Gábor <szeder.dev@gmail.com> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

René Scharfe committed Oct 5, 2017 at 21:41 UTC 2720f6db5d35fece41190b93a1eba76d2f64f490
2 files changed +26 -4
fsck.c
+4 -4
@@ -358,15 +358,15 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
358 continue;
359
360 if (S_ISDIR(entry.mode)) {
361 - obj = &lookup_tree(entry.oid)->object;
362 - if (name)
361 + obj = (struct object *)lookup_tree(entry.oid);
362 + if (name && obj)
363 put_object_name(options, obj, "%s%s/", name,
364 entry.path);
365 result = options->walk(obj, OBJ_TREE, data, options);
366 }
367 else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
368 - obj = &lookup_blob(entry.oid)->object;
369 - if (name)
368 + obj = (struct object *)lookup_blob(entry.oid);
369 + if (name && obj)
370 put_object_name(options, obj, "%s%s", name,
371 entry.path);
372 result = options->walk(obj, OBJ_BLOB, data, options);
t/t1450-fsck.sh
+22
@@ -222,6 +222,28 @@ test_expect_success 'unparseable tree object' '
222 test_i18ngrep ! "fatal: empty filename in tree entry" out
223 '
224
225 +hex2oct() {
226 + perl -ne 'printf "\\%03o", hex for /../g'
227 +}
228 +
229 +test_expect_success 'tree entry with type mismatch' '
230 + test_when_finished "remove_object \$blob" &&
231 + test_when_finished "remove_object \$tree" &&
232 + test_when_finished "remove_object \$commit" &&
233 + test_when_finished "git update-ref -d refs/heads/type_mismatch" &&
234 + blob=$(echo blob | git hash-object -w --stdin) &&
235 + blob_bin=$(echo $blob | hex2oct) &&
236 + tree=$(
237 + printf "40000 dir\0${blob_bin}100644 file\0${blob_bin}" |
238 + git hash-object -t tree --stdin -w --literally
239 + ) &&
240 + commit=$(git commit-tree $tree) &&
241 + git update-ref refs/heads/type_mismatch $commit &&
242 + test_must_fail git fsck >out 2>&1 &&
243 + test_i18ngrep "is a blob, not a tree" out &&
244 + test_i18ngrep ! "dangling blob" out
245 +'
246 +
247 test_expect_success 'tag pointing to nonexistent' '
248 cat >invalid-tag <<-\EOF &&
249 object ffffffffffffffffffffffffffffffffffffffff