mirror of
https://github.com/github/codeql.git
synced 2025-12-17 17:23:36 +01:00
C++: Support std::addressof
I didn't add this support in `AddressConstantExpression.qll` since I think it would require extra work and testing to get the constexprness right. My long-term plan for `AddressConstantExpression.qll` is to move its functionality to the extractor.
This commit is contained in:
@@ -19,15 +19,13 @@ private import cpp
|
||||
* template functions, these functions are essentially casts, so we treat them
|
||||
* as such.
|
||||
*/
|
||||
private predicate stdIdentityFunction(Function f) {
|
||||
f.getNamespace().getParentNamespace() instanceof GlobalNamespace and
|
||||
f.getNamespace().getName() = "std" and
|
||||
(
|
||||
f.getName() = "move"
|
||||
or
|
||||
f.getName() = "forward"
|
||||
)
|
||||
}
|
||||
private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["move", "forward"]) }
|
||||
|
||||
/**
|
||||
* Holds if `f` is an instantiation of `std::addressof`, which effectively
|
||||
* converts a reference to a pointer.
|
||||
*/
|
||||
private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") }
|
||||
|
||||
private predicate lvalueToLvalueStepPure(Expr lvalueIn, Expr lvalueOut) {
|
||||
lvalueIn = lvalueOut.(DotFieldAccess).getQualifier().getFullyConverted()
|
||||
@@ -99,12 +97,17 @@ private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) {
|
||||
}
|
||||
|
||||
private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) {
|
||||
// This probably cannot happen. It would require an expression to be
|
||||
// converted to a reference and back again without an intermediate variable
|
||||
// assignment.
|
||||
referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr)
|
||||
}
|
||||
|
||||
private predicate referenceToPointerStep(Expr referenceIn, Expr pointerOut) {
|
||||
pointerOut =
|
||||
any(FunctionCall call |
|
||||
stdAddressOf(call.getTarget()) and
|
||||
referenceIn = call.getArgument(0).getFullyConverted()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) {
|
||||
referenceOut =
|
||||
any(FunctionCall call |
|
||||
@@ -153,6 +156,12 @@ private predicate pointerFromVariableAccess(VariableAccess va, Expr pointer) {
|
||||
pointerToPointerStep(prev, pointer)
|
||||
)
|
||||
or
|
||||
// reference -> pointer
|
||||
exists(Expr prev |
|
||||
referenceFromVariableAccess(va, prev) and
|
||||
referenceToPointerStep(prev, pointer)
|
||||
)
|
||||
or
|
||||
// lvalue -> pointer
|
||||
exists(Expr prev |
|
||||
lvalueFromVariableAccess(va, prev) and
|
||||
@@ -177,7 +186,8 @@ private predicate referenceFromVariableAccess(VariableAccess va, Expr reference)
|
||||
private predicate valueMayEscapeAt(Expr e) {
|
||||
exists(Call call |
|
||||
e = call.getAnArgument().getFullyConverted() and
|
||||
not stdIdentityFunction(call.getTarget())
|
||||
not stdIdentityFunction(call.getTarget()) and
|
||||
not stdAddressOf(call.getTarget())
|
||||
)
|
||||
or
|
||||
exists(AssignExpr assign | e = assign.getRValue().getFullyConverted())
|
||||
|
||||
@@ -21,15 +21,13 @@ private import cpp
|
||||
* template functions, these functions are essentially casts, so we treat them
|
||||
* as such.
|
||||
*/
|
||||
private predicate stdIdentityFunction(Function f) {
|
||||
f.getNamespace().getParentNamespace() instanceof GlobalNamespace and
|
||||
f.getNamespace().getName() = "std" and
|
||||
(
|
||||
f.getName() = "move"
|
||||
or
|
||||
f.getName() = "forward"
|
||||
)
|
||||
}
|
||||
private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["move", "forward"]) }
|
||||
|
||||
/**
|
||||
* Holds if `f` is an instantiation of `std::addressof`, which effectively
|
||||
* converts a reference to a pointer.
|
||||
*/
|
||||
private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") }
|
||||
|
||||
private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) {
|
||||
lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr)
|
||||
@@ -96,6 +94,14 @@ private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) {
|
||||
referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr)
|
||||
}
|
||||
|
||||
private predicate referenceToPointerStep(Expr referenceIn, Expr pointerOut) {
|
||||
pointerOut =
|
||||
any(FunctionCall call |
|
||||
stdAddressOf(call.getTarget()) and
|
||||
referenceIn = call.getArgument(0).getFullyConverted()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) {
|
||||
referenceOut =
|
||||
any(FunctionCall call |
|
||||
@@ -185,6 +191,7 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode
|
||||
node = call and
|
||||
outer = call.getAnArgument().getFullyConverted() and
|
||||
not stdIdentityFunction(call.getTarget()) and
|
||||
not stdAddressOf(call.getTarget()) and
|
||||
exists(ReferenceType rt | rt = outer.getType().stripTopLevelSpecifiers() |
|
||||
not rt.getBaseType().isConst()
|
||||
)
|
||||
@@ -196,6 +203,11 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode
|
||||
lvalueToUpdate(lvalueMid, outer, node)
|
||||
)
|
||||
or
|
||||
exists(Expr pointerMid |
|
||||
referenceToPointerStep(reference, pointerMid) and
|
||||
pointerToUpdate(pointerMid, outer, node)
|
||||
)
|
||||
or
|
||||
exists(Expr referenceMid |
|
||||
referenceToReferenceStep(reference, referenceMid) and
|
||||
referenceToUpdate(referenceMid, outer, node)
|
||||
|
||||
@@ -63,3 +63,18 @@ void nonexamples(int *ptr, int &ref) {
|
||||
nonexamples(&*ptr, ref);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
constexpr T *addressof(T &obj) noexcept {
|
||||
return __builtin_addressof(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void use_std_addressof() {
|
||||
int x = 0;
|
||||
int *y = std::addressof(x) + *std::addressof(x);
|
||||
}
|
||||
|
||||
// semmle-extractor-options: --clang
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
| addressOf.cpp:62:11:62:13 | ptr | |
|
||||
| addressOf.cpp:63:19:63:21 | ptr | |
|
||||
| addressOf.cpp:63:24:63:26 | ref | non-const address |
|
||||
| addressOf.cpp:71:32:71:34 | obj | |
|
||||
| addressOf.cpp:71:32:71:34 | obj | |
|
||||
| addressOf.cpp:77:27:77:27 | x | non-const address |
|
||||
| addressOf.cpp:77:48:77:48 | x | |
|
||||
| file://:0:0:0:0 | captured | |
|
||||
| file://:0:0:0:0 | captured | |
|
||||
| file://:0:0:0:0 | captured | non-const address |
|
||||
|
||||
Reference in New Issue
Block a user