Compare commits

...

1 Commits

Author SHA1 Message Date
Nick Rolfe
740fd27707 Ruby: add dataflow for getters/setters defined using alias_attribute 2022-11-08 12:47:05 +00:00
5 changed files with 207 additions and 1 deletions

View File

@@ -699,7 +699,7 @@ private DataFlow::Node trackInstanceRec(Module tp, TypeTracker t, boolean exact,
}
pragma[nomagic]
private DataFlow::Node trackInstance(Module tp, boolean exact) {
DataFlow::Node trackInstance(Module tp, boolean exact) {
result = trackInstance(tp, exact, TypeTracker::end())
}

View File

@@ -128,6 +128,12 @@ SummaryComponent interpretComponentSpecific(AccessPathToken c) {
result =
FlowSummary::SummaryComponent::content(TSingletonContent(TFieldContent(c.getAnArgument("Field"))))
or
result =
FlowSummary::SummaryComponent::withContent(TSingletonContent(TFieldContent(c.getAnArgument("WithField"))))
or
result =
FlowSummary::SummaryComponent::withoutContent(TSingletonContent(TFieldContent(c.getAnArgument("WithoutField"))))
or
exists(ContentSet cs |
FlowSummary::SummaryComponent::content(cs) = interpretElementArg(c.getAnArgument("WithElement")) and
result = FlowSummary::SummaryComponent::withContent(cs)

View File

@@ -260,6 +260,96 @@ module ActiveSupport {
}
// TODO: index_by, index_with, pick, pluck (they require Hash dataflow)
}
/** Extensions to the `Module` object. */
module Module {
private import codeql.ruby.dataflow.internal.DataFlowDispatch
/**
* Provides flow summaries for calls to setter methods that are defined using
* `alias_attribute`.
*
* ```rb
* class C
* alias_attribute :foo, :bar
* end
* x = C.new
* x.foo = 123 # sets `bar`
* ```
*/
private class AliasAttributeSetterSummary extends SummarizedCallable {
ClassDeclaration klass;
string aliasName;
string targetName;
AliasAttributeSetterSummary() {
exists(MethodCall aa | aa.getMethodName() = "alias_attribute" |
klass = aa.getEnclosingModule() and
aliasName = aa.getArgument(0).getConstantValue().getSymbol() and
targetName = aa.getArgument(1).getConstantValue().getSymbol() and
this = klass.getName() + "#" + aliasName + "="
)
}
override MethodCall getACall() {
// We're looking for a setter call using the alias name where the receiver
// is an instance of `klass`.
exists(Module m |
klass = m.getADeclaration() and
result.getReceiver() = trackInstance(m, true).asExpr().getExpr() and
result.(SetterMethodCall).getTargetName() = [aliasName, targetName]
)
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[0].WithoutField[@" + [aliasName, targetName] + "]" and
output = "Argument[self].Field[@" + [aliasName, targetName] + "]" and
preservesValue = true
}
}
/**
* Provides flow summaries for calls to getter methods that are defined using
* `alias_attribute`.
*
* ```rb
* class C
* alias_attribute :foo, :bar
* end
* x = C.new
* x.foo # gets `bar`
* ```
*/
private class AliasAttributeGetterSummary extends SummarizedCallable {
ClassDeclaration klass;
string aliasName;
string targetName;
AliasAttributeGetterSummary() {
exists(MethodCall aa | aa.getMethodName() = "alias_attribute" |
klass = aa.getEnclosingModule() and
aliasName = aa.getArgument(0).getConstantValue().getSymbol() and
targetName = aa.getArgument(1).getConstantValue().getSymbol() and
this = klass.getName() + "#" + aliasName
)
}
override MethodCall getACall() {
exists(Module m |
klass = m.getADeclaration() and
result.getReceiver() = trackInstance(m, true).asExpr().getExpr() and
result.getNumberOfArguments() = 0 and
result.getMethodName() = [aliasName, targetName]
)
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[self].Field[@" + [aliasName, targetName] + "]" and
output = "ReturnValue" and
preservesValue = true
}
}
}
}
/**

View File

@@ -1,4 +1,6 @@
failures
| active_support.rb:316:8:316:15 | call to name | Unexpected result: hasValueFlow=a |
| active_support.rb:317:8:317:19 | call to username | Unexpected result: hasValueFlow=a |
edges
| active_support.rb:10:9:10:18 | call to source : | active_support.rb:11:10:11:10 | x : |
| active_support.rb:11:10:11:10 | x : | active_support.rb:11:10:11:19 | call to at |
@@ -186,6 +188,54 @@ edges
| active_support.rb:290:7:290:16 | call to source : | active_support.rb:291:8:291:8 | x : |
| active_support.rb:291:8:291:8 | x : | active_support.rb:291:8:291:17 | call to deep_dup |
| active_support.rb:291:8:291:8 | x : | active_support.rb:291:8:291:17 | call to deep_dup |
| active_support.rb:309:3:309:5 | [post] foo [@name] : | active_support.rb:311:8:311:10 | foo [@name] : |
| active_support.rb:309:3:309:5 | [post] foo [@name] : | active_support.rb:311:8:311:10 | foo [@name] : |
| active_support.rb:309:3:309:5 | [post] foo [@name] : | active_support.rb:312:8:312:10 | foo [@name] : |
| active_support.rb:309:3:309:5 | [post] foo [@name] : | active_support.rb:312:8:312:10 | foo [@name] : |
| active_support.rb:309:3:309:5 | [post] foo [@name] : | active_support.rb:316:8:316:10 | foo [@name] : |
| active_support.rb:309:3:309:5 | [post] foo [@name] : | active_support.rb:316:8:316:10 | foo [@name] : |
| active_support.rb:309:3:309:5 | [post] foo [@name] : | active_support.rb:317:8:317:10 | foo [@name] : |
| active_support.rb:309:3:309:5 | [post] foo [@name] : | active_support.rb:317:8:317:10 | foo [@name] : |
| active_support.rb:309:3:309:5 | [post] foo [@username] : | active_support.rb:311:8:311:10 | foo [@username] : |
| active_support.rb:309:3:309:5 | [post] foo [@username] : | active_support.rb:311:8:311:10 | foo [@username] : |
| active_support.rb:309:3:309:5 | [post] foo [@username] : | active_support.rb:312:8:312:10 | foo [@username] : |
| active_support.rb:309:3:309:5 | [post] foo [@username] : | active_support.rb:312:8:312:10 | foo [@username] : |
| active_support.rb:309:3:309:5 | [post] foo [@username] : | active_support.rb:316:8:316:10 | foo [@username] : |
| active_support.rb:309:3:309:5 | [post] foo [@username] : | active_support.rb:316:8:316:10 | foo [@username] : |
| active_support.rb:309:3:309:5 | [post] foo [@username] : | active_support.rb:317:8:317:10 | foo [@username] : |
| active_support.rb:309:3:309:5 | [post] foo [@username] : | active_support.rb:317:8:317:10 | foo [@username] : |
| active_support.rb:309:14:309:23 | call to source : | active_support.rb:309:3:309:5 | [post] foo [@name] : |
| active_support.rb:309:14:309:23 | call to source : | active_support.rb:309:3:309:5 | [post] foo [@name] : |
| active_support.rb:309:14:309:23 | call to source : | active_support.rb:309:3:309:5 | [post] foo [@username] : |
| active_support.rb:309:14:309:23 | call to source : | active_support.rb:309:3:309:5 | [post] foo [@username] : |
| active_support.rb:311:8:311:10 | foo [@name] : | active_support.rb:311:8:311:15 | call to name |
| active_support.rb:311:8:311:10 | foo [@name] : | active_support.rb:311:8:311:15 | call to name |
| active_support.rb:311:8:311:10 | foo [@username] : | active_support.rb:311:8:311:15 | call to name |
| active_support.rb:311:8:311:10 | foo [@username] : | active_support.rb:311:8:311:15 | call to name |
| active_support.rb:312:8:312:10 | foo [@name] : | active_support.rb:312:8:312:19 | call to username |
| active_support.rb:312:8:312:10 | foo [@name] : | active_support.rb:312:8:312:19 | call to username |
| active_support.rb:312:8:312:10 | foo [@username] : | active_support.rb:312:8:312:19 | call to username |
| active_support.rb:312:8:312:10 | foo [@username] : | active_support.rb:312:8:312:19 | call to username |
| active_support.rb:314:3:314:5 | [post] foo [@name] : | active_support.rb:316:8:316:10 | foo [@name] : |
| active_support.rb:314:3:314:5 | [post] foo [@name] : | active_support.rb:316:8:316:10 | foo [@name] : |
| active_support.rb:314:3:314:5 | [post] foo [@name] : | active_support.rb:317:8:317:10 | foo [@name] : |
| active_support.rb:314:3:314:5 | [post] foo [@name] : | active_support.rb:317:8:317:10 | foo [@name] : |
| active_support.rb:314:3:314:5 | [post] foo [@username] : | active_support.rb:316:8:316:10 | foo [@username] : |
| active_support.rb:314:3:314:5 | [post] foo [@username] : | active_support.rb:316:8:316:10 | foo [@username] : |
| active_support.rb:314:3:314:5 | [post] foo [@username] : | active_support.rb:317:8:317:10 | foo [@username] : |
| active_support.rb:314:3:314:5 | [post] foo [@username] : | active_support.rb:317:8:317:10 | foo [@username] : |
| active_support.rb:314:18:314:27 | call to source : | active_support.rb:314:3:314:5 | [post] foo [@name] : |
| active_support.rb:314:18:314:27 | call to source : | active_support.rb:314:3:314:5 | [post] foo [@name] : |
| active_support.rb:314:18:314:27 | call to source : | active_support.rb:314:3:314:5 | [post] foo [@username] : |
| active_support.rb:314:18:314:27 | call to source : | active_support.rb:314:3:314:5 | [post] foo [@username] : |
| active_support.rb:316:8:316:10 | foo [@name] : | active_support.rb:316:8:316:15 | call to name |
| active_support.rb:316:8:316:10 | foo [@name] : | active_support.rb:316:8:316:15 | call to name |
| active_support.rb:316:8:316:10 | foo [@username] : | active_support.rb:316:8:316:15 | call to name |
| active_support.rb:316:8:316:10 | foo [@username] : | active_support.rb:316:8:316:15 | call to name |
| active_support.rb:317:8:317:10 | foo [@name] : | active_support.rb:317:8:317:19 | call to username |
| active_support.rb:317:8:317:10 | foo [@name] : | active_support.rb:317:8:317:19 | call to username |
| active_support.rb:317:8:317:10 | foo [@username] : | active_support.rb:317:8:317:19 | call to username |
| active_support.rb:317:8:317:10 | foo [@username] : | active_support.rb:317:8:317:19 | call to username |
| hash_extensions.rb:2:14:2:24 | call to source : | hash_extensions.rb:3:9:3:9 | h [element :a] : |
| hash_extensions.rb:2:14:2:24 | call to source : | hash_extensions.rb:3:9:3:9 | h [element :a] : |
| hash_extensions.rb:3:9:3:9 | h [element :a] : | hash_extensions.rb:3:9:3:24 | call to stringify_keys [element] : |
@@ -504,6 +554,42 @@ nodes
| active_support.rb:291:8:291:8 | x : | semmle.label | x : |
| active_support.rb:291:8:291:17 | call to deep_dup | semmle.label | call to deep_dup |
| active_support.rb:291:8:291:17 | call to deep_dup | semmle.label | call to deep_dup |
| active_support.rb:309:3:309:5 | [post] foo [@name] : | semmle.label | [post] foo [@name] : |
| active_support.rb:309:3:309:5 | [post] foo [@name] : | semmle.label | [post] foo [@name] : |
| active_support.rb:309:3:309:5 | [post] foo [@username] : | semmle.label | [post] foo [@username] : |
| active_support.rb:309:3:309:5 | [post] foo [@username] : | semmle.label | [post] foo [@username] : |
| active_support.rb:309:14:309:23 | call to source : | semmle.label | call to source : |
| active_support.rb:309:14:309:23 | call to source : | semmle.label | call to source : |
| active_support.rb:311:8:311:10 | foo [@name] : | semmle.label | foo [@name] : |
| active_support.rb:311:8:311:10 | foo [@name] : | semmle.label | foo [@name] : |
| active_support.rb:311:8:311:10 | foo [@username] : | semmle.label | foo [@username] : |
| active_support.rb:311:8:311:10 | foo [@username] : | semmle.label | foo [@username] : |
| active_support.rb:311:8:311:15 | call to name | semmle.label | call to name |
| active_support.rb:311:8:311:15 | call to name | semmle.label | call to name |
| active_support.rb:312:8:312:10 | foo [@name] : | semmle.label | foo [@name] : |
| active_support.rb:312:8:312:10 | foo [@name] : | semmle.label | foo [@name] : |
| active_support.rb:312:8:312:10 | foo [@username] : | semmle.label | foo [@username] : |
| active_support.rb:312:8:312:10 | foo [@username] : | semmle.label | foo [@username] : |
| active_support.rb:312:8:312:19 | call to username | semmle.label | call to username |
| active_support.rb:312:8:312:19 | call to username | semmle.label | call to username |
| active_support.rb:314:3:314:5 | [post] foo [@name] : | semmle.label | [post] foo [@name] : |
| active_support.rb:314:3:314:5 | [post] foo [@name] : | semmle.label | [post] foo [@name] : |
| active_support.rb:314:3:314:5 | [post] foo [@username] : | semmle.label | [post] foo [@username] : |
| active_support.rb:314:3:314:5 | [post] foo [@username] : | semmle.label | [post] foo [@username] : |
| active_support.rb:314:18:314:27 | call to source : | semmle.label | call to source : |
| active_support.rb:314:18:314:27 | call to source : | semmle.label | call to source : |
| active_support.rb:316:8:316:10 | foo [@name] : | semmle.label | foo [@name] : |
| active_support.rb:316:8:316:10 | foo [@name] : | semmle.label | foo [@name] : |
| active_support.rb:316:8:316:10 | foo [@username] : | semmle.label | foo [@username] : |
| active_support.rb:316:8:316:10 | foo [@username] : | semmle.label | foo [@username] : |
| active_support.rb:316:8:316:15 | call to name | semmle.label | call to name |
| active_support.rb:316:8:316:15 | call to name | semmle.label | call to name |
| active_support.rb:317:8:317:10 | foo [@name] : | semmle.label | foo [@name] : |
| active_support.rb:317:8:317:10 | foo [@name] : | semmle.label | foo [@name] : |
| active_support.rb:317:8:317:10 | foo [@username] : | semmle.label | foo [@username] : |
| active_support.rb:317:8:317:10 | foo [@username] : | semmle.label | foo [@username] : |
| active_support.rb:317:8:317:19 | call to username | semmle.label | call to username |
| active_support.rb:317:8:317:19 | call to username | semmle.label | call to username |
| hash_extensions.rb:2:14:2:24 | call to source : | semmle.label | call to source : |
| hash_extensions.rb:2:14:2:24 | call to source : | semmle.label | call to source : |
| hash_extensions.rb:3:9:3:9 | h [element :a] : | semmle.label | h [element :a] : |
@@ -613,6 +699,12 @@ subpaths
| active_support.rb:283:8:283:17 | call to presence | active_support.rb:282:7:282:16 | call to source : | active_support.rb:283:8:283:17 | call to presence | $@ | active_support.rb:282:7:282:16 | call to source : | call to source : |
| active_support.rb:286:8:286:17 | call to presence | active_support.rb:285:7:285:16 | call to source : | active_support.rb:286:8:286:17 | call to presence | $@ | active_support.rb:285:7:285:16 | call to source : | call to source : |
| active_support.rb:291:8:291:17 | call to deep_dup | active_support.rb:290:7:290:16 | call to source : | active_support.rb:291:8:291:17 | call to deep_dup | $@ | active_support.rb:290:7:290:16 | call to source : | call to source : |
| active_support.rb:311:8:311:15 | call to name | active_support.rb:309:14:309:23 | call to source : | active_support.rb:311:8:311:15 | call to name | $@ | active_support.rb:309:14:309:23 | call to source : | call to source : |
| active_support.rb:312:8:312:19 | call to username | active_support.rb:309:14:309:23 | call to source : | active_support.rb:312:8:312:19 | call to username | $@ | active_support.rb:309:14:309:23 | call to source : | call to source : |
| active_support.rb:316:8:316:15 | call to name | active_support.rb:309:14:309:23 | call to source : | active_support.rb:316:8:316:15 | call to name | $@ | active_support.rb:309:14:309:23 | call to source : | call to source : |
| active_support.rb:316:8:316:15 | call to name | active_support.rb:314:18:314:27 | call to source : | active_support.rb:316:8:316:15 | call to name | $@ | active_support.rb:314:18:314:27 | call to source : | call to source : |
| active_support.rb:317:8:317:19 | call to username | active_support.rb:309:14:309:23 | call to source : | active_support.rb:317:8:317:19 | call to username | $@ | active_support.rb:309:14:309:23 | call to source : | call to source : |
| active_support.rb:317:8:317:19 | call to username | active_support.rb:314:18:314:27 | call to source : | active_support.rb:317:8:317:19 | call to username | $@ | active_support.rb:314:18:314:27 | call to source : | call to source : |
| hash_extensions.rb:4:10:4:14 | ...[...] | hash_extensions.rb:2:14:2:24 | call to source : | hash_extensions.rb:4:10:4:14 | ...[...] | $@ | hash_extensions.rb:2:14:2:24 | call to source : | call to source : |
| hash_extensions.rb:12:10:12:14 | ...[...] | hash_extensions.rb:10:14:10:24 | call to source : | hash_extensions.rb:12:10:12:14 | ...[...] | $@ | hash_extensions.rb:10:14:10:24 | call to source : | call to source : |
| hash_extensions.rb:20:10:20:14 | ...[...] | hash_extensions.rb:18:14:18:24 | call to source : | hash_extensions.rb:20:10:20:14 | ...[...] | $@ | hash_extensions.rb:18:14:18:24 | call to source : | call to source : |

View File

@@ -298,3 +298,21 @@ def m_try(method)
x.try!(:upcase).try!(:downcase)
x.try!(method)
end
def m_alias_attribute
class ClassWithAlias
alias_attribute :username, :name
end
foo = ClassWithAlias.new
foo.name = source "a"
sink foo.name # $ hasValueFlow=a
sink foo.username # $ hasValueFlow=a
foo.username = source "b"
sink foo.name # $ hasValueFlow=b
sink foo.username # $ hasValueFlow=b
end