* bug & patch: exit codes from internal commands are handled incorrectly
@ 2014-12-16 19:28 Kenneth Lorber
2014-12-18 2:15 ` Kenneth Lorber
0 siblings, 1 reply; 8+ messages in thread
From: Kenneth Lorber @ 2014-12-16 19:28 UTC (permalink / raw)
To: git; +Cc: Kenneth Lorber
(Apologies if I’ve missed anything here - I’m still climbing the git learning curve.)
Bug: exit codes from (at least) internal commands are handled incorrectly.
E.g. git-merge-file, docs say:
The exit value of this program is negative on error, and the number of
conflicts otherwise. If the merge was clean, the exit value is 0.
But only 8 bits get carried through exit, so 256 conflicts gives exit(0), which means the merge was clean.
Issue shows up on:
git version 1.8.5.2 (Apple Git-48)
build from source (git version 2.2.0.68.g64396d6.dirty after patch below applied)
Reproduce by:
Put the following test program in an empty directory as buggen.pl
TEST PROGRAM START
open OUTB, ">basefile" or die;
print OUTB "this is the base file\n";
close OUTB;
open OUT1, ">bfile1" or die;
open OUT2, ">bfile2" or die;
$c = shift;
while($c > 0){
print OUT1 "a\nb\nc\nd\nchange $c file 1\n";
print OUT2 "a\nb\nc\nd\nchange $c file 2\n";
$c--;
}
TEST PROGRAM END
Do these tests:
perl buggen.pl 0
git merge-file -p bfile1 basefile bfile2
echo $status
0
perl buggen.pl 1
git merge-file -p bfile1 basefile bfile2
echo $status
1
perl buggen.pl 256
git merge-file -p bfile1 basefile bfile2
echo $status
0 <===OOPS
Proposed patches:
diff --git a/git.c b/git.c
index 82d7a1c..8228a3c 100644
--- a/git.c
+++ b/git.c
@@ -349,6 +349,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const
trace_argv_printf(argv, "trace: built-in: git");
status = p->fn(argc, argv, prefix);
+ if (status > 255)
+ status = 255; /* prevent exit() from truncating to 0 */
if (status)
return status;
diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt
index d2fc12e..76e6a11 100644
--- a/Documentation/git-merge-file.txt
+++ b/Documentation/git-merge-file.txt
@@ -41,7 +41,8 @@ lines from `<other-file>`, or lines from both respectively. T
conflict markers can be given with the `--marker-size` option.
The exit value of this program is negative on error, and the number of
-conflicts otherwise. If the merge was clean, the exit value is 0.
+conflicts otherwise (but 255 will be reported even if more than 255 conflicts
+exist). If the merge was clean, the exit value is 0.
'git merge-file' is designed to be a minimal clone of RCS 'merge'; that is, it
implements all of RCS 'merge''s functionality which is needed by
Open questions:
1) Is 255 safe for all operating systems?
2) Does this issue affect any other places?
Thanks,
Keni
keni@his.com
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: bug & patch: exit codes from internal commands are handled incorrectly 2014-12-16 19:28 bug & patch: exit codes from internal commands are handled incorrectly Kenneth Lorber @ 2014-12-18 2:15 ` Kenneth Lorber 2014-12-18 17:43 ` Torsten Bögershausen 2014-12-18 19:18 ` Junio C Hamano 0 siblings, 2 replies; 8+ messages in thread From: Kenneth Lorber @ 2014-12-18 2:15 UTC (permalink / raw) To: git; +Cc: Kenneth Lorber The situation is actually slightly more complex than I stated previously. From the docs: The exit value of this program is negative on error, But there’s no such thing as a negative error code under Unix, so (at best) that will be exit(255). No patch, because this is getting painfully close to needing someone with a global view of the code to fix. Thanks, Keni On Dec 16, 2014, at 2:28 PM, Kenneth Lorber <keni@his.com> wrote: > (Apologies if I’ve missed anything here - I’m still climbing the git learning curve.) > > Bug: exit codes from (at least) internal commands are handled incorrectly. > E.g. git-merge-file, docs say: > The exit value of this program is negative on error, and the number of > conflicts otherwise. If the merge was clean, the exit value is 0. > But only 8 bits get carried through exit, so 256 conflicts gives exit(0), which means the merge was clean. > > Issue shows up on: > git version 1.8.5.2 (Apple Git-48) > build from source (git version 2.2.0.68.g64396d6.dirty after patch below applied) > > Reproduce by: > > Put the following test program in an empty directory as buggen.pl > > TEST PROGRAM START > open OUTB, ">basefile" or die; > print OUTB "this is the base file\n"; > close OUTB; > > open OUT1, ">bfile1" or die; > open OUT2, ">bfile2" or die; > > $c = shift; > > while($c > 0){ > print OUT1 "a\nb\nc\nd\nchange $c file 1\n"; > print OUT2 "a\nb\nc\nd\nchange $c file 2\n"; > $c--; > } > TEST PROGRAM END > > Do these tests: > > perl buggen.pl 0 > git merge-file -p bfile1 basefile bfile2 > echo $status > 0 > > perl buggen.pl 1 > git merge-file -p bfile1 basefile bfile2 > echo $status > 1 > > perl buggen.pl 256 > git merge-file -p bfile1 basefile bfile2 > echo $status > 0 <===OOPS > > Proposed patches: > diff --git a/git.c b/git.c > index 82d7a1c..8228a3c 100644 > --- a/git.c > +++ b/git.c > @@ -349,6 +349,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const > trace_argv_printf(argv, "trace: built-in: git"); > > status = p->fn(argc, argv, prefix); > + if (status > 255) > + status = 255; /* prevent exit() from truncating to 0 */ > if (status) > return status; > diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt > index d2fc12e..76e6a11 100644 > --- a/Documentation/git-merge-file.txt > +++ b/Documentation/git-merge-file.txt > @@ -41,7 +41,8 @@ lines from `<other-file>`, or lines from both respectively. T > conflict markers can be given with the `--marker-size` option. > > The exit value of this program is negative on error, and the number of > -conflicts otherwise. If the merge was clean, the exit value is 0. > +conflicts otherwise (but 255 will be reported even if more than 255 conflicts > +exist). If the merge was clean, the exit value is 0. > > 'git merge-file' is designed to be a minimal clone of RCS 'merge'; that is, it > implements all of RCS 'merge''s functionality which is needed by > > Open questions: > 1) Is 255 safe for all operating systems? > 2) Does this issue affect any other places? > > Thanks, > Keni > keni@his.com > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: bug & patch: exit codes from internal commands are handled incorrectly 2014-12-18 2:15 ` Kenneth Lorber @ 2014-12-18 17:43 ` Torsten Bögershausen 2014-12-18 19:18 ` Junio C Hamano 1 sibling, 0 replies; 8+ messages in thread From: Torsten Bögershausen @ 2014-12-18 17:43 UTC (permalink / raw) To: Kenneth Lorber, git On 18.12.14 03:15, Kenneth Lorber wrote: > The situation is actually slightly more complex than I stated previously. From the docs: > The exit value of this program is negative on error, > But there’s no such thing as a negative error code under Unix, so (at best) that will be exit(255). > > No patch, because this is getting painfully close to needing someone with a global view of the code to fix. > > Thanks, > Keni > My spontanous question: Would it be save to clamp at 127 ? >> + if (status > 127) >> + status = 127; /* prevent exit() from truncating to 0 or becoming negative */ (And the rest looked good enough to become a patch, or at least to start a wider discussion) ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: bug & patch: exit codes from internal commands are handled incorrectly 2014-12-18 2:15 ` Kenneth Lorber 2014-12-18 17:43 ` Torsten Bögershausen @ 2014-12-18 19:18 ` Junio C Hamano 2014-12-20 12:39 ` Kenneth Lorber 2015-02-01 22:32 ` Kenneth Lorber 1 sibling, 2 replies; 8+ messages in thread From: Junio C Hamano @ 2014-12-18 19:18 UTC (permalink / raw) To: Kenneth Lorber; +Cc: git Kenneth Lorber <keni@his.com> writes: >> Bug: exit codes from (at least) internal commands are handled incorrectly. >> E.g. git-merge-file, docs say: >> The exit value of this program is negative on error, and the number of >> conflicts otherwise. If the merge was clean, the exit value is 0. >> But only 8 bits get carried through exit, so 256 conflicts gives >> exit(0), which means the merge was clean. Wouldn't any cmd_foo() that returns negative to main() be buggy? Your change sweeps such problems under the rug, which is not a healthy thing to do. Expecting that the exit code can signal small positive integers and other generic kinds of failures is a losing proposition. I think it is a better fix to update cmd_merge_file() to return 1 (when ret is positive), 0 (when ret is zero) or 128 (when ret is negative), or something simple like that, and update the documentation to match that, without touching git.c::main(). Among the in-tree users, I notice git-cvsserver.perl is already using the command incorrectly. It does this: my $return = system("git", "merge-file", $file_local, $file_old, $file_new); $return >>= 8; cleanupTmpDir(); if ( $return == 0 ) { $log->info("Merged successfully"); ... } elsif ( $return == 1 ) { $log->info("Merged with conflicts"); ... } else { $log->warn("Merge failed"); next; } which assumes $return == 1 is special "half-good", which is not consistent with the documented interface. It will incorrectly say "Merge failed" when there are two or more conflicts. And with such a "1 or 0 or -1" change, you will fix that caller as well ;-) ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: bug & patch: exit codes from internal commands are handled incorrectly 2014-12-18 19:18 ` Junio C Hamano @ 2014-12-20 12:39 ` Kenneth Lorber 2015-02-01 22:32 ` Kenneth Lorber 1 sibling, 0 replies; 8+ messages in thread From: Kenneth Lorber @ 2014-12-20 12:39 UTC (permalink / raw) To: Junio C Hamano; +Cc: git On Dec 18, 2014, at 2:18 PM, Junio C Hamano <gitster@pobox.com> wrote: > Kenneth Lorber <keni@his.com> writes: > >>> Bug: exit codes from (at least) internal commands are handled incorrectly. >>> E.g. git-merge-file, docs say: >>> The exit value of this program is negative on error, and the number of >>> conflicts otherwise. If the merge was clean, the exit value is 0. >>> But only 8 bits get carried through exit, so 256 conflicts gives >>> exit(0), which means the merge was clean. > > Wouldn't any cmd_foo() that returns negative to main() be buggy? Absolutely. > Your change sweeps such problems under the rug, which is not a > healthy thing to do. True. But as I don’t know the codebase it seemed the safe thing to do at least to prove the bug existed before filing a bug report. > Expecting that the exit code can signal small positive integers and > other generic kinds of failures is a losing proposition. I think it > is a better fix to update cmd_merge_file() to return 1 (when ret is > positive), 0 (when ret is zero) or 128 (when ret is negative), or > something simple like that, and update the documentation to match > that, without touching git.c::main(). I agree. It does leave open the question of whether this bit of information is of any use and should/could be reported out in another way. It’s not to me, so I won’t be proposing anything to address that. > Among the in-tree users, I notice git-cvsserver.perl is already > using the command incorrectly. It does this: > > my $return = system("git", "merge-file", $file_local, $file_old, $file_new); > $return >>= 8; > > cleanupTmpDir(); > > if ( $return == 0 ) > { > $log->info("Merged successfully"); > ... > } > elsif ( $return == 1 ) > { > $log->info("Merged with conflicts"); > ... > } > else > { > $log->warn("Merge failed"); > next; > } > > which assumes $return == 1 is special "half-good", which is not > consistent with the documented interface. It will incorrectly > say "Merge failed" when there are two or more conflicts. > > And with such a "1 or 0 or -1" change, you will fix that caller as > well ;-) Yay! :-) Thanks, Keni ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: bug & patch: exit codes from internal commands are handled incorrectly 2014-12-18 19:18 ` Junio C Hamano 2014-12-20 12:39 ` Kenneth Lorber @ 2015-02-01 22:32 ` Kenneth Lorber 2015-04-01 0:10 ` Kenneth Lorber 1 sibling, 1 reply; 8+ messages in thread From: Kenneth Lorber @ 2015-02-01 22:32 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Kenneth Lorber [-- Attachment #1: Type: text/plain, Size: 2727 bytes --] On Dec 18, 2014, at 2:18 PM, Junio C Hamano <gitster@pobox.com> wrote: > Kenneth Lorber <keni@his.com> writes: > >>> Bug: exit codes from (at least) internal commands are handled incorrectly. >>> E.g. git-merge-file, docs say: >>> The exit value of this program is negative on error, and the number of >>> conflicts otherwise. If the merge was clean, the exit value is 0. >>> But only 8 bits get carried through exit, so 256 conflicts gives >>> exit(0), which means the merge was clean. > > Wouldn't any cmd_foo() that returns negative to main() be buggy? Yes. > > Your change sweeps such problems under the rug, which is not a > healthy thing to do. Agreed. (See below.) > > Expecting that the exit code can signal small positive integers and > other generic kinds of failures is a losing proposition. I think it > is a better fix to update cmd_merge_file() to return 1 (when ret is > positive), 0 (when ret is zero) or 128 (when ret is negative), or > something simple like that, and update the documentation to match > that, without touching git.c::main(). The new patch uses 0, 1, and 2 to match diff(1). > Among the in-tree users, I notice git-cvsserver.perl is already > using the command incorrectly. It does this: > > my $return = system("git", "merge-file", $file_local, $file_old, $file_new); > $return >>= 8; > > cleanupTmpDir(); > > if ( $return == 0 ) > { > $log->info("Merged successfully"); > ... > } > elsif ( $return == 1 ) > { > $log->info("Merged with conflicts"); > ... > } > else > { > $log->warn("Merge failed"); > next; > } > > which assumes $return == 1 is special "half-good", which is not > consistent with the documented interface. It will incorrectly > say "Merge failed" when there are two or more conflicts. > > And with such a "1 or 0 or -1" change, you will fix that caller as > well ;-) I'll call that a win. The attached patch covers the following: - fixes all places where "make test" attempts to call exit() with a value <0 or >255 - changes git-merge-file.txt to reflect the change in exit codes - fixes the exit codes for merge-file - adds a warning (which should probably be changed to something clearer) if git.c:run_builtin() is going to cause an out-of-bounds exit - fixes a typo in t7007-show.sh - replaces return(0) with exit(0) in test-parse-options.c The diff is cut against 15598cf41beed0d86cd2ac443e0f69c5a3b40321 (2.3.0-rc2) Thanks, Keni [-- Attachment #2: d2.ship --] [-- Type: application/octet-stream, Size: 8475 bytes --] diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt index d2fc12e..425dba3 100644 --- a/Documentation/git-merge-file.txt +++ b/Documentation/git-merge-file.txt @@ -40,8 +40,8 @@ however, these conflicts are resolved favouring lines from `<current-file>`, lines from `<other-file>`, or lines from both respectively. The length of the conflict markers can be given with the `--marker-size` option. -The exit value of this program is negative on error, and the number of -conflicts otherwise. If the merge was clean, the exit value is 0. +The exit value of this program is 0 if the merge was clean, 1 if there were +conflicts, and 2 if an error occured. 'git merge-file' is designed to be a minimal clone of RCS 'merge'; that is, it implements all of RCS 'merge''s functionality which is needed by diff --git a/builtin/branch.c b/builtin/branch.c index dc6f0b2..e586846 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -938,10 +938,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix) strbuf_release(&branch_ref); if (!argc) - return error(_("No commit on branch '%s' yet."), + return -error(_("No commit on branch '%s' yet."), branch_name); else - return error(_("No branch named '%s'."), + return -error(_("No branch named '%s'."), branch_name); } strbuf_release(&branch_ref); diff --git a/builtin/check-attr.c b/builtin/check-attr.c index 5600ec3..62cacf3 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -169,7 +169,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix) name = argv[i]; a = git_attr(name); if (!a) - return error("%s: not a valid attribute name", + return -error("%s: not a valid attribute name", name); check[i].attr = a; } diff --git a/builtin/config.c b/builtin/config.c index 15a7bea..23aab25 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -667,7 +667,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) ret = git_config_rename_section_in_file(given_config_source.file, argv[0], argv[1]); if (ret < 0) - return ret; + return -ret; if (ret == 0) die("No such section!"); } @@ -678,7 +678,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) ret = git_config_rename_section_in_file(given_config_source.file, argv[0], NULL); if (ret < 0) - return ret; + return -ret; if (ret == 0) die("No such section!"); } diff --git a/builtin/log.c b/builtin/log.c index 923ffe7..cb6914b 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -561,7 +561,7 @@ int cmd_show(int argc, const char **argv, const char *prefix) break; o = parse_object(t->tagged->sha1); if (!o) - ret = error(_("Could not read object %s"), + ret = -error(_("Could not read object %s"), sha1_to_hex(t->tagged->sha1)); objects[i].item = o; i--; @@ -585,7 +585,7 @@ int cmd_show(int argc, const char **argv, const char *prefix) ret = cmd_log_walk(&rev); break; default: - ret = error(_("Unknown type: %d"), o->type); + ret = -error(_("Unknown type: %d"), o->type); } } free(objects); diff --git a/builtin/merge-file.c b/builtin/merge-file.c index 844f84f..8dfb42c 100644 --- a/builtin/merge-file.c +++ b/builtin/merge-file.c @@ -61,9 +61,11 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) if (argc != 3) usage_with_options(merge_file_usage, options); if (quiet) { - if (!freopen("/dev/null", "w", stderr)) - return error("failed to redirect stderr to /dev/null: " + if (!freopen("/dev/null", "w", stderr)) { + error("failed to redirect stderr to /dev/null: " "%s", strerror(errno)); + return 2; + } } if (prefix) @@ -74,10 +76,12 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) if (!names[i]) names[i] = argv[i]; if (read_mmfile(mmfs + i, fname)) - return -1; - if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size)) - return error("Cannot merge binary files: %s", + return 2; + if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size)) { + error("Cannot merge binary files: %s", argv[i]); + return 2; + } } xmp.ancestor = names[1]; @@ -100,7 +104,11 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) else if (fclose(f)) ret = error("Could not close %s", filename); free(result.ptr); + + if (ret == -1) return 2; /* error */ + if (ret == 0) return 0; /* no conflicts */ + return 1; /* conflicts */ } - return ret; + return 2; /* error */ } diff --git a/builtin/replace.c b/builtin/replace.c index 85d39b5..5ff7ee1 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -299,7 +299,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw) free(tmpfile); if (!hashcmp(old, new)) - return error("new object is the same as the old one: '%s'", sha1_to_hex(old)); + return -error("new object is the same as the old one: '%s'", sha1_to_hex(old)); return replace_object_sha1(object_ref, old, "replacement", new, force); } @@ -410,7 +410,7 @@ static int create_graft(int argc, const char **argv, int force) strbuf_release(&buf); if (!hashcmp(old, new)) - return error("new commit is the same as the old one: '%s'", sha1_to_hex(old)); + return -error("new commit is the same as the old one: '%s'", sha1_to_hex(old)); return replace_object_sha1(old_ref, old, "replacement", new, force); } diff --git a/builtin/send-pack.c b/builtin/send-pack.c index b564a77..7b7f6cd 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -277,7 +277,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) /* match them up */ if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags)) - return -1; + return 1; if (!is_empty_cas(&cas)) apply_push_cas(&cas, remote, remote_refs); @@ -307,5 +307,5 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) if (!ret && !transport_refs_pushed(remote_refs)) fprintf(stderr, "Everything up-to-date\n"); - return ret; + return (ret<0) ? -ret : ret; } diff --git a/git.c b/git.c index 6b5ae6a..b6a75e9 100644 --- a/git.c +++ b/git.c @@ -346,6 +346,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) trace_argv_printf(argv, "trace: built-in: git"); status = p->fn(argc, argv, prefix); + if(status < 0 || status >255) + warning("internal bad status (no effect on the git command)"); if (status) return status; diff --git a/run-command.c b/run-command.c index 0b432cc..353acc8 100644 --- a/run-command.c +++ b/run-command.c @@ -567,6 +567,14 @@ int run_command(struct child_process *cmd) return finish_command(cmd); } +int run_command2(struct child_process *cmd) +{ + int code = start_command(cmd); + if (code) + return code<0 ? -code : code; + return finish_command(cmd); +} + int run_command_v_opt(const char **argv, int opt) { return run_command_v_opt_cd_env(argv, opt, NULL, NULL); diff --git a/run-command.h b/run-command.h index d6868dc..afa0212 100644 --- a/run-command.h +++ b/run-command.h @@ -51,6 +51,7 @@ void child_process_init(struct child_process *); int start_command(struct child_process *); int finish_command(struct child_process *); int run_command(struct child_process *); +int run_command2(struct child_process *); extern char *find_hook(const char *name); LAST_ARG_MUST_BE_NULL diff --git a/t/t7007-show.sh b/t/t7007-show.sh index 1b824fe..e7272bb 100755 --- a/t/t7007-show.sh +++ b/t/t7007-show.sh @@ -13,7 +13,7 @@ test_expect_success setup ' rm -f .git/objects/$HH/$H38 ' -test_expect_success 'showing a tag that point at a missing object' ' +test_expect_success 'showing a tag that points at a missing object' ' test_must_fail git --no-pager show foo-tag ' diff --git a/test-parse-options.c b/test-parse-options.c index 5dabce6..8dba84f 100644 --- a/test-parse-options.c +++ b/test-parse-options.c @@ -97,5 +97,5 @@ int main(int argc, char **argv) for (i = 0; i < argc; i++) printf("arg %02d: %s\n", i, argv[i]); - return 0; + exit(0); } diff --git a/test-run-command.c b/test-run-command.c index 89c7de2..4d8c230 100644 --- a/test-run-command.c +++ b/test-run-command.c @@ -28,7 +28,7 @@ int main(int argc, char **argv) return 1; } if (!strcmp(argv[1], "run-command")) - exit(run_command(&proc)); + exit(run_command2(&proc)); fprintf(stderr, "check usage\n"); return 1; [-- Attachment #3: Type: text/plain, Size: 2 bytes --] ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: bug & patch: exit codes from internal commands are handled incorrectly 2015-02-01 22:32 ` Kenneth Lorber @ 2015-04-01 0:10 ` Kenneth Lorber 2015-04-01 0:40 ` Junio C Hamano 0 siblings, 1 reply; 8+ messages in thread From: Kenneth Lorber @ 2015-04-01 0:10 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Kenneth Lorber Ping? The original version of this got some discussion, but this version - nothing. Thanks, Keni On Feb 1, 2015, at 5:32 PM, Kenneth Lorber <keni@his.com> wrote: > > On Dec 18, 2014, at 2:18 PM, Junio C Hamano <gitster@pobox.com> wrote: > >> Kenneth Lorber <keni@his.com> writes: >> >>>> Bug: exit codes from (at least) internal commands are handled incorrectly. >>>> E.g. git-merge-file, docs say: >>>> The exit value of this program is negative on error, and the number of >>>> conflicts otherwise. If the merge was clean, the exit value is 0. >>>> But only 8 bits get carried through exit, so 256 conflicts gives >>>> exit(0), which means the merge was clean. >> >> Wouldn't any cmd_foo() that returns negative to main() be buggy? > > Yes. > >> >> Your change sweeps such problems under the rug, which is not a >> healthy thing to do. > > Agreed. (See below.) > >> >> Expecting that the exit code can signal small positive integers and >> other generic kinds of failures is a losing proposition. I think it >> is a better fix to update cmd_merge_file() to return 1 (when ret is >> positive), 0 (when ret is zero) or 128 (when ret is negative), or >> something simple like that, and update the documentation to match >> that, without touching git.c::main(). > > The new patch uses 0, 1, and 2 to match diff(1). > >> Among the in-tree users, I notice git-cvsserver.perl is already >> using the command incorrectly. It does this: >> >> my $return = system("git", "merge-file", $file_local, $file_old, $file_new); >> $return >>= 8; >> >> cleanupTmpDir(); >> >> if ( $return == 0 ) >> { >> $log->info("Merged successfully"); >> ... >> } >> elsif ( $return == 1 ) >> { >> $log->info("Merged with conflicts"); >> ... >> } >> else >> { >> $log->warn("Merge failed"); >> next; >> } >> >> which assumes $return == 1 is special "half-good", which is not >> consistent with the documented interface. It will incorrectly >> say "Merge failed" when there are two or more conflicts. >> >> And with such a "1 or 0 or -1" change, you will fix that caller as >> well ;-) > > I'll call that a win. > > The attached patch covers the following: > - fixes all places where "make test" attempts to call exit() with a value <0 or >255 > - changes git-merge-file.txt to reflect the change in exit codes > - fixes the exit codes for merge-file > - adds a warning (which should probably be changed to something clearer) if git.c:run_builtin() is going to cause an out-of-bounds exit > - fixes a typo in t7007-show.sh > - replaces return(0) with exit(0) in test-parse-options.c > > The diff is cut against 15598cf41beed0d86cd2ac443e0f69c5a3b40321 (2.3.0-rc2) > > Thanks, > Keni > > > <d2.ship> > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: bug & patch: exit codes from internal commands are handled incorrectly 2015-04-01 0:10 ` Kenneth Lorber @ 2015-04-01 0:40 ` Junio C Hamano 0 siblings, 0 replies; 8+ messages in thread From: Junio C Hamano @ 2015-04-01 0:40 UTC (permalink / raw) To: Kenneth Lorber; +Cc: Git Mailing List On Tue, Mar 31, 2015 at 5:10 PM, Kenneth Lorber <keni@his.com> wrote: > Ping? The original version of this got some discussion, but this version - nothing. Pong? I do not know what you meant by "this version". Have you followed Documentaiton/SubmittingPatches? Otherwise the mailing list may have dropped the message. ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2015-04-01 0:40 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-12-16 19:28 bug & patch: exit codes from internal commands are handled incorrectly Kenneth Lorber 2014-12-18 2:15 ` Kenneth Lorber 2014-12-18 17:43 ` Torsten Bögershausen 2014-12-18 19:18 ` Junio C Hamano 2014-12-20 12:39 ` Kenneth Lorber 2015-02-01 22:32 ` Kenneth Lorber 2015-04-01 0:10 ` Kenneth Lorber 2015-04-01 0:40 ` Junio C Hamano
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).