Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 35 additions & 31 deletions ruby/ql/lib/codeql/ruby/ast/internal/Literal.qll
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ private import codeql.ruby.ast.internal.Scope
private import codeql.ruby.controlflow.CfgNodes
private import codeql.util.Numbers

bindingset[t]
pragma[inline_late]
private string getTokenValue(Ruby::Token t) { result = t.getValue() }

int parseInteger(Ruby::Integer i) {
exists(string s | s = i.getValue().toLowerCase().replaceAll("_", "") |
exists(string s | s = getTokenValue(i).toLowerCase().replaceAll("_", "") |
s.charAt(0) != "0" and
result = s.toInt()
or
Expand Down Expand Up @@ -38,7 +42,7 @@ class IntegerLiteralReal extends IntegerLiteralImpl, TIntegerLiteralReal {

final override int getValue() { result = parseInteger(g) }

final override string toString() { result = g.getValue() }
final override string toString() { result = getTokenValue(g) }
}

class IntegerLiteralSynth extends IntegerLiteralImpl, TIntegerLiteralSynth {
Expand All @@ -52,7 +56,7 @@ class IntegerLiteralSynth extends IntegerLiteralImpl, TIntegerLiteralSynth {
}

// TODO: implement properly
float parseFloat(Ruby::Float f) { result = f.getValue().toFloat() }
float parseFloat(Ruby::Float f) { result = getTokenValue(f).toFloat() }

class FloatLiteralImpl extends Expr, TFloatLiteral {
private Ruby::Float g;
Expand All @@ -61,7 +65,7 @@ class FloatLiteralImpl extends Expr, TFloatLiteral {

final float getValue() { result = parseFloat(g) }

final override string toString() { result = g.getValue() }
final override string toString() { result = getTokenValue(g) }
}

predicate isRationalValue(Ruby::Rational r, int numerator, int denominator) {
Expand All @@ -71,8 +75,8 @@ predicate isRationalValue(Ruby::Rational r, int numerator, int denominator) {
exists(Ruby::Float f, string regex, string before, string after |
f = r.getChild() and
regex = "([^.]*)\\.(.*)" and
before = f.getValue().regexpCapture(regex, 1) and
after = f.getValue().regexpCapture(regex, 2) and
before = getTokenValue(f).regexpCapture(regex, 1) and
after = getTokenValue(f).regexpCapture(regex, 2) and
numerator = before.toInt() * denominator + after.toInt() and
denominator = 10.pow(after.length())
)
Expand All @@ -87,14 +91,14 @@ class RationalLiteralImpl extends Expr, TRationalLiteral {
isRationalValue(g, numerator, denominator)
}

final override string toString() { result = g.getChild().(Ruby::Token).getValue() + "r" }
final override string toString() { result = getTokenValue(g.getChild()) + "r" }
}

float getComplexValue(Ruby::Complex c) {
exists(int n, int d | isRationalValue(c.getChild(), n, d) and result = n.(float) / d.(float))
or
exists(string s |
s = c.getChild().(Ruby::Token).getValue() and
s = getTokenValue(c.getChild()) and
result = s.prefix(s.length()).toFloat()
)
}
Expand All @@ -109,8 +113,8 @@ class ComplexLiteralImpl extends Expr, TComplexLiteral {
}

final override string toString() {
result = g.getChild().(Ruby::Token).getValue() + "i" or
result = g.getChild().(Ruby::Rational).getChild().(Ruby::Token).getValue() + "ri"
result = getTokenValue(g.getChild()) + "i" or
result = getTokenValue(g.getChild().(Ruby::Rational).getChild()) + "ri"
}
}

Expand All @@ -137,7 +141,7 @@ class TrueLiteral extends BooleanLiteralImpl, TTrueLiteral {

TrueLiteral() { this = TTrueLiteral(g) }

final override string toString() { result = g.getValue() }
final override string toString() { result = getTokenValue(g) }

final override boolean getValue() { result = true }
}
Expand All @@ -147,7 +151,7 @@ class FalseLiteral extends BooleanLiteralImpl, TFalseLiteral {

FalseLiteral() { this = TFalseLiteral(g) }

final override string toString() { result = g.getValue() }
final override string toString() { result = getTokenValue(g) }

final override boolean getValue() { result = false }
}
Expand Down Expand Up @@ -290,9 +294,9 @@ class RangeLiteralSynth extends RangeLiteralImpl, TRangeLiteralSynth {
}

private string getMethodName(MethodName::Token t) {
result = t.(Ruby::Token).getValue()
result = getTokenValue(t)
or
result = t.(Ruby::Setter).getName().getValue() + "="
result = getTokenValue(t.(Ruby::Setter).getName()) + "="
}

class TokenMethodName extends Expr, TTokenMethodName {
Expand Down Expand Up @@ -339,9 +343,9 @@ class StringTextComponentStringOrHeredocContent extends StringTextComponentImpl,

final override string getValue() { result = this.getUnescapedText() }

final override string getRawTextImpl() { result = g.getValue() }
final override string getRawTextImpl() { result = getTokenValue(g) }

final private string getUnescapedText() { result = unescapeTextComponent(g.getValue()) }
final private string getUnescapedText() { result = unescapeTextComponent(getTokenValue(g)) }
}

private class StringTextComponentSimpleSymbol extends StringTextComponentImpl,
Expand All @@ -352,7 +356,7 @@ private class StringTextComponentSimpleSymbol extends StringTextComponentImpl,
StringTextComponentSimpleSymbol() { this = TStringTextComponentNonRegexpSimpleSymbol(g) }

// Tree-sitter gives us value text including the colon, which we skip.
private string getSimpleSymbolValue() { result = g.getValue().suffix(1) }
private string getSimpleSymbolValue() { result = getTokenValue(g).suffix(1) }

final override string getValue() { result = this.getSimpleSymbolValue() }

Expand All @@ -366,9 +370,9 @@ private class StringTextComponentHashKeySymbol extends StringTextComponentImpl,

StringTextComponentHashKeySymbol() { this = TStringTextComponentNonRegexpHashKeySymbol(g) }

final override string getValue() { result = g.getValue() }
final override string getValue() { result = getTokenValue(g) }

final override string getRawTextImpl() { result = g.getValue() }
final override string getRawTextImpl() { result = getTokenValue(g) }
}

bindingset[escaped]
Expand Down Expand Up @@ -438,9 +442,9 @@ class StringEscapeSequenceComponentImpl extends StringComponentImpl,

final override string getValue() { result = this.getUnescapedText() }

final string getRawTextImpl() { result = g.getValue() }
final string getRawTextImpl() { result = getTokenValue(g) }

final private string getUnescapedText() { result = unescapeEscapeSequence(g.getValue()) }
final private string getUnescapedText() { result = unescapeEscapeSequence(getTokenValue(g)) }

final override string toString() { result = this.getRawTextImpl() }
}
Expand Down Expand Up @@ -473,10 +477,10 @@ class RegExpTextComponentImpl extends RegExpComponentImpl, TStringTextComponentR
// Exclude components that are children of a free-spacing regex.
// We do this because `ParseRegExp.qll` cannot handle free-spacing regexes.
not this.getParent().(RegExpLiteral).hasFreeSpacingFlag() and
result = g.getValue()
result = getTokenValue(g)
}

final override string toString() { result = g.getValue() }
final override string toString() { result = getTokenValue(g) }
}

class RegExpEscapeSequenceComponentImpl extends RegExpComponentImpl,
Expand All @@ -490,10 +494,10 @@ class RegExpEscapeSequenceComponentImpl extends RegExpComponentImpl,
// Exclude components that are children of a free-spacing regex.
// We do this because `ParseRegExp.qll` cannot handle free-spacing regexes.
not this.getParent().(RegExpLiteral).hasFreeSpacingFlag() and
result = g.getValue()
result = getTokenValue(g)
}

final override string toString() { result = g.getValue() }
final override string toString() { result = getTokenValue(g) }
}

class RegExpInterpolationComponentImpl extends RegExpComponentImpl,
Expand Down Expand Up @@ -564,7 +568,7 @@ abstract class StringlikeLiteralImpl extends Expr, TStringlikeLiteral {
concat(StringComponent c, int i, string s |
c = this.getComponentImpl(i) and
(
s = toGenerated(c).(Ruby::Token).getValue()
s = getTokenValue(toGenerated(c))
or
not toGenerated(c) instanceof Ruby::Token and
s = "#{...}"
Expand Down Expand Up @@ -635,7 +639,7 @@ class SimpleSymbolLiteralReal extends SimpleSymbolLiteralImpl, TSimpleSymbolLite

final override StringComponent getComponentImpl(int n) { n = 0 and toGenerated(result) = g }

final override string toString() { result = g.getValue() }
final override string toString() { result = getTokenValue(g) }
}

class SimpleSymbolLiteralSynth extends SimpleSymbolLiteralImpl, TSimpleSymbolLiteralSynth,
Expand Down Expand Up @@ -677,7 +681,7 @@ private class HashKeySymbolLiteral extends SymbolLiteralImpl, THashKeySymbolLite

final override StringComponent getComponentImpl(int n) { n = 0 and toGenerated(result) = g }

final override string toString() { result = ":" + g.getValue() }
final override string toString() { result = ":" + getTokenValue(g) }
}

class RegExpLiteralImpl extends StringlikeLiteralImpl, TRegExpLiteral {
Expand All @@ -701,9 +705,9 @@ class CharacterLiteralImpl extends Expr, TCharacterLiteral {

CharacterLiteralImpl() { this = TCharacterLiteral(g) }

final string getValue() { result = g.getValue() }
final string getValue() { result = getTokenValue(g) }

final override string toString() { result = g.getValue() }
final override string toString() { result = getTokenValue(g) }
}

class HereDocImpl extends StringlikeLiteralImpl, THereDoc {
Expand All @@ -715,5 +719,5 @@ class HereDocImpl extends StringlikeLiteralImpl, THereDoc {
toGenerated(result) = getHereDocBody(g).getChild(n)
}

final override string toString() { result = g.getValue() }
final override string toString() { result = getTokenValue(g) }
}
6 changes: 3 additions & 3 deletions ruby/ql/lib/codeql/ruby/ast/internal/Module.qll
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ private TMethodOrExpr lookupMethodOrConst(Module m, string name) {
// For now, we restrict the scope of top-level declarations to their file.
// This may remove some plausible targets, but also removes a lot of
// implausible targets
if getNode(result).getEnclosingModule() instanceof Toplevel
then getNode(result).getFile() = m.getADeclaration().getFile()
else any()
forall(File file | file = getNode(result).getEnclosingModule().(Toplevel).getFile() |
file = m.getADeclaration().getFile()
)
}
16 changes: 11 additions & 5 deletions ruby/ql/lib/codeql/ruby/ast/internal/Scope.qll
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,11 @@ cached
private module Cached {
/** Gets the enclosing scope of a node */
cached
Scope::Range scopeOf(Ruby::AstNode n) {
Scope::Range scopeOfImpl(Ruby::AstNode n) {
exists(Ruby::AstNode p | p = parentOf(n) |
p = result
or
not p instanceof Scope::Range and result = scopeOf(p)
not p instanceof Scope::Range and result = scopeOfImpl(p)
)
}

Expand All @@ -163,16 +163,22 @@ private module Cached {
* and synthesized scopes into account.
*/
cached
Scope scopeOfInclSynth(AstNode n) {
Scope scopeOfInclSynthImpl(AstNode n) {
exists(AstNode p | p = parentOfInclSynth(n) |
p = result
or
not p instanceof Scope and result = scopeOfInclSynth(p)
not p instanceof Scope and result = scopeOfInclSynthImpl(p)
)
}
}

import Cached
bindingset[n]
pragma[inline_late]
Scope::Range scopeOf(Ruby::AstNode n) { result = Cached::scopeOfImpl(n) }

bindingset[n]
pragma[inline_late]
Scope scopeOfInclSynth(AstNode n) { result = Cached::scopeOfInclSynthImpl(n) }

abstract class ScopeImpl extends AstNode, TScopeType {
final Scope getOuterScopeImpl() { result = scopeOfInclSynth(this) }
Expand Down
38 changes: 21 additions & 17 deletions ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll
Original file line number Diff line number Diff line change
Expand Up @@ -687,26 +687,30 @@ pragma[nomagic]
private CfgScope getTargetInstance(DataFlowCall call, string method) {
exists(boolean exact |
result = lookupInstanceMethodCall(call, method, exact) and
(
if result.(Method).isPrivate()
then
call.asCall().getReceiver().getExpr() instanceof SelfVariableAccess and
// For now, we restrict the scope of top-level declarations to their file.
// This may remove some plausible targets, but also removes a lot of
// implausible targets
(
isToplevelMethodInFile(result, call.asCall().getFile()) or
not isToplevelMethodInFile(result, _)
)
else any()
) and
if result.(Method).isProtected()
then
result = lookupMethod(call.asCall().getExpr().getEnclosingModule().getModule(), method, exact)
else any()
(if result.(Method).isPrivate() then result = privateFilter(call) else any()) and
if result.(Method).isProtected() then result = protectedFilter(call, method, exact) else any()
)
}

bindingset[call, result]
pragma[inline_late]
private CfgScope privateFilter(DataFlowCall call) {
call.asCall().getReceiver().getExpr() instanceof SelfVariableAccess and
// For now, we restrict the scope of top-level declarations to their file.
// This may remove some plausible targets, but also removes a lot of
// implausible targets
(
isToplevelMethodInFile(result, call.asCall().getFile()) or
not isToplevelMethodInFile(result, _)
)
}

bindingset[call, method, exact, result]
pragma[inline_late]
private CfgScope protectedFilter(DataFlowCall call, string method, boolean exact) {
result = lookupMethod(call.asCall().getExpr().getEnclosingModule().getModule(), method, exact)
}

private module TrackBlockInput implements CallGraphConstruction::Simple::InputSig {
class State = Block;

Expand Down
Loading
Loading