1212
1313import cpp
1414import 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
2016
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 ( )
5921 }
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