Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: 馃寑 address two null argument instances #4847

Merged
merged 1 commit into from
Nov 18, 2018

Conversation

noahp
Copy link
Contributor

@noahp noahp commented Oct 12, 2018

Handle two null argument cases that occur in the unit tests.
One is in library code, the other is in test code.

Detected by running unit tests with undefined behavior sanitizer:

 # build
mkdir build && cd build
cmake -DBUILD_CLAR=ON -DCMAKE_C_FLAGS="-fsanitize=address \
-fsanitize=undefined -fstack-usage -static-libasan" ..
cmake --build .

 # run with asan
ASAN_OPTIONS="allocator_may_return_null=1" ./libgit2_clar
...
............../libgit2/src/apply.c:316:3: runtime error: null pointer \
passed as argument 1, which is declared to never be null
...................../libgit2/tests/apply/fromfile.c:46:3: runtime \
error: null pointer passed as argument 1, which is declared to never be null

src/apply.c Outdated Show resolved Hide resolved
Copy link
Member

@ethomson ethomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @carlosmn's stylistic suggestion, and would actually take it a step further and check the length instead of that the pointers are not NULL. This fits in a bit better with the existing style.

tests/apply/fromfile.c Outdated Show resolved Hide resolved
tests/apply/fromfile.c Outdated Show resolved Hide resolved
src/apply.c Outdated Show resolved Hide resolved
@pks-t
Copy link
Member

pks-t commented Oct 25, 2018

By the way, one minor nit: there seems to be some kind of unicode character in the commit message. I'd very much prefer to not have them in commit messages, as many setups will not be able to display them correctly and also make it so much harder to search for the commit message.

Otherwise I'm fine with this, thanks for finding and fixing these errors!

@noahp
Copy link
Contributor Author

noahp commented Nov 3, 2018

The unicode emoji in the commit message is just a bit of lightheartedness, removed now!

I've update this per feedback (thanks so much for looking at it!), ready for re-review.

src/apply.c Outdated
/* verify the result matches source. skip the check if source_len is 0 */
if (source_len &&
(source_len != reverse.size ||
memcmp(source, reverse.ptr, source_len) != 0)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ethomson: you made the proposal to use source_len instead of source here. But if you ask me, this makes the code less readable because it leads one to wonder why we need to special case the source length. After all, the C standard says:

2 Where an argument declared as size_t n specifies the length of the array for a function, n can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4. On such a call, a function that locates a character finds no occurrence, a function that compares two character sequences returns zero, and a function that copies characters copies zero characters.

The important part being that if n == 0, a comparison will always compare to 0, so checking the source length is rather confusing. The other important part is that arguments other than n still need to be valid even in the case where n == 0. So we're really not interested in source_len being non-zero, but instead we're interested in source being non-NULL, even if the first will be an indicator for source being NULL.

I'm also not quite sure whether the change is actually correct. What we want to do here is to check whether the source file actually matches the patched file with the reverse patch applied. With this change, we'll skip this check completely if there is no source file content, but shouldn't we instead verify that there also is no target file content?

So e.g.:

/* Verify that the resulting file with the reverse patch applied matches the source file */
if (source_len != reverse_size || (source && memcmp(source, reverse.ptr, source_len) != 0))

The important bit is that the source check is now right in front of the memcmp. So we will only check source if we already know that source and reverse length are the same. If source is NULL, then we know that both source and reverse have a length of 0 and thus are equal. Otherwise, both have the same non-NULL length and need to be compared for equality.

Sorry for this wall of text :P

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good points, I definitely agree! I'll patch this up as you suggest (and thank you for taking the time to write out that comment!).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pks-t I agree that this should be if (source_len != reverse_size || (source_len && memcmp(source, reverse.ptr, source_len) != 0)).

I'm still in favor of checking source_len not source for readability. It won't matter in this case for correctness (mine avoids the call to memcmp, but I think that we can agree that's not really a problem and I could sacrifice that call for readability). It makes it more obvious to me that we short-circuit when source_len is 0, even knowing that yes, memcmp will try to dereference its first two args if source_len is 0.

Anyway, that's a minor personal preference; I would say that we should avoid re-rolling this unnecessarily. So whatever you've got in your editor buffer @noahp, I would think would be fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agree, @ethomson. Happy to merge either way as soon as the condition is fixed, I don't care too deeply

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks guys! Just updated per your recommendations.

Handle two null argument cases that occur in the unit tests.
One is in library code, the other is in test code.

Detected by running unit tests with undefined behavior sanitizer:
```bash
 # build
mkdir build && cd build
cmake -DBUILD_CLAR=ON -DCMAKE_C_FLAGS="-fsanitize=address \
-fsanitize=undefined -fstack-usage -static-libasan" ..
cmake --build .

 # run with asan
ASAN_OPTIONS="allocator_may_return_null=1" ./libgit2_clar
...
............../libgit2/src/apply.c:316:3: runtime error: null pointer \
passed as argument 1, which is declared to never be null
...................../libgit2/tests/apply/fromfile.c:46:3: runtime \
error: null pointer passed as argument 1, which is declared to never be null
```
@ethomson ethomson merged commit 646a94b into libgit2:master Nov 18, 2018
@ethomson
Copy link
Member

Thanks @noahp! 馃榾

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants