mirror of
https://github.com/github/codeql.git
synced 2025-12-21 03:06:31 +01:00
@@ -447,26 +447,6 @@ private predicate skipInitializer(Initializer init) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `e` is an expression in a static initializer that must be evaluated
|
|
||||||
* at run time. This predicate computes "is non-const" instead of "is const" in
|
|
||||||
* order to avoid recursion through forall.
|
|
||||||
*/
|
|
||||||
private predicate runtimeExprInStaticInitializer(Expr e) {
|
|
||||||
inStaticInitializer(e) and
|
|
||||||
if e instanceof AggregateLiteral
|
|
||||||
then runtimeExprInStaticInitializer(e.getAChild())
|
|
||||||
else not e.getFullyConverted().isConstant()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `e` is part of the initializer of a local static variable. */
|
|
||||||
private predicate inStaticInitializer(Expr e) {
|
|
||||||
exists(LocalVariable local |
|
|
||||||
local.isStatic() and
|
|
||||||
e.getParent+() = local.getInitializer()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `i`th child of `n` in control-flow order, where the `i`-indexes are
|
* Gets the `i`th child of `n` in control-flow order, where the `i`-indexes are
|
||||||
* contiguous, and the first index is 0.
|
* contiguous, and the first index is 0.
|
||||||
|
|||||||
@@ -287,20 +287,6 @@ private module SsaDefReaches {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition
|
|
||||||
* `redef` in the same basic block, without crossing another SSA definition of `v`.
|
|
||||||
*/
|
|
||||||
predicate ssaDefReachesUncertainDefWithinBlock(
|
|
||||||
SourceVariable v, Definition def, UncertainWriteDefinition redef
|
|
||||||
) {
|
|
||||||
exists(BasicBlock bb, int rnk, int i |
|
|
||||||
ssaDefReachesRank(bb, def, rnk, v) and
|
|
||||||
rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and
|
|
||||||
redef.definesAt(v, bb, i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
private import ReachableBlock as Reachability
|
private import ReachableBlock as Reachability
|
||||||
|
|
||||||
private module ReachabilityGraph = Reachability::Graph;
|
|
||||||
|
|
||||||
module Graph {
|
module Graph {
|
||||||
import Reachability::Graph
|
import Reachability::Graph
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
private import ReachableBlock as Reachability
|
private import ReachableBlock as Reachability
|
||||||
|
|
||||||
private module ReachabilityGraph = Reachability::Graph;
|
|
||||||
|
|
||||||
module Graph {
|
module Graph {
|
||||||
import Reachability::Graph
|
import Reachability::Graph
|
||||||
|
|
||||||
|
|||||||
@@ -287,20 +287,6 @@ private module SsaDefReaches {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition
|
|
||||||
* `redef` in the same basic block, without crossing another SSA definition of `v`.
|
|
||||||
*/
|
|
||||||
predicate ssaDefReachesUncertainDefWithinBlock(
|
|
||||||
SourceVariable v, Definition def, UncertainWriteDefinition redef
|
|
||||||
) {
|
|
||||||
exists(BasicBlock bb, int rnk, int i |
|
|
||||||
ssaDefReachesRank(bb, def, rnk, v) and
|
|
||||||
rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and
|
|
||||||
redef.definesAt(v, bb, i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -511,13 +511,6 @@ module FinallySplitting {
|
|||||||
predicate isEntryNode() { first(try.getFinally(), this) }
|
predicate isEntryNode() { first(try.getFinally(), this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow element that does not belong to a `finally` block. */
|
|
||||||
private class NonFinallyControlFlowElement extends ControlFlowElement {
|
|
||||||
NonFinallyControlFlowElement() {
|
|
||||||
not this = any(Statements::TryStmtTree t).getAFinallyDescendant()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A split for elements belonging to a `finally` block, which determines how to
|
* A split for elements belonging to a `finally` block, which determines how to
|
||||||
* continue execution after leaving the `finally` block. For example, in
|
* continue execution after leaving the `finally` block. For example, in
|
||||||
|
|||||||
@@ -287,20 +287,6 @@ private module SsaDefReaches {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition
|
|
||||||
* `redef` in the same basic block, without crossing another SSA definition of `v`.
|
|
||||||
*/
|
|
||||||
predicate ssaDefReachesUncertainDefWithinBlock(
|
|
||||||
SourceVariable v, Definition def, UncertainWriteDefinition redef
|
|
||||||
) {
|
|
||||||
exists(BasicBlock bb, int rnk, int i |
|
|
||||||
ssaDefReachesRank(bb, def, rnk, v) and
|
|
||||||
rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and
|
|
||||||
redef.definesAt(v, bb, i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -287,20 +287,6 @@ private module SsaDefReaches {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition
|
|
||||||
* `redef` in the same basic block, without crossing another SSA definition of `v`.
|
|
||||||
*/
|
|
||||||
predicate ssaDefReachesUncertainDefWithinBlock(
|
|
||||||
SourceVariable v, Definition def, UncertainWriteDefinition redef
|
|
||||||
) {
|
|
||||||
exists(BasicBlock bb, int rnk, int i |
|
|
||||||
ssaDefReachesRank(bb, def, rnk, v) and
|
|
||||||
rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and
|
|
||||||
redef.definesAt(v, bb, i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -287,20 +287,6 @@ private module SsaDefReaches {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition
|
|
||||||
* `redef` in the same basic block, without crossing another SSA definition of `v`.
|
|
||||||
*/
|
|
||||||
predicate ssaDefReachesUncertainDefWithinBlock(
|
|
||||||
SourceVariable v, Definition def, UncertainWriteDefinition redef
|
|
||||||
) {
|
|
||||||
exists(BasicBlock bb, int rnk, int i |
|
|
||||||
ssaDefReachesRank(bb, def, rnk, v) and
|
|
||||||
rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and
|
|
||||||
redef.definesAt(v, bb, i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -24,13 +24,6 @@ private class ServiceClass extends Class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Top-level Request DTO types */
|
|
||||||
private class RequestDTO extends Class {
|
|
||||||
RequestDTO() {
|
|
||||||
this.getABaseType*().getABaseInterface().hasQualifiedName("ServiceStack", "IReturn")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Flow sources for the ServiceStack framework */
|
/** Flow sources for the ServiceStack framework */
|
||||||
module Sources {
|
module Sources {
|
||||||
private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||||
|
|||||||
@@ -11,13 +11,6 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
|
|
||||||
class ZeroFloatLiteral extends FloatLiteral {
|
|
||||||
ZeroFloatLiteral() {
|
|
||||||
this.getValue() = "0" or
|
|
||||||
this.getValue() = "0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
from EqualityOperation e
|
from EqualityOperation e
|
||||||
where
|
where
|
||||||
e.getAnOperand().getType() instanceof FloatingPointType and
|
e.getAnOperand().getType() instanceof FloatingPointType and
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
private import ReachableBlock as Reachability
|
private import ReachableBlock as Reachability
|
||||||
|
|
||||||
private module ReachabilityGraph = Reachability::Graph;
|
|
||||||
|
|
||||||
module Graph {
|
module Graph {
|
||||||
import Reachability::Graph
|
import Reachability::Graph
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
private import ReachableBlock as Reachability
|
private import ReachableBlock as Reachability
|
||||||
|
|
||||||
private module ReachabilityGraph = Reachability::Graph;
|
|
||||||
|
|
||||||
module Graph {
|
module Graph {
|
||||||
import Reachability::Graph
|
import Reachability::Graph
|
||||||
|
|
||||||
|
|||||||
@@ -88,15 +88,6 @@ predicate hasAddressType(int byteSize) {
|
|||||||
*/
|
*/
|
||||||
predicate hasFunctionAddressType(int byteSize) { byteSize = getTypeSize(any(NullType type)) }
|
predicate hasFunctionAddressType(int byteSize) { byteSize = getTypeSize(any(NullType type)) }
|
||||||
|
|
||||||
private int getBaseClassSize(ValueOrRefType type) {
|
|
||||||
if exists(type.getBaseClass()) then result = getContentSize(type.getBaseClass()) else result = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getContentSize(ValueOrRefType type) {
|
|
||||||
result =
|
|
||||||
getBaseClassSize(type) + sum(Field field | not field.isStatic() | getTypeSize(field.getType()))
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate isOpaqueType(ValueOrRefType type) {
|
private predicate isOpaqueType(ValueOrRefType type) {
|
||||||
type instanceof Struct or
|
type instanceof Struct or
|
||||||
type instanceof NullableType or
|
type instanceof NullableType or
|
||||||
|
|||||||
@@ -9,26 +9,6 @@ import EJB
|
|||||||
/** A method or constructor that may not be called from an EJB. */
|
/** A method or constructor that may not be called from an EJB. */
|
||||||
abstract class ForbiddenCallable extends Callable { }
|
abstract class ForbiddenCallable extends Callable { }
|
||||||
|
|
||||||
/**
|
|
||||||
* Specialized version of the `polyCalls(..)` predicate for the use
|
|
||||||
* case of finding "shortest" call chains from EJBs to forbidden
|
|
||||||
* methods. This is the same as `polyCalls(..)`, with two exceptions:
|
|
||||||
*
|
|
||||||
* - It does not consider calls into an EJB method.
|
|
||||||
* - It does not consider calls from "forbidden callables".
|
|
||||||
*/
|
|
||||||
private predicate ejbPolyCalls(Callable origin, Callable target) {
|
|
||||||
origin.polyCalls(target) and
|
|
||||||
not exists(EJB ejb | target = ejb.getACallable()) and
|
|
||||||
not origin instanceof ForbiddenCallable
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate ejbPolyCallsPlus(Callable origin, Callable target) {
|
|
||||||
exists(EJB ejb | origin = ejb.getACallable() | ejbPolyCalls(origin, target))
|
|
||||||
or
|
|
||||||
exists(Callable mid | ejbPolyCallsPlus(origin, mid) and ejbPolyCalls(mid, target))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if there exists a call chain from an EJB-`Callable` `origin` to a `ForbiddenCallable` `target`
|
* Holds if there exists a call chain from an EJB-`Callable` `origin` to a `ForbiddenCallable` `target`
|
||||||
* that does not contain any intermediate EJB-`Callable` or `ForbiddenCallable`,
|
* that does not contain any intermediate EJB-`Callable` or `ForbiddenCallable`,
|
||||||
|
|||||||
@@ -16,13 +16,6 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
|
|
||||||
class ReachFromStmt extends Stmt {
|
|
||||||
ReachFromStmt() {
|
|
||||||
exists(Method m | m.getBody() = this) or
|
|
||||||
exists(WhileStmt w | w.getStmt() = this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SleepMethod extends Method {
|
class SleepMethod extends Method {
|
||||||
SleepMethod() {
|
SleepMethod() {
|
||||||
this.getName() = "sleep" and
|
this.getName() = "sleep" and
|
||||||
|
|||||||
@@ -15,11 +15,6 @@ import semmle.code.java.Expr
|
|||||||
import semmle.code.java.Statement
|
import semmle.code.java.Statement
|
||||||
import semmle.code.java.JDK
|
import semmle.code.java.JDK
|
||||||
|
|
||||||
/** A use of `+` that has type `String`. */
|
|
||||||
class StringCat extends AddExpr {
|
|
||||||
StringCat() { this.getType() instanceof TypeString }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An assignment of the form
|
* An assignment of the form
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -36,16 +36,6 @@ class MessageDigest extends RefType {
|
|||||||
MessageDigest() { this.hasQualifiedName("java.security", "MessageDigest") }
|
MessageDigest() { this.hasQualifiedName("java.security", "MessageDigest") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The method call `MessageDigest.getInstance(...)` */
|
|
||||||
class MDConstructor extends StaticMethodAccess {
|
|
||||||
MDConstructor() {
|
|
||||||
exists(Method m | m = this.getMethod() |
|
|
||||||
m.getDeclaringType() instanceof MessageDigest and
|
|
||||||
m.hasName("getInstance")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The method `digest()` declared in `java.security.MessageDigest`. */
|
/** The method `digest()` declared in `java.security.MessageDigest`. */
|
||||||
class MDDigestMethod extends Method {
|
class MDDigestMethod extends Method {
|
||||||
MDDigestMethod() {
|
MDDigestMethod() {
|
||||||
|
|||||||
@@ -9,15 +9,6 @@
|
|||||||
import javascript
|
import javascript
|
||||||
import InsecureDownloadCustomizations::InsecureDownload
|
import InsecureDownloadCustomizations::InsecureDownload
|
||||||
|
|
||||||
// Materialize flow labels
|
|
||||||
private class ConcreteSensitiveInsecureUrl extends Label::SensitiveInsecureUrl {
|
|
||||||
ConcreteSensitiveInsecureUrl() { this = this }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ConcreteInsecureUrl extends Label::InsecureUrl {
|
|
||||||
ConcreteInsecureUrl() { this = this }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A taint tracking configuration for download of sensitive file through insecure connection.
|
* A taint tracking configuration for download of sensitive file through insecure connection.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -969,12 +969,6 @@ private module Scopes {
|
|||||||
scope = n.getEnclosingModule()
|
scope = n.getEnclosingModule()
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate maybe_defined(SsaVariable var) {
|
|
||||||
exists(var.getDefinition()) and not py_ssa_phi(var, _) and not var.getDefinition().isDelete()
|
|
||||||
or
|
|
||||||
exists(SsaVariable input | input = var.getAPhiInput() | maybe_defined(input))
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate maybe_undefined(SsaVariable var) {
|
private predicate maybe_undefined(SsaVariable var) {
|
||||||
not exists(var.getDefinition()) and not py_ssa_phi(var, _)
|
not exists(var.getDefinition()) and not py_ssa_phi(var, _)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -900,22 +900,6 @@ private class EssaTaintTracking extends string {
|
|||||||
or
|
or
|
||||||
result = this.testEvaluates(defn, not_operand(test), use, src).booleanNot()
|
result = this.testEvaluates(defn, not_operand(test), use, src).booleanNot()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `test` is the test in a branch and `use` is that test
|
|
||||||
* with all the `not` prefixes removed.
|
|
||||||
*/
|
|
||||||
private predicate boolean_filter(ControlFlowNode test, ControlFlowNode use) {
|
|
||||||
any(PyEdgeRefinement ref).getTest() = test and
|
|
||||||
(
|
|
||||||
use = test
|
|
||||||
or
|
|
||||||
exists(ControlFlowNode notuse |
|
|
||||||
this.boolean_filter(test, notuse) and
|
|
||||||
use = not_operand(notuse)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate testEvaluatesMaybe(ControlFlowNode test, ControlFlowNode use) {
|
private predicate testEvaluatesMaybe(ControlFlowNode test, ControlFlowNode use) {
|
||||||
|
|||||||
@@ -21,9 +21,6 @@ private module Invoke {
|
|||||||
|
|
||||||
/** Provides models for the `invoke` module. */
|
/** Provides models for the `invoke` module. */
|
||||||
module InvokeModule {
|
module InvokeModule {
|
||||||
/** Gets a reference to the `invoke.context` module. */
|
|
||||||
API::Node context() { result = invoke().getMember("context") }
|
|
||||||
|
|
||||||
/** Provides models for the `invoke.context` module */
|
/** Provides models for the `invoke.context` module */
|
||||||
module Context {
|
module Context {
|
||||||
/** Provides models for the `invoke.context.Context` class */
|
/** Provides models for the `invoke.context.Context` class */
|
||||||
|
|||||||
@@ -295,17 +295,6 @@ private module RestFramework {
|
|||||||
result = API::moduleImport("rest_framework").getMember("response").getMember("Response")
|
result = API::moduleImport("rest_framework").getMember("response").getMember("Response")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A source of instances of `rest_framework.response.Response`, extend this class to model new instances.
|
|
||||||
*
|
|
||||||
* This can include instantiations of the class, return values from function
|
|
||||||
* calls, or a special parameter that will be set when functions are called by an external
|
|
||||||
* library.
|
|
||||||
*
|
|
||||||
* Use the predicate `Response::instance()` to get references to instances of `rest_framework.response.Response`.
|
|
||||||
*/
|
|
||||||
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
|
|
||||||
|
|
||||||
/** A direct instantiation of `rest_framework.response.Response`. */
|
/** A direct instantiation of `rest_framework.response.Response`. */
|
||||||
private class ClassInstantiation extends PrivateDjango::DjangoImpl::Http::Response::HttpResponse::InstanceSource,
|
private class ClassInstantiation extends PrivateDjango::DjangoImpl::Http::Response::HttpResponse::InstanceSource,
|
||||||
DataFlow::CallCfgNode {
|
DataFlow::CallCfgNode {
|
||||||
|
|||||||
@@ -185,11 +185,6 @@ predicate function_can_never_return(FunctionObject func) {
|
|||||||
func = ModuleObject::named("sys").attr("exit")
|
func = ModuleObject::named("sys").attr("exit")
|
||||||
}
|
}
|
||||||
|
|
||||||
private newtype TIterationDefinition =
|
|
||||||
TIterationDefinition_(SsaSourceVariable var, ControlFlowNode def, ControlFlowNode sequence) {
|
|
||||||
SsaSource::iteration_defined_variable(var, def, sequence)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Hold if outer contains inner, both are contained within a test and inner is a use is a plain use or an attribute lookup */
|
/** Hold if outer contains inner, both are contained within a test and inner is a use is a plain use or an attribute lookup */
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
predicate contains_interesting_expression_within_test(ControlFlowNode outer, ControlFlowNode inner) {
|
predicate contains_interesting_expression_within_test(ControlFlowNode outer, ControlFlowNode inner) {
|
||||||
|
|||||||
@@ -40,16 +40,6 @@ private predicate class_statement(Comment c) {
|
|||||||
|
|
||||||
private predicate triple_quote(Comment c) { c.getText().regexpMatch("#.*(\"\"\"|''').*") }
|
private predicate triple_quote(Comment c) { c.getText().regexpMatch("#.*(\"\"\"|''').*") }
|
||||||
|
|
||||||
private predicate triple_quoted_string_part(Comment start, Comment end) {
|
|
||||||
triple_quote(start) and end = start
|
|
||||||
or
|
|
||||||
exists(Comment mid |
|
|
||||||
triple_quoted_string_part(start, mid) and
|
|
||||||
end = non_empty_following(mid) and
|
|
||||||
not triple_quote(end)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate maybe_code(Comment c) {
|
private predicate maybe_code(Comment c) {
|
||||||
not non_code(c) and not filler(c) and not endline_comment(c) and not file_or_url(c)
|
not non_code(c) and not filler(c) and not endline_comment(c) and not file_or_url(c)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import python
|
import python
|
||||||
|
|
||||||
class ImplicitConcat extends StrConst {
|
|
||||||
ImplicitConcat() { exists(this.getAnImplicitlyConcatenatedPart()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
from StringPart s
|
from StringPart s
|
||||||
select s.getLocation().getStartLine(), s.getText(), s.getLocation().getStartColumn(),
|
select s.getLocation().getStartLine(), s.getText(), s.getLocation().getStartColumn(),
|
||||||
s.getLocation().getEndColumn()
|
s.getLocation().getEndColumn()
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import python
|
import python
|
||||||
|
|
||||||
class ImplicitConcat extends StrConst {
|
|
||||||
ImplicitConcat() { exists(this.getAnImplicitlyConcatenatedPart()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
from StrConst s, StringPart part, int n
|
from StrConst s, StringPart part, int n
|
||||||
where part = s.getImplicitlyConcatenatedPart(n)
|
where part = s.getImplicitlyConcatenatedPart(n)
|
||||||
select s.getLocation().getStartLine(), s.getText(), n, part.getText()
|
select s.getLocation().getStartLine(), s.getText(), n, part.getText()
|
||||||
|
|||||||
44
ql/ql/src/codeql_ql/bugs/PathProblemQueryQuery.qll
Normal file
44
ql/ql/src/codeql_ql/bugs/PathProblemQueryQuery.qll
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import ql
|
||||||
|
private import codeql_ql.ast.internal.Module
|
||||||
|
|
||||||
|
FileOrModule hasQueryRelation(ClasslessPredicate pred) {
|
||||||
|
pred.hasAnnotation("query") and
|
||||||
|
(
|
||||||
|
result.asModule().getAMember() = pred
|
||||||
|
or
|
||||||
|
any(TopLevel top | top.getLocation().getFile() = result.asFile()).getAMember() = pred
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOrModule importsQueryRelation(ClasslessPredicate pred) {
|
||||||
|
result = hasQueryRelation(pred)
|
||||||
|
or
|
||||||
|
exists(Import i |
|
||||||
|
not (i.hasAnnotation("private") and i.getLocation().getFile().getExtension() = "qll") and
|
||||||
|
importsQueryRelation(pred) = i.getResolvedModule()
|
||||||
|
|
|
||||||
|
i = result.asModule().getAMember()
|
||||||
|
or
|
||||||
|
i = any(TopLevel top | top.getLocation().getFile() = result.asFile()).getAMember()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Query extends File {
|
||||||
|
Query() { this.getExtension() = "ql" }
|
||||||
|
|
||||||
|
predicate isPathProblem() {
|
||||||
|
exists(QLDoc doc | doc.getLocation().getFile() = this |
|
||||||
|
doc.getContents().matches("%@kind path-problem%")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isProblem() {
|
||||||
|
exists(QLDoc doc | doc.getLocation().getFile() = this |
|
||||||
|
doc.getContents().matches("%@kind problem%")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate hasEdgesRelation(ClasslessPredicate pred) {
|
||||||
|
importsQueryRelation(pred).asFile() = this and pred.getName() = "edges"
|
||||||
|
}
|
||||||
|
}
|
||||||
254
ql/ql/src/codeql_ql/style/DeadCodeQuery.qll
Normal file
254
ql/ql/src/codeql_ql/style/DeadCodeQuery.qll
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
import ql
|
||||||
|
import codeql_ql.bugs.PathProblemQueryQuery as PathProblemQuery
|
||||||
|
import codeql_ql.ast.internal.Module
|
||||||
|
|
||||||
|
/** Gets something that can be imported by a ".qll" file. */
|
||||||
|
private AstNode publicApi() {
|
||||||
|
// base case - the toplevel is always "exported".
|
||||||
|
result instanceof TopLevel
|
||||||
|
or
|
||||||
|
// recursive case. A public class/module/predicate/import that is a child of a public API.
|
||||||
|
not result.hasAnnotation("private") and
|
||||||
|
not result.getLocation().getFile().getExtension() = "ql" and // everything in ".ql" files is kinda private, as you can't import it. Query predicates/from-where-select is handled in `queryable`.
|
||||||
|
result.getParent() = publicApi() and
|
||||||
|
(
|
||||||
|
result instanceof Class
|
||||||
|
or
|
||||||
|
result instanceof ClasslessPredicate
|
||||||
|
or
|
||||||
|
result instanceof Module
|
||||||
|
or
|
||||||
|
result instanceof Import
|
||||||
|
)
|
||||||
|
or
|
||||||
|
result = publicApi().(Import).getResolvedModule().asModule()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets any AstNode that directly computes a result of a query.
|
||||||
|
* I.e. a query predicate or the from-where-select.
|
||||||
|
*/
|
||||||
|
private AstNode queryPredicate() {
|
||||||
|
// result = query relation that is "transitively" imported by a .ql file.
|
||||||
|
PathProblemQuery::importsQueryRelation(result).asFile().getExtension() = "ql"
|
||||||
|
or
|
||||||
|
// the from-where-select
|
||||||
|
result instanceof Select
|
||||||
|
or
|
||||||
|
// child of the above.
|
||||||
|
result = queryPredicate().getAChild()
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode hackyShouldBeTreatedAsAlive() {
|
||||||
|
// Stages from the shared DataFlow impl are copy-pasted, so predicates that are dead in one stage are not dead in another.
|
||||||
|
result = any(Module mod | mod.getName().matches("Stage%")).getAMember().(ClasslessPredicate) and
|
||||||
|
result.getLocation().getFile().getBaseName().matches("DataFlowImpl%")
|
||||||
|
or
|
||||||
|
// Python stuff
|
||||||
|
result.(Predicate).getName() = "quickEvalMe" // private predicate used for quick-eval
|
||||||
|
or
|
||||||
|
result.(Module).getName() = "FutureWork" // holder for later.
|
||||||
|
or
|
||||||
|
result = hackyShouldBeTreatedAsAlive().getAChild()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an AST node that is alive.
|
||||||
|
* That is, an API node that may in some way be part of or affect a query result or a publicly available API.
|
||||||
|
*/
|
||||||
|
private AstNode alive() {
|
||||||
|
//
|
||||||
|
// The 4 base cases.
|
||||||
|
//
|
||||||
|
// 1) everything that can be imported.
|
||||||
|
result = publicApi()
|
||||||
|
or
|
||||||
|
// 2) everything that can be an output when running a query
|
||||||
|
result = queryPredicate()
|
||||||
|
or
|
||||||
|
// 3) A module with an import that imports another file, the import can activate a file.
|
||||||
|
result.(Module).getAMember().(Import).getResolvedModule().getFile() !=
|
||||||
|
result.getLocation().getFile()
|
||||||
|
or
|
||||||
|
// 4) Things that aren't really alive, but that this query treats as live.
|
||||||
|
result = hackyShouldBeTreatedAsAlive()
|
||||||
|
or
|
||||||
|
result instanceof TopLevel // toplevel is always alive.
|
||||||
|
or
|
||||||
|
// recurisve cases
|
||||||
|
result = aliveStep(alive())
|
||||||
|
}
|
||||||
|
|
||||||
|
private AstNode aliveStep(AstNode prev) {
|
||||||
|
//
|
||||||
|
// The recursive cases.
|
||||||
|
//
|
||||||
|
result.getEnclosingPredicate() = prev
|
||||||
|
or
|
||||||
|
result = prev.(Call).getTarget()
|
||||||
|
or
|
||||||
|
prev.(ClassPredicate).overrides(result)
|
||||||
|
or
|
||||||
|
result.(ClassPredicate).overrides(prev)
|
||||||
|
or
|
||||||
|
result = prev.(PredicateExpr).getResolvedPredicate()
|
||||||
|
or
|
||||||
|
// if a sub-class is alive, then the super-class is alive.
|
||||||
|
result = prev.(Class).getASuperType().getResolvedType().(ClassType).getDeclaration()
|
||||||
|
or
|
||||||
|
// if the super class is alive and abstract, then any sub-class is alive.
|
||||||
|
exists(Class sup | sup = prev and sup.isAbstract() |
|
||||||
|
sup = result.(Class).getASuperType().getResolvedType().(ClassType).getDeclaration()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
result = prev.(Class).getAChild() and
|
||||||
|
not result.hasAnnotation("private")
|
||||||
|
or
|
||||||
|
result = prev.getAnAnnotation()
|
||||||
|
or
|
||||||
|
result = prev.getQLDoc()
|
||||||
|
or
|
||||||
|
// any imported module is alive. We don't have to handle the "import a file"-case, those are treated as public APIs.
|
||||||
|
result = prev.(Import).getResolvedModule().asModule()
|
||||||
|
or
|
||||||
|
result = prev.(VarDecl).getType().getDeclaration()
|
||||||
|
or
|
||||||
|
result = prev.(FieldDecl).getVarDecl()
|
||||||
|
or
|
||||||
|
result = prev.(InlineCast).getType().getDeclaration()
|
||||||
|
or
|
||||||
|
// a class overrides some predicate, is the super-predicate is alive.
|
||||||
|
exists(ClassPredicate pred, ClassPredicate sup |
|
||||||
|
pred.hasAnnotation("override") and
|
||||||
|
pred.overrides(sup) and
|
||||||
|
result = pred.getParent() and
|
||||||
|
sup.getParent() = prev
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// if a class is alive, so is it's super-class
|
||||||
|
result =
|
||||||
|
[prev.(Class).getASuperType(), prev.(Class).getAnInstanceofType()]
|
||||||
|
.getResolvedType()
|
||||||
|
.getDeclaration()
|
||||||
|
or
|
||||||
|
// if a class is alive and abstract, then any sub-class is alive.
|
||||||
|
exists(Class clz, Class sup | result = clz |
|
||||||
|
clz.getASuperType().getResolvedType().getDeclaration() = sup and
|
||||||
|
sup.isAbstract() and
|
||||||
|
sup = prev
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// a module containing something live, is also alive.
|
||||||
|
result.(Module).getAMember() = prev
|
||||||
|
or
|
||||||
|
result = prev.(Module).getAlias()
|
||||||
|
or
|
||||||
|
result.(NewType).getABranch() = prev
|
||||||
|
or
|
||||||
|
result = prev.(TypeExpr).getAChild()
|
||||||
|
or
|
||||||
|
result = prev.(FieldAccess).getDeclaration()
|
||||||
|
or
|
||||||
|
result = prev.(VarDecl).getTypeExpr()
|
||||||
|
or
|
||||||
|
result.(Import).getParent() = prev
|
||||||
|
or
|
||||||
|
result = prev.(NewType).getABranch()
|
||||||
|
or
|
||||||
|
result = prev.(ModuleExpr).getAChild()
|
||||||
|
or
|
||||||
|
result = prev.(ModuleExpr).getResolvedModule().asModule()
|
||||||
|
or
|
||||||
|
result = prev.(InstanceOf).getType().getResolvedType().getDeclaration()
|
||||||
|
or
|
||||||
|
result = prev.(Annotation).getAChild()
|
||||||
|
or
|
||||||
|
result = prev.(Predicate).getReturnType().getDeclaration()
|
||||||
|
}
|
||||||
|
|
||||||
|
private AstNode deprecated() {
|
||||||
|
result.hasAnnotation("deprecated")
|
||||||
|
or
|
||||||
|
result = deprecated().getQLDoc()
|
||||||
|
or
|
||||||
|
result = deprecated().getAnAnnotation()
|
||||||
|
or
|
||||||
|
result = deprecated().getAChild()
|
||||||
|
}
|
||||||
|
|
||||||
|
// our type-resolution skips these, so ignore.
|
||||||
|
private AstNode classUnion() {
|
||||||
|
exists(result.(Class).getUnionMember())
|
||||||
|
or
|
||||||
|
exists(result.(Class).getAliasType())
|
||||||
|
or
|
||||||
|
result = classUnion().(Class).getUnionMember()
|
||||||
|
or
|
||||||
|
result = classUnion().(Class).getAliasType()
|
||||||
|
or
|
||||||
|
result = classUnion().getAnAnnotation()
|
||||||
|
or
|
||||||
|
result = classUnion().getQLDoc()
|
||||||
|
or
|
||||||
|
result = classUnion().(TypeExpr).getAChild()
|
||||||
|
or
|
||||||
|
result = classUnion().(ModuleExpr).getAChild()
|
||||||
|
}
|
||||||
|
|
||||||
|
private AstNode benign() {
|
||||||
|
not result.getLocation().getFile().getExtension() = ["ql", "qll"] or // ignore dbscheme files
|
||||||
|
result instanceof BlockComment or
|
||||||
|
not exists(result.toString()) or // <- invalid code
|
||||||
|
// cached-stages pattern
|
||||||
|
result.(Module).getAMember().(ClasslessPredicate).getName() = "forceStage" or
|
||||||
|
result.(ClasslessPredicate).getName() = "forceStage" or
|
||||||
|
result.getLocation().getFile().getBaseName() = "Caching.qll" or
|
||||||
|
// sometimes contains dead code - ignore
|
||||||
|
result.getLocation().getFile().getRelativePath().matches("%/tutorials/%") or
|
||||||
|
result = classUnion()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isDeadInternal(AstNode node) {
|
||||||
|
not node = alive() and
|
||||||
|
not node = deprecated()
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isDead(AstNode node) {
|
||||||
|
isDeadInternal(node) and
|
||||||
|
not isDeadInternal(node.getParent()) and
|
||||||
|
not node = benign()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an AST node that affects a query.
|
||||||
|
*/
|
||||||
|
private AstNode queryable() {
|
||||||
|
//
|
||||||
|
// The base cases.
|
||||||
|
//
|
||||||
|
// everything that can be an output when running a query
|
||||||
|
result = queryPredicate()
|
||||||
|
or
|
||||||
|
// A module with an import that imports another file, the import can activate a file.
|
||||||
|
result.(Module).getAMember().(Import).getResolvedModule().getFile() !=
|
||||||
|
result.getLocation().getFile()
|
||||||
|
or
|
||||||
|
result instanceof TopLevel // toplevel is always alive.
|
||||||
|
or
|
||||||
|
// recurisve cases
|
||||||
|
result = aliveStep(queryable())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an AstNode that does not affect any query result.
|
||||||
|
* Is interresting as an quick-eval target to investigate dead code.
|
||||||
|
* (It is intentional that this predicate is a result of this predicate).
|
||||||
|
*/
|
||||||
|
AstNode unQueryable(string msg) {
|
||||||
|
not result = queryable() and
|
||||||
|
not result = deprecated() and
|
||||||
|
not result = benign() and
|
||||||
|
not result.getParent() = any(AstNode node | not node = queryable()) and
|
||||||
|
msg = result.getLocation().getFile().getBaseName() and
|
||||||
|
result.getLocation().getFile().getAbsolutePath().matches("%/javascript/%")
|
||||||
|
}
|
||||||
@@ -10,48 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import ql
|
import ql
|
||||||
import codeql_ql.ast.internal.Module
|
import codeql_ql.bugs.PathProblemQueryQuery
|
||||||
|
|
||||||
FileOrModule hasEdgesRelation(ClasslessPredicate pred) {
|
|
||||||
pred.getName() = "edges" and
|
|
||||||
pred.hasAnnotation("query") and
|
|
||||||
(
|
|
||||||
result.asModule().getAMember() = pred
|
|
||||||
or
|
|
||||||
any(TopLevel top | top.getLocation().getFile() = result.asFile()).getAMember() = pred
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
FileOrModule importsEdges(ClasslessPredicate pred) {
|
|
||||||
result = hasEdgesRelation(pred)
|
|
||||||
or
|
|
||||||
exists(Import i |
|
|
||||||
not (i.hasAnnotation("private") and i.getLocation().getFile().getExtension() = "qll") and
|
|
||||||
importsEdges(pred) = i.getResolvedModule()
|
|
||||||
|
|
|
||||||
i = result.asModule().getAMember()
|
|
||||||
or
|
|
||||||
i = any(TopLevel top | top.getLocation().getFile() = result.asFile()).getAMember()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Query extends File {
|
|
||||||
Query() { this.getExtension() = "ql" }
|
|
||||||
|
|
||||||
predicate isPathProblem() {
|
|
||||||
exists(QLDoc doc | doc.getLocation().getFile() = this |
|
|
||||||
doc.getContents().matches("%@kind path-problem%")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isProblem() {
|
|
||||||
exists(QLDoc doc | doc.getLocation().getFile() = this |
|
|
||||||
doc.getContents().matches("%@kind problem%")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate hasEdgesRelation(ClasslessPredicate pred) { importsEdges(pred).asFile() = this }
|
|
||||||
}
|
|
||||||
|
|
||||||
from Query query, string msg, AstNode pred
|
from Query query, string msg, AstNode pred
|
||||||
where
|
where
|
||||||
|
|||||||
15
ql/ql/src/queries/style/DeadCode.ql
Normal file
15
ql/ql/src/queries/style/DeadCode.ql
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* @name Dead code
|
||||||
|
* @description Code that cannot be reached should be deleted.
|
||||||
|
* @kind problem
|
||||||
|
* @problem.severity warning
|
||||||
|
* @id ql/dead-code
|
||||||
|
* @precision very-high
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ql
|
||||||
|
import codeql_ql.style.DeadCodeQuery
|
||||||
|
|
||||||
|
from AstNode node
|
||||||
|
where isDead(node)
|
||||||
|
select node, "Code is dead"
|
||||||
@@ -143,10 +143,6 @@ module DataFlow {
|
|||||||
override string toString() { result = p.toString() }
|
override string toString() { result = p.toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
newtype TReturnKind =
|
|
||||||
TNormalReturnKind() or
|
|
||||||
TParameterOutKind(int i) { any(Parameter p).getIndex() = i }
|
|
||||||
|
|
||||||
/** A data flow node that represents the output of a call at the call site. */
|
/** A data flow node that represents the output of a call at the call site. */
|
||||||
abstract class OutNode extends Node {
|
abstract class OutNode extends Node {
|
||||||
/** Gets the underlying call. */
|
/** Gets the underlying call. */
|
||||||
|
|||||||
2
ql/ql/test/queries/style/DeadCode/DeadCode.expected
Normal file
2
ql/ql/test/queries/style/DeadCode/DeadCode.expected
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
| Foo.qll:2:11:2:38 | ClasslessPredicate dead1 | Code is dead |
|
||||||
|
| Foo.qll:6:3:6:30 | ClasslessPredicate dead2 | Code is dead |
|
||||||
1
ql/ql/test/queries/style/DeadCode/DeadCode.qlref
Normal file
1
ql/ql/test/queries/style/DeadCode/DeadCode.qlref
Normal file
@@ -0,0 +1 @@
|
|||||||
|
queries/style/DeadCode.ql
|
||||||
9
ql/ql/test/queries/style/DeadCode/Foo.qll
Normal file
9
ql/ql/test/queries/style/DeadCode/Foo.qll
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
private module Mixed {
|
||||||
|
private predicate dead1() { none() }
|
||||||
|
|
||||||
|
predicate alive1() { none() }
|
||||||
|
|
||||||
|
predicate dead2() { none() }
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate usesAlive() { Mixed::alive1() }
|
||||||
@@ -287,20 +287,6 @@ private module SsaDefReaches {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition
|
|
||||||
* `redef` in the same basic block, without crossing another SSA definition of `v`.
|
|
||||||
*/
|
|
||||||
predicate ssaDefReachesUncertainDefWithinBlock(
|
|
||||||
SourceVariable v, Definition def, UncertainWriteDefinition redef
|
|
||||||
) {
|
|
||||||
exists(BasicBlock bb, int rnk, int i |
|
|
||||||
ssaDefReachesRank(bb, def, rnk, v) and
|
|
||||||
rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and
|
|
||||||
redef.definesAt(v, bb, i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -189,12 +189,6 @@ module IO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Direct" `IO` instances, i.e. cases where there is no more specific
|
|
||||||
// subtype such as `File`
|
|
||||||
private class IOInstanceStrict extends IOInstance {
|
|
||||||
IOInstanceStrict() { this = ioInstance() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `DataFlow::CallNode` that reads data using the `IO` class. For example,
|
* A `DataFlow::CallNode` that reads data using the `IO` class. For example,
|
||||||
* the `read` and `readline` calls in:
|
* the `read` and `readline` calls in:
|
||||||
|
|||||||
Reference in New Issue
Block a user