My rule with pattern-not
doesn't work: using pattern-not-inside
One common issue when writing custom rules involves the unsuccessful exclusion of cases using pattern-not
.
If you are trying to exclude a specific case where a pattern is unacceptable unless it is accompanied by another pattern, try pattern-not-inside
instead of pattern-not
.
Background
In Semgrep, a pattern that's inside another pattern can mean one of two things:
- The pattern is wholly within an outer pattern
- The pattern is at the same level as another pattern, but includes less code
In other words, using pattern-not
in your rule means that Semgrep expects the matches to be the same "size" (same amount of code), and does not match if that's not the case.
Example
The example rule find-unverified-transactions
is a good example: make_transaction($T)
is acceptable only if verify_transaction($T)
is also present.
To successfully match the target code, the rule uses pattern
and pattern-not
:
But this rule is redundant. Both pattern clauses contain:
public $RETURN $METHOD(...){
...
}
However, if you refactor the rule by pulling the container out and using pattern-inside
, the rule doesn't work -- try it out if you like!
rules:
- id: find-unverified-transactions-inside
patterns:
- pattern-inside: |
$RETURN $METHOD(...) {
...
}
- pattern: |
...
make_transaction($T);
...
- pattern-not: |
...
verify_transaction($T);
...
make_transaction($T);
...
With an understanding of how pattern-not
operates, you can see that this rule fails because the matches are not the same size. The pattern-not
match is at the same level, but it is "larger" (contains more code).
If you switch to pattern-not-inside
:
- pattern-not-inside: |
...
verify_transaction($T);
...
make_transaction($T);
...
The rule successfully matches the example code.
Not finding what you need in this doc? Ask questions in our Community Slack group, or see Support for other ways to get help.