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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: Run analysis using CodeChecker #304

Merged
merged 13 commits into from
Jul 6, 2020
Merged

ci: Run analysis using CodeChecker #304

merged 13 commits into from
Jul 6, 2020

Conversation

Swatinem
Copy link
Member

See https://github.com/Ericsson/codechecker

This basically is a frontend for clang-tidy and clang-static-analyzer.

@Swatinem Swatinem force-pushed the ci/scan-build branch 4 times, most recently from 9fb46ba to f6cb01d Compare June 17, 2020 16:13
@Swatinem
Copy link
Member Author

Some examples of false positives I see with CTU running locally (had to disable that on CI for now):

[HIGH] /home/swatinem/Coding/sentry/sentry-native/src/sentry_string.c:39:5: Null pointer passed to 1st parameter expecting 'nonnull' [core.NonNullParamChecker]
    memcpy(sb->buf + sb->len, s, len);
    ^
  Report hash: bbf569e0c283fab9b521cb403de0903c
  Macro expansions:
    1, sentry_envelope.c:360:1: Macro 'MUST_USE' expanded to '__attribute__((warn_unused_result))'
  Steps:
     1, sentry_envelope.c:382:14: Calling 'sentry_envelope_write_to_path'
     2, sentry_envelope.c:360:1: Entered call from 'sentry_envelope_write_to_file'
     3, sentry_envelope.c:367:17: Calling 'sentry_envelope_serialize'
     4, sentry_envelope.c:348:1: Entered call from 'sentry_envelope_write_to_path'
     5, sentry_envelope.c:352:5: Calling 'sentry__stringbuilder_init'
     6, sentry_string.c:8:1: Entered call from 'sentry_envelope_serialize'
     7, sentry_string.c:11:5: Null pointer value stored to 'sb.buf'
     8, sentry_envelope.c:352:5: Returning from 'sentry__stringbuilder_init'
     9, sentry_envelope.c:354:5: Calling 'sentry__envelope_serialize_into_stringbuilder'
    10, sentry_envelope.c:291:1: Entered call from 'sentry_envelope_serialize'
    11, sentry_envelope.c:295:9: Assuming field 'is_raw' is true
    12, sentry_envelope.c:296:9: Calling 'sentry__stringbuilder_append_buf'
    13, sentry_string.c:53:1: Entered call from 'sentry__envelope_serialize_into_stringbuilder'
    14, sentry_string.c:57:12: Calling 'append'
    15, sentry_string.c:16:1: Entered call from 'sentry__stringbuilder_append_buf'
    16, sentry_string.c:20:9: Assuming 'needed' is <= field 'allocated'
    17, sentry_string.c:39:5: Null pointer passed to 1st parameter expecting 'nonnull'

I don’t think this can ever happen, as allocated will be 0 in that case; and needed is always >= 1 even if you want to append an empty string. Anyway, I will add another condition to it.

[MEDIUM] /home/swatinem/Coding/sentry/sentry-native/src/sentry_json.c:258:1: Potential leak of memory pointed to by 'formatted' [unix.Malloc]
}
^
  Report hash: d6367b9302465f90c90a3ab8eb9535cf
  Steps:
     1, sentry_json.c:255:23: Calling 'sentry__msec_time_to_iso8601'
     2, sentry_utils.c:327:1: Entered call from 'sentry__jsonwriter_write_msec_timestamp'
     3, sentry_utils.c:342:9: Assuming 'msecs' is 0
     4, sentry_utils.c:347:12: Calling 'sentry__string_clone'
     5, sentry_string.c:107:1: Entered call from 'sentry__msec_time_to_iso8601'
     6, sentry_string.c:110:18: Calling 'sentry__string_clonen'
     7, sentry_string.c:113:1: Entered call from 'sentry__string_clone'
     8, sentry_string.c:117:16: Calling 'sentry_malloc'
     9, sentry_alloc.c:13:1: Entered call from 'sentry__string_clonen'
    10, sentry_alloc.c:21:12: Memory is allocated
    11, sentry_string.c:117:16: Returned allocated memory
    12, sentry_string.c:118:9: Assuming 'rv' is non-null
    13, sentry_string.c:110:18: Returned allocated memory
    14, sentry_utils.c:347:12: Returned allocated memory
    15, sentry_json.c:255:23: Returned allocated memory
    16, sentry_json.c:258:1: Potential leak of memory pointed to by 'formatted'

Relevant code:

void
sentry__jsonwriter_write_msec_timestamp(sentry_jsonwriter_t *jw, uint64_t time)
{
    char *formatted = sentry__msec_time_to_iso8601(time);
    sentry__jsonwriter_write_str(jw, formatted);
    sentry_free(formatted);
}

lol, we just called sentry_free on it, how can that leak?

Looking at a lot more of these cases, I think the analyzer does not correctly handle ownership transfer of void*.
There are tons of false positives as well with sentry_path_free.

@@ -308,7 +308,11 @@ sentry_value_new_list(void)
list_t *l = SENTRY_MAKE(list_t);
if (l) {
memset(l, 0, sizeof(list_t));
return new_thing_value(l, THING_TYPE_LIST);
sentry_value_t rv = new_thing_value(l, THING_TYPE_LIST);
if (sentry_value_is_null(rv)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

These cases here are interesting. Sure, new_thing_value allocates internally and can fail. But CTU can’t look through the sentry_value_is_null assertion and will still flag all of these as false positives.

Copy link
Member

Choose a reason for hiding this comment

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

Have you checked if there are annotations that you can place sentry_value_is_null to make it understand the invariants? I'd love to take a look at this CTU failure.

Copy link
Member Author

Choose a reason for hiding this comment

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

The problem why I do all the checks outside is that new_thing_value takes ownership of whatever its wrapping, but it doesn’t know how to free. Maybe with a separate function pointer argument, this becomes clearer.

Copy link
Member

Choose a reason for hiding this comment

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

Usually, there are attributes you can put on the function to declare this behavior. Since we encode the pointers in a strange way, it's understandable that tools don't follow the path.

Let's skip this for now.

src/sentry_value.c Show resolved Hide resolved
@Swatinem Swatinem marked this pull request as ready for review June 22, 2020 16:29
@Swatinem Swatinem requested a review from a team June 22, 2020 16:29
tests/cmake.py Outdated Show resolved Hide resolved
tests/cmake.py Show resolved Hide resolved
errors = int(errors[: errors.find(b"\n")])
if errors > 0:
pytest.fail("code-checker analysis failed")

Copy link
Contributor

Choose a reason for hiding this comment

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

minor: personally this function is now too big and long for me to remember all variables in scope etc and i would break this up. at this point it's not problematic though, so i don't mind.

@codecov-commenter
Copy link

codecov-commenter commented Jun 24, 2020

Codecov Report

Merging #304 into master will decrease coverage by 0.16%.
The diff coverage is 53.12%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #304      +/-   ##
==========================================
- Coverage   85.20%   85.03%   -0.17%     
==========================================
  Files          49       49              
  Lines        3946     3975      +29     
==========================================
+ Hits         3362     3380      +18     
- Misses        584      595      +11     
Impacted Files Coverage Δ
src/modulefinder/sentry_modulefinder_linux.c 90.99% <0.00%> (-0.29%) ⬇️
src/sentry_session.c 88.38% <0.00%> (-1.16%) ⬇️
src/sentry_value.c 84.15% <45.94%> (-0.62%) ⬇️
src/sentry_core.c 90.90% <50.00%> (-0.30%) ⬇️
src/path/sentry_path_unix.c 81.96% <66.66%> (-0.22%) ⬇️
src/sentry_envelope.c 87.76% <73.33%> (-0.22%) ⬇️
src/sentry_string.c 81.42% <100.00%> (ø)
src/sentry_utils.c 90.11% <100.00%> (+0.03%) ⬆️
src/symbolizer/sentry_symbolizer_unix.c 91.66% <0.00%> (-8.34%) ⬇️
... and 5 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 30204bd...ed26fdd. Read the comment docs.

@Swatinem Swatinem requested a review from jan-auer July 3, 2020 13:28
azure-pipelines.yml Show resolved Hide resolved
src/path/sentry_path_unix.c Outdated Show resolved Hide resolved
src/sentry_envelope.c Show resolved Hide resolved
src/sentry_string.h Outdated Show resolved Hide resolved
@@ -308,7 +308,11 @@ sentry_value_new_list(void)
list_t *l = SENTRY_MAKE(list_t);
if (l) {
memset(l, 0, sizeof(list_t));
return new_thing_value(l, THING_TYPE_LIST);
sentry_value_t rv = new_thing_value(l, THING_TYPE_LIST);
if (sentry_value_is_null(rv)) {
Copy link
Member

Choose a reason for hiding this comment

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

Have you checked if there are annotations that you can place sentry_value_is_null to make it understand the invariants? I'd love to take a look at this CTU failure.

src/sentry_value.c Show resolved Hide resolved
tests/__init__.py Outdated Show resolved Hide resolved
@Swatinem Swatinem merged commit 4adf9c3 into master Jul 6, 2020
@Swatinem Swatinem deleted the ci/scan-build branch July 6, 2020 11:57
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.

4 participants