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

Skip to content

Commit 5e01b4b

Browse files
committed
C++: Share the constant initializer detection
Since this code is shared between the AST CFG and the IR construction, it seems right to have only one copy. That copy lives on a new class `StaticStorageDurationVariable`, which may prove useful on its own.
1 parent 0cd3eb7 commit 5e01b4b

3 files changed

Lines changed: 45 additions & 35 deletions

File tree

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,47 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
366366
}
367367
}
368368

369+
/**
370+
* A variable whose contents always have static storage duration. This can be a
371+
* global variable, a namespace variable, a static local variable, or a static
372+
* member variable.
373+
*/
374+
class StaticStorageDurationVariable extends Variable {
375+
StaticStorageDurationVariable() {
376+
this instanceof GlobalOrNamespaceVariable
377+
or
378+
this.(LocalVariable).isStatic()
379+
or
380+
this.(MemberVariable).isStatic()
381+
}
382+
383+
/**
384+
* Holds if the initializer for this variable is evaluated at compile time.
385+
*/
386+
predicate hasConstantInitialization() {
387+
not runtimeExprInStaticInitializer(this.getInitializer().getExpr())
388+
}
389+
}
390+
391+
/**
392+
* Holds if `e` is an expression in a static initializer that must be evaluated
393+
* at run time. This predicate computes "is non-const" instead of "is const"
394+
* since computing "is const" for an aggregate literal with many children would
395+
* either involve recursion through `forall` on those children or an iteration
396+
* through the rank numbers of the children, both of which can be slow.
397+
*/
398+
private predicate runtimeExprInStaticInitializer(Expr e) {
399+
inStaticInitializer(e) and
400+
if e instanceof AggregateLiteral
401+
then runtimeExprInStaticInitializer(e.getAChild())
402+
else not e.getFullyConverted().isConstant()
403+
}
404+
405+
/** Holds if `e` is part of the initializer of a `StaticStorageDurationVariable`. */
406+
private predicate inStaticInitializer(Expr e) {
407+
exists(StaticStorageDurationVariable var | e.getParent+() = var.getInitializer())
408+
}
409+
369410
/**
370411
* A C/C++ variable which has global scope or namespace scope. For example the
371412
* variables `a` and `b` in the following code:

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,7 @@ private Node getControlOrderChildSparse(Node n, int i) {
443443
private predicate skipInitializer(Initializer init) {
444444
exists(LocalVariable local |
445445
init = local.getInitializer() and
446-
local.isStatic() and
447-
not runtimeExprInStaticInitializer(init.getExpr())
446+
local.(StaticStorageDurationVariable).hasConstantInitialization()
448447
)
449448
}
450449

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

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -31,37 +31,6 @@ private Element getRealParent(Expr expr) {
3131
*/
3232
predicate isIRConstant(Expr expr) { exists(expr.getValue()) }
3333

34-
/**
35-
* Holds if the expression in this initializer is evaluated at compile time.
36-
*/
37-
private predicate skipInitializer(Initializer init) {
38-
exists(LocalVariable local |
39-
init = local.getInitializer() and
40-
local.isStatic() and
41-
not runtimeExprInStaticInitializer(init.getExpr())
42-
)
43-
}
44-
45-
/**
46-
* Holds if `e` is an expression in a static initializer that must be evaluated
47-
* at run time. This predicate computes "is non-const" instead of "is const" in
48-
* order to avoid recursion through forall.
49-
*/
50-
private predicate runtimeExprInStaticInitializer(Expr e) {
51-
inStaticInitializer(e) and
52-
if e instanceof AggregateLiteral
53-
then runtimeExprInStaticInitializer(e.getAChild())
54-
else not e.getFullyConverted().isConstant()
55-
}
56-
57-
/** Holds if `e` is part of the initializer of a local static variable. */
58-
private predicate inStaticInitializer(Expr e) {
59-
exists(LocalVariable local |
60-
local.isStatic() and
61-
e.getParent+() = local.getInitializer()
62-
)
63-
}
64-
6534
// Pulled out to work around QL-796
6635
private predicate isOrphan(Expr expr) { not exists(getRealParent(expr)) }
6736

@@ -83,8 +52,9 @@ private predicate ignoreExprAndDescendants(Expr expr) {
8352
or
8453
// Only translate the initializer of a static local if it uses run-time data.
8554
// Otherwise the initializer does not run in function scope.
86-
exists(Initializer init |
87-
skipInitializer(init) and
55+
exists(Initializer init, StaticStorageDurationVariable var |
56+
init = var.getInitializer() and
57+
var.hasConstantInitialization() and
8858
expr = init.getExpr().getFullyConverted()
8959
)
9060
or

0 commit comments

Comments
 (0)