mirror of
https://github.com/github/codeql.git
synced 2026-05-03 20:58:03 +02:00
Merge branch 'master' into ir-this-parameter-2
This commit is contained in:
@@ -23,6 +23,9 @@
|
||||
|
||||
* TypeScript 3.9 is now supported.
|
||||
|
||||
* The analysis of sanitizers has improved, leading to more accurate
|
||||
results from the security queries.
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
@@ -36,15 +39,14 @@
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
|
||||
| Client-side cross-site scripting (`js/xss`) | Fewer results | This query no longer flags optionally sanitized values. |
|
||||
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. |
|
||||
| Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe patterns of constructing HTML. |
|
||||
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. |
|
||||
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. |
|
||||
| Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. |
|
||||
| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. |
|
||||
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. |
|
||||
| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. |
|
||||
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. |
|
||||
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more coding patterns that are vulnerable to prototype pollution. |
|
||||
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. |
|
||||
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. |
|
||||
| Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. |
|
||||
|
||||
22
change-notes/1.25/analysis-python.md
Normal file
22
change-notes/1.25/analysis-python.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Improvements to Python analysis
|
||||
|
||||
The following changes in version 1.25 affect Python analysis in all applications.
|
||||
|
||||
## General improvements
|
||||
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* Importing `semmle.python.web.HttpRequest` will no longer import `UntrustedStringKind` transitively. `UntrustedStringKind` is the most commonly used non-abstract subclass of `ExternalStringKind`. If not imported (by one mean or another), taint-tracking queries that concern `ExternalStringKind` will not produce any results. Please ensure such queries contain an explicit import (`import semmle.python.security.strings.Untrusted`).
|
||||
@@ -59,21 +59,32 @@ def file_checksum(filename):
|
||||
return hashlib.sha1(file_handle.read()).hexdigest()
|
||||
|
||||
def check_group(group_name, files, master_file_picker, emit_error):
|
||||
checksums = {file_checksum(f) for f in files}
|
||||
|
||||
if len(checksums) == 1:
|
||||
extant_files = [f for f in files if path.isfile(f)]
|
||||
if len(extant_files) == 0:
|
||||
emit_error(__file__, 0, "No files found from group '" + group_name + "'.")
|
||||
emit_error(__file__, 0,
|
||||
"Create one of the following files, and then run this script with "
|
||||
"the --latest switch to sync it to the other file locations.")
|
||||
for filename in files:
|
||||
emit_error(__file__, 0, " " + filename)
|
||||
return
|
||||
|
||||
master_file = master_file_picker(files)
|
||||
checksums = {file_checksum(f) for f in extant_files}
|
||||
|
||||
if len(checksums) == 1 and len(extant_files) == len(files):
|
||||
# All files are present and identical.
|
||||
return
|
||||
|
||||
master_file = master_file_picker(extant_files)
|
||||
if master_file is None:
|
||||
emit_error(__file__, 0,
|
||||
"Files from group '"+ group_name +"' not in sync.")
|
||||
emit_error(__file__, 0,
|
||||
"Run this script with a file-name argument among the "
|
||||
"following to overwrite the remaining files with the contents "
|
||||
"of that file or run with the --latest switch to update each "
|
||||
"of that file, or run with the --latest switch to update each "
|
||||
"group of files from the most recently modified file in the group.")
|
||||
for filename in files:
|
||||
for filename in extant_files:
|
||||
emit_error(__file__, 0, " " + filename)
|
||||
else:
|
||||
print(" Syncing others from", master_file)
|
||||
@@ -81,7 +92,8 @@ def check_group(group_name, files, master_file_picker, emit_error):
|
||||
if filename == master_file:
|
||||
continue
|
||||
print(" " + filename)
|
||||
os.replace(filename, filename + '~')
|
||||
if path.isfile(filename):
|
||||
os.replace(filename, filename + '~')
|
||||
shutil.copy(master_file, filename)
|
||||
print(" Backups written with '~' appended to file names")
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Provides a class and predicate for recognizing files that are likely to have been generated
|
||||
* automatically.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Comments
|
||||
import semmle.code.cpp.File
|
||||
import semmle.code.cpp.Preprocessor
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes representing C++ classes, including structs, unions, and template classes.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Type
|
||||
import semmle.code.cpp.UserType
|
||||
import semmle.code.cpp.metrics.MetricClass
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes representing C and C++ comments.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Location
|
||||
import semmle.code.cpp.Element
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides a class representing individual compiler invocations that occurred during the build.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.File
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes for working with C and C++ declarations.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.Specifier
|
||||
import semmle.code.cpp.Namespace
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes representing warnings generated during compilation.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Location
|
||||
|
||||
/** A compiler-generated error, warning or remark. */
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Provides the `Element` class, which is the base class for all classes representing C or C++
|
||||
* program elements.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Location
|
||||
private import semmle.code.cpp.Enclosing
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
@@ -261,8 +266,14 @@ private predicate isFromUninstantiatedTemplateRec(Element e, Element template) {
|
||||
class StaticAssert extends Locatable, @static_assert {
|
||||
override string toString() { result = "static_assert(..., \"" + getMessage() + "\")" }
|
||||
|
||||
/**
|
||||
* Gets the expression which this static assertion ensures is true.
|
||||
*/
|
||||
Expr getCondition() { static_asserts(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
/**
|
||||
* Gets the message which will be reported by the compiler if this static assertion fails.
|
||||
*/
|
||||
string getMessage() { static_asserts(underlyingElement(this), _, result, _) }
|
||||
|
||||
override Location getLocation() { static_asserts(underlyingElement(this), _, _, result) }
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides predicates for finding the smallest element that encloses an expression or statement.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes representing C/C++ enums and enum constants.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Type
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
@@ -19,6 +23,17 @@ class Enum extends UserType, IntegralOrEnumType {
|
||||
/** Gets an enumerator of this enumeration. */
|
||||
EnumConstant getAnEnumConstant() { result.getDeclaringEnum() = this }
|
||||
|
||||
/**
|
||||
* Gets the enumerator of this enumeration that was declared at the zero-based position `index`.
|
||||
* For example, `zero` is at index 2 in the following declaration:
|
||||
* ```
|
||||
* enum ReversedOrder {
|
||||
* two = 2,
|
||||
* one = 1,
|
||||
* zero = 0
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
EnumConstant getEnumConstant(int index) {
|
||||
enumconstants(unresolveElement(result), underlyingElement(this), index, _, _, _)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes representing C structure members and C++ non-static member variables.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Variable
|
||||
import semmle.code.cpp.Enum
|
||||
import semmle.code.cpp.exprs.Access
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes representing files and folders.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.Declaration
|
||||
import semmle.code.cpp.metrics.MetricFile
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides a class representing C++ `friend` declarations.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Declaration
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Provides classes for working with functions, including C++ constructors, destructors,
|
||||
* user-defined operators, and template functions.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Location
|
||||
import semmle.code.cpp.Member
|
||||
import semmle.code.cpp.Class
|
||||
@@ -891,8 +896,10 @@ class Constructor extends MemberFunction {
|
||||
* A function that defines an implicit conversion.
|
||||
*/
|
||||
abstract class ImplicitConversionFunction extends MemberFunction {
|
||||
/** Gets the type this `ImplicitConversionFunction` takes as input. */
|
||||
abstract Type getSourceType();
|
||||
|
||||
/** Gets the type this `ImplicitConversionFunction` converts to. */
|
||||
abstract Type getDestType();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Provides classes representing C/C++ `#include`, `#include_next`, and `#import` preprocessor
|
||||
* directives.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Preprocessor
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,6 +67,9 @@ private DataFlow::Node getNodeForSource(Expr source) {
|
||||
// to `gets`. It's impossible here to tell which is which, but the "access
|
||||
// to argv" source is definitely not intended to match an output argument,
|
||||
// and it causes false positives if we let it.
|
||||
//
|
||||
// This case goes together with the similar (but not identical) rule in
|
||||
// `nodeIsBarrierIn`.
|
||||
result = DataFlow::definitionByReferenceNode(source) and
|
||||
not argv(source.(VariableAccess).getTarget())
|
||||
)
|
||||
@@ -202,7 +205,13 @@ private predicate nodeIsBarrier(DataFlow::Node node) {
|
||||
|
||||
private predicate nodeIsBarrierIn(DataFlow::Node node) {
|
||||
// don't use dataflow into taint sources, as this leads to duplicate results.
|
||||
node = getNodeForSource(any(Expr e))
|
||||
exists(Expr source | isUserInput(source, _) |
|
||||
node = DataFlow::exprNode(source)
|
||||
or
|
||||
// This case goes together with the similar (but not identical) rule in
|
||||
// `getNodeForSource`.
|
||||
node = DataFlow::definitionByReferenceNode(source)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -8,16 +8,28 @@ private import DataFlowDispatch
|
||||
* to the callable. Instance arguments (`this` pointer) are also included.
|
||||
*/
|
||||
class ArgumentNode extends InstructionNode {
|
||||
ArgumentNode() { exists(CallInstruction call | this.getInstruction() = call.getAnArgument()) }
|
||||
ArgumentNode() {
|
||||
exists(CallInstruction call |
|
||||
instr = call.getAnArgument()
|
||||
or
|
||||
instr.(ReadSideEffectInstruction).getPrimaryInstruction() = call
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this argument occurs at the given position in the given call.
|
||||
* The instance argument is considered to have index `-1`.
|
||||
*/
|
||||
predicate argumentOf(DataFlowCall call, int pos) {
|
||||
this.getInstruction() = call.getPositionalArgument(pos)
|
||||
instr = call.getPositionalArgument(pos)
|
||||
or
|
||||
this.getInstruction() = call.getThisArgument() and pos = -1
|
||||
instr = call.getThisArgument() and pos = -1
|
||||
or
|
||||
exists(ReadSideEffectInstruction read |
|
||||
read = instr and
|
||||
read.getPrimaryInstruction() = call and
|
||||
pos = getArgumentPosOfSideEffect(read.getIndex())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the call in which this node is an argument. */
|
||||
|
||||
@@ -54,7 +54,7 @@ class Node extends TIRDataFlowNode {
|
||||
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
|
||||
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
|
||||
|
||||
/** Gets the parameter corresponding to this node, if any. */
|
||||
/** Gets the positional parameter corresponding to this node, if any. */
|
||||
Parameter asParameter() { result = this.(ExplicitParameterNode).getParameter() }
|
||||
|
||||
/**
|
||||
@@ -156,44 +156,90 @@ class ExprNode extends InstructionNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Parameter`. This includes both explicit parameters such
|
||||
* as `x` in `f(x)` and implicit parameters such as `this` in `x.f()`
|
||||
* INTERNAL: do not use. Translates a parameter/argument index into a negative
|
||||
* number that denotes the index of its side effect (pointer indirection).
|
||||
*/
|
||||
class ParameterNode extends InstructionNode {
|
||||
override InitializeParameterInstruction instr;
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of `c` at the specified (zero-based)
|
||||
* position. The implicit `this` parameter is considered to have index `-1`.
|
||||
*/
|
||||
predicate isParameterOf(Function f, int i) { none() } // overriden by subclasses
|
||||
bindingset[index]
|
||||
int getArgumentPosOfSideEffect(int index) {
|
||||
// -1 -> -2
|
||||
// 0 -> -3
|
||||
// 1 -> -4
|
||||
// ...
|
||||
result = -3 - index
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
* flow graph. This includes both explicit parameters such as `x` in `f(x)`
|
||||
* and implicit parameters such as `this` in `x.f()`.
|
||||
*
|
||||
* To match a specific kind of parameter, consider using one of the subclasses
|
||||
* `ExplicitParameterNode`, `ThisParameterNode`, or
|
||||
* `ParameterIndirectionNode`.
|
||||
*/
|
||||
class ParameterNode extends InstructionNode {
|
||||
ParameterNode() {
|
||||
// To avoid making this class abstract, we enumerate its values here
|
||||
instr instanceof InitializeParameterInstruction
|
||||
or
|
||||
instr instanceof InitializeIndirectionInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of `f` at the specified position. The
|
||||
* implicit `this` parameter is considered to have position `-1`, and
|
||||
* pointer-indirection parameters are at further negative positions.
|
||||
*/
|
||||
predicate isParameterOf(Function f, int pos) { none() } // overridden by subclasses
|
||||
}
|
||||
|
||||
/** An explicit positional parameter, not including `this` or `...`. */
|
||||
private class ExplicitParameterNode extends ParameterNode {
|
||||
override InitializeParameterInstruction instr;
|
||||
|
||||
ExplicitParameterNode() { exists(instr.getParameter()) }
|
||||
|
||||
override predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() }
|
||||
override predicate isParameterOf(Function f, int pos) {
|
||||
f.getParameter(pos) = instr.getParameter()
|
||||
}
|
||||
|
||||
/** Gets the parameter corresponding to this node. */
|
||||
/** Gets the `Parameter` associated with this node. */
|
||||
Parameter getParameter() { result = instr.getParameter() }
|
||||
|
||||
override string toString() { result = instr.getParameter().toString() }
|
||||
}
|
||||
|
||||
private class ThisParameterNode extends ParameterNode {
|
||||
/** An implicit `this` parameter. */
|
||||
class ThisParameterNode extends ParameterNode {
|
||||
override InitializeParameterInstruction instr;
|
||||
|
||||
ThisParameterNode() { instr.getIRVariable() instanceof IRThisVariable }
|
||||
|
||||
override predicate isParameterOf(Function f, int i) {
|
||||
i = -1 and instr.getEnclosingFunction() = f
|
||||
override predicate isParameterOf(Function f, int pos) {
|
||||
pos = -1 and instr.getEnclosingFunction() = f
|
||||
}
|
||||
|
||||
override string toString() { result = "this" }
|
||||
}
|
||||
|
||||
/** A synthetic parameter to model the pointed-to object of a pointer parameter. */
|
||||
class ParameterIndirectionNode extends ParameterNode {
|
||||
override InitializeIndirectionInstruction instr;
|
||||
|
||||
override predicate isParameterOf(Function f, int pos) {
|
||||
exists(int index |
|
||||
f.getParameter(index) = instr.getParameter()
|
||||
or
|
||||
index = -1 and
|
||||
instr.getIRVariable().(IRThisVariable).getEnclosingFunction() = f
|
||||
|
|
||||
pos = getArgumentPosOfSideEffect(index)
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = "*" + instr.getIRVariable().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Data flow was never an accurate way to determine what
|
||||
* expressions might be uninitialized. It errs on the side of saying that
|
||||
@@ -341,6 +387,18 @@ class DefinitionByReferenceNode extends InstructionNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the memory pointed to by a function argument.
|
||||
*
|
||||
* This class exists only in order to override `toString`, which would
|
||||
* otherwise be the default implementation inherited from `InstructionNode`.
|
||||
*/
|
||||
private class ArgumentIndirectionNode extends InstructionNode {
|
||||
override ReadSideEffectInstruction instr;
|
||||
|
||||
override string toString() { result = "Argument " + instr.getIndex() + " indirection" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Node` corresponding to a variable in the program, as opposed to the
|
||||
* value of that variable at some particular point. This can be used for
|
||||
@@ -442,6 +500,31 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
|
||||
or
|
||||
iTo.(PhiInstruction).getAnOperand().getDef() = iFrom
|
||||
or
|
||||
// A read side effect is almost never exact since we don't know exactly how
|
||||
// much memory the callee will read.
|
||||
iTo.(ReadSideEffectInstruction).getSideEffectOperand().getAnyDef() = iFrom and
|
||||
not iFrom.isResultConflated()
|
||||
or
|
||||
// Loading a single `int` from an `int *` parameter is not an exact load since
|
||||
// the parameter may point to an entire array rather than a single `int`. The
|
||||
// following rule ensures that any flow going into the
|
||||
// `InitializeIndirectionInstruction`, even if it's for a different array
|
||||
// element, will propagate to a load of the first element.
|
||||
//
|
||||
// Since we're linking `InitializeIndirectionInstruction` and
|
||||
// `LoadInstruction` together directly, this rule will break if there's any
|
||||
// reassignment of the parameter indirection, including a conditional one that
|
||||
// leads to a phi node.
|
||||
exists(InitializeIndirectionInstruction init |
|
||||
iFrom = init and
|
||||
iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = init and
|
||||
// Check that the types match. Otherwise we can get flow from an object to
|
||||
// its fields, which leads to field conflation when there's flow from other
|
||||
// fields to the object elsewhere.
|
||||
init.getParameter().getType().getUnspecifiedType().(DerivedType).getBaseType() =
|
||||
iTo.getResultType().getUnspecifiedType()
|
||||
)
|
||||
or
|
||||
// Treat all conversions as flow, even conversions between different numeric types.
|
||||
iTo.(ConvertInstruction).getUnary() = iFrom
|
||||
or
|
||||
|
||||
@@ -56,7 +56,7 @@ class ValueNumber extends TValueNumber {
|
||||
or
|
||||
this instanceof TInitializeParameterValueNumber and result = "InitializeParameter"
|
||||
or
|
||||
this instanceof TInitializeThisValueNumber and result = "InitializeThis"
|
||||
this instanceof TConstantValueNumber and result = "Constant"
|
||||
or
|
||||
this instanceof TStringConstantValueNumber and result = "StringConstant"
|
||||
or
|
||||
|
||||
@@ -7,7 +7,6 @@ newtype TValueNumber =
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
@@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) {
|
||||
or
|
||||
instr instanceof InitializeParameterInstruction
|
||||
or
|
||||
instr instanceof InitializeThisInstruction
|
||||
or
|
||||
instr instanceof ConstantInstruction
|
||||
or
|
||||
instr instanceof StringConstantInstruction
|
||||
@@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber(
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
@@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
|
||||
@@ -56,7 +56,7 @@ class ValueNumber extends TValueNumber {
|
||||
or
|
||||
this instanceof TInitializeParameterValueNumber and result = "InitializeParameter"
|
||||
or
|
||||
this instanceof TInitializeThisValueNumber and result = "InitializeThis"
|
||||
this instanceof TConstantValueNumber and result = "Constant"
|
||||
or
|
||||
this instanceof TStringConstantValueNumber and result = "StringConstant"
|
||||
or
|
||||
|
||||
@@ -7,7 +7,6 @@ newtype TValueNumber =
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
@@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) {
|
||||
or
|
||||
instr instanceof InitializeParameterInstruction
|
||||
or
|
||||
instr instanceof InitializeThisInstruction
|
||||
or
|
||||
instr instanceof ConstantInstruction
|
||||
or
|
||||
instr instanceof StringConstantInstruction
|
||||
@@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber(
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
@@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
|
||||
@@ -1698,7 +1698,8 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
|
||||
else
|
||||
if index = 1 and expr.hasAlignedAllocation()
|
||||
then result = getTranslatedExpr(expr.getAlignmentArgument())
|
||||
else result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index))
|
||||
else
|
||||
result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index).getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ class ValueNumber extends TValueNumber {
|
||||
or
|
||||
this instanceof TInitializeParameterValueNumber and result = "InitializeParameter"
|
||||
or
|
||||
this instanceof TInitializeThisValueNumber and result = "InitializeThis"
|
||||
this instanceof TConstantValueNumber and result = "Constant"
|
||||
or
|
||||
this instanceof TStringConstantValueNumber and result = "StringConstant"
|
||||
or
|
||||
|
||||
@@ -7,7 +7,6 @@ newtype TValueNumber =
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
@@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) {
|
||||
or
|
||||
instr instanceof InitializeParameterInstruction
|
||||
or
|
||||
instr instanceof InitializeThisInstruction
|
||||
or
|
||||
instr instanceof ConstantInstruction
|
||||
or
|
||||
instr instanceof StringConstantInstruction
|
||||
@@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber(
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
@@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
|
||||
@@ -84,8 +84,6 @@ class GVN extends TValueNumber {
|
||||
or
|
||||
this instanceof TInitializeParameterValueNumber and result = "InitializeParameter"
|
||||
or
|
||||
this instanceof TInitializeThisValueNumber and result = "InitializeThis"
|
||||
or
|
||||
this instanceof TStringConstantValueNumber and result = "StringConstant"
|
||||
or
|
||||
this instanceof TFieldAddressValueNumber and result = "FieldAddress"
|
||||
|
||||
@@ -117,3 +117,35 @@ void test_conflated_fields3() {
|
||||
taint_y(&xy);
|
||||
sink(xy.x); // not tainted
|
||||
}
|
||||
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
void callSink() {
|
||||
sink(this->x); // tainted
|
||||
sink(this->y); // not tainted
|
||||
}
|
||||
};
|
||||
|
||||
void test_conflated_fields1() {
|
||||
Point p;
|
||||
p.x = getenv("VAR")[0];
|
||||
sink(p.x); // tainted
|
||||
sink(p.y); // not tainted
|
||||
p.callSink();
|
||||
}
|
||||
|
||||
void taint_x(Point *pp) {
|
||||
pp->x = getenv("VAR")[0];
|
||||
}
|
||||
|
||||
void y_to_sink(Point *pp) {
|
||||
sink(pp->y); // not tainted
|
||||
}
|
||||
|
||||
void test_conflated_fields2() {
|
||||
Point p;
|
||||
taint_x(&p);
|
||||
y_to_sink(&p);
|
||||
}
|
||||
|
||||
@@ -103,6 +103,18 @@
|
||||
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | (int)... |
|
||||
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | access to array |
|
||||
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:12:111:18 | tainted |
|
||||
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:126:16:126:16 | x |
|
||||
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:14 | call to getenv |
|
||||
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:24 | (int)... |
|
||||
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:24 | access to array |
|
||||
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:134:10:134:10 | x |
|
||||
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | shared.h:6:15:6:23 | sinkparam |
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:16 | call to getenv |
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | (int)... |
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | access to array |
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:143:23:143:24 | pp |
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:144:8:144:9 | pp |
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:150:13:150:14 | & ... |
|
||||
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:24:28:27 | call to atoi |
|
||||
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:34 | call to getenv |
|
||||
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:45 | (const char *)... |
|
||||
|
||||
@@ -21,6 +21,14 @@
|
||||
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | p2 | IR only |
|
||||
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR only |
|
||||
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:8:111:8 | y | AST only |
|
||||
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:126:16:126:16 | x | IR only |
|
||||
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:5:133:5 | x | AST only |
|
||||
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:134:10:134:10 | x | IR only |
|
||||
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only |
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:7:140:7 | x | AST only |
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:143:23:143:24 | pp | IR only |
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:144:8:144:9 | pp | IR only |
|
||||
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:150:13:150:14 | & ... | IR only |
|
||||
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only |
|
||||
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:5:23:11 | global2 | AST only |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only |
|
||||
|
||||
@@ -27,7 +27,7 @@ void following_pointers(
|
||||
|
||||
sourceStruct1_ptr->m1 = source();
|
||||
sink(sourceStruct1_ptr->m1); // flow
|
||||
sink(sourceStruct1_ptr->getFirst()); // flow [NOT DETECTED with IR]
|
||||
sink(sourceStruct1_ptr->getFirst()); // flow
|
||||
sink(sourceStruct1_ptr->m2); // no flow
|
||||
sink(sourceStruct1.m1); // no flow
|
||||
|
||||
|
||||
@@ -366,7 +366,7 @@ class FlowThroughFields {
|
||||
}
|
||||
|
||||
int calledAfterTaint() {
|
||||
sink(field); // tainted [NOT DETECTED with IR]
|
||||
sink(field); // tainted
|
||||
}
|
||||
|
||||
int taintAndCall() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
| BarrierGuard.cpp:49:10:49:15 | BarrierGuard.cpp:51:13:51:13 | AST only |
|
||||
| BarrierGuard.cpp:60:11:60:16 | BarrierGuard.cpp:62:14:62:14 | AST only |
|
||||
| clang.cpp:12:9:12:20 | clang.cpp:22:8:22:20 | AST only |
|
||||
| clang.cpp:28:27:28:32 | clang.cpp:30:27:30:34 | AST only |
|
||||
| clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only |
|
||||
| dispatch.cpp:16:37:16:42 | dispatch.cpp:32:16:32:24 | IR only |
|
||||
| dispatch.cpp:16:37:16:42 | dispatch.cpp:40:15:40:23 | IR only |
|
||||
@@ -19,11 +18,7 @@
|
||||
| dispatch.cpp:144:8:144:13 | dispatch.cpp:96:8:96:8 | IR only |
|
||||
| globals.cpp:13:23:13:28 | globals.cpp:12:10:12:24 | IR only |
|
||||
| globals.cpp:23:23:23:28 | globals.cpp:19:10:19:24 | IR only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:14:3:14:6 | AST only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:29:3:29:6 | AST only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:41:8:41:8 | AST only |
|
||||
| lambdas.cpp:43:7:43:12 | lambdas.cpp:46:7:46:7 | AST only |
|
||||
| ref.cpp:29:11:29:16 | ref.cpp:62:10:62:11 | AST only |
|
||||
| ref.cpp:53:9:53:10 | ref.cpp:56:10:56:11 | AST only |
|
||||
@@ -39,7 +34,6 @@
|
||||
| test.cpp:109:9:109:14 | test.cpp:110:10:110:12 | IR only |
|
||||
| test.cpp:347:17:347:22 | test.cpp:349:10:349:18 | AST only |
|
||||
| test.cpp:359:13:359:18 | test.cpp:365:10:365:14 | AST only |
|
||||
| test.cpp:373:13:373:18 | test.cpp:369:10:369:14 | AST only |
|
||||
| test.cpp:399:7:399:9 | test.cpp:401:8:401:10 | AST only |
|
||||
| test.cpp:405:7:405:9 | test.cpp:408:8:408:10 | AST only |
|
||||
| test.cpp:416:7:416:11 | test.cpp:418:8:418:12 | AST only |
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
| clang.cpp:18:8:18:19 | (const int *)... | clang.cpp:12:9:12:20 | sourceArray1 |
|
||||
| clang.cpp:18:8:18:19 | sourceArray1 | clang.cpp:12:9:12:20 | sourceArray1 |
|
||||
| clang.cpp:29:27:29:28 | m1 | clang.cpp:28:27:28:32 | call to source |
|
||||
| clang.cpp:30:27:30:34 | call to getFirst | clang.cpp:28:27:28:32 | call to source |
|
||||
| clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source |
|
||||
| clang.cpp:41:18:41:19 | m2 | clang.cpp:39:42:39:47 | call to source |
|
||||
| clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source |
|
||||
@@ -38,7 +39,11 @@
|
||||
| globals.cpp:6:10:6:14 | local | globals.cpp:5:17:5:22 | call to source |
|
||||
| globals.cpp:12:10:12:24 | flowTestGlobal1 | globals.cpp:13:23:13:28 | call to source |
|
||||
| globals.cpp:19:10:19:24 | flowTestGlobal2 | globals.cpp:23:23:23:28 | call to source |
|
||||
| lambdas.cpp:14:3:14:6 | t | lambdas.cpp:8:10:8:15 | call to source |
|
||||
| lambdas.cpp:18:8:18:8 | call to operator() | lambdas.cpp:8:10:8:15 | call to source |
|
||||
| lambdas.cpp:29:3:29:6 | t | lambdas.cpp:8:10:8:15 | call to source |
|
||||
| lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source |
|
||||
| lambdas.cpp:41:8:41:8 | (reference dereference) | lambdas.cpp:8:10:8:15 | call to source |
|
||||
| ref.cpp:123:13:123:15 | val | ref.cpp:122:23:122:28 | call to source |
|
||||
| ref.cpp:126:13:126:15 | val | ref.cpp:125:19:125:24 | call to source |
|
||||
| ref.cpp:129:13:129:15 | val | ref.cpp:94:15:94:20 | call to source |
|
||||
@@ -65,6 +70,7 @@
|
||||
| test.cpp:266:12:266:12 | x | test.cpp:265:22:265:27 | call to source |
|
||||
| test.cpp:289:14:289:14 | x | test.cpp:305:17:305:22 | call to source |
|
||||
| test.cpp:318:7:318:7 | x | test.cpp:314:4:314:9 | call to source |
|
||||
| test.cpp:369:10:369:14 | field | test.cpp:373:13:373:18 | call to source |
|
||||
| test.cpp:375:10:375:14 | field | test.cpp:373:13:373:18 | call to source |
|
||||
| test.cpp:385:8:385:10 | tmp | test.cpp:382:48:382:54 | source1 |
|
||||
| test.cpp:392:8:392:10 | tmp | test.cpp:388:53:388:59 | source1 |
|
||||
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
{
|
||||
if (C1 *c1 = dynamic_cast<C1 *>(c))
|
||||
{
|
||||
sink(c1->a); // $ast $f-:ir
|
||||
sink(c1->a); // $ast $ir
|
||||
}
|
||||
C *cc;
|
||||
if (C2 *c2 = dynamic_cast<C2 *>(c))
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
private import semmle.code.cpp.dataflow.DataFlow
|
||||
private import DataFlow
|
||||
|
||||
class Conf extends Configuration {
|
||||
Conf() { this = "FieldFlowConf" }
|
||||
|
||||
override predicate isSource(Node src) {
|
||||
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) {
|
||||
exists(Call c |
|
||||
c.getTarget().hasName("sink") and
|
||||
c.getAnArgument() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(Node a, Node b) {
|
||||
b.asPartialDefinition() =
|
||||
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
|
||||
.getQualifier()
|
||||
or
|
||||
b.asExpr().(AddressOfExpr).getOperand() = a.asExpr()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import DataFlow
|
||||
|
||||
class Conf extends Configuration {
|
||||
Conf() { this = "FieldFlowConf" }
|
||||
|
||||
override predicate isSource(Node src) {
|
||||
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) {
|
||||
exists(Call c |
|
||||
c.getTarget().hasName("sink") and
|
||||
c.getAnArgument() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(Node a, Node b) {
|
||||
b.asPartialDefinition() =
|
||||
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
|
||||
.getQualifier()
|
||||
or
|
||||
b.asExpr().(AddressOfExpr).getOperand() = a.asExpr()
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ void test_setThroughNonMember() {
|
||||
void test_nonMemberSetA() {
|
||||
S s;
|
||||
nonMemberSetA(&s, user_input());
|
||||
sink(nonMemberGetA(&s)); // $ast $f-:ir
|
||||
sink(nonMemberGetA(&s)); // $ast,ir
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
@@ -4,49 +4,19 @@
|
||||
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
import DataFlow
|
||||
import ASTConfiguration
|
||||
import cpp
|
||||
|
||||
class Conf extends Configuration {
|
||||
Conf() { this = "FieldFlowConf" }
|
||||
|
||||
override predicate isSource(Node src) {
|
||||
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) {
|
||||
exists(Call c |
|
||||
c.getTarget().hasName("sink") and
|
||||
c.getAnArgument() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(Node a, Node b) {
|
||||
b.asPartialDefinition() =
|
||||
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
|
||||
.getQualifier()
|
||||
or
|
||||
b.asExpr().(AddressOfExpr).getOperand() = a.asExpr()
|
||||
}
|
||||
}
|
||||
|
||||
class ASTFieldFlowTest extends InlineExpectationsTest {
|
||||
ASTFieldFlowTest() { this = "ASTFieldFlowTest" }
|
||||
|
||||
override string getARelevantTag() { result = "ast" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Node source, Node sink, Conf conf, int n |
|
||||
exists(DataFlow::Node source, DataFlow::Node sink, Conf conf, int n |
|
||||
tag = "ast" and
|
||||
conf.hasFlow(source, sink) and
|
||||
n = strictcount(Node otherSource | conf.hasFlow(otherSource, sink)) and
|
||||
n = strictcount(DataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
|
||||
(
|
||||
n = 1 and value = ""
|
||||
or
|
||||
|
||||
@@ -4,49 +4,19 @@
|
||||
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import DataFlow
|
||||
import IRConfiguration
|
||||
import cpp
|
||||
|
||||
class Conf extends Configuration {
|
||||
Conf() { this = "FieldFlowConf" }
|
||||
|
||||
override predicate isSource(Node src) {
|
||||
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) {
|
||||
exists(Call c |
|
||||
c.getTarget().hasName("sink") and
|
||||
c.getAnArgument() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(Node a, Node b) {
|
||||
b.asPartialDefinition() =
|
||||
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
|
||||
.getQualifier()
|
||||
or
|
||||
b.asExpr().(AddressOfExpr).getOperand() = a.asExpr()
|
||||
}
|
||||
}
|
||||
|
||||
class IRFieldFlowTest extends InlineExpectationsTest {
|
||||
IRFieldFlowTest() { this = "IRFieldFlowTest" }
|
||||
|
||||
override string getARelevantTag() { result = "ir" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Node source, Node sink, Conf conf, int n |
|
||||
exists(DataFlow::Node source, DataFlow::Node sink, Conf conf, int n |
|
||||
tag = "ir" and
|
||||
conf.hasFlow(source, sink) and
|
||||
n = strictcount(Node otherSource | conf.hasFlow(otherSource, sink)) and
|
||||
n = strictcount(DataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
|
||||
(
|
||||
n = 1 and value = ""
|
||||
or
|
||||
|
||||
182
cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected
Normal file
182
cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected
Normal file
@@ -0,0 +1,182 @@
|
||||
edges
|
||||
| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store |
|
||||
| A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] |
|
||||
| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] |
|
||||
| A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] |
|
||||
| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a |
|
||||
| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a |
|
||||
| A.cpp:107:16:107:16 | a | A.cpp:107:12:107:16 | (void *)... |
|
||||
| A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] |
|
||||
| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] |
|
||||
| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store |
|
||||
| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c |
|
||||
| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c |
|
||||
| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] |
|
||||
| A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... |
|
||||
| aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] |
|
||||
| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store |
|
||||
| aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] |
|
||||
| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] |
|
||||
| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store |
|
||||
| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 |
|
||||
| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 |
|
||||
| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] |
|
||||
| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 |
|
||||
| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 |
|
||||
| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] |
|
||||
| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] |
|
||||
| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store |
|
||||
| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 |
|
||||
| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 |
|
||||
| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 |
|
||||
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 |
|
||||
| by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] |
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] |
|
||||
| by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
|
||||
| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] |
|
||||
| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] |
|
||||
| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] |
|
||||
| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store |
|
||||
| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] |
|
||||
| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] |
|
||||
| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] |
|
||||
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store |
|
||||
| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a |
|
||||
| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] |
|
||||
| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a |
|
||||
| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] |
|
||||
| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a |
|
||||
| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] |
|
||||
| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a |
|
||||
| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] |
|
||||
| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] |
|
||||
| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] |
|
||||
| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i |
|
||||
| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] |
|
||||
| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | Chi [f1] |
|
||||
| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store |
|
||||
| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 |
|
||||
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a |
|
||||
| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] |
|
||||
| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | Chi [a] |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Store |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a |
|
||||
| struct_init.c:24:10:24:12 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] |
|
||||
| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] |
|
||||
| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | Chi [a] |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a |
|
||||
| struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] |
|
||||
nodes
|
||||
| A.cpp:98:12:98:18 | new | semmle.label | new |
|
||||
| A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] |
|
||||
| A.cpp:100:5:100:13 | Store | semmle.label | Store |
|
||||
| A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] |
|
||||
| A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] |
|
||||
| A.cpp:107:12:107:16 | (void *)... | semmle.label | (void *)... |
|
||||
| A.cpp:107:16:107:16 | a | semmle.label | a |
|
||||
| A.cpp:107:16:107:16 | a | semmle.label | a |
|
||||
| A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:142:7:142:20 | Store | semmle.label | Store |
|
||||
| A.cpp:142:14:142:20 | new | semmle.label | new |
|
||||
| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] |
|
||||
| A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] |
|
||||
| A.cpp:154:10:154:13 | (void *)... | semmle.label | (void *)... |
|
||||
| A.cpp:154:13:154:13 | c | semmle.label | c |
|
||||
| A.cpp:154:13:154:13 | c | semmle.label | c |
|
||||
| aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store |
|
||||
| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store |
|
||||
| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] |
|
||||
| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] |
|
||||
| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store |
|
||||
| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] |
|
||||
| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
|
||||
| by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | semmle.label | nonMemberSetA output argument [a] |
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA |
|
||||
| by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] |
|
||||
| by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:84:3:84:25 | Store | semmle.label | Store |
|
||||
| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:88:3:88:24 | Store | semmle.label | Store |
|
||||
| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] |
|
||||
| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] |
|
||||
| by_reference.cpp:110:27:110:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:114:29:114:29 | a | semmle.label | a |
|
||||
| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] |
|
||||
| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] |
|
||||
| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] |
|
||||
| by_reference.cpp:130:27:130:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:134:29:134:29 | a | semmle.label | a |
|
||||
| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] |
|
||||
| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] |
|
||||
| simple.cpp:67:13:67:13 | i | semmle.label | i |
|
||||
| simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] |
|
||||
| simple.cpp:83:9:83:28 | Store | semmle.label | Store |
|
||||
| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] |
|
||||
| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 |
|
||||
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
|
||||
| struct_init.c:15:12:15:12 | a | semmle.label | a |
|
||||
| struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] |
|
||||
| struct_init.c:20:20:20:29 | Store | semmle.label | Store |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:22:11:22:11 | a | semmle.label | a |
|
||||
| struct_init.c:24:10:24:12 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] |
|
||||
| struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] |
|
||||
| struct_init.c:27:7:27:16 | Store | semmle.label | Store |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:31:23:31:23 | a | semmle.label | a |
|
||||
| struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] |
|
||||
#select
|
||||
| A.cpp:107:12:107:16 | (void *)... | A.cpp:98:12:98:18 | new | A.cpp:107:12:107:16 | (void *)... | (void *)... flows from $@ | A.cpp:98:12:98:18 | new | new |
|
||||
| A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new |
|
||||
| A.cpp:154:10:154:13 | (void *)... | A.cpp:142:14:142:20 | new | A.cpp:154:10:154:13 | (void *)... | (void *)... flows from $@ | A.cpp:142:14:142:20 | new | new |
|
||||
| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new |
|
||||
| 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:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | 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 |
|
||||
| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input |
|
||||
| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input |
|
||||
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
||||
| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||
| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
||||
12
cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql
Normal file
12
cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import IRConfiguration
|
||||
import cpp
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf
|
||||
where conf.hasFlowPath(src, sink)
|
||||
select sink, src, sink, sink + " flows from $@", src, src.toString()
|
||||
838
cpp/ql/test/library-tests/dataflow/fields/path-flow.expected
Normal file
838
cpp/ql/test/library-tests/dataflow/fields/path-flow.expected
Normal file
@@ -0,0 +1,838 @@
|
||||
edges
|
||||
| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... |
|
||||
| A.cpp:47:12:47:18 | new | A.cpp:48:20:48:20 | c |
|
||||
| A.cpp:48:12:48:18 | call to make [c] | A.cpp:49:10:49:10 | b [c] |
|
||||
| A.cpp:48:20:48:20 | c | A.cpp:48:12:48:18 | call to make [c] |
|
||||
| A.cpp:49:10:49:10 | b [c] | A.cpp:49:13:49:13 | c |
|
||||
| A.cpp:55:5:55:5 | ref arg b [c] | A.cpp:56:10:56:10 | b [c] |
|
||||
| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | ref arg b [c] |
|
||||
| A.cpp:56:10:56:10 | b [c] | A.cpp:56:13:56:15 | call to get |
|
||||
| A.cpp:57:11:57:24 | call to B [c] | A.cpp:57:11:57:24 | new [c] |
|
||||
| A.cpp:57:11:57:24 | new [c] | A.cpp:57:28:57:30 | call to get |
|
||||
| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | call to B [c] |
|
||||
| A.cpp:64:10:64:15 | call to setOnB [c] | A.cpp:66:10:66:11 | b2 [c] |
|
||||
| A.cpp:64:21:64:28 | new | A.cpp:64:10:64:15 | call to setOnB [c] |
|
||||
| A.cpp:66:10:66:11 | b2 [c] | A.cpp:66:14:66:14 | c |
|
||||
| A.cpp:73:10:73:19 | call to setOnBWrap [c] | A.cpp:75:10:75:11 | b2 [c] |
|
||||
| A.cpp:73:25:73:32 | new | A.cpp:73:10:73:19 | call to setOnBWrap [c] |
|
||||
| A.cpp:75:10:75:11 | b2 [c] | A.cpp:75:14:75:14 | c |
|
||||
| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | ... = ... |
|
||||
| A.cpp:100:5:100:6 | c1 [post update] [a] | A.cpp:101:8:101:9 | c1 [a] |
|
||||
| A.cpp:100:5:100:13 | ... = ... | A.cpp:100:5:100:6 | c1 [post update] [a] |
|
||||
| A.cpp:101:8:101:9 | c1 [a] | A.cpp:103:14:103:14 | c [a] |
|
||||
| A.cpp:103:14:103:14 | c [a] | A.cpp:107:12:107:13 | c1 [a] |
|
||||
| A.cpp:103:14:103:14 | c [a] | A.cpp:120:12:120:13 | c1 [a] |
|
||||
| A.cpp:107:12:107:13 | c1 [a] | A.cpp:107:16:107:16 | a |
|
||||
| A.cpp:120:12:120:13 | c1 [a] | A.cpp:120:16:120:16 | a |
|
||||
| A.cpp:126:5:126:5 | ref arg b [c] | A.cpp:131:8:131:8 | ref arg b [c] |
|
||||
| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | ref arg b [c] |
|
||||
| A.cpp:131:8:131:8 | ref arg b [c] | A.cpp:132:10:132:10 | b [c] |
|
||||
| A.cpp:132:10:132:10 | b [c] | A.cpp:132:13:132:13 | c |
|
||||
| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:143:7:143:31 | ... = ... [c] |
|
||||
| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:151:18:151:18 | ref arg b [c] |
|
||||
| A.cpp:142:7:142:20 | ... = ... | A.cpp:142:7:142:7 | b [post update] [c] |
|
||||
| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | ... = ... |
|
||||
| A.cpp:143:7:143:10 | this [post update] [b, c] | A.cpp:151:12:151:24 | call to D [b, c] |
|
||||
| A.cpp:143:7:143:10 | this [post update] [b] | A.cpp:151:12:151:24 | call to D [b] |
|
||||
| A.cpp:143:7:143:31 | ... = ... | A.cpp:143:7:143:10 | this [post update] [b] |
|
||||
| A.cpp:143:7:143:31 | ... = ... [c] | A.cpp:143:7:143:10 | this [post update] [b, c] |
|
||||
| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | ... = ... |
|
||||
| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b |
|
||||
| A.cpp:151:12:151:24 | call to D [b, c] | A.cpp:153:10:153:10 | d [b, c] |
|
||||
| A.cpp:151:12:151:24 | call to D [b] | A.cpp:152:10:152:10 | d [b] |
|
||||
| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | call to D [b] |
|
||||
| A.cpp:151:18:151:18 | ref arg b [c] | A.cpp:154:10:154:10 | b [c] |
|
||||
| A.cpp:152:10:152:10 | d [b] | A.cpp:152:13:152:13 | b |
|
||||
| A.cpp:153:10:153:10 | d [b, c] | A.cpp:153:13:153:13 | b [c] |
|
||||
| A.cpp:153:13:153:13 | b [c] | A.cpp:153:16:153:16 | c |
|
||||
| A.cpp:154:10:154:10 | b [c] | A.cpp:154:13:154:13 | c |
|
||||
| A.cpp:159:12:159:18 | new | A.cpp:160:29:160:29 | b |
|
||||
| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:161:38:161:39 | l1 [head] |
|
||||
| A.cpp:160:29:160:29 | b | A.cpp:160:18:160:60 | call to MyList [head] |
|
||||
| A.cpp:161:18:161:40 | call to MyList [next, head] | A.cpp:162:38:162:39 | l2 [next, head] |
|
||||
| A.cpp:161:38:161:39 | l1 [head] | A.cpp:161:18:161:40 | call to MyList [next, head] |
|
||||
| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:165:10:165:11 | l3 [next, next, ... (3)] |
|
||||
| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:167:44:167:44 | l [next, next, ... (3)] |
|
||||
| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] |
|
||||
| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | A.cpp:165:14:165:17 | next [next, head] |
|
||||
| A.cpp:165:14:165:17 | next [next, head] | A.cpp:165:20:165:23 | next [head] |
|
||||
| A.cpp:165:20:165:23 | next [head] | A.cpp:165:26:165:29 | head |
|
||||
| A.cpp:167:44:167:44 | l [next, head] | A.cpp:167:47:167:50 | next [head] |
|
||||
| A.cpp:167:44:167:44 | l [next, next, ... (3)] | A.cpp:167:47:167:50 | next [next, head] |
|
||||
| A.cpp:167:47:167:50 | next [head] | A.cpp:169:12:169:12 | l [head] |
|
||||
| A.cpp:167:47:167:50 | next [next, head] | A.cpp:167:44:167:44 | l [next, head] |
|
||||
| A.cpp:169:12:169:12 | l [head] | A.cpp:169:15:169:18 | head |
|
||||
| B.cpp:6:15:6:24 | new | B.cpp:7:25:7:25 | e |
|
||||
| B.cpp:7:16:7:35 | call to Box1 [elem1] | B.cpp:8:25:8:26 | b1 [elem1] |
|
||||
| B.cpp:7:25:7:25 | e | B.cpp:7:16:7:35 | call to Box1 [elem1] |
|
||||
| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | B.cpp:9:10:9:11 | b2 [box1, elem1] |
|
||||
| B.cpp:8:25:8:26 | b1 [elem1] | B.cpp:8:16:8:27 | call to Box2 [box1, elem1] |
|
||||
| B.cpp:9:10:9:11 | b2 [box1, elem1] | B.cpp:9:14:9:17 | box1 [elem1] |
|
||||
| B.cpp:9:14:9:17 | box1 [elem1] | B.cpp:9:20:9:24 | elem1 |
|
||||
| B.cpp:15:15:15:27 | new | B.cpp:16:37:16:37 | e |
|
||||
| B.cpp:16:16:16:38 | call to Box1 [elem2] | B.cpp:17:25:17:26 | b1 [elem2] |
|
||||
| B.cpp:16:37:16:37 | e | B.cpp:16:16:16:38 | call to Box1 [elem2] |
|
||||
| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | B.cpp:19:10:19:11 | b2 [box1, elem2] |
|
||||
| B.cpp:17:25:17:26 | b1 [elem2] | B.cpp:17:16:17:27 | call to Box2 [box1, elem2] |
|
||||
| B.cpp:19:10:19:11 | b2 [box1, elem2] | B.cpp:19:14:19:17 | box1 [elem2] |
|
||||
| B.cpp:19:14:19:17 | box1 [elem2] | B.cpp:19:20:19:24 | elem2 |
|
||||
| C.cpp:18:12:18:18 | call to C [s1] | C.cpp:19:5:19:5 | c [s1] |
|
||||
| C.cpp:18:12:18:18 | call to C [s3] | C.cpp:19:5:19:5 | c [s3] |
|
||||
| C.cpp:19:5:19:5 | c [s1] | C.cpp:27:8:27:11 | this [s1] |
|
||||
| C.cpp:19:5:19:5 | c [s3] | C.cpp:27:8:27:11 | this [s3] |
|
||||
| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | C.cpp:18:12:18:18 | call to C [s1] |
|
||||
| C.cpp:22:12:22:21 | new | C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] |
|
||||
| C.cpp:24:5:24:8 | this [post update] [s3] | C.cpp:18:12:18:18 | call to C [s3] |
|
||||
| C.cpp:24:5:24:25 | ... = ... | C.cpp:24:5:24:8 | this [post update] [s3] |
|
||||
| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | ... = ... |
|
||||
| C.cpp:27:8:27:11 | this [s1] | C.cpp:29:10:29:11 | this [s1] |
|
||||
| C.cpp:27:8:27:11 | this [s3] | C.cpp:31:10:31:11 | this [s3] |
|
||||
| C.cpp:29:10:29:11 | this [s1] | C.cpp:29:10:29:11 | s1 |
|
||||
| C.cpp:31:10:31:11 | this [s3] | C.cpp:31:10:31:11 | s3 |
|
||||
| D.cpp:21:30:21:31 | b2 [box, elem] | D.cpp:22:10:22:11 | b2 [box, elem] |
|
||||
| D.cpp:22:10:22:11 | b2 [box, elem] | D.cpp:22:14:22:20 | call to getBox1 [elem] |
|
||||
| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:22:25:22:31 | call to getElem |
|
||||
| D.cpp:28:15:28:24 | new | D.cpp:30:5:30:20 | ... = ... |
|
||||
| D.cpp:30:5:30:5 | b [post update] [box, elem] | D.cpp:31:14:31:14 | b [box, elem] |
|
||||
| D.cpp:30:5:30:20 | ... = ... | D.cpp:30:8:30:10 | box [post update] [elem] |
|
||||
| D.cpp:30:8:30:10 | box [post update] [elem] | D.cpp:30:5:30:5 | b [post update] [box, elem] |
|
||||
| D.cpp:31:14:31:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] |
|
||||
| D.cpp:35:15:35:24 | new | D.cpp:37:21:37:21 | e |
|
||||
| D.cpp:37:5:37:5 | b [post update] [box, elem] | D.cpp:38:14:38:14 | b [box, elem] |
|
||||
| D.cpp:37:8:37:10 | ref arg box [elem] | D.cpp:37:5:37:5 | b [post update] [box, elem] |
|
||||
| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | ref arg box [elem] |
|
||||
| D.cpp:38:14:38:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] |
|
||||
| D.cpp:42:15:42:24 | new | D.cpp:44:5:44:26 | ... = ... |
|
||||
| D.cpp:44:5:44:5 | ref arg b [box, elem] | D.cpp:45:14:45:14 | b [box, elem] |
|
||||
| D.cpp:44:5:44:26 | ... = ... | D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] |
|
||||
| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | D.cpp:44:5:44:5 | ref arg b [box, elem] |
|
||||
| D.cpp:45:14:45:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] |
|
||||
| D.cpp:49:15:49:24 | new | D.cpp:51:27:51:27 | e |
|
||||
| D.cpp:51:5:51:5 | ref arg b [box, elem] | D.cpp:52:14:52:14 | b [box, elem] |
|
||||
| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | D.cpp:51:5:51:5 | ref arg b [box, elem] |
|
||||
| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] |
|
||||
| D.cpp:52:14:52:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] |
|
||||
| D.cpp:56:15:56:24 | new | D.cpp:58:5:58:27 | ... = ... |
|
||||
| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] |
|
||||
| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] |
|
||||
| D.cpp:58:5:58:27 | ... = ... | D.cpp:58:15:58:17 | box [post update] [elem] |
|
||||
| D.cpp:58:15:58:17 | box [post update] [elem] | D.cpp:58:5:58:12 | boxfield [post update] [box, elem] |
|
||||
| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] |
|
||||
| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | 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: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 | ... = ... |
|
||||
| aliasing.cpp:12:25:12:25 | s [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] |
|
||||
| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:12:25:12:25 | s [m1] |
|
||||
| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] |
|
||||
| aliasing.cpp:13:3:13:21 | ... = ... | aliasing.cpp:13:3:13:3 | s [post update] [m1] |
|
||||
| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | ... = ... |
|
||||
| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | aliasing.cpp:29:8:29:9 | s1 [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | aliasing.cpp:30:8:30:9 | s2 [m1] |
|
||||
| aliasing.cpp:29:8:29:9 | s1 [m1] | aliasing.cpp:29:11:29:12 | m1 |
|
||||
| aliasing.cpp:30:8:30:9 | s2 [m1] | aliasing.cpp:30:11:30:12 | m1 |
|
||||
| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | aliasing.cpp:62:8:62:12 | copy2 [m1] |
|
||||
| aliasing.cpp:60:3:60:22 | ... = ... | aliasing.cpp:60:3:60:4 | s2 [post update] [m1] |
|
||||
| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | ... = ... |
|
||||
| aliasing.cpp:62:8:62:12 | copy2 [m1] | aliasing.cpp:62:14:62:15 | m1 |
|
||||
| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | aliasing.cpp:93:8:93:8 | w [s, m1] |
|
||||
| aliasing.cpp:92:3:92:23 | ... = ... | aliasing.cpp:92:5:92:5 | s [post update] [m1] |
|
||||
| aliasing.cpp:92:5:92:5 | s [post update] [m1] | aliasing.cpp:92:3:92:3 | w [post update] [s, m1] |
|
||||
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... |
|
||||
| aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] |
|
||||
| aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 |
|
||||
| by_reference.cpp:50:3:50:3 | ref arg s [a] | by_reference.cpp:51:8:51:8 | s [a] |
|
||||
| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | ref arg s [a] |
|
||||
| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly |
|
||||
| by_reference.cpp:56:3:56:3 | ref arg s [a] | by_reference.cpp:57:8:57:8 | s [a] |
|
||||
| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | ref arg s [a] |
|
||||
| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly |
|
||||
| by_reference.cpp:62:3:62:3 | ref arg s [a] | by_reference.cpp:63:8:63:8 | s [a] |
|
||||
| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | ref arg s [a] |
|
||||
| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
|
||||
| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] |
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] |
|
||||
| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
|
||||
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:102:21:102:39 | ref arg & ... [a] |
|
||||
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] |
|
||||
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:106:21:106:41 | ref arg & ... [a] |
|
||||
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] |
|
||||
| by_reference.cpp:84:3:84:25 | ... = ... | by_reference.cpp:84:3:84:7 | inner [post update] [a] |
|
||||
| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | ... = ... |
|
||||
| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] |
|
||||
| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] |
|
||||
| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] |
|
||||
| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] |
|
||||
| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:87:31:87:35 | inner [a] |
|
||||
| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] |
|
||||
| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] |
|
||||
| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] |
|
||||
| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] |
|
||||
| by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] |
|
||||
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... |
|
||||
| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a |
|
||||
| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a |
|
||||
| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | pa |
|
||||
| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] |
|
||||
| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | by_reference.cpp:110:8:110:12 | outer [inner_nested, a] |
|
||||
| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] |
|
||||
| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] |
|
||||
| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] |
|
||||
| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] |
|
||||
| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] |
|
||||
| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] |
|
||||
| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] |
|
||||
| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] |
|
||||
| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | by_reference.cpp:110:14:110:25 | inner_nested [a] |
|
||||
| by_reference.cpp:110:14:110:25 | inner_nested [a] | by_reference.cpp:110:27:110:27 | a |
|
||||
| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] |
|
||||
| by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a |
|
||||
| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | by_reference.cpp:114:16:114:27 | inner_nested [a] |
|
||||
| by_reference.cpp:114:16:114:27 | inner_nested [a] | by_reference.cpp:114:29:114:29 | a |
|
||||
| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] |
|
||||
| by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a |
|
||||
| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] |
|
||||
| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] |
|
||||
| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] |
|
||||
| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] |
|
||||
| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] |
|
||||
| by_reference.cpp:124:15:124:19 | outer [post update] [a] | by_reference.cpp:132:8:132:12 | outer [a] |
|
||||
| by_reference.cpp:124:21:124:21 | ref arg a | by_reference.cpp:124:15:124:19 | outer [post update] [a] |
|
||||
| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] |
|
||||
| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] |
|
||||
| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] |
|
||||
| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] |
|
||||
| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] |
|
||||
| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | by_reference.cpp:136:8:136:13 | pouter [a] |
|
||||
| by_reference.cpp:128:23:128:23 | ref arg a | by_reference.cpp:128:15:128:20 | pouter [post update] [a] |
|
||||
| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | by_reference.cpp:130:14:130:25 | inner_nested [a] |
|
||||
| by_reference.cpp:130:14:130:25 | inner_nested [a] | by_reference.cpp:130:27:130:27 | a |
|
||||
| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | by_reference.cpp:131:14:131:22 | inner_ptr [a] |
|
||||
| by_reference.cpp:131:14:131:22 | inner_ptr [a] | by_reference.cpp:131:25:131:25 | a |
|
||||
| by_reference.cpp:132:8:132:12 | outer [a] | by_reference.cpp:132:14:132:14 | a |
|
||||
| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | by_reference.cpp:134:16:134:27 | inner_nested [a] |
|
||||
| by_reference.cpp:134:16:134:27 | inner_nested [a] | by_reference.cpp:134:29:134:29 | a |
|
||||
| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] |
|
||||
| by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a |
|
||||
| by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a |
|
||||
| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | complex.cpp:51:8:51:8 | b [inner, f, ... (3)] |
|
||||
| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | complex.cpp:52:8:52:8 | b [inner, f, ... (3)] |
|
||||
| complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | complex.cpp:51:10:51:14 | inner [f, a_] |
|
||||
| complex.cpp:51:10:51:14 | inner [f, a_] | complex.cpp:51:16:51:16 | f [a_] |
|
||||
| complex.cpp:51:16:51:16 | f [a_] | complex.cpp:51:18:51:18 | call to a |
|
||||
| complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | complex.cpp:52:10:52:14 | inner [f, b_] |
|
||||
| complex.cpp:52:10:52:14 | inner [f, b_] | complex.cpp:52:16:52:16 | f [b_] |
|
||||
| complex.cpp:52:16:52:16 | f [b_] | complex.cpp:52:18:52:18 | call to b |
|
||||
| complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] |
|
||||
| complex.cpp:62:6:62:10 | inner [post update] [f, a_] | complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] |
|
||||
| complex.cpp:62:12:62:12 | ref arg f [a_] | complex.cpp:62:6:62:10 | inner [post update] [f, a_] |
|
||||
| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:62:12:62:12 | ref arg f [a_] |
|
||||
| complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] |
|
||||
| complex.cpp:63:6:63:10 | inner [post update] [f, b_] | complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] |
|
||||
| complex.cpp:63:12:63:12 | ref arg f [b_] | complex.cpp:63:6:63:10 | inner [post update] [f, b_] |
|
||||
| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:63:12:63:12 | ref arg f [b_] |
|
||||
| complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] |
|
||||
| complex.cpp:64:6:64:10 | inner [post update] [f, a_] | complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] |
|
||||
| complex.cpp:64:12:64:12 | ref arg f [a_] | complex.cpp:64:6:64:10 | inner [post update] [f, a_] |
|
||||
| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:64:12:64:12 | ref arg f [a_] |
|
||||
| complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] |
|
||||
| complex.cpp:65:6:65:10 | inner [post update] [f, b_] | complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] |
|
||||
| complex.cpp:65:12:65:12 | ref arg f [b_] | complex.cpp:65:6:65:10 | inner [post update] [f, b_] |
|
||||
| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:65:12:65:12 | ref arg f [b_] |
|
||||
| complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] |
|
||||
| complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] |
|
||||
| complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] |
|
||||
| constructors.cpp:26:15:26:15 | f [a_] | constructors.cpp:28:10:28:10 | f [a_] |
|
||||
| constructors.cpp:26:15:26:15 | f [b_] | constructors.cpp:29:10:29:10 | f [b_] |
|
||||
| constructors.cpp:28:10:28:10 | f [a_] | constructors.cpp:28:12:28:12 | call to a |
|
||||
| constructors.cpp:29:10:29:10 | f [b_] | constructors.cpp:29:12:29:12 | call to b |
|
||||
| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:34:11:34:26 | call to Foo [a_] |
|
||||
| constructors.cpp:34:11:34:26 | call to Foo [a_] | constructors.cpp:40:9:40:9 | f [a_] |
|
||||
| constructors.cpp:35:11:35:26 | call to Foo [b_] | constructors.cpp:43:9:43:9 | g [b_] |
|
||||
| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:35:11:35:26 | call to Foo [b_] |
|
||||
| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [a_] |
|
||||
| constructors.cpp:36:11:36:37 | call to Foo [a_] | constructors.cpp:46:9:46:9 | h [a_] |
|
||||
| constructors.cpp:36:11:36:37 | call to Foo [b_] | constructors.cpp:46:9:46:9 | h [b_] |
|
||||
| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [b_] |
|
||||
| constructors.cpp:40:9:40:9 | f [a_] | constructors.cpp:26:15:26:15 | f [a_] |
|
||||
| constructors.cpp:43:9:43:9 | g [b_] | constructors.cpp:26:15:26:15 | f [b_] |
|
||||
| constructors.cpp:46:9:46:9 | h [a_] | constructors.cpp:26:15:26:15 | f [a_] |
|
||||
| constructors.cpp:46:9:46:9 | h [b_] | constructors.cpp:26:15:26:15 | f [b_] |
|
||||
| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] |
|
||||
| qualifiers.cpp:22:5:22:38 | ... = ... | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] |
|
||||
| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:22:5:22:38 | ... = ... |
|
||||
| qualifiers.cpp:23:10:23:14 | outer [inner, a] | qualifiers.cpp:23:16:23:20 | inner [a] |
|
||||
| qualifiers.cpp:23:16:23:20 | inner [a] | qualifiers.cpp:23:23:23:23 | a |
|
||||
| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] |
|
||||
| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] |
|
||||
| qualifiers.cpp:28:10:28:14 | outer [inner, a] | qualifiers.cpp:28:16:28:20 | inner [a] |
|
||||
| qualifiers.cpp:28:16:28:20 | inner [a] | qualifiers.cpp:28:23:28:23 | a |
|
||||
| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | qualifiers.cpp:33:10:33:14 | outer [inner, a] |
|
||||
| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] |
|
||||
| qualifiers.cpp:33:10:33:14 | outer [inner, a] | qualifiers.cpp:33:16:33:20 | inner [a] |
|
||||
| qualifiers.cpp:33:16:33:20 | inner [a] | qualifiers.cpp:33:23:33:23 | a |
|
||||
| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] |
|
||||
| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | qualifiers.cpp:38:10:38:14 | outer [inner, a] |
|
||||
| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] |
|
||||
| qualifiers.cpp:38:10:38:14 | outer [inner, a] | qualifiers.cpp:38:16:38:20 | inner [a] |
|
||||
| qualifiers.cpp:38:16:38:20 | inner [a] | qualifiers.cpp:38:23:38:23 | a |
|
||||
| qualifiers.cpp:42:5:42:40 | ... = ... | qualifiers.cpp:42:6:42:22 | * ... [post update] [a] |
|
||||
| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] |
|
||||
| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | qualifiers.cpp:43:10:43:14 | outer [inner, a] |
|
||||
| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:42:5:42:40 | ... = ... |
|
||||
| qualifiers.cpp:43:10:43:14 | outer [inner, a] | qualifiers.cpp:43:16:43:20 | inner [a] |
|
||||
| qualifiers.cpp:43:16:43:20 | inner [a] | qualifiers.cpp:43:23:43:23 | a |
|
||||
| qualifiers.cpp:47:5:47:42 | ... = ... | qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] |
|
||||
| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | qualifiers.cpp:48:10:48:14 | outer [inner, a] |
|
||||
| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] |
|
||||
| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:47:5:47:42 | ... = ... |
|
||||
| qualifiers.cpp:48:10:48:14 | outer [inner, a] | qualifiers.cpp:48:16:48:20 | inner [a] |
|
||||
| qualifiers.cpp:48:16:48:20 | inner [a] | qualifiers.cpp:48:23:48:23 | a |
|
||||
| simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] |
|
||||
| simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] |
|
||||
| simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a |
|
||||
| simple.cpp:29:10:29:10 | f [b_] | simple.cpp:29:12:29:12 | call to b |
|
||||
| simple.cpp:39:5:39:5 | ref arg f [a_] | simple.cpp:45:9:45:9 | f [a_] |
|
||||
| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | ref arg f [a_] |
|
||||
| simple.cpp:40:5:40:5 | ref arg g [b_] | simple.cpp:48:9:48:9 | g [b_] |
|
||||
| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | ref arg g [b_] |
|
||||
| simple.cpp:41:5:41:5 | ref arg h [a_] | simple.cpp:51:9:51:9 | h [a_] |
|
||||
| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | ref arg h [a_] |
|
||||
| simple.cpp:42:5:42:5 | ref arg h [b_] | simple.cpp:51:9:51:9 | h [b_] |
|
||||
| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | ref arg h [b_] |
|
||||
| simple.cpp:45:9:45:9 | f [a_] | simple.cpp:26:15:26:15 | f [a_] |
|
||||
| simple.cpp:48:9:48:9 | g [b_] | simple.cpp:26:15:26:15 | f [b_] |
|
||||
| simple.cpp:51:9:51:9 | h [a_] | simple.cpp:26:15:26:15 | f [a_] |
|
||||
| simple.cpp:51:9:51:9 | h [b_] | simple.cpp:26:15:26:15 | f [b_] |
|
||||
| simple.cpp:65:5:65:5 | a [post update] [i] | simple.cpp:67:10:67:11 | a2 [i] |
|
||||
| simple.cpp:65:5:65:22 | ... = ... | simple.cpp:65:5:65:5 | a [post update] [i] |
|
||||
| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | ... = ... |
|
||||
| simple.cpp:67:10:67:11 | a2 [i] | simple.cpp:67:13:67:13 | i |
|
||||
| simple.cpp:83:9:83:10 | f2 [post update] [f1] | simple.cpp:83:9:83:10 | this [post update] [f2, f1] |
|
||||
| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | simple.cpp:84:14:84:20 | this [f2, f1] |
|
||||
| simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] |
|
||||
| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... |
|
||||
| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 |
|
||||
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] |
|
||||
| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a |
|
||||
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] |
|
||||
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:24:10:24:12 | & ... [a] |
|
||||
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:28:5:28:7 | & ... [a] |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | {...} [a] |
|
||||
| struct_init.c:22:8:22:9 | ab [a] | struct_init.c:22:11:22:11 | a |
|
||||
| struct_init.c:24:10:24:12 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] |
|
||||
| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:31:8:31:12 | outer [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:36:11:36:15 | outer [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | struct_init.c:33:8:33:12 | outer [pointerAB, a] |
|
||||
| struct_init.c:27:5:27:23 | {...} [a] | struct_init.c:26:23:29:3 | {...} [nestedAB, a] |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | {...} [a] |
|
||||
| struct_init.c:28:5:28:7 | & ... [a] | struct_init.c:26:23:29:3 | {...} [pointerAB, a] |
|
||||
| struct_init.c:31:8:31:12 | outer [nestedAB, a] | struct_init.c:31:14:31:21 | nestedAB [a] |
|
||||
| struct_init.c:31:14:31:21 | nestedAB [a] | struct_init.c:31:23:31:23 | a |
|
||||
| struct_init.c:33:8:33:12 | outer [pointerAB, a] | struct_init.c:33:14:33:22 | pointerAB [a] |
|
||||
| struct_init.c:33:14:33:22 | pointerAB [a] | struct_init.c:33:25:33:25 | a |
|
||||
| struct_init.c:36:10:36:24 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] |
|
||||
| struct_init.c:36:11:36:15 | outer [nestedAB, a] | struct_init.c:36:17:36:24 | nestedAB [a] |
|
||||
| struct_init.c:36:17:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | & ... [a] |
|
||||
| struct_init.c:40:17:40:36 | {...} [a] | struct_init.c:43:5:43:7 | & ... [a] |
|
||||
| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:40:17:40:36 | {...} [a] |
|
||||
| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | struct_init.c:46:10:46:14 | outer [pointerAB, a] |
|
||||
| struct_init.c:43:5:43:7 | & ... [a] | struct_init.c:41:23:44:3 | {...} [pointerAB, a] |
|
||||
| struct_init.c:46:10:46:14 | outer [pointerAB, a] | struct_init.c:46:16:46:24 | pointerAB [a] |
|
||||
| struct_init.c:46:16:46:24 | pointerAB [a] | struct_init.c:14:24:14:25 | ab [a] |
|
||||
nodes
|
||||
| A.cpp:41:15:41:21 | new | semmle.label | new |
|
||||
| A.cpp:43:10:43:12 | & ... | semmle.label | & ... |
|
||||
| A.cpp:47:12:47:18 | new | semmle.label | new |
|
||||
| A.cpp:48:12:48:18 | call to make [c] | semmle.label | call to make [c] |
|
||||
| A.cpp:48:20:48:20 | c | semmle.label | c |
|
||||
| A.cpp:49:10:49:10 | b [c] | semmle.label | b [c] |
|
||||
| A.cpp:49:13:49:13 | c | semmle.label | c |
|
||||
| A.cpp:55:5:55:5 | ref arg b [c] | semmle.label | ref arg b [c] |
|
||||
| A.cpp:55:12:55:19 | new | semmle.label | new |
|
||||
| A.cpp:56:10:56:10 | b [c] | semmle.label | b [c] |
|
||||
| A.cpp:56:13:56:15 | call to get | semmle.label | call to get |
|
||||
| A.cpp:57:11:57:24 | call to B [c] | semmle.label | call to B [c] |
|
||||
| A.cpp:57:11:57:24 | new [c] | semmle.label | new [c] |
|
||||
| A.cpp:57:17:57:23 | new | semmle.label | new |
|
||||
| A.cpp:57:28:57:30 | call to get | semmle.label | call to get |
|
||||
| A.cpp:64:10:64:15 | call to setOnB [c] | semmle.label | call to setOnB [c] |
|
||||
| A.cpp:64:21:64:28 | new | semmle.label | new |
|
||||
| A.cpp:66:10:66:11 | b2 [c] | semmle.label | b2 [c] |
|
||||
| A.cpp:66:14:66:14 | c | semmle.label | c |
|
||||
| A.cpp:73:10:73:19 | call to setOnBWrap [c] | semmle.label | call to setOnBWrap [c] |
|
||||
| A.cpp:73:25:73:32 | new | semmle.label | new |
|
||||
| A.cpp:75:10:75:11 | b2 [c] | semmle.label | b2 [c] |
|
||||
| A.cpp:75:14:75:14 | c | semmle.label | c |
|
||||
| A.cpp:98:12:98:18 | new | semmle.label | new |
|
||||
| A.cpp:100:5:100:6 | c1 [post update] [a] | semmle.label | c1 [post update] [a] |
|
||||
| A.cpp:100:5:100:13 | ... = ... | semmle.label | ... = ... |
|
||||
| A.cpp:101:8:101:9 | c1 [a] | semmle.label | c1 [a] |
|
||||
| A.cpp:103:14:103:14 | c [a] | semmle.label | c [a] |
|
||||
| A.cpp:107:12:107:13 | c1 [a] | semmle.label | c1 [a] |
|
||||
| A.cpp:107:16:107:16 | a | semmle.label | a |
|
||||
| A.cpp:120:12:120:13 | c1 [a] | semmle.label | c1 [a] |
|
||||
| A.cpp:120:16:120:16 | a | semmle.label | a |
|
||||
| A.cpp:126:5:126:5 | ref arg b [c] | semmle.label | ref arg b [c] |
|
||||
| A.cpp:126:12:126:18 | new | semmle.label | new |
|
||||
| A.cpp:131:8:131:8 | ref arg b [c] | semmle.label | ref arg b [c] |
|
||||
| A.cpp:132:10:132:10 | b [c] | semmle.label | b [c] |
|
||||
| A.cpp:132:13:132:13 | c | semmle.label | c |
|
||||
| A.cpp:142:7:142:7 | b [post update] [c] | semmle.label | b [post update] [c] |
|
||||
| A.cpp:142:7:142:20 | ... = ... | semmle.label | ... = ... |
|
||||
| A.cpp:142:14:142:20 | new | semmle.label | new |
|
||||
| A.cpp:143:7:143:10 | this [post update] [b, c] | semmle.label | this [post update] [b, c] |
|
||||
| A.cpp:143:7:143:10 | this [post update] [b] | semmle.label | this [post update] [b] |
|
||||
| A.cpp:143:7:143:31 | ... = ... | semmle.label | ... = ... |
|
||||
| A.cpp:143:7:143:31 | ... = ... [c] | semmle.label | ... = ... [c] |
|
||||
| A.cpp:143:25:143:31 | new | semmle.label | new |
|
||||
| A.cpp:150:12:150:18 | new | semmle.label | new |
|
||||
| A.cpp:151:12:151:24 | call to D [b, c] | semmle.label | call to D [b, c] |
|
||||
| A.cpp:151:12:151:24 | call to D [b] | semmle.label | call to D [b] |
|
||||
| A.cpp:151:18:151:18 | b | semmle.label | b |
|
||||
| A.cpp:151:18:151:18 | ref arg b [c] | semmle.label | ref arg b [c] |
|
||||
| A.cpp:152:10:152:10 | d [b] | semmle.label | d [b] |
|
||||
| A.cpp:152:13:152:13 | b | semmle.label | b |
|
||||
| A.cpp:153:10:153:10 | d [b, c] | semmle.label | d [b, c] |
|
||||
| A.cpp:153:13:153:13 | b [c] | semmle.label | b [c] |
|
||||
| A.cpp:153:16:153:16 | c | semmle.label | c |
|
||||
| A.cpp:154:10:154:10 | b [c] | semmle.label | b [c] |
|
||||
| A.cpp:154:13:154:13 | c | semmle.label | c |
|
||||
| A.cpp:159:12:159:18 | new | semmle.label | new |
|
||||
| A.cpp:160:18:160:60 | call to MyList [head] | semmle.label | call to MyList [head] |
|
||||
| A.cpp:160:29:160:29 | b | semmle.label | b |
|
||||
| A.cpp:161:18:161:40 | call to MyList [next, head] | semmle.label | call to MyList [next, head] |
|
||||
| A.cpp:161:38:161:39 | l1 [head] | semmle.label | l1 [head] |
|
||||
| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | semmle.label | call to MyList [next, next, ... (3)] |
|
||||
| A.cpp:162:38:162:39 | l2 [next, head] | semmle.label | l2 [next, head] |
|
||||
| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | semmle.label | l3 [next, next, ... (3)] |
|
||||
| A.cpp:165:14:165:17 | next [next, head] | semmle.label | next [next, head] |
|
||||
| A.cpp:165:20:165:23 | next [head] | semmle.label | next [head] |
|
||||
| A.cpp:165:26:165:29 | head | semmle.label | head |
|
||||
| A.cpp:167:44:167:44 | l [next, head] | semmle.label | l [next, head] |
|
||||
| A.cpp:167:44:167:44 | l [next, next, ... (3)] | semmle.label | l [next, next, ... (3)] |
|
||||
| A.cpp:167:47:167:50 | next [head] | semmle.label | next [head] |
|
||||
| A.cpp:167:47:167:50 | next [next, head] | semmle.label | next [next, head] |
|
||||
| A.cpp:169:12:169:12 | l [head] | semmle.label | l [head] |
|
||||
| A.cpp:169:15:169:18 | head | semmle.label | head |
|
||||
| B.cpp:6:15:6:24 | new | semmle.label | new |
|
||||
| B.cpp:7:16:7:35 | call to Box1 [elem1] | semmle.label | call to Box1 [elem1] |
|
||||
| B.cpp:7:25:7:25 | e | semmle.label | e |
|
||||
| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | semmle.label | call to Box2 [box1, elem1] |
|
||||
| B.cpp:8:25:8:26 | b1 [elem1] | semmle.label | b1 [elem1] |
|
||||
| B.cpp:9:10:9:11 | b2 [box1, elem1] | semmle.label | b2 [box1, elem1] |
|
||||
| B.cpp:9:14:9:17 | box1 [elem1] | semmle.label | box1 [elem1] |
|
||||
| B.cpp:9:20:9:24 | elem1 | semmle.label | elem1 |
|
||||
| B.cpp:15:15:15:27 | new | semmle.label | new |
|
||||
| B.cpp:16:16:16:38 | call to Box1 [elem2] | semmle.label | call to Box1 [elem2] |
|
||||
| B.cpp:16:37:16:37 | e | semmle.label | e |
|
||||
| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | semmle.label | call to Box2 [box1, elem2] |
|
||||
| B.cpp:17:25:17:26 | b1 [elem2] | semmle.label | b1 [elem2] |
|
||||
| B.cpp:19:10:19:11 | b2 [box1, elem2] | semmle.label | b2 [box1, elem2] |
|
||||
| B.cpp:19:14:19:17 | box1 [elem2] | semmle.label | box1 [elem2] |
|
||||
| B.cpp:19:20:19:24 | elem2 | semmle.label | elem2 |
|
||||
| C.cpp:18:12:18:18 | call to C [s1] | semmle.label | call to C [s1] |
|
||||
| C.cpp:18:12:18:18 | call to C [s3] | semmle.label | call to C [s3] |
|
||||
| C.cpp:19:5:19:5 | c [s1] | semmle.label | c [s1] |
|
||||
| C.cpp:19:5:19:5 | c [s3] | semmle.label | c [s3] |
|
||||
| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | semmle.label | constructor init of field s1 [post-this] [s1] |
|
||||
| C.cpp:22:12:22:21 | new | semmle.label | new |
|
||||
| C.cpp:24:5:24:8 | this [post update] [s3] | semmle.label | this [post update] [s3] |
|
||||
| C.cpp:24:5:24:25 | ... = ... | semmle.label | ... = ... |
|
||||
| C.cpp:24:16:24:25 | new | semmle.label | new |
|
||||
| C.cpp:27:8:27:11 | this [s1] | semmle.label | this [s1] |
|
||||
| C.cpp:27:8:27:11 | this [s3] | semmle.label | this [s3] |
|
||||
| C.cpp:29:10:29:11 | s1 | semmle.label | s1 |
|
||||
| C.cpp:29:10:29:11 | this [s1] | semmle.label | this [s1] |
|
||||
| C.cpp:31:10:31:11 | s3 | semmle.label | s3 |
|
||||
| C.cpp:31:10:31:11 | this [s3] | semmle.label | this [s3] |
|
||||
| D.cpp:21:30:21:31 | b2 [box, elem] | semmle.label | b2 [box, elem] |
|
||||
| D.cpp:22:10:22:11 | b2 [box, elem] | semmle.label | b2 [box, elem] |
|
||||
| D.cpp:22:14:22:20 | call to getBox1 [elem] | semmle.label | call to getBox1 [elem] |
|
||||
| D.cpp:22:25:22:31 | call to getElem | semmle.label | call to getElem |
|
||||
| D.cpp:28:15:28:24 | new | semmle.label | new |
|
||||
| D.cpp:30:5:30:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] |
|
||||
| D.cpp:30:5:30:20 | ... = ... | semmle.label | ... = ... |
|
||||
| D.cpp:30:8:30:10 | box [post update] [elem] | semmle.label | box [post update] [elem] |
|
||||
| D.cpp:31:14:31:14 | b [box, elem] | semmle.label | b [box, elem] |
|
||||
| D.cpp:35:15:35:24 | new | semmle.label | new |
|
||||
| D.cpp:37:5:37:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] |
|
||||
| D.cpp:37:8:37:10 | ref arg box [elem] | semmle.label | ref arg box [elem] |
|
||||
| D.cpp:37:21:37:21 | e | semmle.label | e |
|
||||
| D.cpp:38:14:38:14 | b [box, elem] | semmle.label | b [box, elem] |
|
||||
| D.cpp:42:15:42:24 | new | semmle.label | new |
|
||||
| D.cpp:44:5:44:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] |
|
||||
| D.cpp:44:5:44:26 | ... = ... | semmle.label | ... = ... |
|
||||
| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] |
|
||||
| D.cpp:45:14:45:14 | b [box, elem] | semmle.label | b [box, elem] |
|
||||
| D.cpp:49:15:49:24 | new | semmle.label | new |
|
||||
| D.cpp:51:5:51:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] |
|
||||
| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | semmle.label | ref arg call to getBox1 [elem] |
|
||||
| D.cpp:51:27:51:27 | e | semmle.label | e |
|
||||
| D.cpp:52:14:52:14 | b [box, elem] | semmle.label | b [box, elem] |
|
||||
| D.cpp:56:15:56:24 | new | semmle.label | new |
|
||||
| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | semmle.label | boxfield [post update] [box, elem] |
|
||||
| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | semmle.label | this [post update] [boxfield, box, ... (3)] |
|
||||
| D.cpp:58:5:58:27 | ... = ... | semmle.label | ... = ... |
|
||||
| D.cpp:58:15:58:17 | box [post update] [elem] | semmle.label | box [post update] [elem] |
|
||||
| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] |
|
||||
| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] |
|
||||
| D.cpp:64:10:64:17 | boxfield [box, elem] | semmle.label | boxfield [box, elem] |
|
||||
| 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 |
|
||||
| aliasing.cpp:12:25:12:25 | s [m1] | semmle.label | s [m1] |
|
||||
| aliasing.cpp:13:3:13:3 | s [post update] [m1] | semmle.label | s [post update] [m1] |
|
||||
| aliasing.cpp:13:3:13:21 | ... = ... | semmle.label | ... = ... |
|
||||
| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | semmle.label | ref arg & ... [m1] |
|
||||
| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | semmle.label | ref arg s2 [m1] |
|
||||
| aliasing.cpp:29:8:29:9 | s1 [m1] | semmle.label | s1 [m1] |
|
||||
| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:30:8:30:9 | s2 [m1] | semmle.label | s2 [m1] |
|
||||
| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | semmle.label | s2 [post update] [m1] |
|
||||
| aliasing.cpp:60:3:60:22 | ... = ... | semmle.label | ... = ... |
|
||||
| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:62:8:62:12 | copy2 [m1] | semmle.label | copy2 [m1] |
|
||||
| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 |
|
||||
| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | semmle.label | w [post update] [s, m1] |
|
||||
| aliasing.cpp:92:3:92:23 | ... = ... | semmle.label | ... = ... |
|
||||
| aliasing.cpp:92:5:92:5 | s [post update] [m1] | semmle.label | s [post update] [m1] |
|
||||
| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input |
|
||||
| aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] |
|
||||
| aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] |
|
||||
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
|
||||
| by_reference.cpp:50:3:50:3 | ref arg s [a] | semmle.label | ref arg s [a] |
|
||||
| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] |
|
||||
| by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly |
|
||||
| by_reference.cpp:56:3:56:3 | ref arg s [a] | semmle.label | ref arg s [a] |
|
||||
| by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:57:8:57:8 | s [a] | semmle.label | s [a] |
|
||||
| by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly |
|
||||
| by_reference.cpp:62:3:62:3 | ref arg s [a] | semmle.label | ref arg s [a] |
|
||||
| by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:63:8:63:8 | s [a] | semmle.label | s [a] |
|
||||
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember |
|
||||
| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | semmle.label | ref arg & ... [a] |
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA |
|
||||
| by_reference.cpp:69:22:69:23 | & ... [a] | semmle.label | & ... [a] |
|
||||
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | semmle.label | inner [post update] [a] |
|
||||
| by_reference.cpp:84:3:84:25 | ... = ... | semmle.label | ... = ... |
|
||||
| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:87:31:87:35 | inner [a] | semmle.label | inner [a] |
|
||||
| by_reference.cpp:88:3:88:7 | inner [post update] [a] | semmle.label | inner [post update] [a] |
|
||||
| by_reference.cpp:88:3:88:24 | ... = ... | semmle.label | ... = ... |
|
||||
| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:95:25:95:26 | pa | semmle.label | pa |
|
||||
| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | semmle.label | ref arg & ... [a] |
|
||||
| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] |
|
||||
| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] |
|
||||
| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] |
|
||||
| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] |
|
||||
| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | semmle.label | ref arg & ... [a] |
|
||||
| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] |
|
||||
| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] |
|
||||
| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] |
|
||||
| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] |
|
||||
| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] |
|
||||
| by_reference.cpp:110:14:110:25 | inner_nested [a] | semmle.label | inner_nested [a] |
|
||||
| by_reference.cpp:110:27:110:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] |
|
||||
| by_reference.cpp:111:14:111:22 | inner_ptr [a] | semmle.label | inner_ptr [a] |
|
||||
| by_reference.cpp:111:25:111:25 | a | semmle.label | a |
|
||||
| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] |
|
||||
| by_reference.cpp:114:16:114:27 | inner_nested [a] | semmle.label | inner_nested [a] |
|
||||
| by_reference.cpp:114:29:114:29 | a | semmle.label | a |
|
||||
| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] |
|
||||
| by_reference.cpp:115:16:115:24 | inner_ptr [a] | semmle.label | inner_ptr [a] |
|
||||
| by_reference.cpp:115:27:115:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] |
|
||||
| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] |
|
||||
| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | semmle.label | ref arg * ... [a] |
|
||||
| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] |
|
||||
| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] |
|
||||
| by_reference.cpp:124:15:124:19 | outer [post update] [a] | semmle.label | outer [post update] [a] |
|
||||
| by_reference.cpp:124:21:124:21 | ref arg a | semmle.label | ref arg a |
|
||||
| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] |
|
||||
| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] |
|
||||
| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | semmle.label | ref arg * ... [a] |
|
||||
| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] |
|
||||
| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] |
|
||||
| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | semmle.label | pouter [post update] [a] |
|
||||
| by_reference.cpp:128:23:128:23 | ref arg a | semmle.label | ref arg a |
|
||||
| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] |
|
||||
| by_reference.cpp:130:14:130:25 | inner_nested [a] | semmle.label | inner_nested [a] |
|
||||
| by_reference.cpp:130:27:130:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] |
|
||||
| by_reference.cpp:131:14:131:22 | inner_ptr [a] | semmle.label | inner_ptr [a] |
|
||||
| by_reference.cpp:131:25:131:25 | a | semmle.label | a |
|
||||
| by_reference.cpp:132:8:132:12 | outer [a] | semmle.label | outer [a] |
|
||||
| by_reference.cpp:132:14:132:14 | a | semmle.label | a |
|
||||
| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] |
|
||||
| by_reference.cpp:134:16:134:27 | inner_nested [a] | semmle.label | inner_nested [a] |
|
||||
| by_reference.cpp:134:29:134:29 | a | semmle.label | a |
|
||||
| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] |
|
||||
| by_reference.cpp:135:16:135:24 | inner_ptr [a] | semmle.label | inner_ptr [a] |
|
||||
| by_reference.cpp:135:27:135:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] |
|
||||
| by_reference.cpp:136:16:136:16 | a | semmle.label | a |
|
||||
| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] |
|
||||
| complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] |
|
||||
| complex.cpp:51:10:51:14 | inner [f, a_] | semmle.label | inner [f, a_] |
|
||||
| complex.cpp:51:16:51:16 | f [a_] | semmle.label | f [a_] |
|
||||
| complex.cpp:51:18:51:18 | call to a | semmle.label | call to a |
|
||||
| complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] |
|
||||
| complex.cpp:52:10:52:14 | inner [f, b_] | semmle.label | inner [f, b_] |
|
||||
| complex.cpp:52:16:52:16 | f [b_] | semmle.label | f [b_] |
|
||||
| complex.cpp:52:18:52:18 | call to b | semmle.label | call to b |
|
||||
| complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | semmle.label | b1 [post update] [inner, f, ... (3)] |
|
||||
| complex.cpp:62:6:62:10 | inner [post update] [f, a_] | semmle.label | inner [post update] [f, a_] |
|
||||
| complex.cpp:62:12:62:12 | ref arg f [a_] | semmle.label | ref arg f [a_] |
|
||||
| complex.cpp:62:19:62:28 | call to user_input | semmle.label | call to user_input |
|
||||
| complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | semmle.label | b2 [post update] [inner, f, ... (3)] |
|
||||
| complex.cpp:63:6:63:10 | inner [post update] [f, b_] | semmle.label | inner [post update] [f, b_] |
|
||||
| complex.cpp:63:12:63:12 | ref arg f [b_] | semmle.label | ref arg f [b_] |
|
||||
| complex.cpp:63:19:63:28 | call to user_input | semmle.label | call to user_input |
|
||||
| complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | semmle.label | b3 [post update] [inner, f, ... (3)] |
|
||||
| complex.cpp:64:6:64:10 | inner [post update] [f, a_] | semmle.label | inner [post update] [f, a_] |
|
||||
| complex.cpp:64:12:64:12 | ref arg f [a_] | semmle.label | ref arg f [a_] |
|
||||
| complex.cpp:64:19:64:28 | call to user_input | semmle.label | call to user_input |
|
||||
| complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | semmle.label | b3 [post update] [inner, f, ... (3)] |
|
||||
| complex.cpp:65:6:65:10 | inner [post update] [f, b_] | semmle.label | inner [post update] [f, b_] |
|
||||
| complex.cpp:65:12:65:12 | ref arg f [b_] | semmle.label | ref arg f [b_] |
|
||||
| complex.cpp:65:19:65:28 | call to user_input | semmle.label | call to user_input |
|
||||
| complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | semmle.label | b1 [inner, f, ... (3)] |
|
||||
| complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | semmle.label | b2 [inner, f, ... (3)] |
|
||||
| complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | semmle.label | b3 [inner, f, ... (3)] |
|
||||
| constructors.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] |
|
||||
| constructors.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] |
|
||||
| constructors.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] |
|
||||
| constructors.cpp:28:12:28:12 | call to a | semmle.label | call to a |
|
||||
| constructors.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] |
|
||||
| constructors.cpp:29:12:29:12 | call to b | semmle.label | call to b |
|
||||
| constructors.cpp:34:11:34:20 | call to user_input | semmle.label | call to user_input |
|
||||
| constructors.cpp:34:11:34:26 | call to Foo [a_] | semmle.label | call to Foo [a_] |
|
||||
| constructors.cpp:35:11:35:26 | call to Foo [b_] | semmle.label | call to Foo [b_] |
|
||||
| constructors.cpp:35:14:35:23 | call to user_input | semmle.label | call to user_input |
|
||||
| constructors.cpp:36:11:36:20 | call to user_input | semmle.label | call to user_input |
|
||||
| constructors.cpp:36:11:36:37 | call to Foo [a_] | semmle.label | call to Foo [a_] |
|
||||
| constructors.cpp:36:11:36:37 | call to Foo [b_] | semmle.label | call to Foo [b_] |
|
||||
| constructors.cpp:36:25:36:34 | call to user_input | semmle.label | call to user_input |
|
||||
| constructors.cpp:40:9:40:9 | f [a_] | semmle.label | f [a_] |
|
||||
| constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] |
|
||||
| constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] |
|
||||
| constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] |
|
||||
| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:22:5:22:38 | ... = ... | semmle.label | ... = ... |
|
||||
| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] |
|
||||
| qualifiers.cpp:22:27:22:36 | call to user_input | semmle.label | call to user_input |
|
||||
| qualifiers.cpp:23:10:23:14 | outer [inner, a] | semmle.label | outer [inner, a] |
|
||||
| qualifiers.cpp:23:16:23:20 | inner [a] | semmle.label | inner [a] |
|
||||
| qualifiers.cpp:23:23:23:23 | a | semmle.label | a |
|
||||
| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] |
|
||||
| qualifiers.cpp:27:28:27:37 | call to user_input | semmle.label | call to user_input |
|
||||
| qualifiers.cpp:28:10:28:14 | outer [inner, a] | semmle.label | outer [inner, a] |
|
||||
| qualifiers.cpp:28:16:28:20 | inner [a] | semmle.label | inner [a] |
|
||||
| qualifiers.cpp:28:23:28:23 | a | semmle.label | a |
|
||||
| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] |
|
||||
| qualifiers.cpp:32:35:32:44 | call to user_input | semmle.label | call to user_input |
|
||||
| qualifiers.cpp:33:10:33:14 | outer [inner, a] | semmle.label | outer [inner, a] |
|
||||
| qualifiers.cpp:33:16:33:20 | inner [a] | semmle.label | inner [a] |
|
||||
| qualifiers.cpp:33:23:33:23 | a | semmle.label | a |
|
||||
| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | semmle.label | ref arg * ... [a] |
|
||||
| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] |
|
||||
| qualifiers.cpp:37:38:37:47 | call to user_input | semmle.label | call to user_input |
|
||||
| qualifiers.cpp:38:10:38:14 | outer [inner, a] | semmle.label | outer [inner, a] |
|
||||
| qualifiers.cpp:38:16:38:20 | inner [a] | semmle.label | inner [a] |
|
||||
| qualifiers.cpp:38:23:38:23 | a | semmle.label | a |
|
||||
| qualifiers.cpp:42:5:42:40 | ... = ... | semmle.label | ... = ... |
|
||||
| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | semmle.label | * ... [post update] [a] |
|
||||
| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] |
|
||||
| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] |
|
||||
| qualifiers.cpp:42:29:42:38 | call to user_input | semmle.label | call to user_input |
|
||||
| qualifiers.cpp:43:10:43:14 | outer [inner, a] | semmle.label | outer [inner, a] |
|
||||
| qualifiers.cpp:43:16:43:20 | inner [a] | semmle.label | inner [a] |
|
||||
| qualifiers.cpp:43:23:43:23 | a | semmle.label | a |
|
||||
| qualifiers.cpp:47:5:47:42 | ... = ... | semmle.label | ... = ... |
|
||||
| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | semmle.label | ref arg & ... [inner, a] |
|
||||
| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] |
|
||||
| qualifiers.cpp:47:31:47:40 | call to user_input | semmle.label | call to user_input |
|
||||
| qualifiers.cpp:48:10:48:14 | outer [inner, a] | semmle.label | outer [inner, a] |
|
||||
| qualifiers.cpp:48:16:48:20 | inner [a] | semmle.label | inner [a] |
|
||||
| qualifiers.cpp:48:23:48:23 | a | semmle.label | a |
|
||||
| simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] |
|
||||
| simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] |
|
||||
| simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] |
|
||||
| simple.cpp:28:12:28:12 | call to a | semmle.label | call to a |
|
||||
| simple.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] |
|
||||
| simple.cpp:29:12:29:12 | call to b | semmle.label | call to b |
|
||||
| simple.cpp:39:5:39:5 | ref arg f [a_] | semmle.label | ref arg f [a_] |
|
||||
| simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:40:5:40:5 | ref arg g [b_] | semmle.label | ref arg g [b_] |
|
||||
| simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:41:5:41:5 | ref arg h [a_] | semmle.label | ref arg h [a_] |
|
||||
| simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:42:5:42:5 | ref arg h [b_] | semmle.label | ref arg h [b_] |
|
||||
| simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:45:9:45:9 | f [a_] | semmle.label | f [a_] |
|
||||
| simple.cpp:48:9:48:9 | g [b_] | semmle.label | g [b_] |
|
||||
| simple.cpp:51:9:51:9 | h [a_] | semmle.label | h [a_] |
|
||||
| simple.cpp:51:9:51:9 | h [b_] | semmle.label | h [b_] |
|
||||
| simple.cpp:65:5:65:5 | a [post update] [i] | semmle.label | a [post update] [i] |
|
||||
| simple.cpp:65:5:65:22 | ... = ... | semmle.label | ... = ... |
|
||||
| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:67:10:67:11 | a2 [i] | semmle.label | a2 [i] |
|
||||
| simple.cpp:67:13:67:13 | i | semmle.label | i |
|
||||
| simple.cpp:83:9:83:10 | f2 [post update] [f1] | semmle.label | f2 [post update] [f1] |
|
||||
| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | semmle.label | this [post update] [f2, f1] |
|
||||
| simple.cpp:83:9:83:28 | ... = ... | semmle.label | ... = ... |
|
||||
| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input |
|
||||
| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 |
|
||||
| simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] |
|
||||
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
|
||||
| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] |
|
||||
| struct_init.c:15:12:15:12 | a | semmle.label | a |
|
||||
| struct_init.c:20:17:20:36 | {...} [a] | semmle.label | {...} [a] |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:22:8:22:9 | ab [a] | semmle.label | ab [a] |
|
||||
| struct_init.c:22:11:22:11 | a | semmle.label | a |
|
||||
| struct_init.c:24:10:24:12 | & ... [a] | semmle.label | & ... [a] |
|
||||
| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | semmle.label | {...} [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] |
|
||||
| struct_init.c:27:5:27:23 | {...} [a] | semmle.label | {...} [a] |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:28:5:28:7 | & ... [a] | semmle.label | & ... [a] |
|
||||
| struct_init.c:31:8:31:12 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] |
|
||||
| struct_init.c:31:14:31:21 | nestedAB [a] | semmle.label | nestedAB [a] |
|
||||
| struct_init.c:31:23:31:23 | a | semmle.label | a |
|
||||
| struct_init.c:33:8:33:12 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] |
|
||||
| struct_init.c:33:14:33:22 | pointerAB [a] | semmle.label | pointerAB [a] |
|
||||
| struct_init.c:33:25:33:25 | a | semmle.label | a |
|
||||
| struct_init.c:36:10:36:24 | & ... [a] | semmle.label | & ... [a] |
|
||||
| struct_init.c:36:11:36:15 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] |
|
||||
| struct_init.c:36:17:36:24 | nestedAB [a] | semmle.label | nestedAB [a] |
|
||||
| struct_init.c:40:17:40:36 | {...} [a] | semmle.label | {...} [a] |
|
||||
| struct_init.c:40:20:40:29 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] |
|
||||
| struct_init.c:43:5:43:7 | & ... [a] | semmle.label | & ... [a] |
|
||||
| struct_init.c:46:10:46:14 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] |
|
||||
| struct_init.c:46:16:46:24 | pointerAB [a] | semmle.label | pointerAB [a] |
|
||||
#select
|
||||
| A.cpp:43:10:43:12 | & ... | A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | & ... flows from $@ | A.cpp:41:15:41:21 | new | new |
|
||||
| A.cpp:49:13:49:13 | c | A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | c flows from $@ | A.cpp:47:12:47:18 | new | new |
|
||||
| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new |
|
||||
| A.cpp:57:28:57:30 | call to get | A.cpp:57:17:57:23 | new | A.cpp:57:28:57:30 | call to get | call to get flows from $@ | A.cpp:57:17:57:23 | new | new |
|
||||
| A.cpp:66:14:66:14 | c | A.cpp:64:21:64:28 | new | A.cpp:66:14:66:14 | c | c flows from $@ | A.cpp:64:21:64:28 | new | new |
|
||||
| A.cpp:75:14:75:14 | c | A.cpp:73:25:73:32 | new | A.cpp:75:14:75:14 | c | c flows from $@ | A.cpp:73:25:73:32 | new | new |
|
||||
| A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new |
|
||||
| A.cpp:120:16:120:16 | a | A.cpp:98:12:98:18 | new | A.cpp:120:16:120:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new |
|
||||
| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new | new |
|
||||
| A.cpp:152:13:152:13 | b | A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:143:25:143:31 | new | new |
|
||||
| A.cpp:152:13:152:13 | b | A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:150:12:150:18 | new | new |
|
||||
| A.cpp:153:16:153:16 | c | A.cpp:142:14:142:20 | new | A.cpp:153:16:153:16 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new |
|
||||
| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new |
|
||||
| A.cpp:165:26:165:29 | head | A.cpp:159:12:159:18 | new | A.cpp:165:26:165:29 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new |
|
||||
| A.cpp:169:15:169:18 | head | A.cpp:159:12:159:18 | new | A.cpp:169:15:169:18 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new |
|
||||
| B.cpp:9:20:9:24 | elem1 | B.cpp:6:15:6:24 | new | B.cpp:9:20:9:24 | elem1 | elem1 flows from $@ | B.cpp:6:15:6:24 | new | new |
|
||||
| B.cpp:19:20:19:24 | elem2 | B.cpp:15:15:15:27 | new | B.cpp:19:20:19:24 | elem2 | elem2 flows from $@ | B.cpp:15:15:15:27 | new | new |
|
||||
| C.cpp:29:10:29:11 | s1 | C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | s1 flows from $@ | C.cpp:22:12:22:21 | new | new |
|
||||
| C.cpp:31:10:31:11 | s3 | C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | s3 flows from $@ | C.cpp:24:16:24:25 | new | new |
|
||||
| D.cpp:22:25:22:31 | call to getElem | D.cpp:28:15:28:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:28:15:28:24 | new | new |
|
||||
| D.cpp:22:25:22:31 | call to getElem | D.cpp:35:15:35:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:35:15:35:24 | new | new |
|
||||
| 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 |
|
||||
| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:111:25:111:25 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:115:27:115:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:131:25:131:25 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input |
|
||||
| complex.cpp:51:18:51:18 | call to a | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:51:18:51:18 | call to a | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:51:18:51:18 | call to a | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:51:18:51:18 | call to a | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:52:18:52:18 | call to b | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:52:18:52:18 | call to b | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:52:18:52:18 | call to b | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:52:18:52:18 | call to b | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input |
|
||||
| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input |
|
||||
| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input |
|
||||
| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input |
|
||||
| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input |
|
||||
| qualifiers.cpp:23:23:23:23 | a | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | a flows from $@ | qualifiers.cpp:22:27:22:36 | call to user_input | call to user_input |
|
||||
| qualifiers.cpp:28:23:28:23 | a | qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | a flows from $@ | qualifiers.cpp:27:28:27:37 | call to user_input | call to user_input |
|
||||
| qualifiers.cpp:33:23:33:23 | a | qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | a flows from $@ | qualifiers.cpp:32:35:32:44 | call to user_input | call to user_input |
|
||||
| qualifiers.cpp:38:23:38:23 | a | qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | a flows from $@ | qualifiers.cpp:37:38:37:47 | call to user_input | call to user_input |
|
||||
| qualifiers.cpp:43:23:43:23 | a | qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | a flows from $@ | qualifiers.cpp:42:29:42:38 | call to user_input | call to user_input |
|
||||
| qualifiers.cpp:48:23:48:23 | a | qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | a flows from $@ | qualifiers.cpp:47:31:47:40 | call to user_input | call to user_input |
|
||||
| simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input |
|
||||
| simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input |
|
||||
| simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input |
|
||||
| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input |
|
||||
| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input |
|
||||
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input |
|
||||
| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||
| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
||||
| struct_init.c:33:25:33:25 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:33:25:33:25 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||
12
cpp/ql/test/library-tests/dataflow/fields/path-flow.ql
Normal file
12
cpp/ql/test/library-tests/dataflow/fields/path-flow.ql
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
import ASTConfiguration
|
||||
import cpp
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf
|
||||
where conf.hasFlowPath(src, sink)
|
||||
select sink, src, sink, sink + " flows from $@", src, src.toString()
|
||||
@@ -81,7 +81,7 @@ struct C2
|
||||
|
||||
void m() {
|
||||
f2.f1 = user_input();
|
||||
sink(getf2f1()); //$ast $f-:ir
|
||||
sink(getf2f1()); //$ast,ir
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ struct Outer {
|
||||
};
|
||||
|
||||
void absink(struct AB *ab) {
|
||||
sink(ab->a); //$ast=20:20 $ast=27:7 $ast=40:20 $f-:ir
|
||||
sink(ab->a); //$ast,ir=20:20 $ast,ir=27:7 $ast=40:20 $f-:ir
|
||||
sink(ab->b); // no flow
|
||||
}
|
||||
|
||||
|
||||
@@ -23,14 +23,9 @@
|
||||
| taint.cpp:130:7:130:9 | taint.cpp:127:8:127:13 | IR only |
|
||||
| taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only |
|
||||
| taint.cpp:173:8:173:13 | taint.cpp:164:19:164:24 | AST only |
|
||||
| taint.cpp:181:8:181:9 | taint.cpp:185:11:185:16 | AST only |
|
||||
| taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only |
|
||||
| taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only |
|
||||
| taint.cpp:229:3:229:6 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:233:8:233:8 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:244:3:244:6 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:256:8:256:8 | taint.cpp:223:10:223:15 | AST only |
|
||||
| taint.cpp:261:7:261:7 | taint.cpp:258:7:258:12 | AST only |
|
||||
| taint.cpp:351:7:351:7 | taint.cpp:330:6:330:11 | AST only |
|
||||
| taint.cpp:352:7:352:7 | taint.cpp:330:6:330:11 | AST only |
|
||||
|
||||
@@ -21,10 +21,15 @@
|
||||
| taint.cpp:151:7:151:12 | call to select | taint.cpp:151:20:151:25 | call to source |
|
||||
| taint.cpp:167:8:167:13 | call to source | taint.cpp:167:8:167:13 | call to source |
|
||||
| taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source |
|
||||
| taint.cpp:181:8:181:9 | * ... | taint.cpp:185:11:185:16 | call to source |
|
||||
| taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source |
|
||||
| taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source |
|
||||
| taint.cpp:216:7:216:7 | y | taint.cpp:207:6:207:11 | call to source |
|
||||
| taint.cpp:229:3:229:6 | t | taint.cpp:223:10:223:15 | call to source |
|
||||
| taint.cpp:233:8:233:8 | call to operator() | taint.cpp:223:10:223:15 | call to source |
|
||||
| taint.cpp:244:3:244:6 | t | taint.cpp:223:10:223:15 | call to source |
|
||||
| taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source |
|
||||
| taint.cpp:256:8:256:8 | (reference dereference) | taint.cpp:223:10:223:15 | call to source |
|
||||
| taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source |
|
||||
| taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source |
|
||||
| taint.cpp:290:7:290:7 | x | taint.cpp:275:6:275:11 | call to source |
|
||||
|
||||
@@ -10483,6 +10483,35 @@ ir.cpp:
|
||||
# 1315| 2: [VariableAccess] y
|
||||
# 1315| Type = [IntType] int
|
||||
# 1315| ValueCategory = prvalue(load)
|
||||
# 1318| [Operator,TopLevelFunction] void* operator new(size_t, void*)
|
||||
# 1318| params:
|
||||
# 1318| 0: [Parameter] p#0
|
||||
# 1318| Type = [CTypedefType,Size_t] size_t
|
||||
# 1318| 1: [Parameter] p#1
|
||||
# 1318| Type = [VoidPointerType] void *
|
||||
# 1320| [TopLevelFunction] void f(int*)
|
||||
# 1320| params:
|
||||
# 1320| 0: [Parameter] p
|
||||
# 1320| Type = [IntPointerType] int *
|
||||
# 1321| body: [Block] { ... }
|
||||
# 1322| 0: [ExprStmt] ExprStmt
|
||||
# 1322| 0: [NewExpr] new
|
||||
# 1322| Type = [IntPointerType] int *
|
||||
# 1322| ValueCategory = prvalue
|
||||
# 1322| 0: [FunctionCall] call to operator new
|
||||
# 1322| Type = [VoidPointerType] void *
|
||||
# 1322| ValueCategory = prvalue
|
||||
# 1322| 0: [ErrorExpr] <error expr>
|
||||
# 1322| Type = [LongType] unsigned long
|
||||
# 1322| ValueCategory = prvalue
|
||||
# 1322| 1: [CStyleCast] (void *)...
|
||||
# 1322| Conversion = [PointerConversion] pointer conversion
|
||||
# 1322| Type = [VoidPointerType] void *
|
||||
# 1322| ValueCategory = prvalue
|
||||
# 1322| expr: [VariableAccess] p
|
||||
# 1322| Type = [IntPointerType] int *
|
||||
# 1322| ValueCategory = prvalue(load)
|
||||
# 1323| 1: [ReturnStmt] return ...
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| params:
|
||||
|
||||
@@ -1315,4 +1315,11 @@ int shortCircuitConditional(int x, int y) {
|
||||
return predicateA() && predicateB() ? x : y;
|
||||
}
|
||||
|
||||
void *operator new(size_t, void *) noexcept;
|
||||
|
||||
void f(int* p)
|
||||
{
|
||||
new (p) int;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
@@ -7409,6 +7409,30 @@ ir.cpp:
|
||||
# 1314| v1314_10(void) = AliasedUse : ~m?
|
||||
# 1314| v1314_11(void) = ExitFunction :
|
||||
|
||||
# 1320| void f(int*)
|
||||
# 1320| Block 0
|
||||
# 1320| v1320_1(void) = EnterFunction :
|
||||
# 1320| mu1320_2(unknown) = AliasedDefinition :
|
||||
# 1320| mu1320_3(unknown) = InitializeNonLocal :
|
||||
# 1320| r1320_4(glval<int *>) = VariableAddress[p] :
|
||||
# 1320| mu1320_5(int *) = InitializeParameter[p] : &:r1320_4
|
||||
# 1320| r1320_6(int *) = Load : &:r1320_4, ~m?
|
||||
# 1320| mu1320_7(unknown) = InitializeIndirection[p] : &:r1320_6
|
||||
# 1322| r1322_1(glval<unknown>) = FunctionAddress[operator new] :
|
||||
# 1322| r1322_2(unsigned long) = Constant[4] :
|
||||
# 1322| r1322_3(glval<int *>) = VariableAddress[p] :
|
||||
# 1322| r1322_4(int *) = Load : &:r1322_3, ~m?
|
||||
# 1322| r1322_5(void *) = Convert : r1322_4
|
||||
# 1322| r1322_6(void *) = Call : func:r1322_1, 0:r1322_2, 1:r1322_5
|
||||
# 1322| mu1322_7(unknown) = ^CallSideEffect : ~m?
|
||||
# 1322| mu1322_8(unknown) = ^InitializeDynamicAllocation : &:r1322_6
|
||||
# 1322| r1322_9(int *) = Convert : r1322_6
|
||||
# 1323| v1323_1(void) = NoOp :
|
||||
# 1320| v1320_8(void) = ReturnIndirection[p] : &:r1320_6, ~m?
|
||||
# 1320| v1320_9(void) = ReturnVoid :
|
||||
# 1320| v1320_10(void) = AliasedUse : ~m?
|
||||
# 1320| v1320_11(void) = ExitFunction :
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
|
||||
@@ -39,7 +39,6 @@ instructionWithoutSuccessor
|
||||
| condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt |
|
||||
| condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt |
|
||||
| condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt |
|
||||
| cpp17.cpp:15:11:15:21 | Convert: (void *)... |
|
||||
| misc.c:171:10:171:13 | Uninitialized: definition of str2 |
|
||||
| misc.c:219:47:219:48 | InitializeIndirection: sp |
|
||||
| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x |
|
||||
@@ -156,8 +155,6 @@ ambiguousSuccessors
|
||||
| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c |
|
||||
| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c |
|
||||
| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i |
|
||||
| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new |
|
||||
| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... |
|
||||
| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... |
|
||||
| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c |
|
||||
| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c |
|
||||
|
||||
@@ -200,7 +200,7 @@ uniqueNodeLocation
|
||||
| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. |
|
||||
| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. |
|
||||
| fieldaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. |
|
||||
| file://:0:0:0:0 | InitializeIndirection | Node should have one location but has 0. |
|
||||
| file://:0:0:0:0 | *p#2 | Node should have one location but has 0. |
|
||||
| file://:0:0:0:0 | Load | Node should have one location but has 0. |
|
||||
| file://:0:0:0:0 | ReturnIndirection | Node should have one location but has 0. |
|
||||
| file://:0:0:0:0 | VariableAddress | Node should have one location but has 0. |
|
||||
|
||||
@@ -52,7 +52,6 @@ instructionWithoutSuccessor
|
||||
| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt |
|
||||
| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt |
|
||||
| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new |
|
||||
| cpp17.cpp:15:11:15:21 | Convert: (void *)... |
|
||||
| enum.c:6:9:6:9 | Constant: (int)... |
|
||||
| file://:0:0:0:0 | CompareNE: (bool)... |
|
||||
| file://:0:0:0:0 | CompareNE: (bool)... |
|
||||
@@ -208,8 +207,6 @@ ambiguousSuccessors
|
||||
| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c |
|
||||
| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c |
|
||||
| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i |
|
||||
| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new |
|
||||
| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... |
|
||||
| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... |
|
||||
| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c |
|
||||
| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c |
|
||||
|
||||
@@ -39,7 +39,6 @@ instructionWithoutSuccessor
|
||||
| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt |
|
||||
| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt |
|
||||
| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt |
|
||||
| cpp17.cpp:15:11:15:21 | Convert: (void *)... |
|
||||
| misc.c:171:10:171:13 | Uninitialized: definition of str2 |
|
||||
| misc.c:219:47:219:48 | InitializeIndirection: sp |
|
||||
| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x |
|
||||
@@ -156,8 +155,6 @@ ambiguousSuccessors
|
||||
| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c |
|
||||
| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c |
|
||||
| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i |
|
||||
| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new |
|
||||
| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... |
|
||||
| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... |
|
||||
| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c |
|
||||
| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c |
|
||||
|
||||
@@ -53,6 +53,8 @@ edges
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | (const char *)... |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | Argument 0 indirection |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | Argument 0 indirection |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | array to pointer conversion |
|
||||
@@ -63,6 +65,8 @@ edges
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | (const char *)... |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | Argument 0 indirection |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | Argument 0 indirection |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 |
|
||||
@@ -77,9 +81,11 @@ edges
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... |
|
||||
| argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... |
|
||||
| argvLocal.c:117:15:117:16 | Argument 0 indirection | argvLocal.c:117:15:117:16 | printWrapper output argument |
|
||||
| argvLocal.c:117:15:117:16 | array to pointer conversion | argvLocal.c:117:15:117:16 | printWrapper output argument |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | (const char *)... |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:121:9:121:10 | i4 |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | Argument 0 indirection |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 |
|
||||
@@ -87,6 +93,7 @@ edges
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... |
|
||||
| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... |
|
||||
| argvLocal.c:122:15:122:16 | Argument 0 indirection | argvLocal.c:122:15:122:16 | printWrapper output argument |
|
||||
| argvLocal.c:122:15:122:16 | i4 | argvLocal.c:122:15:122:16 | printWrapper output argument |
|
||||
| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | (const char *)... |
|
||||
| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | ... ++ |
|
||||
@@ -96,6 +103,8 @@ edges
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | (const char *)... |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | Argument 0 indirection |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | Argument 0 indirection |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | array to pointer conversion |
|
||||
@@ -110,6 +119,7 @@ edges
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... |
|
||||
| argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... |
|
||||
| argvLocal.c:128:15:128:16 | Argument 0 indirection | argvLocal.c:128:15:128:16 | printWrapper output argument |
|
||||
| argvLocal.c:128:15:128:16 | array to pointer conversion | argvLocal.c:128:15:128:16 | printWrapper output argument |
|
||||
| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | (const char *)... |
|
||||
| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:131:9:131:14 | ... + ... |
|
||||
@@ -156,8 +166,10 @@ edges
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 |
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 |
|
||||
nodes
|
||||
| argvLocal.c:9:25:9:31 | *correct | semmle.label | *correct |
|
||||
| argvLocal.c:9:25:9:31 | correct | semmle.label | correct |
|
||||
| argvLocal.c:10:9:10:15 | Chi | semmle.label | Chi |
|
||||
| argvLocal.c:10:9:10:15 | Chi | semmle.label | Chi |
|
||||
| argvLocal.c:95:9:95:12 | argv | semmle.label | argv |
|
||||
| argvLocal.c:95:9:95:12 | argv | semmle.label | argv |
|
||||
| argvLocal.c:95:9:95:15 | (const char *)... | semmle.label | (const char *)... |
|
||||
@@ -203,6 +215,7 @@ nodes
|
||||
| argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... |
|
||||
| argvLocal.c:116:9:116:10 | (const char *)... | semmle.label | (const char *)... |
|
||||
| argvLocal.c:116:9:116:10 | i3 | semmle.label | i3 |
|
||||
| argvLocal.c:117:15:117:16 | Argument 0 indirection | semmle.label | Argument 0 indirection |
|
||||
| argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion |
|
||||
| argvLocal.c:117:15:117:16 | array to pointer conversion | semmle.label | array to pointer conversion |
|
||||
| argvLocal.c:117:15:117:16 | i3 | semmle.label | i3 |
|
||||
@@ -210,6 +223,7 @@ nodes
|
||||
| argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... |
|
||||
| argvLocal.c:121:9:121:10 | (const char *)... | semmle.label | (const char *)... |
|
||||
| argvLocal.c:121:9:121:10 | i4 | semmle.label | i4 |
|
||||
| argvLocal.c:122:15:122:16 | Argument 0 indirection | semmle.label | Argument 0 indirection |
|
||||
| argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 |
|
||||
| argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 |
|
||||
| argvLocal.c:122:15:122:16 | i4 | semmle.label | i4 |
|
||||
@@ -219,6 +233,7 @@ nodes
|
||||
| argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... |
|
||||
| argvLocal.c:127:9:127:10 | (const char *)... | semmle.label | (const char *)... |
|
||||
| argvLocal.c:127:9:127:10 | i5 | semmle.label | i5 |
|
||||
| argvLocal.c:128:15:128:16 | Argument 0 indirection | semmle.label | Argument 0 indirection |
|
||||
| argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion |
|
||||
| argvLocal.c:128:15:128:16 | array to pointer conversion | semmle.label | array to pointer conversion |
|
||||
| argvLocal.c:128:15:128:16 | i5 | semmle.label | i5 |
|
||||
|
||||
@@ -35,11 +35,5 @@ import semmle.code.csharp.dataflow.DataFlow
|
||||
import semmle.code.csharp.dataflow.TaintTracking
|
||||
import semmle.code.csharp.dataflow.SSA
|
||||
|
||||
/** DEPRECATED: Use `ControlFlow` instead. */
|
||||
deprecated module ControlFlowGraph {
|
||||
import semmle.code.csharp.controlflow.ControlFlowGraph
|
||||
import ControlFlow
|
||||
}
|
||||
|
||||
/** Whether the source was extracted without a build command. */
|
||||
predicate extractionIsStandalone() { exists(SourceFile f | f.extractedStandalone()) }
|
||||
|
||||
@@ -25,12 +25,6 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
|
||||
/** Gets the annotated return type of this callable. */
|
||||
final AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) }
|
||||
|
||||
/** DEPRECATED: Use `getAnnotatedReturnType().isRef()` instead. */
|
||||
deprecated predicate returnsRef() { this.getAnnotatedReturnType().isRef() }
|
||||
|
||||
/** DEPRECATED: Use `getAnnotatedReturnType().isReadonlyRef()` instead. */
|
||||
deprecated predicate returnsRefReadonly() { this.getAnnotatedReturnType().isReadonlyRef() }
|
||||
|
||||
override Callable getSourceDeclaration() { result = Parameterizable.super.getSourceDeclaration() }
|
||||
|
||||
/**
|
||||
|
||||
@@ -197,24 +197,6 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter {
|
||||
* ```
|
||||
*/
|
||||
class TypeParameterConstraints extends Element, @type_parameter_constraints {
|
||||
/**
|
||||
* DEPRECATED: Use `getATypeConstraint()` instead.
|
||||
* Gets a specific interface constraint, if any.
|
||||
*/
|
||||
deprecated Interface getAnInterfaceConstraint() { result = getATypeConstraint() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getATypeConstraint()` instead.
|
||||
* Gets a specific type parameter constraint, if any.
|
||||
*/
|
||||
deprecated TypeParameter getATypeParameterConstraint() { result = getATypeConstraint() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getATypeConstraint()` instead.
|
||||
* Gets the specific class constraint, if any.
|
||||
*/
|
||||
deprecated Class getClassConstraint() { result = getATypeConstraint() }
|
||||
|
||||
/** Gets a specific type constraint, if any. */
|
||||
Type getATypeConstraint() { specific_type_parameter_constraints(this, getTypeRef(result)) }
|
||||
|
||||
|
||||
@@ -178,9 +178,6 @@ class SwitchStmt extends SelectionStmt, Switch, @switch_stmt {
|
||||
/** Gets the default case of this `switch` statement, if any. */
|
||||
DefaultCase getDefaultCase() { result = this.getACase() }
|
||||
|
||||
/** Gets a type case of this `switch` statement, if any. */
|
||||
deprecated TypeCase getATypeCase() { result = this.getACase() }
|
||||
|
||||
override string toString() { result = "switch (...) {...}" }
|
||||
|
||||
/**
|
||||
@@ -310,73 +307,6 @@ class ConstCase extends CaseStmt, LabeledStmt {
|
||||
override string toString() { result = CaseStmt.super.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type matching case in a `switch` statement, for example `case int i:` on line 3 or
|
||||
* `case string s when s.Length > 0:` on line 4 in
|
||||
*
|
||||
* ```
|
||||
* switch(p)
|
||||
* {
|
||||
* case int i:
|
||||
* case string s when s.Length > 0:
|
||||
* break;
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
deprecated class TypeCase extends CaseStmt {
|
||||
private TypeAccess ta;
|
||||
|
||||
TypeCase() { expr_parent(ta, 1, this) }
|
||||
|
||||
/**
|
||||
* Gets the local variable declaration of this type case, if any. For example,
|
||||
* the local variable declaration of the type case on line 3 is `string s` in
|
||||
*
|
||||
* ```
|
||||
* switch(p) {
|
||||
* case int i:
|
||||
* case string s when s.Length>0:
|
||||
* break;
|
||||
* case bool _:
|
||||
* break;
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
LocalVariableDeclExpr getVariableDeclExpr() { result = this.getPattern() }
|
||||
|
||||
/**
|
||||
* Gets the type access of this case, for example access to `string` or
|
||||
* access to `int` in
|
||||
*
|
||||
* ```
|
||||
* switch(p) {
|
||||
* case int i:
|
||||
* case string s when s.Length>0:
|
||||
* break;
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
TypeAccess getTypeAccess() { result = ta }
|
||||
|
||||
/**
|
||||
* Gets the type being checked by this case. For example, the type being checked
|
||||
* by the type case on line 3 is `string` in
|
||||
*
|
||||
* ```
|
||||
* switch(p) {
|
||||
* case int i:
|
||||
* case string s when s.Length>0:
|
||||
* break;
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
Type getCheckedType() { result = this.getTypeAccess().getType() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A default case of a `switch` statement, for example `default:` on
|
||||
* line 3 in
|
||||
|
||||
@@ -769,12 +769,6 @@ class DelegateType extends RefType, Parameterizable, @delegate_type {
|
||||
|
||||
/** Gets the annotated return type of this delegate. */
|
||||
AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) }
|
||||
|
||||
/** Holds if this delegate returns a `ref`. */
|
||||
deprecated predicate returnsRef() { this.getAnnotatedReturnType().isRef() }
|
||||
|
||||
/** Holds if this delegate returns a `ref readonly`. */
|
||||
deprecated predicate returnsRefReadonly() { this.getAnnotatedReturnType().isReadonlyRef() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/**
|
||||
* DEPRECATED.
|
||||
*
|
||||
* Provides classes representing data flow sources for parameters of public callables.
|
||||
*/
|
||||
|
||||
|
||||
@@ -441,65 +441,6 @@ class IsExpr extends Expr, PatternMatch, @is_expr {
|
||||
override string toString() { result = "... is ..." }
|
||||
}
|
||||
|
||||
/** An `is` type expression, for example, `x is string` or `x is string s`. */
|
||||
deprecated class IsTypeExpr extends IsExpr {
|
||||
TypeAccess typeAccess;
|
||||
|
||||
IsTypeExpr() { typeAccess = this.getChild(1) }
|
||||
|
||||
/**
|
||||
* Gets the type being accessed in this `is` expression, for example `string`
|
||||
* in `x is string`.
|
||||
*/
|
||||
Type getCheckedType() { result = typeAccess.getTarget() }
|
||||
|
||||
/**
|
||||
* Gets the type access in this `is` expression, for example `string` in
|
||||
* `x is string`.
|
||||
*/
|
||||
TypeAccess getTypeAccess() { result = typeAccess }
|
||||
}
|
||||
|
||||
/** An `is` pattern expression, for example `x is string s`. */
|
||||
deprecated class IsPatternExpr extends IsExpr {
|
||||
LocalVariableDeclExpr typeDecl;
|
||||
|
||||
IsPatternExpr() { typeDecl = this.getChild(2) }
|
||||
|
||||
/**
|
||||
* Gets the local variable declaration in this `is` pattern expression.
|
||||
* For example `string s` in `x is string s`.
|
||||
*/
|
||||
LocalVariableDeclExpr getVariableDeclExpr() { result = typeDecl }
|
||||
|
||||
/**
|
||||
* Gets the type being accessed in this `is` expression, for example `string`
|
||||
* in `x is string`.
|
||||
*/
|
||||
Type getCheckedType() { result = getTypeAccess().getTarget() }
|
||||
|
||||
/**
|
||||
* Gets the type access in this `is` expression, for example `string` in
|
||||
* `x is string`.
|
||||
*/
|
||||
TypeAccess getTypeAccess() { result = this.getChild(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An `is` constant expression, for example `x is 5`.
|
||||
*/
|
||||
deprecated class IsConstantExpr extends IsExpr {
|
||||
ConstantPatternExpr constant;
|
||||
|
||||
IsConstantExpr() { constant = this.getPattern() }
|
||||
|
||||
/** Gets the constant expression, for example `5` in `x is 5`. */
|
||||
Expr getConstant() { result = constant }
|
||||
|
||||
/** Gets the value of the constant, for example 5 in `x is 5`. */
|
||||
string getConstantValue() { result = constant.getValue() }
|
||||
}
|
||||
|
||||
/** A `switch` expression or statement. */
|
||||
class Switch extends ControlFlowElement, @switch {
|
||||
/** Gets the `i`th case of this `switch`. */
|
||||
|
||||
@@ -56,7 +56,7 @@ class ValueNumber extends TValueNumber {
|
||||
or
|
||||
this instanceof TInitializeParameterValueNumber and result = "InitializeParameter"
|
||||
or
|
||||
this instanceof TInitializeThisValueNumber and result = "InitializeThis"
|
||||
this instanceof TConstantValueNumber and result = "Constant"
|
||||
or
|
||||
this instanceof TStringConstantValueNumber and result = "StringConstant"
|
||||
or
|
||||
|
||||
@@ -7,7 +7,6 @@ newtype TValueNumber =
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
@@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) {
|
||||
or
|
||||
instr instanceof InitializeParameterInstruction
|
||||
or
|
||||
instr instanceof InitializeThisInstruction
|
||||
or
|
||||
instr instanceof ConstantInstruction
|
||||
or
|
||||
instr instanceof StringConstantInstruction
|
||||
@@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber(
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
@@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
|
||||
@@ -56,7 +56,7 @@ class ValueNumber extends TValueNumber {
|
||||
or
|
||||
this instanceof TInitializeParameterValueNumber and result = "InitializeParameter"
|
||||
or
|
||||
this instanceof TInitializeThisValueNumber and result = "InitializeThis"
|
||||
this instanceof TConstantValueNumber and result = "Constant"
|
||||
or
|
||||
this instanceof TStringConstantValueNumber and result = "StringConstant"
|
||||
or
|
||||
|
||||
@@ -7,7 +7,6 @@ newtype TValueNumber =
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
@@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) {
|
||||
or
|
||||
instr instanceof InitializeParameterInstruction
|
||||
or
|
||||
instr instanceof InitializeThisInstruction
|
||||
or
|
||||
instr instanceof ConstantInstruction
|
||||
or
|
||||
instr instanceof StringConstantInstruction
|
||||
@@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber(
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
@@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
|
||||
@@ -42,6 +42,8 @@ of ``OldVersion``, you could deprecate the name ``OldVersion`` as follows::
|
||||
That way both names resolve to the same module, but if you use the name ``OldVersion``,
|
||||
a deprecation warning is displayed.
|
||||
|
||||
.. _type-aliases:
|
||||
|
||||
Type aliases
|
||||
============
|
||||
|
||||
|
||||
@@ -42,6 +42,76 @@ A QL program can be *evaluated* (see `Evaluation <#evaluation>`__) to produce a
|
||||
|
||||
For a QL program to be *valid*, it must conform to a variety of conditions that are described throughout this specification; otherwise the program is said to be *invalid*. An implementation of QL must detect all invalid programs and refuse to evaluate them.
|
||||
|
||||
Library path
|
||||
------------
|
||||
|
||||
The library path is an ordered list of directory locations. It is used
|
||||
for resolving module imports (see `Module resolution <#module-resolution>`__). The library path is not strictly
|
||||
speaking a core part of the QL language, since different
|
||||
implementations of QL construct it in slightly different ways. Most QL
|
||||
tools also allow you to explicitly specify the library path on the command line for a
|
||||
particular invocation, though that is rarely done, and only
|
||||
useful in very special situations. This section describes the default
|
||||
construction of the library path.
|
||||
|
||||
First, determine the *query directory* of the ``.ql`` file being
|
||||
compiled. Starting with the directory containing the ``.ql`` file, and
|
||||
walking up the directory structure, each directory is checked for a
|
||||
file called ``queries.xml`` or ``qlpack.yml``. The first directory
|
||||
where such a file is found is the query directory. If there is no such
|
||||
directory, the directory of the ``.ql`` file itself is the query
|
||||
directory.
|
||||
|
||||
A ``queries.xml`` file that defines a query directory must always
|
||||
contain a single top-level tag named
|
||||
``queries``, which has a ``language`` attribute set to the identifier
|
||||
of the active database schema (for example, ``<queries
|
||||
language="java"/>``).
|
||||
|
||||
A ``qlpack.yml`` file defines a `QL pack
|
||||
<https://help.semmle.com/codeql/codeql-cli/reference/qlpack-overview.html>`__.
|
||||
The content of a ``qlpack.yml`` file is described in the CodeQL CLI documentation. This file
|
||||
will not be recognized when using legacy tools that are not based
|
||||
on the CodeQL CLI (that is, LGTM.com, LGTM Enterprise, ODASA, CodeQL for
|
||||
Eclipse, and CodeQL for Visual Studio).
|
||||
|
||||
If both a ``queries.xml`` and a ``qlpack.yml`` exist in the same
|
||||
directory, the latter takes precedence (and the former is assumed to
|
||||
exist for compatibility with older tooling).
|
||||
|
||||
In legacy QL tools that don't recognize ``qlpack.yml`` files, the default
|
||||
value of the library path for
|
||||
each supported language is hard-coded. The tools contain directories within the ODASA
|
||||
distribution that define the default CodeQL libraries for the selected
|
||||
language. Which language to use depends on the ``language`` attribute
|
||||
of the ``queries.xml`` file if not overridden with a ``--language``
|
||||
option to the ODASA CLI.
|
||||
|
||||
On the other hand, the CodeQL CLI and newer tools based on it (such as
|
||||
GitHub Code Scanning and the CodeQL extension for Visual Studio Code)
|
||||
construct a library path using QL packs. For each QL pack
|
||||
added to the library path, the QL packs named in its
|
||||
``libraryPathDependencies`` will be subsequently added to the library
|
||||
path, and the process continues until all packs have been
|
||||
resolved. The actual library path consists of the root directories of
|
||||
the selected QL packs. This process depends on a mechanism for finding
|
||||
QL packs by pack name, as described in the `CodeQL CLI documentation <https://help.semmle.com/codeql/codeql-cli.html>`__.
|
||||
|
||||
When the query directory contains a ``queries.xml`` file but no
|
||||
``qlpack.yml``, the QL pack resolution behaves as if it defines a QL
|
||||
pack with no name and a single library path dependency named
|
||||
``legacy-libraries-LANGUAGE`` where ``LANGUAGE`` is taken from
|
||||
``queries.xml``. The ``github/codeql`` repository provides packs with
|
||||
names following this pattern, which themselves depend on the actual
|
||||
CodeQL libraries for each language.
|
||||
|
||||
When the query directory contains neither a ``queries.xml`` nor
|
||||
``qlpack.yml`` file, it is considered to be a QL pack with no name and
|
||||
no library dependencies. This causes the library path to consist of
|
||||
*only* the query directory itself. This is not generally useful,
|
||||
but it suffices for running toy examples of QL code that don't
|
||||
use information from the database.
|
||||
|
||||
Name resolution
|
||||
---------------
|
||||
|
||||
@@ -162,11 +232,10 @@ For selection identifiers (``a::b``):
|
||||
|
||||
For qualified identifiers (``a.b``):
|
||||
|
||||
- Define the *current file* as the file the import directive occurs in.
|
||||
|
||||
- Determine the current file's *query directory*, if any. Starting with the directory containing the current file, and walking up the directory structure, each directory is checked for a file called ``queries.xml``, containing a single top-level tag named ``queries``, which has a ``language`` attribute set to the identifier of the active database scheme (for example, ``<queries language="java"/>``). The closest enclosing directory is taken as the current file's query directory.
|
||||
|
||||
- Build up a list of *candidate search paths*, consisting of the current file's directory, the current file's query directory (if one was determined in the previous step), and the list of directories making up the library path (in order).
|
||||
- Build up a list of *candidate search paths*, consisting of the
|
||||
current file's directory, then the *query directory* of the current
|
||||
file, and finally each of the directories on the
|
||||
`library path <#library-path>`__ (in order).
|
||||
|
||||
- Determine the first candidate search path that has a *matching* QLL file for the import directive's qualified name. A QLL file in a candidate search path is said to match a qualified name if, starting from the candidate search path, there is a subdirectory for each successive qualifier in the qualified name, and the directory named by the final qualifier contains a file whose base name matches the qualified name's base name, with the addition of the file extension ``.qll``. The file and directory names are matched case-sensitively, regardless of whether the filesystem is case-sensitive or not.
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ than one type.
|
||||
|
||||
The kinds of types in QL are :ref:`primitive types <primitive-types>`, :ref:`classes <classes>`,
|
||||
:ref:`character types <character-types>`, :ref:`class domain types <domain-types>`,
|
||||
:ref:`algebraic datatypes <algebraic-datatypes>`, and :ref:`database types <database-types>`.
|
||||
:ref:`algebraic datatypes <algebraic-datatypes>`, :ref:`type unions <type-unions>`,
|
||||
and :ref:`database types <database-types>`.
|
||||
|
||||
.. index:: boolean, float, int, string, date
|
||||
.. _primitive-types:
|
||||
@@ -479,6 +480,50 @@ program, so it's helpful to extend a new type (namely ``TTaintType``)::
|
||||
class Tainted extends TaintType, TTaintedValue {
|
||||
}
|
||||
|
||||
.. _type-unions:
|
||||
|
||||
Type unions
|
||||
***********
|
||||
|
||||
Type unions are user-defined types that are declared with the keyword ``class``.
|
||||
The syntax resembles :ref:`type aliases <type-aliases>`, but with two or more type expressions on the right-hand side.
|
||||
|
||||
Type unions are used for creating restricted subsets of an existing :ref:`algebraic datatype <algebraic-datatypes>`, by explicitly
|
||||
selecting a subset of the branches of that datatype and binding them to a new type.
|
||||
Type unions of :ref:`database types <database-types>` are also supported.
|
||||
|
||||
You can use a type union to give a name to a subset of the branches from an algebraic datatype.
|
||||
In some cases, using the type union over the whole algebraic datatype can avoid spurious
|
||||
:ref:`recursion <recursion>` in predicates.
|
||||
For example, the following construction is legal::
|
||||
|
||||
newtype InitialValueSource =
|
||||
ExplicitInitialization(VarDecl v) { exists(v.getInitializer()) } or
|
||||
ParameterPassing(Call c, int pos) { exists(c.getParameter(pos)) } or
|
||||
UnknownInitialGarbage(VarDecl v) { not exists(DefiniteInitialization di | v = target(di)) }
|
||||
|
||||
class DefiniteInitialization = ParameterPassing or ExplicitInitialization;
|
||||
|
||||
VarDecl target(DefiniteInitialization di) {
|
||||
di = ExplicitInitialization(result) or
|
||||
exists(Call c, int pos | di = ParameterPassing(c, pos) and
|
||||
result = c.getCallee().getFormalArg(pos))
|
||||
}
|
||||
|
||||
However, a similar implementation that restricts ``InitialValueSource`` in a class extension is not valid.
|
||||
If we had implemented ``DefiniteInitialization`` as a class extension instead, it would trigger a type test for ``InitialValueSource``. This results in an illegal recursion ``DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization`` since ``UnknownInitialGarbage`` relies on ``DefiniteInitialization``::
|
||||
|
||||
// THIS WON'T WORK: The implicit type check for InitialValueSource involves an illegal recursion
|
||||
// DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization!
|
||||
class DefiniteInitialization extends InitialValueSource {
|
||||
DefiniteInitialization() {
|
||||
this instanceof ParameterPassing or this instanceof ExplicitInitialization
|
||||
}
|
||||
// ...
|
||||
}
|
||||
|
||||
Type unions are supported from release 2.2.0 of the CodeQL CLI.
|
||||
|
||||
.. _database-types:
|
||||
|
||||
Database types
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
public Object evaluate(Socket socket) throws IOException {
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(socket.getInputStream()))) {
|
||||
|
||||
String string = reader.readLine();
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expression = parser.parseExpression(string);
|
||||
SimpleEvaluationContext context
|
||||
= SimpleEvaluationContext.forReadWriteDataBinding().build();
|
||||
return expression.getValue(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
The Spring Expression Language (SpEL) is a powerful expression language
|
||||
provided by Spring Framework. The language offers many features
|
||||
including invocation of methods available in the JVM.
|
||||
If a SpEL expression is built using attacker-controlled data,
|
||||
and then evaluated in a powerful context,
|
||||
then it may allow the attacker to run arbitrary code.
|
||||
</p>
|
||||
<p>
|
||||
The <code>SpelExpressionParser</code> class parses a SpEL expression string
|
||||
and returns an <code>Expression</code> instance
|
||||
that can be then evaluated by calling one of its methods.
|
||||
By default, an expression is evaluated in a powerful <code>StandardEvaluationContext</code>
|
||||
that allows the expression to access other methods available in the JVM.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
In general, including user input in a SpEL expression should be avoided.
|
||||
If user input must be included in the expression,
|
||||
it should be then evaluated in a limited context
|
||||
that doesn't allow arbitrary method invocation.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example uses untrusted data to build a SpEL expression
|
||||
and then runs it in the default powerfull context.
|
||||
</p>
|
||||
<sample src="UnsafeSpelExpressionEvaluation.java" />
|
||||
|
||||
<p>
|
||||
The next example shows how an untrusted SpEL expression can be run
|
||||
in <code>SimpleEvaluationContext</code> that doesn't allow accessing arbitrary methods.
|
||||
However, it's recommended to avoid using untrusted input in SpEL expressions.
|
||||
</p>
|
||||
<sample src="SaferSpelExpressionEvaluation.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Spring Framework Reference Documentation:
|
||||
<a href="https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/expressions.html">Spring Expression Language (SpEL)</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://owasp.org/www-community/vulnerabilities/Expression_Language_Injection">Expression Language Injection</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @name Expression language injection (Spring)
|
||||
* @description Evaluation of a user-controlled Spring Expression Language (SpEL) expression
|
||||
* may lead to remote code execution.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/spel-expression-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-094
|
||||
*/
|
||||
|
||||
import java
|
||||
import SpelInjectionLib
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ExpressionInjectionConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "SpEL injection from $@.", source.getNode(), "this user input"
|
||||
@@ -0,0 +1,100 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking2
|
||||
import SpringFrameworkLib
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate a SpEL expression.
|
||||
*/
|
||||
class ExpressionInjectionConfig extends TaintTracking::Configuration {
|
||||
ExpressionInjectionConfig() { this = "ExpressionInjectionConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source instanceof RemoteFlowSource or
|
||||
source instanceof WebRequestSource
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionEvaluationSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
expressionParsingStep(node1, node2) or
|
||||
springPropertiesStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sink for SpEL injection vulnerabilities,
|
||||
* i.e. methods that run evaluation of a SpEL expression in a powerfull context.
|
||||
*/
|
||||
class ExpressionEvaluationSink extends DataFlow::ExprNode {
|
||||
ExpressionEvaluationSink() {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
m instanceof ExpressionEvaluationMethod and
|
||||
getExpr() = ma.getQualifier() and
|
||||
not exists(SafeEvaluationContextFlowConfig config |
|
||||
config.hasFlowTo(DataFlow::exprNode(ma.getArgument(0)))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node1` to `node2` is a dataflow step that parses a SpEL expression,
|
||||
* i.e. `parser.parseExpression(tainted)`.
|
||||
*/
|
||||
predicate expressionParsingStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
m.getDeclaringType().getAnAncestor*() instanceof ExpressionParser and
|
||||
m.hasName("parseExpression") and
|
||||
ma.getAnArgument() = node1.asExpr() and
|
||||
node2.asExpr() = ma
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration for safe evaluation context that may be used in expression evaluation.
|
||||
*/
|
||||
class SafeEvaluationContextFlowConfig extends DataFlow2::Configuration {
|
||||
SafeEvaluationContextFlowConfig() { this = "SpelInjection::SafeEvaluationContextFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof SafeContextSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
m instanceof ExpressionEvaluationMethod and
|
||||
ma.getArgument(0) = sink.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override int fieldFlowBranchLimit() { result = 0 }
|
||||
}
|
||||
|
||||
class SafeContextSource extends DataFlow::ExprNode {
|
||||
SafeContextSource() {
|
||||
isSimpleEvaluationContextConstructorCall(getExpr()) or
|
||||
isSimpleEvaluationContextBuilderCall(getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` constructs `SimpleEvaluationContext`.
|
||||
*/
|
||||
predicate isSimpleEvaluationContextConstructorCall(Expr expr) {
|
||||
exists(ConstructorCall cc |
|
||||
cc.getConstructedType() instanceof SimpleEvaluationContext and
|
||||
cc = expr
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` builds `SimpleEvaluationContext` via `SimpleEvaluationContext.Builder`,
|
||||
* e.g. `SimpleEvaluationContext.forReadWriteDataBinding().build()`.
|
||||
*/
|
||||
predicate isSimpleEvaluationContextBuilderCall(Expr expr) {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
m.getDeclaringType() instanceof SimpleEvaluationContextBuilder and
|
||||
m.hasName("build") and
|
||||
ma = expr
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* Methods that trigger evaluation of an expression.
|
||||
*/
|
||||
class ExpressionEvaluationMethod extends Method {
|
||||
ExpressionEvaluationMethod() {
|
||||
getDeclaringType() instanceof Expression and
|
||||
(
|
||||
hasName("getValue") or
|
||||
hasName("getValueTypeDescriptor") or
|
||||
hasName("getValueType") or
|
||||
hasName("setValue")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `WebRequest` interface is a source of tainted data.
|
||||
*/
|
||||
class WebRequestSource extends DataFlow::Node {
|
||||
WebRequestSource() {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
m.getDeclaringType() instanceof WebRequest and
|
||||
(
|
||||
m.hasName("getHeader") or
|
||||
m.hasName("getHeaderValues") or
|
||||
m.hasName("getHeaderNames") or
|
||||
m.hasName("getParameter") or
|
||||
m.hasName("getParameterValues") or
|
||||
m.hasName("getParameterNames") or
|
||||
m.hasName("getParameterMap")
|
||||
) and
|
||||
ma = asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node1` to `node2` is a dataflow step that converts `PropertyValues`
|
||||
* to an array of `PropertyValue`, i.e. `tainted.getPropertyValues()`.
|
||||
*/
|
||||
predicate getPropertyValuesStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
node1.asExpr() = ma.getQualifier() and
|
||||
node2.asExpr() = ma and
|
||||
m.getDeclaringType() instanceof PropertyValues and
|
||||
m.hasName("getPropertyValues")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node1` to `node2` is a dataflow step that constructs `MutablePropertyValues`,
|
||||
* i.e. `new MutablePropertyValues(tainted)`.
|
||||
*/
|
||||
predicate createMutablePropertyValuesStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(ConstructorCall cc | cc.getConstructedType() instanceof MutablePropertyValues |
|
||||
node1.asExpr() = cc.getAnArgument() and
|
||||
node2.asExpr() = cc
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node1` to `node2` is a dataflow step that returns a name of `PropertyValue`,
|
||||
* i.e. `tainted.getName()`.
|
||||
*/
|
||||
predicate getPropertyNameStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
node1.asExpr() = ma.getQualifier() and
|
||||
node2.asExpr() = ma and
|
||||
m.getDeclaringType() instanceof PropertyValue and
|
||||
m.hasName("getName")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node1` to `node2` is a dataflow step that converts `MutablePropertyValues`
|
||||
* to a list of `PropertyValue`, i.e. `tainted.getPropertyValueList()`.
|
||||
*/
|
||||
predicate getPropertyValueListStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
node1.asExpr() = ma.getQualifier() and
|
||||
node2.asExpr() = ma and
|
||||
m.getDeclaringType() instanceof MutablePropertyValues and
|
||||
m.hasName("getPropertyValueList")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node1` to `node2` is one of the dataflow steps that propagate
|
||||
* tainted data via Spring properties.
|
||||
*/
|
||||
predicate springPropertiesStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
createMutablePropertyValuesStep(node1, node2) or
|
||||
getPropertyNameStep(node1, node2) or
|
||||
getPropertyValuesStep(node1, node2) or
|
||||
getPropertyValueListStep(node1, node2)
|
||||
}
|
||||
|
||||
class PropertyValue extends RefType {
|
||||
PropertyValue() { hasQualifiedName("org.springframework.beans", "PropertyValue") }
|
||||
}
|
||||
|
||||
class PropertyValues extends RefType {
|
||||
PropertyValues() { hasQualifiedName("org.springframework.beans", "PropertyValues") }
|
||||
}
|
||||
|
||||
class MutablePropertyValues extends RefType {
|
||||
MutablePropertyValues() { hasQualifiedName("org.springframework.beans", "MutablePropertyValues") }
|
||||
}
|
||||
|
||||
class SimpleEvaluationContext extends RefType {
|
||||
SimpleEvaluationContext() {
|
||||
hasQualifiedName("org.springframework.expression.spel.support", "SimpleEvaluationContext")
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleEvaluationContextBuilder extends RefType {
|
||||
SimpleEvaluationContextBuilder() {
|
||||
hasQualifiedName("org.springframework.expression.spel.support",
|
||||
"SimpleEvaluationContext$Builder")
|
||||
}
|
||||
}
|
||||
|
||||
class WebRequest extends RefType {
|
||||
WebRequest() { hasQualifiedName("org.springframework.web.context.request", "WebRequest") }
|
||||
}
|
||||
|
||||
class Expression extends RefType {
|
||||
Expression() { hasQualifiedName("org.springframework.expression", "Expression") }
|
||||
}
|
||||
|
||||
class ExpressionParser extends RefType {
|
||||
ExpressionParser() { hasQualifiedName("org.springframework.expression", "ExpressionParser") }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
public Object evaluate(Socket socket) throws IOException {
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(socket.getInputStream()))) {
|
||||
|
||||
String string = reader.readLine();
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expression = parser.parseExpression(string);
|
||||
return expression.getValue();
|
||||
}
|
||||
}
|
||||
@@ -305,6 +305,21 @@ private predicate instanceOfGuarded(VarAccess va, RefType t) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `aa` is an access to a value that is guarded by `instanceof t`.
|
||||
*/
|
||||
predicate arrayInstanceOfGuarded(ArrayAccess aa, RefType t) {
|
||||
exists(InstanceOfExpr ioe, BaseSsaVariable v1, BaseSsaVariable v2, ArrayAccess aa1 |
|
||||
ioe.getExpr() = aa1 and
|
||||
t = ioe.getTypeName().getType() and
|
||||
aa1.getArray() = v1.getAUse() and
|
||||
aa1.getIndexExpr() = v2.getAUse() and
|
||||
aa.getArray() = v1.getAUse() and
|
||||
aa.getIndexExpr() = v2.getAUse() and
|
||||
guardControls_v1(ioe, aa.getBasicBlock(), true)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` has type `t` and this information is discarded, such that `t`
|
||||
* might be a better type bound for nodes where `n` flows to.
|
||||
@@ -315,6 +330,7 @@ private predicate typeFlowBase(TypeFlowNode n, RefType t) {
|
||||
upcastEnhancedForStmt(n.asSsa(), srctype) or
|
||||
downcastSuccessor(n.asExpr(), srctype) or
|
||||
instanceOfGuarded(n.asExpr(), srctype) or
|
||||
arrayInstanceOfGuarded(n.asExpr(), srctype) or
|
||||
n.asExpr().(FunctionalExpr).getConstructedType() = srctype
|
||||
|
|
||||
t = srctype.(BoundedType).getAnUltimateUpperBoundType()
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
edges
|
||||
| SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | SpelInjection.java:23:5:23:14 | expression |
|
||||
| SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | SpelInjection.java:34:5:34:14 | expression |
|
||||
| SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | SpelInjection.java:48:5:48:14 | expression |
|
||||
| SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | SpelInjection.java:59:5:59:14 | expression |
|
||||
| SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | SpelInjection.java:70:5:70:14 | expression |
|
||||
| SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | SpelInjection.java:83:5:83:14 | expression |
|
||||
nodes
|
||||
| SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| SpelInjection.java:23:5:23:14 | expression | semmle.label | expression |
|
||||
| SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| SpelInjection.java:34:5:34:14 | expression | semmle.label | expression |
|
||||
| SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| SpelInjection.java:48:5:48:14 | expression | semmle.label | expression |
|
||||
| SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| SpelInjection.java:59:5:59:14 | expression | semmle.label | expression |
|
||||
| SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| SpelInjection.java:70:5:70:14 | expression | semmle.label | expression |
|
||||
| SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| SpelInjection.java:83:5:83:14 | expression | semmle.label | expression |
|
||||
#select
|
||||
| SpelInjection.java:23:5:23:14 | expression | SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | SpelInjection.java:23:5:23:14 | expression | SpEL injection from $@. | SpelInjection.java:15:22:15:44 | getInputStream(...) | this user input |
|
||||
| SpelInjection.java:34:5:34:14 | expression | SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | SpelInjection.java:34:5:34:14 | expression | SpEL injection from $@. | SpelInjection.java:27:22:27:44 | getInputStream(...) | this user input |
|
||||
| SpelInjection.java:48:5:48:14 | expression | SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | SpelInjection.java:48:5:48:14 | expression | SpEL injection from $@. | SpelInjection.java:38:22:38:44 | getInputStream(...) | this user input |
|
||||
| SpelInjection.java:59:5:59:14 | expression | SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | SpelInjection.java:59:5:59:14 | expression | SpEL injection from $@. | SpelInjection.java:52:22:52:44 | getInputStream(...) | this user input |
|
||||
| SpelInjection.java:70:5:70:14 | expression | SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | SpelInjection.java:70:5:70:14 | expression | SpEL injection from $@. | SpelInjection.java:63:22:63:44 | getInputStream(...) | this user input |
|
||||
| SpelInjection.java:83:5:83:14 | expression | SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | SpelInjection.java:83:5:83:14 | expression | SpEL injection from $@. | SpelInjection.java:74:22:74:44 | getInputStream(...) | this user input |
|
||||
@@ -0,0 +1,100 @@
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.SimpleEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
public class SpelInjection {
|
||||
|
||||
private static final ExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
public void testGetValue(Socket socket) throws IOException {
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
byte[] bytes = new byte[1024];
|
||||
int n = in.read(bytes);
|
||||
String input = new String(bytes, 0, n);
|
||||
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expression = parser.parseExpression(input);
|
||||
expression.getValue();
|
||||
}
|
||||
|
||||
public void testGetValueWithChainedCalls(Socket socket) throws IOException {
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
byte[] bytes = new byte[1024];
|
||||
int n = in.read(bytes);
|
||||
String input = new String(bytes, 0, n);
|
||||
|
||||
Expression expression = new SpelExpressionParser().parseExpression(input);
|
||||
expression.getValue();
|
||||
}
|
||||
|
||||
public void testSetValueWithRootObject(Socket socket) throws IOException {
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
byte[] bytes = new byte[1024];
|
||||
int n = in.read(bytes);
|
||||
String input = new String(bytes, 0, n);
|
||||
|
||||
Expression expression = new SpelExpressionParser().parseExpression(input);
|
||||
|
||||
Object root = new Object();
|
||||
Object value = new Object();
|
||||
expression.setValue(root, value);
|
||||
}
|
||||
|
||||
public void testGetValueWithStaticParser(Socket socket) throws IOException {
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
byte[] bytes = new byte[1024];
|
||||
int n = in.read(bytes);
|
||||
String input = new String(bytes, 0, n);
|
||||
|
||||
Expression expression = PARSER.parseExpression(input);
|
||||
expression.getValue();
|
||||
}
|
||||
|
||||
public void testGetValueType(Socket socket) throws IOException {
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
byte[] bytes = new byte[1024];
|
||||
int n = in.read(bytes);
|
||||
String input = new String(bytes, 0, n);
|
||||
|
||||
Expression expression = PARSER.parseExpression(input);
|
||||
expression.getValueType();
|
||||
}
|
||||
|
||||
public void testWithStandardEvaluationContext(Socket socket) throws IOException {
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
byte[] bytes = new byte[1024];
|
||||
int n = in.read(bytes);
|
||||
String input = new String(bytes, 0, n);
|
||||
|
||||
Expression expression = PARSER.parseExpression(input);
|
||||
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
expression.getValue(context);
|
||||
}
|
||||
|
||||
public void testWithSimpleEvaluationContext(Socket socket) throws IOException {
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
byte[] bytes = new byte[1024];
|
||||
int n = in.read(bytes);
|
||||
String input = new String(bytes, 0, n);
|
||||
|
||||
Expression expression = PARSER.parseExpression(input);
|
||||
SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
|
||||
|
||||
// the expression is evaluated in a limited context
|
||||
expression.getValue(context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-094/SpelInjection.ql
|
||||
1
java/ql/test/experimental/Security/CWE/CWE-094/options
Normal file
1
java/ql/test/experimental/Security/CWE/CWE-094/options
Normal file
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3
|
||||
@@ -85,4 +85,11 @@ public class A extends ArrayList<Long> {
|
||||
empty.put(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
public void m8(Object[] xs, int i) {
|
||||
if (xs[i] instanceof Integer) {
|
||||
Object n = xs[i];
|
||||
Object r = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,3 +12,4 @@
|
||||
| A.java:61:11:61:11 | x | Integer | false |
|
||||
| A.java:67:22:67:22 | x | Integer | false |
|
||||
| A.java:70:23:70:24 | x2 | Integer | false |
|
||||
| A.java:92:18:92:18 | n | Integer | false |
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.springframework.expression;
|
||||
|
||||
public interface EvaluationContext {}
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.springframework.expression;
|
||||
|
||||
public class EvaluationException extends RuntimeException {}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.springframework.expression;
|
||||
|
||||
public interface Expression {
|
||||
|
||||
Object getValue() throws EvaluationException;
|
||||
|
||||
Object getValue(EvaluationContext context) throws EvaluationException;
|
||||
|
||||
Class<?> getValueType() throws EvaluationException;
|
||||
|
||||
Class<?> getValueType(EvaluationContext context) throws EvaluationException;
|
||||
|
||||
void setValue(Object rootObject, Object value) throws EvaluationException;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.springframework.expression;
|
||||
|
||||
public interface ExpressionParser {
|
||||
|
||||
Expression parseExpression(String string);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.springframework.expression.spel.standard;
|
||||
|
||||
import org.springframework.expression.*;
|
||||
|
||||
public class SpelExpressionParser implements ExpressionParser {
|
||||
|
||||
public SpelExpressionParser() {}
|
||||
|
||||
public Expression parseExpression(String string) { return null; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
package org.springframework.expression.spel.support;
|
||||
|
||||
import org.springframework.expression.*;
|
||||
|
||||
public class SimpleEvaluationContext implements EvaluationContext {
|
||||
|
||||
public static Builder forReadWriteDataBinding() { return null; }
|
||||
|
||||
public static class Builder {
|
||||
public SimpleEvaluationContext build() { return null; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.springframework.expression.spel.support;
|
||||
|
||||
import org.springframework.expression.*;
|
||||
|
||||
public class StandardEvaluationContext implements EvaluationContext {}
|
||||
@@ -61,18 +61,14 @@ DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) {
|
||||
sw.getSubstring().mayHaveStringValue(scheme)
|
||||
)
|
||||
or
|
||||
// check of the form `array.includes(getScheme(nd))`
|
||||
exists(InclusionTest test, DataFlow::ArrayCreationNode array | test = result |
|
||||
schemeOf(nd).flowsTo(test.getContainedNode()) and
|
||||
array.flowsTo(test.getContainerNode()) and
|
||||
array.getAnElement().mayHaveStringValue(scheme.getWithOrWithoutColon())
|
||||
)
|
||||
or
|
||||
// check of the form `getScheme(nd) === scheme`
|
||||
exists(EqualityTest test, Expr op1, Expr op2 | test.flow() = result |
|
||||
test.hasOperands(op1, op2) and
|
||||
schemeOf(nd).flowsToExpr(op1) and
|
||||
op2.mayHaveStringValue(scheme.getWithOrWithoutColon())
|
||||
exists(MembershipCandidate candidate |
|
||||
result = candidate.getTest()
|
||||
or
|
||||
// fall back to the candidate if the test itself is implicit
|
||||
not exists(candidate.getTest()) and result = candidate
|
||||
|
|
||||
candidate.getAMemberString() = scheme.getWithOrWithoutColon() and
|
||||
schemeOf(nd).flowsTo(candidate)
|
||||
)
|
||||
or
|
||||
// propagate through trimming, case conversion, and regexp replace
|
||||
|
||||
@@ -449,8 +449,10 @@ class BlacklistInclusionGuard extends DataFlow::LabeledBarrierGuardNode, Inclusi
|
||||
*/
|
||||
class WhitelistInclusionGuard extends DataFlow::LabeledBarrierGuardNode {
|
||||
WhitelistInclusionGuard() {
|
||||
this instanceof TaintTracking::PositiveIndexOfSanitizer or
|
||||
this instanceof TaintTracking::InclusionSanitizer
|
||||
this instanceof TaintTracking::PositiveIndexOfSanitizer
|
||||
or
|
||||
this instanceof TaintTracking::MembershipTestSanitizer and
|
||||
not this = any(MembershipCandidate::ObjectPropertyNameMembershipCandidate c).getTest() // handled with more precision in `HasOwnPropertyGuard`
|
||||
}
|
||||
|
||||
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel lbl) {
|
||||
|
||||
@@ -37,6 +37,7 @@ import semmle.javascript.JsonParsers
|
||||
import semmle.javascript.JSX
|
||||
import semmle.javascript.Lines
|
||||
import semmle.javascript.Locations
|
||||
import semmle.javascript.MembershipCandidates
|
||||
import semmle.javascript.Modules
|
||||
import semmle.javascript.NodeJS
|
||||
import semmle.javascript.NPM
|
||||
|
||||
@@ -108,6 +108,7 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
|
||||
int getIntValue() { none() }
|
||||
|
||||
/** Gets the constant string value this expression evaluates to, if any. */
|
||||
cached
|
||||
string getStringValue() { none() }
|
||||
|
||||
/** Holds if this expression is impure, that is, its evaluation could have side effects. */
|
||||
@@ -1354,6 +1355,11 @@ class EqualityTest extends @equalitytest, Comparison {
|
||||
(this instanceof NEqExpr or this instanceof StrictNEqExpr) and
|
||||
result = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the equality operator is strict (`===` or `!==`).
|
||||
*/
|
||||
predicate isStrict() { this instanceof StrictEqExpr or this instanceof StrictNEqExpr }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
private import javascript
|
||||
|
||||
/**
|
||||
* A expression that checks if an element is contained in an array
|
||||
* An expression that checks if an element is contained in an array
|
||||
* or is a substring of another string.
|
||||
*
|
||||
* Examples:
|
||||
|
||||
261
javascript/ql/src/semmle/javascript/MembershipCandidates.qll
Normal file
261
javascript/ql/src/semmle/javascript/MembershipCandidates.qll
Normal file
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* Provides classes for recognizing membership tests.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* An expression that is tested for membership of a collection.
|
||||
*
|
||||
* Additional candidates can be added by subclassing `MembershipCandidate::Range`
|
||||
*/
|
||||
class MembershipCandidate extends DataFlow::Node {
|
||||
MembershipCandidate::Range range;
|
||||
|
||||
MembershipCandidate() { this = range }
|
||||
|
||||
/**
|
||||
* Gets the expression that performs the membership test, if any.
|
||||
*/
|
||||
DataFlow::Node getTest() { result = range.getTest() }
|
||||
|
||||
/**
|
||||
* Gets a string that this candidate is tested against, if
|
||||
* it can be determined.
|
||||
*/
|
||||
string getAMemberString() { result = range.getAMemberString() }
|
||||
|
||||
/**
|
||||
* Gets a node that this candidate is tested against, if
|
||||
* it can be determined.
|
||||
*/
|
||||
DataFlow::Node getAMemberNode() { result = range.getAMemberNode() }
|
||||
|
||||
/**
|
||||
* Gets the polarity of the test.
|
||||
*
|
||||
* If the polarity is `false` the test returns `true` if the
|
||||
* collection does not contain this candidate.
|
||||
*/
|
||||
boolean getTestPolarity() { result = range.getTestPolarity() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes for recognizing membership candidates.
|
||||
*/
|
||||
module MembershipCandidate {
|
||||
/**
|
||||
* An expression that is tested for membership of a collection.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the expression that performs the membership test, if any.
|
||||
*/
|
||||
abstract DataFlow::Node getTest();
|
||||
|
||||
/**
|
||||
* Gets a string that this candidate is tested against, if
|
||||
* it can be determined.
|
||||
*/
|
||||
string getAMemberString() { this.getAMemberNode().mayHaveStringValue(result) }
|
||||
|
||||
/**
|
||||
* Gets a node that this candidate is tested against, if
|
||||
* it can be determined.
|
||||
*/
|
||||
DataFlow::Node getAMemberNode() { none() }
|
||||
|
||||
/**
|
||||
* Gets the polarity of the test.
|
||||
*
|
||||
* If the polarity is `false` the test returns `true` if the
|
||||
* collection does not contain this candidate.
|
||||
*/
|
||||
boolean getTestPolarity() { result = true }
|
||||
}
|
||||
|
||||
/**
|
||||
* An `InclusionTest` candidate viewed as a `MembershipCandidate`.
|
||||
*/
|
||||
private class OrdinaryInclusionTestCandidate extends MembershipCandidate::Range {
|
||||
InclusionTest test;
|
||||
|
||||
OrdinaryInclusionTestCandidate() { this = test.getContainedNode() }
|
||||
|
||||
override DataFlow::Node getTest() { result = test }
|
||||
|
||||
override boolean getTestPolarity() { result = test.getPolarity() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A candidate that may be a member of an array.
|
||||
*/
|
||||
class ArrayMembershipCandidate extends OrdinaryInclusionTestCandidate {
|
||||
DataFlow::ArrayCreationNode array;
|
||||
|
||||
ArrayMembershipCandidate() { array.flowsTo(test.getContainerNode()) }
|
||||
|
||||
/**
|
||||
* Gets the array of this test.
|
||||
*/
|
||||
DataFlow::ArrayCreationNode getArray() { result = array }
|
||||
|
||||
override DataFlow::Node getAMemberNode() { result = array.getAnElement() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A candidate that may be a member of an array constructed
|
||||
* from a call to `String.prototype.split`.
|
||||
*/
|
||||
private class ShorthandArrayMembershipCandidate extends OrdinaryInclusionTestCandidate {
|
||||
string toSplit;
|
||||
string separator;
|
||||
|
||||
ShorthandArrayMembershipCandidate() {
|
||||
exists(StringSplitCall split |
|
||||
split.flowsTo(test.getContainerNode()) and
|
||||
toSplit = split.getBaseString().getStringValue() and
|
||||
separator = split.getSeparator()
|
||||
)
|
||||
}
|
||||
|
||||
override string getAMemberString() { result = toSplit.splitAt(separator) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An `EqualityTest` operand viewed as a `MembershipCandidate`.
|
||||
*/
|
||||
private class EqualityTestOperand extends MembershipCandidate::Range, DataFlow::ValueNode {
|
||||
EqualityTest test;
|
||||
|
||||
EqualityTestOperand() { this = test.getAnOperand().flow() }
|
||||
|
||||
override DataFlow::Node getTest() { result = test.flow() }
|
||||
|
||||
override DataFlow::Node getAMemberNode() { test.hasOperands(this.asExpr(), result.asExpr()) }
|
||||
|
||||
override boolean getTestPolarity() { result = test.getPolarity() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A regular expression that enumerates all of its matched strings.
|
||||
*/
|
||||
private class EnumerationRegExp extends RegExpTerm {
|
||||
EnumerationRegExp() {
|
||||
this.isRootTerm() and
|
||||
RegExp::isFullyAnchoredTerm(this) and
|
||||
exists(RegExpTerm child | this.getAChild*() = child |
|
||||
child instanceof RegExpSequence or
|
||||
child instanceof RegExpCaret or
|
||||
child instanceof RegExpDollar or
|
||||
child instanceof RegExpConstant or
|
||||
child instanceof RegExpAlt or
|
||||
child instanceof RegExpGroup
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string matched by this regular expression.
|
||||
*/
|
||||
string getAMember() { result = this.getAChild*().getAMatchedString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A candidate that may be matched by a regular expression that
|
||||
* enumerates all of its matched strings.
|
||||
*/
|
||||
private class RegExpEnumerationCandidate extends MembershipCandidate::Range, DataFlow::Node {
|
||||
DataFlow::Node test;
|
||||
EnumerationRegExp enumeration;
|
||||
boolean polarity;
|
||||
|
||||
RegExpEnumerationCandidate() {
|
||||
exists(DataFlow::MethodCallNode mcn, DataFlow::Node base, string m, DataFlow::Node firstArg |
|
||||
(
|
||||
test = any(ConditionGuardNode g).getTest().flow() and
|
||||
mcn.flowsTo(test) and
|
||||
polarity = true
|
||||
or
|
||||
exists(EqualityTest eq, Expr null, Expr op |
|
||||
test = eq.flow() and
|
||||
polarity = eq.getPolarity().booleanNot() and
|
||||
mcn.flowsToExpr(op) and
|
||||
eq.hasOperands(op, null) and
|
||||
SyntacticConstants::isNull(null)
|
||||
)
|
||||
) and
|
||||
mcn.calls(base, m) and
|
||||
firstArg = mcn.getArgument(0)
|
||||
|
|
||||
// /re/.test(u) or /re/.exec(u)
|
||||
enumeration = RegExp::getRegExpObjectFromNode(base) and
|
||||
(m = "test" or m = "exec") and
|
||||
firstArg = this
|
||||
or
|
||||
// u.match(/re/) or u.match("re")
|
||||
base = this and
|
||||
m = "match" and
|
||||
enumeration = RegExp::getRegExpFromNode(firstArg)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getTest() { result = test }
|
||||
|
||||
override string getAMemberString() { result = enumeration.getAMember() }
|
||||
|
||||
override boolean getTestPolarity() { result = polarity }
|
||||
}
|
||||
|
||||
/**
|
||||
* A candidate that may be a member of a collection class, such as a map or set.
|
||||
*/
|
||||
class CollectionMembershipCandidate extends MembershipCandidate::Range {
|
||||
DataFlow::MethodCallNode test;
|
||||
|
||||
CollectionMembershipCandidate() { test.getMethodName() = "has" and this = test.getArgument(0) }
|
||||
|
||||
override DataFlow::Node getTest() { result = test }
|
||||
}
|
||||
|
||||
/**
|
||||
* A candidate that may be a property name of an object.
|
||||
*/
|
||||
class ObjectPropertyNameMembershipCandidate extends MembershipCandidate::Range,
|
||||
DataFlow::ValueNode {
|
||||
DataFlow::ValueNode test;
|
||||
DataFlow::ValueNode membersNode;
|
||||
|
||||
ObjectPropertyNameMembershipCandidate() {
|
||||
exists(InExpr inExpr |
|
||||
this = inExpr.getLeftOperand().flow() and
|
||||
test = inExpr.flow() and
|
||||
membersNode = inExpr.getRightOperand().flow()
|
||||
)
|
||||
or
|
||||
exists(DataFlow::MethodCallNode hasOwn |
|
||||
this = hasOwn.getArgument(0) and
|
||||
test = hasOwn and
|
||||
hasOwn.calls(membersNode, "hasOwnProperty")
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getTest() { result = test }
|
||||
|
||||
override string getAMemberString() {
|
||||
exists(membersNode.getALocalSource().getAPropertyWrite(result))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A candidate that may match a switch case.
|
||||
*/
|
||||
class SwitchCaseCandidate extends MembershipCandidate::Range {
|
||||
SwitchStmt switch;
|
||||
|
||||
SwitchCaseCandidate() { this = switch.getExpr().flow() }
|
||||
|
||||
override DataFlow::Node getTest() { none() }
|
||||
|
||||
override DataFlow::Node getAMemberNode() { result = switch.getACase().getExpr().flow() }
|
||||
}
|
||||
}
|
||||
@@ -629,4 +629,153 @@ module StringOps {
|
||||
class HtmlConcatenationLeaf extends ConcatenationLeaf {
|
||||
HtmlConcatenationLeaf() { getRoot() instanceof HtmlConcatenationRoot }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node whose boolean value indicates whether a regexp matches a given string.
|
||||
*
|
||||
* For example, the condition of each of the following `if`-statements are `RegExpTest` nodes:
|
||||
* ```js
|
||||
* if (regexp.test(str)) { ... }
|
||||
* if (regexp.exec(str) != null) { ... }
|
||||
* if (str.matches(regexp)) { ... }
|
||||
* ```
|
||||
*
|
||||
* Note that `RegExpTest` represents a boolean-valued expression or one
|
||||
* that is coerced to a boolean, which is not always the same as the call that performs the
|
||||
* regexp-matching. For example, the `exec` call below is not itself a `RegExpTest`,
|
||||
* but the `match` variable in the condition is:
|
||||
* ```js
|
||||
* let match = regexp.exec(str);
|
||||
* if (!match) { ... } // <--- 'match' is the RegExpTest
|
||||
* ```
|
||||
*/
|
||||
class RegExpTest extends DataFlow::Node {
|
||||
RegExpTest::Range range;
|
||||
|
||||
RegExpTest() { this = range }
|
||||
|
||||
/**
|
||||
* Gets the AST of the regular expression used in the test, if it can be seen locally.
|
||||
*/
|
||||
RegExpTerm getRegExp() {
|
||||
result = getRegExpOperand().getALocalSource().(DataFlow::RegExpCreationNode).getRoot()
|
||||
or
|
||||
result = range.getRegExpOperand(true).asExpr().(StringLiteral).asRegExp()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data flow node corresponding to the regular expression object used in the test.
|
||||
*
|
||||
* In some cases this represents a string value being coerced to a RegExp object.
|
||||
*/
|
||||
DataFlow::Node getRegExpOperand() { result = range.getRegExpOperand(_) }
|
||||
|
||||
/**
|
||||
* Gets the data flow node corresponding to the string being tested against the regular expression.
|
||||
*/
|
||||
DataFlow::Node getStringOperand() { result = range.getStringOperand() }
|
||||
|
||||
/**
|
||||
* Gets the return value indicating that the string matched the regular expression.
|
||||
*
|
||||
* For example, for `regexp.exec(str) == null`, the polarity is `false`, and for
|
||||
* `regexp.exec(str) != null` the polarity is `true`.
|
||||
*/
|
||||
boolean getPolarity() { result = range.getPolarity() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Companion module to the `RegExpTest` class.
|
||||
*/
|
||||
module RegExpTest {
|
||||
/**
|
||||
* A data flow node whose boolean value indicates whether a regexp matches a given string.
|
||||
*
|
||||
* This class can be extended to contribute new kinds of `RegExpTest` nodes.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the data flow node corresponding to the regular expression object used in the test.
|
||||
*/
|
||||
abstract DataFlow::Node getRegExpOperand(boolean coerced);
|
||||
|
||||
/**
|
||||
* Gets the data flow node corresponding to the string being tested against the regular expression.
|
||||
*/
|
||||
abstract DataFlow::Node getStringOperand();
|
||||
|
||||
/**
|
||||
* Gets the return value indicating that the string matched the regular expression.
|
||||
*/
|
||||
boolean getPolarity() { result = true }
|
||||
}
|
||||
|
||||
private class TestCall extends Range, DataFlow::MethodCallNode {
|
||||
TestCall() { getMethodName() = "test" }
|
||||
|
||||
override DataFlow::Node getRegExpOperand(boolean coerced) {
|
||||
result = getReceiver() and coerced = false
|
||||
}
|
||||
|
||||
override DataFlow::Node getStringOperand() { result = getArgument(0) }
|
||||
}
|
||||
|
||||
private class MatchesCall extends Range, DataFlow::MethodCallNode {
|
||||
MatchesCall() { getMethodName() = "matches" }
|
||||
|
||||
override DataFlow::Node getRegExpOperand(boolean coerced) {
|
||||
result = getArgument(0) and coerced = true
|
||||
}
|
||||
|
||||
override DataFlow::Node getStringOperand() { result = getReceiver() }
|
||||
}
|
||||
|
||||
private class ExecCall extends DataFlow::MethodCallNode {
|
||||
ExecCall() { getMethodName() = "exec" }
|
||||
}
|
||||
|
||||
private predicate isCoercedToBoolean(Expr e) {
|
||||
e = any(ConditionGuardNode guard).getTest()
|
||||
or
|
||||
e = any(LogNotExpr n).getOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` evaluating to `polarity` implies that `operand` is not null.
|
||||
*/
|
||||
private predicate impliesNotNull(Expr e, Expr operand, boolean polarity) {
|
||||
exists(EqualityTest test, Expr other |
|
||||
e = test and
|
||||
polarity = test.getPolarity().booleanNot() and
|
||||
test.hasOperands(other, operand) and
|
||||
SyntacticConstants::isNullOrUndefined(other) and
|
||||
not (
|
||||
// 'exec() === undefined' doesn't work
|
||||
other instanceof SyntacticConstants::UndefinedConstant and
|
||||
test.isStrict()
|
||||
)
|
||||
)
|
||||
or
|
||||
isCoercedToBoolean(e) and
|
||||
operand = e and
|
||||
polarity = true
|
||||
}
|
||||
|
||||
private class ExecTest extends Range, DataFlow::ValueNode {
|
||||
ExecCall exec;
|
||||
boolean polarity;
|
||||
|
||||
ExecTest() {
|
||||
exists(Expr use | exec.flowsToExpr(use) | impliesNotNull(astNode, use, polarity))
|
||||
}
|
||||
|
||||
override DataFlow::Node getRegExpOperand(boolean coerced) {
|
||||
result = exec.getReceiver() and coerced = false
|
||||
}
|
||||
|
||||
override DataFlow::Node getStringOperand() { result = exec.getArgument(0) }
|
||||
|
||||
override boolean getPolarity() { result = polarity }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +438,10 @@ private predicate barrierGuardBlocksNode(BarrierGuardNode guard, DataFlow::Node
|
||||
barrierGuardIsRelevant(guard) and
|
||||
exists(AccessPath p, BasicBlock bb, ConditionGuardNode cond, boolean outcome |
|
||||
nd = DataFlow::valueNode(p.getAnInstanceIn(bb)) and
|
||||
guard.getEnclosingExpr() = cond.getTest() and
|
||||
(
|
||||
guard.getEnclosingExpr() = cond.getTest() or
|
||||
guard = cond.getTest().flow().getImmediatePredecessor+()
|
||||
) and
|
||||
outcome = cond.getOutcome() and
|
||||
barrierGuardBlocksAccessPath(guard, outcome, p, label) and
|
||||
cond.dominates(bb)
|
||||
|
||||
@@ -827,6 +827,29 @@ module TaintTracking {
|
||||
override predicate appliesTo(Configuration cfg) { any() }
|
||||
}
|
||||
|
||||
/** A check of the form `type x === "undefined"`, which sanitized `x` in its "then" branch. */
|
||||
class TypeOfUndefinedSanitizer extends AdditionalSanitizerGuardNode, DataFlow::ValueNode {
|
||||
Expr x;
|
||||
override EqualityTest astNode;
|
||||
|
||||
TypeOfUndefinedSanitizer() {
|
||||
exists(StringLiteral str, TypeofExpr typeof | astNode.hasOperands(str, typeof) |
|
||||
str.getValue() = "undefined" and
|
||||
typeof.getOperand() = x
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sanitizes(boolean outcome, Expr e) {
|
||||
outcome = astNode.getPolarity() and
|
||||
e = x
|
||||
}
|
||||
|
||||
override predicate appliesTo(Configuration cfg) { any() }
|
||||
}
|
||||
|
||||
/** DEPRECATED. This class has been renamed to `MembershipTestSanitizer`. */
|
||||
deprecated class StringInclusionSanitizer = MembershipTestSanitizer;
|
||||
|
||||
/**
|
||||
* A test of form `x.length === "0"`, preventing `x` from being tainted.
|
||||
*/
|
||||
@@ -849,18 +872,19 @@ module TaintTracking {
|
||||
override predicate appliesTo(Configuration cfg) { any() }
|
||||
}
|
||||
|
||||
/** DEPRECATED. This class has been renamed to `InclusionSanitizer`. */
|
||||
deprecated class StringInclusionSanitizer = InclusionSanitizer;
|
||||
/** DEPRECATED. This class has been renamed to `MembershipTestSanitizer`. */
|
||||
deprecated class InclusionSanitizer = MembershipTestSanitizer;
|
||||
|
||||
/** A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. */
|
||||
class InclusionSanitizer extends AdditionalSanitizerGuardNode {
|
||||
InclusionTest inclusion;
|
||||
/**
|
||||
* A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch.
|
||||
*/
|
||||
class MembershipTestSanitizer extends AdditionalSanitizerGuardNode {
|
||||
MembershipCandidate candidate;
|
||||
|
||||
InclusionSanitizer() { this = inclusion }
|
||||
MembershipTestSanitizer() { this = candidate.getTest() }
|
||||
|
||||
override predicate sanitizes(boolean outcome, Expr e) {
|
||||
outcome = inclusion.getPolarity() and
|
||||
e = inclusion.getContainedNode().asExpr()
|
||||
candidate = e.flow() and candidate.getTestPolarity() = outcome
|
||||
}
|
||||
|
||||
override predicate appliesTo(Configuration cfg) { any() }
|
||||
@@ -895,8 +919,12 @@ module TaintTracking {
|
||||
/** Gets a variable that is defined exactly once. */
|
||||
private Variable singleDef() { strictcount(result.getADefinition()) = 1 }
|
||||
|
||||
/** A check of the form `if(x == 'some-constant')`, which sanitizes `x` in its "then" branch. */
|
||||
class ConstantComparison extends AdditionalSanitizerGuardNode, DataFlow::ValueNode {
|
||||
/**
|
||||
* A check of the form `if(x == 'some-constant')`, which sanitizes `x` in its "then" branch.
|
||||
*
|
||||
* DEPRECATED: use `MembershipTestSanitizer` instead.
|
||||
*/
|
||||
deprecated class ConstantComparison extends SanitizerGuardNode, DataFlow::ValueNode {
|
||||
Expr x;
|
||||
override EqualityTest astNode;
|
||||
|
||||
@@ -914,7 +942,10 @@ module TaintTracking {
|
||||
outcome = astNode.getPolarity() and x = e
|
||||
}
|
||||
|
||||
override predicate appliesTo(Configuration cfg) { any() }
|
||||
/**
|
||||
* Holds if this guard applies to the flow in `cfg`.
|
||||
*/
|
||||
predicate appliesTo(Configuration cfg) { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user