Merge branch 'main' into moresensitive2

This commit is contained in:
Geoffrey White
2025-07-14 11:58:08 +01:00
186 changed files with 6792 additions and 2004 deletions

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* Most classes and predicates in the AST, SSA, and control-flow-graph libraries are now annotated with `overlay[local]`, in preparation for incremental analysis. This could result in compiler errors for custom queries if they extend these classes. To mitigate such errors, look for ways to restructure custom QL code so it doesn't depend on changing the behavior of standard-library classes.

View File

@@ -1,4 +1,6 @@
/** Provides classes for working with locations. */
overlay[local]
module;
import files.FileSystem

View File

@@ -1,4 +1,6 @@
/** Provides classes for working with files and folders. */
overlay[local]
module;
private import codeql.Locations
private import codeql.util.FileSystem

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import codeql.Locations
import ast.Call
import ast.Control

View File

@@ -1,4 +1,6 @@
/** Provides classes relating to extraction diagnostics. */
overlay[local]
module;
private import codeql.Locations

View File

@@ -1,6 +1,10 @@
overlay[local]
module;
private import codeql.ruby.AST
private import internal.AST
private import internal.Call
private import internal.Literal
private import internal.TreeSitter
private import codeql.ruby.dataflow.internal.DataFlowDispatch
private import codeql.ruby.dataflow.internal.DataFlowImplCommon
@@ -41,7 +45,7 @@ class Call extends Expr instanceof CallImpl {
final Expr getKeywordArgument(string keyword) {
exists(Pair p |
p = this.getAnArgument() and
p.getKey().getConstantValue().isSymbol(keyword) and
keyword = p.getKey().(SymbolLiteral).(StringlikeLiteralImpl).getStringValue() and
result = p.getValue()
)
}
@@ -52,6 +56,7 @@ class Call extends Expr instanceof CallImpl {
final int getNumberOfArguments() { result = super.getNumberOfArgumentsImpl() }
/** Gets a potential target of this call, if any. */
overlay[global]
final Callable getATarget() {
exists(DataFlowCall c |
this = c.asCall().getExpr() and
@@ -153,6 +158,7 @@ class MethodCall extends Call instanceof MethodCallImpl {
* TODO: When API Graphs is able to resolve calls to methods like `Kernel.send`
* this class is no longer necessary and should be removed.
*/
overlay[global]
class UnknownMethodCall extends MethodCall {
UnknownMethodCall() { not exists(this.(Call).getATarget()) }
}

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import internal.AST
private import internal.Constant
@@ -6,6 +9,7 @@ private import internal.Variable
private import internal.TreeSitter
/** A constant value. */
overlay[global]
class ConstantValue extends TConstantValue {
/** Gets a textual representation of this constant value. */
final string toString() { this.hasValueWithType(result, _) }
@@ -134,6 +138,7 @@ class ConstantValue extends TConstantValue {
}
/** Provides different sub classes of `ConstantValue`. */
overlay[global]
module ConstantValue {
/** A constant integer value. */
class ConstantIntegerValue extends ConstantValue, TInt { }
@@ -268,15 +273,18 @@ class ConstantReadAccess extends ConstantAccess {
*
* the value being read at `M::CONST` is `"const"`.
*/
overlay[global]
Expr getValue() { result = getConstantReadAccessValue(this) }
/**
* Gets a fully qualified name for this constant read, based on the context in
* which it occurs.
*/
overlay[global]
string getAQualifiedName() { result = resolveConstant(this) }
/** Gets the module that this read access resolves to, if any. */
overlay[global]
Module getModule() { result = resolveConstantReadAccess(this) }
final override string getAPrimaryQlClass() { result = "ConstantReadAccess" }
@@ -342,6 +350,7 @@ class ConstantWriteAccess extends ConstantAccess {
* constants up the namespace chain, the fully qualified name of a nested
* constant can be ambiguous from just statically looking at the AST.
*/
overlay[global]
string getAQualifiedName() { result = resolveConstantWrite(this) }
}

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import internal.AST
private import internal.Control

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import internal.Erb
private import internal.TreeSitter

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.CFG
private import internal.AST
@@ -12,6 +15,7 @@ private import internal.TreeSitter
*/
class Expr extends Stmt, TExpr {
/** Gets the constant value of this expression, if any. */
overlay[global]
ConstantValue getConstantValue() { result = getConstantValueExpr(this) }
}
@@ -425,6 +429,7 @@ class StringConcatenation extends Expr, TStringConcatenation {
* "foo" "bar#{ n }"
* ```
*/
overlay[global]
final string getConcatenatedValueText() {
forall(StringLiteral c | c = this.getString(_) |
exists(c.getConstantValue().getStringlikeValue())

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.Regexp as RE
private import internal.AST
@@ -41,6 +44,7 @@ class IntegerLiteral extends NumericLiteral instanceof IntegerLiteralImpl {
/** Gets the numerical value of this integer literal. */
final int getValue() { result = super.getValue() }
overlay[global]
final override ConstantValue::ConstantIntegerValue getConstantValue() {
result = NumericLiteral.super.getConstantValue()
}
@@ -57,6 +61,7 @@ class IntegerLiteral extends NumericLiteral instanceof IntegerLiteralImpl {
* ```
*/
class FloatLiteral extends NumericLiteral instanceof FloatLiteralImpl {
overlay[global]
final override ConstantValue::ConstantFloatValue getConstantValue() {
result = NumericLiteral.super.getConstantValue()
}
@@ -72,6 +77,7 @@ class FloatLiteral extends NumericLiteral instanceof FloatLiteralImpl {
* ```
*/
class RationalLiteral extends NumericLiteral instanceof RationalLiteralImpl {
overlay[global]
final override ConstantValue::ConstantRationalValue getConstantValue() {
result = NumericLiteral.super.getConstantValue()
}
@@ -87,6 +93,7 @@ class RationalLiteral extends NumericLiteral instanceof RationalLiteralImpl {
* ```
*/
class ComplexLiteral extends NumericLiteral instanceof ComplexLiteralImpl {
overlay[global]
final override ConstantValue::ConstantComplexValue getConstantValue() {
result = NumericLiteral.super.getConstantValue()
}
@@ -96,6 +103,7 @@ class ComplexLiteral extends NumericLiteral instanceof ComplexLiteralImpl {
/** A `nil` literal. */
class NilLiteral extends Literal instanceof NilLiteralImpl {
overlay[global]
final override ConstantValue::ConstantNilValue getConstantValue() { result = TNil() }
final override string getAPrimaryQlClass() { result = "NilLiteral" }
@@ -122,6 +130,7 @@ class BooleanLiteral extends Literal instanceof BooleanLiteralImpl {
/** Gets the value of this Boolean literal. */
boolean getValue() { result = super.getValue() }
overlay[global]
final override ConstantValue::ConstantBooleanValue getConstantValue() {
result = Literal.super.getConstantValue()
}
@@ -133,6 +142,7 @@ class BooleanLiteral extends Literal instanceof BooleanLiteralImpl {
class EncodingLiteral extends Literal instanceof EncodingLiteralImpl {
final override string getAPrimaryQlClass() { result = "EncodingLiteral" }
overlay[global]
final override ConstantValue::ConstantStringValue getConstantValue() {
result = Literal.super.getConstantValue()
}
@@ -144,6 +154,7 @@ class EncodingLiteral extends Literal instanceof EncodingLiteralImpl {
class LineLiteral extends Literal instanceof LineLiteralImpl {
final override string getAPrimaryQlClass() { result = "LineLiteral" }
overlay[global]
final override ConstantValue::ConstantIntegerValue getConstantValue() {
result = Literal.super.getConstantValue()
}
@@ -155,6 +166,7 @@ class LineLiteral extends Literal instanceof LineLiteralImpl {
class FileLiteral extends Literal instanceof FileLiteralImpl {
final override string getAPrimaryQlClass() { result = "FileLiteral" }
overlay[global]
final override ConstantValue::ConstantStringValue getConstantValue() {
result = Literal.super.getConstantValue()
}
@@ -166,6 +178,7 @@ class FileLiteral extends Literal instanceof FileLiteralImpl {
*/
class StringComponent extends AstNode instanceof StringComponentImpl {
/** Gets the constant value of this string component, if any. */
overlay[global]
ConstantValue::ConstantStringValue getConstantValue() { result = TString(super.getValue()) }
}
@@ -210,6 +223,7 @@ class StringInterpolationComponent extends StringComponent, StmtSequence instanc
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
overlay[global]
final override ConstantValue::ConstantStringValue getConstantValue() {
result = StmtSequence.super.getConstantValue()
}
@@ -257,6 +271,7 @@ class RegExpInterpolationComponent extends RegExpComponent, StmtSequence instanc
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
overlay[global]
final override ConstantValue::ConstantStringValue getConstantValue() {
result = StmtSequence.super.getConstantValue()
}
@@ -387,6 +402,7 @@ class RegExpLiteral extends StringlikeLiteral instanceof RegExpLiteralImpl {
final predicate hasFreeSpacingFlag() { this.getFlagString().charAt(_) = "x" }
/** Returns the root node of the parse tree of this regular expression. */
overlay[global]
final RE::RegExpTerm getParsed() { result = RE::getParsedRegExp(this) }
}
@@ -404,6 +420,7 @@ class SymbolLiteral extends StringlikeLiteral instanceof SymbolLiteralImpl {
not this instanceof MethodName and result = "SymbolLiteral"
}
overlay[global]
final override ConstantValue::ConstantSymbolValue getConstantValue() {
result = StringlikeLiteral.super.getConstantValue()
}
@@ -436,6 +453,7 @@ class SubshellLiteral extends StringlikeLiteral instanceof SubshellLiteralImpl {
class CharacterLiteral extends Literal instanceof CharacterLiteralImpl {
final override string getAPrimaryQlClass() { result = "CharacterLiteral" }
overlay[global]
final override ConstantValue::ConstantStringValue getConstantValue() {
result = Literal.super.getConstantValue()
}

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.controlflow.ControlFlowGraph
private import internal.AST
@@ -40,18 +43,22 @@ class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
* Holds if this method is public.
* Methods are public by default.
*/
overlay[global]
predicate isPublic() { this.getVisibility() = "public" }
/** Holds if this method is private. */
overlay[global]
predicate isPrivate() { this.getVisibility() = "private" }
/** Holds if this method is protected. */
overlay[global]
predicate isProtected() { this.getVisibility() = "protected" }
/**
* Gets a string describing the visibility of this method.
* This is either 'public', 'private' or 'protected'.
*/
overlay[global]
string getVisibility() {
result = getVisibilityModifier(this).getVisibility()
or
@@ -73,6 +80,7 @@ class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
* end
* ```
*/
overlay[global]
private VisibilityModifier getExplicitVisibilityModifier(Method m) {
result.getMethodArgument() = m
or
@@ -86,6 +94,7 @@ private VisibilityModifier getExplicitVisibilityModifier(Method m) {
* Gets the visibility modifier that defines the visibility of method `m`, if
* any.
*/
overlay[global]
private VisibilityModifier getVisibilityModifier(MethodBase mb) {
mb =
any(Method m |
@@ -202,6 +211,7 @@ class Method extends MethodBase, TMethod {
* end
* ```
*/
overlay[global]
override predicate isPrivate() { super.isPrivate() }
final override Parameter getParameter(int n) {
@@ -210,6 +220,7 @@ class Method extends MethodBase, TMethod {
final override string toString() { result = this.getName() }
overlay[global]
override string getVisibility() {
result = getVisibilityModifier(this).getVisibility()
or
@@ -223,6 +234,7 @@ class Method extends MethodBase, TMethod {
}
}
overlay[global]
pragma[nomagic]
private predicate modifiesIn(VisibilityModifier vm, ModuleBase n, string name) {
n = vm.getEnclosingModule() and
@@ -299,6 +311,7 @@ class SingletonMethod extends MethodBase, TSingletonMethod {
* end
* ```
*/
overlay[global]
override predicate isPrivate() { super.isPrivate() }
}

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.CFG
private import internal.AST
@@ -8,6 +11,7 @@ private import internal.Scope
/**
* A representation of a run-time `module` or `class` value.
*/
overlay[global]
class Module extends TModule {
/** Gets a declaration of this module, if any. */
ModuleBase getADeclaration() { result.getModule() = this }
@@ -255,6 +259,7 @@ class ModuleBase extends BodyStmt, Scope, TModuleBase {
}
/** Gets the representation of the run-time value of this module or class. */
overlay[global]
Module getModule() { none() }
/**
@@ -333,6 +338,7 @@ class Toplevel extends ModuleBase, TToplevel {
pred = "getBeginBlock" and result = this.getBeginBlock(_)
}
overlay[global]
final override Module getModule() { result = TResolved("Object") }
final override string toString() { result = g.getLocation().getFile().getBaseName() }
@@ -405,6 +411,7 @@ class Namespace extends ModuleBase, ConstantWriteAccess, TNamespace {
*/
override predicate hasGlobalScope() { none() }
overlay[global]
final override Module getModule() {
result = any(string qName | qName = namespaceDeclaration(this) | TResolved(qName))
or

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import internal.AST
private import internal.TreeSitter

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import internal.AST
private import internal.Variable

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import internal.AST
private import internal.Pattern
@@ -203,6 +206,7 @@ class HashPattern extends CasePattern, THashPattern {
}
/** Gets the value for a given key name. */
overlay[global]
CasePattern getValueByKey(string key) {
exists(int i |
this.getKey(i).getConstantValue().isStringlikeValue(key) and result = this.getValue(i)

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import internal.AST
private import internal.Scope

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.CFG
private import internal.AST

View File

@@ -1,4 +1,6 @@
/** Provides classes for modeling program variables. */
overlay[local]
module;
private import codeql.ruby.AST
private import internal.AST

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import codeql.Locations
private import TreeSitter
private import codeql.ruby.ast.internal.Call

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import TreeSitter
private import Variable
private import codeql.ruby.AST

View File

@@ -38,6 +38,7 @@ private import ExprNodes
* constant value in some cases.
*/
private module Propagation {
overlay[local]
ExprCfgNode getSource(VariableReadAccessCfgNode read) {
exists(Ssa::WriteDefinition def |
def.assigns(result) and
@@ -199,6 +200,7 @@ private module Propagation {
forex(ExprCfgNode n | n = e.getAControlFlowNode() | isComplex(n, real, imaginary))
}
overlay[local]
private class StringlikeLiteralWithInterpolationCfgNode extends StringlikeLiteralCfgNode {
StringlikeLiteralWithInterpolationCfgNode() {
this.getAComponent() =
@@ -208,6 +210,7 @@ private module Propagation {
)
}
overlay[global]
pragma[nomagic]
private string getComponentValue(int i) {
this.getComponent(i) =
@@ -219,17 +222,20 @@ private module Propagation {
}
language[monotonicAggregates]
overlay[global]
private string getValue() {
result =
strictconcat(int i | exists(this.getComponent(i)) | this.getComponentValue(i) order by i)
}
overlay[global]
pragma[nomagic]
string getSymbolValue() {
result = this.getValue() and
this.getExpr() instanceof SymbolLiteral
}
overlay[global]
pragma[nomagic]
string getStringValue() {
result = this.getValue() and
@@ -237,6 +243,7 @@ private module Propagation {
not this.getExpr() instanceof RegExpLiteral
}
overlay[global]
pragma[nomagic]
string getRegExpValue(string flags) {
result = this.getValue() and
@@ -566,6 +573,7 @@ private predicate isArrayExpr(Expr e, ArrayLiteralCfgNode arr) {
isArrayExpr(e.(MethodCall).getReceiver(), arr)
}
overlay[local]
private class TokenConstantAccess extends ConstantAccess, TTokenConstantAccess {
private Ruby::Constant g;
@@ -577,6 +585,7 @@ private class TokenConstantAccess extends ConstantAccess, TTokenConstantAccess {
/**
* A constant access that has a scope resolution qualifier.
*/
overlay[local]
class ScopeResolutionConstantAccess extends ConstantAccess, TScopeResolutionConstantAccess {
private Ruby::ScopeResolution g;
private Ruby::Constant constant;
@@ -595,6 +604,7 @@ class ScopeResolutionConstantAccess extends ConstantAccess, TScopeResolutionCons
final override predicate hasGlobalScope() { not exists(g.getScope()) }
}
overlay[local]
private class ConstantReadAccessSynth extends ConstantAccess, TConstantReadAccessSynth {
private string value;
@@ -609,6 +619,7 @@ private class ConstantReadAccessSynth extends ConstantAccess, TConstantReadAcces
final override predicate hasGlobalScope() { value.matches("::%") }
}
overlay[local]
private class ConstantWriteAccessSynth extends ConstantAccess, TConstantWriteAccessSynth {
private string value;

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import TreeSitter
private import codeql.ruby.AST
private import codeql.ruby.ast.internal.AST

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
import codeql.Locations
private import TreeSitter
private import codeql.ruby.ast.Erb

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.CFG
private import AST

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import AST
private import Constant

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import AST
private import TreeSitter

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import Scope as Scope
@@ -11,6 +14,7 @@ private string builtin() {
]
}
overlay[global]
cached
private module Cached {
cached
@@ -215,6 +219,7 @@ private string scopeAppend(string qualifier, string name) {
* both as a performance optimization (minimize non-linear recursion), and as a way
* to prevent infinite recursion.
*/
overlay[global]
private module ResolveImpl {
private ModuleBase enclosing(ModuleBase m, int level) {
result = m and level = 0
@@ -583,6 +588,7 @@ private ModuleBase enclosingModuleNoBlock(Stmt node) {
result = enclosingScopesNoBlock(Scope::scopeOfInclSynth(node))
}
overlay[global]
private Module getAncestors(Module m) {
result = m or
result = getAncestors(m.getAnIncludedModule()) or
@@ -593,6 +599,7 @@ private newtype TMethodOrExpr =
TMethod(Method m) or
TExpr(Expr e)
overlay[global]
private TMethodOrExpr getMethodOrConst(TModule owner, string name) {
exists(ModuleBase m | m.getModule() = owner |
result = TMethod(m.getMethod(name))
@@ -601,12 +608,14 @@ private TMethodOrExpr getMethodOrConst(TModule owner, string name) {
)
}
overlay[global]
module ExposedForTestingOnly {
Method getMethod(TModule owner, string name) { TMethod(result) = getMethodOrConst(owner, name) }
Expr getConst(TModule owner, string name) { TExpr(result) = getMethodOrConst(owner, name) }
}
overlay[global]
private TMethodOrExpr lookupMethodOrConst0(Module m, string name) {
result = lookupMethodOrConst0(m.getAPrependedModule(), name)
or
@@ -621,6 +630,7 @@ private TMethodOrExpr lookupMethodOrConst0(Module m, string name) {
private AstNode getNode(TMethodOrExpr e) { e = TMethod(result) or e = TExpr(result) }
overlay[global]
private TMethodOrExpr lookupMethodOrConst(Module m, string name) {
result = lookupMethodOrConst0(m, name)
or

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import AST
private import TreeSitter

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import AST
private import TreeSitter

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.ast.internal.Expr
private import codeql.ruby.ast.internal.Parameter

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import TreeSitter
private import codeql.ruby.AST
private import codeql.ruby.ast.internal.AST

View File

@@ -1,4 +1,6 @@
/** Provides predicates for synthesizing AST nodes. */
overlay[local]
module;
private import AST
private import TreeSitter

View File

@@ -23,6 +23,7 @@ private predicate discardLocation(@location_default loc) {
)
}
overlay[local]
module Ruby {
/** The base class for all AST nodes */
class AstNode extends @ruby_ast_node {
@@ -67,7 +68,6 @@ module Ruby {
}
/** Gets the file containing the given `node`. */
overlay[local]
private @file getNodeFile(@ruby_ast_node node) {
exists(@location_default loc | ruby_ast_node_location(node, loc) |
locations_default(loc, result, _, _, _, _)
@@ -75,7 +75,6 @@ module Ruby {
}
/** Holds if `node` is in the `file` and is part of the overlay base database. */
overlay[local]
private predicate discardableAstNode(@file file, @ruby_ast_node node) {
not isOverlay() and file = getNodeFile(node)
}
@@ -1967,6 +1966,7 @@ module Ruby {
}
}
overlay[local]
module Erb {
/** The base class for all AST nodes */
class AstNode extends @erb_ast_node {
@@ -2011,7 +2011,6 @@ module Erb {
}
/** Gets the file containing the given `node`. */
overlay[local]
private @file getNodeFile(@erb_ast_node node) {
exists(@location_default loc | erb_ast_node_location(node, loc) |
locations_default(loc, result, _, _, _, _)
@@ -2019,7 +2018,6 @@ module Erb {
}
/** Holds if `node` is in the `file` and is part of the overlay base database. */
overlay[local]
private predicate discardableAstNode(@file file, @erb_ast_node node) {
not isOverlay() and file = getNodeFile(node)
}

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import TreeSitter
private import codeql.ruby.AST
private import codeql.ruby.CFG

View File

@@ -1,4 +1,6 @@
/** Provides classes representing basic blocks. */
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.ast.internal.AST

View File

@@ -1,10 +1,11 @@
/** Provides classes representing nodes in a control flow graph. */
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.controlflow.BasicBlocks
private import codeql.ruby.dataflow.SSA
private import codeql.ruby.ast.internal.Constant
private import codeql.ruby.ast.internal.Literal
private import ControlFlowGraph
private import internal.ControlFlowGraphImpl as CfgImpl
@@ -36,11 +37,13 @@ class ExitNode extends CfgNode, CfgImpl::ExitNode {
*/
class AstCfgNode extends CfgNode, CfgImpl::AstCfgNode {
/** Gets the name of the primary QL class for this node. */
overlay[global]
override string getAPrimaryQlClass() { result = "AstCfgNode" }
}
/** A control-flow node that wraps an AST expression. */
class ExprCfgNode extends AstCfgNode {
overlay[global]
override string getAPrimaryQlClass() { result = "ExprCfgNode" }
Expr e;
@@ -51,6 +54,7 @@ class ExprCfgNode extends AstCfgNode {
Expr getExpr() { result = e }
/** Gets the constant value of this expression, if any. */
overlay[global]
ConstantValue getConstantValue() { result = getConstantValue(this) }
}
@@ -76,6 +80,7 @@ class StringComponentCfgNode extends AstCfgNode {
StringComponentCfgNode() { this.getAstNode() instanceof StringComponent }
/** Gets the constant value of this string component. */
overlay[global]
ConstantValue getConstantValue() {
result = this.getAstNode().(StringComponent).getConstantValue()
}
@@ -297,6 +302,7 @@ module ExprNodes {
/** A control-flow node that wraps a `Call` AST expression. */
class CallCfgNode extends ExprCfgNode {
overlay[global]
override string getAPrimaryQlClass() { result = "CallCfgNode" }
override CallExprChildMapping e;
@@ -310,6 +316,7 @@ module ExprNodes {
final ExprCfgNode getAnArgument() { result = this.getArgument(_) }
/** Gets the keyword argument whose key is `keyword` of this call. */
overlay[global]
final ExprCfgNode getKeywordArgument(string keyword) {
exists(PairCfgNode n |
e.hasCfgChild(e.getAnArgument(), this, n) and
@@ -338,6 +345,7 @@ module ExprNodes {
/** A control-flow node that wraps a `MethodCall` AST expression. */
class MethodCallCfgNode extends CallCfgNode {
overlay[global]
override string getAPrimaryQlClass() { result = "MethodCallCfgNode" }
MethodCallCfgNode() { super.getExpr() instanceof MethodCall }
@@ -842,6 +850,7 @@ module ExprNodes {
this.getAstNode() instanceof StringInterpolationComponent
}
overlay[global]
final override ConstantValue getConstantValue() {
result = StmtSequenceCfgNode.super.getConstantValue()
}
@@ -855,6 +864,7 @@ module ExprNodes {
this.getAstNode() instanceof RegExpInterpolationComponent
}
overlay[global]
final override ConstantValue getConstantValue() {
result = StmtSequenceCfgNode.super.getConstantValue()
}
@@ -946,6 +956,7 @@ module ExprNodes {
* into calls to `Array.[]`, so this includes both desugared calls as well as
* explicit calls.
*/
overlay[global]
class ArrayLiteralCfgNode extends MethodCallCfgNode {
override string getAPrimaryQlClass() { result = "ArrayLiteralCfgNode" }
@@ -963,6 +974,7 @@ module ExprNodes {
* into calls to `Hash.[]`, so this includes both desugared calls as well as
* explicit calls.
*/
overlay[global]
class HashLiteralCfgNode extends MethodCallCfgNode {
override string getAPrimaryQlClass() { result = "HashLiteralCfgNode" }

View File

@@ -1,4 +1,6 @@
/** Provides classes representing the control flow graph. */
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.controlflow.BasicBlocks
@@ -35,6 +37,7 @@ class CfgScope extends Scope instanceof CfgImpl::CfgScopeImpl {
*/
class CfgNode extends CfgImpl::Node {
/** Gets the name of the primary QL class for this node. */
overlay[global]
string getAPrimaryQlClass() { none() }
/** Gets the file of this control flow node. */

View File

@@ -3,6 +3,8 @@
*
* A completion represents how a statement or expression terminates.
*/
overlay[local]
module;
private import codeql.ruby.AST
private import codeql.ruby.ast.internal.AST

View File

@@ -2,6 +2,8 @@
* Provides an implementation for constructing control-flow graphs (CFGs) from
* abstract syntax trees (ASTs), using the shared library from `codeql.controlflow.Cfg`.
*/
overlay[local]
module;
private import codeql.controlflow.Cfg as CfgShared
private import codeql.ruby.AST

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ruby.CFG
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */

View File

@@ -1,4 +1,6 @@
/** Provides a simple analysis for identifying calls that will not return. */
overlay[local]
module;
private import codeql.ruby.AST
private import Completion

View File

@@ -1,6 +1,8 @@
/**
* Provides classes and predicates relevant for splitting the control flow graph.
*/
overlay[local]
module;
private import codeql.ruby.AST as Ast
private import Completion as Comp

View File

@@ -1,6 +1,8 @@
/**
* Provides the module `Ssa` for working with static single assignment (SSA) form.
*/
overlay[local]
module;
/**
* Provides classes for working with static single assignment (SSA) form.

View File

@@ -1,3 +1,6 @@
overlay[local]
module;
private import codeql.ssa.Ssa as SsaImplCommon
private import codeql.ruby.AST
private import codeql.ruby.CFG as Cfg
@@ -393,6 +396,7 @@ private module Cached {
signature predicate guardChecksSig(Cfg::CfgNodes::AstCfgNode g, Cfg::CfgNode e, boolean branch);
overlay[global]
cached // nothing is actually cached
module BarrierGuard<guardChecksSig/3 guardChecks> {
private predicate guardChecksAdjTypes(

View File

@@ -18,6 +18,16 @@ private module PolynomialReDoSConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
// Diff-informedness is disabled because of RegExpTerms having incorrect locations when
// the regexp is parsed from a string arising from constant folding.
predicate observeDiffInformedIncrementalMode() { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
result = sink.(Sink).getHighlight().getLocation()
or
result = sink.(Sink).getRegExp().getRootTerm().getLocation()
}
}
/**