mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
C++: support functions in HashCons
This commit is contained in:
@@ -80,10 +80,25 @@ private cached newtype HCBase =
|
||||
mk_ArrayAccess(x,i,_)
|
||||
}
|
||||
or
|
||||
HC_NonmemberFunctionCall(Function fcn, HC_Args args) {
|
||||
mk_NonmemberFunctionCall(fcn, args, _)
|
||||
}
|
||||
or
|
||||
HC_MemberFunctionCall(Function trg, HC qual, HC_Args args) {
|
||||
mk_MemberFunctionCall(trg, qual, args, _)
|
||||
}
|
||||
or
|
||||
// Any expression that is not handled by the cases above is
|
||||
// given a unique number based on the expression itself.
|
||||
HC_Unanalyzable(Expr e) { not analyzableExpr(e,_) }
|
||||
|
||||
private cached newtype HC_Args =
|
||||
HC_EmptyArgs(Function fcn) {
|
||||
any()
|
||||
}
|
||||
or HC_ArgCons(Function fcn, HC hc, int i, HC_Args list) {
|
||||
mk_ArgCons(fcn, hc, i, list, _)
|
||||
}
|
||||
/**
|
||||
* HC is the hash-cons of an expression. The relationship between `Expr`
|
||||
* and `HC` is many-to-one: every `Expr` has exactly one `HC`, but multiple
|
||||
@@ -120,6 +135,8 @@ class HC extends HCBase {
|
||||
if this instanceof HC_UnaryOp then result = "UnaryOp" else
|
||||
if this instanceof HC_ArrayAccess then result = "ArrayAccess" else
|
||||
if this instanceof HC_Unanalyzable then result = "Unanalyzable" else
|
||||
if this instanceof HC_NonmemberFunctionCall then result = "NonmemberFunctionCall" else
|
||||
if this instanceof HC_MemberFunctionCall then result = "MemberFunctionCall" else
|
||||
result = "error"
|
||||
}
|
||||
|
||||
@@ -329,6 +346,116 @@ private predicate mk_Deref(
|
||||
p = hashCons(deref.getOperand().getFullyConverted())
|
||||
}
|
||||
|
||||
private predicate analyzableNonmemberFunctionCall(
|
||||
FunctionCall fc) {
|
||||
forall(int i | exists(fc.getArgument(i)) | strictcount(fc.getArgument(i)) = 1) and
|
||||
strictcount(fc.getTarget()) = 1 and
|
||||
not fc.getTarget().isMember()
|
||||
}
|
||||
|
||||
private predicate mk_NonmemberFunctionCall(
|
||||
Function fcn,
|
||||
HC_Args args,
|
||||
FunctionCall fc
|
||||
) {
|
||||
fc.getTarget() = fcn and
|
||||
analyzableNonmemberFunctionCall(fc) and
|
||||
(
|
||||
exists(HC head, HC_Args tail |
|
||||
args = HC_ArgCons(fcn, head, fc.getNumberOfArguments() - 1, tail) and
|
||||
mk_ArgCons(fcn, head, fc.getNumberOfArguments() - 1, tail, fc)
|
||||
)
|
||||
or
|
||||
fc.getNumberOfArguments() = 0 and
|
||||
args = HC_EmptyArgs(fcn)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate analyzableMemberFunctionCall(
|
||||
FunctionCall fc) {
|
||||
forall(int i | exists(fc.getArgument(i)) | strictcount(fc.getArgument(i)) = 1) and
|
||||
strictcount(fc.getTarget()) = 1 and
|
||||
strictcount(fc.getQualifier()) = 1
|
||||
}
|
||||
|
||||
private predicate analyzableFunctionCall(
|
||||
FunctionCall fc
|
||||
) {
|
||||
analyzableNonmemberFunctionCall(fc)
|
||||
or
|
||||
analyzableMemberFunctionCall(fc)
|
||||
}
|
||||
|
||||
private predicate mk_MemberFunctionCall(
|
||||
Function fcn,
|
||||
HC qual,
|
||||
HC_Args args,
|
||||
FunctionCall fc
|
||||
) {
|
||||
fc.getTarget() = fcn and
|
||||
analyzableMemberFunctionCall(fc) and
|
||||
hashCons(fc.getQualifier()) = qual and
|
||||
(
|
||||
exists(HC head, HC_Args tail |
|
||||
args = HC_ArgCons(fcn, head, fc.getNumberOfArguments() - 1, tail) and
|
||||
mk_ArgCons(fcn, head, fc.getNumberOfArguments() - 1, tail, fc)
|
||||
)
|
||||
or
|
||||
fc.getNumberOfArguments() = 0 and
|
||||
args = HC_EmptyArgs(fcn)
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
private predicate analyzableImplicitThisFunctionCall(FunctionCall fc) {
|
||||
forall(int i | exists(fc.getArgument(i)) | strictcount(fc.getArgument(i)) = 1) and
|
||||
strictcount(fc.getTarget()) = 1 and
|
||||
fc.getQualifier().(ThisExpr).isCompilerGenerated() and
|
||||
fc.getTarget().isMember()
|
||||
}
|
||||
|
||||
private predicate mk_ImplicitThisFunctionCall(Function fcn, Function targ, HC_Args args, FunctionCall fc) {
|
||||
analyzableImplicitThisFunctionCall(fc) and
|
||||
fc.getTarget() = targ and
|
||||
fc.getEnclosingFunction() = fcn and
|
||||
analyzableImplicitThisFunctionCall(fc) and
|
||||
(
|
||||
exists(HC head, HC_Args tail |
|
||||
args = HC_ArgCons(targ, head, fc.getNumberOfArguments() - 1, tail) and
|
||||
mk_ArgCons(targ, head, fc.getNumberOfArguments() - 1, tail, fc)
|
||||
)
|
||||
or
|
||||
fc.getNumberOfArguments() = 0 and
|
||||
args = HC_EmptyArgs(targ)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate mk_ImplicitThisFunctionCall_with_qualifier(
|
||||
Function fcn,
|
||||
Function targ,
|
||||
HC qual,
|
||||
HC_Args args,
|
||||
FunctionCall fc) {
|
||||
mk_ImplicitThisFunctionCall(fcn, targ, args, fc) and
|
||||
qual = HC_ThisExpr(fcn)
|
||||
}
|
||||
*/
|
||||
private predicate mk_ArgCons(Function fcn, HC hc, int i, HC_Args list, FunctionCall fc) {
|
||||
analyzableFunctionCall(fc) and
|
||||
fc.getTarget() = fcn and
|
||||
hc = hashCons(fc.getArgument(i).getFullyConverted()) and
|
||||
(
|
||||
exists(HC head, HC_Args tail |
|
||||
list = HC_ArgCons(fcn, head, i - 1, tail) and
|
||||
mk_ArgCons(fcn, head, i - 1, tail, fc) and
|
||||
i > 0
|
||||
)
|
||||
or
|
||||
i = 0 and
|
||||
list = HC_EmptyArgs(fcn)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the hash-cons of expression `e`. */
|
||||
cached HC hashCons(Expr e) {
|
||||
exists (int val, Type t
|
||||
@@ -383,6 +510,17 @@ cached HC hashCons(Expr e) {
|
||||
exists (HC p
|
||||
| mk_Deref(p, e) and
|
||||
result = HC_Deref(p))
|
||||
or
|
||||
exists(Function fcn, HC_Args args
|
||||
| mk_NonmemberFunctionCall(fcn, args, e) and
|
||||
result = HC_NonmemberFunctionCall(fcn, args)
|
||||
)
|
||||
or
|
||||
exists(Function fcn, HC qual, HC_Args args
|
||||
| mk_MemberFunctionCall(fcn, qual, args, e) and
|
||||
result = HC_MemberFunctionCall(fcn, qual, args)
|
||||
)
|
||||
|
||||
or
|
||||
(not analyzableExpr(e,_) and result = HC_Unanalyzable(e))
|
||||
}
|
||||
@@ -405,5 +543,7 @@ predicate analyzableExpr(Expr e, string kind) {
|
||||
(analyzableUnaryOp(e) and kind = "UnaryOp") or
|
||||
(analyzableThisExpr(e) and kind = "ThisExpr") or
|
||||
(analyzableArrayAccess(e) and kind = "ArrayAccess") or
|
||||
(analyzablePointerDereferenceExpr(e) and kind = "PointerDereferenceExpr")
|
||||
(analyzablePointerDereferenceExpr(e) and kind = "PointerDereferenceExpr") or
|
||||
(analyzableNonmemberFunctionCall(e) and kind = "NonmemberFunctionCall") or
|
||||
(analyzableMemberFunctionCall(e) and kind = "MemberFunctionCall")
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
| file://:0:0:0:0 | this | 0:c0-c0 141:c23-c26 |
|
||||
| test.cpp:5:3:5:3 | x | 5:c3-c3 6:c3-c3 7:c7-c7 |
|
||||
| test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 |
|
||||
| test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 |
|
||||
@@ -30,6 +31,8 @@
|
||||
| test.cpp:56:13:56:16 | (int)... | 56:c13-c16 56:c31-c34 59:c9-c12 |
|
||||
| test.cpp:56:13:56:16 | * ... | 56:c13-c16 56:c31-c34 59:c9-c12 |
|
||||
| test.cpp:62:5:62:10 | result | 62:c5-c10 65:c10-c15 |
|
||||
| test.cpp:77:20:77:28 | call to getAValue | 77:c20-c28 80:c9-c17 |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | 77:c20-c30 80:c9-c19 |
|
||||
| test.cpp:79:7:79:7 | v | 79:c7-c7 80:c5-c5 |
|
||||
| test.cpp:79:11:79:14 | vals | 79:c11-c14 79:c24-c27 |
|
||||
| test.cpp:92:11:92:11 | x | 92:c11-c11 93:c10-c10 |
|
||||
@@ -51,3 +54,12 @@
|
||||
| test.cpp:116:3:116:3 | y | 116:c3-c3 117:c3-c3 118:c3-c3 |
|
||||
| test.cpp:117:7:117:9 | 0.10000000000000001 | 117:c7-c9 118:c7-c9 |
|
||||
| test.cpp:117:7:117:9 | (float)... | 117:c7-c9 118:c7-c9 |
|
||||
| test.cpp:122:3:122:8 | call to test07 | 122:c3-c8 123:c3-c8 |
|
||||
| test.cpp:125:3:125:11 | call to my_strspn | 125:c3-c11 126:c3-c11 |
|
||||
| test.cpp:125:13:125:17 | array to pointer conversion | 125:c13-c17 126:c13-c17 129:c20-c24 |
|
||||
| test.cpp:125:13:125:17 | foo | 125:c13-c17 126:c13-c17 129:c20-c24 |
|
||||
| test.cpp:125:20:125:24 | array to pointer conversion | 125:c20-c24 126:c20-c24 129:c13-c17 |
|
||||
| test.cpp:125:20:125:24 | bar | 125:c20-c24 126:c20-c24 129:c13-c17 |
|
||||
| test.cpp:141:12:141:17 | call to getInt | 141:c12-c17 141:c29-c34 |
|
||||
| test.cpp:146:10:146:11 | ih | 146:c10-c11 146:c31-c32 |
|
||||
| test.cpp:146:13:146:25 | call to getDoubledInt | 146:c13-c25 146:c34-c46 |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.HashCons
|
||||
|
||||
// Every expression should have exactly one GVN.
|
||||
// Every expression should have exactly one HC.
|
||||
// So this query should have zero results.
|
||||
from Expr e
|
||||
where count(hashCons(e)) != 1
|
||||
|
||||
@@ -117,3 +117,31 @@ void test07() {
|
||||
y = 0.1;
|
||||
y = 0.1;
|
||||
}
|
||||
|
||||
void test08() {
|
||||
test07();
|
||||
test07();
|
||||
|
||||
my_strspn("foo", "bar");
|
||||
my_strspn("foo", "bar");
|
||||
|
||||
|
||||
my_strspn("bar", "foo");
|
||||
}
|
||||
|
||||
class IntHolder {
|
||||
int myInt;
|
||||
|
||||
int getInt() {
|
||||
return myInt;
|
||||
}
|
||||
|
||||
public:
|
||||
int getDoubledInt() {
|
||||
return getInt() + this->getInt();
|
||||
}
|
||||
};
|
||||
|
||||
int quadrupleInt(IntHolder ih) {
|
||||
return ih.getDoubledInt() + ih.getDoubledInt();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user