Skip to content

Commit 51229a6

Browse files
authored
Merge pull request #19493 from jketema/delete-expr
C++: Fix IR edge case where there are no function calls taking an argument
2 parents e4b7b91 + 4012813 commit 51229a6

File tree

7 files changed

+139
-1
lines changed

7 files changed

+139
-1
lines changed

cpp/ql/lib/semmle/code/cpp/ir/internal/IRCppLanguage.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,13 @@ class Class = Cpp::Class; // Used for inheritance conversions
6767
predicate hasCaseEdge(string minValue, string maxValue) { hasCaseEdge(_, minValue, maxValue) }
6868

6969
predicate hasPositionalArgIndex(int argIndex) {
70-
exists(Cpp::FunctionCall call | exists(call.getArgument(argIndex))) or
70+
exists(Cpp::FunctionCall call | exists(call.getArgument(argIndex)))
71+
or
7172
exists(Cpp::BuiltInOperation op | exists(op.getChild(argIndex)))
73+
or
74+
// Ensure we are always able to output the argument of a call to the delete operator.
75+
exists(Cpp::DeleteExpr d) and
76+
argIndex = 0
7277
}
7378

7479
predicate hasAsmOperandIndex(int operandIndex) {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#-----| [CopyAssignmentOperator] __va_list_tag& __va_list_tag::operator=(__va_list_tag const&)
2+
#-----| <params>:
3+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
4+
#-----| Type = [LValueReferenceType] const __va_list_tag &
5+
#-----| [MoveAssignmentOperator] __va_list_tag& __va_list_tag::operator=(__va_list_tag&&)
6+
#-----| <params>:
7+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
8+
#-----| Type = [RValueReferenceType] __va_list_tag &&
9+
#-----| [Operator,TopLevelFunction] void operator delete(void*)
10+
#-----| <params>:
11+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
12+
#-----| Type = [VoidPointerType] void *
13+
test.cpp:
14+
# 5| [TopLevelFunction] void foo(int*)
15+
# 5| <params>:
16+
# 5| getParameter(0): [Parameter] x
17+
# 5| Type = [IntPointerType] int *
18+
# 5| getEntryPoint(): [BlockStmt] { ... }
19+
# 6| getStmt(0): [ExprStmt] ExprStmt
20+
# 6| getExpr(): [DeleteExpr] delete
21+
# 6| Type = [VoidType] void
22+
# 6| ValueCategory = prvalue
23+
# 6| getExprWithReuse(): [VariableAccess] x
24+
# 6| Type = [IntPointerType] int *
25+
# 6| ValueCategory = prvalue(load)
26+
# 7| getStmt(1): [ReturnStmt] return ...
27+
# 9| [TopLevelFunction] void bar()
28+
# 9| <params>:
29+
# 11| [TopLevelFunction] void jazz()
30+
# 11| <params>:
31+
# 11| getEntryPoint(): [BlockStmt] { ... }
32+
# 12| getStmt(0): [ExprStmt] ExprStmt
33+
# 12| getExpr(): [FunctionCall] call to bar
34+
# 12| Type = [VoidType] void
35+
# 12| ValueCategory = prvalue
36+
# 13| getStmt(1): [ReturnStmt] return ...
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @kind graph
3+
*/
4+
5+
private import cpp
6+
private import semmle.code.cpp.PrintAST
7+
private import PrintConfig
8+
9+
private class PrintConfig extends PrintAstConfiguration {
10+
override predicate shouldPrintDeclaration(Declaration decl) { shouldDumpDeclaration(decl) }
11+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
private import cpp
2+
3+
/**
4+
* Holds if the specified location is in standard headers.
5+
*/
6+
predicate locationIsInStandardHeaders(Location loc) {
7+
loc.getFile().getAbsolutePath().regexpMatch(".*/include/[^/]+")
8+
}
9+
10+
/**
11+
* Holds if the AST or IR for the specified declaration should be printed in the test output.
12+
*
13+
* This predicate excludes declarations defined in standard headers.
14+
*/
15+
predicate shouldDumpDeclaration(Declaration decl) {
16+
not locationIsInStandardHeaders(decl.getLocation()) and
17+
(
18+
decl instanceof Function
19+
or
20+
decl.(GlobalOrNamespaceVariable).hasInitializer()
21+
or
22+
decl.(StaticLocalVariable).hasInitializer()
23+
)
24+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
test.cpp:
2+
# 5| void foo(int*)
3+
# 5| Block 0
4+
# 5| v5_1(void) = EnterFunction :
5+
# 5| m5_2(unknown) = AliasedDefinition :
6+
# 5| m5_3(unknown) = InitializeNonLocal :
7+
# 5| m5_4(unknown) = Chi : total:m5_2, partial:m5_3
8+
# 5| r5_5(glval<int *>) = VariableAddress[x] :
9+
# 5| m5_6(int *) = InitializeParameter[x] : &:r5_5
10+
# 5| r5_7(int *) = Load[x] : &:r5_5, m5_6
11+
# 5| m5_8(unknown) = InitializeIndirection[x] : &:r5_7
12+
# 5| m5_9(unknown) = Chi : total:m5_4, partial:m5_8
13+
# 6| r6_1(glval<unknown>) = FunctionAddress[operator delete] :
14+
# 6| r6_2(glval<int *>) = VariableAddress[x] :
15+
# 6| r6_3(int *) = Load[x] : &:r6_2, m5_6
16+
# 6| v6_4(void) = Call[operator delete] : func:r6_1, 0:r6_3
17+
# 6| m6_5(unknown) = ^CallSideEffect : ~m5_9
18+
# 6| m6_6(unknown) = Chi : total:m5_9, partial:m6_5
19+
# 7| v7_1(void) = NoOp :
20+
# 5| v5_10(void) = ReturnIndirection[x] : &:r5_7, ~m6_6
21+
# 5| v5_11(void) = ReturnVoid :
22+
# 5| v5_12(void) = AliasedUse : ~m6_6
23+
# 5| v5_13(void) = ExitFunction :
24+
25+
# 11| void jazz()
26+
# 11| Block 0
27+
# 11| v11_1(void) = EnterFunction :
28+
# 11| m11_2(unknown) = AliasedDefinition :
29+
# 11| m11_3(unknown) = InitializeNonLocal :
30+
# 11| m11_4(unknown) = Chi : total:m11_2, partial:m11_3
31+
# 12| r12_1(glval<unknown>) = FunctionAddress[bar] :
32+
# 12| v12_2(void) = Call[bar] : func:r12_1
33+
# 12| m12_3(unknown) = ^CallSideEffect : ~m11_4
34+
# 12| m12_4(unknown) = Chi : total:m11_4, partial:m12_3
35+
# 13| v13_1(void) = NoOp :
36+
# 11| v11_5(void) = ReturnVoid :
37+
# 11| v11_6(void) = AliasedUse : ~m12_4
38+
# 11| v11_7(void) = ExitFunction :
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @kind graph
3+
*/
4+
5+
private import cpp
6+
private import semmle.code.cpp.ir.implementation.aliased_ssa.PrintIR
7+
private import PrintConfig
8+
9+
private class PrintConfig extends PrintIRConfiguration {
10+
override predicate shouldPrintDeclaration(Declaration decl) { shouldDumpDeclaration(decl) }
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Test for edge case, where we have a database without any function calls or
2+
// where none of the function calls have any arguments, but where we do have
3+
// a delete expression.
4+
5+
void foo(int* x) {
6+
delete x;
7+
}
8+
9+
void bar();
10+
11+
void jazz() {
12+
bar();
13+
}

0 commit comments

Comments
 (0)