Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ffbe1e0

Browse files
authored
Merge pull request #11314 from MathiasVP/fix-flow-out-of-const-member-functions
C++: Fix flow out of const member functions
2 parents 7251f2f + b9bcff4 commit ffbe1e0

5 files changed

Lines changed: 55 additions & 17 deletions

File tree

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
9098
private 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

cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,6 @@
153153
| by_reference.cpp:16:11:16:11 | a | AST only |
154154
| by_reference.cpp:32:15:32:15 | s | IR only |
155155
| by_reference.cpp:36:18:36:18 | this | IR only |
156-
| by_reference.cpp:40:12:40:15 | this | AST only |
157-
| by_reference.cpp:51:8:51:8 | s | AST only |
158-
| by_reference.cpp:57:8:57:8 | s | AST only |
159-
| by_reference.cpp:63:8:63:8 | s | AST only |
160156
| by_reference.cpp:84:10:84:10 | a | AST only |
161157
| by_reference.cpp:88:9:88:9 | a | AST only |
162158
| by_reference.cpp:92:3:92:5 | * ... | AST only |

cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,14 +332,18 @@
332332
| by_reference.cpp:24:25:24:29 | value |
333333
| by_reference.cpp:32:12:32:12 | s |
334334
| by_reference.cpp:36:12:36:15 | this |
335+
| by_reference.cpp:40:12:40:15 | this |
335336
| by_reference.cpp:50:3:50:3 | s |
336337
| by_reference.cpp:50:17:50:26 | call to user_input |
338+
| by_reference.cpp:51:8:51:8 | s |
337339
| by_reference.cpp:51:10:51:20 | call to getDirectly |
338340
| by_reference.cpp:56:3:56:3 | s |
339341
| by_reference.cpp:56:19:56:28 | call to user_input |
342+
| by_reference.cpp:57:8:57:8 | s |
340343
| by_reference.cpp:57:10:57:22 | call to getIndirectly |
341344
| by_reference.cpp:62:3:62:3 | s |
342345
| by_reference.cpp:62:25:62:34 | call to user_input |
346+
| by_reference.cpp:63:8:63:8 | s |
343347
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
344348
| by_reference.cpp:68:17:68:18 | & ... |
345349
| by_reference.cpp:68:21:68:30 | call to user_input |

cpp/ql/test/library-tests/dataflow/taint-tests/smart_pointer.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,16 @@ void test_reverse_taint_shared() {
3535
std::shared_ptr<int> p = std::make_shared<int>();
3636

3737
*p = source();
38-
sink(p); // $ ast MISSING: ir
39-
sink(*p); // $ ast MISSING: ir
38+
sink(p); // $ ast,ir
39+
sink(*p); // $ ast,ir
4040
}
4141

4242
void test_reverse_taint_unique() {
4343
std::unique_ptr<int> p = std::unique_ptr<int>();
4444

4545
*p = source();
46-
sink(p); // $ ast MISSING: ir
47-
sink(*p); // $ ast MISSING: ir
46+
sink(p); // $ ast,ir
47+
sink(*p); // $ ast,ir
4848
}
4949

5050
void test_shared_get() {
@@ -134,5 +134,5 @@ int nested_shared_ptr_taint_cref(std::shared_ptr<C> p1, std::unique_ptr<std::sha
134134
sink(p1->q->x); // $ ast MISSING: ir
135135

136136
getNumberCRef(*p2);
137-
sink(**p2); // $ ast MISSING: ir
137+
sink(**p2); // $ ast,ir
138138
}

cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ class C_const_member_function {
677677
void test_with_const_member(char* source) {
678678
C_const_member_function c;
679679
memcpy(c.data(), source, 16);
680-
sink(c.data()); // $ ast MISSING: ir
680+
sink(c.data()); // $ ast,ir
681681
}
682682

683683
void argument_source(void*);

0 commit comments

Comments
 (0)