@@ -4,6 +4,7 @@ import semmle.code.cpp.ir.internal.IRCppLanguage
44private import semmle.code.cpp.ir.implementation.raw.internal.SideEffects as SideEffects
55private import DataFlowImplCommon as DataFlowImplCommon
66private import DataFlowUtil
7+ private import semmle.code.cpp.models.interfaces.PointerWrapper
78private import DataFlowPrivate
89
910/**
@@ -137,7 +138,7 @@ abstract class Indirection extends Type {
137138 Type baseType ;
138139
139140 /** Gets the type of this indirection. */
140- final Type getType ( ) { result = super . getUnspecifiedType ( ) }
141+ final Type getType ( ) { result = this }
141142
142143 /**
143144 * Gets the number of indirections supported by this type.
@@ -166,7 +167,7 @@ abstract class Indirection extends Type {
166167 *
167168 * For example, the base type of `int*&` is `int*`, and the base type of `int*` is `int`.
168169 */
169- final Type getBaseType ( ) { result = baseType . getUnspecifiedType ( ) }
170+ final Type getBaseType ( ) { result = baseType }
170171
171172 /** Holds if there should be an additional taint step from `node1` to `node2`. */
172173 predicate isAdditionalTaintStep ( Node node1 , Node node2 ) { none ( ) }
@@ -181,7 +182,9 @@ abstract class Indirection extends Type {
181182private class PointerOrReferenceTypeIndirection extends Indirection instanceof PointerOrReferenceType {
182183 PointerOrReferenceTypeIndirection ( ) { baseType = PointerOrReferenceType .super .getBaseType ( ) }
183184
184- override int getNumberOfIndirections ( ) { result = 1 + countIndirections ( this .getBaseType ( ) ) }
185+ override int getNumberOfIndirections ( ) {
186+ result = 1 + countIndirections ( this .getBaseType ( ) .getUnspecifiedType ( ) )
187+ }
185188
186189 override predicate isAdditionalDereference ( Instruction deref , Operand address ) { none ( ) }
187190
@@ -198,7 +201,9 @@ private module IteratorIndirections {
198201 not this instanceof PointerOrReferenceTypeIndirection and baseType = super .getValueType ( )
199202 }
200203
201- override int getNumberOfIndirections ( ) { result = 1 + countIndirections ( this .getBaseType ( ) ) }
204+ override int getNumberOfIndirections ( ) {
205+ result = 1 + countIndirections ( this .getBaseType ( ) .getUnspecifiedType ( ) )
206+ }
202207
203208 override predicate isAdditionalDereference ( Instruction deref , Operand address ) {
204209 exists ( CallInstruction call |
@@ -352,8 +357,9 @@ class BaseCallVariable extends BaseSourceVariable, TBaseCallVariable {
352357 * Holds if the value pointed to by `operand` can potentially be
353358 * modified be the caller.
354359 */
355- predicate isModifiableByCall ( ArgumentOperand operand ) {
360+ predicate isModifiableByCall ( ArgumentOperand operand , int indirectionIndex ) {
356361 exists ( CallInstruction call , int index , CppType type |
362+ indirectionIndex = [ 1 .. countIndirectionsForCppType ( type ) ] and
357363 type = getLanguageType ( operand ) and
358364 call .getArgumentOperand ( index ) = operand and
359365 if index = - 1
@@ -385,13 +391,50 @@ predicate isModifiableByCall(ArgumentOperand operand) {
385391 else any ( )
386392 else
387393 // An argument is modifiable if it's a non-const pointer or reference type.
388- exists ( Type t , boolean isGLValue | type .hasType ( t , isGLValue ) |
389- // If t is a glvalue it means that t is always a pointer-like type.
390- isGLValue = true
391- or
392- t instanceof PointerOrReferenceType and
393- not SideEffects:: isConstPointerLike ( t )
394- )
394+ isModifiableAt ( type , indirectionIndex )
395+ )
396+ }
397+
398+ /**
399+ * Holds if `t` is a pointer or reference type that supports at least `indirectionIndex` number
400+ * of indirections, and the `indirectionIndex` indirection cannot be modfiied by passing a
401+ * value of `t` to a function.
402+ */
403+ private predicate isModifiableAtImpl ( CppType cppType , int indirectionIndex ) {
404+ indirectionIndex = [ 1 .. countIndirectionsForCppType ( cppType ) ] and
405+ (
406+ exists ( PointerOrReferenceType pointerType , Type base , Type t |
407+ cppType .hasType ( t , _) and
408+ pointerType = t .getUnderlyingType ( ) and
409+ base = getTypeImpl ( pointerType , indirectionIndex )
410+ |
411+ // The value cannot be modified if it has a const specifier,
412+ not base .isConst ( )
413+ or
414+ // but in the case of a class type, it may be the case that
415+ // one of the members were modified.
416+ exists ( base .stripType ( ) .( Cpp:: Class ) .getAField ( ) )
417+ )
418+ or
419+ // If the `indirectionIndex`'th dereference of a type can be modified
420+ // then so can the `indirectionIndex + 1`'th dereference.
421+ isModifiableAtImpl ( cppType , indirectionIndex - 1 )
422+ )
423+ }
424+
425+ /**
426+ * Holds if `t` is a type with at least `indirectionIndex` number of indirections,
427+ * and the `indirectionIndex` indirection can be modified by passing a value of
428+ * type `t` to a function function.
429+ */
430+ bindingset [ indirectionIndex]
431+ private predicate isModifiableAt ( CppType cppType , int indirectionIndex ) {
432+ isModifiableAtImpl ( cppType , indirectionIndex )
433+ or
434+ exists ( PointerWrapper pw , Type t |
435+ cppType .hasType ( t , _) and
436+ t .stripType ( ) = pw and
437+ not pw .pointsToConst ( )
395438 )
396439}
397440
0 commit comments