* [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation
@ 2016-04-14 18:07 Junio C Hamano
2016-04-14 18:07 ` [PATCH 2/2] fsck: detect and warn a commit with embedded NUL Junio C Hamano
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Junio C Hamano @ 2016-04-14 18:07 UTC (permalink / raw)
To: git
The pattern taken by all the validations in this function is:
if (notice a violation exists) {
err = report(... VIOLATION_KIND ...);
if (err)
return err;
}
where report() returns zero if specified kind of violation is set to
be ignored, and otherwise shows an error message and returns non-zero.
The last validation in the function immediately after the function
returns 0 to declare "all good" can cheat and directly return the
return value from report(), and the current code does so, i.e.
if (notice a violation exists)
return report(... VIOLATION_KIND ...);
return 0;
But that is a selfish code that declares it is the ultimate and
final form of the function, never to be enhanced later. To allow
and invite future enhancements, make the last test follow the same
pattern.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
fsck.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/fsck.c b/fsck.c
index ca4c685..21dfa5f 100644
--- a/fsck.c
+++ b/fsck.c
@@ -666,9 +666,11 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
err = fsck_ident(&buffer, &commit->object, options);
if (err)
return err;
- if (!commit->tree)
- return report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
-
+ if (!commit->tree) {
+ err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
+ if (err)
+ return err;
+ }
return 0;
}
--
2.8.1-355-gcea30bb
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 2/2] fsck: detect and warn a commit with embedded NUL 2016-04-14 18:07 [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation Junio C Hamano @ 2016-04-14 18:07 ` Junio C Hamano 2016-04-14 18:21 ` Jeff King 2016-04-15 13:43 ` Johannes Schindelin 2016-04-14 18:10 ` [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation Jeff King 2016-04-15 13:41 ` Johannes Schindelin 2 siblings, 2 replies; 13+ messages in thread From: Junio C Hamano @ 2016-04-14 18:07 UTC (permalink / raw) To: git Even though a Git commit object is designed to be capable of storing any binary data as its payload, in practice people use it to describe the changes in textual form, and tools like "git log" are designed to treat the payload as text. Detect and warn when we see any commit object with a NUL byte in it. Note that a NUL byte in the header part is already detected as a grave error. This change is purely about the message part. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- fsck.c | 8 ++++++++ t/t1450-fsck.sh | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/fsck.c b/fsck.c index 21dfa5f..3366b3f 100644 --- a/fsck.c +++ b/fsck.c @@ -59,6 +59,7 @@ FUNC(HAS_DOTGIT, WARN) \ FUNC(NULL_SHA1, WARN) \ FUNC(ZERO_PADDED_FILEMODE, WARN) \ + FUNC(NUL_IN_COMMIT, WARN) \ /* infos (reported as warnings, but ignored by default) */ \ FUNC(BAD_TAG_NAME, INFO) \ FUNC(MISSING_TAGGER_ENTRY, INFO) @@ -610,6 +611,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer, struct commit_graft *graft; unsigned parent_count, parent_line_count = 0, author_count; int err; + const char *buffer_begin = buffer; if (verify_headers(buffer, size, &commit->object, options)) return -1; @@ -671,6 +673,12 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer, if (err) return err; } + if (memchr(buffer_begin, '\0', size)) { + err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT, + "NUL byte in the commit object body"); + if (err) + return err; + } return 0; } diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index e66b7cb..9012046 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -427,6 +427,23 @@ ) ' +test_expect_success 'NUL in commit' ' + rm -fr nul-in-commit && + git init nul-in-commit && + ( + cd nul-in-commit && + git commit --allow-empty -m "initial commitQNUL after message" && + git cat-file commit HEAD >original && + q_to_nul <original >munged && + git hash-object -w -t commit --stdin <munged >name && + git branch bad $(cat name) && + + test_must_fail git -c fsck.nulInCommit=error fsck 2>warn.1 && + git fsck 2>warn.2 && + grep nulInCommit warn.2 + ) +' + # create a static test repo which is broken by omitting # one particular object ($1, which is looked up via rev-parse # in the new repository). -- 2.8.1-355-gcea30bb ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 2/2] fsck: detect and warn a commit with embedded NUL 2016-04-14 18:07 ` [PATCH 2/2] fsck: detect and warn a commit with embedded NUL Junio C Hamano @ 2016-04-14 18:21 ` Jeff King 2016-04-14 18:25 ` Junio C Hamano 2016-04-14 18:25 ` Jeff King 2016-04-15 13:43 ` Johannes Schindelin 1 sibling, 2 replies; 13+ messages in thread From: Jeff King @ 2016-04-14 18:21 UTC (permalink / raw) To: Junio C Hamano; +Cc: git On Thu, Apr 14, 2016 at 11:07:09AM -0700, Junio C Hamano wrote: > Even though a Git commit object is designed to be capable of storing > any binary data as its payload, in practice people use it to describe > the changes in textual form, and tools like "git log" are designed to > treat the payload as text. > > Detect and warn when we see any commit object with a NUL byte in > it. > > Note that a NUL byte in the header part is already detected as a > grave error. This change is purely about the message part. > > Signed-off-by: Junio C Hamano <gitster@pobox.com> Thanks, I was just reading over some of the old threads, and wondering if it was time to resurrect this idea. > @@ -610,6 +611,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer, > struct commit_graft *graft; > unsigned parent_count, parent_line_count = 0, author_count; > int err; > + const char *buffer_begin = buffer; > > if (verify_headers(buffer, size, &commit->object, options)) > return -1; You need this "buffer_begin" because we move the "buffer" pointer forward as we parse. But perhaps whole-buffer checks should simply go at the top (next to verify_headers) before we start advancing the pointer. To me, that makes the function's flow more natural. But alternatively... > @@ -671,6 +673,12 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer, > if (err) > return err; > } > + if (memchr(buffer_begin, '\0', size)) { > + err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT, > + "NUL byte in the commit object body"); > + if (err) > + return err; > + } Here we've parsed to the end of the headers we know about. We know there's no NUL there, because verify_headers() would have complained. And because the individual header parsers would have complained. So I actually think we could check from "buffer" (of course we do still need to record the beginning of the buffer to adjust "size" appropriately). It's a little more efficient (we don't have to memchr over the same bytes again). But I'd worry a little that doing it that way would introduce coupling between this check and verify_headers(), though (so that if the latter ever changes, our check may start missing cases). So yet another alternative would be to include this check in verify_headers(). It would parse to the end of the headers as now, and then from there additionally look for a NUL in the body. Of the three approaches, I think I like that third one. It's the most efficient, and I think the flow is pretty clear. We'd probably want to rename verify_headers(), though. :) -Peff ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/2] fsck: detect and warn a commit with embedded NUL 2016-04-14 18:21 ` Jeff King @ 2016-04-14 18:25 ` Junio C Hamano 2016-04-14 18:29 ` Jeff King 2016-04-14 18:25 ` Jeff King 1 sibling, 1 reply; 13+ messages in thread From: Junio C Hamano @ 2016-04-14 18:25 UTC (permalink / raw) To: Jeff King; +Cc: git Jeff King <peff@peff.net> writes: >> + const char *buffer_begin = buffer; >> >> if (verify_headers(buffer, size, &commit->object, options)) >> return -1; > > You need this "buffer_begin" because we move the "buffer" pointer > forward as we parse. But perhaps whole-buffer checks should simply go at > the top (next to verify_headers) before we start advancing the pointer. > To me, that makes the function's flow more natural. That was my second iteration. I didn't want the function return with warning without checking more serious errors that may be in the object. > But alternatively... > >> @@ -671,6 +673,12 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer, >> if (err) >> return err; >> } >> + if (memchr(buffer_begin, '\0', size)) { >> + err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT, >> + "NUL byte in the commit object body"); >> + if (err) >> + return err; >> + } > > Here we've parsed to the end of the headers we know about. We know > there's no NUL there, because verify_headers() would have complained. > And because the individual header parsers would have complained. So I > actually think we could check from "buffer" (of course we do still need > to record the beginning of the buffer to adjust "size" appropriately). Yes, keeping the "begin" pointer is a cheap way to do an equivalent of "adjusting size". > It's a little more efficient (we don't have to memchr over the same > bytes again). But I'd worry a little that doing it that way would > introduce coupling between this check and verify_headers(), though (so > that if the latter ever changes, our check may start missing cases). > > So yet another alternative would be to include this check in > verify_headers(). It would parse to the end of the headers as now, and > then from there additionally look for a NUL in the body. > > Of the three approaches, I think I like that third one. It's the most > efficient, and I think the flow is pretty clear. We'd probably want to > rename verify_headers(), though. :) Sounds sensible, except the "should a mere warning hide potentially more serious errors?" question remains. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/2] fsck: detect and warn a commit with embedded NUL 2016-04-14 18:25 ` Junio C Hamano @ 2016-04-14 18:29 ` Jeff King 2016-04-14 19:04 ` Junio C Hamano 0 siblings, 1 reply; 13+ messages in thread From: Jeff King @ 2016-04-14 18:29 UTC (permalink / raw) To: Junio C Hamano; +Cc: git On Thu, Apr 14, 2016 at 11:25:29AM -0700, Junio C Hamano wrote: > > You need this "buffer_begin" because we move the "buffer" pointer > > forward as we parse. But perhaps whole-buffer checks should simply go at > > the top (next to verify_headers) before we start advancing the pointer. > > To me, that makes the function's flow more natural. > > That was my second iteration. I didn't want the function return > with warning without checking more serious errors that may be in the > object. Ah, I didn't consider that. In general I'm not sure the distinction between "warning" and "error" is all that important, or has been applied all that consistently. transfer.fsckObjects will barf on either. But I do agree in general that we should be checking as many things as we can. And that we are already wrong to return an error immediately when verify_headers() complains. We should be accumulating problems in an error code and progressing as far as possible. I think fsck_tree() is a good example of how to do this. -Peff ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/2] fsck: detect and warn a commit with embedded NUL 2016-04-14 18:29 ` Jeff King @ 2016-04-14 19:04 ` Junio C Hamano 0 siblings, 0 replies; 13+ messages in thread From: Junio C Hamano @ 2016-04-14 19:04 UTC (permalink / raw) To: Jeff King; +Cc: git Jeff King <peff@peff.net> writes: > But I do agree in general that we should be checking as many things as > we can. I was about to say "I agree with that in principle, but there are cases where you would want to say 'if the object does not pass even this basic check, it is not worth validating it further', and verify-headers may fall into that category". That's another way of saying that something that we cannot even parse into constituent fields we cannot check the validity of each field for the semantics. However, with the current "violations of various classes can be configured out" way of doing things, that is a difficult stance to take. If you choose to accept syntax violation that makes us unable to parse, you must accept warnings and errors coming from "missing" fields due to our inability to parse and your telling us to proceed anyway. So in the end, I do agree that we should be checking as many things as we can. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/2] fsck: detect and warn a commit with embedded NUL 2016-04-14 18:21 ` Jeff King 2016-04-14 18:25 ` Junio C Hamano @ 2016-04-14 18:25 ` Jeff King 2016-04-14 18:37 ` Junio C Hamano 1 sibling, 1 reply; 13+ messages in thread From: Jeff King @ 2016-04-14 18:25 UTC (permalink / raw) To: Junio C Hamano; +Cc: git On Thu, Apr 14, 2016 at 02:21:03PM -0400, Jeff King wrote: > So yet another alternative would be to include this check in > verify_headers(). It would parse to the end of the headers as now, and > then from there additionally look for a NUL in the body. Hmm. Looking at verify_headers(), I think it has another bug. It wants to "return report(...)" as soon as it sees a problem, and stops looking for other ones. But the new model for reporting errors is that report() might ignore a problem if configured to do so. So I think if you were to ignore NUL_IN_HEADER, then a commit with NUL_IN_HEADER could still pass fsck, even though it should trigger UNTERMINATED_HEADER. -Peff ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/2] fsck: detect and warn a commit with embedded NUL 2016-04-14 18:25 ` Jeff King @ 2016-04-14 18:37 ` Junio C Hamano 0 siblings, 0 replies; 13+ messages in thread From: Junio C Hamano @ 2016-04-14 18:37 UTC (permalink / raw) To: Jeff King; +Cc: git Jeff King <peff@peff.net> writes: > On Thu, Apr 14, 2016 at 02:21:03PM -0400, Jeff King wrote: > >> So yet another alternative would be to include this check in >> verify_headers(). It would parse to the end of the headers as now, and >> then from there additionally look for a NUL in the body. > > Hmm. Looking at verify_headers(), I think it has another bug. > > It wants to "return report(...)" as soon as it sees a problem, and stops > looking for other ones. But the new model for reporting errors is that > report() might ignore a problem if configured to do so. Yup, it should be doing the "do not return early unless report says it is questionable", at least. Accumulating the error with err |= report() is an improvement, but even without that, doing the usual case '\0': err = report(...); return err if err; would be a real bugfix. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/2] fsck: detect and warn a commit with embedded NUL 2016-04-14 18:07 ` [PATCH 2/2] fsck: detect and warn a commit with embedded NUL Junio C Hamano 2016-04-14 18:21 ` Jeff King @ 2016-04-15 13:43 ` Johannes Schindelin 1 sibling, 0 replies; 13+ messages in thread From: Johannes Schindelin @ 2016-04-15 13:43 UTC (permalink / raw) To: Junio C Hamano; +Cc: git Hi Junio, On Thu, 14 Apr 2016, Junio C Hamano wrote: > Even though a Git commit object is designed to be capable of storing > any binary data as its payload, in practice people use it to describe > the changes in textual form, and tools like "git log" are designed to > treat the payload as text. > > Detect and warn when we see any commit object with a NUL byte in > it. > > Note that a NUL byte in the header part is already detected as a > grave error. This change is purely about the message part. IIRC there was some discussion going on about this, and since it was 1) legal and 2) not checked before, I decided not to make this an error. But of course it is good to introduce a warning! Thank you, Dscho ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation 2016-04-14 18:07 [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation Junio C Hamano 2016-04-14 18:07 ` [PATCH 2/2] fsck: detect and warn a commit with embedded NUL Junio C Hamano @ 2016-04-14 18:10 ` Jeff King 2016-04-14 18:15 ` Junio C Hamano 2016-04-15 13:41 ` Johannes Schindelin 2 siblings, 1 reply; 13+ messages in thread From: Jeff King @ 2016-04-14 18:10 UTC (permalink / raw) To: Junio C Hamano; +Cc: git On Thu, Apr 14, 2016 at 11:07:08AM -0700, Junio C Hamano wrote: > The pattern taken by all the validations in this function is: > > if (notice a violation exists) { > err = report(... VIOLATION_KIND ...); > if (err) > return err; > } > > where report() returns zero if specified kind of violation is set to > be ignored, and otherwise shows an error message and returns non-zero. > > The last validation in the function immediately after the function > returns 0 to declare "all good" can cheat and directly return the > return value from report(), and the current code does so, i.e. > > if (notice a violation exists) > return report(... VIOLATION_KIND ...); > return 0; > > But that is a selfish code that declares it is the ultimate and > final form of the function, never to be enhanced later. To allow > and invite future enhancements, make the last test follow the same > pattern. > > Signed-off-by: Junio C Hamano <gitster@pobox.com> > --- > fsck.c | 8 +++++--- > 1 file changed, 5 insertions(+), 3 deletions(-) Patch looks good, and nicely explained. -Peff ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation 2016-04-14 18:10 ` [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation Jeff King @ 2016-04-14 18:15 ` Junio C Hamano 0 siblings, 0 replies; 13+ messages in thread From: Junio C Hamano @ 2016-04-14 18:15 UTC (permalink / raw) To: Jeff King; +Cc: git Jeff King <peff@peff.net> writes: > On Thu, Apr 14, 2016 at 11:07:08AM -0700, Junio C Hamano wrote: > >> The pattern taken by all the validations in this function is: >> >> if (notice a violation exists) { >> err = report(... VIOLATION_KIND ...); >> if (err) >> return err; >> } >> >> where report() returns zero if specified kind of violation is set to >> be ignored, and otherwise shows an error message and returns non-zero. >> >> The last validation in the function immediately after the function s/after/before/ >> returns 0 to declare "all good" can cheat and directly return the >> return value from report(), and the current code does so, i.e. >> >> if (notice a violation exists) >> return report(... VIOLATION_KIND ...); >> return 0; >> >> But that is a selfish code that declares it is the ultimate and >> final form of the function, never to be enhanced later. To allow >> and invite future enhancements, make the last test follow the same >> pattern. >> >> Signed-off-by: Junio C Hamano <gitster@pobox.com> >> --- >> fsck.c | 8 +++++--- >> 1 file changed, 5 insertions(+), 3 deletions(-) > > Patch looks good, and nicely explained. > > -Peff ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation 2016-04-14 18:07 [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation Junio C Hamano 2016-04-14 18:07 ` [PATCH 2/2] fsck: detect and warn a commit with embedded NUL Junio C Hamano 2016-04-14 18:10 ` [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation Jeff King @ 2016-04-15 13:41 ` Johannes Schindelin 2016-04-15 15:06 ` Junio C Hamano 2 siblings, 1 reply; 13+ messages in thread From: Johannes Schindelin @ 2016-04-15 13:41 UTC (permalink / raw) To: Junio C Hamano; +Cc: git Hi Junio, On Thu, 14 Apr 2016, Junio C Hamano wrote: > The pattern taken by all the validations in this function is: > > if (notice a violation exists) { > err = report(... VIOLATION_KIND ...); > if (err) > return err; > } > > where report() returns zero if specified kind of violation is set to > be ignored, and otherwise shows an error message and returns non-zero. > > The last validation in the function immediately after the function > returns 0 to declare "all good" can cheat and directly return the > return value from report(), and the current code does so, i.e. > > if (notice a violation exists) > return report(... VIOLATION_KIND ...); > return 0; > > But that is a selfish code that declares it is the ultimate and > final form of the function, never to be enhanced later. To allow > and invite future enhancements, make the last test follow the same > pattern. FWIW I agree with this reasoning. Sorry for leaving this to you to clean up. Ciao, Dscho ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation 2016-04-15 13:41 ` Johannes Schindelin @ 2016-04-15 15:06 ` Junio C Hamano 0 siblings, 0 replies; 13+ messages in thread From: Junio C Hamano @ 2016-04-15 15:06 UTC (permalink / raw) To: Johannes Schindelin; +Cc: git Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: >> But that is a selfish code that declares it is the ultimate and >> final form of the function, never to be enhanced later. To allow >> and invite future enhancements, make the last test follow the same >> pattern. > > FWIW I agree with this reasoning. Sorry for leaving this to you to clean > up. Thanks. I often fall into the same trap, and I suspect everybody does. After doing a large-ish change, it is easy to think that what was just finished is the final one for quite some time to come, without even realizing that I am being selfish. ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2016-04-15 15:06 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-04-14 18:07 [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation Junio C Hamano 2016-04-14 18:07 ` [PATCH 2/2] fsck: detect and warn a commit with embedded NUL Junio C Hamano 2016-04-14 18:21 ` Jeff King 2016-04-14 18:25 ` Junio C Hamano 2016-04-14 18:29 ` Jeff King 2016-04-14 19:04 ` Junio C Hamano 2016-04-14 18:25 ` Jeff King 2016-04-14 18:37 ` Junio C Hamano 2016-04-15 13:43 ` Johannes Schindelin 2016-04-14 18:10 ` [PATCH 1/2] fsck_commit_buffer(): do not special case the last validation Jeff King 2016-04-14 18:15 ` Junio C Hamano 2016-04-15 13:41 ` Johannes Schindelin 2016-04-15 15:06 ` 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