Skip to content

Fix #15129: Improve matching performance for hash based suppressions - #8970

Merged
ludviggunne merged 8 commits into
cppcheck-opensource:mainfrom
ludviggunne:15129-suppression-perf
Oct 28, 2026
Merged

ludviggunne merged 8 commits into
cppcheck-opensource:mainfrom
ludviggunne:15129-suppression-perf

Conversation

@ludviggunne

@ludviggunne ludviggunne commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Makes it so that hash based suppressions are indexed by hash.
Matching hash based suppressions is now O(1) (ignoring collisions) instead of O(n).
For large code bases using baseline suppressions (which may be in the number of tens of thousands) this leads to a substantial speed up. We could probably speed up matching of other suppressions in the future as well, but I assume these are in general manually added and won't even get close to the same number as baseline suppressions. Also fixed a bug in ProcessExecutor that would cause new suppressions to be added unintentionally.

@ludviggunne
ludviggunne force-pushed the 15129-suppression-perf branch from 4f206e4 to 10081d5 Compare October 28, 2026 08:24
@ludviggunne
ludviggunne force-pushed the 15129-suppression-perf branch from 10081d5 to b7cb7b9 Compare October 28, 2026 08:46

@dmcppcheck dmcppcheck left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

AI review

I found no new problems.

The new index (mHashSuppressions / mNonHashSuppressions) holds raw pointers into the std::list mSuppressions. That is safe here for three reasons:

  • Elements are only ever appended with push_back, never erased, so the pointers stay valid.
  • SuppressionList cannot be copied or moved because it has a std::mutex member, so no copy can end up pointing into another object's list.
  • Every lookup and change of the index happens while mSuppressionsSync is locked.

The new matching gives the same results as before. A hash suppression could only ever match an error with the same hash; for any other error it was marked checked and nothing more. checked is never read for hash suppressions, because all three getUnmatched*Suppressions skip hash > 0, so skipping them changes nothing. isSuppressed still checks every candidate and marks all of them matched. isSuppressedExplicitly still stops at the first match, which only changes which suppression gets marked matched, and that has no visible effect.

The ProcessExecutor change is right. Suppression::toString() leaves out the hash, so before this PR the parent rebuilt a checked hash suppression from the child as a suppression without a hash, which is a broader suppression than the user wrote.

Testing

  • Built cppcheck and testrunner in pr/ with make -j8, without errors.
  • ./testrunner TestSuppressions TestProcessExecutor TestThreadExecutor TestSingleExecutor: 71 tests, 0 failed.
  • pytest other_test.py -k "ipc or suppr": 23 passed, including the new test_ipc_hash_suppressions.
  • pytest inline-suppress_test.py: 26 passed, 7 skipped, 1 xfailed.

Manual tests in scratch/:

  • Executors agree: four files, each void fN() { int x = 1; int yN = 2; }, checked with --suppress-xml holding one unreadVariable suppression that has a hash and no fileName. -j1, -j2 --executor=process and -j2 --executor=thread each reported 7 unreadVariable (8 minus the suppressed one), so all three executors give the same result.
  • Large baseline: a file with 50,000 hash suppressions plus the real one, run on 3 files. It finished in about 0.25 s single-threaded and about 0.33 s with -j2 --executor=process, with the correct results.
  • Duplicates: two identical hash suppressions in the XML are still rejected with suppression 'unreadVariable' already exists.

I did not build base/, so I have no timing from before the PR to compare with.


Automated review of b7cb7b9 by Claude. The pull request was built and tested locally.

@ludviggunne
ludviggunne merged commit ebadd92 into cppcheck-opensource:main Oct 28, 2026
71 checks passed
@ludviggunne
ludviggunne deleted the 15129-suppression-perf branch October 28, 2026 13:14
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.

3 participants