commit e8bfb8f3994fa8096bf56db895d969b4961f8b4b from: Stefan Sperling date: Fri Dec 18 15:52:25 2020 UTC fix path existence check in got_object_tree_path_changed() A symptom of this was a segfault in 'got blame distrib/miniroot/install.sub' with the OpenBSD src.git from github, reported by jrick. The problem was that the commit graph traversed one commit too far. This could be more easily reproduced with 'got log': got log -c 05f568 -P distrib/miniroot/install.sub Which listed two commits instead of just the first one: 05f568ecc6aadefa1aff9064a29e798874a71409 <-- install.sub first created here 7c0d87f00e480cdf004324dad6f3e6f4418f8f42 "distrib/miniroot" exists in 7c0d87f00e480cdf004324... but not in the parent of this commit. Ensure that we traverse the full path in tree1 even if an intermediate tree2 cannot be opened. Instead of reporting success and a file change if we can't traverse further through tree2, we now hit this failing attempt to open the file 'install.sub' in tree object 180aa33df8d1 (tree1): te1 = find_entry_by_name(tree1, seg, seglen); if (te1 == NULL) { err = got_error(GOT_ERR_NO_OBJ); goto done; } fix tested and ok jrick commit - a4153d5b903b1fe20edad776a6d0ec3c3cbcc0aa commit + e8bfb8f3994fa8096bf56db895d969b4961f8b4b blob - 7c0aac05143e35448209231ec4347e3ad6e2252b blob + 7bd55922b5b83ac06fbadac4c69364802b1a6179 --- lib/object.c +++ lib/object.c @@ -1768,25 +1768,24 @@ got_object_tree_path_changed(int *changed, te1 = find_entry_by_name(tree1, seg, seglen); if (te1 == NULL) { err = got_error(GOT_ERR_NO_OBJ); - goto done; - } - - te2 = find_entry_by_name(tree2, seg, seglen); - if (te2 == NULL) { - *changed = 1; goto done; } - mode1 = normalize_mode_for_comparison(te1->mode); - mode2 = normalize_mode_for_comparison(te2->mode); - if (mode1 != mode2) { - *changed = 1; - goto done; - } + if (tree2) + te2 = find_entry_by_name(tree2, seg, seglen); - if (got_object_id_cmp(&te1->id, &te2->id) == 0) { - *changed = 0; - goto done; + if (te2) { + mode1 = normalize_mode_for_comparison(te1->mode); + mode2 = normalize_mode_for_comparison(te2->mode); + if (mode1 != mode2) { + *changed = 1; + goto done; + } + + if (got_object_id_cmp(&te1->id, &te2->id) == 0) { + *changed = 0; + goto done; + } } if (*s == '\0') { /* final path element */ @@ -1807,14 +1806,20 @@ got_object_tree_path_changed(int *changed, got_object_tree_close(tree1); tree1 = next_tree1; - err = got_object_open_as_tree(&next_tree2, repo, - &te2->id); - te2 = NULL; - if (err) - goto done; - if (tree2 != tree02) - got_object_tree_close(tree2); - tree2 = next_tree2; + if (te2) { + err = got_object_open_as_tree(&next_tree2, repo, + &te2->id); + te2 = NULL; + if (err) + goto done; + if (tree2 != tree02) + got_object_tree_close(tree2); + tree2 = next_tree2; + } else if (tree2) { + if (tree2 != tree02) + got_object_tree_close(tree2); + tree2 = NULL; + } } } done: