12
12
13
13
import cpp
14
14
import codingstandards.c.cert
15
- import codingstandards.c.Pointers
16
- import codingstandards.c.Variable
17
- import codingstandards.cpp.dataflow.DataFlow
18
- import semmle.code.cpp.pointsto.PointsTo
19
- import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
15
+ import codingstandards.cpp.rules.donotpassaliasedpointertorestrictqualifiedparam_shared.DoNotPassAliasedPointerToRestrictQualifiedParam_Shared
20
16
21
- /**
22
- * A function that has a parameter with a restrict-qualified pointer type.
23
- */
24
- class FunctionWithRestrictParameters extends Function {
25
- Parameter restrictPtrParam ;
26
-
27
- FunctionWithRestrictParameters ( ) {
28
- restrictPtrParam .getUnspecifiedType ( ) instanceof PointerOrArrayType and
29
- (
30
- restrictPtrParam .getType ( ) .hasSpecifier ( [ "restrict" ] ) and
31
- restrictPtrParam = this .getAParameter ( )
32
- or
33
- this .hasGlobalName ( [ "strcpy" , "strncpy" , "strcat" , "strncat" , "memcpy" ] ) and
34
- restrictPtrParam = this .getParameter ( [ 0 , 1 ] )
35
- or
36
- this .hasGlobalName ( [ "strcpy_s" , "strncpy_s" , "strcat_s" , "strncat_s" , "memcpy_s" ] ) and
37
- restrictPtrParam = this .getParameter ( [ 0 , 2 ] )
38
- or
39
- this .hasGlobalName ( [ "strtok_s" ] ) and
40
- restrictPtrParam = this .getAParameter ( )
41
- or
42
- this .hasGlobalName ( [ "printf" , "printf_s" , "scanf" , "scanf_s" ] ) and
43
- restrictPtrParam = this .getParameter ( 0 )
44
- or
45
- this .hasGlobalName ( [ "sprintf" , "sprintf_s" , "snprintf" , "snprintf_s" ] ) and
46
- restrictPtrParam = this .getParameter ( 3 )
47
- )
48
- }
49
-
50
- Parameter getARestrictPtrParam ( ) { result = restrictPtrParam }
51
- }
52
-
53
- /**
54
- * A call to a function that has a parameter with a restrict-qualified pointer type.
55
- */
56
- class CallToFunctionWithRestrictParameters extends FunctionCall {
57
- CallToFunctionWithRestrictParameters ( ) {
58
- this .getTarget ( ) instanceof FunctionWithRestrictParameters
17
+ class DoNotPassAliasedPointerToRestrictQualifiedParamQuery extends DoNotPassAliasedPointerToRestrictQualifiedParam_SharedSharedQuery
18
+ {
19
+ DoNotPassAliasedPointerToRestrictQualifiedParamQuery ( ) {
20
+ this = Pointers3Package:: doNotPassAliasedPointerToRestrictQualifiedParamQuery ( )
59
21
}
60
-
61
- Expr getARestrictPtrArg ( ) {
62
- result =
63
- this .getArgument ( this .getTarget ( )
64
- .( FunctionWithRestrictParameters )
65
- .getARestrictPtrParam ( )
66
- .getIndex ( ) )
67
- }
68
-
69
- Expr getAPtrArg ( int index ) {
70
- result = this .getArgument ( index ) and
71
- pointerValue ( result )
72
- }
73
-
74
- Expr getAPossibleSizeArg ( ) {
75
- exists ( Parameter param |
76
- param = this .getTarget ( ) .( FunctionWithRestrictParameters ) .getAParameter ( ) and
77
- param .getUnderlyingType ( ) instanceof IntegralType and
78
- // exclude __builtin_object_size
79
- not result .( FunctionCall ) .getTarget ( ) instanceof BuiltInFunction and
80
- result = this .getArgument ( param .getIndex ( ) )
81
- )
82
- }
83
- }
84
-
85
- /**
86
- * A `PointsToExpr` that is an argument of a pointer-type in a `CallToFunctionWithRestrictParameters`
87
- */
88
- class CallToFunctionWithRestrictParametersArgExpr extends Expr {
89
- int paramIndex ;
90
-
91
- CallToFunctionWithRestrictParametersArgExpr ( ) {
92
- this = any ( CallToFunctionWithRestrictParameters call ) .getAPtrArg ( paramIndex )
93
- }
94
-
95
- int getParamIndex ( ) { result = paramIndex }
96
- }
97
-
98
- int getStatedValue ( Expr e ) {
99
- // `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
100
- // result in this case we pick the minimum value obtainable from dataflow and range analysis.
101
- result =
102
- upperBound ( e )
103
- .minimum ( min ( Expr source | DataFlow:: localExprFlow ( source , e ) | source .getValue ( ) .toInt ( ) ) )
104
- }
105
-
106
- int getPointerArithmeticOperandStatedValue ( CallToFunctionWithRestrictParametersArgExpr expr ) {
107
- result = getStatedValue ( expr .( PointerArithmeticExpr ) .getOperand ( ) )
108
- or
109
- // edge-case: &(array[index]) expressions
110
- result = getStatedValue ( expr .( AddressOfExpr ) .getOperand ( ) .( PointerArithmeticExpr ) .getOperand ( ) )
111
- or
112
- // fall-back if `expr` is not a pointer arithmetic expression
113
- not expr instanceof PointerArithmeticExpr and
114
- not expr .( AddressOfExpr ) .getOperand ( ) instanceof PointerArithmeticExpr and
115
- result = 0
116
- }
117
-
118
- module PointerValueToRestrictArgConfig implements DataFlow:: ConfigSig {
119
- predicate isSource ( DataFlow:: Node source ) { pointerValue ( source .asExpr ( ) ) }
120
-
121
- predicate isSink ( DataFlow:: Node sink ) {
122
- exists ( CallToFunctionWithRestrictParameters call |
123
- sink .asExpr ( ) = call .getAPtrArg ( _) .getAChild * ( )
124
- )
125
- }
126
-
127
- predicate isBarrierIn ( DataFlow:: Node node ) {
128
- exists ( AddressOfExpr a | node .asExpr ( ) = a .getOperand ( ) .getAChild * ( ) )
129
- }
130
- }
131
-
132
- module PointerValueToRestrictArgFlow = DataFlow:: Global< PointerValueToRestrictArgConfig > ;
133
-
134
- from
135
- CallToFunctionWithRestrictParameters call , CallToFunctionWithRestrictParametersArgExpr arg1 ,
136
- CallToFunctionWithRestrictParametersArgExpr arg2 , int argOffset1 , int argOffset2 , Expr source1 ,
137
- Expr source2 , string sourceMessage1 , string sourceMessage2
138
- where
139
- not isExcluded ( call , Pointers3Package:: doNotPassAliasedPointerToRestrictQualifiedParamQuery ( ) ) and
140
- arg1 = call .getARestrictPtrArg ( ) and
141
- arg2 = call .getAPtrArg ( _) and
142
- // enforce ordering to remove permutations if multiple restrict-qualified args exist
143
- ( not arg2 = call .getARestrictPtrArg ( ) or arg2 .getParamIndex ( ) > arg1 .getParamIndex ( ) ) and
144
- (
145
- // check if two pointers address the same object
146
- PointerValueToRestrictArgFlow:: flow ( DataFlow:: exprNode ( source1 ) ,
147
- DataFlow:: exprNode ( arg1 .getAChild * ( ) ) ) and
148
- (
149
- // one pointer value flows to both args
150
- PointerValueToRestrictArgFlow:: flow ( DataFlow:: exprNode ( source1 ) ,
151
- DataFlow:: exprNode ( arg2 .getAChild * ( ) ) ) and
152
- sourceMessage1 = "$@" and
153
- sourceMessage2 = "source" and
154
- source1 = source2
155
- or
156
- // there are two separate values that flow from an AddressOfExpr of the same target
157
- getAddressOfExprTargetBase ( source1 ) = getAddressOfExprTargetBase ( source2 ) and
158
- PointerValueToRestrictArgFlow:: flow ( DataFlow:: exprNode ( source2 ) ,
159
- DataFlow:: exprNode ( arg2 .getAChild * ( ) ) ) and
160
- sourceMessage1 = "a pair of address-of expressions ($@, $@)" and
161
- sourceMessage2 = "addressof1" and
162
- not source1 = source2
163
- )
164
- ) and
165
- // get the offset of the pointer arithmetic operand (or '0' if there is none)
166
- argOffset1 = getPointerArithmeticOperandStatedValue ( arg1 ) and
167
- argOffset2 = getPointerArithmeticOperandStatedValue ( arg2 ) and
168
- (
169
- // case 1: the pointer args are the same.
170
- // (definite aliasing)
171
- argOffset1 = argOffset2
172
- or
173
- // case 2: the pointer args are different, a size arg exists,
174
- // and the size arg is greater than the difference between the offsets.
175
- // (potential aliasing)
176
- exists ( Expr sizeArg |
177
- sizeArg = call .getAPossibleSizeArg ( ) and
178
- getStatedValue ( sizeArg ) > ( argOffset1 - argOffset2 ) .abs ( )
179
- )
180
- or
181
- // case 3: the pointer args are different, and a size arg does not exist
182
- // (potential aliasing)
183
- not exists ( call .getAPossibleSizeArg ( ) )
184
- )
185
- select call ,
186
- "Call to '" + call .getTarget ( ) .getName ( ) + "' passes an $@ to a $@ (pointer value derived from " +
187
- sourceMessage1 + "." , arg2 , "aliased pointer" , arg1 , "restrict-qualified parameter" , source1 ,
188
- sourceMessage2 , source2 , "addressof2"
22
+ }
0 commit comments