diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index 2e7fdd422af..68795215b13 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -17,4 +17,11 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. ## Changes to libraries -* +* The new class `StackVariable` should be used in place of `LocalScopeVariable` + in most cases. The difference is that `StackVariable` does not include + variables declared with `static` or `thread_local`. + * As a rule of thumb, custom queries about the _values_ of variables should + be changed from `LocalScopeVariable` to `StackVariable`, while queries + about the _name or scope_ of variables should remain unchanged. + * The `LocalScopeVariableReachability` library is deprecated in favor of + `StackVariableReachability`. The functionality is the same. diff --git a/cpp/ql/src/Critical/DeadCodeCondition.ql b/cpp/ql/src/Critical/DeadCodeCondition.ql index 45b4418f155..a769d3d4025 100644 --- a/cpp/ql/src/Critical/DeadCodeCondition.ql +++ b/cpp/ql/src/Critical/DeadCodeCondition.ql @@ -22,7 +22,7 @@ predicate testAndBranch(Expr e, Stmt branch) { ) } -predicate choice(LocalScopeVariable v, Stmt branch, string value) { +predicate choice(StackVariable v, Stmt branch, string value) { exists(AnalysedExpr e | testAndBranch(e, branch) and ( @@ -33,7 +33,7 @@ predicate choice(LocalScopeVariable v, Stmt branch, string value) { ) } -predicate guarded(LocalScopeVariable v, Stmt loopstart, AnalysedExpr child) { +predicate guarded(StackVariable v, Stmt loopstart, AnalysedExpr child) { choice(v, loopstart, _) and loopstart.getChildStmt*() = child.getEnclosingStmt() and (definition(v, child) or exists(child.getNullSuccessor(v))) @@ -47,9 +47,7 @@ predicate addressLeak(Variable v, Stmt leak) { ) } -from - LocalScopeVariable v, Stmt branch, AnalysedExpr cond, string context, string test, - string testresult +from StackVariable v, Stmt branch, AnalysedExpr cond, string context, string test, string testresult where choice(v, branch, context) and forall(ControlFlowNode def | definition(v, def) and definitionReaches(def, cond) | diff --git a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql index 47401c6eea5..135b9a644d1 100644 --- a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql +++ b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql @@ -23,14 +23,14 @@ predicate closeCall(FunctionCall fc, Variable v) { ) } -predicate openDefinition(LocalScopeVariable v, ControlFlowNode def) { +predicate openDefinition(StackVariable v, ControlFlowNode def) { exists(Expr expr | exprDefinition(v, def, expr) and allocateDescriptorCall(expr)) } predicate openReaches(ControlFlowNode def, ControlFlowNode node) { - exists(LocalScopeVariable v | openDefinition(v, def) and node = def.getASuccessor()) + exists(StackVariable v | openDefinition(v, def) and node = def.getASuccessor()) or - exists(LocalScopeVariable v, ControlFlowNode mid | + exists(StackVariable v, ControlFlowNode mid | openDefinition(v, def) and openReaches(def, mid) and not errorSuccessor(v, mid) and @@ -40,7 +40,7 @@ predicate openReaches(ControlFlowNode def, ControlFlowNode node) { ) } -predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) { +predicate assignedToFieldOrGlobal(StackVariable v, Assignment assign) { exists(Variable external | assign.getRValue() = v.getAnAccess() and assign.getLValue().(VariableAccess).getTarget() = external and @@ -48,7 +48,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) { ) } -from LocalScopeVariable v, ControlFlowNode def, ReturnStmt ret +from StackVariable v, ControlFlowNode def, ReturnStmt ret where openDefinition(v, def) and openReaches(def, ret) and diff --git a/cpp/ql/src/Critical/FileMayNotBeClosed.ql b/cpp/ql/src/Critical/FileMayNotBeClosed.ql index fefe43aa845..c97e7cacca3 100644 --- a/cpp/ql/src/Critical/FileMayNotBeClosed.ql +++ b/cpp/ql/src/Critical/FileMayNotBeClosed.ql @@ -10,7 +10,7 @@ */ import FileClosed -import semmle.code.cpp.controlflow.LocalScopeVariableReachability +import semmle.code.cpp.controlflow.StackVariableReachability /** * Extend the NullValue class used by Nullness.qll to include simple -1 as a 'null' value @@ -68,18 +68,18 @@ predicate fcloseCallOrIndirect(FunctionCall fc, Variable v) { ) } -predicate fopenDefinition(LocalScopeVariable v, ControlFlowNode def) { +predicate fopenDefinition(StackVariable v, ControlFlowNode def) { exists(Expr expr | exprDefinition(v, def, expr) and fopenCallOrIndirect(expr)) } -class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassignment { +class FOpenVariableReachability extends StackVariableReachabilityWithReassignment { FOpenVariableReachability() { this = "FOpenVariableReachability" } - override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSourceActual(ControlFlowNode node, StackVariable v) { fopenDefinition(v, node) } - override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSinkActual(ControlFlowNode node, StackVariable v) { // node may be used in fopenReaches exists(node.(AnalysedExpr).getNullSuccessor(v)) or fcloseCallOrIndirect(node, v) or @@ -88,15 +88,13 @@ class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassi v.getFunction() = node.(ReturnStmt).getEnclosingFunction() } - override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) { - definitionBarrier(v, node) - } + override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) } } /** * The value from fopen at `def` is still held in Variable `v` upon entering `node`. */ -predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) { +predicate fopenVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) { exists(FOpenVariableReachability r | // reachability r.reachesTo(def, _, node, v) @@ -107,25 +105,23 @@ predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, Contro ) } -class FOpenReachability extends LocalScopeVariableReachabilityExt { +class FOpenReachability extends StackVariableReachabilityExt { FOpenReachability() { this = "FOpenReachability" } - override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { - fopenDefinition(v, node) - } + override predicate isSource(ControlFlowNode node, StackVariable v) { fopenDefinition(v, node) } - override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSink(ControlFlowNode node, StackVariable v) { v.getFunction() = node.(ReturnStmt).getEnclosingFunction() } override predicate isBarrier( - ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v + ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v ) { isSource(source, v) and next = node.getASuccessor() and // the file (stored in any variable `v0`) opened at `source` is closed or // assigned to a global at node, or NULL checked on the edge node -> next. - exists(LocalScopeVariable v0 | fopenVariableReaches(v0, source, node) | + exists(StackVariable v0 | fopenVariableReaches(v0, source, node) | node.(AnalysedExpr).getNullSuccessor(v0) = next or fcloseCallOrIndirect(node, v0) or assignedToFieldOrGlobal(v0, node) @@ -142,11 +138,11 @@ predicate fopenReaches(ControlFlowNode def, ControlFlowNode node) { exists(FOpenReachability r | r.reaches(def, _, node)) } -predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) { - // assigned to anything except a LocalScopeVariable +predicate assignedToFieldOrGlobal(StackVariable v, Expr e) { + // assigned to anything except a StackVariable // (typically a field or global, but for example also *ptr = v) e.(Assignment).getRValue() = v.getAnAccess() and - not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable + not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable or exists(Expr midExpr, Function mid, int arg | // indirect assignment @@ -163,7 +159,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) { from ControlFlowNode def, ReturnStmt ret where fopenReaches(def, ret) and - not exists(LocalScopeVariable v | + not exists(StackVariable v | fopenVariableReaches(v, def, ret) and ret.getAChild*() = v.getAnAccess() ) diff --git a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql index 52d551f6bfd..86e2cb4fb29 100644 --- a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql +++ b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql @@ -11,7 +11,7 @@ import cpp -from LocalScopeVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked +from StackVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked where checked = v.getAnAccess() and dereferenced(checked) and diff --git a/cpp/ql/src/Critical/LateNegativeTest.ql b/cpp/ql/src/Critical/LateNegativeTest.ql index f7693d5c28e..098a224c818 100644 --- a/cpp/ql/src/Critical/LateNegativeTest.ql +++ b/cpp/ql/src/Critical/LateNegativeTest.ql @@ -13,7 +13,7 @@ import cpp -predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) { +predicate negativeCheck(StackVariable v, ComparisonOperation op) { exists(int varindex, string constant, Literal lit | op.getChild(varindex) = v.getAnAccess() and op.getChild(1 - varindex) = lit and @@ -38,7 +38,7 @@ predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) { ) } -from LocalScopeVariable v, ArrayExpr dangerous, Expr check +from StackVariable v, ArrayExpr dangerous, Expr check where useUsePair(v, dangerous.getArrayOffset(), check.getAChild()) and negativeCheck(v, check) and diff --git a/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql b/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql index 2bede681912..b60fa917e9a 100644 --- a/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql +++ b/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql @@ -10,7 +10,7 @@ */ import MemoryFreed -import semmle.code.cpp.controlflow.LocalScopeVariableReachability +import semmle.code.cpp.controlflow.StackVariableReachability /** * 'call' is either a direct call to f, or a possible call to f @@ -97,18 +97,18 @@ predicate freeCallOrIndirect(ControlFlowNode n, Variable v) { ) } -predicate allocationDefinition(LocalScopeVariable v, ControlFlowNode def) { +predicate allocationDefinition(StackVariable v, ControlFlowNode def) { exists(Expr expr | exprDefinition(v, def, expr) and allocCallOrIndirect(expr)) } -class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassignment { +class AllocVariableReachability extends StackVariableReachabilityWithReassignment { AllocVariableReachability() { this = "AllocVariableReachability" } - override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSourceActual(ControlFlowNode node, StackVariable v) { allocationDefinition(v, node) } - override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSinkActual(ControlFlowNode node, StackVariable v) { // node may be used in allocationReaches exists(node.(AnalysedExpr).getNullSuccessor(v)) or freeCallOrIndirect(node, v) or @@ -117,15 +117,13 @@ class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassi v.getFunction() = node.(ReturnStmt).getEnclosingFunction() } - override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) { - definitionBarrier(v, node) - } + override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) } } /** * The value from allocation `def` is still held in Variable `v` upon entering `node`. */ -predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) { +predicate allocatedVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) { exists(AllocVariableReachability r | // reachability r.reachesTo(def, _, node, v) @@ -136,25 +134,25 @@ predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, Co ) } -class AllocReachability extends LocalScopeVariableReachabilityExt { +class AllocReachability extends StackVariableReachabilityExt { AllocReachability() { this = "AllocReachability" } - override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSource(ControlFlowNode node, StackVariable v) { allocationDefinition(v, node) } - override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSink(ControlFlowNode node, StackVariable v) { v.getFunction() = node.(ReturnStmt).getEnclosingFunction() } override predicate isBarrier( - ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v + ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v ) { isSource(source, v) and next = node.getASuccessor() and // the memory (stored in any variable `v0`) allocated at `source` is freed or // assigned to a global at node, or NULL checked on the edge node -> next. - exists(LocalScopeVariable v0 | allocatedVariableReaches(v0, source, node) | + exists(StackVariable v0 | allocatedVariableReaches(v0, source, node) | node.(AnalysedExpr).getNullSuccessor(v0) = next or freeCallOrIndirect(node, v0) or assignedToFieldOrGlobal(v0, node) @@ -171,11 +169,11 @@ predicate allocationReaches(ControlFlowNode def, ControlFlowNode node) { exists(AllocReachability r | r.reaches(def, _, node)) } -predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) { - // assigned to anything except a LocalScopeVariable +predicate assignedToFieldOrGlobal(StackVariable v, Expr e) { + // assigned to anything except a StackVariable // (typically a field or global, but for example also *ptr = v) e.(Assignment).getRValue() = v.getAnAccess() and - not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable + not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable or exists(Expr midExpr, Function mid, int arg | // indirect assignment @@ -192,7 +190,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) { from ControlFlowNode def, ReturnStmt ret where allocationReaches(def, ret) and - not exists(LocalScopeVariable v | + not exists(StackVariable v | allocatedVariableReaches(v, def, ret) and ret.getAChild*() = v.getAnAccess() ) diff --git a/cpp/ql/src/Critical/MissingNegativityTest.ql b/cpp/ql/src/Critical/MissingNegativityTest.ql index e351cba163e..565217578e0 100644 --- a/cpp/ql/src/Critical/MissingNegativityTest.ql +++ b/cpp/ql/src/Critical/MissingNegativityTest.ql @@ -43,7 +43,7 @@ class FunctionWithNegativeReturn extends Function { predicate dangerousUse(IntegralReturnValue val, Expr use) { exists(ArrayExpr ae | ae.getArrayOffset() = val and use = val) or - exists(LocalScopeVariable v, ControlFlowNode def, ArrayExpr ae | + exists(StackVariable v, ControlFlowNode def, ArrayExpr ae | exprDefinition(v, def, val) and use = ae.getArrayOffset() and not boundsChecked(v, use) and @@ -54,7 +54,7 @@ predicate dangerousUse(IntegralReturnValue val, Expr use) { val = use and use.getType().getUnderlyingType() instanceof PointerType or - exists(LocalScopeVariable v, ControlFlowNode def, AddExpr add | + exists(StackVariable v, ControlFlowNode def, AddExpr add | exprDefinition(v, def, val) and definitionUsePair(v, def, use) and add.getAnOperand() = use and diff --git a/cpp/ql/src/Critical/NewDelete.qll b/cpp/ql/src/Critical/NewDelete.qll index 39b265556b0..691c9a1031d 100644 --- a/cpp/ql/src/Critical/NewDelete.qll +++ b/cpp/ql/src/Critical/NewDelete.qll @@ -60,7 +60,7 @@ predicate allocExprOrIndirect(Expr alloc, string kind) { pragma[nomagic] private predicate allocReachesVariable(Variable v, Expr alloc, string kind) { exists(Expr mid | - not v instanceof LocalScopeVariable and + not v instanceof StackVariable and v.getAnAssignedValue() = mid and allocReaches0(mid, alloc, kind) ) @@ -76,7 +76,7 @@ private predicate allocReaches0(Expr e, Expr alloc, string kind) { allocExprOrIndirect(alloc, kind) and e = alloc or - exists(SsaDefinition def, LocalScopeVariable v | + exists(SsaDefinition def, StackVariable v | // alloc via SSA allocReaches0(def.getAnUltimateDefiningValue(v), alloc, kind) and e = def.getAUse(v) diff --git a/cpp/ql/src/Critical/OverflowCalculated.ql b/cpp/ql/src/Critical/OverflowCalculated.ql index fbca4a20a8f..c60ed7a610d 100644 --- a/cpp/ql/src/Critical/OverflowCalculated.ql +++ b/cpp/ql/src/Critical/OverflowCalculated.ql @@ -18,7 +18,7 @@ class MallocCall extends FunctionCall { Expr getAllocatedSize() { if this.getArgument(0) instanceof VariableAccess then - exists(LocalScopeVariable v, ControlFlowNode def | + exists(StackVariable v, ControlFlowNode def | definitionUsePair(v, def, this.getArgument(0)) and exprDefinition(v, def, result) ) diff --git a/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql b/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql index 6d5cf2a58cc..353e51daa71 100644 --- a/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql +++ b/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql @@ -20,11 +20,10 @@ class ReturnPointsToExpr extends PointsToExpr { ReturnStmt getReturnStmt() { result.getExpr().getFullyConverted() = this } } -from ReturnPointsToExpr ret, LocalVariable local, float confidence +from ReturnPointsToExpr ret, StackVariable local, float confidence where ret.pointsTo() = local and ret.getReturnStmt().getEnclosingFunction() = local.getFunction() and - not local.isStatic() and confidence = ret.confidence() and confidence > 0.01 select ret, diff --git a/cpp/ql/src/Critical/Unused.ql b/cpp/ql/src/Critical/Unused.ql index 8046d47c746..89ebde29171 100644 --- a/cpp/ql/src/Critical/Unused.ql +++ b/cpp/ql/src/Critical/Unused.ql @@ -20,11 +20,10 @@ class ScopeUtilityClass extends Class { Call getAUse() { result = this.getAConstructor().getACallToThisFunction() } } -from LocalScopeVariable v, ControlFlowNode def +from StackVariable v, ControlFlowNode def where definition(v, def) and not definitionUsePair(v, def, _) and - not v.isStatic() and not v.getAnAccess().isAddressOfAccess() and // parameter initializers are not in the call-graph at the moment not v.(Parameter).getInitializer().getExpr() = def and diff --git a/cpp/ql/src/Critical/UseAfterFree.ql b/cpp/ql/src/Critical/UseAfterFree.ql index 9efbb6c3b44..8fd228ca7e4 100644 --- a/cpp/ql/src/Critical/UseAfterFree.ql +++ b/cpp/ql/src/Critical/UseAfterFree.ql @@ -10,10 +10,10 @@ */ import cpp -import semmle.code.cpp.controlflow.LocalScopeVariableReachability +import semmle.code.cpp.controlflow.StackVariableReachability /** `e` is an expression that frees the memory pointed to by `v`. */ -predicate isFreeExpr(Expr e, LocalScopeVariable v) { +predicate isFreeExpr(Expr e, StackVariable v) { exists(VariableAccess va | va.getTarget() = v | exists(FunctionCall fc | fc = e | fc.getTarget().hasGlobalOrStdName("free") and @@ -27,7 +27,7 @@ predicate isFreeExpr(Expr e, LocalScopeVariable v) { } /** `e` is an expression that (may) dereference `v`. */ -predicate isDerefExpr(Expr e, LocalScopeVariable v) { +predicate isDerefExpr(Expr e, StackVariable v) { v.getAnAccess() = e and dereferenced(e) or isDerefByCallExpr(_, _, e, v) @@ -39,27 +39,27 @@ predicate isDerefExpr(Expr e, LocalScopeVariable v) { * or a source code function that dereferences the relevant * parameter. */ -predicate isDerefByCallExpr(Call c, int i, VariableAccess va, LocalScopeVariable v) { +predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) { v.getAnAccess() = va and va = c.getAnArgumentSubExpr(i) and not c.passesByReference(i, va) and (c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i))) } -class UseAfterFreeReachability extends LocalScopeVariableReachability { +class UseAfterFreeReachability extends StackVariableReachability { UseAfterFreeReachability() { this = "UseAfterFree" } - override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { isFreeExpr(node, v) } + override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) } - override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { isDerefExpr(node, v) } + override predicate isSink(ControlFlowNode node, StackVariable v) { isDerefExpr(node, v) } - override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) { + override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) or isFreeExpr(node, v) } } -from UseAfterFreeReachability r, LocalScopeVariable v, Expr free, Expr e +from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e where r.reaches(free, v, e) select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@", free, "here" diff --git a/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql b/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql index 6a0098df131..029f11dd8c6 100644 --- a/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql +++ b/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql @@ -37,7 +37,7 @@ predicate flowsToExprImpl(Expr source, Expr sink, boolean pathMightOverflow) { pathMightOverflow = false and source.(FunctionCall).getTarget().(Snprintf).returnsFullFormatLength() or - exists(RangeSsaDefinition def, LocalScopeVariable v | + exists(RangeSsaDefinition def, StackVariable v | flowsToDef(source, def, v, pathMightOverflow) and sink = def.getAUse(v) ) @@ -63,9 +63,7 @@ predicate flowsToExprImpl(Expr source, Expr sink, boolean pathMightOverflow) { * `pathMightOverflow` is true if there is an arithmetic operation * on the path that might overflow. */ -predicate flowsToDef( - Expr source, RangeSsaDefinition def, LocalScopeVariable v, boolean pathMightOverflow -) { +predicate flowsToDef(Expr source, RangeSsaDefinition def, StackVariable v, boolean pathMightOverflow) { // Might the current definition overflow? exists(boolean otherMightOverflow | flowsToDefImpl(source, def, v, otherMightOverflow) | if defMightOverflow(def, v) @@ -86,7 +84,7 @@ predicate flowsToDef( * the path. But it is a good way to reduce the number of false positives. */ predicate flowsToDefImpl( - Expr source, RangeSsaDefinition def, LocalScopeVariable v, boolean pathMightOverflow + Expr source, RangeSsaDefinition def, StackVariable v, boolean pathMightOverflow ) { // Assignment or initialization: `e = v;` exists(Expr e | diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql b/cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql index 368171a1359..c25febfc6b7 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql @@ -12,24 +12,24 @@ */ import cpp -import semmle.code.cpp.controlflow.LocalScopeVariableReachability +import semmle.code.cpp.controlflow.StackVariableReachability -class UndefReachability extends LocalScopeVariableReachability { +class UndefReachability extends StackVariableReachability { UndefReachability() { this = "UndefReachability" } - override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSource(ControlFlowNode node, StackVariable v) { candidateVariable(v) and node = v.getParentScope() and not v instanceof Parameter and not v.hasInitializer() } - override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSink(ControlFlowNode node, StackVariable v) { candidateVariable(v) and node = v.getAnAccess() } - override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) { + override predicate isBarrier(ControlFlowNode node, StackVariable v) { node.(AssignExpr).getLValue() = v.getAnAccess() } } diff --git a/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql b/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql index 54392d105a6..2a4b2d16507 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql +++ b/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql @@ -11,7 +11,7 @@ */ import cpp -import semmle.code.cpp.controlflow.LocalScopeVariableReachability +import semmle.code.cpp.controlflow.StackVariableReachability import semmle.code.cpp.commons.NullTermination /** @@ -22,10 +22,10 @@ DeclStmt declWithNoInit(LocalVariable v) { not exists(v.getInitializer()) } -class ImproperNullTerminationReachability extends LocalScopeVariableReachabilityWithReassignment { +class ImproperNullTerminationReachability extends StackVariableReachabilityWithReassignment { ImproperNullTerminationReachability() { this = "ImproperNullTerminationReachability" } - override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSourceActual(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) or exists(Call c, VariableAccess va | @@ -36,12 +36,12 @@ class ImproperNullTerminationReachability extends LocalScopeVariableReachability ) } - override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) { + override predicate isSinkActual(ControlFlowNode node, StackVariable v) { node.(VariableAccess).getTarget() = v and variableMustBeNullTerminated(node) } - override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) { + override predicate isBarrier(ControlFlowNode node, StackVariable v) { exprDefinition(v, node, _) or mayAddNullTerminator(node, v.getAnAccess()) or isSinkActual(node, v) // only report first use diff --git a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql index d10addadca9..fc06ed0a500 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql +++ b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql @@ -42,10 +42,8 @@ predicate hasNontrivialConversion(Expr e) { hasNontrivialConversion(e.getConversion()) } -from LocalScopeVariable var, VariableAccess va, ReturnStmt r +from StackVariable var, VariableAccess va, ReturnStmt r where - not var.isStatic() and - not var.isThreadLocal() and not var.getUnspecifiedType() instanceof ReferenceType and not r.isFromUninstantiatedTemplate(_) and va = var.getAnAccess() and diff --git a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql index e213e9e461d..57dac90c850 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql +++ b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql @@ -12,7 +12,7 @@ */ import cpp -import semmle.code.cpp.controlflow.LocalScopeVariableReachability +import semmle.code.cpp.controlflow.StackVariableReachability /** * Auxiliary predicate: Types that don't require initialization @@ -40,23 +40,17 @@ DeclStmt declWithNoInit(LocalVariable v) { result.getADeclaration() = v and not exists(v.getInitializer()) and /* The type of the variable is not stack-allocated. */ - not allocatedType(v.getType()) and - /* The variable is not static (otherwise it is zeroed). */ - not v.isStatic() and - /* The variable is not extern (otherwise it is zeroed). */ - not v.hasSpecifier("extern") + not allocatedType(v.getType()) } -class UninitialisedLocalReachability extends LocalScopeVariableReachability { +class UninitialisedLocalReachability extends StackVariableReachability { UninitialisedLocalReachability() { this = "UninitialisedLocal" } - override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { - node = declWithNoInit(v) - } + override predicate isSource(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) } - override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { useOfVarActual(v, node) } + override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVarActual(v, node) } - override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) { + override predicate isBarrier(ControlFlowNode node, StackVariable v) { // only report the _first_ possibly uninitialized use useOfVarActual(v, node) or definitionBarrier(v, node) diff --git a/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql b/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql index 3d7379be507..c073cf37af8 100644 --- a/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql +++ b/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql @@ -16,7 +16,7 @@ private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils import semmle.code.cpp.security.TaintTracking predicate hasUpperBound(VariableAccess offsetExpr) { - exists(BasicBlock controlled, LocalScopeVariable offsetVar, SsaDefinition def | + exists(BasicBlock controlled, StackVariable offsetVar, SsaDefinition def | controlled.contains(offsetExpr) and linearBoundControls(controlled, def, offsetVar) and offsetExpr = def.getAUse(offsetVar) @@ -24,7 +24,7 @@ predicate hasUpperBound(VariableAccess offsetExpr) { } pragma[noinline] -predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, LocalScopeVariable offsetVar) { +predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, StackVariable offsetVar) { exists(GuardCondition guard, boolean branch | guard.controls(controlled, branch) and cmpWithLinearBound(guard, def.getAUse(offsetVar), Lesser(), branch) diff --git a/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql b/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql index 67b2f5c7eef..052cce56198 100644 --- a/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql +++ b/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql @@ -82,7 +82,7 @@ FunctionCall stat(Expr path, Expr buf) { predicate referenceTo(Expr source, Expr use) { source = use or - exists(SsaDefinition def, LocalScopeVariable v | + exists(SsaDefinition def, StackVariable v | def.getAnUltimateDefiningValue(v) = source and def.getAUse(v) = use ) } @@ -109,9 +109,7 @@ where ) ) and // checkUse and opUse refer to the same SSA variable - exists(SsaDefinition def, LocalScopeVariable v | - def.getAUse(v) = checkUse and def.getAUse(v) = opUse - ) and + exists(SsaDefinition def, StackVariable v | def.getAUse(v) = checkUse and def.getAUse(v) = opUse) and // opUse looks like an operation on a filename fc = filenameOperation(opUse) and // the return value of check is used (possibly with one step of diff --git a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingCommon.qll b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingCommon.qll index e2756de18fd..4854c1dc38e 100644 --- a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingCommon.qll +++ b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingCommon.qll @@ -100,9 +100,9 @@ Type baseType(Type t) { */ predicate exprSourceType(Expr use, Type sourceType, Location sourceLoc) { // Reaching definitions. - if exists(SsaDefinition def, LocalScopeVariable v | use = def.getAUse(v)) + if exists(SsaDefinition def, StackVariable v | use = def.getAUse(v)) then - exists(SsaDefinition def, LocalScopeVariable v | use = def.getAUse(v) | + exists(SsaDefinition def, StackVariable v | use = def.getAUse(v) | defSourceType(def, v, sourceType, sourceLoc) ) else @@ -137,7 +137,7 @@ predicate exprSourceType(Expr use, Type sourceType, Location sourceLoc) { * Holds if there is a pointer expression with type `sourceType` at * location `sourceLoc` which might define the value of `v` at `def`. */ -predicate defSourceType(SsaDefinition def, LocalScopeVariable v, Type sourceType, Location sourceLoc) { +predicate defSourceType(SsaDefinition def, StackVariable v, Type sourceType, Location sourceLoc) { exprSourceType(def.getDefiningValue(v), sourceType, sourceLoc) or defSourceType(def.getAPhiInput(v), v, sourceType, sourceLoc) diff --git a/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.ql b/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.ql index 8c62c5763aa..8cdeb486c1f 100644 --- a/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.ql +++ b/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.ql @@ -20,10 +20,9 @@ class ReturnPointsToExpr extends PointsToExpr { ReturnStmt getReturnStmt() { result.getExpr() = this } } -from ReturnPointsToExpr ret, LocalVariable dest +from ReturnPointsToExpr ret, StackVariable dest where ret.pointsTo() = dest and - ret.getReturnStmt().getParentStmt().getEnclosingFunction() = dest.getFunction() and - not dest.isStatic() + ret.getReturnStmt().getParentStmt().getEnclosingFunction() = dest.getFunction() select ret.getReturnStmt(), "AV Rule 111: A function shall not return a pointer or reference to a non-static local object." diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index 194cc5333c7..221a77f1a40 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -307,8 +307,8 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { * } * ``` * - * Local variables can be static; use the `isStatic` member predicate to - * detect those. + * See also `StackVariable`, which is the class of local-scope variables + * without statics and thread-locals. */ class LocalScopeVariable extends Variable, @localscopevariable { /** Gets the function to which this variable belongs. */ @@ -316,12 +316,21 @@ class LocalScopeVariable extends Variable, @localscopevariable { } /** - * DEPRECATED: use `LocalScopeVariable` instead. + * A C/C++ variable with _automatic storage duration_. In other words, a + * function parameter or a local variable that is not static or thread-local. + * For example, the variables `a` and `b` in the following code. + * ``` + * void myFunction(int a) { + * int b; + * static int c; + * } + * ``` */ -deprecated class StackVariable extends Variable { - StackVariable() { this instanceof LocalScopeVariable } - - Function getFunction() { result = this.(LocalScopeVariable).getFunction() } +class StackVariable extends LocalScopeVariable { + StackVariable() { + not this.isStatic() and + not this.isThreadLocal() + } } /** @@ -496,7 +505,7 @@ class TemplateVariable extends Variable { * `myTemplateFunction`: * ``` * void myFunction() { - * T a; + * float a; * } * * template @@ -509,9 +518,6 @@ class TemplateVariable extends Variable { * myTemplateFunction(); * ``` */ -class SemanticStackVariable extends LocalScopeVariable { - SemanticStackVariable() { - not this.isStatic() and - not this.isFromUninstantiatedTemplate(_) - } +class SemanticStackVariable extends StackVariable { + SemanticStackVariable() { not this.isFromUninstantiatedTemplate(_) } } diff --git a/cpp/ql/src/semmle/code/cpp/commons/NullTermination.qll b/cpp/ql/src/semmle/code/cpp/commons/NullTermination.qll index 650e2bc9954..38add4ab5ef 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/NullTermination.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/NullTermination.qll @@ -3,7 +3,7 @@ private import semmle.code.cpp.models.interfaces.ArrayFunction private import semmle.code.cpp.models.implementations.Strcat private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, Expr e0) { - exists(LocalScopeVariable v0, Expr val | + exists(StackVariable v0, Expr val | exprDefinition(v0, e, val) and val.getAChild*() = va and mayAddNullTerminator(e0, v0.getAnAccess()) @@ -41,7 +41,7 @@ predicate mayAddNullTerminator(Expr e, VariableAccess va) { or // Assignment to non-stack variable exists(AssignExpr ae | e = ae | - not ae.getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable and + not ae.getLValue().(VariableAccess).getTarget() instanceof StackVariable and ae.getRValue().getAChild*() = va ) or diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll b/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll index 0bac436d16e..1ab33c9a25c 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll @@ -1,5 +1,5 @@ import cpp -private import semmle.code.cpp.controlflow.LocalScopeVariableReachability +private import semmle.code.cpp.controlflow.StackVariableReachability private import semmle.code.cpp.dataflow.EscapesTree /** @@ -108,7 +108,7 @@ library class DefOrUse extends ControlFlowNodeBase { /* * Implementation detail: this predicate and its private auxiliary * predicates are instances of the more general predicates in - * LocalScopeVariableReachability.qll, and should be kept in sync. + * StackVariableReachability.qll, and should be kept in sync. * * Unfortunately, caching of abstract predicates does not work well, so the * predicates are duplicated for now. diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll index c64f724975d..007c1f2ecfc 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll @@ -371,7 +371,7 @@ private int int_value(Expr e) { /** An `SsaDefinition` with an additional predicate `isLt`. */ class GuardedSsa extends SsaDefinition { /** Holds if this `SsaDefinition` is guarded such that `this(var) < gt + k` is `testIsTrue` in `block`. */ - predicate isLt(LocalScopeVariable var, Expr gt, int k, BasicBlock block, boolean testIsTrue) { + predicate isLt(StackVariable var, Expr gt, int k, BasicBlock block, boolean testIsTrue) { exists(Expr luse, GuardCondition test | this.getAUse(var) = luse | test.ensuresLt(luse, gt, k, block, testIsTrue) ) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll b/cpp/ql/src/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll index 117854d39e6..32857146029 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll @@ -1,6 +1,12 @@ +/** + * DEPRECATED: Use `StackVariableReachability` instead. + */ + import cpp /** + * DEPRECATED: Use `StackVariableReachability` instead. + * * A reachability analysis for control-flow nodes involving stack variables. * This defines sources, sinks, and any other configurable aspect of the * analysis. Multiple analyses can coexist. To create an analysis, extend this @@ -18,7 +24,7 @@ import cpp * Then, to query whether there is flow between some source and sink, call the * `reaches` predicate on an instance of `MyAnalysisConfiguration`. */ -abstract class LocalScopeVariableReachability extends string { +abstract deprecated class LocalScopeVariableReachability extends string { bindingset[this] LocalScopeVariableReachability() { length() >= 0 } @@ -207,6 +213,8 @@ predicate bbSuccessorEntryReachesLoopInvariant( } /** + * DEPRECATED: Use `StackVariableReachabilityWithReassignment` instead. + * * Reachability analysis for control-flow nodes involving stack variables. * Unlike `LocalScopeVariableReachability`, this analysis takes variable * reassignments into account. @@ -216,7 +224,7 @@ predicate bbSuccessorEntryReachesLoopInvariant( * `isSource` and `isSink`, and that there is a `reachesTo` predicate in * addition to `reaches`. */ -abstract class LocalScopeVariableReachabilityWithReassignment extends LocalScopeVariableReachability { +abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends LocalScopeVariableReachability { bindingset[this] LocalScopeVariableReachabilityWithReassignment() { length() >= 0 } @@ -314,12 +322,14 @@ abstract class LocalScopeVariableReachabilityWithReassignment extends LocalScope } /** + * DEPRECATED: Use `StackVariableReachabilityExt` instead. + * * Same as `LocalScopeVariableReachability`, but `isBarrier` works on control-flow * edges rather than nodes and is therefore parameterized by the original * source node as well. Otherwise, this class is used like * `LocalScopeVariableReachability`. */ -abstract class LocalScopeVariableReachabilityExt extends string { +abstract deprecated class LocalScopeVariableReachabilityExt extends string { bindingset[this] LocalScopeVariableReachabilityExt() { length() >= 0 } diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll index 8384a5b3c66..4e2e018eda3 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll @@ -9,11 +9,11 @@ library class StandardSSA extends SSAHelper { /** * A definition of one or more SSA variables, including phi node definitions. * An _SSA variable_, as defined in the literature, is effectively the pair of - * an `SsaDefinition d` and a `LocalScopeVariable v`, written `(d, v)` in this + * an `SsaDefinition d` and a `StackVariable v`, written `(d, v)` in this * documentation. Note that definitions and uses can be coincident due to the * presence of parameter definitions and phi nodes. * - * Not all `LocalScopeVariable`s of a function have SSA definitions. If the variable + * Not all `StackVariable`s of a function have SSA definitions. If the variable * has its address taken, either explicitly or implicitly, then it is excluded * from analysis. `SsaDefinition`s are not generated in locations that are * statically seen to be unreachable. @@ -22,21 +22,19 @@ class SsaDefinition extends ControlFlowNodeBase { SsaDefinition() { exists(StandardSSA x | x.ssa_defn(_, this, _, _)) } /** - * Gets a variable corresponding to an SSA LocalScopeVariable defined by + * Gets a variable corresponding to an SSA StackVariable defined by * this definition. */ - LocalScopeVariable getAVariable() { exists(StandardSSA x | x.ssa_defn(result, this, _, _)) } + StackVariable getAVariable() { exists(StandardSSA x | x.ssa_defn(result, this, _, _)) } /** * Gets a string representation of the SSA variable represented by the pair * `(this, v)`. */ - string toString(LocalScopeVariable v) { exists(StandardSSA x | result = x.toString(this, v)) } + string toString(StackVariable v) { exists(StandardSSA x | result = x.toString(this, v)) } /** Gets a use of the SSA variable represented by the pair `(this, v)`. */ - VariableAccess getAUse(LocalScopeVariable v) { - exists(StandardSSA x | result = x.getAUse(this, v)) - } + VariableAccess getAUse(StackVariable v) { exists(StandardSSA x | result = x.getAUse(this, v)) } /** * Gets the control-flow node for this definition. This will usually be the @@ -55,9 +53,7 @@ class SsaDefinition extends ControlFlowNodeBase { BasicBlock getBasicBlock() { result.contains(getDefinition()) } /** Holds if this definition is a phi node for variable `v`. */ - predicate isPhiNode(LocalScopeVariable v) { - exists(StandardSSA x | x.phi_node(v, this.(BasicBlock))) - } + predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this.(BasicBlock))) } Location getLocation() { result = this.(ControlFlowNode).getLocation() } @@ -68,7 +64,7 @@ class SsaDefinition extends ControlFlowNodeBase { * Holds if the SSA variable `(result, v)` is an input to the phi definition * `(this, v)`. */ - SsaDefinition getAPhiInput(LocalScopeVariable v) { + SsaDefinition getAPhiInput(StackVariable v) { this.isPhiNode(v) and result.reachesEndOfBB(v, this.(BasicBlock).getAPredecessor()) } @@ -92,7 +88,7 @@ class SsaDefinition extends ControlFlowNodeBase { * instead covered via `definedByParameter` and `getDefinition`, * respectively. */ - Expr getDefiningValue(LocalScopeVariable v) { + Expr getDefiningValue(StackVariable v) { exists(ControlFlowNode def | def = this.getDefinition() | def = v.getInitializer().getExpr() and def = result or @@ -117,7 +113,7 @@ class SsaDefinition extends ControlFlowNodeBase { } /** Holds if `(this, v)` reaches the end of basic block `b`. */ - predicate reachesEndOfBB(LocalScopeVariable v, BasicBlock b) { + predicate reachesEndOfBB(StackVariable v, BasicBlock b) { exists(StandardSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b)) } @@ -125,7 +121,7 @@ class SsaDefinition extends ControlFlowNodeBase { * Gets a definition that ultimately defines this variable and is not * itself a phi node. */ - SsaDefinition getAnUltimateSsaDefinition(LocalScopeVariable v) { + SsaDefinition getAnUltimateSsaDefinition(StackVariable v) { result = this.getAPhiInput(v).getAnUltimateSsaDefinition(v) or v = this.getAVariable() and @@ -138,7 +134,7 @@ class SsaDefinition extends ControlFlowNodeBase { * recursing backwards through phi definitions. Not all definitions have a * defining expression---see the documentation for `getDefiningValue`. */ - Expr getAnUltimateDefiningValue(LocalScopeVariable v) { + Expr getAnUltimateDefiningValue(StackVariable v) { result = this.getAnUltimateSsaDefinition(v).getDefiningValue(v) } @@ -149,7 +145,7 @@ class SsaDefinition extends ControlFlowNodeBase { * `getAnUltimateSsaDefinition` to refer to a predicate named * `getAnUltimateSsaDefinition` in this class. */ - deprecated Expr getAnUltimateDefinition(LocalScopeVariable v) { + deprecated Expr getAnUltimateDefinition(StackVariable v) { result = this.getAnUltimateDefiningValue(v) } } diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll index 5501fb0a394..b9b34a1d68c 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll @@ -21,11 +21,9 @@ private predicate dominanceFrontier(BasicBlock x, BasicBlock w) { } /** - * Extended version of `definition` that also includes parameters but excludes - * static variables. + * Extended version of `definition` that also includes parameters. */ -predicate var_definition(LocalScopeVariable v, ControlFlowNode node) { - not v.isStatic() and +predicate var_definition(StackVariable v, ControlFlowNode node) { not addressTakenVariable(v) and not unreachable(node) and ( @@ -51,7 +49,7 @@ predicate var_definition(LocalScopeVariable v, ControlFlowNode node) { * analysis because the pointer could be used to change the value at * any moment. */ -private predicate addressTakenVariable(LocalScopeVariable var) { +private predicate addressTakenVariable(StackVariable var) { // If the type of the variable is a reference type, then it is safe (as // far as SSA is concerned) to take its address, because this does not // enable the variable to be modified indirectly. Obviously the @@ -71,7 +69,7 @@ private predicate addressTakenVariable(LocalScopeVariable var) { ) } -private predicate isReferenceVar(LocalScopeVariable v) { +private predicate isReferenceVar(StackVariable v) { v.getUnspecifiedType() instanceof ReferenceType } @@ -79,22 +77,22 @@ private predicate isReferenceVar(LocalScopeVariable v) { * This predicate is the same as `var_definition`, but annotated with * the basic block and index of the control flow node. */ -private predicate variableUpdate(LocalScopeVariable v, ControlFlowNode n, BasicBlock b, int i) { +private predicate variableUpdate(StackVariable v, ControlFlowNode n, BasicBlock b, int i) { var_definition(v, n) and n = b.getNode(i) } -private predicate ssa_use(LocalScopeVariable v, VariableAccess node, BasicBlock b, int index) { +private predicate ssa_use(StackVariable v, VariableAccess node, BasicBlock b, int index) { useOfVar(v, node) and b.getNode(index) = node } -private predicate live_at_start_of_bb(LocalScopeVariable v, BasicBlock b) { +private predicate live_at_start_of_bb(StackVariable v, BasicBlock b) { exists(int i | ssa_use(v, _, b, i) | not exists(int j | variableUpdate(v, _, b, j) | j < i)) or live_at_exit_of_bb(v, b) and not variableUpdate(v, _, b, _) } pragma[noinline] -private predicate live_at_exit_of_bb(LocalScopeVariable v, BasicBlock b) { +private predicate live_at_exit_of_bb(StackVariable v, BasicBlock b) { live_at_start_of_bb(v, b.getASuccessor()) } @@ -110,12 +108,12 @@ library class SSAHelper extends int { * basic block `b`. */ cached - predicate custom_phi_node(LocalScopeVariable v, BasicBlock b) { none() } + predicate custom_phi_node(StackVariable v, BasicBlock b) { none() } /** * Remove any custom phi nodes that are invalid. */ - private predicate sanitized_custom_phi_node(LocalScopeVariable v, BasicBlock b) { + private predicate sanitized_custom_phi_node(StackVariable v, BasicBlock b) { custom_phi_node(v, b) and not addressTakenVariable(v) and not isReferenceVar(v) and @@ -127,7 +125,7 @@ library class SSAHelper extends int { * `b`. */ cached - predicate phi_node(LocalScopeVariable v, BasicBlock b) { + predicate phi_node(StackVariable v, BasicBlock b) { frontier_phi_node(v, b) or sanitized_custom_phi_node(v, b) } @@ -138,13 +136,13 @@ library class SSAHelper extends int { * definitions). This is known as the iterated dominance frontier. See * Modern Compiler Implementation by Andrew Appel. */ - private predicate frontier_phi_node(LocalScopeVariable v, BasicBlock b) { + private predicate frontier_phi_node(StackVariable v, BasicBlock b) { exists(BasicBlock x | dominanceFrontier(x, b) and ssa_defn_rec(v, x)) and /* We can also eliminate those nodes where the variable is not live on any incoming edge */ live_at_start_of_bb(v, b) } - private predicate ssa_defn_rec(LocalScopeVariable v, BasicBlock b) { + private predicate ssa_defn_rec(StackVariable v, BasicBlock b) { phi_node(v, b) or variableUpdate(v, _, b, _) @@ -155,7 +153,7 @@ library class SSAHelper extends int { * position `index` in block `b`. This includes definitions from phi nodes. */ cached - predicate ssa_defn(LocalScopeVariable v, ControlFlowNode node, BasicBlock b, int index) { + predicate ssa_defn(StackVariable v, ControlFlowNode node, BasicBlock b, int index) { phi_node(v, b) and b.getStart() = node and index = -1 or variableUpdate(v, node, b, index) @@ -179,7 +177,7 @@ library class SSAHelper extends int { * irrelevant indices at which there is no definition or use when traversing * basic blocks. */ - private predicate defUseRank(LocalScopeVariable v, BasicBlock b, int rankix, int i) { + private predicate defUseRank(StackVariable v, BasicBlock b, int rankix, int i) { i = rank[rankix](int j | ssa_defn(v, _, b, j) or ssa_use(v, _, b, j)) } @@ -189,7 +187,7 @@ library class SSAHelper extends int { * the extra rank at the end represents a position past the last node in * the block. */ - private int lastRank(LocalScopeVariable v, BasicBlock b) { + private int lastRank(StackVariable v, BasicBlock b) { result = max(int rankix | defUseRank(v, b, rankix, _)) + 1 } @@ -197,7 +195,7 @@ library class SSAHelper extends int { * Holds if SSA variable `(v, def)` is defined at rank index `rankix` in * basic block `b`. */ - private predicate ssaDefRank(LocalScopeVariable v, ControlFlowNode def, BasicBlock b, int rankix) { + private predicate ssaDefRank(StackVariable v, ControlFlowNode def, BasicBlock b, int rankix) { exists(int i | ssa_defn(v, def, b, i) and defUseRank(v, b, rankix, i) @@ -210,9 +208,7 @@ library class SSAHelper extends int { * `v` that comes _at or after_ the reached node. Reaching a node means * that the definition is visible to any _use_ at that node. */ - private predicate ssaDefReachesRank( - LocalScopeVariable v, ControlFlowNode def, BasicBlock b, int rankix - ) { + private predicate ssaDefReachesRank(StackVariable v, ControlFlowNode def, BasicBlock b, int rankix) { // A definition should not reach its own node unless a loop allows it. // When nodes are both definitions and uses for the same variable, the // use is understood to happen _before_ the definition. Phi nodes are @@ -227,7 +223,7 @@ library class SSAHelper extends int { /** Holds if SSA variable `(v, def)` reaches the end of block `b`. */ cached - predicate ssaDefinitionReachesEndOfBB(LocalScopeVariable v, ControlFlowNode def, BasicBlock b) { + predicate ssaDefinitionReachesEndOfBB(StackVariable v, ControlFlowNode def, BasicBlock b) { live_at_exit_of_bb(v, b) and ssaDefReachesRank(v, def, b, lastRank(v, b)) or exists(BasicBlock idom | @@ -243,7 +239,7 @@ library class SSAHelper extends int { * reaches the end of `b`. */ pragma[noinline] - private predicate noDefinitionsSinceIDominator(LocalScopeVariable v, BasicBlock idom, BasicBlock b) { + private predicate noDefinitionsSinceIDominator(StackVariable v, BasicBlock idom, BasicBlock b) { bbIDominates(idom, b) and // It is sufficient to traverse the dominator graph, cf. discussion above. live_at_exit_of_bb(v, b) and not ssa_defn(v, _, b, _) @@ -253,9 +249,7 @@ library class SSAHelper extends int { * Holds if SSA variable `(v, def)` reaches `use` within the same basic * block, where `use` is a `VariableAccess` of `v`. */ - private predicate ssaDefinitionReachesUseWithinBB( - LocalScopeVariable v, ControlFlowNode def, Expr use - ) { + private predicate ssaDefinitionReachesUseWithinBB(StackVariable v, ControlFlowNode def, Expr use) { exists(BasicBlock b, int rankix, int i | ssaDefReachesRank(v, def, b, rankix) and defUseRank(v, b, rankix, i) and @@ -266,7 +260,7 @@ library class SSAHelper extends int { /** * Holds if SSA variable `(v, def)` reaches the control-flow node `use`. */ - private predicate ssaDefinitionReaches(LocalScopeVariable v, ControlFlowNode def, Expr use) { + private predicate ssaDefinitionReaches(StackVariable v, ControlFlowNode def, Expr use) { ssaDefinitionReachesUseWithinBB(v, def, use) or exists(BasicBlock b | @@ -281,7 +275,7 @@ library class SSAHelper extends int { * `(node, v)`. */ cached - string toString(ControlFlowNode node, LocalScopeVariable v) { + string toString(ControlFlowNode node, StackVariable v) { if phi_node(v, node.(BasicBlock)) then result = "SSA phi(" + v.getName() + ")" else ( @@ -294,7 +288,7 @@ library class SSAHelper extends int { * access of `v`. */ cached - VariableAccess getAUse(ControlFlowNode def, LocalScopeVariable v) { + VariableAccess getAUse(ControlFlowNode def, StackVariable v) { ssaDefinitionReaches(v, def, result) and ssa_use(v, result, _, _) } diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll b/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll index b8ffa3344f6..696184620e3 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll @@ -1,11 +1,24 @@ import cpp /** - * DEPRECATED: use `LocalScopeVariableReachability` instead. - * * A reachability analysis for control-flow nodes involving stack variables. + * This defines sources, sinks, and any other configurable aspect of the + * analysis. Multiple analyses can coexist. To create an analysis, extend this + * class with a subclass whose characteristic predicate is a unique singleton + * string. For example, write + * + * ``` + * class MyAnalysisConfiguration extends StackVariableReachability { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Override `isBarrier`. + * } + * ``` + * + * Then, to query whether there is flow between some source and sink, call the + * `reaches` predicate on an instance of `MyAnalysisConfiguration`. */ -abstract deprecated class StackVariableReachability extends string { +abstract class StackVariableReachability extends string { bindingset[this] StackVariableReachability() { length() >= 0 } @@ -24,13 +37,13 @@ abstract deprecated class StackVariableReachability extends string { * uses basic blocks internally for better performance: * * ``` - * predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) { + * predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { * reachesImpl(source, v, sink) * and * isSink(sink, v) * } * - * predicate reachesImpl(ControlFlowNode source, StackVariable v, ControlFlowNode sink) { + * predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { * sink = source.getASuccessor() and isSource(source, v) * or * exists(ControlFlowNode mid | reachesImpl(source, v, mid) | @@ -44,7 +57,7 @@ abstract deprecated class StackVariableReachability extends string { * In addition to using a better performing implementation, this analysis * accounts for loops where the condition is provably true upon entry. */ - predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) { + predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { /* * Implementation detail: the predicates in this class are a generalization of * those in DefinitionsAndUses.qll, and should be kept in sync. @@ -71,7 +84,8 @@ abstract deprecated class StackVariableReachability extends string { } private predicate bbSuccessorEntryReaches( - BasicBlock bb, StackVariable v, ControlFlowNode node, boolean skipsFirstLoopAlwaysTrueUponEntry + BasicBlock bb, SemanticStackVariable v, ControlFlowNode node, + boolean skipsFirstLoopAlwaysTrueUponEntry ) { exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry | bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry, @@ -85,11 +99,22 @@ abstract deprecated class StackVariableReachability extends string { ) } - private predicate bbEntryReachesLocally(BasicBlock bb, StackVariable v, ControlFlowNode node) { - exists(int n | node = bb.getNode(n) and isSink(node, v) | - not exists(int m | m < n | isBarrier(bb.getNode(m), v)) + private predicate bbEntryReachesLocally( + BasicBlock bb, SemanticStackVariable v, ControlFlowNode node + ) { + exists(int n | + node = bb.getNode(n) and + isSink(node, v) + | + not exists(this.firstBarrierIndexIn(bb, v)) + or + n <= this.firstBarrierIndexIn(bb, v) ) } + + private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) { + result = min(int m | isBarrier(bb.getNode(m), v)) + } } /** @@ -113,26 +138,32 @@ private predicate bbLoopEntryConditionAlwaysTrueAt(BasicBlock bb, int i, Control } /** - * Basic block `pred` ends with a condition belonging to a loop, and that - * condition is provably true upon entry. Basic block `succ` is a successor - * of `pred`, and `skipsLoop` indicates whether `succ` is the false-successor - * of `pred`. + * Basic block `pred` contains all or part of the condition belonging to a loop, + * and there is an edge from `pred` to `succ` that concludes the condition. + * If the edge corrseponds with the loop condition being found to be `true`, then + * `skipsLoop` is `false`. Otherwise the edge corresponds with the loop condition + * being found to be `false` and `skipsLoop` is `true`. Non-concluding edges + * within a complex loop condition are not matched by this predicate. */ private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor( BasicBlock pred, BasicBlock succ, boolean skipsLoop ) { - succ = pred.getASuccessor() and - exists(ControlFlowNode last | - last = pred.getEnd() and - loopConditionAlwaysTrueUponEntry(_, last) and - if succ = pred.getAFalseSuccessor() then skipsLoop = true else skipsLoop = false + exists(Expr cond | + loopConditionAlwaysTrueUponEntry(_, cond) and + cond.getAChild*() = pred.getEnd() and + succ = pred.getASuccessor() and + not cond.getAChild*() = succ.getStart() and + ( + succ = pred.getAFalseSuccessor() and + skipsLoop = true + or + succ = pred.getATrueSuccessor() and + skipsLoop = false + ) ) } /** - * DEPRECATED: use the corresponding predicate in - * `LocalScopeVariableReachability` instead. - * * Loop invariant for `bbSuccessorEntryReaches`: * * - `succ` is a successor of `pred`. @@ -146,7 +177,7 @@ private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor( * is provably true upon entry, then `succ` is not allowed to skip * that loop (`succSkipsFirstLoopAlwaysTrueUponEntry = false`). */ -deprecated predicate bbSuccessorEntryReachesLoopInvariant( +predicate bbSuccessorEntryReachesLoopInvariant( BasicBlock pred, BasicBlock succ, boolean predSkipsFirstLoopAlwaysTrueUponEntry, boolean succSkipsFirstLoopAlwaysTrueUponEntry ) { @@ -162,7 +193,7 @@ deprecated predicate bbSuccessorEntryReachesLoopInvariant( // The edge from `pred` to `succ` is _not_ from a loop condition provably // true upon entry, so the values of `predSkipsFirstLoopAlwaysTrueUponEntry` // and `succSkipsFirstLoopAlwaysTrueUponEntry` must be the same. - not bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, _, _) and + not bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, succ, _) and succSkipsFirstLoopAlwaysTrueUponEntry = predSkipsFirstLoopAlwaysTrueUponEntry and // Moreover, if `pred` contains the entry point of a loop where the // condition is provably true upon entry, then `succ` is not allowed @@ -176,13 +207,16 @@ deprecated predicate bbSuccessorEntryReachesLoopInvariant( } /** - * DEPRECATED: use `LocalScopeVariableReachabilityWithReassignment` instead. - * * Reachability analysis for control-flow nodes involving stack variables. * Unlike `StackVariableReachability`, this analysis takes variable * reassignments into account. + * + * This class is used like `StackVariableReachability`, except that + * subclasses should override `isSourceActual` and `isSinkActual` instead of + * `isSource` and `isSink`, and that there is a `reachesTo` predicate in + * addition to `reaches`. */ -abstract deprecated class StackVariableReachabilityWithReassignment extends StackVariableReachability { +abstract class StackVariableReachabilityWithReassignment extends StackVariableReachability { bindingset[this] StackVariableReachabilityWithReassignment() { length() >= 0 } @@ -199,19 +233,19 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac * performance: * * ``` - * predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) { + * predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { * reachesImpl(source, v, sink) * and * isSinkActual(sink, v) * } * - * predicate reachesImpl(ControlFlowNode source, StackVariable v, ControlFlowNode sink) { + * predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { * isSourceActual(source, v) * and * ( * sink = source.getASuccessor() * or - * exists(ControlFlowNode mid, StackVariable v0 | reachesImpl(source, v0, mid) | + * exists(ControlFlowNode mid, SemanticStackVariable v0 | reachesImpl(source, v0, mid) | * // ordinary successor * not isBarrier(mid, v) and * sink = mid.getASuccessor() and @@ -228,7 +262,7 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac * In addition to using a better performing implementation, this analysis * accounts for loops where the condition is provably true upon entry. */ - override predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) { + override predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { reachesTo(source, v, sink, _) } @@ -236,7 +270,7 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac * As `reaches`, but also specifies the last variable it was reassigned to (`v0`). */ predicate reachesTo( - ControlFlowNode source, StackVariable v, ControlFlowNode sink, StackVariable v0 + ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink, SemanticStackVariable v0 ) { exists(ControlFlowNode def | actualSourceReaches(source, v, def, v0) and @@ -246,17 +280,19 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac } private predicate actualSourceReaches( - ControlFlowNode source, StackVariable v, ControlFlowNode def, StackVariable v0 + ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0 ) { isSourceActual(source, v) and def = source and v0 = v or - exists(ControlFlowNode source1, StackVariable v1 | actualSourceReaches(source, v, source1, v1) | + exists(ControlFlowNode source1, SemanticStackVariable v1 | + actualSourceReaches(source, v, source1, v1) + | reassignment(source1, v1, def, v0) ) } private predicate reassignment( - ControlFlowNode source, StackVariable v, ControlFlowNode def, StackVariable v0 + ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0 ) { StackVariableReachability.super.reaches(source, v, def) and exprDefinition(v0, def, v.getAnAccess()) @@ -278,13 +314,12 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac } /** - * DEPRECATED: use `LocalScopeVariableReachabilityExt` instead. - * * Same as `StackVariableReachability`, but `isBarrier` works on control-flow * edges rather than nodes and is therefore parameterized by the original - * source node as well. + * source node as well. Otherwise, this class is used like + * `StackVariableReachability`. */ -abstract deprecated class StackVariableReachabilityExt extends string { +abstract class StackVariableReachabilityExt extends string { bindingset[this] StackVariableReachabilityExt() { length() >= 0 } @@ -300,7 +335,7 @@ abstract deprecated class StackVariableReachabilityExt extends string { ); /** See `StackVariableReachability.reaches`. */ - predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) { + predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) { exists(BasicBlock bb, int i | isSource(source, v) and bb.getNode(i) = source and @@ -321,7 +356,7 @@ abstract deprecated class StackVariableReachabilityExt extends string { } private predicate bbSuccessorEntryReaches( - ControlFlowNode source, BasicBlock bb, StackVariable v, ControlFlowNode node, + ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node, boolean skipsFirstLoopAlwaysTrueUponEntry ) { exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry | @@ -338,7 +373,7 @@ abstract deprecated class StackVariableReachabilityExt extends string { } private predicate bbEntryReachesLocally( - ControlFlowNode source, BasicBlock bb, StackVariable v, ControlFlowNode node + ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node ) { isSource(source, v) and exists(int n | node = bb.getNode(n) and isSink(node, v) | diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll b/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll index 43b1a76c837..263fb141312 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll @@ -924,7 +924,7 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator { /* * Use primitive basic blocks in reachability analysis for better performance. * This is similar to the pattern used in e.g. `DefinitionsAndUses` and - * `LocalScopeVariableReachability`. + * `StackVariableReachability`. */ exists(PrimitiveBasicBlock bb1, int pos1 | bb1.getNode(pos1) = valueOrDef | diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/StackAddress.qll b/cpp/ql/src/semmle/code/cpp/dataflow/StackAddress.qll index d0694a12932..f375bbae199 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/StackAddress.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/StackAddress.qll @@ -61,7 +61,7 @@ predicate stackPointerFlowsToUse(Expr use, Type useType, Expr source, boolean is stackPointerFlowsToUse(use.(PointerAddExpr).getAnOperand(), useType, source, isLocal) or // Indirect use of a stack address. - exists(SsaDefinition def, LocalScopeVariable var | + exists(SsaDefinition def, StackVariable var | stackPointerFlowsToDef(def, var, useType, source, isLocal) and use = def.getAUse(var) ) @@ -97,8 +97,7 @@ private PointerType getExprPtrType(Expr use) { result = use.getUnspecifiedType() predicate stackReferenceFlowsToUse(Expr use, Type useType, Expr source, boolean isLocal) { // Stack variables - exists(LocalScopeVariable var | - not var.isStatic() and + exists(StackVariable var | use = source and source = var.getAnAccess() and isLocal = true and @@ -140,7 +139,7 @@ predicate stackReferenceFlowsToUse(Expr use, Type useType, Expr source, boolean stackPointerFlowsToUse(use.(PointerDereferenceExpr).getOperand(), useType, source, isLocal) or // Indirect use of a stack reference, via a reference variable. - exists(SsaDefinition def, LocalScopeVariable var | + exists(SsaDefinition def, StackVariable var | stackReferenceFlowsToDef(def, var, useType, source, isLocal) and use = def.getAUse(var) ) @@ -162,7 +161,7 @@ predicate stackReferenceFlowsToUse(Expr use, Type useType, Expr source, boolean * addresses through SSA definitions. */ predicate stackPointerFlowsToDef( - SsaDefinition def, LocalScopeVariable var, Type useType, Expr source, boolean isLocal + SsaDefinition def, StackVariable var, Type useType, Expr source, boolean isLocal ) { stackPointerFlowsToUse(def.getDefiningValue(var), useType, source, isLocal) or @@ -184,7 +183,7 @@ predicate stackPointerFlowsToDef( * int&, rather than pointers. */ predicate stackReferenceFlowsToDef( - SsaDefinition def, LocalScopeVariable var, Type useType, Expr source, boolean isLocal + SsaDefinition def, StackVariable var, Type useType, Expr source, boolean isLocal ) { // Check that the type of the variable is a reference type and delegate // the rest of the work to stackReferenceFlowsToDef_Impl. @@ -197,7 +196,7 @@ predicate stackReferenceFlowsToDef( * predicate. */ predicate stackReferenceFlowsToDef_Impl( - SsaDefinition def, LocalScopeVariable var, Type useType, Expr source, boolean isLocal + SsaDefinition def, StackVariable var, Type useType, Expr source, boolean isLocal ) { stackReferenceFlowsToUse(def.getDefiningValue(var), useType, source, isLocal) or @@ -213,7 +212,7 @@ predicate stackReferenceFlowsToDef_Impl( } /** The type of the variable is a reference type, such as int&. */ -predicate isReferenceVariable(LocalScopeVariable var) { +predicate isReferenceVariable(StackVariable var) { var.getUnspecifiedType() instanceof ReferenceType } @@ -284,7 +283,7 @@ predicate memberFcnMightRunOnStack(MemberFunction fcn, Type useType) { predicate constructorMightRunOnStack(Constructor constructor) { exists(ConstructorCall call | call.getTarget() = constructor | // Call to a constructor from a stack variable's initializer. - exists(LocalScopeVariable var | var.getInitializer().getExpr() = call) + exists(StackVariable var | var.getInitializer().getExpr() = call) or // Call to a constructor from another constructor which might // also run on the stack. diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll index abd56c6283c..5085e74a97f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -88,7 +88,7 @@ class FlowVar extends TFlowVar { * `FlowVar` instance for the uninitialized value of that variable. */ cached - abstract predicate definedByInitialValue(LocalScopeVariable v); + abstract predicate definedByInitialValue(StackVariable v); /** Gets a textual representation of this element. */ cached @@ -268,7 +268,7 @@ module FlowVar_internal { * Holds if `sbb` is the `SubBasicBlock` where `v` receives its initial value. * See the documentation for `FlowVar.definedByInitialValue`. */ - predicate blockVarDefinedByVariable(SubBasicBlock sbb, LocalScopeVariable v) { + predicate blockVarDefinedByVariable(SubBasicBlock sbb, StackVariable v) { sbb = v.(Parameter).getFunction().getEntryPoint() or exists(DeclStmt declStmt | @@ -279,7 +279,7 @@ module FlowVar_internal { } newtype TFlowVar = - TSsaVar(SsaDefinition def, LocalScopeVariable v) { + TSsaVar(SsaDefinition def, StackVariable v) { fullySupportedSsaVariable(v) and v = def.getAVariable() } or @@ -303,7 +303,7 @@ module FlowVar_internal { */ class SsaVar extends TSsaVar, FlowVar { SsaDefinition def; - LocalScopeVariable v; + StackVariable v; SsaVar() { this = TSsaVar(def, v) } @@ -343,7 +343,7 @@ module FlowVar_internal { override predicate definedPartiallyAt(Expr e) { none() } - override predicate definedByInitialValue(LocalScopeVariable param) { + override predicate definedByInitialValue(StackVariable param) { def.definedByParameter(param) and param = v } @@ -407,7 +407,7 @@ module FlowVar_internal { getAReachedBlockVarSBB(this).getANode() = p.getFunction() } - override predicate definedByInitialValue(LocalScopeVariable lsv) { + override predicate definedByInitialValue(StackVariable lsv) { blockVarDefinedByVariable(sbb, lsv) and lsv = v } @@ -647,11 +647,8 @@ module FlowVar_internal { /** * A local variable that is uninitialized immediately after its declaration. */ - class UninitializedLocalVariable extends LocalVariable { - UninitializedLocalVariable() { - not this.hasInitializer() and - not this.isStatic() - } + class UninitializedLocalVariable extends LocalVariable, StackVariable { + UninitializedLocalVariable() { not this.hasInitializer() } } /** Holds if `va` may be an uninitialized access to `v`. */ diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll index 741d63fbc44..46e672f1d98 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll @@ -62,11 +62,10 @@ abstract class CrementOperation extends UnaryArithmeticOperation { override predicate mayBeImpure() { any() } override predicate mayBeGloballyImpure() { - not exists(VariableAccess va, LocalScopeVariable v | + not exists(VariableAccess va, StackVariable v | va = this.getOperand() and v = va.getTarget() and - not va.getConversion+() instanceof ReferenceDereferenceExpr and - not v.isStatic() + not va.getConversion+() instanceof ReferenceDereferenceExpr ) } } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll b/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll index aeabe10f168..1d787f03167 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll @@ -21,11 +21,10 @@ abstract class Assignment extends Operation { override predicate mayBeGloballyImpure() { this.getRValue().mayBeGloballyImpure() or - not exists(VariableAccess va, LocalScopeVariable v | + not exists(VariableAccess va, StackVariable v | va = this.getLValue() and v = va.getTarget() and - not va.getConversion+() instanceof ReferenceDereferenceExpr and - not v.isStatic() + not va.getConversion+() instanceof ReferenceDereferenceExpr ) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll index 613958a0d4c..cc41429489f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll @@ -32,7 +32,7 @@ class StringLiteral = Cpp::StringLiteral; class Variable = Cpp::Variable; -class AutomaticVariable = Cpp::LocalScopeVariable; +class AutomaticVariable = Cpp::StackVariable; class StaticVariable = Cpp::Variable; @@ -66,10 +66,7 @@ int getTypeSize(Type type) { result = type.getSize() } int getPointerSize() { exists(Cpp::NullPointerType nullptr | result = nullptr.getSize()) } -predicate isVariableAutomatic(Variable var) { - var instanceof Cpp::LocalScopeVariable and - not var.(Cpp::LocalScopeVariable).isStatic() -} +predicate isVariableAutomatic(Cpp::StackVariable var) { any() } string getStringLiteralText(StringLiteral s) { result = s.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll index 10a91deaa3a..ea12434ac5b 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll @@ -24,7 +24,7 @@ predicate nanExcludingComparison(ComparisonOperation guard, boolean polarity) { * by virtue of the guard in `def`. */ private predicate excludesNan(RangeSsaDefinition def, VariableAccess v) { - exists(VariableAccess inCond, ComparisonOperation guard, boolean branch, LocalScopeVariable lsv | + exists(VariableAccess inCond, ComparisonOperation guard, boolean branch, StackVariable lsv | def.isGuardPhi(inCond, guard, branch) and inCond.getTarget() = lsv and v = def.getAUse(lsv) and diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll index 61068801978..99e6539658d 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll @@ -31,7 +31,7 @@ library class RangeSSA extends SSAHelper { /** * Add a phi node on the out-edge of a guard. */ - override predicate custom_phi_node(LocalScopeVariable v, BasicBlock b) { + override predicate custom_phi_node(StackVariable v, BasicBlock b) { guard_defn(v.getAnAccess(), _, b, _) } } @@ -67,19 +67,19 @@ class RangeSsaDefinition extends ControlFlowNodeBase { RangeSsaDefinition() { exists(RangeSSA x | x.ssa_defn(_, this, _, _)) } /** - * Gets a variable corresponding to a SSA LocalScopeVariable defined by + * Gets a variable corresponding to a SSA StackVariable defined by * this definition. */ - LocalScopeVariable getAVariable() { exists(RangeSSA x | x.ssa_defn(result, this, _, _)) } + StackVariable getAVariable() { exists(RangeSSA x | x.ssa_defn(result, this, _, _)) } /** * A string representation of the SSA variable represented by the pair * `(this, v)`. */ - string toString(LocalScopeVariable v) { exists(RangeSSA x | result = x.toString(this, v)) } + string toString(StackVariable v) { exists(RangeSSA x | result = x.toString(this, v)) } /** Gets a use of the SSA variable represented by the pair `(this, v)`. */ - VariableAccess getAUse(LocalScopeVariable v) { exists(RangeSSA x | result = x.getAUse(this, v)) } + VariableAccess getAUse(StackVariable v) { exists(RangeSSA x | result = x.getAUse(this, v)) } /** Gets the control flow node for this definition. */ ControlFlowNode getDefinition() { result = this } @@ -87,9 +87,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase { BasicBlock getBasicBlock() { result.contains(getDefinition()) } /** Whether this definition is a phi node for variable `v`. */ - predicate isPhiNode(LocalScopeVariable v) { - exists(RangeSSA x | x.phi_node(v, this.(BasicBlock))) - } + predicate isPhiNode(StackVariable v) { exists(RangeSSA x | x.phi_node(v, this.(BasicBlock))) } /** * If this definition is a phi node corresponding to a guard, @@ -104,7 +102,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase { /** Whether this definition is from a parameter */ predicate definedByParameter(Parameter p) { this = p.getFunction().getEntryPoint() } - RangeSsaDefinition getAPhiInput(LocalScopeVariable v) { + RangeSsaDefinition getAPhiInput(StackVariable v) { this.isPhiNode(v) and exists(BasicBlock pred | pred = this.(BasicBlock).getAPredecessor() and @@ -137,7 +135,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase { } /** Gets the expression assigned to this SsaDefinition. */ - Expr getDefiningValue(LocalScopeVariable v) { + Expr getDefiningValue(StackVariable v) { exists(ControlFlowNode def | def = this.getDefinition() | def = v.getInitializer().getExpr() and def = result or @@ -155,7 +153,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase { ) } - predicate reachesEndOfBB(LocalScopeVariable v, BasicBlock b) { + predicate reachesEndOfBB(StackVariable v, BasicBlock b) { exists(RangeSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b)) } } diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index b7b646d5c8a..72dba0ab609 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -120,7 +120,7 @@ private predicate analyzableExpr(Expr e) { exists(exprMinVal(e.(Conversion).getExpr())) or // Also allow variable accesses, provided that they have SSA // information. - exists(RangeSsaDefinition def, LocalScopeVariable v | e = def.getAUse(v)) + exists(RangeSsaDefinition def, StackVariable v | e = def.getAUse(v)) ) } @@ -136,7 +136,7 @@ private predicate analyzableExpr(Expr e) { * here. */ private predicate defDependsOnDef( - RangeSsaDefinition def, LocalScopeVariable v, RangeSsaDefinition srcDef, LocalScopeVariable srcVar + RangeSsaDefinition def, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar ) { // Definitions with a defining value. exists(Expr expr | assignmentDef(def, v, expr) | exprDependsOnDef(expr, srcDef, srcVar)) @@ -171,7 +171,7 @@ private predicate defDependsOnDef( * Helper predicate for `defDependsOnDef`. This predicate matches * the structure of `getLowerBoundsImpl` and `getUpperBoundsImpl`. */ -private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, LocalScopeVariable srcVar) { +private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVariable srcVar) { exists(UnaryMinusExpr negateExpr | e = negateExpr | exprDependsOnDef(negateExpr.getOperand(), srcDef, srcVar) ) @@ -226,7 +226,7 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, LocalScope * the structure of `getPhiLowerBounds` and `getPhiUpperBounds`. */ private predicate phiDependsOnDef( - RangeSsaDefinition phi, LocalScopeVariable v, RangeSsaDefinition srcDef, LocalScopeVariable srcVar + RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar ) { exists(VariableAccess access, ComparisonOperation guard | access = v.getAnAccess() and @@ -241,19 +241,17 @@ private predicate phiDependsOnDef( /** The transitive closure of `defDependsOnDef`. */ private predicate defDependsOnDefTransitively( - RangeSsaDefinition def, LocalScopeVariable v, RangeSsaDefinition srcDef, LocalScopeVariable srcVar + RangeSsaDefinition def, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar ) { defDependsOnDef(def, v, srcDef, srcVar) or - exists(RangeSsaDefinition midDef, LocalScopeVariable midVar | - defDependsOnDef(def, v, midDef, midVar) - | + exists(RangeSsaDefinition midDef, StackVariable midVar | defDependsOnDef(def, v, midDef, midVar) | defDependsOnDefTransitively(midDef, midVar, srcDef, srcVar) ) } /** The set of definitions that depend recursively on themselves. */ -private predicate isRecursiveDef(RangeSsaDefinition def, LocalScopeVariable v) { +private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) { defDependsOnDefTransitively(def, v, def, v) } @@ -271,7 +269,7 @@ private predicate isRecursiveDef(RangeSsaDefinition def, LocalScopeVariable v) { * * This predicate finds all the definitions in the first set. */ -private predicate assignmentDef(RangeSsaDefinition def, LocalScopeVariable v, Expr expr) { +private predicate assignmentDef(RangeSsaDefinition def, StackVariable v, Expr expr) { v.getUnspecifiedType() instanceof ArithmeticType and ( def = v.getInitializer().getExpr() and def = expr @@ -285,7 +283,7 @@ private predicate assignmentDef(RangeSsaDefinition def, LocalScopeVariable v, Ex } /** See comment above sourceDef. */ -private predicate analyzableDef(RangeSsaDefinition def, LocalScopeVariable v) { +private predicate analyzableDef(RangeSsaDefinition def, StackVariable v) { assignmentDef(def, v, _) or defDependsOnDef(def, v, _, _) } @@ -613,7 +611,7 @@ private float getLowerBoundsImpl(Expr expr) { ) or // Use SSA to get the lower bounds for a variable use. - exists(RangeSsaDefinition def, LocalScopeVariable v | expr = def.getAUse(v) | + exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | result = getDefLowerBounds(def, v) ) } @@ -766,7 +764,7 @@ private float getUpperBoundsImpl(Expr expr) { ) or // Use SSA to get the upper bounds for a variable use. - exists(RangeSsaDefinition def, LocalScopeVariable v | expr = def.getAUse(v) | + exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | result = getDefUpperBounds(def, v) ) } @@ -860,7 +858,7 @@ private float boolConversionUpperBound(Expr expr) { * In this example, the lower bound of x is 0, but we can * use the guard to deduce that the lower bound is 2 inside the block. */ -private float getPhiLowerBounds(LocalScopeVariable v, RangeSsaDefinition phi) { +private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) { exists( VariableAccess access, ComparisonOperation guard, boolean branch, float defLB, float guardLB | @@ -877,7 +875,7 @@ private float getPhiLowerBounds(LocalScopeVariable v, RangeSsaDefinition phi) { } /** See comment for `getPhiLowerBounds`, above. */ -private float getPhiUpperBounds(LocalScopeVariable v, RangeSsaDefinition phi) { +private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) { exists( VariableAccess access, ComparisonOperation guard, boolean branch, float defUB, float guardUB | @@ -894,7 +892,7 @@ private float getPhiUpperBounds(LocalScopeVariable v, RangeSsaDefinition phi) { } /** Only to be called by `getDefLowerBounds`. */ -private float getDefLowerBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) { +private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) { // Definitions with a defining value. exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedLowerBounds(expr)) or @@ -936,7 +934,7 @@ private float getDefLowerBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v } /** Only to be called by `getDefUpperBounds`. */ -private float getDefUpperBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) { +private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) { // Definitions with a defining value. exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedUpperBounds(expr)) or @@ -982,7 +980,7 @@ private float getDefUpperBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v * done by `getDefLowerBoundsImpl`, but this is where widening is applied * to prevent the analysis from exploding due to a recursive definition. */ -private float getDefLowerBounds(RangeSsaDefinition def, LocalScopeVariable v) { +private float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) { exists(float newLB, float truncatedLB | newLB = getDefLowerBoundsImpl(def, v) and if varMinVal(v) <= newLB and newLB <= varMaxVal(v) @@ -1011,7 +1009,7 @@ private float getDefLowerBounds(RangeSsaDefinition def, LocalScopeVariable v) { } /** See comment for `getDefLowerBounds`, above. */ -private float getDefUpperBounds(RangeSsaDefinition def, LocalScopeVariable v) { +private float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) { exists(float newUB, float truncatedUB | newUB = getDefUpperBoundsImpl(def, v) and if varMinVal(v) <= newUB and newUB <= varMaxVal(v) @@ -1044,9 +1042,7 @@ private float getDefUpperBounds(RangeSsaDefinition def, LocalScopeVariable v) { * unanalyzable definitions (such as function parameters) and make their * bounds unknown. */ -private predicate unanalyzableDefBounds( - RangeSsaDefinition def, LocalScopeVariable v, float lb, float ub -) { +private predicate unanalyzableDefBounds(RangeSsaDefinition def, StackVariable v, float lb, float ub) { v = def.getAVariable() and not analyzableDef(def, v) and lb = varMinVal(v) and @@ -1268,13 +1264,13 @@ private module SimpleRangeAnalysisCached { /** Holds if the definition might overflow negatively. */ cached - predicate defMightOverflowNegatively(RangeSsaDefinition def, LocalScopeVariable v) { + predicate defMightOverflowNegatively(RangeSsaDefinition def, StackVariable v) { getDefLowerBoundsImpl(def, v) < varMinVal(v) } /** Holds if the definition might overflow positively. */ cached - predicate defMightOverflowPositively(RangeSsaDefinition def, LocalScopeVariable v) { + predicate defMightOverflowPositively(RangeSsaDefinition def, StackVariable v) { getDefUpperBoundsImpl(def, v) > varMaxVal(v) } @@ -1283,7 +1279,7 @@ private module SimpleRangeAnalysisCached { * negatively). */ cached - predicate defMightOverflow(RangeSsaDefinition def, LocalScopeVariable v) { + predicate defMightOverflow(RangeSsaDefinition def, StackVariable v) { defMightOverflowNegatively(def, v) or defMightOverflowPositively(def, v) } diff --git a/cpp/ql/src/semmle/code/cpp/valuenumbering/GlobalValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/valuenumbering/GlobalValueNumbering.qll index 5c8196c15e0..f9231e24725 100644 --- a/cpp/ql/src/semmle/code/cpp/valuenumbering/GlobalValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/valuenumbering/GlobalValueNumbering.qll @@ -170,8 +170,8 @@ private newtype GVNBase = GVN_FloatConst(float val, Type t) { mk_FloatConst(val, t, _) } or // If the local variable does not have a defining value, then // we use the SsaDefinition as its global value number. - GVN_UndefinedLocalScopeVariable(LocalScopeVariable x, SsaDefinition def) { - mk_UndefinedLocalScopeVariable(x, def, _) + GVN_UndefinedStackVariable(StackVariable x, SsaDefinition def) { + mk_UndefinedStackVariable(x, def, _) } or // Variables with no SSA information. As a crude (but safe) // approximation, we use `mostRecentSideEffect` to compute a definition @@ -235,8 +235,8 @@ class GVN extends GVNBase { if this instanceof GVN_FloatConst then result = "FloatConst" else - if this instanceof GVN_UndefinedLocalScopeVariable - then result = "UndefinedLocalScopeVariable" + if this instanceof GVN_UndefinedStackVariable + then result = "UndefinedStackVariable" else if this instanceof GVN_OtherVariable then result = "OtherVariable" @@ -307,7 +307,7 @@ private predicate mk_FloatConst(float val, Type t, Expr e) { t = e.getUnspecifiedType() } -private predicate analyzableLocalScopeVariable(VariableAccess access) { +private predicate analyzableStackVariable(VariableAccess access) { strictcount(SsaDefinition def | def.getAUse(_) = access | def) = 1 and strictcount(SsaDefinition def, Variable v | def.getAUse(v) = access | v) = 1 and count(SsaDefinition def, Variable v | @@ -322,10 +322,10 @@ private predicate analyzableLocalScopeVariable(VariableAccess access) { // defining value. If there is a defining value, then there is no // need to generate a fresh `GVN` for the access because `globalValueNumber` // will follow the chain and use the GVN of the defining value. -private predicate mk_UndefinedLocalScopeVariable( - LocalScopeVariable x, SsaDefinition def, VariableAccess access +private predicate mk_UndefinedStackVariable( + StackVariable x, SsaDefinition def, VariableAccess access ) { - analyzableLocalScopeVariable(access) and + analyzableStackVariable(access) and access = def.getAUse(x) and not exists(def.getDefiningValue(x)) } @@ -515,16 +515,16 @@ GVN globalValueNumber(Expr e) { ) or // Local variable with a defining value. - exists(LocalScopeVariable x, SsaDefinition def | - analyzableLocalScopeVariable(e) and + exists(StackVariable x, SsaDefinition def | + analyzableStackVariable(e) and e = def.getAUse(x) and result = globalValueNumber(def.getDefiningValue(x).getFullyConverted()) ) or // Local variable without a defining value. - exists(LocalScopeVariable x, SsaDefinition def | - mk_UndefinedLocalScopeVariable(x, def, e) and - result = GVN_UndefinedLocalScopeVariable(x, def) + exists(StackVariable x, SsaDefinition def | + mk_UndefinedStackVariable(x, def, e) and + result = GVN_UndefinedStackVariable(x, def) ) or // Variable with no SSA information. @@ -594,7 +594,7 @@ private predicate analyzableConst(Expr e) { */ private predicate analyzableExpr(Expr e) { analyzableConst(e) or - analyzableLocalScopeVariable(e) or + analyzableStackVariable(e) or analyzableDotFieldAccess(e) or analyzablePointerFieldAccess(e) or analyzableImplicitThisFieldAccess(e) or diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaCompleteness.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaCompleteness.ql index 7af147f73d6..5d11509470c 100644 --- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaCompleteness.ql +++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaCompleteness.ql @@ -9,12 +9,12 @@ import cpp import semmle.code.cpp.controlflow.SSA /* - * Count of number of uses of a LocalScopeVariable where no corresponding SSA definition exists, + * Count of number of uses of a StackVariable where no corresponding SSA definition exists, * but at least one SSA definition for that variable can reach that use. * Should always be zero *regardless* of the input */ -select count(LocalScopeVariable v, Expr use | +select count(StackVariable v, Expr use | exists(SsaDefinition def, BasicBlock db, BasicBlock ub | def.getAUse(v) = use and db.contains(def.getDefinition()) and ub.contains(use) | diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaDefUsePairs.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaDefUsePairs.ql index 2328645e098..9bcb32918aa 100644 --- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaDefUsePairs.ql +++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaDefUsePairs.ql @@ -7,6 +7,6 @@ import cpp import semmle.code.cpp.controlflow.SSA -from SsaDefinition def, LocalScopeVariable var, Expr use +from SsaDefinition def, StackVariable var, Expr use where def.getAUse(var) = use select def, def.toString(var), use diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaDominance.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaDominance.ql index 2bbf7c7707d..087b8a809fb 100644 --- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaDominance.ql +++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaDominance.ql @@ -12,7 +12,7 @@ import semmle.code.cpp.controlflow.SSA * Should always be zero *regardless* of the input */ -select count(SsaDefinition d, LocalScopeVariable v, Expr u | +select count(SsaDefinition d, StackVariable v, Expr u | d.getAUse(v) = u and not exists(BasicBlock bd, BasicBlock bu | bd.contains(mkElement(d).(ControlFlowNode)) and bu.contains(u) diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaLt.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaLt.ql index ef422265b61..37aaaba5013 100644 --- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaLt.ql +++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaLt.ql @@ -8,7 +8,7 @@ import cpp import semmle.code.cpp.controlflow.SSA import semmle.code.cpp.controlflow.Guards -from GuardedSsa def, LocalScopeVariable var, Expr other, int k, int start, int end, string op +from GuardedSsa def, StackVariable var, Expr other, int k, int start, int end, string op where exists(BasicBlock block | def.isLt(var, other, k, block, true) and op = "<" diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaPhiInputs.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaPhiInputs.ql index 353b6cd279c..c0ab984f671 100644 --- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaPhiInputs.ql +++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaPhiInputs.ql @@ -8,8 +8,7 @@ import cpp import semmle.code.cpp.controlflow.SSA from - File file, SsaDefinition phi, LocalScopeVariable var, SsaDefinition input, int philine, - int inputline + File file, SsaDefinition phi, StackVariable var, SsaDefinition input, int philine, int inputline where phi.getAPhiInput(var) = input and file = phi.getLocation().getFile() and diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaUniqueness.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaUniqueness.ql index bff4301287f..b42b2edf61f 100644 --- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaUniqueness.ql +++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaUniqueness.ql @@ -12,7 +12,7 @@ import semmle.code.cpp.controlflow.SSA * Should always be zero *regardless* of the input */ -select count(SsaDefinition d1, SsaDefinition d2, Expr u, LocalScopeVariable v | +select count(SsaDefinition d1, SsaDefinition d2, Expr u, StackVariable v | d1.getAUse(v) = u and d2.getAUse(v) = u and not d1 = d2 diff --git a/cpp/ql/test/library-tests/controlflow_stresstest/SsaDefUsePairs.ql b/cpp/ql/test/library-tests/controlflow_stresstest/SsaDefUsePairs.ql index 2328645e098..9bcb32918aa 100644 --- a/cpp/ql/test/library-tests/controlflow_stresstest/SsaDefUsePairs.ql +++ b/cpp/ql/test/library-tests/controlflow_stresstest/SsaDefUsePairs.ql @@ -7,6 +7,6 @@ import cpp import semmle.code.cpp.controlflow.SSA -from SsaDefinition def, LocalScopeVariable var, Expr use +from SsaDefinition def, StackVariable var, Expr use where def.getAUse(var) = use select def, def.toString(var), use diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.ql b/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.ql index 8be3004152e..71de17cbcf1 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.ql +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.ql @@ -1,5 +1,5 @@ import semmle.code.cpp.dataflow.internal.FlowVar -from LocalScopeVariable var, VariableAccess va +from Variable var, VariableAccess va where FlowVar_internal::mayBeUsedUninitialized(var, va) select var, va diff --git a/cpp/ql/test/library-tests/dataflow/variable/noInit.ql b/cpp/ql/test/library-tests/dataflow/variable/noInit.ql index 8be3004152e..71de17cbcf1 100644 --- a/cpp/ql/test/library-tests/dataflow/variable/noInit.ql +++ b/cpp/ql/test/library-tests/dataflow/variable/noInit.ql @@ -1,5 +1,5 @@ import semmle.code.cpp.dataflow.internal.FlowVar -from LocalScopeVariable var, VariableAccess va +from Variable var, VariableAccess va where FlowVar_internal::mayBeUsedUninitialized(var, va) select var, va diff --git a/cpp/ql/test/library-tests/defuse/definition.ql b/cpp/ql/test/library-tests/defuse/definition.ql index adcf9e68ffa..3bb62428895 100644 --- a/cpp/ql/test/library-tests/defuse/definition.ql +++ b/cpp/ql/test/library-tests/defuse/definition.ql @@ -1,5 +1,5 @@ import cpp -from LocalScopeVariable v, ControlFlowNode d +from StackVariable v, ControlFlowNode d where definition(v, d) select v, d diff --git a/cpp/ql/test/library-tests/defuse/definitionUsePairEquivalence.ql b/cpp/ql/test/library-tests/defuse/definitionUsePairEquivalence.ql index a84e397a97e..2d4474b3302 100644 --- a/cpp/ql/test/library-tests/defuse/definitionUsePairEquivalence.ql +++ b/cpp/ql/test/library-tests/defuse/definitionUsePairEquivalence.ql @@ -1,24 +1,22 @@ import cpp -import semmle.code.cpp.controlflow.LocalScopeVariableReachability +import semmle.code.cpp.controlflow.StackVariableReachability -// Test that def/use algorithm is an instance of LocalScopeVariableReachability -class MyDefOrUse extends LocalScopeVariableReachability { +// Test that def/use algorithm is an instance of StackVariableReachability +class MyDefOrUse extends StackVariableReachability { MyDefOrUse() { this = "MyDefUse" } - override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { definition(v, node) } + override predicate isSource(ControlFlowNode node, StackVariable v) { definition(v, node) } - override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { useOfVar(v, node) } + override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVar(v, node) } - override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) { - definitionBarrier(v, node) - } + override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) } } predicate equivalence() { - forall(LocalScopeVariable v, Expr first, Expr second | definitionUsePair(v, first, second) | + forall(StackVariable v, Expr first, Expr second | definitionUsePair(v, first, second) | exists(MyDefOrUse x | x.reaches(first, v, second)) ) and - forall(LocalScopeVariable v, Expr first, Expr second | + forall(StackVariable v, Expr first, Expr second | exists(MyDefOrUse x | x.reaches(first, v, second)) | definitionUsePair(v, first, second) diff --git a/cpp/ql/test/library-tests/defuse/exprDefinition.ql b/cpp/ql/test/library-tests/defuse/exprDefinition.ql index 4bf86e1ae17..531cb0f7436 100644 --- a/cpp/ql/test/library-tests/defuse/exprDefinition.ql +++ b/cpp/ql/test/library-tests/defuse/exprDefinition.ql @@ -1,5 +1,5 @@ import cpp -from LocalScopeVariable v, ControlFlowNode def, Expr e +from StackVariable v, ControlFlowNode def, Expr e where exprDefinition(v, def, e) select v, def, e diff --git a/cpp/ql/test/library-tests/defuse/useOfVar.ql b/cpp/ql/test/library-tests/defuse/useOfVar.ql index c68a1d6d19a..17ea92df3cd 100644 --- a/cpp/ql/test/library-tests/defuse/useOfVar.ql +++ b/cpp/ql/test/library-tests/defuse/useOfVar.ql @@ -1,5 +1,5 @@ import cpp -from LocalScopeVariable v, VariableAccess use +from StackVariable v, VariableAccess use where useOfVar(v, use) select v, use diff --git a/cpp/ql/test/library-tests/defuse/useOfVarActual.ql b/cpp/ql/test/library-tests/defuse/useOfVarActual.ql index d3ce210f780..45794ca661d 100644 --- a/cpp/ql/test/library-tests/defuse/useOfVarActual.ql +++ b/cpp/ql/test/library-tests/defuse/useOfVarActual.ql @@ -1,9 +1,9 @@ import cpp -from LocalScopeVariable v, VariableAccess use +from StackVariable v, VariableAccess use where useOfVarActual(v, use) and // Also check that `useOfVarActual` is a subset of `useOfVar`; if not // the query will not return any results - forall(LocalScopeVariable v0, VariableAccess use0 | useOfVarActual(v0, use0) | useOfVar(v0, use0)) + forall(StackVariable v0, VariableAccess use0 | useOfVarActual(v0, use0) | useOfVar(v0, use0)) select v, use diff --git a/cpp/ql/test/library-tests/literal_locations/duplicate_literal_locations.ql b/cpp/ql/test/library-tests/literal_locations/duplicate_literal_locations.ql index 4bf86e1ae17..531cb0f7436 100644 --- a/cpp/ql/test/library-tests/literal_locations/duplicate_literal_locations.ql +++ b/cpp/ql/test/library-tests/literal_locations/duplicate_literal_locations.ql @@ -1,5 +1,5 @@ import cpp -from LocalScopeVariable v, ControlFlowNode def, Expr e +from StackVariable v, ControlFlowNode def, Expr e where exprDefinition(v, def, e) select v, def, e diff --git a/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaCompleteness.ql b/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaCompleteness.ql index 232f64e7154..6cfa00f08b4 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaCompleteness.ql +++ b/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaCompleteness.ql @@ -10,12 +10,12 @@ import cpp import semmle.code.cpp.rangeanalysis.RangeSSA /* - * Count of number of uses of a LocalScopeVariable where no corresponding SSA definition exists, + * Count of number of uses of a StackVariable where no corresponding SSA definition exists, * but at least one SSA definition for that variable can reach that use. * Should always be zero *regardless* of the input */ -select count(LocalScopeVariable v, Expr use | +select count(StackVariable v, Expr use | exists(RangeSsaDefinition def, BasicBlock db, BasicBlock ub | def.getAUse(v) = use and db.contains(def.getDefinition()) and ub.contains(use) | diff --git a/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaDefUsePairs.ql b/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaDefUsePairs.ql index 762fcfa8a3b..5c0acadb9db 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaDefUsePairs.ql +++ b/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaDefUsePairs.ql @@ -7,6 +7,6 @@ import cpp import semmle.code.cpp.rangeanalysis.RangeSSA -from RangeSsaDefinition def, LocalScopeVariable var, Expr use +from RangeSsaDefinition def, StackVariable var, Expr use where def.getAUse(var) = use select def, def.toString(var), use diff --git a/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaDominance.ql b/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaDominance.ql index 2f9fafef0ab..6dab291f125 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaDominance.ql +++ b/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaDominance.ql @@ -12,7 +12,7 @@ import semmle.code.cpp.rangeanalysis.RangeSSA * Should always be zero *regardless* of the input */ -select count(RangeSsaDefinition d, LocalScopeVariable v, Expr u | +select count(RangeSsaDefinition d, StackVariable v, Expr u | d.getAUse(v) = u and not exists(BasicBlock bd, BasicBlock bu | bd.contains(mkElement(d).(ControlFlowNode)) and bu.contains(u) diff --git a/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaPhiInputs.ql b/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaPhiInputs.ql index 2e1f038d136..b6808eccbc0 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaPhiInputs.ql +++ b/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaPhiInputs.ql @@ -7,9 +7,7 @@ import cpp import semmle.code.cpp.rangeanalysis.RangeSSA -from - RangeSsaDefinition phi, LocalScopeVariable var, RangeSsaDefinition input, int philine, - int inputline +from RangeSsaDefinition phi, StackVariable var, RangeSsaDefinition input, int philine, int inputline where phi.getAPhiInput(var) = input and philine = phi.getLocation().getStartLine() and diff --git a/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaUniqueness.ql b/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaUniqueness.ql index fda74759074..2fb56b8ef89 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaUniqueness.ql +++ b/cpp/ql/test/library-tests/rangeanalysis/RangeSSA/RangeSsaUniqueness.ql @@ -12,7 +12,7 @@ import semmle.code.cpp.rangeanalysis.RangeSSA * Should always be zero *regardless* of the input */ -select count(RangeSsaDefinition d1, RangeSsaDefinition d2, Expr u, LocalScopeVariable v | +select count(RangeSsaDefinition d1, RangeSsaDefinition d2, Expr u, StackVariable v | d1.getAUse(v) = u and d2.getAUse(v) = u and not d1 = d2 diff --git a/cpp/ql/test/library-tests/variables/variables/variable.expected b/cpp/ql/test/library-tests/variables/variables/variable.expected index 0599d840068..11a68882ddc 100644 --- a/cpp/ql/test/library-tests/variables/variables/variable.expected +++ b/cpp/ql/test/library-tests/variables/variables/variable.expected @@ -2,13 +2,9 @@ | file://:0:0:0:0 | gp_offset | file://:0:0:0:0 | unsigned int | Field | | | | file://:0:0:0:0 | overflow_arg_area | file://:0:0:0:0 | void * | Field | | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | __va_list_tag && | SemanticStackVariable | | | -| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | __va_list_tag && | StackVariable | | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | address && | SemanticStackVariable | | | -| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | address && | StackVariable | | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const __va_list_tag & | SemanticStackVariable | | | -| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const __va_list_tag & | StackVariable | | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const address & | SemanticStackVariable | | | -| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const address & | StackVariable | | | | file://:0:0:0:0 | reg_save_area | file://:0:0:0:0 | void * | Field | | | | variables.cpp:1:12:1:12 | i | file://:0:0:0:0 | int | GlobalVariable | | | | variables.cpp:2:12:2:12 | i | file://:0:0:0:0 | int | GlobalVariable | | | @@ -38,11 +34,10 @@ | variables.cpp:37:6:37:8 | ap3 | file://:0:0:0:0 | int * | GlobalVariable | | | | variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | LocalVariable | | | | variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | SemanticStackVariable | | | -| variables.cpp:41:7:41:11 | local | file://:0:0:0:0 | char[] | StackVariable | | | | variables.cpp:43:14:43:18 | local | file://:0:0:0:0 | int | LocalVariable | | static | -| variables.cpp:43:14:43:18 | local | file://:0:0:0:0 | int | StackVariable | | static | | variables.cpp:48:9:48:12 | name | file://:0:0:0:0 | char * | Field | | | | variables.cpp:49:12:49:17 | number | file://:0:0:0:0 | long | Field | | | | variables.cpp:50:9:50:14 | street | file://:0:0:0:0 | char * | Field | | | | variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | Field | | | | variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | MemberVariable | | static | +| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | GlobalVariable | | | diff --git a/cpp/ql/test/library-tests/variables/variables/variables.cpp b/cpp/ql/test/library-tests/variables/variables/variables.cpp index cbca2b3b822..6cbbacebc3c 100644 --- a/cpp/ql/test/library-tests/variables/variables/variables.cpp +++ b/cpp/ql/test/library-tests/variables/variables/variables.cpp @@ -51,3 +51,7 @@ struct address { char* town; static char* country; }; + +void hasExtern() { + extern int externInFunction; +}