зеркало из https://github.com/github/codeql.git
Merge branch 'master' into overflowcalc
This commit is contained in:
Коммит
939979ddef
|
@ -1,11 +0,0 @@
|
|||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v2
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
|
@ -27,4 +27,3 @@
|
|||
## Changes to libraries
|
||||
|
||||
* The predicates `RegExpTerm.getSuccessor` and `RegExpTerm.getPredecessor` have been changed to reflect textual, not operational, matching order. This only makes a difference in lookbehind assertions, which are operationally matched backwards. Previously, `getSuccessor` would mimick this, so in an assertion `(?<=ab)` the term `b` would be considered the predecessor, not the successor, of `a`. Textually, however, `a` is still matched before `b`, and this is the order we now follow.
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[[ condition: enterprise-only ]]
|
||||
|
||||
# Improvements to JavaScript analysis
|
||||
|
||||
## Changes to code extraction
|
||||
|
||||
* `import.meta` expressions no longer result in a syntax error in JavaScript files.
|
|
@ -265,5 +265,11 @@
|
|||
"C# IR ValueNumberingImports": [
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll"
|
||||
],
|
||||
"XML": [
|
||||
"cpp/ql/src/semmle/code/cpp/XML.qll",
|
||||
"java/ql/src/semmle/code/xml/XML.qll",
|
||||
"javascript/ql/src/semmle/javascript/XML.qll",
|
||||
"python/ql/src/semmle/python/xml/XML.qll"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -10,12 +10,25 @@ import cpp
|
|||
/**
|
||||
* An alert suppression comment.
|
||||
*/
|
||||
class SuppressionComment extends CppStyleComment {
|
||||
class SuppressionComment extends Comment {
|
||||
string annotation;
|
||||
string text;
|
||||
|
||||
SuppressionComment() {
|
||||
text = getContents().suffix(2) and
|
||||
(
|
||||
this instanceof CppStyleComment and
|
||||
// strip the beginning slashes
|
||||
text = getContents().suffix(2)
|
||||
or
|
||||
this instanceof CStyleComment and
|
||||
// strip both the beginning /* and the end */ the comment
|
||||
exists(string text0 |
|
||||
text0 = getContents().suffix(2) and
|
||||
text = text0.prefix(text0.length() - 2)
|
||||
) and
|
||||
// The /* */ comment must be a single-line comment
|
||||
not text.matches("%\n%")
|
||||
) and
|
||||
(
|
||||
// match `lgtm[...]` anywhere in the comment
|
||||
annotation = text.regexpFind("(?i)\\blgtm\\s*\\[[^\\]]*\\]", _, _)
|
||||
|
|
|
@ -157,4 +157,6 @@ library class SpecialNameQualifyingElement extends NameQualifyingElement,
|
|||
@specialnamequalifyingelement {
|
||||
/** Gets the name of this special qualifying element. */
|
||||
override string getName() { specialnamequalifyingelements(underlyingElement(this), result) }
|
||||
|
||||
override string toString() { result = getName() }
|
||||
}
|
||||
|
|
|
@ -214,7 +214,9 @@ class PreprocessorUndef extends PreprocessorDirective, @ppd_undef {
|
|||
* A C/C++ preprocessor `#pragma` directive.
|
||||
*/
|
||||
class PreprocessorPragma extends PreprocessorDirective, @ppd_pragma {
|
||||
override string toString() { result = "#pragma " + this.getHead() }
|
||||
override string toString() {
|
||||
if exists(this.getHead()) then result = "#pragma " + this.getHead() else result = "#pragma"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Provides classes and predicates for working with XML files and their content.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Location
|
||||
import semmle.files.FileSystem
|
||||
|
||||
/** An XML element that has a location. */
|
||||
abstract class XMLLocatable extends @xmllocatable {
|
||||
|
@ -10,19 +10,22 @@ abstract class XMLLocatable extends @xmllocatable {
|
|||
Location getLocation() { xmllocations(this, result) }
|
||||
|
||||
/**
|
||||
* Holds if this element has the specified location information,
|
||||
* including file path, start line, start column, end line and end column.
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
exists(File f, Location l | l = this.getLocation() |
|
||||
locations_default(l, unresolveElement(f), startline, startcolumn, endline, endcolumn) and
|
||||
locations_default(l, f, startline, startcolumn, endline, endcolumn) and
|
||||
filepath = f.getAbsolutePath()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a printable representation of this element. */
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
|
@ -31,6 +34,12 @@ abstract class XMLLocatable extends @xmllocatable {
|
|||
* both of which can contain other elements.
|
||||
*/
|
||||
class XMLParent extends @xmlparent {
|
||||
XMLParent() {
|
||||
// explicitly restrict `this` to be either an `XMLElement` or an `XMLFile`;
|
||||
// the type `@xmlparent` currently also includes non-XML files
|
||||
this instanceof @xmlelement or xmlEncoding(this, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a printable representation of this XML parent.
|
||||
* (Intended to be overridden in subclasses.)
|
||||
|
@ -106,15 +115,21 @@ class XMLFile extends XMLParent, File {
|
|||
override string toString() { result = XMLParent.super.toString() }
|
||||
|
||||
/** Gets the name of this XML file. */
|
||||
override string getName() { files(this, result, _, _, _) }
|
||||
override string getName() { result = File.super.getAbsolutePath() }
|
||||
|
||||
/** Gets the path of this XML file. */
|
||||
string getPath() { files(this, _, result, _, _) }
|
||||
/**
|
||||
* DEPRECATED: Use `getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of this XML file.
|
||||
*/
|
||||
deprecated string getPath() { result = getAbsolutePath() }
|
||||
|
||||
/** Gets the path of the folder that contains this XML file. */
|
||||
string getFolder() {
|
||||
result = this.getPath().substring(0, this.getPath().length() - this.getName().length())
|
||||
}
|
||||
/**
|
||||
* DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of the folder that contains this XML file.
|
||||
*/
|
||||
deprecated string getFolder() { result = getParentContainer().getAbsolutePath() }
|
||||
|
||||
/** Gets the encoding of this XML file. */
|
||||
string getEncoding() { xmlEncoding(this, result) }
|
||||
|
@ -129,7 +144,17 @@ class XMLFile extends XMLParent, File {
|
|||
XMLDTD getADTD() { xmlDTDs(result, _, _, _, this) }
|
||||
}
|
||||
|
||||
/** A "Document Type Definition" of an XML file. */
|
||||
/**
|
||||
* An XML document type definition (DTD).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <!ELEMENT person (firstName, lastName?)>
|
||||
* <!ELEMENT firstName (#PCDATA)>
|
||||
* <!ELEMENT lastName (#PCDATA)>
|
||||
* ```
|
||||
*/
|
||||
class XMLDTD extends @xmldtd {
|
||||
/** Gets the name of the root element of this DTD. */
|
||||
string getRoot() { xmlDTDs(this, result, _, _, _) }
|
||||
|
@ -156,7 +181,17 @@ class XMLDTD extends @xmldtd {
|
|||
}
|
||||
}
|
||||
|
||||
/** An XML tag in an XML file. */
|
||||
/**
|
||||
* An XML element in an XML file.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
* package="com.example.exampleapp" android:versionCode="1">
|
||||
* </manifest>
|
||||
* ```
|
||||
*/
|
||||
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
/** Holds if this XML element has the given `name`. */
|
||||
predicate hasName(string name) { name = getName() }
|
||||
|
@ -201,7 +236,16 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
|||
override string toString() { result = XMLParent.super.toString() }
|
||||
}
|
||||
|
||||
/** An attribute that occurs inside an XML element. */
|
||||
/**
|
||||
* An attribute that occurs inside an XML element.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ```
|
||||
* package="com.example.exampleapp"
|
||||
* android:versionCode="1"
|
||||
* ```
|
||||
*/
|
||||
class XMLAttribute extends @xmlattribute, XMLLocatable {
|
||||
/** Gets the name of this attribute. */
|
||||
string getName() { xmlAttrs(this, _, result, _, _, _) }
|
||||
|
@ -222,7 +266,15 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
|
|||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/** A namespace used in an XML file */
|
||||
/**
|
||||
* A namespace used in an XML file.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
* ```
|
||||
*/
|
||||
class XMLNamespace extends @xmlnamespace {
|
||||
/** Gets the prefix of this namespace. */
|
||||
string getPrefix() { xmlNs(this, result, _, _) }
|
||||
|
@ -241,7 +293,15 @@ class XMLNamespace extends @xmlnamespace {
|
|||
}
|
||||
}
|
||||
|
||||
/** A comment of the form `<!-- ... -->` is an XML comment. */
|
||||
/**
|
||||
* A comment in an XML file.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <!-- This is a comment. -->
|
||||
* ```
|
||||
*/
|
||||
class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
/** Gets the text content of this XML comment. */
|
||||
string getText() { xmlComments(this, result, _, _) }
|
||||
|
@ -256,6 +316,12 @@ class XMLComment extends @xmlcomment, XMLLocatable {
|
|||
/**
|
||||
* A sequence of characters that occurs between opening and
|
||||
* closing tags of an XML element, excluding other elements.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <content>This is a sequence of characters.</content>
|
||||
* ```
|
||||
*/
|
||||
class XMLCharacters extends @xmlcharacters, XMLLocatable {
|
||||
/** Gets the content of this character sequence. */
|
||||
|
|
|
@ -19,10 +19,32 @@ private predicate predictableInstruction(Instruction instr) {
|
|||
predictableInstruction(instr.(UnaryInstruction).getUnary())
|
||||
}
|
||||
|
||||
private predicate userInputInstruction(Instruction instr) {
|
||||
exists(CallInstruction ci, WriteSideEffectInstruction wsei |
|
||||
userInputArgument(ci.getConvertedResultExpression(), wsei.getIndex()) and
|
||||
instr = wsei and
|
||||
wsei.getPrimaryInstruction() = ci
|
||||
)
|
||||
or
|
||||
userInputReturned(instr.getConvertedResultExpression())
|
||||
or
|
||||
instr.getConvertedResultExpression() instanceof EnvironmentRead
|
||||
or
|
||||
instr
|
||||
.(LoadInstruction)
|
||||
.getSourceAddress()
|
||||
.(VariableAddressInstruction)
|
||||
.getASTVariable()
|
||||
.hasName("argv") and
|
||||
instr.getEnclosingFunction().hasGlobalName("main")
|
||||
}
|
||||
|
||||
private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
|
||||
DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { isUserInput(source.asExpr(), _) }
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
userInputInstruction(source.asInstruction())
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { any() }
|
||||
|
||||
|
@ -135,6 +157,8 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
|
|||
// This is part of the translation of `a[i]`, where we want taint to flow
|
||||
// from `a`.
|
||||
i2.(PointerAddInstruction).getLeft() = i1
|
||||
// TODO: robust Chi handling
|
||||
//
|
||||
// TODO: Flow from argument to return of known functions: Port missing parts
|
||||
// of `returnArgument` to the `interfaces.Taint` and `interfaces.DataFlow`
|
||||
// libraries.
|
||||
|
@ -176,11 +200,30 @@ private Element adjustedSink(DataFlow::Node sink) {
|
|||
// For compatibility, send flow into a `NotExpr` even if it's part of a
|
||||
// short-circuiting condition and thus might get skipped.
|
||||
result.(NotExpr).getOperand() = sink.asExpr()
|
||||
or
|
||||
// For compatibility, send flow from argument read side effects to their
|
||||
// corresponding argument expression
|
||||
exists(IndirectReadSideEffectInstruction read |
|
||||
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
|
||||
read.getArgumentDef().getUnconvertedResultExpression() = result
|
||||
)
|
||||
or
|
||||
exists(BufferReadSideEffectInstruction read |
|
||||
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
|
||||
read.getArgumentDef().getUnconvertedResultExpression() = result
|
||||
)
|
||||
or
|
||||
exists(SizedBufferReadSideEffectInstruction read |
|
||||
read.getAnOperand().(SideEffectOperand).getAnyDef() = sink.asInstruction() and
|
||||
read.getArgumentDef().getUnconvertedResultExpression() = result
|
||||
)
|
||||
}
|
||||
|
||||
predicate tainted(Expr source, Element tainted) {
|
||||
exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink |
|
||||
cfg.hasFlow(DataFlow::exprNode(source), sink)
|
||||
or
|
||||
cfg.hasFlow(DataFlow::definitionByReferenceNode(source), sink)
|
||||
|
|
||||
tainted = adjustedSink(sink)
|
||||
)
|
||||
|
|
|
@ -173,11 +173,48 @@ abstract class PostUpdateNode extends Node {
|
|||
abstract Node getPreUpdateNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that represents the value of a variable after a function call that
|
||||
* may have changed the variable because it's passed by reference.
|
||||
*
|
||||
* A typical example would be a call `f(&x)`. Firstly, there will be flow into
|
||||
* `x` from previous definitions of `x`. Secondly, there will be a
|
||||
* `DefinitionByReferenceNode` to represent the value of `x` after the call has
|
||||
* returned. This node will have its `getArgument()` equal to `&x` and its
|
||||
* `getVariableAccess()` equal to `x`.
|
||||
*/
|
||||
class DefinitionByReferenceNode extends Node {
|
||||
override WriteSideEffectInstruction instr;
|
||||
|
||||
/** Gets the argument corresponding to this node. */
|
||||
Expr getArgument() {
|
||||
result = instr
|
||||
.getPrimaryInstruction()
|
||||
.(CallInstruction)
|
||||
.getPositionalArgument(instr.getIndex())
|
||||
.getUnconvertedResultExpression()
|
||||
or
|
||||
result = instr
|
||||
.getPrimaryInstruction()
|
||||
.(CallInstruction)
|
||||
.getThisArgument()
|
||||
.getUnconvertedResultExpression() and
|
||||
instr.getIndex() = -1
|
||||
}
|
||||
|
||||
/** Gets the parameter through which this value is assigned. */
|
||||
Parameter getParameter() {
|
||||
exists(CallInstruction ci | result = ci.getStaticCallTarget().getParameter(instr.getIndex()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the node corresponding to `instr`.
|
||||
*/
|
||||
Node instructionNode(Instruction instr) { result.asInstruction() = instr }
|
||||
|
||||
DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e }
|
||||
|
||||
/**
|
||||
* Gets a `Node` corresponding to `e` or any of its conversions. There is no
|
||||
* result if `e` is a `Conversion`.
|
||||
|
|
|
@ -1236,6 +1236,8 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
|||
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1245,6 +1247,8 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1258,12 +1262,14 @@ class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
*/
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction {
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
|
|
@ -1236,6 +1236,8 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
|||
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1245,6 +1247,8 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1258,12 +1262,14 @@ class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
*/
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction {
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
|
|
@ -143,26 +143,23 @@ private module Cached {
|
|||
.getInstructionSuccessor(getInstructionTag(instruction), kind)
|
||||
}
|
||||
|
||||
// This predicate has pragma[noopt] because otherwise the `getAChild*` calls
|
||||
// get joined too early. The join order for the loop cases goes like this:
|
||||
// - Find all loops of that type (tens of thousands).
|
||||
// - Find all edges into the start of the loop (x 2).
|
||||
// - Restrict to edges that originate within the loop (/ 2).
|
||||
pragma[noopt]
|
||||
cached
|
||||
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
/**
|
||||
* Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`-->
|
||||
* `targetInstruction` is a back edge under the condition that
|
||||
* `requiredAncestor` is an ancestor of `sourceElement`.
|
||||
*/
|
||||
private predicate backEdgeCandidate(
|
||||
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor,
|
||||
Instruction targetInstruction, EdgeKind kind
|
||||
) {
|
||||
// While loop:
|
||||
// Any edge from within the body of the loop to the condition of the loop
|
||||
// is a back edge. This includes edges from `continue` and the fall-through
|
||||
// edge(s) after the last instruction(s) in the body.
|
||||
exists(TranslatedWhileStmt s |
|
||||
s instanceof TranslatedWhileStmt and
|
||||
result = s.getFirstConditionInstruction() and
|
||||
exists(TranslatedElement inBody, InstructionTag tag |
|
||||
result = inBody.getInstructionSuccessor(tag, kind) and
|
||||
exists(TranslatedElement body | body = s.getBody() | inBody = body.getAChild*()) and
|
||||
instruction = inBody.getInstruction(tag)
|
||||
)
|
||||
targetInstruction = s.getFirstConditionInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
requiredAncestor = s.getBody()
|
||||
)
|
||||
or
|
||||
// Do-while loop:
|
||||
|
@ -171,15 +168,9 @@ private module Cached {
|
|||
// { ... } while (0)` statement. Note that all `continue` statements in a
|
||||
// do-while loop produce forward edges.
|
||||
exists(TranslatedDoStmt s |
|
||||
s instanceof TranslatedDoStmt and
|
||||
exists(TranslatedStmt body | body = s.getBody() | result = body.getFirstInstruction()) and
|
||||
exists(TranslatedElement inCondition, InstructionTag tag |
|
||||
result = inCondition.getInstructionSuccessor(tag, kind) and
|
||||
exists(TranslatedElement condition | condition = s.getCondition() |
|
||||
inCondition = condition.getAChild*()
|
||||
) and
|
||||
instruction = inCondition.getInstruction(tag)
|
||||
)
|
||||
targetInstruction = s.getBody().getFirstInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
requiredAncestor = s.getCondition()
|
||||
)
|
||||
or
|
||||
// For loop:
|
||||
|
@ -189,33 +180,42 @@ private module Cached {
|
|||
// last instruction(s) in the body. A for loop may not have a condition, in
|
||||
// which case `getFirstConditionInstruction` returns the body instead.
|
||||
exists(TranslatedForStmt s |
|
||||
s instanceof TranslatedForStmt and
|
||||
result = s.getFirstConditionInstruction() and
|
||||
exists(TranslatedElement inLoop, InstructionTag tag |
|
||||
result = inLoop.getInstructionSuccessor(tag, kind) and
|
||||
exists(TranslatedElement bodyOrUpdate |
|
||||
bodyOrUpdate = s.getBody()
|
||||
or
|
||||
bodyOrUpdate = s.getUpdate()
|
||||
|
|
||||
inLoop = bodyOrUpdate.getAChild*()
|
||||
) and
|
||||
instruction = inLoop.getInstruction(tag)
|
||||
targetInstruction = s.getFirstConditionInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
(
|
||||
requiredAncestor = s.getUpdate()
|
||||
or
|
||||
not exists(s.getUpdate()) and
|
||||
requiredAncestor = s.getBody()
|
||||
)
|
||||
)
|
||||
or
|
||||
// Range-based for loop:
|
||||
// Any edge from within the update of the loop to the condition of
|
||||
// the loop is a back edge.
|
||||
exists(TranslatedRangeBasedForStmt s, TranslatedCondition condition |
|
||||
s instanceof TranslatedRangeBasedForStmt and
|
||||
condition = s.getCondition() and
|
||||
result = condition.getFirstInstruction() and
|
||||
exists(TranslatedElement inUpdate, InstructionTag tag |
|
||||
result = inUpdate.getInstructionSuccessor(tag, kind) and
|
||||
exists(TranslatedElement update | update = s.getUpdate() | inUpdate = update.getAChild*()) and
|
||||
instruction = inUpdate.getInstruction(tag)
|
||||
)
|
||||
exists(TranslatedRangeBasedForStmt s |
|
||||
targetInstruction = s.getCondition().getFirstInstruction() and
|
||||
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
|
||||
requiredAncestor = s.getUpdate()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) {
|
||||
backEdgeCandidate(jumpSource, _, _, _, _) and
|
||||
ancestor = jumpSource
|
||||
or
|
||||
// For performance, we don't want a fastTC here
|
||||
jumpSourceHasAncestor(jumpSource, ancestor.getAChild())
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
exists(
|
||||
TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor
|
||||
|
|
||||
backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and
|
||||
jumpSourceHasAncestor(sourceElement, requiredAncestor) and
|
||||
instruction = sourceElement.getInstruction(sourceTag)
|
||||
)
|
||||
or
|
||||
// Goto statement:
|
||||
|
@ -225,7 +225,6 @@ private module Cached {
|
|||
// same location for source and target, so we conservatively assume that
|
||||
// such a `goto` creates a back edge.
|
||||
exists(TranslatedElement s, GotoStmt goto |
|
||||
goto instanceof GotoStmt and
|
||||
not isStrictlyForwardGoto(goto) and
|
||||
goto = s.getAST() and
|
||||
exists(InstructionTag tag |
|
||||
|
|
|
@ -1236,6 +1236,8 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
|||
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1245,6 +1247,8 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1258,12 +1262,14 @@ class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
*/
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction {
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
private import implementations.Allocation
|
||||
private import implementations.Deallocation
|
||||
private import implementations.Fread
|
||||
private import implementations.IdentityFunction
|
||||
private import implementations.Inet
|
||||
private import implementations.Memcpy
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
class Fread extends AliasFunction {
|
||||
Fread() { this.hasGlobalName("fread") }
|
||||
|
||||
override predicate parameterNeverEscapes(int n) {
|
||||
n = 0 or
|
||||
n = 3
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int n) { none() }
|
||||
|
||||
override predicate parameterIsAlwaysReturned(int n) { none() }
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
import semmle.code.cpp.models.interfaces.FormattingFunction
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* The standard functions `printf`, `wprintf` and their glib variants.
|
||||
*/
|
||||
class Printf extends FormattingFunction {
|
||||
class Printf extends FormattingFunction, AliasFunction {
|
||||
Printf() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
|
@ -22,6 +23,12 @@ class Printf extends FormattingFunction {
|
|||
hasGlobalOrStdName("wprintf") or
|
||||
hasGlobalName("wprintf_s")
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int n) { n = 0 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int n) { none() }
|
||||
|
||||
override predicate parameterIsAlwaysReturned(int n) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
| CPP-205.cpp:8:3:8:15 | return ... | |
|
||||
| CPP-205.cpp:8:10:8:11 | call to fn | |
|
||||
| CPP-205.cpp:8:13:8:13 | 0 | |
|
||||
| file://:0:0:0:0 | __super | |
|
||||
| file://:0:0:0:0 | __va_list_tag | |
|
||||
| file://:0:0:0:0 | operator= | function __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & |
|
||||
| file://:0:0:0:0 | operator= | function __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & |
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
| clang_ms.cpp:11:5:11:13 | asm statement |
|
||||
| clang_ms.cpp:12:1:12:1 | return ... |
|
||||
| clang_ms.cpp:16:1:16:19 | // Test for CPP-184 |
|
||||
| clang_ms.cpp:17:1:17:32 | #pragma |
|
||||
| clang_ms.cpp:18:1:18:31 | #pragma |
|
||||
| file://:0:0:0:0 | |
|
||||
| file://:0:0:0:0 | (global namespace) |
|
||||
| file://:0:0:0:0 | _Complex __float128 |
|
||||
|
@ -48,6 +50,7 @@
|
|||
| file://:0:0:0:0 | __ptr32 |
|
||||
| file://:0:0:0:0 | __ptr64 |
|
||||
| file://:0:0:0:0 | __sptr |
|
||||
| file://:0:0:0:0 | __super |
|
||||
| file://:0:0:0:0 | __uptr |
|
||||
| file://:0:0:0:0 | __va_list_tag |
|
||||
| file://:0:0:0:0 | __va_list_tag & |
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
| file://:0:0:0:0 | __ptr32 |
|
||||
| file://:0:0:0:0 | __ptr64 |
|
||||
| file://:0:0:0:0 | __sptr |
|
||||
| file://:0:0:0:0 | __super |
|
||||
| file://:0:0:0:0 | __uptr |
|
||||
| file://:0:0:0:0 | __va_list_tag |
|
||||
| file://:0:0:0:0 | __va_list_tag & |
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
class buf
|
||||
{
|
||||
public:
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
class packet
|
||||
{
|
||||
public:
|
||||
buf data;
|
||||
};
|
||||
|
||||
typedef long ssize_t;
|
||||
|
||||
ssize_t argument_source(void *buf);
|
||||
|
||||
void sink(char *b);
|
||||
|
||||
void handlePacket(packet *p)
|
||||
{
|
||||
sink(p->data.buffer);
|
||||
}
|
||||
|
||||
void f(buf* b)
|
||||
{
|
||||
char *raw;
|
||||
packet p;
|
||||
argument_source(raw);
|
||||
argument_source(b->buffer);
|
||||
argument_source(p.data.buffer);
|
||||
sink(raw);
|
||||
sink(b->buffer);
|
||||
handlePacket(&p);
|
||||
}
|
|
@ -122,6 +122,17 @@ edges
|
|||
| D.cpp:64:10:64:17 | boxfield [box, elem] | D.cpp:64:20:64:22 | box [elem] |
|
||||
| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | boxfield [box, elem] |
|
||||
| D.cpp:64:20:64:22 | box [elem] | D.cpp:64:25:64:28 | elem |
|
||||
| E.cpp:19:27:19:27 | p [data, buffer] | E.cpp:21:10:21:10 | p [data, buffer] |
|
||||
| E.cpp:21:10:21:10 | p [data, buffer] | E.cpp:21:13:21:16 | data [buffer] |
|
||||
| E.cpp:21:13:21:16 | data [buffer] | E.cpp:21:18:21:23 | buffer |
|
||||
| E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw |
|
||||
| E.cpp:29:21:29:21 | b [post update] [buffer] | E.cpp:32:10:32:10 | b [buffer] |
|
||||
| E.cpp:29:24:29:29 | ref arg buffer | E.cpp:29:21:29:21 | b [post update] [buffer] |
|
||||
| E.cpp:30:21:30:21 | p [post update] [data, buffer] | E.cpp:33:18:33:19 | & ... [data, buffer] |
|
||||
| E.cpp:30:23:30:26 | data [post update] [buffer] | E.cpp:30:21:30:21 | p [post update] [data, buffer] |
|
||||
| E.cpp:30:28:30:33 | ref arg buffer | E.cpp:30:23:30:26 | data [post update] [buffer] |
|
||||
| E.cpp:32:10:32:10 | b [buffer] | E.cpp:32:13:32:18 | buffer |
|
||||
| E.cpp:33:18:33:19 | & ... [data, buffer] | E.cpp:19:27:19:27 | p [data, buffer] |
|
||||
| aliasing.cpp:9:3:9:3 | s [post update] [m1] | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | ... = ... | aliasing.cpp:9:3:9:3 | s [post update] [m1] |
|
||||
| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | ... = ... |
|
||||
|
@ -378,6 +389,20 @@ nodes
|
|||
| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] |
|
||||
| D.cpp:64:20:64:22 | box [elem] | semmle.label | box [elem] |
|
||||
| D.cpp:64:25:64:28 | elem | semmle.label | elem |
|
||||
| E.cpp:19:27:19:27 | p [data, buffer] | semmle.label | p [data, buffer] |
|
||||
| E.cpp:21:10:21:10 | p [data, buffer] | semmle.label | p [data, buffer] |
|
||||
| E.cpp:21:13:21:16 | data [buffer] | semmle.label | data [buffer] |
|
||||
| E.cpp:21:18:21:23 | buffer | semmle.label | buffer |
|
||||
| E.cpp:28:21:28:23 | ref arg raw | semmle.label | ref arg raw |
|
||||
| E.cpp:29:21:29:21 | b [post update] [buffer] | semmle.label | b [post update] [buffer] |
|
||||
| E.cpp:29:24:29:29 | ref arg buffer | semmle.label | ref arg buffer |
|
||||
| E.cpp:30:21:30:21 | p [post update] [data, buffer] | semmle.label | p [post update] [data, buffer] |
|
||||
| E.cpp:30:23:30:26 | data [post update] [buffer] | semmle.label | data [post update] [buffer] |
|
||||
| E.cpp:30:28:30:33 | ref arg buffer | semmle.label | ref arg buffer |
|
||||
| E.cpp:31:10:31:12 | raw | semmle.label | raw |
|
||||
| E.cpp:32:10:32:10 | b [buffer] | semmle.label | b [buffer] |
|
||||
| E.cpp:32:13:32:18 | buffer | semmle.label | buffer |
|
||||
| E.cpp:33:18:33:19 | & ... [data, buffer] | semmle.label | & ... [data, buffer] |
|
||||
| aliasing.cpp:9:3:9:3 | s [post update] [m1] | semmle.label | s [post update] [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | ... = ... | semmle.label | ... = ... |
|
||||
| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input |
|
||||
|
@ -532,6 +557,9 @@ nodes
|
|||
| D.cpp:22:25:22:31 | call to getElem | D.cpp:42:15:42:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:42:15:42:24 | new | new |
|
||||
| D.cpp:22:25:22:31 | call to getElem | D.cpp:49:15:49:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:49:15:49:24 | new | new |
|
||||
| D.cpp:64:25:64:28 | elem | D.cpp:56:15:56:24 | new | D.cpp:64:25:64:28 | elem | elem flows from $@ | D.cpp:56:15:56:24 | new | new |
|
||||
| E.cpp:21:18:21:23 | buffer | E.cpp:30:28:30:33 | ref arg buffer | E.cpp:21:18:21:23 | buffer | buffer flows from $@ | E.cpp:30:28:30:33 | ref arg buffer | ref arg buffer |
|
||||
| E.cpp:31:10:31:12 | raw | E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | raw flows from $@ | E.cpp:28:21:28:23 | ref arg raw | ref arg raw |
|
||||
| E.cpp:32:13:32:18 | buffer | E.cpp:29:24:29:29 | ref arg buffer | E.cpp:32:13:32:18 | buffer | buffer flows from $@ | E.cpp:29:24:29:29 | ref arg buffer | ref arg buffer |
|
||||
| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input |
|
||||
|
|
|
@ -14,6 +14,11 @@ class Conf extends Configuration {
|
|||
src.asExpr() instanceof NewExpr
|
||||
or
|
||||
src.asExpr().(Call).getTarget().hasName("user_input")
|
||||
or
|
||||
exists(FunctionCall fc |
|
||||
fc.getAnArgument() = src.asDefiningArgument() and
|
||||
fc.getTarget().hasName("argument_source")
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(Node sink) {
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
| c.c | library-tests/files/c.c |
|
||||
| files1.cpp | library-tests/files/files1.cpp |
|
||||
| files1.h | library-tests/files/files1.h |
|
||||
| files2.cpp | library-tests/files/files2.cpp |
|
|
@ -1,5 +0,0 @@
|
|||
import cpp
|
||||
|
||||
from File f
|
||||
where f.toString() != ""
|
||||
select f.toString(), f.getRelativePath()
|
|
@ -0,0 +1,4 @@
|
|||
| c.c | library-tests/files/c.c | CFile, MetricFile | C | | |
|
||||
| files1.cpp | library-tests/files/files1.cpp | CppFile, MetricFile | C++ | swap | t |
|
||||
| files1.h | library-tests/files/files1.h | HeaderFile, MetricFile | | swap | |
|
||||
| files2.cpp | library-tests/files/files2.cpp | CppFile, MetricFile | C++ | g | x, y |
|
|
@ -0,0 +1,18 @@
|
|||
import cpp
|
||||
|
||||
string describe(File f) {
|
||||
f.compiledAsC() and
|
||||
result = "C"
|
||||
or
|
||||
f.compiledAsCpp() and
|
||||
result = "C++"
|
||||
or
|
||||
f instanceof XMLParent and
|
||||
result = "XMLParent" // regression tests a bug in the characteristic predicate of XMLParent
|
||||
}
|
||||
|
||||
from File f
|
||||
where f.toString() != ""
|
||||
select f.toString(), f.getRelativePath(), concat(f.getAQlClass().toString(), ", "),
|
||||
concat(describe(f), ", "), concat(f.getATopLevelDeclaration().toString(), ", "),
|
||||
concat(LocalVariable v | f.getADeclaration() = v | v.toString(), ", ")
|
|
@ -1 +0,0 @@
|
|||
| files1.h:0:0:0:0 | files1.h | files1.cpp:4:6:4:9 | swap |
|
|
@ -1,4 +0,0 @@
|
|||
import cpp
|
||||
|
||||
from HeaderFile f
|
||||
select f, f.getATopLevelDeclaration()
|
|
@ -1,8 +0,0 @@
|
|||
| CFile | C | --- | c.c |
|
||||
| CppFile | - | C++ | files1.cpp |
|
||||
| CppFile | - | C++ | files2.cpp |
|
||||
| HeaderFile | - | --- | files1.h |
|
||||
| MetricFile | - | --- | files1.h |
|
||||
| MetricFile | - | C++ | files1.cpp |
|
||||
| MetricFile | - | C++ | files2.cpp |
|
||||
| MetricFile | C | --- | c.c |
|
|
@ -1,11 +0,0 @@
|
|||
import cpp
|
||||
|
||||
string isCompiledAsC(File f) { if f.compiledAsC() then result = "C" else result = "-" }
|
||||
|
||||
string isCompiledAsCpp(File f) { if f.compiledAsCpp() then result = "C++" else result = "---" }
|
||||
|
||||
from File f
|
||||
// On 64bit Linux, __va_list_tag is in the unknown file (""). Ignore it.
|
||||
where f.getAbsolutePath() != ""
|
||||
select (f.getAQlClass().toString() + " ").prefix(10), isCompiledAsC(f), isCompiledAsCpp(f),
|
||||
f.toString()
|
|
@ -1,3 +0,0 @@
|
|||
| files1.cpp | files1.cpp:4:6:4:9 | swap |
|
||||
| files1.h | files1.cpp:4:6:4:9 | swap |
|
||||
| files2.cpp | files2.cpp:3:6:3:6 | g |
|
|
@ -1,7 +0,0 @@
|
|||
import cpp
|
||||
|
||||
from File f, Declaration d
|
||||
where
|
||||
d = f.getATopLevelDeclaration() and
|
||||
d.getName() != "__va_list_tag"
|
||||
select f.toString(), d
|
|
@ -1,3 +0,0 @@
|
|||
| files1.cpp | files1.cpp:6:6:6:6 | t |
|
||||
| files2.cpp | files2.cpp:4:6:4:6 | x |
|
||||
| files2.cpp | files2.cpp:5:6:5:6 | y |
|
|
@ -1,5 +0,0 @@
|
|||
import cpp
|
||||
|
||||
from File f, LocalVariable v
|
||||
where f.getADeclaration() = v
|
||||
select f.toString(), v
|
|
@ -201,6 +201,7 @@
|
|||
| file://:0:0:0:0 | ..(*)(..) |
|
||||
| file://:0:0:0:0 | ..(*)(..) |
|
||||
| file://:0:0:0:0 | ..(..) |
|
||||
| file://:0:0:0:0 | __super |
|
||||
| file://:0:0:0:0 | __va_list_tag |
|
||||
| file://:0:0:0:0 | __va_list_tag & |
|
||||
| file://:0:0:0:0 | __va_list_tag && |
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
| file://:0:0:0:0 | __super | false |
|
||||
| file://:0:0:0:0 | __va_list_tag | false |
|
||||
| file://:0:0:0:0 | operator= | false |
|
||||
| file://:0:0:0:0 | operator= | false |
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import cpp
|
||||
|
||||
from Expr e
|
||||
where exists(e.toString())
|
||||
select e, e.getType()
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
| file://:0:0:0:0 | X |
|
||||
| file://:0:0:0:0 | X |
|
||||
| file://:0:0:0:0 | Y |
|
||||
| file://:0:0:0:0 | __super |
|
||||
| file://:0:0:0:0 | __va_list_tag |
|
||||
| file://:0:0:0:0 | __va_list_tag & |
|
||||
| file://:0:0:0:0 | __va_list_tag && |
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
| file://:0:0:0:0 | __ptr32 |
|
||||
| file://:0:0:0:0 | __ptr64 |
|
||||
| file://:0:0:0:0 | __sptr |
|
||||
| file://:0:0:0:0 | __super |
|
||||
| file://:0:0:0:0 | __uptr |
|
||||
| file://:0:0:0:0 | __va_list_tag |
|
||||
| file://:0:0:0:0 | __va_list_tag & |
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
| file://:0:0:0:0 | __ptr32 | Other |
|
||||
| file://:0:0:0:0 | __ptr64 | Other |
|
||||
| file://:0:0:0:0 | __sptr | Other |
|
||||
| file://:0:0:0:0 | __super | Other |
|
||||
| file://:0:0:0:0 | __uptr | Other |
|
||||
| file://:0:0:0:0 | __va_list_tag | Other |
|
||||
| file://:0:0:0:0 | abstract | Other |
|
||||
|
|
|
@ -3,5 +3,6 @@ import cpp
|
|||
from Element e, string s
|
||||
where
|
||||
not e instanceof Folder and
|
||||
exists(e.toString()) and // Work around `VariableDeclarationEntry.toString()` not holding
|
||||
if e instanceof VariableAccess then s = "Variable access" else s = "Other"
|
||||
select e, s
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
| tst.c:8:1:8:18 | // lgtm: blah blah | lgtm: blah blah | lgtm | tst.c:8:1:8:18 | // lgtm: blah blah |
|
||||
| tst.c:9:1:9:32 | // lgtm blah blah #falsepositive | lgtm blah blah #falsepositive | lgtm | tst.c:9:1:9:32 | // lgtm blah blah #falsepositive |
|
||||
| tst.c:10:1:10:39 | //lgtm [js/invocation-of-non-function] | lgtm [js/invocation-of-non-function] | lgtm [js/invocation-of-non-function] | tst.c:10:1:10:39 | //lgtm [js/invocation-of-non-function] |
|
||||
| tst.c:11:1:11:10 | /* lgtm */ | lgtm | lgtm | tst.c:11:1:11:10 | /* lgtm */ |
|
||||
| tst.c:12:1:12:9 | // lgtm[] | lgtm[] | lgtm[] | tst.c:12:1:12:9 | // lgtm[] |
|
||||
| tst.c:14:1:14:6 | //lgtm | lgtm | lgtm | tst.c:14:1:14:6 | //lgtm |
|
||||
| tst.c:15:1:15:7 | //\tlgtm | \tlgtm | lgtm | tst.c:15:1:15:7 | //\tlgtm |
|
||||
|
@ -22,6 +23,10 @@
|
|||
| tst.c:27:1:27:70 | // lgtm[js/debugger-statement] and lgtm[js/invocation-of-non-function] | lgtm[js/debugger-statement] and lgtm[js/invocation-of-non-function] | lgtm[js/invocation-of-non-function] | tst.c:27:1:27:70 | // lgtm[js/debugger-statement] and lgtm[js/invocation-of-non-function] |
|
||||
| tst.c:28:1:28:36 | // lgtm[js/debugger-statement]; lgtm | lgtm[js/debugger-statement]; lgtm | lgtm | tst.c:28:1:28:36 | // lgtm[js/debugger-statement]; lgtm |
|
||||
| tst.c:28:1:28:36 | // lgtm[js/debugger-statement]; lgtm | lgtm[js/debugger-statement]; lgtm | lgtm[js/debugger-statement] | tst.c:28:1:28:36 | // lgtm[js/debugger-statement]; lgtm |
|
||||
| tst.c:29:1:29:12 | /* lgtm[] */ | lgtm[] | lgtm[] | tst.c:29:1:29:12 | /* lgtm[] */ |
|
||||
| tst.c:30:1:30:41 | /* lgtm[js/invocation-of-non-function] */ | lgtm[js/invocation-of-non-function] | lgtm[js/invocation-of-non-function] | tst.c:30:1:30:41 | /* lgtm[js/invocation-of-non-function] */ |
|
||||
| tst.c:36:1:36:55 | /* lgtm[@tag:nullness,js/invocation-of-non-function] */ | lgtm[@tag:nullness,js/invocation-of-non-function] | lgtm[@tag:nullness,js/invocation-of-non-function] | tst.c:36:1:36:55 | /* lgtm[@tag:nullness,js/invocation-of-non-function] */ |
|
||||
| tst.c:37:1:37:25 | /* lgtm[@tag:nullness] */ | lgtm[@tag:nullness] | lgtm[@tag:nullness] | tst.c:37:1:37:25 | /* lgtm[@tag:nullness] */ |
|
||||
| tstWindows.c:1:12:1:18 | // lgtm | lgtm | lgtm | tstWindows.c:1:1:1:18 | // lgtm |
|
||||
| tstWindows.c:2:1:2:30 | // lgtm[js/debugger-statement] | lgtm[js/debugger-statement] | lgtm[js/debugger-statement] | tstWindows.c:2:1:2:30 | // lgtm[js/debugger-statement] |
|
||||
| tstWindows.c:3:1:3:61 | // lgtm[js/debugger-statement, js/invocation-of-non-function] | lgtm[js/debugger-statement, js/invocation-of-non-function] | lgtm[js/debugger-statement, js/invocation-of-non-function] | tstWindows.c:3:1:3:61 | // lgtm[js/debugger-statement, js/invocation-of-non-function] |
|
||||
|
@ -32,6 +37,7 @@
|
|||
| tstWindows.c:8:1:8:18 | // lgtm: blah blah | lgtm: blah blah | lgtm | tstWindows.c:8:1:8:18 | // lgtm: blah blah |
|
||||
| tstWindows.c:9:1:9:32 | // lgtm blah blah #falsepositive | lgtm blah blah #falsepositive | lgtm | tstWindows.c:9:1:9:32 | // lgtm blah blah #falsepositive |
|
||||
| tstWindows.c:10:1:10:39 | //lgtm [js/invocation-of-non-function] | lgtm [js/invocation-of-non-function] | lgtm [js/invocation-of-non-function] | tstWindows.c:10:1:10:39 | //lgtm [js/invocation-of-non-function] |
|
||||
| tstWindows.c:11:1:11:10 | /* lgtm */ | lgtm | lgtm | tstWindows.c:11:1:11:10 | /* lgtm */ |
|
||||
| tstWindows.c:12:1:12:9 | // lgtm[] | lgtm[] | lgtm[] | tstWindows.c:12:1:12:9 | // lgtm[] |
|
||||
| tstWindows.c:14:1:14:6 | //lgtm | lgtm | lgtm | tstWindows.c:14:1:14:6 | //lgtm |
|
||||
| tstWindows.c:15:1:15:7 | //\tlgtm | \tlgtm | lgtm | tstWindows.c:15:1:15:7 | //\tlgtm |
|
||||
|
@ -46,3 +52,7 @@
|
|||
| tstWindows.c:27:1:27:70 | // lgtm[js/debugger-statement] and lgtm[js/invocation-of-non-function] | lgtm[js/debugger-statement] and lgtm[js/invocation-of-non-function] | lgtm[js/invocation-of-non-function] | tstWindows.c:27:1:27:70 | // lgtm[js/debugger-statement] and lgtm[js/invocation-of-non-function] |
|
||||
| tstWindows.c:28:1:28:36 | // lgtm[js/debugger-statement]; lgtm | lgtm[js/debugger-statement]; lgtm | lgtm | tstWindows.c:28:1:28:36 | // lgtm[js/debugger-statement]; lgtm |
|
||||
| tstWindows.c:28:1:28:36 | // lgtm[js/debugger-statement]; lgtm | lgtm[js/debugger-statement]; lgtm | lgtm[js/debugger-statement] | tstWindows.c:28:1:28:36 | // lgtm[js/debugger-statement]; lgtm |
|
||||
| tstWindows.c:29:1:29:12 | /* lgtm[] */ | lgtm[] | lgtm[] | tstWindows.c:29:1:29:12 | /* lgtm[] */ |
|
||||
| tstWindows.c:30:1:30:41 | /* lgtm[js/invocation-of-non-function] */ | lgtm[js/invocation-of-non-function] | lgtm[js/invocation-of-non-function] | tstWindows.c:30:1:30:41 | /* lgtm[js/invocation-of-non-function] */ |
|
||||
| tstWindows.c:36:1:36:55 | /* lgtm[@tag:nullness,js/invocation-of-non-function] */ | lgtm[@tag:nullness,js/invocation-of-non-function] | lgtm[@tag:nullness,js/invocation-of-non-function] | tstWindows.c:36:1:36:55 | /* lgtm[@tag:nullness,js/invocation-of-non-function] */ |
|
||||
| tstWindows.c:37:1:37:25 | /* lgtm[@tag:nullness] */ | lgtm[@tag:nullness] | lgtm[@tag:nullness] | tstWindows.c:37:1:37:25 | /* lgtm[@tag:nullness] */ |
|
||||
|
|
|
@ -26,3 +26,12 @@ int x = 0; // lgtm
|
|||
// LGTM[js/debugger-statement]
|
||||
// lgtm[js/debugger-statement] and lgtm[js/invocation-of-non-function]
|
||||
// lgtm[js/debugger-statement]; lgtm
|
||||
/* lgtm[] */
|
||||
/* lgtm[js/invocation-of-non-function] */
|
||||
/* lgtm
|
||||
*/
|
||||
/* lgtm
|
||||
|
||||
*/
|
||||
/* lgtm[@tag:nullness,js/invocation-of-non-function] */
|
||||
/* lgtm[@tag:nullness] */
|
|
@ -26,3 +26,12 @@ int x = 0; // lgtm
|
|||
// LGTM[js/debugger-statement]
|
||||
// lgtm[js/debugger-statement] and lgtm[js/invocation-of-non-function]
|
||||
// lgtm[js/debugger-statement]; lgtm
|
||||
/* lgtm[] */
|
||||
/* lgtm[js/invocation-of-non-function] */
|
||||
/* lgtm
|
||||
*/
|
||||
/* lgtm
|
||||
|
||||
*/
|
||||
/* lgtm[@tag:nullness,js/invocation-of-non-function] */
|
||||
/* lgtm[@tag:nullness] */
|
|
@ -5,13 +5,6 @@
|
|||
import semmle.code.csharp.Element
|
||||
import semmle.code.csharp.Location
|
||||
|
||||
/** Adapter so that XMLLocatables are elements */
|
||||
library class XMLLocatableElement extends @xmllocatable, Element {
|
||||
override string toString() { result = this.(XMLLocatable).toString() }
|
||||
|
||||
override Location getALocation() { result = this.(XMLLocatable).getALocation() }
|
||||
}
|
||||
|
||||
/** An XML element that has a location. */
|
||||
class XMLLocatable extends @xmllocatable {
|
||||
XMLLocatable() {
|
||||
|
|
|
@ -793,7 +793,10 @@ module Internal {
|
|||
TBooleanValue(boolean b) { b = true or b = false } or
|
||||
TIntegerValue(int i) { i = any(Expr e).getValue().toInt() } or
|
||||
TNullValue(boolean b) { b = true or b = false } or
|
||||
TMatchValue(Case c, boolean b) { b = true or b = false } or
|
||||
TMatchValue(Case c, boolean b) {
|
||||
exists(c.getPattern()) and
|
||||
(b = true or b = false)
|
||||
} or
|
||||
TEmptyCollectionValue(boolean b) { b = true or b = false }
|
||||
|
||||
/** A callable that always returns a `null` value. */
|
||||
|
|
|
@ -355,7 +355,7 @@ private module Cached {
|
|||
TSsaDefinitionNode(Ssa::Definition def) or
|
||||
TInstanceParameterNode(Callable c) { c.hasBody() and not c.(Modifiable).isStatic() } or
|
||||
TCilParameterNode(CIL::Parameter p) { p.getMethod().hasBody() } or
|
||||
TTaintedParameterNode(Parameter p) { p.getCallable().hasBody() } or
|
||||
TTaintedParameterNode(Parameter p) { explicitParameterNode(_, p) } or
|
||||
TTaintedReturnNode(ControlFlow::Nodes::ElementNode cfn) {
|
||||
any(Callable c).canYieldReturn(cfn.getElement())
|
||||
} or
|
||||
|
|
|
@ -295,7 +295,7 @@ class MethodCall extends Call, QualifiableExpr, LateBindableExpr, @method_invoca
|
|||
|
||||
override Method getQualifiedDeclaration() { result = getTarget() }
|
||||
|
||||
override string toString() { result = "call to method " + this.getTarget().getName() }
|
||||
override string toString() { result = "call to method " + concat(this.getTarget().getName()) }
|
||||
|
||||
override Expr getRawArgument(int i) {
|
||||
if exists(getQualifier())
|
||||
|
|
|
@ -116,10 +116,17 @@ private predicate isDynamicElementAccess(@dynamic_element_access_expr e) { any()
|
|||
* A local variable declaration, for example `var i = 0`.
|
||||
*/
|
||||
class LocalVariableDeclExpr extends Expr, @local_var_decl_expr {
|
||||
/** Gets the local variable being declared. */
|
||||
/**
|
||||
* Gets the local variable being declared, if any. The only case where
|
||||
* no variable is declared is when a discard symbol is used, for example
|
||||
* ```
|
||||
* if (int.TryParse(s, out var _))
|
||||
* ...
|
||||
* ```
|
||||
*/
|
||||
LocalVariable getVariable() { localvars(result, _, _, _, _, this) }
|
||||
|
||||
/** Gets the name of the variable being declared. */
|
||||
/** Gets the name of the variable being declared, if any. */
|
||||
string getName() { result = this.getVariable().getName() }
|
||||
|
||||
/** Gets the initializer expression of this local variable declaration, if any. */
|
||||
|
@ -136,6 +143,9 @@ class LocalVariableDeclExpr extends Expr, @local_var_decl_expr {
|
|||
|
||||
override string toString() {
|
||||
result = this.getVariable().getType().getName() + " " + this.getName()
|
||||
or
|
||||
not exists(this.getVariable()) and
|
||||
result = "_"
|
||||
}
|
||||
|
||||
/** Gets the variable access used in this declaration, if any. */
|
||||
|
|
|
@ -1236,6 +1236,8 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
|||
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1245,6 +1247,8 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1258,12 +1262,14 @@ class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
*/
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction {
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
|
|
@ -1236,6 +1236,8 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
|||
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1245,6 +1247,8 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1258,12 +1262,14 @@ class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
|
|||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
|
||||
Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
*/
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction {
|
||||
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
|
||||
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
|
||||
|
||||
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
|
||||
|
|
|
@ -82,8 +82,8 @@
|
|||
| GlobalDataFlow.cs:100:24:100:33 | call to method Return | return | GlobalDataFlow.cs:100:24:100:33 | call to method Return |
|
||||
| GlobalDataFlow.cs:102:28:102:63 | call to method GetMethod | return | GlobalDataFlow.cs:102:28:102:63 | call to method GetMethod |
|
||||
| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | return | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke |
|
||||
| GlobalDataFlow.cs:104:9:104:46 | call to method ReturnOut | out | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) |
|
||||
| GlobalDataFlow.cs:104:9:104:46 | call to method ReturnOut | ref | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) |
|
||||
| GlobalDataFlow.cs:104:9:104:49 | call to method ReturnOut | out | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) |
|
||||
| GlobalDataFlow.cs:104:9:104:49 | call to method ReturnOut | ref | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) |
|
||||
| GlobalDataFlow.cs:106:9:106:49 | call to method ReturnOut | out | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) |
|
||||
| GlobalDataFlow.cs:108:9:108:49 | call to method ReturnRef | out | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) |
|
||||
| GlobalDataFlow.cs:108:9:108:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) |
|
||||
|
|
|
@ -101,7 +101,7 @@ public class DataFlow
|
|||
Check(nonSink0);
|
||||
nonSink0 = (string)typeof(DataFlow).GetMethod("Return").Invoke(null, new object[] { nonSink0 });
|
||||
Check(nonSink0);
|
||||
ReturnOut("", out nonSink0, out var _);
|
||||
ReturnOut("", out nonSink0, out string _);
|
||||
Check(nonSink0);
|
||||
ReturnOut(sink1, out var _, out nonSink0);
|
||||
Check(nonSink0);
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
| queries.cs:27:11:27:42 | call to method Join | 2 | queries.cs:27:21:27:25 | access to local variable list1 |
|
||||
| queries.cs:27:11:27:42 | call to method Join | 3 | queries.cs:27:30:27:33 | access to local variable next |
|
||||
| queries.cs:27:11:27:42 | call to method Join | 4 | queries.cs:27:42:27:42 | access to local variable c |
|
||||
| queries.cs:28:11:28:18 | call to method | 0 | queries.cs:27:11:27:42 | call to method Join |
|
||||
| queries.cs:28:11:28:18 | call to method | 1 | queries.cs:28:18:28:18 | 1 |
|
||||
| queries.cs:32:11:32:21 | call to method SelectMany | 0 | queries.cs:31:11:31:25 | IList<Int32> a = ... |
|
||||
| queries.cs:32:11:32:21 | call to method SelectMany | 1 | queries.cs:32:11:32:21 | IList<Int32> b = ... |
|
||||
| queries.cs:32:11:32:21 | call to method SelectMany | 2 | queries.cs:32:21:32:21 | access to local variable a |
|
||||
|
@ -49,3 +51,5 @@
|
|||
| queries.cs:55:11:55:49 | call to method GroupJoin | 3 | queries.cs:55:30:55:30 | access to local variable a |
|
||||
| queries.cs:55:11:55:49 | call to method GroupJoin | 4 | queries.cs:55:39:55:42 | access to indexer |
|
||||
| queries.cs:55:11:55:49 | call to method GroupJoin | 5 | queries.cs:55:11:55:49 | IList<IList<Int32>> d = ... |
|
||||
| queries.cs:56:11:56:22 | call to method | 0 | queries.cs:55:11:55:49 | call to method GroupJoin |
|
||||
| queries.cs:56:11:56:22 | call to method | 1 | queries.cs:56:18:56:22 | (..., ...) |
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
| ControlFlow.cs:9:17:9:33 | Call (unknown target) | ControlFlow.cs:9:13:9:33 | (unknown type) v |
|
||||
| ControlFlow.cs:10:9:10:13 | Expression | ControlFlow.cs:10:22:10:22 | access to local variable v |
|
||||
| ControlFlow.cs:10:9:10:43 | Call (unknown target) | ControlFlow.cs:12:9:12:87 | ...; |
|
||||
| ControlFlow.cs:10:9:10:43 | call to method | ControlFlow.cs:12:9:12:87 | ...; |
|
||||
| ControlFlow.cs:10:9:10:44 | ...; | ControlFlow.cs:10:9:10:13 | Expression |
|
||||
| ControlFlow.cs:10:22:10:22 | access to local variable v | ControlFlow.cs:10:22:10:24 | Expression |
|
||||
| ControlFlow.cs:10:22:10:24 | Expression | ControlFlow.cs:10:22:10:26 | Expression |
|
||||
| ControlFlow.cs:10:22:10:26 | Expression | ControlFlow.cs:10:29:10:42 | "This is true" |
|
||||
| ControlFlow.cs:10:29:10:42 | "This is true" | ControlFlow.cs:10:9:10:43 | Call (unknown target) |
|
||||
| ControlFlow.cs:10:29:10:42 | "This is true" | ControlFlow.cs:10:9:10:43 | call to method |
|
||||
| ControlFlow.cs:12:9:12:86 | Call (unknown target) | ControlFlow.cs:12:37:12:47 | Expression |
|
||||
| ControlFlow.cs:12:9:12:87 | ...; | ControlFlow.cs:12:9:12:86 | Call (unknown target) |
|
||||
| ControlFlow.cs:12:35:12:86 | { ..., ... } | ControlFlow.cs:7:10:7:10 | exit F |
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
| errors.cs:24:31:24:40 | errors.cs:24:31:24:40 | unknown | none |
|
||||
| errors.cs:24:31:24:40 | errors.cs:24:31:24:40 | call to method | none |
|
||||
| errors.cs:43:21:43:28 | errors.cs:43:21:43:28 | object creation of type C1 | C1 |
|
||||
| errors.cs:44:13:44:19 | errors.cs:44:13:44:19 | call to method m1 | m1 |
|
||||
| errors.cs:45:13:45:19 | errors.cs:45:13:45:19 | call to method m2 | m2 |
|
||||
| errors.cs:46:13:46:38 | errors.cs:46:13:46:38 | unknown | none |
|
||||
| errors.cs:46:13:46:38 | errors.cs:46:13:46:38 | call to method | none |
|
||||
| errors.cs:53:17:53:25 | errors.cs:53:17:53:25 | object creation of type C2 | none |
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Find the thief: Introduction
|
||||
============================
|
||||
|
||||
There is a small village hidden away in the mountains. The village is divided into four parts - north, south, east, and west - and in the center stands a dark and mysterious castle... Inside the castle, locked away in the highest tower, lies the king's valuable golden crown. One night, a terrible crime is committed. A thief breaks into the tower and steals the crown!
|
||||
There is a small village hidden away in the mountains. The village is divided into four parts—north, south, east, and west—and in the center stands a dark and mysterious castle... Inside the castle, locked away in the highest tower, lies the king's valuable golden crown. One night, a terrible crime is committed. A thief breaks into the tower and steals the crown!
|
||||
|
||||
You know that the thief must live in the village, since nobody else knew about the crown. After some expert detective work, you obtain a list of all the people in the village and some of their personal details.
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ Notice that we have only temporarily introduced the variable ``c`` and we didn't
|
|||
|
||||
Note
|
||||
|
||||
If you are familiar with logic, you may notice that ``exists`` in QL corresponds to the existential `quantifier <https://help.semmle.com/QL/ql-handbook/formulas.html#quantified-formulas>`__ in logic. QL also has a universal quantifier ``forall(vars | formula 1 | formula 2)`` which is logically equivalent to ``not(exists(vars | formula 1 | not formula 2))``.
|
||||
If you are familiar with logic, you may notice that ``exists`` in QL corresponds to the existential `quantifier <https://help.semmle.com/QL/ql-handbook/formulas.html#quantified-formulas>`__ in logic. QL also has a universal quantifier ``forall(vars | formula 1 | formula 2)`` which is logically equivalent to ``not exists(vars | formula 1 | not formula 2)``.
|
||||
|
||||
The real investigation
|
||||
----------------------
|
||||
|
@ -124,8 +124,8 @@ Hints
|
|||
|
||||
from Person t
|
||||
where <condition 1> and
|
||||
not <condition 2> and
|
||||
...
|
||||
not <condition 2> and
|
||||
...
|
||||
select t
|
||||
|
||||
Once you have finished, you will have a list of possible suspects. One of those people must be the thief!
|
||||
|
|
|
@ -12,50 +12,50 @@ Read the examples below to learn how to define predicates and classes in QL. The
|
|||
Select the southerners
|
||||
----------------------
|
||||
|
||||
This time you only need to consider a specific group of villagers, namely those living in the south of the village. Instead of writing ``getLocation() = "south"`` in all your queries, you could define a new `predicate <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ ``southern``:
|
||||
This time you only need to consider a specific group of villagers, namely those living in the south of the village. Instead of writing ``getLocation() = "south"`` in all your queries, you could define a new `predicate <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ ``isSouthern``:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
predicate southern(Person p) {
|
||||
p.getLocation() = "south"
|
||||
predicate isSouthern(Person p) {
|
||||
p.getLocation() = "south"
|
||||
}
|
||||
|
||||
The predicate ``southern(p)`` takes a single parameter ``p`` and checks if ``p`` satisfies the property ``p.getLocation() = "south"``.
|
||||
The predicate ``isSouthern(p)`` takes a single parameter ``p`` and checks if ``p`` satisfies the property ``p.getLocation() = "south"``.
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
- The name of a predicate always starts with a lowercase letter.
|
||||
- You can also define predicates with a result. In that case, the keyword ``predicate`` is replaced with the type of the result. This is like introducing a new argument, the special variable ``result``. For example, ``int getAge() {result = ...}`` returns an ``int``.
|
||||
- You can also define predicates with a result. In that case, the keyword ``predicate`` is replaced with the type of the result. This is like introducing a new argument, the special variable ``result``. For example, ``int getAge() { result = ... }`` returns an ``int``.
|
||||
|
||||
You can now list all southerners using:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
/* define predicate `southern` as above */
|
||||
/* define predicate `isSouthern` as above */
|
||||
|
||||
from Person p
|
||||
where southern(p)
|
||||
where isSouthern(p)
|
||||
select p
|
||||
|
||||
This is already a nice way to simplify the logic, but we could be more efficient. Currently, the query looks at every ``Person p``, and then restricts to those who satisfy ``southern(p)``. Instead, we could define a new `class <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__ ``Southerner`` containing precisely the people we want to consider.
|
||||
This is already a nice way to simplify the logic, but we could be more efficient. Currently, the query looks at every ``Person p``, and then restricts to those who satisfy ``isSouthern(p)``. Instead, we could define a new `class <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__ ``Southerner`` containing precisely the people we want to consider.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class Southerner extends Person {
|
||||
Southerner() { southern(this) }
|
||||
Southerner() { isSouthern(this) }
|
||||
}
|
||||
|
||||
A class in QL represents a logical property: when a value satisfies that property, it is a member of the class. This means that a value can be in many classes - being in a particular class doesn't stop it from being in other classes too.
|
||||
A class in QL represents a logical property: when a value satisfies that property, it is a member of the class. This means that a value can be in many classes—being in a particular class doesn't stop it from being in other classes too.
|
||||
|
||||
The expression ``southern(this)`` defines the logical property represented by the class, called its *characteristic predicate*. It uses a special variable ``this`` and indicates that a ``Person`` "``this``" is a ``Southerner`` if the property ``southern(this)`` holds.
|
||||
The expression ``isSouthern(this)`` defines the logical property represented by the class, called its *characteristic predicate*. It uses a special variable ``this`` and indicates that a ``Person`` "``this``" is a ``Southerner`` if the property ``isSouthern(this)`` holds.
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
If you are familiar with object-oriented programming languages, you might be tempted to think of the characteristic predicate as a *constructor*. However, this is **not** the case - it is a logical property which does not create any objects.
|
||||
If you are familiar with object-oriented programming languages, you might be tempted to think of the characteristic predicate as a *constructor*. However, this is **not** the case—it is a logical property which does not create any objects.
|
||||
|
||||
You always need to define a class in QL in terms of an existing (larger) class. In our example, a ``Southerner`` is a special kind of ``Person``, so we say that ``Southerner`` *extends* ("is a subset of") ``Person``.
|
||||
|
||||
|
@ -66,7 +66,7 @@ Using this class you can now list all people living in the south simply as:
|
|||
from Southerner s
|
||||
select s
|
||||
|
||||
You may have noticed that some predicates are appended, for example ``p.getAge()``, while others are not, for example ``southern(p)``. This is because ``getAge()`` is a member predicate, that is, a predicate that only applies to members of a class. You define such a member predicate inside a class. In this case, ``getAge()`` is defined inside the class ``Person``. In contrast, ``southern`` is defined separately and is not inside any classes. Member predicates are especially useful because you can chain them together easily. For example, ``p.getAge().sqrt()`` first gets the age of ``p`` and then calculates the square root of that number.
|
||||
You may have noticed that some predicates are appended, for example ``p.getAge()``, while others are not, for example ``isSouthern(p)``. This is because ``getAge()`` is a member predicate, that is, a predicate that only applies to members of a class. You define such a member predicate inside a class. In this case, ``getAge()`` is defined inside the class ``Person``. In contrast, ``isSouthern`` is defined separately and is not inside any classes. Member predicates are especially useful because you can chain them together easily. For example, ``p.getAge().sqrt()`` first gets the age of ``p`` and then calculates the square root of that number.
|
||||
|
||||
Travel restrictions
|
||||
-------------------
|
||||
|
@ -88,20 +88,19 @@ Start by defining a class ``Child`` containing all villagers under 10 years old.
|
|||
.. code-block:: ql
|
||||
|
||||
class Child extends Person {
|
||||
/* the characteristic predicate */
|
||||
Child() { this.getAge() < 10 }
|
||||
|
||||
/* the characteristic predicate */
|
||||
Child() { this.getAge() < 10 }
|
||||
|
||||
/* a member predicate */
|
||||
override predicate isAllowedIn(string region) {
|
||||
region = this.getLocation()
|
||||
}
|
||||
/* a member predicate */
|
||||
override predicate isAllowedIn(string region) {
|
||||
region = this.getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
Now try applying ``isAllowedIn(string region)`` to a person ``p``. If ``p`` is not a child, the original definition is used, but if ``p`` is a child, the new predicate definition overrides the original.
|
||||
|
||||
You know that the fire starters live in the south *and* that they must have been able to travel to the north. Write a query to find the possible suspects. You could also extend the ``select`` clause to list the age of the suspects. That way you can clearly see that all the children have been excluded from the list.
|
||||
|
||||
➤ `See the answer in the query console <https://lgtm.com/query/2164870087/>`__
|
||||
➤ `See the answer in the query console <https://lgtm.com/query/2551838470440192723/>`__
|
||||
|
||||
Continue to the :doc:`next page <fire-2>` to gather more clues and find out which of your suspects started the fire...
|
||||
|
|
|
@ -11,27 +11,27 @@ This is a very helpful clue. Remember that you wrote a QL query to select all ba
|
|||
where not exists (string c | p.getHairColor() = c)
|
||||
select p
|
||||
|
||||
To avoid having to type ``not exists (string c | p.getHairColor() = c)`` every time you want to select a bald person, you can instead define another new predicate ``bald``.
|
||||
To avoid having to type ``not exists (string c | p.getHairColor() = c)`` every time you want to select a bald person, you can instead define another new predicate ``isBald``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
predicate bald(Person p) {
|
||||
not exists (string c | p.getHairColor() = c)
|
||||
predicate isBald(Person p) {
|
||||
not exists (string c | p.getHairColor() = c)
|
||||
}
|
||||
|
||||
The property ``bald(p)`` holds whenever ``p`` is bald, so you can replace the previous query with:
|
||||
The property ``isBald(p)`` holds whenever ``p`` is bald, so you can replace the previous query with:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
from Person p
|
||||
where bald(p)
|
||||
where isBald(p)
|
||||
select p
|
||||
|
||||
The predicate ``bald`` is defined to take a ``Person``, so it can also take a ``Southerner``, as ``Southerner`` is a subtype of ``Person``. It can't take an ``int`` for example - that would cause an error.
|
||||
The predicate ``isBald`` is defined to take a ``Person``, so it can also take a ``Southerner``, as ``Southerner`` is a subtype of ``Person``. It can't take an ``int`` for example—that would cause an error.
|
||||
|
||||
You can now write a query to select the bald southerners who are allowed into the north.
|
||||
|
||||
➤ `See the answer in the query console <https://lgtm.com/query/1505746995987/>`__
|
||||
➤ `See the answer in the query console <https://lgtm.com/query/2572701606358725253/>`__
|
||||
|
||||
You have found the two fire starters! They are arrested and the villagers are once again impressed with your work.
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Crown the rightful heir
|
||||
=======================
|
||||
|
||||
Phew! No more crimes in the village - you can finally leave the village and go home.
|
||||
Phew! No more crimes in the village—you can finally leave the village and go home.
|
||||
|
||||
But then... During your last night in the village, the old king - the great King Basil - dies in his sleep and there is chaos everywhere!
|
||||
But then... During your last night in the village, the old king—the great King Basil—dies in his sleep and there is chaos everywhere!
|
||||
|
||||
The king never married and he had no children, so nobody knows who should inherit the king's castle and fortune. Immediately, lots of villagers claim that they are somehow descended from the king's family and that they are the true heir. People argue and fight and the situation seems hopeless.
|
||||
|
||||
|
@ -38,8 +38,8 @@ We know that the king has no children himself, but perhaps he has siblings. Writ
|
|||
.. code-block:: ql
|
||||
|
||||
from Person p
|
||||
where parentOf(p) = parentOf("King Basil") and
|
||||
not p = "King Basil"
|
||||
where parentOf(p) = parentOf("King Basil") and
|
||||
not p = "King Basil"
|
||||
select p
|
||||
|
||||
He does indeed have siblings! But you need to check if any of them are alive... Here is one more predicate you might need:
|
||||
|
@ -56,8 +56,8 @@ Use this predicate to see if the any of the king's siblings are alive.
|
|||
|
||||
from Person p
|
||||
where parentOf(p) = parentOf("King Basil") and
|
||||
not p = "King Basil"
|
||||
and not p.isDeceased()
|
||||
not p = "King Basil"
|
||||
and not p.isDeceased()
|
||||
select p
|
||||
|
||||
Unfortunately, none of King Basil's siblings are alive. Time to investigate further. It might be helpful to define a predicate ``childOf()`` which returns a child of the person. To do this, the ``parentOf()`` predicate can be used inside the definition of ``childOf()``. Remember that someone is a child of ``p`` if and only if ``p`` is their parent:
|
||||
|
@ -65,7 +65,7 @@ Unfortunately, none of King Basil's siblings are alive. Time to investigate furt
|
|||
.. code-block:: ql
|
||||
|
||||
Person childOf(Person p) {
|
||||
p = parentOf(result)
|
||||
p = parentOf(result)
|
||||
}
|
||||
|
||||
.. pull-quote::
|
||||
|
@ -80,7 +80,7 @@ Try to write a query to find out if any of the king's siblings have children:
|
|||
|
||||
from Person p
|
||||
where parentOf(p) = parentOf("King Basil") and
|
||||
not p = "King Basil"
|
||||
not p = "King Basil"
|
||||
select childOf(p)
|
||||
|
||||
The query returns no results, so they have no children. But perhaps King Basil has a cousin who is alive or has children, or a second cousin, or...
|
||||
|
@ -100,8 +100,8 @@ You can translate this into QL as follows:
|
|||
.. code-block:: ql
|
||||
|
||||
Person ancestorOf(Person p) {
|
||||
result = parentOf(p) or
|
||||
result = parentOf(ancestorOf(p))
|
||||
result = parentOf(p) or
|
||||
result = parentOf(ancestorOf(p))
|
||||
}
|
||||
|
||||
As you can see, you have used the predicate ``ancestorOf()`` inside its own definition. This is an example of `recursion <https://help.semmle.com/QL/ql-handbook/recursion.html>`__.
|
||||
|
@ -120,12 +120,12 @@ Here is one way to define ``relativeOf()``:
|
|||
.. code-block:: ql
|
||||
|
||||
Person relativeOf(Person p) {
|
||||
parentOf*(result) = parentOf*(p)
|
||||
parentOf*(result) = parentOf*(p)
|
||||
}
|
||||
|
||||
Don't forget to use the predicate ``isDeceased()`` to find relatives that are still alive.
|
||||
|
||||
➤ `See the answer in the query console <https://lgtm.com/query/2164460071/>`__
|
||||
➤ `See the answer in the query console <https://lgtm.com/query/6710025057257064639/>`__
|
||||
|
||||
Select the true heir
|
||||
--------------------
|
||||
|
@ -136,9 +136,9 @@ To decide who should inherit the king's fortune, the villagers carefully read th
|
|||
|
||||
*"The heir to the throne is the closest living relative of the king. Any person with a criminal record will not be considered. If there are multiple candidates, the oldest person is the heir."*
|
||||
|
||||
As your final challenge, define a predicate ``criminalRecord`` so that ``criminalRecord(p)`` holds if ``p`` is any of the criminals you unmasked earlier (in the :doc:`Find the thief <find-thief-1>` and :doc:`Catch the fire starter <fire-1>` tutorials).
|
||||
As your final challenge, define a predicate ``hasCriminalRecord`` so that ``hasCriminalRecord(p)`` holds if ``p`` is any of the criminals you unmasked earlier (in the :doc:`Find the thief <find-thief-1>` and :doc:`Catch the fire starter <fire-1>` tutorials).
|
||||
|
||||
➤ `See the answer in the query console <https://lgtm.com/query/1505745996002/>`__
|
||||
➤ `See the answer in the query console <https://lgtm.com/query/1820692755164273290/>`__
|
||||
|
||||
Experimental explorations
|
||||
-------------------------
|
||||
|
|
|
@ -16,9 +16,9 @@ some simple examples.
|
|||
|
||||
Currently the following detective tutorials are available:
|
||||
|
||||
- :doc:`Find the thief <find-thief-1>` - a three part mystery that introduces logical connectives, quantifiers, and aggregates
|
||||
- :doc:`Catch the fire starter <fire-1>` - an intriguing search that introduces predicates and classes
|
||||
- :doc:`Crown the rightful heir <heir>` - a detective puzzle that introduces recursion
|
||||
- :doc:`Find the thief <find-thief-1>`—a three part mystery that introduces logical connectives, quantifiers, and aggregates
|
||||
- :doc:`Catch the fire starter <fire-1>`—an intriguing search that introduces predicates and classes
|
||||
- :doc:`Crown the rightful heir <heir>`—a detective puzzle that introduces recursion
|
||||
|
||||
Further resources
|
||||
-----------------
|
||||
|
|
|
@ -39,6 +39,9 @@ predicate notDeliberatelyBoxed(LocalBoxedVar v) {
|
|||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
int callableGetNumberOfParameters(Callable c) { result = c.getNumberOfParameters() }
|
||||
|
||||
/**
|
||||
* Replacing the type of a boxed variable with the corresponding primitive type may affect
|
||||
* overload resolution. If this is the case then the boxing is most likely intentional and
|
||||
|
@ -52,7 +55,7 @@ predicate affectsOverload(LocalBoxedVar v) {
|
|||
c1.getParameterType(i) instanceof RefType and
|
||||
c2.getParameterType(i) instanceof PrimitiveType and
|
||||
c1.getName() = c2.getName() and
|
||||
c1.getNumberOfParameters() = c2.getNumberOfParameters()
|
||||
callableGetNumberOfParameters(c1) = callableGetNumberOfParameters(c2)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ class Top extends @top {
|
|||
int getNumberOfCommentLines() { numlines(this, _, _, result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
cached
|
||||
string toString() { hasName(this, result) }
|
||||
}
|
||||
|
||||
|
|
|
@ -301,7 +301,7 @@ class RootdefCallable extends Callable {
|
|||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate overrideAccess(Callable c, int i) {
|
||||
exists(Method m | m.overridesOrInstantiates+(c) | exists(m.getParameter(i).getAnAccess()))
|
||||
}
|
||||
|
|
|
@ -61,19 +61,29 @@ class ClientSideGwtCompilationUnit extends GwtCompilationUnit {
|
|||
}
|
||||
}
|
||||
|
||||
/** Auxiliary predicate: `jsni` is a JSNI comment associated with method `m`. */
|
||||
private predicate jsniComment(Javadoc jsni, Method m) {
|
||||
private predicate jsni(Javadoc jsni, File file, int startline) {
|
||||
// The comment must start with `-{` ...
|
||||
jsni.getChild(0).getText().matches("-{%") and
|
||||
// ... and it must end with `}-`.
|
||||
jsni.getChild(jsni.getNumChild() - 1).getText().matches("%}-") and
|
||||
// The associated callable must be marked as `native` ...
|
||||
file = jsni.getFile() and
|
||||
startline = jsni.getLocation().getStartLine()
|
||||
}
|
||||
|
||||
private predicate nativeMethodLines(Method m, File file, int line) {
|
||||
m.isNative() and
|
||||
// ... and the comment has to be contained in `m`.
|
||||
jsni.getFile() = m.getFile() and
|
||||
jsni.getLocation().getStartLine() in [m.getLocation().getStartLine() .. m
|
||||
.getLocation()
|
||||
.getEndLine()]
|
||||
file = m.getFile() and
|
||||
line in [m.getLocation().getStartLine() .. m.getLocation().getEndLine()]
|
||||
}
|
||||
|
||||
/** Auxiliary predicate: `jsni` is a JSNI comment associated with method `m`. */
|
||||
private predicate jsniComment(Javadoc jsni, Method m) {
|
||||
exists(File file, int line |
|
||||
jsni(jsni, file, line) and
|
||||
// The associated callable must be marked as `native`
|
||||
// and the comment has to be contained in `m`.
|
||||
nativeMethodLines(m, file, line)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Provides classes and predicates for working with XML files and their content.
|
||||
*/
|
||||
|
||||
import semmle.code.Location
|
||||
import semmle.files.FileSystem
|
||||
|
||||
/** An XML element that has a location. */
|
||||
abstract class XMLLocatable extends @xmllocatable {
|
||||
|
@ -34,6 +34,12 @@ abstract class XMLLocatable extends @xmllocatable {
|
|||
* both of which can contain other elements.
|
||||
*/
|
||||
class XMLParent extends @xmlparent {
|
||||
XMLParent() {
|
||||
// explicitly restrict `this` to be either an `XMLElement` or an `XMLFile`;
|
||||
// the type `@xmlparent` currently also includes non-XML files
|
||||
this instanceof @xmlelement or xmlEncoding(this, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a printable representation of this XML parent.
|
||||
* (Intended to be overridden in subclasses.)
|
||||
|
@ -82,7 +88,10 @@ class XMLParent extends @xmlparent {
|
|||
)
|
||||
}
|
||||
|
||||
/** Append all the character sequences of this XML parent from left to right, separated by a space. */
|
||||
/**
|
||||
* Gets the result of appending all the character sequences of this XML parent from
|
||||
* left to right, separated by a space.
|
||||
*/
|
||||
string allCharactersString() {
|
||||
result = concat(string chars, int pos |
|
||||
xmlChars(_, chars, this, pos, _, _)
|
||||
|
@ -108,6 +117,20 @@ class XMLFile extends XMLParent, File {
|
|||
/** Gets the name of this XML file. */
|
||||
override string getName() { result = File.super.getAbsolutePath() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of this XML file.
|
||||
*/
|
||||
deprecated string getPath() { result = getAbsolutePath() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of the folder that contains this XML file.
|
||||
*/
|
||||
deprecated string getFolder() { result = getParentContainer().getAbsolutePath() }
|
||||
|
||||
/** Gets the encoding of this XML file. */
|
||||
string getEncoding() { xmlEncoding(this, result) }
|
||||
|
||||
|
@ -121,7 +144,17 @@ class XMLFile extends XMLParent, File {
|
|||
XMLDTD getADTD() { xmlDTDs(result, _, _, _, this) }
|
||||
}
|
||||
|
||||
/** A "Document Type Definition" of an XML file. */
|
||||
/**
|
||||
* An XML document type definition (DTD).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <!ELEMENT person (firstName, lastName?)>
|
||||
* <!ELEMENT firstName (#PCDATA)>
|
||||
* <!ELEMENT lastName (#PCDATA)>
|
||||
* ```
|
||||
*/
|
||||
class XMLDTD extends @xmldtd {
|
||||
/** Gets the name of the root element of this DTD. */
|
||||
string getRoot() { xmlDTDs(this, result, _, _, _) }
|
||||
|
@ -148,7 +181,17 @@ class XMLDTD extends @xmldtd {
|
|||
}
|
||||
}
|
||||
|
||||
/** An XML tag in an XML file. */
|
||||
/**
|
||||
* An XML element in an XML file.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
* package="com.example.exampleapp" android:versionCode="1">
|
||||
* </manifest>
|
||||
* ```
|
||||
*/
|
||||
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
/** Holds if this XML element has the given `name`. */
|
||||
predicate hasName(string name) { name = getName() }
|
||||
|
@ -193,7 +236,16 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
|||
override string toString() { result = XMLParent.super.toString() }
|
||||
}
|
||||
|
||||
/** An attribute that occurs inside an XML element. */
|
||||
/**
|
||||
* An attribute that occurs inside an XML element.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ```
|
||||
* package="com.example.exampleapp"
|
||||
* android:versionCode="1"
|
||||
* ```
|
||||
*/
|
||||
class XMLAttribute extends @xmlattribute, XMLLocatable {
|
||||
/** Gets the name of this attribute. */
|
||||
string getName() { xmlAttrs(this, _, result, _, _, _) }
|
||||
|
@ -214,7 +266,15 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
|
|||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/** A namespace used in an XML file */
|
||||
/**
|
||||
* A namespace used in an XML file.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
* ```
|
||||
*/
|
||||
class XMLNamespace extends @xmlnamespace {
|
||||
/** Gets the prefix of this namespace. */
|
||||
string getPrefix() { xmlNs(this, result, _, _) }
|
||||
|
@ -233,7 +293,15 @@ class XMLNamespace extends @xmlnamespace {
|
|||
}
|
||||
}
|
||||
|
||||
/** A comment of the form `<!-- ... -->` is an XML comment. */
|
||||
/**
|
||||
* A comment in an XML file.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <!-- This is a comment. -->
|
||||
* ```
|
||||
*/
|
||||
class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
/** Gets the text content of this XML comment. */
|
||||
string getText() { xmlComments(this, result, _, _) }
|
||||
|
@ -248,6 +316,12 @@ class XMLComment extends @xmlcomment, XMLLocatable {
|
|||
/**
|
||||
* A sequence of characters that occurs between opening and
|
||||
* closing tags of an XML element, excluding other elements.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <content>This is a sequence of characters.</content>
|
||||
* ```
|
||||
*/
|
||||
class XMLCharacters extends @xmlcharacters, XMLLocatable {
|
||||
/** Gets the content of this character sequence. */
|
||||
|
|
|
@ -240,6 +240,9 @@ public class ESNextParser extends JSXParser {
|
|||
if (this.type == TokenType._import) {
|
||||
Position startLoc = this.startLoc;
|
||||
this.next();
|
||||
if (this.eat(TokenType.dot)) {
|
||||
return parseImportMeta(startLoc);
|
||||
}
|
||||
this.expect(TokenType.parenL);
|
||||
return parseDynamicImport(startLoc);
|
||||
}
|
||||
|
@ -413,6 +416,19 @@ public class ESNextParser extends JSXParser {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an import.meta expression, assuming that the initial "import" and "." has been consumed.
|
||||
*/
|
||||
private MetaProperty parseImportMeta(Position loc) {
|
||||
Position propertyLoc = this.startLoc;
|
||||
Identifier property = this.parseIdent(true);
|
||||
if (!property.getName().equals("meta")) {
|
||||
this.unexpected(propertyLoc);
|
||||
}
|
||||
return this.finishNode(
|
||||
new MetaProperty(new SourceLocation(loc), new Identifier(new SourceLocation(loc), "import"), property));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a dynamic import, assuming that the keyword `import` and the opening parenthesis have
|
||||
* already been consumed.
|
||||
|
|
|
@ -3,8 +3,8 @@ package com.semmle.js.ast;
|
|||
/**
|
||||
* A meta property access (cf. ECMAScript 2015 Language Specification, Chapter 12.3.8).
|
||||
*
|
||||
* <p>Currently the only recognised meta properties are <code>new.target</code> and <code>
|
||||
* function.sent</code>.
|
||||
* <p>Currently the only recognised meta properties are <code>new.target</code>,
|
||||
* <code>import.meta</code> and <code> function.sent</code>.
|
||||
*/
|
||||
public class MetaProperty extends Expression {
|
||||
private final Identifier meta, property;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Provides classes and predicates for working with XML files and their content.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import semmle.files.FileSystem
|
||||
|
||||
/** An XML element that has a location. */
|
||||
abstract class XMLLocatable extends @xmllocatable {
|
||||
|
@ -88,7 +88,10 @@ class XMLParent extends @xmlparent {
|
|||
)
|
||||
}
|
||||
|
||||
/** Append all the character sequences of this XML parent from left to right, separated by a space. */
|
||||
/**
|
||||
* Gets the result of appending all the character sequences of this XML parent from
|
||||
* left to right, separated by a space.
|
||||
*/
|
||||
string allCharactersString() {
|
||||
result = concat(string chars, int pos |
|
||||
xmlChars(_, chars, this, pos, _, _)
|
||||
|
@ -114,6 +117,20 @@ class XMLFile extends XMLParent, File {
|
|||
/** Gets the name of this XML file. */
|
||||
override string getName() { result = File.super.getAbsolutePath() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of this XML file.
|
||||
*/
|
||||
deprecated string getPath() { result = getAbsolutePath() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of the folder that contains this XML file.
|
||||
*/
|
||||
deprecated string getFolder() { result = getParentContainer().getAbsolutePath() }
|
||||
|
||||
/** Gets the encoding of this XML file. */
|
||||
string getEncoding() { xmlEncoding(this, result) }
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import semmle.javascript.ES2015Modules
|
||||
|
||||
query predicate test_ImportMetaExpr(ImportMetaExpr meta) {
|
||||
any()
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
var foo = new URL('../cli.svg', import.meta.url).pathname;
|
|
@ -26,6 +26,8 @@ test_getExportedName
|
|||
| m/c.js:5:10:5:15 | g as h | g |
|
||||
test_OtherImports
|
||||
| es2015_require.js:1:11:1:24 | require('./d') | d.js:1:1:5:0 | <toplevel> |
|
||||
test_ImportMetaExpr
|
||||
| importmeta.js:1:33:1:43 | import.meta |
|
||||
test_ReExportDeclarations
|
||||
| b.js:7:1:7:21 | export ... './a'; | b.js:7:16:7:20 | './a' |
|
||||
| d.js:4:1:4:20 | export * from 'm/c'; | d.js:4:15:4:19 | 'm/c' |
|
||||
|
@ -102,6 +104,7 @@ test_NamedImportSpecifier
|
|||
test_GlobalVariableRef
|
||||
| a.js:5:31:5:31 | o |
|
||||
| exports.js:3:9:3:15 | exports |
|
||||
| importmeta.js:1:15:1:17 | URL |
|
||||
| tst.html:6:3:6:7 | alert |
|
||||
test_BulkReExportDeclarations
|
||||
| d.js:4:1:4:20 | export * from 'm/c'; |
|
||||
|
|
|
@ -2,6 +2,7 @@ import ImportSpecifiers
|
|||
import getLocalName
|
||||
import getExportedName
|
||||
import OtherImports
|
||||
import ImportMeta
|
||||
import ReExportDeclarations
|
||||
import ImportDefaultSpecifiers
|
||||
import getImportedName
|
||||
|
|
|
@ -211,7 +211,7 @@ module Value {
|
|||
}
|
||||
|
||||
/** Gets the `Value` for the integer constant `i`, if it exists.
|
||||
* There will be no `Value` for most integers, but the following are
|
||||
* There will be no `Value` for most integers, but the following are
|
||||
* guaranteed to exist:
|
||||
* * From zero to 511 inclusive.
|
||||
* * All powers of 2 (up to 2**30)
|
||||
|
@ -486,6 +486,11 @@ class PythonFunctionValue extends FunctionValue {
|
|||
)
|
||||
}
|
||||
|
||||
/** Gets a control flow node corresponding to a return statement in this function */
|
||||
ControlFlowNode getAReturnedNode() {
|
||||
result = this.getScope().getAReturnValueFlowNode()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Class representing builtin functions, such as `len` or `print` */
|
||||
|
|
|
@ -9,8 +9,8 @@ import semmle.python.web.flask.General
|
|||
*/
|
||||
class FlaskRoutedResponse extends HttpResponseTaintSink {
|
||||
FlaskRoutedResponse() {
|
||||
exists(PyFunctionObject response |
|
||||
flask_routing(_, response.getFunction()) and
|
||||
exists(PythonFunctionValue response |
|
||||
flask_routing(_, response.getScope()) and
|
||||
this = response.getAReturnedNode()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ private import semmle.python.web.Http
|
|||
*/
|
||||
class PyramidRoutedResponse extends HttpResponseTaintSink {
|
||||
PyramidRoutedResponse() {
|
||||
exists(PyFunctionObject view |
|
||||
is_pyramid_view_function(view.getFunction()) and
|
||||
exists(PythonFunctionValue view |
|
||||
is_pyramid_view_function(view.getScope()) and
|
||||
this = view.getAReturnedNode()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,53 +1,35 @@
|
|||
import python
|
||||
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import Twisted
|
||||
|
||||
/** A twisted.web.http.Request object */
|
||||
class TwistedRequest extends TaintKind {
|
||||
|
||||
TwistedRequest() {
|
||||
this = "twisted.request.http.Request"
|
||||
}
|
||||
TwistedRequest() { this = "twisted.request.http.Request" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
result instanceof ExternalStringSequenceDictKind and
|
||||
(
|
||||
name = "args"
|
||||
)
|
||||
name = "args"
|
||||
or
|
||||
result instanceof ExternalStringKind and
|
||||
(
|
||||
name = "uri"
|
||||
)
|
||||
name = "uri"
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
(
|
||||
name = "getHeader" or
|
||||
name = "getCookie" or
|
||||
name = "getUser" or
|
||||
name = "getPassword"
|
||||
) and
|
||||
result instanceof ExternalStringKind
|
||||
(
|
||||
name = "getHeader" or
|
||||
name = "getCookie" or
|
||||
name = "getUser" or
|
||||
name = "getPassword"
|
||||
) and
|
||||
result instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class TwistedRequestSource extends TaintSource {
|
||||
TwistedRequestSource() { isTwistedRequestInstance(this) }
|
||||
|
||||
TwistedRequestSource() {
|
||||
isTwistedRequestInstance(this)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Twisted request source"
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind instanceof TwistedRequest
|
||||
}
|
||||
override string toString() { result = "Twisted request source" }
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof TwistedRequest }
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import python
|
||||
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.security.strings.Basic
|
||||
|
@ -8,7 +7,7 @@ import Request
|
|||
|
||||
class TwistedResponse extends TaintSink {
|
||||
TwistedResponse() {
|
||||
exists(PyFunctionObject func, string name |
|
||||
exists(PythonFunctionValue func, string name, Return ret |
|
||||
isKnownRequestHandlerMethodName(name) and
|
||||
name = func.getName() and
|
||||
func = getTwistedRequestHandlerMethod(name) and
|
||||
|
@ -16,13 +15,9 @@ class TwistedResponse extends TaintSink {
|
|||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() {
|
||||
result = "Twisted response"
|
||||
}
|
||||
override string toString() { result = "Twisted response" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,7 +25,7 @@ class TwistedResponse extends TaintSink {
|
|||
* object, which affects the properties of the subsequent response sent to this
|
||||
* request.
|
||||
*/
|
||||
class TwistedRequestSetter extends HttpResponseTaintSink {
|
||||
class TwistedRequestSetter extends HttpResponseTaintSink {
|
||||
TwistedRequestSetter() {
|
||||
exists(CallNode call, ControlFlowNode node, string name |
|
||||
(
|
||||
|
@ -44,11 +39,7 @@ class TwistedResponse extends TaintSink {
|
|||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) {
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() {
|
||||
result = "Twisted request setter"
|
||||
}
|
||||
}
|
||||
override string toString() { result = "Twisted request setter" }
|
||||
}
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
import python
|
||||
|
||||
import semmle.python.security.TaintTracking
|
||||
|
||||
private ClassObject theTwistedHttpRequestClass() {
|
||||
result = ModuleObject::named("twisted.web.http").attr("Request")
|
||||
private ClassValue theTwistedHttpRequestClass() {
|
||||
result = Value::named("twisted.web.http.Request")
|
||||
}
|
||||
|
||||
private ClassObject theTwistedHttpResourceClass() {
|
||||
result = ModuleObject::named("twisted.web.resource").attr("Resource")
|
||||
private ClassValue theTwistedHttpResourceClass() {
|
||||
result = Value::named("twisted.web.resource.Resource")
|
||||
}
|
||||
|
||||
ClassObject aTwistedRequestHandlerClass() {
|
||||
result.getASuperType() = theTwistedHttpResourceClass()
|
||||
}
|
||||
ClassValue aTwistedRequestHandlerClass() { result.getABaseType+() = theTwistedHttpResourceClass() }
|
||||
|
||||
FunctionObject getTwistedRequestHandlerMethod(string name) {
|
||||
FunctionValue getTwistedRequestHandlerMethod(string name) {
|
||||
result = aTwistedRequestHandlerClass().declaredAttribute(name)
|
||||
}
|
||||
|
||||
|
@ -24,29 +21,30 @@ predicate isKnownRequestHandlerMethodName(string name) {
|
|||
name.matches("render_%")
|
||||
}
|
||||
|
||||
/** Holds if `node` is likely to refer to an instance of the twisted
|
||||
/**
|
||||
* Holds if `node` is likely to refer to an instance of the twisted
|
||||
* `Request` class.
|
||||
*/
|
||||
predicate isTwistedRequestInstance(NameNode node) {
|
||||
node.refersTo(_, theTwistedHttpRequestClass(), _)
|
||||
node.pointsTo().getClass() = theTwistedHttpRequestClass()
|
||||
or
|
||||
/* In points-to analysis cannot infer that a given object is an instance of
|
||||
/*
|
||||
* In points-to analysis cannot infer that a given object is an instance of
|
||||
* the `twisted.web.http.Request` class, we also include any parameter
|
||||
* called `request` that appears inside a subclass of a request handler
|
||||
* class, and the appropriate arguments of known request handler methods.
|
||||
*/
|
||||
exists(Function func | func = node.getScope() |
|
||||
func.getEnclosingScope().(Class).getClassObject() = aTwistedRequestHandlerClass()
|
||||
) and
|
||||
(
|
||||
/* Any parameter called `request` */
|
||||
node.getId() = "request" and
|
||||
node.isParameter()
|
||||
or
|
||||
/* Any request parameter of a known request handler method */
|
||||
exists(FunctionObject func | node.getScope() = func.getFunction() |
|
||||
|
||||
exists(Function func |
|
||||
func = node.getScope() and
|
||||
func.getEnclosingScope() = aTwistedRequestHandlerClass().getScope()
|
||||
|
|
||||
/* Any parameter called `request` */
|
||||
node.getId() = "request" and
|
||||
node.isParameter()
|
||||
or
|
||||
/* Any request parameter of a known request handler method */
|
||||
isKnownRequestHandlerMethodName(func.getName()) and
|
||||
node.getNode() = func.getFunction().getArg(1)
|
||||
)
|
||||
node.getNode() = func.getArg(1)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,26 +1,31 @@
|
|||
/**
|
||||
* A library for working with XML files and their content.
|
||||
* Provides classes and predicates for working with XML files and their content.
|
||||
*/
|
||||
|
||||
import semmle.python.Files
|
||||
import semmle.files.FileSystem
|
||||
|
||||
/** An XML element that has a location. */
|
||||
abstract class XMLLocatable extends @xmllocatable {
|
||||
/** The source location for this element. */
|
||||
Location getLocation() { xmllocations(this,result) }
|
||||
/** Gets the source location for this element. */
|
||||
Location getLocation() { xmllocations(this, result) }
|
||||
|
||||
/**
|
||||
* Whether this element has the specified location information,
|
||||
* including file path, start line, start column, end line and end column.
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
*/
|
||||
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
exists(File f, Location l | l = this.getLocation() |
|
||||
locations_default(l,f,startline,startcolumn,endline,endcolumn) and
|
||||
filepath = f.getName()
|
||||
locations_default(l, f, startline, startcolumn, endline, endcolumn) and
|
||||
filepath = f.getAbsolutePath()
|
||||
)
|
||||
}
|
||||
|
||||
/** A printable representation of this element. */
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
|
@ -29,254 +34,305 @@ abstract class XMLLocatable extends @xmllocatable {
|
|||
* both of which can contain other elements.
|
||||
*/
|
||||
class XMLParent extends @xmlparent {
|
||||
XMLParent() {
|
||||
// explicitly restrict `this` to be either an `XMLElement` or an `XMLFile`;
|
||||
// the type `@xmlparent` currently also includes non-XML files
|
||||
this instanceof @xmlelement or xmlEncoding(this, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* A printable representation of this XML parent.
|
||||
* Gets a printable representation of this XML parent.
|
||||
* (Intended to be overridden in subclasses.)
|
||||
*/
|
||||
/*abstract*/ string getName() { result = "parent" }
|
||||
abstract string getName();
|
||||
|
||||
/** The file to which this XML parent belongs. */
|
||||
XMLFile getFile() { result = this or xmlElements(this,_,_,_,result) }
|
||||
/** Gets the file to which this XML parent belongs. */
|
||||
XMLFile getFile() { result = this or xmlElements(this, _, _, _, result) }
|
||||
|
||||
/** The child element at a specified index of this XML parent. */
|
||||
/** Gets the child element at a specified index of this XML parent. */
|
||||
XMLElement getChild(int index) { xmlElements(result, _, this, index, _) }
|
||||
|
||||
/** A child element of this XML parent. */
|
||||
XMLElement getAChild() { xmlElements(result,_,this,_,_) }
|
||||
/** Gets a child element of this XML parent. */
|
||||
XMLElement getAChild() { xmlElements(result, _, this, _, _) }
|
||||
|
||||
/** A child element of this XML parent with the given `name`. */
|
||||
XMLElement getAChild(string name) { xmlElements(result,_,this,_,_) and result.hasName(name) }
|
||||
/** Gets a child element of this XML parent with the given `name`. */
|
||||
XMLElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) }
|
||||
|
||||
/** A comment that is a child of this XML parent. */
|
||||
XMLComment getAComment() { xmlComments(result,_,this,_) }
|
||||
/** Gets a comment that is a child of this XML parent. */
|
||||
XMLComment getAComment() { xmlComments(result, _, this, _) }
|
||||
|
||||
/** A character sequence that is a child of this XML parent. */
|
||||
XMLCharacters getACharactersSet() { xmlChars(result,_,this,_,_,_) }
|
||||
/** Gets a character sequence that is a child of this XML parent. */
|
||||
XMLCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) }
|
||||
|
||||
/** The depth in the tree. (Overridden in XMLElement.) */
|
||||
/** Gets the depth in the tree. (Overridden in XMLElement.) */
|
||||
int getDepth() { result = 0 }
|
||||
|
||||
/** The number of child XML elements of this XML parent. */
|
||||
int getNumberOfChildren() {
|
||||
result = count(XMLElement e | xmlElements(e,_,this,_,_))
|
||||
}
|
||||
/** Gets the number of child XML elements of this XML parent. */
|
||||
int getNumberOfChildren() { result = count(XMLElement e | xmlElements(e, _, this, _, _)) }
|
||||
|
||||
/** The number of places in the body of this XML parent where text occurs. */
|
||||
int getNumberOfCharacterSets() {
|
||||
result = count(int pos | xmlChars(_,_,this,pos,_,_))
|
||||
}
|
||||
/** Gets the number of places in the body of this XML parent where text occurs. */
|
||||
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Internal.
|
||||
*
|
||||
* Append the character sequences of this XML parent from left to right, separated by a space,
|
||||
* up to a specified (zero-based) index.
|
||||
*/
|
||||
string charsSetUpTo(int n) {
|
||||
(n = 0 and xmlChars(_,result,this,0,_,_)) or
|
||||
(n > 0 and exists(string chars | xmlChars(_,chars,this,n,_,_) |
|
||||
result = this.charsSetUpTo(n-1) + " " + chars))
|
||||
}
|
||||
|
||||
/** Append all the character sequences of this XML parent from left to right, separated by a space. */
|
||||
string allCharactersString() {
|
||||
exists(int n | n = this.getNumberOfCharacterSets() |
|
||||
(n = 0 and result = "") or
|
||||
(n > 0 and result = this.charsSetUpTo(n-1))
|
||||
deprecated string charsSetUpTo(int n) {
|
||||
n = 0 and xmlChars(_, result, this, 0, _, _)
|
||||
or
|
||||
n > 0 and
|
||||
exists(string chars | xmlChars(_, chars, this, n, _, _) |
|
||||
result = this.charsSetUpTo(n - 1) + " " + chars
|
||||
)
|
||||
}
|
||||
|
||||
/** The text value contained in this XML parent. */
|
||||
string getTextValue() {
|
||||
result = allCharactersString()
|
||||
/**
|
||||
* Gets the result of appending all the character sequences of this XML parent from
|
||||
* left to right, separated by a space.
|
||||
*/
|
||||
string allCharactersString() {
|
||||
result = concat(string chars, int pos |
|
||||
xmlChars(_, chars, this, pos, _, _)
|
||||
|
|
||||
chars, " " order by pos
|
||||
)
|
||||
}
|
||||
|
||||
/** A printable representation of this XML parent. */
|
||||
/** Gets the text value contained in this XML parent. */
|
||||
string getTextValue() { result = allCharactersString() }
|
||||
|
||||
/** Gets a printable representation of this XML parent. */
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** An XML file. */
|
||||
class XMLFile extends XMLParent, File {
|
||||
XMLFile() {
|
||||
xmlEncoding(this,_)
|
||||
}
|
||||
XMLFile() { xmlEncoding(this, _) }
|
||||
|
||||
/** A printable representation of this XML file. */
|
||||
override
|
||||
string toString() { result = XMLParent.super.toString() }
|
||||
/** Gets a printable representation of this XML file. */
|
||||
override string toString() { result = XMLParent.super.toString() }
|
||||
|
||||
/** The name of this XML file. */
|
||||
override
|
||||
string getName() { files(this,result,_,_,_) }
|
||||
/** Gets the name of this XML file. */
|
||||
override string getName() { result = File.super.getAbsolutePath() }
|
||||
|
||||
/** The path of this XML file. */
|
||||
string getPath() { files(this,_,result,_,_) }
|
||||
/**
|
||||
* DEPRECATED: Use `getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of this XML file.
|
||||
*/
|
||||
deprecated string getPath() { result = getAbsolutePath() }
|
||||
|
||||
/** The path of the folder that contains this XML file. */
|
||||
string getFolder() {
|
||||
result = this.getPath().substring(0, this.getPath().length()-this.getName().length())
|
||||
}
|
||||
/**
|
||||
* DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of the folder that contains this XML file.
|
||||
*/
|
||||
deprecated string getFolder() { result = getParentContainer().getAbsolutePath() }
|
||||
|
||||
/** The encoding of this XML file. */
|
||||
string getEncoding() { xmlEncoding(this,result) }
|
||||
/** Gets the encoding of this XML file. */
|
||||
string getEncoding() { xmlEncoding(this, result) }
|
||||
|
||||
/** The XML file itself. */
|
||||
override
|
||||
XMLFile getFile() { result = this }
|
||||
/** Gets the XML file itself. */
|
||||
override XMLFile getFile() { result = this }
|
||||
|
||||
/** A top-most element in an XML file. */
|
||||
/** Gets a top-most element in an XML file. */
|
||||
XMLElement getARootElement() { result = this.getAChild() }
|
||||
|
||||
/** A DTD associated with this XML file. */
|
||||
XMLDTD getADTD() { xmlDTDs(result,_,_,_,this) }
|
||||
/** Gets a DTD associated with this XML file. */
|
||||
XMLDTD getADTD() { xmlDTDs(result, _, _, _, this) }
|
||||
}
|
||||
|
||||
/** A "Document Type Definition" of an XML file. */
|
||||
/**
|
||||
* An XML document type definition (DTD).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <!ELEMENT person (firstName, lastName?)>
|
||||
* <!ELEMENT firstName (#PCDATA)>
|
||||
* <!ELEMENT lastName (#PCDATA)>
|
||||
* ```
|
||||
*/
|
||||
class XMLDTD extends @xmldtd {
|
||||
/** The name of the root element of this DTD. */
|
||||
string getRoot() { xmlDTDs(this,result,_,_,_) }
|
||||
/** Gets the name of the root element of this DTD. */
|
||||
string getRoot() { xmlDTDs(this, result, _, _, _) }
|
||||
|
||||
/** The public ID of this DTD. */
|
||||
string getPublicId() { xmlDTDs(this,_,result,_,_) }
|
||||
/** Gets the public ID of this DTD. */
|
||||
string getPublicId() { xmlDTDs(this, _, result, _, _) }
|
||||
|
||||
/** The system ID of this DTD. */
|
||||
string getSystemId() { xmlDTDs(this,_,_,result,_) }
|
||||
/** Gets the system ID of this DTD. */
|
||||
string getSystemId() { xmlDTDs(this, _, _, result, _) }
|
||||
|
||||
/** Whether this DTD is public. */
|
||||
predicate isPublic() { not xmlDTDs(this,_,"",_,_) }
|
||||
/** Holds if this DTD is public. */
|
||||
predicate isPublic() { not xmlDTDs(this, _, "", _, _) }
|
||||
|
||||
/** The parent of this DTD. */
|
||||
XMLParent getParent() { xmlDTDs(this,_,_,_,result) }
|
||||
/** Gets the parent of this DTD. */
|
||||
XMLParent getParent() { xmlDTDs(this, _, _, _, result) }
|
||||
|
||||
/** A printable representation of this DTD. */
|
||||
/** Gets a printable representation of this DTD. */
|
||||
string toString() {
|
||||
(this.isPublic() and result = this.getRoot() + " PUBLIC '" +
|
||||
this.getPublicId() + "' '" +
|
||||
this.getSystemId() + "'") or
|
||||
(not this.isPublic() and result = this.getRoot() +
|
||||
" SYSTEM '" +
|
||||
this.getSystemId() + "'")
|
||||
this.isPublic() and
|
||||
result = this.getRoot() + " PUBLIC '" + this.getPublicId() + "' '" + this.getSystemId() + "'"
|
||||
or
|
||||
not this.isPublic() and
|
||||
result = this.getRoot() + " SYSTEM '" + this.getSystemId() + "'"
|
||||
}
|
||||
}
|
||||
|
||||
/** An XML tag in an XML file. */
|
||||
/**
|
||||
* An XML element in an XML file.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
* package="com.example.exampleapp" android:versionCode="1">
|
||||
* </manifest>
|
||||
* ```
|
||||
*/
|
||||
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
/** Whether this XML element has the given `name`. */
|
||||
/** Holds if this XML element has the given `name`. */
|
||||
predicate hasName(string name) { name = getName() }
|
||||
|
||||
/** The name of this XML element. */
|
||||
override
|
||||
string getName() { xmlElements(this,result,_,_,_) }
|
||||
/** Gets the name of this XML element. */
|
||||
override string getName() { xmlElements(this, result, _, _, _) }
|
||||
|
||||
/** The XML file in which this XML element occurs. */
|
||||
override
|
||||
XMLFile getFile() { xmlElements(this,_,_,_,result) }
|
||||
/** Gets the XML file in which this XML element occurs. */
|
||||
override XMLFile getFile() { xmlElements(this, _, _, _, result) }
|
||||
|
||||
/** The parent of this XML element. */
|
||||
XMLParent getParent() { xmlElements(this,_,result,_,_) }
|
||||
/** Gets the parent of this XML element. */
|
||||
XMLParent getParent() { xmlElements(this, _, result, _, _) }
|
||||
|
||||
/** The index of this XML element among its parent's children. */
|
||||
/** Gets the index of this XML element among its parent's children. */
|
||||
int getIndex() { xmlElements(this, _, _, result, _) }
|
||||
|
||||
/** Whether this XML element has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this,_,_) }
|
||||
/** Holds if this XML element has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this, _, _) }
|
||||
|
||||
/** The namespace of this XML element, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
|
||||
/** Gets the namespace of this XML element, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
|
||||
|
||||
/** The index of this XML element among its parent's children. */
|
||||
int getElementPositionIndex() { xmlElements(this,_,_,result,_) }
|
||||
/** Gets the index of this XML element among its parent's children. */
|
||||
int getElementPositionIndex() { xmlElements(this, _, _, result, _) }
|
||||
|
||||
/** The depth of this element within the XML file tree structure. */
|
||||
override
|
||||
int getDepth() { result = this.getParent().getDepth() + 1 }
|
||||
/** Gets the depth of this element within the XML file tree structure. */
|
||||
override int getDepth() { result = this.getParent().getDepth() + 1 }
|
||||
|
||||
/** An XML attribute of this XML element. */
|
||||
/** Gets an XML attribute of this XML element. */
|
||||
XMLAttribute getAnAttribute() { result.getElement() = this }
|
||||
|
||||
/** The attribute with the specified `name`, if any. */
|
||||
XMLAttribute getAttribute(string name) {
|
||||
result.getElement() = this and result.getName() = name
|
||||
}
|
||||
/** Gets the attribute with the specified `name`, if any. */
|
||||
XMLAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
|
||||
|
||||
/** Whether this XML element has an attribute with the specified `name`. */
|
||||
predicate hasAttribute(string name) {
|
||||
exists(XMLAttribute a| a = this.getAttribute(name))
|
||||
}
|
||||
/** Holds if this XML element has an attribute with the specified `name`. */
|
||||
predicate hasAttribute(string name) { exists(XMLAttribute a | a = this.getAttribute(name)) }
|
||||
|
||||
/** The value of the attribute with the specified `name`, if any. */
|
||||
string getAttributeValue(string name) {
|
||||
result = this.getAttribute(name).getValue()
|
||||
}
|
||||
/** Gets the value of the attribute with the specified `name`, if any. */
|
||||
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
|
||||
|
||||
/** A printable representation of this XML element. */
|
||||
override
|
||||
string toString() { result = XMLParent.super.toString() }
|
||||
/** Gets a printable representation of this XML element. */
|
||||
override string toString() { result = XMLParent.super.toString() }
|
||||
}
|
||||
|
||||
/** An attribute that occurs inside an XML element. */
|
||||
/**
|
||||
* An attribute that occurs inside an XML element.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ```
|
||||
* package="com.example.exampleapp"
|
||||
* android:versionCode="1"
|
||||
* ```
|
||||
*/
|
||||
class XMLAttribute extends @xmlattribute, XMLLocatable {
|
||||
/** The name of this attribute. */
|
||||
string getName() { xmlAttrs(this,_,result,_,_,_) }
|
||||
/** Gets the name of this attribute. */
|
||||
string getName() { xmlAttrs(this, _, result, _, _, _) }
|
||||
|
||||
/** The XML element to which this attribute belongs. */
|
||||
XMLElement getElement() { xmlAttrs(this,result,_,_,_,_) }
|
||||
/** Gets the XML element to which this attribute belongs. */
|
||||
XMLElement getElement() { xmlAttrs(this, result, _, _, _, _) }
|
||||
|
||||
/** Whether this attribute has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this,_,_) }
|
||||
/** Holds if this attribute has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this, _, _) }
|
||||
|
||||
/** The namespace of this attribute, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
|
||||
/** Gets the namespace of this attribute, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
|
||||
|
||||
/** The value of this attribute. */
|
||||
string getValue() { xmlAttrs(this,_,_,result,_,_) }
|
||||
/** Gets the value of this attribute. */
|
||||
string getValue() { xmlAttrs(this, _, _, result, _, _) }
|
||||
|
||||
/** A printable representation of this XML attribute. */
|
||||
/** Gets a printable representation of this XML attribute. */
|
||||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/** A namespace used in an XML file */
|
||||
/**
|
||||
* A namespace used in an XML file.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
* ```
|
||||
*/
|
||||
class XMLNamespace extends @xmlnamespace {
|
||||
/** The prefix of this namespace. */
|
||||
string getPrefix() { xmlNs(this,result,_,_) }
|
||||
/** Gets the prefix of this namespace. */
|
||||
string getPrefix() { xmlNs(this, result, _, _) }
|
||||
|
||||
/** The URI of this namespace. */
|
||||
string getURI() { xmlNs(this,_,result,_) }
|
||||
/** Gets the URI of this namespace. */
|
||||
string getURI() { xmlNs(this, _, result, _) }
|
||||
|
||||
/** Whether this namespace has no prefix. */
|
||||
/** Holds if this namespace has no prefix. */
|
||||
predicate isDefault() { this.getPrefix() = "" }
|
||||
|
||||
/** A printable representation of this XML namespace. */
|
||||
/** Gets a printable representation of this XML namespace. */
|
||||
string toString() {
|
||||
(this.isDefault() and result = this.getURI()) or
|
||||
(not this.isDefault() and result = this.getPrefix() + ":" + this.getURI())
|
||||
this.isDefault() and result = this.getURI()
|
||||
or
|
||||
not this.isDefault() and result = this.getPrefix() + ":" + this.getURI()
|
||||
}
|
||||
}
|
||||
|
||||
/** A comment of the form `<!-- ... -->` is an XML comment. */
|
||||
/**
|
||||
* A comment in an XML file.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <!-- This is a comment. -->
|
||||
* ```
|
||||
*/
|
||||
class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
/** The text content of this XML comment. */
|
||||
string getText() { xmlComments(this,result,_,_) }
|
||||
/** Gets the text content of this XML comment. */
|
||||
string getText() { xmlComments(this, result, _, _) }
|
||||
|
||||
/** The parent of this XML comment. */
|
||||
XMLParent getParent() { xmlComments(this,_,result,_) }
|
||||
/** Gets the parent of this XML comment. */
|
||||
XMLParent getParent() { xmlComments(this, _, result, _) }
|
||||
|
||||
/** A printable representation of this XML comment. */
|
||||
/** Gets a printable representation of this XML comment. */
|
||||
override string toString() { result = this.getText() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence of characters that occurs between opening and
|
||||
* closing tags of an XML element, excluding other elements.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <content>This is a sequence of characters.</content>
|
||||
* ```
|
||||
*/
|
||||
class XMLCharacters extends @xmlcharacters, XMLLocatable {
|
||||
/** The content of this character sequence. */
|
||||
string getCharacters() { xmlChars(this,result,_,_,_,_) }
|
||||
/** Gets the content of this character sequence. */
|
||||
string getCharacters() { xmlChars(this, result, _, _, _, _) }
|
||||
|
||||
/** The parent of this character sequence. */
|
||||
XMLParent getParent() { xmlChars(this,_,result,_,_,_) }
|
||||
/** Gets the parent of this character sequence. */
|
||||
XMLParent getParent() { xmlChars(this, _, result, _, _, _) }
|
||||
|
||||
/** Whether this character sequence is CDATA. */
|
||||
predicate isCDATA() { xmlChars(this,_,_,_,1,_) }
|
||||
/** Holds if this character sequence is CDATA. */
|
||||
predicate isCDATA() { xmlChars(this, _, _, _, 1, _) }
|
||||
|
||||
/** A printable representation of this XML character sequence. */
|
||||
/** Gets a printable representation of this XML character sequence. */
|
||||
override string toString() { result = this.getCharacters() }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
| class MyRequestHandler1 | test.py:3 |
|
||||
| class MyRequestHandler2 | test.py:23 |
|
||||
| class MyRequestHandler3 | test.py:27 |
|
||||
| class MyRequestHandler4 | test.py:38 |
|
||||
| class MyRequestHandler5 | test.py:42 |
|
|
@ -0,0 +1,7 @@
|
|||
import python
|
||||
import semmle.python.TestUtils
|
||||
import semmle.python.web.twisted.Twisted
|
||||
|
||||
from ClassValue cls
|
||||
where cls = aTwistedRequestHandlerClass()
|
||||
select cls.toString(), remove_library_prefix(cls.getScope().getLocation())
|
|
@ -0,0 +1,8 @@
|
|||
| myrender | Function MyRequestHandler2.myrender | test.py:24 |
|
||||
| render | Function MyRequestHandler1.render | test.py:4 |
|
||||
| render | Function MyRequestHandler3.render | test.py:28 |
|
||||
| render | Function MyRequestHandler4.render | test.py:39 |
|
||||
| render | Function MyRequestHandler5.render | test.py:43 |
|
||||
| render_GET | Function MyRequestHandler1.render_GET | test.py:9 |
|
||||
| render_POST | Function MyRequestHandler1.render_POST | test.py:16 |
|
||||
| render_POST | Function MyRequestHandler3.render_POST | test.py:31 |
|
|
@ -0,0 +1,7 @@
|
|||
import python
|
||||
import semmle.python.TestUtils
|
||||
import semmle.python.web.twisted.Twisted
|
||||
|
||||
from FunctionValue func, string name
|
||||
where func = getTwistedRequestHandlerMethod(name)
|
||||
select name, func.toString(), remove_library_prefix(func.getScope().getLocation())
|
|
@ -0,0 +1,8 @@
|
|||
| test.py:7 | response | externally controlled string |
|
||||
| test.py:14 | response | externally controlled string |
|
||||
| test.py:21 | response | externally controlled string |
|
||||
| test.py:36 | do_stuff_with() | externally controlled string |
|
||||
| test.py:40 | Str | externally controlled string |
|
||||
| test.py:44 | Str | externally controlled string |
|
||||
| test.py:45 | Str | externally controlled string |
|
||||
| test.py:46 | Str | externally controlled string |
|
|
@ -0,0 +1,10 @@
|
|||
import python
|
||||
|
||||
import semmle.python.web.HttpRequest
|
||||
import semmle.python.web.HttpResponse
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.TestUtils
|
||||
|
||||
from TaintSink sink, TaintKind kind
|
||||
where sink.sinks(kind)
|
||||
select remove_library_prefix(sink.getLocation()), sink.(ControlFlowNode).getNode().toString(), kind
|
|
@ -0,0 +1,8 @@
|
|||
| test.py:4 | request | twisted.request.http.Request |
|
||||
| test.py:9 | request | twisted.request.http.Request |
|
||||
| test.py:16 | request | twisted.request.http.Request |
|
||||
| test.py:24 | request | twisted.request.http.Request |
|
||||
| test.py:28 | myrequest | twisted.request.http.Request |
|
||||
| test.py:31 | postrequest | twisted.request.http.Request |
|
||||
| test.py:39 | request | twisted.request.http.Request |
|
||||
| test.py:43 | request | twisted.request.http.Request |
|
|
@ -0,0 +1,11 @@
|
|||
import python
|
||||
import semmle.python.TestUtils
|
||||
|
||||
import semmle.python.web.HttpRequest
|
||||
import semmle.python.web.HttpResponse
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
|
||||
from TaintSource src, TaintKind kind
|
||||
where src.isSourceOf(kind)
|
||||
select remove_library_prefix(src.getLocation()), src.(ControlFlowNode).getNode().toString(), kind
|
|
@ -0,0 +1,41 @@
|
|||
| test.py:4 | request | twisted.request.http.Request |
|
||||
| test.py:5 | Attribute | externally controlled string |
|
||||
| test.py:5 | request | twisted.request.http.Request |
|
||||
| test.py:6 | request | twisted.request.http.Request |
|
||||
| test.py:9 | request | twisted.request.http.Request |
|
||||
| test.py:10 | request | twisted.request.http.Request |
|
||||
| test.py:11 | Attribute | externally controlled string |
|
||||
| test.py:11 | x | twisted.request.http.Request |
|
||||
| test.py:12 | request | twisted.request.http.Request |
|
||||
| test.py:13 | request | twisted.request.http.Request |
|
||||
| test.py:16 | request | twisted.request.http.Request |
|
||||
| test.py:17 | Attribute | {[externally controlled string]} |
|
||||
| test.py:17 | request | twisted.request.http.Request |
|
||||
| test.py:18 | Attribute | {[externally controlled string]} |
|
||||
| test.py:18 | Attribute() | [externally controlled string] |
|
||||
| test.py:18 | request | twisted.request.http.Request |
|
||||
| test.py:19 | Subscript | externally controlled string |
|
||||
| test.py:19 | foo | [externally controlled string] |
|
||||
| test.py:20 | quux | externally controlled string |
|
||||
| test.py:24 | request | twisted.request.http.Request |
|
||||
| test.py:25 | request | twisted.request.http.Request |
|
||||
| test.py:28 | myrequest | twisted.request.http.Request |
|
||||
| test.py:29 | myrequest | twisted.request.http.Request |
|
||||
| test.py:31 | postrequest | twisted.request.http.Request |
|
||||
| test.py:32 | Attribute() | externally controlled string |
|
||||
| test.py:32 | postrequest | twisted.request.http.Request |
|
||||
| test.py:33 | Attribute() | externally controlled string |
|
||||
| test.py:33 | postrequest | twisted.request.http.Request |
|
||||
| test.py:34 | Attribute() | externally controlled string |
|
||||
| test.py:34 | postrequest | twisted.request.http.Request |
|
||||
| test.py:35 | Attribute() | externally controlled string |
|
||||
| test.py:35 | postrequest | twisted.request.http.Request |
|
||||
| test.py:36 | w | externally controlled string |
|
||||
| test.py:36 | x | externally controlled string |
|
||||
| test.py:36 | y | externally controlled string |
|
||||
| test.py:36 | z | externally controlled string |
|
||||
| test.py:39 | request | twisted.request.http.Request |
|
||||
| test.py:40 | request | twisted.request.http.Request |
|
||||
| test.py:43 | request | twisted.request.http.Request |
|
||||
| test.py:44 | request | twisted.request.http.Request |
|
||||
| test.py:45 | request | twisted.request.http.Request |
|
|
@ -0,0 +1,11 @@
|
|||
import python
|
||||
import semmle.python.TestUtils
|
||||
|
||||
import semmle.python.web.HttpRequest
|
||||
import semmle.python.web.HttpResponse
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
from TaintedNode node
|
||||
|
||||
select remove_library_prefix(node.getLocation()), node.getAstNode().toString(), node.getTaintKind()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
semmle-extractor-options: --max-import-depth=1 -p ../../../query-tests/Security/lib/
|
||||
optimize: true
|
|
@ -0,0 +1,51 @@
|
|||
from twisted.web import resource
|
||||
|
||||
class MyRequestHandler1(resource.Resource):
|
||||
def render(self, request):
|
||||
foo(request.uri)
|
||||
response = do_stuff_with(request)
|
||||
return response
|
||||
|
||||
def render_GET(self, request):
|
||||
x = request
|
||||
bar(x.uri)
|
||||
do_stuff_with(request)
|
||||
response = do_stuff_with(request)
|
||||
return response
|
||||
|
||||
def render_POST(self, request):
|
||||
baz(request.args)
|
||||
foo = request.args.get("baz")
|
||||
quux = foo[5]
|
||||
response = do_stuff_with(quux)
|
||||
return response
|
||||
|
||||
class MyRequestHandler2(resource.Resource):
|
||||
def myrender(self, request):
|
||||
do_stuff_with(request)
|
||||
|
||||
class MyRequestHandler3(resource.Resource):
|
||||
def render(self, myrequest):
|
||||
do_stuff_with(myrequest)
|
||||
|
||||
def render_POST(self, postrequest):
|
||||
x = postrequest.getHeader("someheader")
|
||||
y = postrequest.getCookie("somecookie")
|
||||
z = postrequest.getUser()
|
||||
w = postrequest.getPassword()
|
||||
return do_stuff_with(x,y,z,w)
|
||||
|
||||
class MyRequestHandler4(resource.Resource):
|
||||
def render(self, request):
|
||||
request.write("Foobar")
|
||||
|
||||
class MyRequestHandler5(resource.Resource):
|
||||
def render(self, request):
|
||||
request.setHeader("foo", "bar")
|
||||
request.addCookie("key", "value")
|
||||
return "This is my response."
|
||||
|
||||
class NotATwistedRequestHandler(object):
|
||||
def render(self, request):
|
||||
return do_stuff_with(request)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
| 12 | ControlFlowNode for implementer | class implementer | ../../../query-tests/Security/lib/zope/interface/__init__.py:5 |
|
||||
| 13 | ControlFlowNode for IThing | class IThing | test.py:4 |
|
||||
| 14 | ControlFlowNode for Thing | class Thing | test.py:9 |
|
|
@ -0,0 +1,10 @@
|
|||
import python
|
||||
import semmle.python.TestUtils
|
||||
|
||||
from ControlFlowNode f, Value v, ControlFlowNode x
|
||||
where
|
||||
exists(ExprStmt s | s.getValue().getAFlowNode() = f) and
|
||||
f.pointsTo(v, x) and
|
||||
f.getLocation().getFile().getBaseName() = "test.py"
|
||||
select f.getLocation().getStartLine(), f.toString(), v.toString(),
|
||||
remove_library_prefix(x.getLocation())
|
|
@ -0,0 +1 @@
|
|||
semmle-extractor-options: --max-import-depth=3 -p ../../../query-tests/Security/lib/
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
from zope.interface import Interface, implementer
|
||||
|
||||
class IThing(Interface):
|
||||
pass
|
||||
|
||||
|
||||
@implementer(IThing)
|
||||
class Thing(object):
|
||||
pass
|
||||
|
||||
implementer
|
||||
IThing
|
||||
Thing
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче