Skip to content

Add ACN Mutator (assert(...) Condition Negation) - #3000

Open
sidarth16 wants to merge 4 commits into
crytic:masterfrom
sidarth16:acn-assert-condition-negation
Open

Add ACN Mutator (assert(...) Condition Negation)#3000
sidarth16 wants to merge 4 commits into
crytic:masterfrom
sidarth16:acn-assert-condition-negation

Conversation

@sidarth16

Copy link
Copy Markdown
Contributor

Summary

This PR introduces ACN (Assert Condition Negation) to the mutator set.

The mutator rewrites the first condition argument of assert(...) by wrapping it in a negation, so assertion-style guards can be flipped during mutation testing.

Examples:

  • assert(x > 0 && x < 10) becomes assert(!(x > 0 && x < 10))
  • assert(msg.sender == owner) becomes assert(!(msg.sender == owner))
  • assert(!isOwner) becomes assert(!(!isOwner))

Changes

  • Added ACN mutator:
    • slither/tools/mutator/mutators/ACN.py
    • detects assert(...) calls & generates a patch that rewrites the condition as !(...)
  • Register ACN mutator in:
    • slither/tools/mutator/mutators/all_mutators.py
  • Updated test Contract:
    • Added assert(..) statement in tests/tools/mutator/test_data/test_source_unit/src/Counter.sol
  • Added tests in:
    • tests/tools/mutator/test_mutator.py testing the ACN mutator

Notes

  • This PR is intentionally limited to assert(...) mutations.
  • The require(...) variant is being handled separately in PR Add RCN Mutator (require(...) Condition Negation) #2998.
  • ACN is listed with # severity medium in all_mutators.py for consistency with the existing mutator list comments.
  • ACN is counted as tweak mutant by current framework rules (RR/CR special-cased)

Fixes #2999

@bohendo

bohendo commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

I'm not sure this gives us a good signal compared to the noise it adds. Of these 3 examples:

  • assert(msg.sender == owner) becomes assert(!(msg.sender == owner)): Direct, logical duplicate of the existing ==->!= mutation. I'd expect the majority of ACN mutants to be duplicates in this vein.
  • assert(x > 0 && x < 10) becomes assert(!(x > 0 && x < 10)): Not a direct dup like the above, so arguably some added value especially bc it's medium-sev so it might let us skip existing low-sev >/</&& replacements later. However, if negating an assertion is uncaught then the assertion probably isn't being checked at all, which means CR would have already flagged it.
  • assert(!isOwner) becomes assert(!(!isOwner)): This might be better served by a negation removal mutation instead; such a mutation wouldn't overlap so much with existing mutations & deliver a similar signal with much less noise.

@sidarth16

Copy link
Copy Markdown
Contributor Author

Thanks for the feedback! @bohendo
My initial thought was to have dedicated mutators for assert/require since they're security-critical guard statements, instead of relying solely on operator-level mutations. That said, I understand your concern about the overlap.

Do you think a dedicated negation-removal mutator would be a better direction ?

@bohendo

bohendo commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Yea @sidarth16, I'd be happy to review and eventually approve a negation removal mutation 🚀

@sidarth16

Copy link
Copy Markdown
Contributor Author

Thanks! @bohendo
I'll work on a dedicated negation-removal mutator instead and open a new PR.

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.

Enhancement: Add ACN Mutator (assert(...) Condition Negation)

3 participants