Skip to content

Commit 9922958

Browse files
author
Dave Bartolomeo
committed
C++: Fix failed tests
Added a new `StaticLocalVariable` class, which made several other pieces of the original change a bit cleaner. Fixed test failures due to a mistake in the original `CFG.qll` change. Added a test case for static local variables with constructors. Removed the `Uninitialized` instruction from the initialization of a static local, because all objects with static storage duration are zero-initialized at startup. Fixed expectations for `SignAnalysis.ql` to reflect that a bad result is now fixed.
1 parent 4c0d5c9 commit 9922958

File tree

14 files changed

+166
-43
lines changed

14 files changed

+166
-43
lines changed

cpp/ql/src/semmle/code/cpp/Variable.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,11 @@ private predicate inStaticInitializer(Expr e) {
409409
inStaticInitializer(e.getParent())
410410
}
411411

412+
/**
413+
* A C++ local variable declared as `static`.
414+
*/
415+
class StaticLocalVariable extends LocalVariable, StaticStorageDurationVariable { }
416+
412417
/**
413418
* A C/C++ variable which has global scope or namespace scope. For example the
414419
* variables `a` and `b` in the following code:

cpp/ql/src/semmle/code/cpp/controlflow/internal/CFG.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,9 +441,9 @@ private Node getControlOrderChildSparse(Node n, int i) {
441441
* thus should not have control flow computed.
442442
*/
443443
private predicate skipInitializer(Initializer init) {
444-
exists(LocalVariable local |
444+
exists(StaticLocalVariable local |
445445
init = local.getInitializer() and
446-
not local.(StaticStorageDurationVariable).hasDynamicInitialization()
446+
not local.hasDynamicInitialization()
447447
)
448448
}
449449

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,8 @@ private module Cached {
5252
}
5353

5454
cached
55-
predicate hasDynamicInitializationFlag(
56-
Function func, StaticStorageDurationVariable var, CppType type
57-
) {
58-
var.(LocalVariable).getFunction() = func and
55+
predicate hasDynamicInitializationFlag(Function func, StaticLocalVariable var, CppType type) {
56+
var.getFunction() = func and
5957
var.hasDynamicInitialization() and
6058
type = getBoolType()
6159
}

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ abstract class TranslatedLocalVariableDeclaration extends TranslatedVariableInit
7171
*/
7272
class TranslatedAutoVariableDeclarationEntry extends TranslatedLocalVariableDeclaration,
7373
TranslatedDeclarationEntry {
74-
LocalVariable var;
74+
StackVariable var;
7575

76-
TranslatedAutoVariableDeclarationEntry() { var = entry.getDeclaration() and not var.isStatic() }
76+
TranslatedAutoVariableDeclarationEntry() { var = entry.getDeclaration() }
7777

7878
override LocalVariable getVariable() { result = var }
7979
}
@@ -86,10 +86,10 @@ class TranslatedAutoVariableDeclarationEntry extends TranslatedLocalVariableDecl
8686
* `TranslatedStaticLocalVariableInitialization`, which is a child of this element.
8787
*/
8888
class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclarationEntry {
89-
LocalVariable var;
89+
StaticLocalVariable var;
9090

9191
TranslatedStaticLocalVariableDeclarationEntry() {
92-
var = entry.getDeclaration() and var.isStatic()
92+
var = entry.getDeclaration()
9393
}
9494

9595
final override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
@@ -197,7 +197,7 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio
197197
class TranslatedStaticLocalVariableInitialization extends TranslatedElement,
198198
TranslatedLocalVariableDeclaration, TTranslatedStaticLocalVariableInitialization {
199199
VariableDeclarationEntry entry;
200-
LocalVariable var;
200+
StaticLocalVariable var;
201201

202202
TranslatedStaticLocalVariableInitialization() {
203203
this = TTranslatedStaticLocalVariableInitialization(entry) and

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ newtype TTranslatedElement =
403403
not var.isStatic()
404404
or
405405
// Ignore static variables unless they have a dynamic initializer.
406-
var.(StaticStorageDurationVariable).hasDynamicInitialization()
406+
var.(StaticLocalVariable).hasDynamicInitialization()
407407
)
408408
)
409409
} or
@@ -412,7 +412,7 @@ newtype TTranslatedElement =
412412
TTranslatedStaticLocalVariableInitialization(DeclarationEntry entry) {
413413
exists(TTranslatedDeclarationEntry translatedEntry |
414414
translatedEntry = TTranslatedDeclarationEntry(entry) and
415-
entry.getDeclaration().(LocalVariable).isStatic()
415+
entry.getDeclaration() instanceof StaticLocalVariable
416416
)
417417
} or
418418
// A compiler-generated variable to implement a range-based for loop. These don't have a

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,14 @@ abstract class TranslatedVariableInitialization extends TranslatedElement, Initi
115115
* evaluating the initializer.
116116
*/
117117
final predicate hasUninitializedInstruction() {
118-
not exists(getInitialization()) or
119-
getInitialization() instanceof TranslatedListInitialization or
120-
getInitialization() instanceof TranslatedConstructorInitialization or
121-
getInitialization().(TranslatedStringLiteralInitialization).zeroInitRange(_, _)
118+
(
119+
not exists(getInitialization()) or
120+
getInitialization() instanceof TranslatedListInitialization or
121+
getInitialization() instanceof TranslatedConstructorInitialization or
122+
getInitialization().(TranslatedStringLiteralInitialization).zeroInitRange(_, _)
123+
) and
124+
// Variables with static or thread-local storage duration are zero-initialized at program startup.
125+
getIRVariable() instanceof IRAutomaticVariable
122126
}
123127
}
124128

cpp/ql/test/library-tests/ir/ir/PrintAST.expected

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8367,6 +8367,43 @@ ir.cpp:
83678367
# 1228| 1: [VariableAccess] d
83688368
# 1228| Type = [IntType] int
83698369
# 1228| ValueCategory = prvalue(load)
8370+
# 1231| [TopLevelFunction] void staticLocalWithConstructor(char const*)
8371+
# 1231| params:
8372+
# 1231| 0: [Parameter] dynamic
8373+
# 1231| Type = [PointerType] const char *
8374+
# 1231| body: [Block] { ... }
8375+
# 1232| 0: [DeclStmt] declaration
8376+
# 1232| 0: [VariableDeclarationEntry] definition of a
8377+
# 1232| Type = [Struct] String
8378+
#-----| init: [Initializer] initializer for a
8379+
#-----| expr: [ConstructorCall] call to String
8380+
#-----| Type = [VoidType] void
8381+
#-----| ValueCategory = prvalue
8382+
# 1233| 1: [DeclStmt] declaration
8383+
# 1233| 0: [VariableDeclarationEntry] definition of b
8384+
# 1233| Type = [Struct] String
8385+
# 1233| init: [Initializer] initializer for b
8386+
# 1233| expr: [ConstructorCall] call to String
8387+
# 1233| Type = [VoidType] void
8388+
# 1233| ValueCategory = prvalue
8389+
# 1233| 0: [ArrayToPointerConversion] array to pointer conversion
8390+
# 1233| Type = [PointerType] const char *
8391+
# 1233| ValueCategory = prvalue
8392+
# 1233| expr: static
8393+
# 1233| Type = [ArrayType] const char[7]
8394+
# 1233| Value = [StringLiteral] "static"
8395+
# 1233| ValueCategory = lvalue
8396+
# 1234| 2: [DeclStmt] declaration
8397+
# 1234| 0: [VariableDeclarationEntry] definition of c
8398+
# 1234| Type = [Struct] String
8399+
# 1234| init: [Initializer] initializer for c
8400+
# 1234| expr: [ConstructorCall] call to String
8401+
# 1234| Type = [VoidType] void
8402+
# 1234| ValueCategory = prvalue
8403+
# 1234| 0: [VariableAccess] dynamic
8404+
# 1234| Type = [PointerType] const char *
8405+
# 1234| ValueCategory = prvalue(load)
8406+
# 1235| 3: [ReturnStmt] return ...
83708407
perf-regression.cpp:
83718408
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
83728409
# 4| params:

cpp/ql/test/library-tests/ir/ir/ir.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,4 +1228,10 @@ int staticLocalInit(int x) {
12281228
return a + b + c + d;
12291229
}
12301230

1231+
void staticLocalWithConstructor(const char* dynamic) {
1232+
static String a;
1233+
static String b("static");
1234+
static String c(dynamic);
1235+
}
1236+
12311237
// semmle-extractor-options: -std=c++17 --clang

cpp/ql/test/library-tests/ir/ir/raw_ir.expected

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6271,6 +6271,82 @@ ir.cpp:
62716271
# 1225| mu1225_9(bool) = Store : &:r1225_1, r1225_8
62726272
#-----| Goto -> Block 1
62736273

6274+
# 1231| void staticLocalWithConstructor(char const*)
6275+
# 1231| Block 0
6276+
# 1231| v1231_1(void) = EnterFunction :
6277+
# 1231| mu1231_2(unknown) = AliasedDefinition :
6278+
# 1231| mu1231_3(unknown) = InitializeNonLocal :
6279+
# 1231| mu1231_4(unknown) = UnmodeledDefinition :
6280+
# 1231| r1231_5(glval<char *>) = VariableAddress[dynamic] :
6281+
# 1231| mu1231_6(char *) = InitializeParameter[dynamic] : &:r1231_5
6282+
# 1231| r1231_7(char *) = Load : &:r1231_5, ~mu1231_6
6283+
# 1231| mu1231_8(unknown) = InitializeIndirection[dynamic] : &:r1231_7
6284+
# 1232| r1232_1(glval<bool>) = VariableAddress[a#init] :
6285+
# 1232| r1232_2(bool) = Load : &:r1232_1, ~mu1231_4
6286+
# 1232| v1232_3(void) = ConditionalBranch : r1232_2
6287+
#-----| False -> Block 6
6288+
#-----| True -> Block 1
6289+
6290+
# 1233| Block 1
6291+
# 1233| r1233_1(glval<bool>) = VariableAddress[b#init] :
6292+
# 1233| r1233_2(bool) = Load : &:r1233_1, ~mu1231_4
6293+
# 1233| v1233_3(void) = ConditionalBranch : r1233_2
6294+
#-----| False -> Block 2
6295+
#-----| True -> Block 3
6296+
6297+
# 1233| Block 2
6298+
# 1233| r1233_4(glval<String>) = VariableAddress[b] :
6299+
# 1233| r1233_5(glval<unknown>) = FunctionAddress[String] :
6300+
# 1233| r1233_6(glval<char[7]>) = StringConstant["static"] :
6301+
# 1233| r1233_7(char *) = Convert : r1233_6
6302+
# 1233| v1233_8(void) = Call : func:r1233_5, this:r1233_4, 0:r1233_7
6303+
# 1233| mu1233_9(unknown) = ^CallSideEffect : ~mu1231_4
6304+
# 1233| mu1233_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1233_4
6305+
# 1233| v1233_11(void) = ^BufferReadSideEffect[0] : &:r1233_7, ~mu1231_4
6306+
# 1233| mu1233_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r1233_7
6307+
# 1233| r1233_13(bool) = Constant[1] :
6308+
# 1233| mu1233_14(bool) = Store : &:r1233_1, r1233_13
6309+
#-----| Goto -> Block 3
6310+
6311+
# 1234| Block 3
6312+
# 1234| r1234_1(glval<bool>) = VariableAddress[c#init] :
6313+
# 1234| r1234_2(bool) = Load : &:r1234_1, ~mu1231_4
6314+
# 1234| v1234_3(void) = ConditionalBranch : r1234_2
6315+
#-----| False -> Block 4
6316+
#-----| True -> Block 5
6317+
6318+
# 1234| Block 4
6319+
# 1234| r1234_4(glval<String>) = VariableAddress[c] :
6320+
# 1234| r1234_5(glval<unknown>) = FunctionAddress[String] :
6321+
# 1234| r1234_6(glval<char *>) = VariableAddress[dynamic] :
6322+
# 1234| r1234_7(char *) = Load : &:r1234_6, ~mu1231_4
6323+
# 1234| v1234_8(void) = Call : func:r1234_5, this:r1234_4, 0:r1234_7
6324+
# 1234| mu1234_9(unknown) = ^CallSideEffect : ~mu1231_4
6325+
# 1234| mu1234_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1234_4
6326+
# 1234| v1234_11(void) = ^BufferReadSideEffect[0] : &:r1234_7, ~mu1231_4
6327+
# 1234| mu1234_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r1234_7
6328+
# 1234| r1234_13(bool) = Constant[1] :
6329+
# 1234| mu1234_14(bool) = Store : &:r1234_1, r1234_13
6330+
#-----| Goto -> Block 5
6331+
6332+
# 1235| Block 5
6333+
# 1235| v1235_1(void) = NoOp :
6334+
# 1231| v1231_9(void) = ReturnIndirection : &:r1231_7, ~mu1231_4
6335+
# 1231| v1231_10(void) = ReturnVoid :
6336+
# 1231| v1231_11(void) = UnmodeledUse : mu*
6337+
# 1231| v1231_12(void) = AliasedUse : ~mu1231_4
6338+
# 1231| v1231_13(void) = ExitFunction :
6339+
6340+
# 1232| Block 6
6341+
# 1232| r1232_4(glval<String>) = VariableAddress[a] :
6342+
#-----| r0_1(glval<unknown>) = FunctionAddress[String] :
6343+
#-----| v0_2(void) = Call : func:r0_1, this:r1232_4
6344+
#-----| mu0_3(unknown) = ^CallSideEffect : ~mu1231_4
6345+
#-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r1232_4
6346+
# 1232| r1232_5(bool) = Constant[1] :
6347+
# 1232| mu1232_6(bool) = Store : &:r1232_1, r1232_5
6348+
#-----| Goto -> Block 1
6349+
62746350
perf-regression.cpp:
62756351
# 6| void Big::Big()
62766352
# 6| Block 0
@@ -6430,26 +6506,25 @@ struct_init.cpp:
64306506

64316507
# 37| Block 2
64326508
# 37| r37_4(glval<Info[2]>) = VariableAddress[static_infos] :
6433-
# 37| mu37_5(Info[2]) = Uninitialized[static_infos] : &:r37_4
6434-
# 37| r37_6(int) = Constant[0] :
6435-
# 37| r37_7(glval<Info>) = PointerAdd[16] : r37_4, r37_6
6436-
# 38| r38_1(glval<char *>) = FieldAddress[name] : r37_7
6509+
# 37| r37_5(int) = Constant[0] :
6510+
# 37| r37_6(glval<Info>) = PointerAdd[16] : r37_4, r37_5
6511+
# 38| r38_1(glval<char *>) = FieldAddress[name] : r37_6
64376512
# 38| r38_2(glval<char *>) = VariableAddress[name1] :
64386513
# 38| r38_3(char *) = Load : &:r38_2, ~mu36_4
64396514
# 38| mu38_4(char *) = Store : &:r38_1, r38_3
6440-
# 38| r38_5(glval<..(*)(..)>) = FieldAddress[handler] : r37_7
6515+
# 38| r38_5(glval<..(*)(..)>) = FieldAddress[handler] : r37_6
64416516
# 38| r38_6(..(*)(..)) = FunctionAddress[handler1] :
64426517
# 38| mu38_7(..(*)(..)) = Store : &:r38_5, r38_6
6443-
# 37| r37_8(int) = Constant[1] :
6444-
# 37| r37_9(glval<Info>) = PointerAdd[16] : r37_4, r37_8
6445-
# 39| r39_1(glval<char *>) = FieldAddress[name] : r37_9
6518+
# 37| r37_7(int) = Constant[1] :
6519+
# 37| r37_8(glval<Info>) = PointerAdd[16] : r37_4, r37_7
6520+
# 39| r39_1(glval<char *>) = FieldAddress[name] : r37_8
64466521
# 39| r39_2(glval<char[2]>) = StringConstant["2"] :
64476522
# 39| r39_3(char *) = Convert : r39_2
64486523
# 39| mu39_4(char *) = Store : &:r39_1, r39_3
6449-
# 39| r39_5(glval<..(*)(..)>) = FieldAddress[handler] : r37_9
6524+
# 39| r39_5(glval<..(*)(..)>) = FieldAddress[handler] : r37_8
64506525
# 39| r39_6(glval<..()(..)>) = FunctionAddress[handler2] :
64516526
# 39| r39_7(..(*)(..)) = CopyValue : r39_6
64526527
# 39| mu39_8(..(*)(..)) = Store : &:r39_5, r39_7
6453-
# 37| r37_10(bool) = Constant[1] :
6454-
# 37| mu37_11(bool) = Store : &:r37_1, r37_10
6528+
# 37| r37_9(bool) = Constant[1] :
6529+
# 37| mu37_10(bool) = Store : &:r37_1, r37_9
64556530
#-----| Goto -> Block 1

cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@
137137
| test.c:109:14:109:16 | Constant: 44 | positive strictlyPositive |
138138
| test.c:110:14:110:14 | Constant: 1 | positive strictlyPositive |
139139
| test.c:110:14:110:14 | Store: 1 | positive strictlyPositive |
140-
| test.c:118:20:118:20 | Uninitialized: definition of n | positive |
141140
| test.c:119:10:119:10 | Load: n | positive |
142141
| test.c:119:10:119:12 | Add: ... ++ | positive strictlyPositive |
143142
| test.c:119:10:119:12 | Constant: ... ++ | positive strictlyPositive |

0 commit comments

Comments
 (0)