11/**
22 * @name Call to `memset` may be deleted
3- * @description Using <code> memset</code> the function to clear private data in a variable that has no subsequent use
3+ * @description Using ` memset` the function to clear private data in a variable that has no subsequent use
44 * can make information-leak vulnerabilities easier to exploit because the compiler can remove the call.
55 * @kind problem
66 * @id cpp/memset-may-be-deleted
1313import cpp
1414import semmle.code.cpp.dataflow.EscapesTree
1515import semmle.code.cpp.commons.Exclusions
16+ import semmle.code.cpp.models.interfaces.Alias
1617
1718class MemsetFunction extends Function {
1819 MemsetFunction ( ) {
@@ -24,22 +25,33 @@ class MemsetFunction extends Function {
2425 }
2526}
2627
28+ predicate isNonEscapingArgument ( Expr escaped ) {
29+ exists ( Call call , AliasFunction aliasFunction , int i |
30+ aliasFunction = call .getTarget ( ) and
31+ call .getArgument ( i ) = escaped .getUnconverted ( ) and
32+ (
33+ aliasFunction .parameterNeverEscapes ( i )
34+ or
35+ aliasFunction .parameterEscapesOnlyViaReturn ( i ) and
36+ ( call instanceof ExprInVoidContext or call .getConversion * ( ) instanceof BoolConversion )
37+ )
38+ )
39+ }
40+
2741from FunctionCall call , LocalVariable v , MemsetFunction memset
2842where
2943 call .getTarget ( ) = memset and
3044 not isFromMacroDefinition ( call ) and
31- // `v` only escapes as the argument to `memset`.
45+ // `v` escapes as the argument to `memset`
46+ variableAddressEscapesTree ( v .getAnAccess ( ) , call .getArgument ( 0 ) .getFullyConverted ( ) ) and
47+ // ... and `v` doesn't escape anywhere else.
3248 forall ( Expr escape | variableAddressEscapesTree ( v .getAnAccess ( ) , escape ) |
33- call . getArgument ( 0 ) = escape . getUnconverted ( )
49+ isNonEscapingArgument ( escape )
3450 ) and
35- // `v` is a stack-allocated array or a struct, and `v` is not static.
3651 not v .isStatic ( ) and
37- (
38- v .getUnspecifiedType ( ) instanceof ArrayType and call .getArgument ( 0 ) = v .getAnAccess ( )
39- or
40- v .getUnspecifiedType ( ) instanceof Struct and
41- call .getArgument ( 0 ) .( AddressOfExpr ) .getAddressable ( ) = v
42- ) and
52+ // Reference-typed variables get special treatment in `variableAddressEscapesTree` so we leave them
53+ // out of this query.
54+ not v .getUnspecifiedType ( ) instanceof ReferenceType and
4355 // There is no later use of `v`.
4456 not v .getAnAccess ( ) = call .getASuccessor * ( ) and
4557 // Not using the `-fno-builtin-memset` flag
0 commit comments