@@ -81,19 +81,24 @@ int getMaxIndirectionsForType(Type type) {
8181 result = countIndirectionsForCppType ( getTypeForGLValue ( type ) )
8282}
8383
84+ private class PointerOrReferenceType extends Cpp:: DerivedType {
85+ PointerOrReferenceType ( ) {
86+ this instanceof Cpp:: PointerType
87+ or
88+ this instanceof Cpp:: ReferenceType
89+ }
90+ }
91+
8492/**
8593 * Gets the maximum number of indirections a value of type `type` can have.
8694 *
8795 * Note that this predicate is intended to be called on unspecified types
8896 * (i.e., `countIndirections(e.getUnspecifiedType())`).
8997 */
9098private int countIndirections ( Type t ) {
91- result =
92- 1 +
93- countIndirections ( [ t .( Cpp:: PointerType ) .getBaseType ( ) , t .( Cpp:: ReferenceType ) .getBaseType ( ) ] )
99+ result = 1 + countIndirections ( t .( PointerOrReferenceType ) .getBaseType ( ) )
94100 or
95- not t instanceof Cpp:: PointerType and
96- not t instanceof Cpp:: ReferenceType and
101+ not t instanceof PointerOrReferenceType and
97102 result = 0
98103}
99104
@@ -139,8 +144,41 @@ predicate isModifiableByCall(ArgumentOperand operand) {
139144 type = getLanguageType ( operand ) and
140145 call .getArgumentOperand ( index ) = operand and
141146 if index = - 1
142- then not call .getStaticCallTarget ( ) instanceof Cpp:: ConstMemberFunction
143- else not SideEffects:: isConstPointerLike ( any ( Type t | type .hasType ( t , _) ) )
147+ then
148+ // A qualifier is "modifiable" if:
149+ // 1. the member function is not const specified, or
150+ // 2. the member funtion is `const` specified, but returns a pointer or reference
151+ // type that is non-const.
152+ //
153+ // To see why this is necessary, consider the following function:
154+ // ```
155+ // struct C {
156+ // void* data_;
157+ // void* data() const { return data; }
158+ // };
159+ // ...
160+ // C c;
161+ // memcpy(c.data(), source, 16)
162+ // ```
163+ // the data pointed to by `c.data_` is potentially modified by the call to `memcpy` even though
164+ // `C::data` has a const specifier. So we further place the restriction that the type returned
165+ // by `call` should not be of the form `const T*` (for some deeply const type `T`).
166+ if call .getStaticCallTarget ( ) instanceof Cpp:: ConstMemberFunction
167+ then
168+ exists ( PointerOrReferenceType resultType |
169+ resultType = call .getResultType ( ) and
170+ not resultType .isDeeplyConstBelow ( )
171+ )
172+ else any ( )
173+ else
174+ // An argument is modifiable if it's a non-const pointer or reference type.
175+ exists ( Type t , boolean isGLValue | type .hasType ( t , isGLValue ) |
176+ // If t is a glvalue it means that t is always a pointer-like type.
177+ isGLValue = true
178+ or
179+ t instanceof PointerOrReferenceType and
180+ not SideEffects:: isConstPointerLike ( t )
181+ )
144182 )
145183}
146184
0 commit comments