Merge branch 'master' into overflowcalc

This commit is contained in:
Jonas Jensen
2019-12-19 14:12:00 +01:00
committed by GitHub
104 changed files with 1134 additions and 457 deletions

View File

@@ -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*\\[[^\\]]*\\]", _, _)

View File

@@ -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() }
}

View File

@@ -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"
}
}
/**

View File

@@ -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. */

View File

@@ -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)
)

View File

@@ -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`.

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -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 |

View File

@@ -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() }

View File

@@ -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

View File

@@ -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() }
}

View File

@@ -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() }
}
/**

View File

@@ -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 & |

View File

@@ -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 & |

View File

@@ -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 & |

View File

@@ -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);
}

View File

@@ -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 |

View File

@@ -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) {

View File

@@ -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 |

View File

@@ -1,5 +0,0 @@
import cpp
from File f
where f.toString() != ""
select f.toString(), f.getRelativePath()

View File

@@ -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 |

View File

@@ -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(), ", ")

View File

@@ -1 +0,0 @@
| files1.h:0:0:0:0 | files1.h | files1.cpp:4:6:4:9 | swap |

View File

@@ -1,4 +0,0 @@
import cpp
from HeaderFile f
select f, f.getATopLevelDeclaration()

View File

@@ -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 |

View File

@@ -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()

View File

@@ -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 |

View File

@@ -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

View File

@@ -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 |

View File

@@ -1,5 +0,0 @@
import cpp
from File f, LocalVariable v
where f.getADeclaration() = v
select f.toString(), v

View File

@@ -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 && |

View File

@@ -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 |

View File

@@ -1,4 +1,5 @@
import cpp
from Expr e
where exists(e.toString())
select e, e.getType()

View File

@@ -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 && |

View File

@@ -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 & |

View File

@@ -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 |

View File

@@ -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

View File

@@ -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] */ |

View File

@@ -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] */

View File

@@ -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] */