mirror of
https://github.com/github/codeql.git
synced 2026-05-02 12:15:17 +02:00
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.
This commit is contained in:
@@ -366,6 +366,47 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable whose contents always have static storage duration. This can be a
|
||||
* global variable, a namespace variable, a static local variable, or a static
|
||||
* member variable.
|
||||
*/
|
||||
class StaticStorageDurationVariable extends Variable {
|
||||
StaticStorageDurationVariable() {
|
||||
this instanceof GlobalOrNamespaceVariable
|
||||
or
|
||||
this.(LocalVariable).isStatic()
|
||||
or
|
||||
this.(MemberVariable).isStatic()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the initializer for this variable is evaluated at compile time.
|
||||
*/
|
||||
predicate hasConstantInitialization() {
|
||||
not runtimeExprInStaticInitializer(this.getInitializer().getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is an expression in a static initializer that must be evaluated
|
||||
* at run time. This predicate computes "is non-const" instead of "is const"
|
||||
* since computing "is const" for an aggregate literal with many children would
|
||||
* either involve recursion through `forall` on those children or an iteration
|
||||
* through the rank numbers of the children, both of which can be slow.
|
||||
*/
|
||||
private predicate runtimeExprInStaticInitializer(Expr e) {
|
||||
inStaticInitializer(e) and
|
||||
if e instanceof AggregateLiteral
|
||||
then runtimeExprInStaticInitializer(e.getAChild())
|
||||
else not e.getFullyConverted().isConstant()
|
||||
}
|
||||
|
||||
/** Holds if `e` is part of the initializer of a `StaticStorageDurationVariable`. */
|
||||
private predicate inStaticInitializer(Expr e) {
|
||||
exists(StaticStorageDurationVariable var | e.getParent+() = var.getInitializer())
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ variable which has global scope or namespace scope. For example the
|
||||
* variables `a` and `b` in the following code:
|
||||
|
||||
@@ -443,8 +443,7 @@ private Node getControlOrderChildSparse(Node n, int i) {
|
||||
private predicate skipInitializer(Initializer init) {
|
||||
exists(LocalVariable local |
|
||||
init = local.getInitializer() and
|
||||
local.isStatic() and
|
||||
not runtimeExprInStaticInitializer(init.getExpr())
|
||||
local.(StaticStorageDurationVariable).hasConstantInitialization()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,37 +31,6 @@ private Element getRealParent(Expr expr) {
|
||||
*/
|
||||
predicate isIRConstant(Expr expr) { exists(expr.getValue()) }
|
||||
|
||||
/**
|
||||
* Holds if the expression in this initializer is evaluated at compile time.
|
||||
*/
|
||||
private predicate skipInitializer(Initializer init) {
|
||||
exists(LocalVariable local |
|
||||
init = local.getInitializer() and
|
||||
local.isStatic() and
|
||||
not runtimeExprInStaticInitializer(init.getExpr())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is an expression in a static initializer that must be evaluated
|
||||
* at run time. This predicate computes "is non-const" instead of "is const" in
|
||||
* order to avoid recursion through forall.
|
||||
*/
|
||||
private predicate runtimeExprInStaticInitializer(Expr e) {
|
||||
inStaticInitializer(e) and
|
||||
if e instanceof AggregateLiteral
|
||||
then runtimeExprInStaticInitializer(e.getAChild())
|
||||
else not e.getFullyConverted().isConstant()
|
||||
}
|
||||
|
||||
/** Holds if `e` is part of the initializer of a local static variable. */
|
||||
private predicate inStaticInitializer(Expr e) {
|
||||
exists(LocalVariable local |
|
||||
local.isStatic() and
|
||||
e.getParent+() = local.getInitializer()
|
||||
)
|
||||
}
|
||||
|
||||
// Pulled out to work around QL-796
|
||||
private predicate isOrphan(Expr expr) { not exists(getRealParent(expr)) }
|
||||
|
||||
@@ -83,8 +52,9 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
or
|
||||
// Only translate the initializer of a static local if it uses run-time data.
|
||||
// Otherwise the initializer does not run in function scope.
|
||||
exists(Initializer init |
|
||||
skipInitializer(init) and
|
||||
exists(Initializer init, StaticStorageDurationVariable var |
|
||||
init = var.getInitializer() and
|
||||
var.hasConstantInitialization() and
|
||||
expr = init.getExpr().getFullyConverted()
|
||||
)
|
||||
or
|
||||
|
||||
Reference in New Issue
Block a user