mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge branch 'main' into alternative-instruction-operand-flow
This commit is contained in:
@@ -11,6 +11,17 @@
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Gets the template that a function `f` is constructed from, or just `f` if it
|
||||
* is not from a template instantiation.
|
||||
*/
|
||||
Function getConstructedFrom(Function f) {
|
||||
f.isConstructedFrom(result)
|
||||
or
|
||||
not f.isConstructedFrom(_) and
|
||||
result = f
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parameter of `f` with name `name`, which has to come from the
|
||||
* _definition_ of `f` and not a prototype declaration.
|
||||
@@ -18,13 +29,17 @@ import cpp
|
||||
* This should not happen in a single application but since we
|
||||
* have a system wide view it is likely to happen for instance for
|
||||
* the main function.
|
||||
*
|
||||
* Note: we use `getConstructedFrom` to ensure that we look at template
|
||||
* functions rather than their instantiations. We get better results this way
|
||||
* as the instantiation is artificial and may have inherited parameter names
|
||||
* from the declaration rather than the definition.
|
||||
*/
|
||||
ParameterDeclarationEntry functionParameterNames(Function f, string name) {
|
||||
exists(FunctionDeclarationEntry fe |
|
||||
result.getFunctionDeclarationEntry() = fe and
|
||||
fe.getFunction() = f and
|
||||
getConstructedFrom(f).getDefinition() = fe and
|
||||
fe.getLocation() = f.getDefinitionLocation() and
|
||||
result.getFile() = fe.getFile() and // Work around CPP-331
|
||||
strictcount(f.getDefinitionLocation()) = 1 and
|
||||
result.getName() = name
|
||||
)
|
||||
|
||||
11
cpp/ql/src/Critical/aliasAnalysisWarning.qhelp
Normal file
11
cpp/ql/src/Critical/aliasAnalysisWarning.qhelp
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<fragment>
|
||||
<warning>
|
||||
This check is an approximation, so some results may not be actual defects in the program.
|
||||
It is not possible in general to compute the exact value of the variable without running the program with all possible input data.
|
||||
</warning>
|
||||
</fragment>
|
||||
</qhelp>
|
||||
12
cpp/ql/src/Critical/callGraphWarning.qhelp
Normal file
12
cpp/ql/src/Critical/callGraphWarning.qhelp
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<fragment>
|
||||
<warning>
|
||||
This check is an approximation, so some results may not be actual defects in the program.
|
||||
It is not possible in general to compute which function is actually called in a virtual call,
|
||||
or a call through a pointer, without running the program with all possible input data.
|
||||
</warning>
|
||||
</fragment>
|
||||
</qhelp>
|
||||
13
cpp/ql/src/Critical/dataFlowWarning.qhelp
Normal file
13
cpp/ql/src/Critical/dataFlowWarning.qhelp
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<fragment>
|
||||
<warning>
|
||||
This check is an approximation, so some results may not be actual defects in the program.
|
||||
It is not possible in general to compute the actual branch taken in conditional statements such
|
||||
as "if" without running the program with all possible input data. This means that it is not possible
|
||||
to determine if a particular statement is going to be executed.
|
||||
</warning>
|
||||
</fragment>
|
||||
</qhelp>
|
||||
11
cpp/ql/src/Critical/pointsToWarning.qhelp
Normal file
11
cpp/ql/src/Critical/pointsToWarning.qhelp
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<fragment>
|
||||
<warning>
|
||||
This check is an approximation, so some results may not be actual defects in the program. It is not possible
|
||||
in general to compute the values of pointers without running the program with all input data.
|
||||
</warning>
|
||||
</fragment>
|
||||
</qhelp>
|
||||
@@ -3,5 +3,5 @@
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="CommentedOutCodeQuery.qhelp" />
|
||||
<include src="CommentedOutCodeReferences.qhelp" />
|
||||
<include src="../Metrics/Files/CommentedOutCodeReferences.qhelp" />
|
||||
</qhelp>
|
||||
|
||||
25
cpp/ql/src/Documentation/CommentedOutCodeQuery.qhelp
Normal file
25
cpp/ql/src/Documentation/CommentedOutCodeQuery.qhelp
Normal file
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Commented-out code is distracting and confusing for developers who read the surrounding code,
|
||||
and its significance is often unclear. It will not get compiled or tested when the code around
|
||||
it changes, so it's likely to break over time. For these reasons, commented-out code should be
|
||||
avoided.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
Remove or reinstate the commented-out code. If you want to include a snippet of example code
|
||||
in a comment, consider enclosing it in quotes or marking it up as appropriate for the source
|
||||
language.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
This metric counts the number of lines of commented-out code in each file. Large amounts of
|
||||
commented-out code often indicate poorly maintained code.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
</qhelp>
|
||||
12
cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp
Normal file
12
cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<references>
|
||||
|
||||
<li>Mark Needham: <a href="http://www.markhneedham.com/blog/2009/01/17/the-danger-of-commenting-out-code/">The danger of commenting out code</a>.</li>
|
||||
<li>Los Techies: <a href="http://lostechies.com/rodpaddock/2010/12/29/commented-code-technical-debt">Commented Code == Technical Debt</a>.</li>
|
||||
<li>High Integrity C++ Coding Standard: <a href="http://www.codingstandard.com/rule/2-3-2-do-not-comment-out-code/">2.3.2 Do not comment out code</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
16
cpp/ql/src/Metrics/Files/DuplicationProblems.qhelp
Normal file
16
cpp/ql/src/Metrics/Files/DuplicationProblems.qhelp
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Duplicated code increases overall code size, making the code base
|
||||
harder to maintain and harder to understand. It also becomes harder to fix bugs,
|
||||
since a programmer applying a fix to one copy has to always remember to update
|
||||
other copies accordingly. Finally, code duplication is generally an indication of
|
||||
a poorly designed or hastily written code base, which typically suffers from other
|
||||
problems as well.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
</qhelp>
|
||||
35
cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp
Normal file
35
cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp
Normal file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
|
||||
<p>
|
||||
This metric measures the number of lines in a file that are contained within a block that is duplicated elsewhere. These lines may include code, comments and whitespace, and the duplicate block may be in this file or in another file.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A file that contains many lines that are duplicated within the code base is problematic
|
||||
for a number of reasons.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<include src="DuplicationProblems.qhelp" />
|
||||
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
Refactor files with lots of duplicated code to extract the common code into
|
||||
a shared library or module.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<references>
|
||||
|
||||
|
||||
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Duplicate_code">Duplicate code</a>.</li>
|
||||
<li>M. Fowler, <em>Refactoring</em>. Addison-Wesley, 1999.</li>
|
||||
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,11 @@
|
||||
void test(char *arg1, int *arg2) {
|
||||
if (arg1[0] == 'A') {
|
||||
if (arg2 != NULL) { //maybe redundant
|
||||
*arg2 = 42;
|
||||
}
|
||||
}
|
||||
if (arg1[1] == 'B')
|
||||
{
|
||||
*arg2 = 54; //dereferenced without checking first
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>This rule finds comparisons of a function parameter to null that occur when in another path the parameter is dereferenced without a guard check. It's
|
||||
likely either the check is not required and can be removed, or it should be added before the dereference
|
||||
so that a null pointer dereference does not occur.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>A check should be added to before the dereference, in a way that prevents a null pointer value from
|
||||
being dereferenced. If it's clear that the pointer cannot be null, consider removing the check instead.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<sample src="RedundantNullCheckParam.cpp" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://www.owasp.org/index.php/Null_Dereference">
|
||||
Null Dereference
|
||||
</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @name Redundant null check or missing null check of parameter
|
||||
* @description Checking a parameter for nullness in one path,
|
||||
* and not in another is likely to be a sign that either
|
||||
* the check can be removed, or added in the other case.
|
||||
* @kind problem
|
||||
* @id cpp/redundant-null-check-param
|
||||
* @problem.severity recommendation
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-476
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
predicate blockDominates(Block check, Block access) {
|
||||
check.getLocation().getStartLine() <= access.getLocation().getStartLine() and
|
||||
check.getLocation().getEndLine() >= access.getLocation().getEndLine()
|
||||
}
|
||||
|
||||
predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) {
|
||||
checked = any(VariableAccess va | va.getTarget() = unchecked.getTarget()) and
|
||||
//Simple test if the first access in this code path is dereferenced
|
||||
not dereferenced(checked) and
|
||||
blockDominates(checked.getEnclosingBlock(), unchecked.getEnclosingBlock())
|
||||
}
|
||||
|
||||
predicate candidateResultUnchecked(VariableAccess unchecked) {
|
||||
not isCheckedInstruction(unchecked, _)
|
||||
}
|
||||
|
||||
predicate candidateResultChecked(VariableAccess check, EqualityOperation eqop) {
|
||||
//not dereferenced to check against pointer, not its pointed value
|
||||
not dereferenced(check) and
|
||||
//assert macros are not taken into account
|
||||
not check.isInMacroExpansion() and
|
||||
// is part of a comparison against some constant NULL
|
||||
eqop.getAnOperand() = check and
|
||||
eqop.getAnOperand() instanceof NullValue
|
||||
}
|
||||
|
||||
from VariableAccess unchecked, VariableAccess check, EqualityOperation eqop, Parameter param
|
||||
where
|
||||
// a dereference
|
||||
dereferenced(unchecked) and
|
||||
// for a function parameter
|
||||
unchecked.getTarget() = param and
|
||||
// this function parameter is not overwritten
|
||||
count(param.getAnAssignment()) = 0 and
|
||||
check.getTarget() = param and
|
||||
// which is once checked
|
||||
candidateResultChecked(check, eqop) and
|
||||
// and which has not been checked before in this code path
|
||||
candidateResultUnchecked(unchecked)
|
||||
select check, "This null check is redundant or there is a missing null check before $@ ", unchecked,
|
||||
"where dereferencing happens"
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="cpp/jsfNote.qhelp" />
|
||||
<include src="../jsfNote.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights calls to the standard library functions <code>abort, exit, getenv</code> and <code>system</code>.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="cpp/jsfNote.qhelp" />
|
||||
<include src="../jsfNote.qhelp" />
|
||||
|
||||
<p>
|
||||
This query ensures that all operators with opposites (e.g. == and !=) are both defined, and
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="cpp/jsfNote.qhelp" />
|
||||
<include src="../jsfNote.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights return statements that return pointers to an object allocated on the stack. The lifetime
|
||||
@@ -18,7 +18,7 @@ memory after the function has already returned will have undefined results.
|
||||
|
||||
|
||||
<!-- Mention how the results could be probabilistic (uses pointsto) -->
|
||||
<include src="pointsToWarning.qhelp" />
|
||||
<include src="../../Critical/pointsToWarning.qhelp" />
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
@@ -12,7 +12,7 @@ calling convention for x86, it would be whatever value was in the AX/EAX registe
|
||||
assuming the function had a non-float return type that can fit in a machine word.
|
||||
</p>
|
||||
|
||||
<include src="dataFlowWarning.qhelp" />
|
||||
<include src="../../Critical/dataFlowWarning.qhelp" />
|
||||
|
||||
<!--/*FALSEPOSITIVE_WARNING*/-->
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="cpp/jsfNote.qhelp" />
|
||||
<include src="../jsfNote.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights identifiers in an inner scope that hide (have the same name as) an identifier in an outer scope.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="cpp/jsfNote.qhelp" />
|
||||
<include src="../jsfNote.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights variables with the <code>register</code> storage class specifier. Modern compilers are now capable of
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="cpp/jsfNote.qhelp" />
|
||||
<include src="../jsfNote.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights portions of code that can expose the floating point implementation of the underlying
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="cpp/jsfNote.qhelp" />
|
||||
<include src="../jsfNote.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights string literals that are assigned to a non-<code>const</code> variable. String literals
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="cpp/jsfNote.qhelp" />
|
||||
<include src="../jsfNote.qhelp" />
|
||||
|
||||
<p>
|
||||
This query finds bit fields with members that are not explicitly declared to be unsigned.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="cpp/jsfNote.qhelp" />
|
||||
<include src="../jsfNote.qhelp" />
|
||||
|
||||
<p>
|
||||
This query finds unsigned values that are being negated. Behavior is undefined in such cases.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="cpp/jsfNote.qhelp" />
|
||||
<include src="../jsfNote.qhelp" />
|
||||
|
||||
<p>Use of goto statements makes code more difficult to understand and maintain. Consequently, the use
|
||||
of goto statements is deprecated except as a mechanism for breaking out of multiple nested loops.
|
||||
|
||||
18
cpp/ql/src/jsf/jsfNote.qhelp
Normal file
18
cpp/ql/src/jsf/jsfNote.qhelp
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<fragment>
|
||||
<p>
|
||||
This query is part of a suite that tests code against
|
||||
the <em>Joint Strike Fighter Air Vehicle C++ Coding Standard</em> (JSF).
|
||||
Alerts reported by this query highlight code that may break the
|
||||
JSF rule listed in the References section.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The JSF rule this query tests is likely to be too strict for projects
|
||||
that do not follow the JSF standard.
|
||||
</p>
|
||||
</fragment>
|
||||
</qhelp>
|
||||
@@ -65,7 +65,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
|
||||
* taken when this expression is true.
|
||||
*/
|
||||
ControlFlowNode getATrueSuccessor() {
|
||||
truecond_base(this, result) and
|
||||
qlCFGTrueSuccessor(this, result) and
|
||||
result = getASuccessor()
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
|
||||
* taken when this expression is false.
|
||||
*/
|
||||
ControlFlowNode getAFalseSuccessor() {
|
||||
falsecond_base(this, result) and
|
||||
qlCFGFalseSuccessor(this, result) and
|
||||
result = getASuccessor()
|
||||
}
|
||||
|
||||
@@ -95,18 +95,20 @@ import ControlFlowGraphPublic
|
||||
class ControlFlowNodeBase extends ElementBase, @cfgnode { }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ControlFlowNode.getATrueSuccessor()` instead.
|
||||
* Holds when `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
||||
*/
|
||||
predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
|
||||
deprecated predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
|
||||
qlCFGTrueSuccessor(n1, n2)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ControlFlowNode.getAFalseSuccessor()` instead.
|
||||
* Holds when `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
||||
*/
|
||||
predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
|
||||
deprecated predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
|
||||
qlCFGFalseSuccessor(n1, n2)
|
||||
}
|
||||
|
||||
@@ -134,7 +136,7 @@ abstract class AdditionalControlFlowEdge extends ControlFlowNodeBase {
|
||||
/**
|
||||
* Holds if there is a control-flow edge from `source` to `target` in either
|
||||
* the extractor-generated control-flow graph or in a subclass of
|
||||
* `AdditionalControlFlowEdge`. Use this relation instead of `successors`.
|
||||
* `AdditionalControlFlowEdge`. Use this relation instead of `qlCFGSuccessor`.
|
||||
*/
|
||||
predicate successors_extended(ControlFlowNodeBase source, ControlFlowNodeBase target) {
|
||||
qlCFGSuccessor(source, target)
|
||||
|
||||
@@ -73,8 +73,20 @@ private predicate addressTakenVariable(StackVariable var) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is a stack-allocated reference-typed local variable. We don't
|
||||
* build SSA for such variables since they are likely to change values even
|
||||
* when not syntactically mentioned. For the same reason,
|
||||
* `addressTakenVariable` is used to prevent tracking variables that may be
|
||||
* aliased by such a reference.
|
||||
*
|
||||
* Reference-typed parameters are treated as if they weren't references.
|
||||
* That's because it's in practice highly unlikely that they alias other data
|
||||
* accessible from the function body.
|
||||
*/
|
||||
private predicate isReferenceVar(StackVariable v) {
|
||||
v.getUnspecifiedType() instanceof ReferenceType
|
||||
v.getUnspecifiedType() instanceof ReferenceType and
|
||||
not v instanceof Parameter
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1376,8 +1376,6 @@ private module Cached {
|
||||
/**
|
||||
* Holds if `n2` is a successor of `n1` in the CFG. This includes also
|
||||
* true-successors and false-successors.
|
||||
*
|
||||
* This corresponds to the old `successors` dbscheme relation.
|
||||
*/
|
||||
cached
|
||||
predicate qlCFGSuccessor(Node n1, Node n2) {
|
||||
@@ -1390,9 +1388,8 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n2` is a true-successor of `n1` in the CFG.
|
||||
*
|
||||
* This corresponds to the old `truecond` dbscheme relation.
|
||||
* Holds if `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
||||
*/
|
||||
cached
|
||||
predicate qlCFGTrueSuccessor(Node n1, Node n2) {
|
||||
@@ -1401,9 +1398,8 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n2` is a false-successor of `n1` in the CFG.
|
||||
*
|
||||
* This corresponds to the old `falsecond` dbscheme relation.
|
||||
* Holds if `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
||||
*/
|
||||
cached
|
||||
predicate qlCFGFalseSuccessor(Node n1, Node n2) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import cpp
|
||||
private import PrimitiveBasicBlocks
|
||||
private import semmle.code.cpp.controlflow.internal.CFG
|
||||
|
||||
private class Node = ControlFlowNodeBase;
|
||||
|
||||
@@ -153,8 +154,8 @@ private predicate nonAnalyzableFunction(Function f) {
|
||||
*/
|
||||
private predicate impossibleFalseEdge(Expr condition, Node succ) {
|
||||
conditionAlwaysTrue(condition) and
|
||||
falsecond_base(condition, succ) and
|
||||
not truecond_base(condition, succ)
|
||||
qlCFGFalseSuccessor(condition, succ) and
|
||||
not qlCFGTrueSuccessor(condition, succ)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,8 +163,8 @@ private predicate impossibleFalseEdge(Expr condition, Node succ) {
|
||||
*/
|
||||
private predicate impossibleTrueEdge(Expr condition, Node succ) {
|
||||
conditionAlwaysFalse(condition) and
|
||||
truecond_base(condition, succ) and
|
||||
not falsecond_base(condition, succ)
|
||||
qlCFGTrueSuccessor(condition, succ) and
|
||||
not qlCFGFalseSuccessor(condition, succ)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -863,9 +864,9 @@ library class ConditionEvaluator extends ExprEvaluator {
|
||||
ConditionEvaluator() { this = 0 }
|
||||
|
||||
override predicate interesting(Expr e) {
|
||||
falsecond_base(e, _)
|
||||
qlCFGFalseSuccessor(e, _)
|
||||
or
|
||||
truecond_base(e, _)
|
||||
qlCFGTrueSuccessor(e, _)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,8 +123,18 @@ module Consistency {
|
||||
n.getEnclosingCallable() != call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
// This predicate helps the compiler forget that in some languages
|
||||
// it is impossible for a result of `getPreUpdateNode` to be an
|
||||
// instance of `PostUpdateNode`.
|
||||
private Node getPre(PostUpdateNode n) {
|
||||
result = n.getPreUpdateNode()
|
||||
or
|
||||
none()
|
||||
}
|
||||
|
||||
query predicate postIsNotPre(PostUpdateNode n, string msg) {
|
||||
n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node."
|
||||
getPre(n) = n and
|
||||
msg = "PostUpdateNode should not equal its pre-update node."
|
||||
}
|
||||
|
||||
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
|
||||
@@ -152,12 +162,6 @@ module Consistency {
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
query predicate storeIsPostUpdate(Node n, string msg) {
|
||||
storeStep(_, _, n) and
|
||||
not n instanceof PostUpdateNode and
|
||||
msg = "Store targets should be PostUpdateNodes."
|
||||
}
|
||||
|
||||
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
|
||||
not hasPost(n) and
|
||||
not isImmutableOrUnobservable(n) and
|
||||
|
||||
@@ -50,13 +50,25 @@ class Node extends TNode {
|
||||
/** Gets the type of this node. */
|
||||
Type getType() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the expression corresponding to this node, if any. */
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. This predicate
|
||||
* only has a result on nodes that represent the value of evaluating the
|
||||
* expression. For data flowing _out of_ an expression, like when an
|
||||
* argument is passed by reference, use `asDefiningArgument` instead of
|
||||
* `asExpr`.
|
||||
*/
|
||||
Expr asExpr() { result = this.(ExprNode).getExpr() }
|
||||
|
||||
/** Gets the parameter corresponding to this node, if any. */
|
||||
Parameter asParameter() { result = this.(ExplicitParameterNode).getParameter() }
|
||||
|
||||
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
|
||||
/**
|
||||
* Gets the argument that defines this `DefinitionByReferenceNode`, if any.
|
||||
* This predicate should be used instead of `asExpr` when referring to the
|
||||
* value of a reference argument _after_ the call has returned. For example,
|
||||
* in `f(&x)`, this predicate will have `&x` as its result for the `Node`
|
||||
* that represents the new value of `x`.
|
||||
*/
|
||||
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
|
||||
|
||||
/**
|
||||
@@ -383,7 +395,9 @@ class PreConstructorInitThis extends Node, TPreConstructorInitThis {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Node` corresponding to `e`.
|
||||
* Gets the `Node` corresponding to the value of evaluating `e`. For data
|
||||
* flowing _out of_ an expression, like when an argument is passed by
|
||||
* reference, use `definitionByReferenceNodeFromArgument` instead.
|
||||
*/
|
||||
ExprNode exprNode(Expr e) { result.getExpr() = e }
|
||||
|
||||
@@ -484,6 +498,17 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// Expr -> Expr
|
||||
exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
or
|
||||
// Assignment -> LValue post-update node
|
||||
//
|
||||
// This is used for assignments whose left-hand side is not a variable
|
||||
// assignment or a storeStep but is still modeled by other means. It could be
|
||||
// a call to `operator*` or `operator[]` where taint should flow to the
|
||||
// post-update node of the qualifier.
|
||||
exists(AssignExpr assign |
|
||||
nodeFrom.asExpr() = assign and
|
||||
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = assign.getLValue()
|
||||
)
|
||||
or
|
||||
// Node -> FlowVar -> VariableAccess
|
||||
exists(FlowVar var |
|
||||
(
|
||||
@@ -514,6 +539,19 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and
|
||||
outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr()
|
||||
)
|
||||
or
|
||||
// Reverse flow: data that flows from the post-update node of a reference
|
||||
// returned by a function call, back into the qualifier of that function.
|
||||
// This allows data to flow 'in' through references returned by a modeled
|
||||
// function such as `operator[]`.
|
||||
exists(DataFlowFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
inModel.isReturnValueDeref() and
|
||||
outModel.isQualifierObject() and
|
||||
f.hasDataFlow(inModel, outModel) and
|
||||
nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr() = call and
|
||||
nodeTo.asDefiningArgument() = call.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -120,15 +120,25 @@ private module PartialDefinitions {
|
||||
)
|
||||
}
|
||||
|
||||
predicate partiallyDefines(Variable v) { innerDefinedExpr = v.getAnAccess() }
|
||||
deprecated predicate partiallyDefines(Variable v) { innerDefinedExpr = v.getAnAccess() }
|
||||
|
||||
predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e }
|
||||
deprecated predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e }
|
||||
|
||||
/**
|
||||
* Gets the subBasicBlock where this `PartialDefinition` is defined.
|
||||
*/
|
||||
ControlFlowNode getSubBasicBlockStart() { result = node }
|
||||
|
||||
/**
|
||||
* Holds if this `PartialDefinition` defines variable `v` at control-flow
|
||||
* node `cfn`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate partiallyDefinesVariableAt(Variable v, ControlFlowNode cfn) {
|
||||
innerDefinedExpr = v.getAnAccess() and
|
||||
cfn = node
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this partial definition may modify `inner` (or what it points
|
||||
* to) through `outer`. These expressions will never be `Conversion`s.
|
||||
@@ -188,7 +198,7 @@ module FlowVar_internal {
|
||||
predicate fullySupportedSsaVariable(Variable v) {
|
||||
v = any(SsaDefinition def).getAVariable() and
|
||||
// A partially-defined variable is handled using the partial definitions logic.
|
||||
not any(PartialDefinition p).partiallyDefines(v) and
|
||||
not any(PartialDefinition p).partiallyDefinesVariableAt(v, _) and
|
||||
// SSA variables do not exist before their first assignment, but one
|
||||
// feature of this data flow library is to track where uninitialized data
|
||||
// ends up.
|
||||
@@ -232,7 +242,7 @@ module FlowVar_internal {
|
||||
or
|
||||
assignmentLikeOperation(sbb, v, _, _)
|
||||
or
|
||||
sbb = any(PartialDefinition p | p.partiallyDefines(v)).getSubBasicBlockStart()
|
||||
exists(PartialDefinition p | p.partiallyDefinesVariableAt(v, sbb))
|
||||
or
|
||||
blockVarDefinedByVariable(sbb, v)
|
||||
)
|
||||
@@ -363,8 +373,7 @@ module FlowVar_internal {
|
||||
|
||||
override predicate definedPartiallyAt(Expr e) {
|
||||
exists(PartialDefinition p |
|
||||
p.partiallyDefines(v) and
|
||||
sbb = p.getSubBasicBlockStart() and
|
||||
p.partiallyDefinesVariableAt(v, sbb) and
|
||||
p.definesExpressions(_, e)
|
||||
)
|
||||
}
|
||||
@@ -427,7 +436,7 @@ module FlowVar_internal {
|
||||
/**
|
||||
* Gets a variable that is assigned in this loop and read outside the loop.
|
||||
*/
|
||||
private Variable getARelevantVariable() {
|
||||
Variable getARelevantVariable() {
|
||||
result = this.getAVariableAssignedInLoop() and
|
||||
exists(VariableAccess va |
|
||||
va.getTarget() = result and
|
||||
@@ -472,10 +481,16 @@ module FlowVar_internal {
|
||||
reachesWithoutAssignment(bb.getAPredecessor(), v) and
|
||||
this.bbInLoop(bb)
|
||||
) and
|
||||
not assignmentLikeOperation(bb.getANode(), v, _, _)
|
||||
not assignsToVar(bb, v)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate assignsToVar(BasicBlock bb, Variable v) {
|
||||
assignmentLikeOperation(bb.getANode(), v, _, _) and
|
||||
exists(AlwaysTrueUponEntryLoop loop | v = loop.getARelevantVariable())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `loop` always assigns to `v` before leaving through an edge
|
||||
* from `bbInside` in its condition to `bbOutside` outside the loop. Also,
|
||||
@@ -736,7 +751,7 @@ module FlowVar_internal {
|
||||
exists(Variable v | not fullySupportedSsaVariable(v) |
|
||||
assignmentLikeOperation(this, v, _, _)
|
||||
or
|
||||
this = any(PartialDefinition p | p.partiallyDefines(v)).getSubBasicBlockStart()
|
||||
exists(PartialDefinition p | p.partiallyDefinesVariableAt(v, this))
|
||||
// It is not necessary to cut the basic blocks at `Initializer` nodes
|
||||
// because the affected variable can have no _other_ value before its
|
||||
// initializer. It is not necessary to cut basic blocks at procedure
|
||||
|
||||
@@ -82,6 +82,19 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
|
||||
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
|
||||
or
|
||||
exprToPartialDefinitionStep(nodeFrom.asExpr(), nodeTo.asPartialDefinition())
|
||||
or
|
||||
// Reverse taint: taint that flows from the post-update node of a reference
|
||||
// returned by a function call, back into the qualifier of that function.
|
||||
// This allows taint to flow 'in' through references returned by a modeled
|
||||
// function such as `operator[]`.
|
||||
exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
inModel.isReturnValueDeref() and
|
||||
outModel.isQualifierObject() and
|
||||
f.hasTaintFlow(inModel, outModel) and
|
||||
nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = call and
|
||||
nodeTo.asDefiningArgument() = call.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -70,7 +70,7 @@ private DataFlow::Node getNodeForSource(Expr source) {
|
||||
//
|
||||
// This case goes together with the similar (but not identical) rule in
|
||||
// `nodeIsBarrierIn`.
|
||||
result = DataFlow::definitionByReferenceNode(source) and
|
||||
result = DataFlow::definitionByReferenceNodeFromArgument(source) and
|
||||
not argv(source.(VariableAccess).getTarget())
|
||||
)
|
||||
}
|
||||
@@ -210,7 +210,7 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) {
|
||||
or
|
||||
// This case goes together with the similar (but not identical) rule in
|
||||
// `getNodeForSource`.
|
||||
node = DataFlow::definitionByReferenceNode(source)
|
||||
node = DataFlow::definitionByReferenceNodeFromArgument(source)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -123,8 +123,18 @@ module Consistency {
|
||||
n.getEnclosingCallable() != call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
// This predicate helps the compiler forget that in some languages
|
||||
// it is impossible for a result of `getPreUpdateNode` to be an
|
||||
// instance of `PostUpdateNode`.
|
||||
private Node getPre(PostUpdateNode n) {
|
||||
result = n.getPreUpdateNode()
|
||||
or
|
||||
none()
|
||||
}
|
||||
|
||||
query predicate postIsNotPre(PostUpdateNode n, string msg) {
|
||||
n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node."
|
||||
getPre(n) = n and
|
||||
msg = "PostUpdateNode should not equal its pre-update node."
|
||||
}
|
||||
|
||||
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
|
||||
@@ -152,12 +162,6 @@ module Consistency {
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
query predicate storeIsPostUpdate(Node n, string msg) {
|
||||
storeStep(_, _, n) and
|
||||
not n instanceof PostUpdateNode and
|
||||
msg = "Store targets should be PostUpdateNodes."
|
||||
}
|
||||
|
||||
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
|
||||
not hasPost(n) and
|
||||
not isImmutableOrUnobservable(n) and
|
||||
|
||||
@@ -43,9 +43,14 @@ class Node extends TIRDataFlowNode {
|
||||
Operand asOperand() { result = this.(OperandNode).getOperand() }
|
||||
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any. If
|
||||
* this node strictly (in the sense of `asConvertedExpr`) corresponds to a
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* Gets the non-conversion expression corresponding to this node, if any.
|
||||
* This predicate only has a result on nodes that represent the value of
|
||||
* evaluating the expression. For data flowing _out of_ an expression, like
|
||||
* when an argument is passed by reference, use `asDefiningArgument` instead
|
||||
* of `asExpr`.
|
||||
*
|
||||
* If this node strictly (in the sense of `asConvertedExpr`) corresponds to
|
||||
* a `Conversion`, then the result is the underlying non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
Expr asExpr() { result = this.(ExprNode).getExpr() }
|
||||
@@ -56,7 +61,13 @@ class Node extends TIRDataFlowNode {
|
||||
*/
|
||||
Expr asConvertedExpr() { result = this.(ExprNode).getConvertedExpr() }
|
||||
|
||||
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
|
||||
/**
|
||||
* Gets the argument that defines this `DefinitionByReferenceNode`, if any.
|
||||
* This predicate should be used instead of `asExpr` when referring to the
|
||||
* value of a reference argument _after_ the call has returned. For example,
|
||||
* in `f(&x)`, this predicate will have `&x` as its result for the `Node`
|
||||
* that represents the new value of `x`.
|
||||
*/
|
||||
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
|
||||
|
||||
/** Gets the positional parameter corresponding to this node, if any. */
|
||||
@@ -379,7 +390,7 @@ private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNod
|
||||
class DefinitionByReferenceNode extends InstructionNode {
|
||||
override WriteSideEffectInstruction instr;
|
||||
|
||||
/** Gets the argument corresponding to this node. */
|
||||
/** Gets the unconverted argument corresponding to this node. */
|
||||
Expr getArgument() {
|
||||
result =
|
||||
instr
|
||||
@@ -463,20 +474,26 @@ class VariableNode extends Node, TVariableNode {
|
||||
InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `definitionByReferenceNodeFromArgument` instead.
|
||||
*
|
||||
* Gets the `Node` corresponding to a definition by reference of the variable
|
||||
* that is passed as `argument` of a call.
|
||||
*/
|
||||
DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e }
|
||||
deprecated DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e }
|
||||
|
||||
/**
|
||||
* Gets a `Node` corresponding to `e` or any of its conversions. There is no
|
||||
* result if `e` is a `Conversion`.
|
||||
* Gets the `Node` corresponding to the value of evaluating `e` or any of its
|
||||
* conversions. There is no result if `e` is a `Conversion`. For data flowing
|
||||
* _out of_ an expression, like when an argument is passed by reference, use
|
||||
* `definitionByReferenceNodeFromArgument` instead.
|
||||
*/
|
||||
ExprNode exprNode(Expr e) { result.getExpr() = e }
|
||||
|
||||
/**
|
||||
* Gets the `Node` corresponding to `e`, if any. Here, `e` may be a
|
||||
* `Conversion`.
|
||||
* Gets the `Node` corresponding to the value of evaluating `e`. Here, `e` may
|
||||
* be a `Conversion`. For data flowing _out of_ an expression, like when an
|
||||
* argument is passed by reference, use
|
||||
* `definitionByReferenceNodeFromArgument` instead.
|
||||
*/
|
||||
ExprNode convertedExprNode(Expr e) { result.getConvertedExpr() = e }
|
||||
|
||||
@@ -485,6 +502,14 @@ ExprNode convertedExprNode(Expr e) { result.getConvertedExpr() = e }
|
||||
*/
|
||||
ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p }
|
||||
|
||||
/**
|
||||
* Gets the `Node` corresponding to a definition by reference of the variable
|
||||
* that is passed as unconverted `argument` of a call.
|
||||
*/
|
||||
DefinitionByReferenceNode definitionByReferenceNodeFromArgument(Expr argument) {
|
||||
result.getArgument() = argument
|
||||
}
|
||||
|
||||
/** Gets the `VariableNode` corresponding to the variable `v`. */
|
||||
VariableNode variableNode(Variable v) { result.getVariable() = v }
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ private import implementations.Fread
|
||||
private import implementations.Gets
|
||||
private import implementations.IdentityFunction
|
||||
private import implementations.Inet
|
||||
private import implementations.Iterator
|
||||
private import implementations.MemberFunction
|
||||
private import implementations.Memcpy
|
||||
private import implementations.Memset
|
||||
|
||||
273
cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll
Normal file
273
cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* Provides implementation classes modeling C++ iterators, including
|
||||
* `std::iterator`, `std::iterator_traits`, and types meeting the
|
||||
* `LegacyIterator` named requirement. See `semmle.code.cpp.models.Models` for
|
||||
* usage information.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
|
||||
/**
|
||||
* An instantiation of the `std::iterator_traits` template.
|
||||
*/
|
||||
class IteratorTraits extends Class {
|
||||
IteratorTraits() {
|
||||
this.hasQualifiedName("std", "iterator_traits") and
|
||||
not this instanceof TemplateClass and
|
||||
exists(TypedefType t |
|
||||
this.getAMember() = t and
|
||||
t.getName() = "iterator_category"
|
||||
)
|
||||
}
|
||||
|
||||
Type getIteratorType() { result = this.getTemplateArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type which has the typedefs expected for an iterator.
|
||||
*/
|
||||
class IteratorByTypedefs extends Class {
|
||||
IteratorByTypedefs() {
|
||||
this.getAMember().(TypedefType).hasName("difference_type") and
|
||||
this.getAMember().(TypedefType).hasName("value_type") and
|
||||
this.getAMember().(TypedefType).hasName("pointer") and
|
||||
this.getAMember().(TypedefType).hasName("reference") and
|
||||
this.getAMember().(TypedefType).hasName("iterator_category") and
|
||||
not this.hasQualifiedName("std", "iterator_traits")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::iterator` class.
|
||||
*/
|
||||
class StdIterator extends Class {
|
||||
StdIterator() { this.hasQualifiedName("std", "iterator") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type which can be used as an iterator
|
||||
*/
|
||||
class Iterator extends Type {
|
||||
Iterator() {
|
||||
this instanceof IteratorByTypedefs or
|
||||
exists(IteratorTraits it | it.getIteratorType() = this) or
|
||||
this instanceof StdIterator
|
||||
}
|
||||
}
|
||||
|
||||
private FunctionInput getIteratorArgumentInput(Operator op, int index) {
|
||||
exists(Type t |
|
||||
t =
|
||||
op
|
||||
.getACallToThisFunction()
|
||||
.getArgument(index)
|
||||
.getExplicitlyConverted()
|
||||
.getType()
|
||||
.stripTopLevelSpecifiers()
|
||||
|
|
||||
(
|
||||
t instanceof Iterator or
|
||||
t.(ReferenceType).getBaseType() instanceof Iterator
|
||||
) and
|
||||
if op.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
then result.isParameterDeref(index)
|
||||
else result.isParameter(index)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-member prefix `operator*` function for an iterator type.
|
||||
*/
|
||||
class IteratorPointerDereferenceOperator extends Operator, TaintFunction {
|
||||
FunctionInput iteratorInput;
|
||||
|
||||
IteratorPointerDereferenceOperator() {
|
||||
this.hasName("operator*") and
|
||||
iteratorInput = getIteratorArgumentInput(this, 0)
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = iteratorInput and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-member `operator++` or `operator--` function for an iterator type.
|
||||
*/
|
||||
class IteratorCrementOperator extends Operator, DataFlowFunction {
|
||||
FunctionInput iteratorInput;
|
||||
|
||||
IteratorCrementOperator() {
|
||||
this.hasName(["operator++", "operator--"]) and
|
||||
iteratorInput = getIteratorArgumentInput(this, 0)
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = iteratorInput and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-member `operator+` function for an iterator type.
|
||||
*/
|
||||
class IteratorAddOperator extends Operator, TaintFunction {
|
||||
FunctionInput iteratorInput;
|
||||
|
||||
IteratorAddOperator() {
|
||||
this.hasName("operator+") and
|
||||
iteratorInput = getIteratorArgumentInput(this, [0, 1])
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = iteratorInput and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-member `operator-` function that takes a pointer difference type as its second argument.
|
||||
*/
|
||||
class IteratorSubOperator extends Operator, TaintFunction {
|
||||
FunctionInput iteratorInput;
|
||||
|
||||
IteratorSubOperator() {
|
||||
this.hasName("operator-") and
|
||||
iteratorInput = getIteratorArgumentInput(this, 0) and
|
||||
this.getParameter(1).getUnspecifiedType() instanceof IntegralType // not an iterator difference
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = iteratorInput and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-member `operator+=` or `operator-=` function for an iterator type.
|
||||
*/
|
||||
class IteratorAssignArithmeticOperator extends Operator, DataFlowFunction, TaintFunction {
|
||||
IteratorAssignArithmeticOperator() {
|
||||
this.hasName(["operator+=", "operator-="]) and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameter(0) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(1) and
|
||||
output.isParameterDeref(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A prefix `operator*` member function for an iterator type.
|
||||
*/
|
||||
class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction {
|
||||
IteratorPointerDereferenceMemberOperator() {
|
||||
this.hasName("operator*") and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `operator++` or `operator--` member function for an iterator type.
|
||||
*/
|
||||
class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction {
|
||||
IteratorCrementMemberOperator() {
|
||||
this.hasName(["operator++", "operator--"]) and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierAddress() and
|
||||
output.isReturnValue()
|
||||
or
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A member `operator->` function for an iterator type.
|
||||
*/
|
||||
class IteratorFieldMemberOperator extends Operator, TaintFunction {
|
||||
IteratorFieldMemberOperator() {
|
||||
this.hasName("operator->") and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `operator+` or `operator-` member function of an iterator class.
|
||||
*/
|
||||
class IteratorBinaryArithmeticMemberOperator extends MemberFunction, TaintFunction {
|
||||
IteratorBinaryArithmeticMemberOperator() {
|
||||
this.hasName(["operator+", "operator-"]) and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `operator+=` or `operator-=` member function of an iterator class.
|
||||
*/
|
||||
class IteratorAssignArithmeticMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction {
|
||||
IteratorAssignArithmeticMemberOperator() {
|
||||
this.hasName(["operator+=", "operator-="]) and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierAddress() and
|
||||
output.isReturnValue()
|
||||
or
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `operator[]` member function of an iterator class.
|
||||
*/
|
||||
class IteratorArrayMemberOperator extends MemberFunction, TaintFunction {
|
||||
IteratorArrayMemberOperator() {
|
||||
this.hasName("operator[]") and
|
||||
this.getDeclaringType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.implementations.Iterator
|
||||
|
||||
/**
|
||||
* Additional model for standard container constructors that reference the
|
||||
@@ -14,10 +15,7 @@ import semmle.code.cpp.models.interfaces.Taint
|
||||
*/
|
||||
class StdSequenceContainerConstructor extends Constructor, TaintFunction {
|
||||
StdSequenceContainerConstructor() {
|
||||
this.getDeclaringType().hasQualifiedName("std", "vector") or
|
||||
this.getDeclaringType().hasQualifiedName("std", "deque") or
|
||||
this.getDeclaringType().hasQualifiedName("std", "list") or
|
||||
this.getDeclaringType().hasQualifiedName("std", "forward_list")
|
||||
this.getDeclaringType().hasQualifiedName("std", ["vector", "deque", "list", "forward_list"])
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,26 +24,50 @@ class StdSequenceContainerConstructor extends Constructor, TaintFunction {
|
||||
*/
|
||||
int getAValueTypeParameterIndex() {
|
||||
getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||
getDeclaringType().getTemplateArgument(0) // i.e. the `T` of this `std::vector<T>`
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// taint flow from any parameter of the value type to the returned object
|
||||
input.isParameterDeref(getAValueTypeParameterIndex()) and
|
||||
(
|
||||
input.isParameterDeref(getAValueTypeParameterIndex()) or
|
||||
input.isParameter(getAnIteratorParameterIndex())
|
||||
) and
|
||||
output.isReturnValue() // TODO: this should be `isQualifierObject` by our current definitions, but that flow is not yet supported.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container function `data`.
|
||||
*/
|
||||
class StdSequenceContainerData extends TaintFunction {
|
||||
StdSequenceContainerData() { this.hasQualifiedName("std", ["array", "vector"], "data") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from container itself (qualifier) to return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier (for writes to
|
||||
// `data`)
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `push_back` and `push_front`.
|
||||
*/
|
||||
class StdSequenceContainerPush extends TaintFunction {
|
||||
StdSequenceContainerPush() {
|
||||
this.hasQualifiedName("std", "vector", "push_back") or
|
||||
this.hasQualifiedName("std", "deque", "push_back") or
|
||||
this.hasQualifiedName("std", "deque", "push_front") or
|
||||
this.hasQualifiedName("std", "list", "push_back") or
|
||||
this.hasQualifiedName("std", "list", "push_front") or
|
||||
this.hasQualifiedName("std", "deque", ["push_back", "push_front"]) or
|
||||
this.hasQualifiedName("std", "list", ["push_back", "push_front"]) or
|
||||
this.hasQualifiedName("std", "forward_list", "push_front")
|
||||
}
|
||||
|
||||
@@ -61,14 +83,10 @@ class StdSequenceContainerPush extends TaintFunction {
|
||||
*/
|
||||
class StdSequenceContainerFrontBack extends TaintFunction {
|
||||
StdSequenceContainerFrontBack() {
|
||||
this.hasQualifiedName("std", "array", "front") or
|
||||
this.hasQualifiedName("std", "array", "back") or
|
||||
this.hasQualifiedName("std", "vector", "front") or
|
||||
this.hasQualifiedName("std", "vector", "back") or
|
||||
this.hasQualifiedName("std", "deque", "front") or
|
||||
this.hasQualifiedName("std", "deque", "back") or
|
||||
this.hasQualifiedName("std", "list", "front") or
|
||||
this.hasQualifiedName("std", "list", "back") or
|
||||
this.hasQualifiedName("std", "array", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "vector", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "deque", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "list", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "forward_list", "front")
|
||||
}
|
||||
|
||||
@@ -79,16 +97,101 @@ class StdSequenceContainerFrontBack extends TaintFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `insert` and `insert_after`.
|
||||
*/
|
||||
class StdSequenceContainerInsert extends TaintFunction {
|
||||
StdSequenceContainerInsert() {
|
||||
this.hasQualifiedName("std", ["vector", "deque", "list"], "insert") or
|
||||
this.hasQualifiedName("std", ["forward_list"], "insert_after")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a reference to the
|
||||
* value type of the container.
|
||||
*/
|
||||
int getAValueTypeParameterIndex() {
|
||||
getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameter to container itself (qualifier) and return value
|
||||
(
|
||||
input.isQualifierObject() or
|
||||
input.isParameterDeref(getAValueTypeParameterIndex()) or
|
||||
input.isParameter(getAnIteratorParameterIndex())
|
||||
) and
|
||||
(
|
||||
output.isQualifierObject() or
|
||||
output.isReturnValueDeref()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container function `assign`.
|
||||
*/
|
||||
class StdSequenceContainerAssign extends TaintFunction {
|
||||
StdSequenceContainerAssign() {
|
||||
this.hasQualifiedName("std", ["vector", "deque", "list", "forward_list"], "assign")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a reference to the
|
||||
* value type of the container.
|
||||
*/
|
||||
int getAValueTypeParameterIndex() {
|
||||
getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameter to container itself (qualifier)
|
||||
(
|
||||
input.isParameterDeref(getAValueTypeParameterIndex()) or
|
||||
input.isParameter(getAnIteratorParameterIndex())
|
||||
) and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container `begin` and `end` functions and their
|
||||
* variants.
|
||||
*/
|
||||
class StdSequenceContainerBeginEnd extends TaintFunction {
|
||||
StdSequenceContainerBeginEnd() {
|
||||
this
|
||||
.hasQualifiedName("std", ["array", "vector", "deque", "list"],
|
||||
["begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend"]) or
|
||||
this
|
||||
.hasQualifiedName("std", "forward_list",
|
||||
["before_begin", "begin", "end", "cbefore_begin", "cbegin", "cend"])
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container `swap` functions.
|
||||
*/
|
||||
class StdSequenceContainerSwap extends TaintFunction {
|
||||
StdSequenceContainerSwap() {
|
||||
this.hasQualifiedName("std", "array", "swap") or
|
||||
this.hasQualifiedName("std", "vector", "swap") or
|
||||
this.hasQualifiedName("std", "deque", "swap") or
|
||||
this.hasQualifiedName("std", "list", "swap") or
|
||||
this.hasQualifiedName("std", "forward_list", "swap")
|
||||
this.hasQualifiedName("std", ["array", "vector", "deque", "list", "forward_list"], "swap")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -100,3 +203,22 @@ class StdSequenceContainerSwap extends TaintFunction {
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `at` and `operator[]`.
|
||||
*/
|
||||
class StdSequenceContainerAt extends TaintFunction {
|
||||
StdSequenceContainerAt() {
|
||||
this.hasQualifiedName("std", ["vector", "array", "deque"], ["at", "operator[]"])
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from qualifier to referenced return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
/**
|
||||
* Provides implementation classes modeling `std::string` and other
|
||||
* instantiations of `std::basic_string`. See `semmle.code.cpp.models.Models`
|
||||
* for usage information.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.implementations.Iterator
|
||||
|
||||
/**
|
||||
* The `std::basic_string` template class.
|
||||
@@ -8,18 +15,96 @@ class StdBasicString extends TemplateClass {
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` functions `c_str` and `data`.
|
||||
* Additional model for `std::string` constructors that reference the character
|
||||
* type of the container, or an iterator. For example construction from
|
||||
* iterators:
|
||||
* ```
|
||||
* std::string b(a.begin(), a.end());
|
||||
* ```
|
||||
*/
|
||||
class StdStringConstructor extends Constructor, TaintFunction {
|
||||
StdStringConstructor() { this.getDeclaringType().hasQualifiedName("std", "basic_string") }
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameterIndex() {
|
||||
getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *`
|
||||
getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &`
|
||||
getParameter(result).getUnspecifiedType() =
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// taint flow from any parameter of the value type to the returned object
|
||||
(
|
||||
input.isParameterDeref(getAStringParameterIndex()) or
|
||||
input.isParameter(getAnIteratorParameterIndex())
|
||||
) and
|
||||
output.isReturnValue() // TODO: this should be `isQualifierObject` by our current definitions, but that flow is not yet supported.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` function `c_str`.
|
||||
*/
|
||||
class StdStringCStr extends TaintFunction {
|
||||
StdStringCStr() {
|
||||
this.hasQualifiedName("std", "basic_string", "c_str") or
|
||||
this.hasQualifiedName("std", "basic_string", "data")
|
||||
}
|
||||
StdStringCStr() { this.hasQualifiedName("std", "basic_string", "c_str") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string itself (qualifier) to return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` function `data`.
|
||||
*/
|
||||
class StdStringData extends TaintFunction {
|
||||
StdStringData() { this.hasQualifiedName("std", "basic_string", "data") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string itself (qualifier) to return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier (for writes to
|
||||
// `data`)
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` function `push_back`.
|
||||
*/
|
||||
class StdStringPush extends TaintFunction {
|
||||
StdStringPush() { this.hasQualifiedName("std", "basic_string", "push_back") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameter to qualifier
|
||||
input.isParameterDeref(0) and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` functions `front` and `back`.
|
||||
*/
|
||||
class StdStringFrontBack extends TaintFunction {
|
||||
StdStringFrontBack() { this.hasQualifiedName("std", "basic_string", ["front", "back"]) }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from object to returned reference
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,32 +134,41 @@ class StdStringPlus extends TaintFunction {
|
||||
*/
|
||||
class StdStringAppend extends TaintFunction {
|
||||
StdStringAppend() {
|
||||
this.hasQualifiedName("std", "basic_string", "operator+=") or
|
||||
this.hasQualifiedName("std", "basic_string", "append") or
|
||||
this.hasQualifiedName("std", "basic_string", "insert") or
|
||||
this.hasQualifiedName("std", "basic_string", "replace")
|
||||
this.hasQualifiedName("std", "basic_string", ["operator+=", "append", "insert", "replace"])
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameter() {
|
||||
getParameter(result).getType() instanceof PointerType or
|
||||
getParameter(result).getType() instanceof ReferenceType or
|
||||
getParameter(result).getType() = getDeclaringType().getTemplateArgument(0) // i.e. `std::basic_string::CharT`
|
||||
int getAStringParameterIndex() {
|
||||
getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *`
|
||||
getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &`
|
||||
getParameter(result).getUnspecifiedType() =
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string and parameter to string (qualifier) and return value
|
||||
(
|
||||
input.isQualifierObject() or
|
||||
input.isParameterDeref(getAStringParameter())
|
||||
input.isParameterDeref(getAStringParameterIndex()) or
|
||||
input.isParameter(getAnIteratorParameterIndex())
|
||||
) and
|
||||
(
|
||||
output.isQualifierObject() or
|
||||
output.isReturnValueDeref()
|
||||
)
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier (for writes to
|
||||
// the result)
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,19 +182,50 @@ class StdStringAssign extends TaintFunction {
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameter() {
|
||||
getParameter(result).getType() instanceof PointerType or
|
||||
getParameter(result).getType() instanceof ReferenceType or
|
||||
getParameter(result).getType() = getDeclaringType().getTemplateArgument(0) // i.e. `std::basic_string::CharT`
|
||||
int getAStringParameterIndex() {
|
||||
getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *`
|
||||
getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &`
|
||||
getParameter(result).getUnspecifiedType() =
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameter to string itself (qualifier) and return value
|
||||
input.isParameterDeref(getAStringParameter()) and
|
||||
(
|
||||
input.isParameterDeref(getAStringParameterIndex()) or
|
||||
input.isParameter(getAnIteratorParameterIndex())
|
||||
) and
|
||||
(
|
||||
output.isQualifierObject() or
|
||||
output.isReturnValueDeref()
|
||||
)
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier (for writes to
|
||||
// the result)
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard functions `std::string.begin` and `std::string.end` and their
|
||||
* variants.
|
||||
*/
|
||||
class StdStringBeginEnd extends TaintFunction {
|
||||
StdStringBeginEnd() {
|
||||
this
|
||||
.hasQualifiedName("std", "basic_string",
|
||||
["begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend"])
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,3 +270,20 @@ class StdStringSwap extends TaintFunction {
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` functions `at` and `operator[]`.
|
||||
*/
|
||||
class StdStringAt extends TaintFunction {
|
||||
StdStringAt() { this.hasQualifiedName("std", "basic_string", ["at", "operator[]"]) }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from qualifier to referenced return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ private newtype TFunctionInput =
|
||||
TInParameter(ParameterIndex i) or
|
||||
TInParameterDeref(ParameterIndex i) or
|
||||
TInQualifierObject() or
|
||||
TInQualifierAddress()
|
||||
TInQualifierAddress() or
|
||||
TInReturnValueDeref()
|
||||
|
||||
/**
|
||||
* An input to a function. This can be:
|
||||
@@ -106,6 +107,31 @@ class FunctionInput extends TFunctionInput {
|
||||
* (with type `C const *`) on entry to the function.
|
||||
*/
|
||||
predicate isQualifierAddress() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this is the input value pointed to by the return value of a
|
||||
* function, if the function returns a pointer, or the input value referred
|
||||
* to by the return value of a function, if the function returns a reference.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* char* getPointer();
|
||||
* float& getReference();
|
||||
* int getInt();
|
||||
* ```
|
||||
* - `isReturnValueDeref()` holds for the `FunctionInput` that represents the
|
||||
* value of `*getPointer()` (with type `char`).
|
||||
* - `isReturnValueDeref()` holds for the `FunctionInput` that represents the
|
||||
* value of `getReference()` (with type `float`).
|
||||
* - There is no `FunctionInput` of `getInt()` for which
|
||||
* `isReturnValueDeref()` holds because the return type of `getInt()` is
|
||||
* neither a pointer nor a reference.
|
||||
*
|
||||
* Note that data flows in through function return values are relatively
|
||||
* rare, but they do occur when a function returns a reference to itself,
|
||||
* part of itself, or one of its other inputs.
|
||||
*/
|
||||
predicate isReturnValueDeref() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,6 +225,34 @@ class InQualifierAddress extends FunctionInput, TInQualifierAddress {
|
||||
override predicate isQualifierAddress() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The input value pointed to by the return value of a function, if the
|
||||
* function returns a pointer, or the input value referred to by the return
|
||||
* value of a function, if the function returns a reference.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* char* getPointer();
|
||||
* float& getReference();
|
||||
* int getInt();
|
||||
* ```
|
||||
* - `InReturnValueDeref` represents the value of `*getPointer()` (with type
|
||||
* `char`).
|
||||
* - `InReturnValueDeref` represents the value of `getReference()` (with type
|
||||
* `float`).
|
||||
* - `InReturnValueDeref` does not represent the return value of `getInt()`
|
||||
* because the return type of `getInt()` is neither a pointer nor a reference.
|
||||
*
|
||||
* Note that data flows in through function return values are relatively
|
||||
* rare, but they do occur when a function returns a reference to itself,
|
||||
* part of itself, or one of its other inputs.
|
||||
*/
|
||||
class InReturnValueDeref extends FunctionInput, TInReturnValueDeref {
|
||||
override string toString() { result = "InReturnValueDeref" }
|
||||
|
||||
override predicate isReturnValueDeref() { any() }
|
||||
}
|
||||
|
||||
private newtype TFunctionOutput =
|
||||
TOutParameterDeref(ParameterIndex i) or
|
||||
TOutQualifierObject() or
|
||||
|
||||
@@ -191,6 +191,8 @@ private predicate linearAccessImpl(Expr expr, VariableAccess v, float p, float q
|
||||
// Base case
|
||||
expr = v and p = 1.0 and q = 0.0
|
||||
or
|
||||
expr.(ReferenceDereferenceExpr).getExpr() = v and p = 1.0 and q = 0.0
|
||||
or
|
||||
// a+(p*v+b) == p*v + (a+b)
|
||||
exists(AddExpr addExpr, float a, float b |
|
||||
addExpr.getLeftOperand().isConstant() and
|
||||
@@ -349,13 +351,20 @@ private predicate typeBounds(ArithmeticType t, float lb, float ub) {
|
||||
t instanceof FloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
||||
}
|
||||
|
||||
private Type stripReference(Type t) {
|
||||
if t instanceof ReferenceType then result = t.(ReferenceType).getBaseType() else result = t
|
||||
}
|
||||
|
||||
/** Gets the type used by range analysis for the given `StackVariable`. */
|
||||
Type getVariableRangeType(StackVariable v) { result = stripReference(v.getUnspecifiedType()) }
|
||||
|
||||
/**
|
||||
* Gets the lower bound for the unspecified type `t`.
|
||||
*
|
||||
* For example, if `t` is a signed 32-bit type then the result is
|
||||
* `-2^31`.
|
||||
*/
|
||||
float typeLowerBound(ArithmeticType t) { typeBounds(t, result, _) }
|
||||
float typeLowerBound(Type t) { typeBounds(stripReference(t), result, _) }
|
||||
|
||||
/**
|
||||
* Gets the upper bound for the unspecified type `t`.
|
||||
@@ -363,7 +372,7 @@ float typeLowerBound(ArithmeticType t) { typeBounds(t, result, _) }
|
||||
* For example, if `t` is a signed 32-bit type then the result is
|
||||
* `2^31 - 1`.
|
||||
*/
|
||||
float typeUpperBound(ArithmeticType t) { typeBounds(t, _, result) }
|
||||
float typeUpperBound(Type t) { typeBounds(stripReference(t), _, result) }
|
||||
|
||||
/**
|
||||
* Gets the minimum value that this expression could represent, based on
|
||||
|
||||
@@ -319,28 +319,12 @@ private predicate defDependsOnDef(
|
||||
// Definitions with a defining value.
|
||||
exists(Expr expr | assignmentDef(def, v, expr) | exprDependsOnDef(expr, srcDef, srcVar))
|
||||
or
|
||||
exists(AssignAddExpr assignAdd |
|
||||
def = assignAdd and
|
||||
// Assignment operations with a defining value
|
||||
exists(AssignOperation assignOp |
|
||||
analyzableExpr(assignOp) and
|
||||
def = assignOp and
|
||||
def.getAVariable() = v and
|
||||
exprDependsOnDef(assignAdd.getAnOperand(), srcDef, srcVar)
|
||||
)
|
||||
or
|
||||
exists(AssignSubExpr assignSub |
|
||||
def = assignSub and
|
||||
def.getAVariable() = v and
|
||||
exprDependsOnDef(assignSub.getAnOperand(), srcDef, srcVar)
|
||||
)
|
||||
or
|
||||
exists(UnsignedAssignMulExpr assignMul |
|
||||
def = assignMul and
|
||||
def.getAVariable() = v and
|
||||
exprDependsOnDef(assignMul.getAnOperand(), srcDef, srcVar)
|
||||
)
|
||||
or
|
||||
exists(AssignMulByConstantExpr assignMul |
|
||||
def = assignMul and
|
||||
def.getAVariable() = v and
|
||||
exprDependsOnDef(assignMul.getLValue(), srcDef, srcVar)
|
||||
exprDependsOnDef(assignOp, srcDef, srcVar)
|
||||
)
|
||||
or
|
||||
exists(CrementOperation crem |
|
||||
@@ -485,7 +469,7 @@ private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) {
|
||||
* This predicate finds all the definitions in the first set.
|
||||
*/
|
||||
private predicate assignmentDef(RangeSsaDefinition def, StackVariable v, Expr expr) {
|
||||
v.getUnspecifiedType() instanceof ArithmeticType and
|
||||
getVariableRangeType(v) instanceof ArithmeticType and
|
||||
(
|
||||
def = v.getInitializer().getExpr() and def = expr
|
||||
or
|
||||
@@ -1160,6 +1144,17 @@ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
if guardLB > defLB then result = guardLB else result = defLB
|
||||
)
|
||||
or
|
||||
exists(VariableAccess access, float neConstant, float lower |
|
||||
isNEPhi(v, phi, access, neConstant) and
|
||||
lower = getFullyConvertedLowerBounds(access) and
|
||||
if lower = neConstant then result = lower + 1 else result = lower
|
||||
)
|
||||
or
|
||||
exists(VariableAccess access |
|
||||
isUnsupportedGuardPhi(v, phi, access) and
|
||||
result = getFullyConvertedLowerBounds(access)
|
||||
)
|
||||
or
|
||||
result = getDefLowerBounds(phi.getAPhiInput(v), v)
|
||||
}
|
||||
|
||||
@@ -1177,6 +1172,17 @@ private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
if guardUB < defUB then result = guardUB else result = defUB
|
||||
)
|
||||
or
|
||||
exists(VariableAccess access, float neConstant, float upper |
|
||||
isNEPhi(v, phi, access, neConstant) and
|
||||
upper = getFullyConvertedUpperBounds(access) and
|
||||
if upper = neConstant then result = upper - 1 else result = upper
|
||||
)
|
||||
or
|
||||
exists(VariableAccess access |
|
||||
isUnsupportedGuardPhi(v, phi, access) and
|
||||
result = getFullyConvertedUpperBounds(access)
|
||||
)
|
||||
or
|
||||
result = getDefUpperBounds(phi.getAPhiInput(v), v)
|
||||
}
|
||||
|
||||
@@ -1185,42 +1191,11 @@ private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) {
|
||||
// Definitions with a defining value.
|
||||
exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedLowerBounds(expr))
|
||||
or
|
||||
exists(AssignAddExpr assignAdd, RangeSsaDefinition nextDef, float lhsLB, float rhsLB |
|
||||
def = assignAdd and
|
||||
assignAdd.getLValue() = nextDef.getAUse(v) and
|
||||
lhsLB = getDefLowerBounds(nextDef, v) and
|
||||
rhsLB = getFullyConvertedLowerBounds(assignAdd.getRValue()) and
|
||||
result = addRoundingDown(lhsLB, rhsLB)
|
||||
)
|
||||
or
|
||||
exists(AssignSubExpr assignSub, RangeSsaDefinition nextDef, float lhsLB, float rhsUB |
|
||||
def = assignSub and
|
||||
assignSub.getLValue() = nextDef.getAUse(v) and
|
||||
lhsLB = getDefLowerBounds(nextDef, v) and
|
||||
rhsUB = getFullyConvertedUpperBounds(assignSub.getRValue()) and
|
||||
result = addRoundingDown(lhsLB, -rhsUB)
|
||||
)
|
||||
or
|
||||
exists(UnsignedAssignMulExpr assignMul, RangeSsaDefinition nextDef, float lhsLB, float rhsLB |
|
||||
def = assignMul and
|
||||
assignMul.getLValue() = nextDef.getAUse(v) and
|
||||
lhsLB = getDefLowerBounds(nextDef, v) and
|
||||
rhsLB = getFullyConvertedLowerBounds(assignMul.getRValue()) and
|
||||
result = lhsLB * rhsLB
|
||||
)
|
||||
or
|
||||
exists(AssignMulByPositiveConstantExpr assignMul, RangeSsaDefinition nextDef, float lhsLB |
|
||||
def = assignMul and
|
||||
assignMul.getLValue() = nextDef.getAUse(v) and
|
||||
lhsLB = getDefLowerBounds(nextDef, v) and
|
||||
result = lhsLB * assignMul.getConstant()
|
||||
)
|
||||
or
|
||||
exists(AssignMulByNegativeConstantExpr assignMul, RangeSsaDefinition nextDef, float lhsUB |
|
||||
def = assignMul and
|
||||
assignMul.getLValue() = nextDef.getAUse(v) and
|
||||
lhsUB = getDefUpperBounds(nextDef, v) and
|
||||
result = lhsUB * assignMul.getConstant()
|
||||
// Assignment operations with a defining value
|
||||
exists(AssignOperation assignOp |
|
||||
def = assignOp and
|
||||
assignOp.getLValue() = v.getAnAccess() and
|
||||
result = getTruncatedLowerBounds(assignOp)
|
||||
)
|
||||
or
|
||||
exists(IncrementOperation incr, float newLB |
|
||||
@@ -1249,42 +1224,11 @@ private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) {
|
||||
// Definitions with a defining value.
|
||||
exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedUpperBounds(expr))
|
||||
or
|
||||
exists(AssignAddExpr assignAdd, RangeSsaDefinition nextDef, float lhsUB, float rhsUB |
|
||||
def = assignAdd and
|
||||
assignAdd.getLValue() = nextDef.getAUse(v) and
|
||||
lhsUB = getDefUpperBounds(nextDef, v) and
|
||||
rhsUB = getFullyConvertedUpperBounds(assignAdd.getRValue()) and
|
||||
result = addRoundingUp(lhsUB, rhsUB)
|
||||
)
|
||||
or
|
||||
exists(AssignSubExpr assignSub, RangeSsaDefinition nextDef, float lhsUB, float rhsLB |
|
||||
def = assignSub and
|
||||
assignSub.getLValue() = nextDef.getAUse(v) and
|
||||
lhsUB = getDefUpperBounds(nextDef, v) and
|
||||
rhsLB = getFullyConvertedLowerBounds(assignSub.getRValue()) and
|
||||
result = addRoundingUp(lhsUB, -rhsLB)
|
||||
)
|
||||
or
|
||||
exists(UnsignedAssignMulExpr assignMul, RangeSsaDefinition nextDef, float lhsUB, float rhsUB |
|
||||
def = assignMul and
|
||||
assignMul.getLValue() = nextDef.getAUse(v) and
|
||||
lhsUB = getDefUpperBounds(nextDef, v) and
|
||||
rhsUB = getFullyConvertedUpperBounds(assignMul.getRValue()) and
|
||||
result = lhsUB * rhsUB
|
||||
)
|
||||
or
|
||||
exists(AssignMulByPositiveConstantExpr assignMul, RangeSsaDefinition nextDef, float lhsUB |
|
||||
def = assignMul and
|
||||
assignMul.getLValue() = nextDef.getAUse(v) and
|
||||
lhsUB = getDefUpperBounds(nextDef, v) and
|
||||
result = lhsUB * assignMul.getConstant()
|
||||
)
|
||||
or
|
||||
exists(AssignMulByNegativeConstantExpr assignMul, RangeSsaDefinition nextDef, float lhsLB |
|
||||
def = assignMul and
|
||||
assignMul.getLValue() = nextDef.getAUse(v) and
|
||||
lhsLB = getDefLowerBounds(nextDef, v) and
|
||||
result = lhsLB * assignMul.getConstant()
|
||||
// Assignment operations with a defining value
|
||||
exists(AssignOperation assignOp |
|
||||
def = assignOp and
|
||||
assignOp.getLValue() = v.getAnAccess() and
|
||||
result = getTruncatedUpperBounds(assignOp)
|
||||
)
|
||||
or
|
||||
exists(IncrementOperation incr, float newUB |
|
||||
@@ -1329,7 +1273,7 @@ private float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) {
|
||||
// recursion from exploding.
|
||||
result =
|
||||
max(float widenLB |
|
||||
widenLB = wideningLowerBounds(v.getUnspecifiedType()) and
|
||||
widenLB = wideningLowerBounds(getVariableRangeType(v)) and
|
||||
not widenLB > truncatedLB
|
||||
|
|
||||
widenLB
|
||||
@@ -1359,7 +1303,7 @@ private float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) {
|
||||
// from exploding.
|
||||
result =
|
||||
min(float widenUB |
|
||||
widenUB = wideningUpperBounds(v.getUnspecifiedType()) and
|
||||
widenUB = wideningUpperBounds(getVariableRangeType(v)) and
|
||||
not widenUB < truncatedUB
|
||||
|
|
||||
widenUB
|
||||
@@ -1391,9 +1335,10 @@ private predicate unanalyzableDefBounds(RangeSsaDefinition def, StackVariable v,
|
||||
*/
|
||||
bindingset[guard, v, branch]
|
||||
predicate nonNanGuardedVariable(ComparisonOperation guard, VariableAccess v, boolean branch) {
|
||||
v.getUnspecifiedType() instanceof IntegralType
|
||||
getVariableRangeType(v.getTarget()) instanceof IntegralType
|
||||
or
|
||||
v.getUnspecifiedType() instanceof FloatingPointType and v instanceof NonNanVariableAccess
|
||||
getVariableRangeType(v.getTarget()) instanceof FloatingPointType and
|
||||
v instanceof NonNanVariableAccess
|
||||
or
|
||||
// The reason the following case is here is to ensure that when we say
|
||||
// `if (x > 5) { ...then... } else { ...else... }`
|
||||
@@ -1418,7 +1363,7 @@ private predicate lowerBoundFromGuard(
|
||||
then
|
||||
if
|
||||
strictness = Nonstrict() or
|
||||
not v.getUnspecifiedType() instanceof IntegralType
|
||||
not getVariableRangeType(v.getTarget()) instanceof IntegralType
|
||||
then lb = childLB
|
||||
else lb = childLB + 1
|
||||
else lb = varMinVal(v.getTarget())
|
||||
@@ -1440,7 +1385,7 @@ private predicate upperBoundFromGuard(
|
||||
then
|
||||
if
|
||||
strictness = Nonstrict() or
|
||||
not v.getUnspecifiedType() instanceof IntegralType
|
||||
not getVariableRangeType(v.getTarget()) instanceof IntegralType
|
||||
then ub = childUB
|
||||
else ub = childUB - 1
|
||||
else ub = varMaxVal(v.getTarget())
|
||||
@@ -1500,22 +1445,13 @@ private predicate linearBoundFromGuard(
|
||||
// 1. x <= upperbound(RHS)
|
||||
// 2. x >= lowerbound(RHS)
|
||||
//
|
||||
// For x != RHS, we create trivial bounds:
|
||||
//
|
||||
// 1. x <= typeUpperBound(RHS.getUnspecifiedType())
|
||||
// 2. x >= typeLowerBound(RHS.getUnspecifiedType())
|
||||
//
|
||||
exists(Expr lhs, Expr rhs, boolean isEQ |
|
||||
exists(Expr lhs, Expr rhs |
|
||||
linearAccess(lhs, v, p, q) and
|
||||
eqOpWithSwapAndNegate(guard, lhs, rhs, isEQ, branch) and
|
||||
eqOpWithSwapAndNegate(guard, lhs, rhs, true, branch) and
|
||||
getBounds(rhs, boundValue, isLowerBound) and
|
||||
strictness = Nonstrict()
|
||||
|
|
||||
// True branch
|
||||
isEQ = true and getBounds(rhs, boundValue, isLowerBound)
|
||||
or
|
||||
// False branch: set the bounds to the min/max for the type.
|
||||
isEQ = false and exprTypeBounds(rhs, boundValue, isLowerBound)
|
||||
)
|
||||
// x != RHS and !x are handled elsewhere
|
||||
}
|
||||
|
||||
/** Utility for `linearBoundFromGuard`. */
|
||||
@@ -1532,6 +1468,42 @@ private predicate exprTypeBounds(Expr expr, float boundValue, boolean isLowerBou
|
||||
isLowerBound = false and boundValue = exprMaxVal(expr.getFullyConverted())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(v, phi)` ensures that `access` is not equal to `neConstant`. For
|
||||
* example, the condition `if (x + 1 != 3)` ensures that `x` is not equal to 2.
|
||||
* Only integral types are supported.
|
||||
*/
|
||||
private predicate isNEPhi(
|
||||
Variable v, RangeSsaDefinition phi, VariableAccess access, float neConstant
|
||||
) {
|
||||
exists(
|
||||
ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, float p, float q, float r
|
||||
|
|
||||
access.getTarget() = v and
|
||||
phi.isGuardPhi(access, cmp, branch) and
|
||||
eqOpWithSwapAndNegate(cmp, linearExpr, rExpr, false, branch) and
|
||||
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!=` is too imprecise
|
||||
r = getValue(rExpr).toFloat() and
|
||||
linearAccess(linearExpr, access, p, q) and
|
||||
neConstant = (r - q) / p
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(v, phi)` constrains the value of `access` but in a way that
|
||||
* doesn't allow this library to constrain the upper or lower bounds of
|
||||
* `access`. An example is `if (x != y)` if neither `x` nor `y` is a
|
||||
* compile-time constant.
|
||||
*/
|
||||
private predicate isUnsupportedGuardPhi(Variable v, RangeSsaDefinition phi, VariableAccess access) {
|
||||
exists(ComparisonOperation cmp, boolean branch |
|
||||
access.getTarget() = v and
|
||||
phi.isGuardPhi(access, cmp, branch) and
|
||||
eqOpWithSwapAndNegate(cmp, _, _, false, branch) and
|
||||
not isNEPhi(v, phi, access, _)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private module SimpleRangeAnalysisCached {
|
||||
/**
|
||||
|
||||
@@ -1935,20 +1935,6 @@ stmtparents(
|
||||
ishandler(unique int block: @stmt_block ref);
|
||||
|
||||
@cfgnode = @stmt | @expr | @function | @initialiser ;
|
||||
successors(
|
||||
int from: @cfgnode ref,
|
||||
int to: @cfgnode ref
|
||||
);
|
||||
|
||||
truecond(
|
||||
unique int from: @cfgnode ref,
|
||||
int to: @cfgnode ref
|
||||
);
|
||||
|
||||
falsecond(
|
||||
unique int from: @cfgnode ref,
|
||||
int to: @cfgnode ref
|
||||
);
|
||||
|
||||
stmt_decl_bind(
|
||||
int stmt: @stmt_decl ref,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,11 @@
|
||||
* Provides a library for writing QL tests whose success or failure is based on expected results
|
||||
* embedded in the test source code as comments, rather than a `.expected` file.
|
||||
*
|
||||
* To add this framework to a new language:
|
||||
* - Add a file `InlineExpectationsTestPrivate.qll` that defines a `LineComment` class. This class
|
||||
* must support a `getContents` method that returns the contents of the given comment, _excluding_
|
||||
* the comment indicator itself. It should also define `toString` and `getLocation` as usual.
|
||||
*
|
||||
* To create a new inline expectations test:
|
||||
* - Declare a class that extends `InlineExpectationsTest`. In the characteristic predicate of the
|
||||
* new class, bind `this` to a unique string (usually the name of the test).
|
||||
@@ -13,7 +18,7 @@
|
||||
* `hasActualResult()`. Often this is just a single tag.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* ```ql
|
||||
* class ConstantValueTest extends InlineExpectationsTest {
|
||||
* ConstantValueTest() { this = "ConstantValueTest" }
|
||||
*
|
||||
@@ -23,11 +28,11 @@
|
||||
* }
|
||||
*
|
||||
* override predicate hasActualResult(
|
||||
* Location location, string element, string tag, string valuesasas
|
||||
* Location location, string element, string tag, string value
|
||||
* ) {
|
||||
* exists(Expr e |
|
||||
* tag = "const" and // The tag for this test.
|
||||
* valuesasas = e.getValue() and // The expected value. Will only hold for constant expressions.
|
||||
* value = e.getValue() and // The expected value. Will only hold for constant expressions.
|
||||
* location = e.getLocation() and // The location of the result to be reported.
|
||||
* element = e.toString() // The display text for the result.
|
||||
* )
|
||||
@@ -38,10 +43,10 @@
|
||||
* There is no need to write a `select` clause or query predicate. All of the differences between
|
||||
* expected results and actual results will be reported in the `failures()` query predicate.
|
||||
*
|
||||
* To annotate the test source code with an expected result, place a C++-style (`//`) comment on the
|
||||
* To annotate the test source code with an expected result, place a comment on the
|
||||
* same line as the expected result, with text of the following format as the body of the comment:
|
||||
*
|
||||
* `// $tag=expected-value`
|
||||
* `$tag=expected-value`
|
||||
*
|
||||
* Where `tag` is the value of the `tag` parameter from `hasActualResult()`, and `expected-value` is
|
||||
* the value of the `value` parameter from `hasActualResult()`. The `=expected-value` portion may be
|
||||
@@ -53,7 +58,7 @@
|
||||
* "Missing result: tag=expected-value".
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* ```cpp
|
||||
* int i = x + 5; // $const=5
|
||||
* int j = y + (7 - 3) // $const=7 $const=3 $const=4 // The result of the subtraction is a constant.
|
||||
* ```
|
||||
@@ -62,8 +67,8 @@
|
||||
* annotate that a particular expected result is known to be a false positive, or that a particular
|
||||
* missing result is known to be a false negative:
|
||||
*
|
||||
* `// $f+:tag=expected-value` // False positive
|
||||
* `// $f-:tag=expected-value` // False negative
|
||||
* `$f+:tag=expected-value` // False positive
|
||||
* `$f-:tag=expected-value` // False negative
|
||||
*
|
||||
* A false positive expectation is treated as any other expected result, except that if there is no
|
||||
* matching actual result, the message will be of the form "Fixed false positive: tag=value". A
|
||||
@@ -74,14 +79,14 @@
|
||||
* If the same result value is expected for two or more tags on the same line, there is a shorthand
|
||||
* notation available:
|
||||
*
|
||||
* `// $tag1,tag2=expected-value`
|
||||
* `$tag1,tag2=expected-value`
|
||||
*
|
||||
* is equivalent to:
|
||||
*
|
||||
* `// $tag1=expected-value $tag2=expected-value`
|
||||
* `$tag1=expected-value $tag2=expected-value`
|
||||
*/
|
||||
|
||||
import cpp
|
||||
private import InlineExpectationsTestPrivate
|
||||
|
||||
/**
|
||||
* Base class for tests with inline expectations. The test extends this class to provide the actual
|
||||
@@ -150,12 +155,12 @@ abstract class InlineExpectationsTest extends string {
|
||||
}
|
||||
|
||||
/**
|
||||
* RegEx pattern to match a comment containing one or more expected results. The comment must be a
|
||||
* C++-style (`//`) comment with `$` as its first non-whitespace character. Any subsequent character
|
||||
* RegEx pattern to match a comment containing one or more expected results. The comment must have
|
||||
* `$` as its first non-whitespace character. Any subsequent character
|
||||
* is treated as part of the expected results, except that the comment may contain a `//` sequence
|
||||
* to treat the remainder of the line as a regular (non-interpreted) comment.
|
||||
*/
|
||||
private string expectationCommentPattern() { result = "//\\s*(\\$(?:[^/]|/[^/])*)(?://.*)?" }
|
||||
private string expectationCommentPattern() { result = "\\s*(\\$(?:[^/]|/[^/])*)(?://.*)?" }
|
||||
|
||||
/**
|
||||
* RegEx pattern to match a single expected result, not including the leading `$`. It starts with an
|
||||
@@ -166,7 +171,7 @@ private string expectationPattern() {
|
||||
result = "(?:(f(?:\\+|-)):)?((?:[A-Za-z-_]+)(?:\\s*,\\s*[A-Za-z-_]+)*)(?:=(.*))?"
|
||||
}
|
||||
|
||||
private string getAnExpectation(CppStyleComment comment) {
|
||||
private string getAnExpectation(LineComment comment) {
|
||||
result = comment.getContents().regexpCapture(expectationCommentPattern(), 1).splitAt("$").trim() and
|
||||
result != ""
|
||||
}
|
||||
@@ -177,7 +182,7 @@ private newtype TFailureLocatable =
|
||||
) {
|
||||
test.hasActualResult(location, element, tag, value)
|
||||
} or
|
||||
TValidExpectation(CppStyleComment comment, string tag, string value, string knownFailure) {
|
||||
TValidExpectation(LineComment comment, string tag, string value, string knownFailure) {
|
||||
exists(string expectation |
|
||||
expectation = getAnExpectation(comment) and
|
||||
expectation.regexpMatch(expectationPattern()) and
|
||||
@@ -194,7 +199,7 @@ private newtype TFailureLocatable =
|
||||
)
|
||||
)
|
||||
} or
|
||||
TInvalidExpectation(CppStyleComment comment, string expectation) {
|
||||
TInvalidExpectation(LineComment comment, string expectation) {
|
||||
expectation = getAnExpectation(comment) and
|
||||
not expectation.regexpMatch(expectationPattern())
|
||||
}
|
||||
@@ -232,7 +237,7 @@ class ActualResult extends FailureLocatable, TActualResult {
|
||||
}
|
||||
|
||||
abstract private class Expectation extends FailureLocatable {
|
||||
CppStyleComment comment;
|
||||
LineComment comment;
|
||||
|
||||
override string toString() { result = comment.toString() }
|
||||
|
||||
|
||||
23
cpp/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll
Normal file
23
cpp/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll
Normal file
@@ -0,0 +1,23 @@
|
||||
import cpp
|
||||
|
||||
private newtype TLineComment = MkLineComment(CppStyleComment c)
|
||||
|
||||
/**
|
||||
* Represents a line comment in the CPP style.
|
||||
* Unlike the `CppStyleComment` class, however, the string returned by `getContents` does _not_
|
||||
* include the preceding comment marker (`//`).
|
||||
*/
|
||||
class LineComment extends TLineComment {
|
||||
CppStyleComment comment;
|
||||
|
||||
LineComment() { this = MkLineComment(comment) }
|
||||
|
||||
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
string getContents() { result = comment.getContents().suffix(2) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = comment.toString() }
|
||||
|
||||
/** Gets the location of this comment. */
|
||||
Location getLocation() { result = comment.getLocation() }
|
||||
}
|
||||
@@ -14,7 +14,6 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
| lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. |
|
||||
| lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. |
|
||||
|
||||
@@ -29,5 +29,4 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
| example.c:17:19:17:22 | {...} | example.c:26:19:26:24 | coords |
|
||||
| example.c:24:2:24:7 | coords [post update] | example.c:26:2:26:7 | coords |
|
||||
| example.c:24:2:24:7 | coords [post update] | example.c:26:19:26:24 | coords |
|
||||
| example.c:24:2:24:30 | ... = ... | example.c:24:9:24:9 | x [post update] |
|
||||
| example.c:24:13:24:18 | coords [post update] | example.c:24:2:24:7 | coords |
|
||||
| example.c:24:13:24:18 | coords [post update] | example.c:26:2:26:7 | coords |
|
||||
| example.c:24:13:24:18 | coords [post update] | example.c:26:19:26:24 | coords |
|
||||
| example.c:24:13:24:30 | ... = ... | example.c:24:2:24:30 | ... = ... |
|
||||
| example.c:24:13:24:30 | ... = ... | example.c:24:20:24:20 | y [post update] |
|
||||
| example.c:24:24:24:30 | ... + ... | example.c:24:13:24:30 | ... = ... |
|
||||
| example.c:26:2:26:25 | ... = ... | example.c:26:9:26:9 | x [post update] |
|
||||
| example.c:26:13:26:16 | call to getX | example.c:26:2:26:25 | ... = ... |
|
||||
| example.c:26:18:26:24 | ref arg & ... | example.c:26:2:26:7 | coords |
|
||||
| example.c:26:18:26:24 | ref arg & ... | example.c:26:19:26:24 | coords [inner post update] |
|
||||
|
||||
@@ -16,7 +16,6 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
| A.cpp:41:15:41:21 | new | ArgumentNode is missing PostUpdateNode. |
|
||||
| A.cpp:55:12:55:19 | new | ArgumentNode is missing PostUpdateNode. |
|
||||
|
||||
@@ -23,5 +23,4 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
|
||||
int source();
|
||||
void sink(int);
|
||||
void sink(class MyInt);
|
||||
void sink(class MyArray);
|
||||
|
||||
void test_pointer_deref_assignment()
|
||||
{
|
||||
int x = 0;
|
||||
int *p_x = &x;
|
||||
int *p2_x = &x;
|
||||
int &r_x = x;
|
||||
|
||||
*p_x = source();
|
||||
|
||||
sink(x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(*p_x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(*p2_x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(r_x); // tainted [DETECTED BY IR ONLY]
|
||||
}
|
||||
|
||||
void test_reference_deref_assignment()
|
||||
{
|
||||
int x = 0;
|
||||
int *p_x = &x;
|
||||
int &r_x = x;
|
||||
int &r2_x = x;
|
||||
|
||||
r_x = source();
|
||||
|
||||
sink(x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(*p_x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(r_x); // tainted
|
||||
sink(r2_x); // tainted [DETECTED BY IR ONLY]
|
||||
}
|
||||
|
||||
class MyInt
|
||||
{
|
||||
public:
|
||||
MyInt() : i(0) {}
|
||||
|
||||
int &get() { return i; }
|
||||
|
||||
MyInt &operator=(const int &other);
|
||||
MyInt &operator=(const MyInt &other);
|
||||
|
||||
int i;
|
||||
};
|
||||
|
||||
void test_myint_member_assignment()
|
||||
{
|
||||
MyInt mi;
|
||||
|
||||
mi.i = source();
|
||||
|
||||
sink(mi); // tainted [DETECTED BY IR ONLY]
|
||||
sink(mi.get()); // tainted
|
||||
}
|
||||
|
||||
void test_myint_method_assignment()
|
||||
{
|
||||
MyInt mi;
|
||||
|
||||
mi.get() = source();
|
||||
|
||||
sink(mi); // tainted [DETECTED BY IR ONLY]
|
||||
sink(mi.get()); // tainted
|
||||
}
|
||||
|
||||
void test_myint_overloaded_assignment()
|
||||
{
|
||||
MyInt mi, mi2;
|
||||
|
||||
mi = source();
|
||||
mi2 = mi;
|
||||
|
||||
sink(mi); // tainted [NOT DETECTED]
|
||||
sink(mi.get()); // tainted [NOT DETECTED]
|
||||
sink(mi2); // tainted [NOT DETECTED]
|
||||
sink(mi2.get()); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
class MyArray
|
||||
{
|
||||
public:
|
||||
MyArray() : values({0}) {}
|
||||
|
||||
int &get(int i) { return values[i]; }
|
||||
|
||||
int &operator[](int i);
|
||||
|
||||
int values[10];
|
||||
};
|
||||
|
||||
void test_myarray_member_assignment()
|
||||
{
|
||||
MyArray ma;
|
||||
|
||||
ma.values[0] = source();
|
||||
|
||||
sink(ma.values[0]); // tainted
|
||||
}
|
||||
|
||||
void test_myarray_method_assignment()
|
||||
{
|
||||
MyArray ma;
|
||||
|
||||
ma.get(0) = source();
|
||||
|
||||
sink(ma.get(0)); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_myarray_overloaded_assignment()
|
||||
{
|
||||
MyArray ma, ma2;
|
||||
|
||||
ma[0] = source();
|
||||
ma2 = ma;
|
||||
|
||||
sink(ma[0]); // tainted [NOT DETECTED]
|
||||
sink(ma2[0]); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void sink(int *);
|
||||
|
||||
void test_array_reference_assignment()
|
||||
{
|
||||
int arr1[10] = {0};
|
||||
int arr2[10] = {0};
|
||||
int arr3[10] = {0};
|
||||
int &ref1 = arr1[5];
|
||||
int *ptr2, *ptr3;
|
||||
|
||||
ref1 = source();
|
||||
sink(ref1); // tainted
|
||||
sink(arr1[5]); // tainted [DETECTED BY IR ONLY]
|
||||
|
||||
ptr2 = &(arr2[5]);
|
||||
*ptr2 = source();
|
||||
sink(*ptr2); // tainted [DETECTED BY IR ONLY]
|
||||
sink(arr2[5]); // tainted [DETECTED BY IR ONLY]
|
||||
|
||||
ptr3 = arr3;
|
||||
ptr3[5] = source();
|
||||
sink(ptr3[5]); // tainted [DETECTED BY IR ONLY]
|
||||
sink(arr3[5]); // tainted [DETECTED BY IR ONLY]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
||||
#include "stl.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void sink(int);
|
||||
|
||||
class int_iterator_by_typedefs {
|
||||
public:
|
||||
typedef input_iterator_tag iterator_category;
|
||||
typedef int value_type;
|
||||
typedef size_t difference_type;
|
||||
typedef int * pointer;
|
||||
typedef int & reference;
|
||||
|
||||
int_iterator_by_typedefs &operator++();
|
||||
int_iterator_by_typedefs operator++(int);
|
||||
int operator*() const;
|
||||
};
|
||||
|
||||
class int_iterator_by_trait {
|
||||
public:
|
||||
int_iterator_by_trait &operator++();
|
||||
int_iterator_by_trait operator++(int);
|
||||
int operator*() const;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct std::iterator_traits<int_iterator_by_trait> {
|
||||
typedef input_iterator_tag iterator_category;
|
||||
};
|
||||
|
||||
class non_iterator {
|
||||
public:
|
||||
non_iterator &operator++();
|
||||
non_iterator operator++(int);
|
||||
int operator*() const;
|
||||
};
|
||||
|
||||
void test_typedefs(int_iterator_by_typedefs source1) {
|
||||
sink(*source1);
|
||||
sink(*(source1++));
|
||||
sink(*(++source1));
|
||||
}
|
||||
|
||||
void test_trait(int_iterator_by_trait source1) {
|
||||
sink(*source1);
|
||||
sink(*(source1++));
|
||||
sink(*(++source1));
|
||||
}
|
||||
|
||||
void test_non_iterator(non_iterator source1) {
|
||||
sink(*source1);
|
||||
sink(*(source1++));
|
||||
sink(*(++source1));
|
||||
}
|
||||
@@ -1,6 +1,55 @@
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
template<class T>
|
||||
struct remove_const { typedef T type; };
|
||||
|
||||
template<class T>
|
||||
struct remove_const<const T> { typedef T type; };
|
||||
|
||||
// `remove_const_t<T>` removes any `const` specifier from `T`
|
||||
template<class T>
|
||||
using remove_const_t = typename remove_const<T>::type;
|
||||
|
||||
// --- iterator ---
|
||||
|
||||
namespace std {
|
||||
struct ptrdiff_t;
|
||||
|
||||
template<class I> struct iterator_traits;
|
||||
|
||||
template <class Category,
|
||||
class value_type,
|
||||
class difference_type = ptrdiff_t,
|
||||
class pointer_type = value_type*,
|
||||
class reference_type = value_type&>
|
||||
struct iterator {
|
||||
typedef Category iterator_category;
|
||||
|
||||
iterator();
|
||||
iterator(iterator<Category, remove_const_t<value_type> > const &other); // non-const -> const conversion constructor
|
||||
|
||||
iterator &operator++();
|
||||
iterator operator++(int);
|
||||
iterator &operator--();
|
||||
iterator operator--(int);
|
||||
bool operator==(iterator other) const;
|
||||
bool operator!=(iterator other) const;
|
||||
reference_type operator*() const;
|
||||
iterator operator+(int);
|
||||
iterator operator-(int);
|
||||
iterator &operator+=(int);
|
||||
iterator &operator-=(int);
|
||||
int operator-(iterator);
|
||||
reference_type operator[](int);
|
||||
};
|
||||
|
||||
struct input_iterator_tag {};
|
||||
struct forward_iterator_tag : public input_iterator_tag {};
|
||||
struct bidirectional_iterator_tag : public forward_iterator_tag {};
|
||||
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
|
||||
}
|
||||
|
||||
// --- string ---
|
||||
|
||||
namespace std
|
||||
@@ -9,40 +58,24 @@ namespace std
|
||||
|
||||
typedef size_t streamsize;
|
||||
|
||||
struct ptrdiff_t;
|
||||
|
||||
template <class iterator_category,
|
||||
class value_type,
|
||||
class difference_type = ptrdiff_t,
|
||||
class pointer_type = value_type*,
|
||||
class reference_type = value_type&>
|
||||
struct iterator {
|
||||
iterator &operator++();
|
||||
iterator operator++(int);
|
||||
bool operator==(iterator other) const;
|
||||
bool operator!=(iterator other) const;
|
||||
reference_type operator*() const;
|
||||
};
|
||||
|
||||
struct input_iterator_tag {};
|
||||
struct forward_iterator_tag : public input_iterator_tag {};
|
||||
struct bidirectional_iterator_tag : public forward_iterator_tag {};
|
||||
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
|
||||
|
||||
template <class T> class allocator {
|
||||
public:
|
||||
allocator() throw();
|
||||
typedef size_t size_type;
|
||||
};
|
||||
|
||||
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||
class basic_string {
|
||||
public:
|
||||
using value_type = charT;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
typedef typename Allocator::size_type size_type;
|
||||
static const size_type npos = -1;
|
||||
|
||||
explicit basic_string(const Allocator& a = Allocator());
|
||||
basic_string(const charT* s, const Allocator& a = Allocator());
|
||||
template<class InputIterator> basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator());
|
||||
|
||||
const charT* c_str() const;
|
||||
charT* data() noexcept;
|
||||
@@ -58,15 +91,31 @@ namespace std
|
||||
const_iterator cbegin() const;
|
||||
const_iterator cend() const;
|
||||
|
||||
void push_back(charT c);
|
||||
|
||||
const charT& front() const;
|
||||
charT& front();
|
||||
const charT& back() const;
|
||||
charT& back();
|
||||
|
||||
const_reference operator[](size_type pos) const;
|
||||
reference operator[](size_type pos);
|
||||
const_reference at(size_type n) const;
|
||||
reference at(size_type n);
|
||||
template<class T> basic_string& operator+=(const T& t);
|
||||
basic_string& operator+=(const charT* s);
|
||||
basic_string& append(const basic_string& str);
|
||||
basic_string& append(const charT* s);
|
||||
basic_string& append(size_type n, charT c);
|
||||
template<class InputIterator> basic_string& append(InputIterator first, InputIterator last);
|
||||
basic_string& assign(const basic_string& str);
|
||||
basic_string& assign(size_type n, charT c);
|
||||
template<class InputIterator> basic_string& assign(InputIterator first, InputIterator last);
|
||||
basic_string& insert(size_type pos, const basic_string& str);
|
||||
basic_string& insert(size_type pos, size_type n, charT c);
|
||||
basic_string& insert(size_type pos, const charT* s);
|
||||
iterator insert(const_iterator p, size_type n, charT c);
|
||||
template<class InputIterator> iterator insert(const_iterator p, InputIterator first, InputIterator last);
|
||||
basic_string& replace(size_type pos1, size_type n1, const basic_string& str);
|
||||
basic_string& replace(size_type pos1, size_type n1, size_type n2, charT c);
|
||||
size_type copy(charT* s, size_type n, size_type pos = 0) const;
|
||||
@@ -130,11 +179,18 @@ namespace std {
|
||||
vector() noexcept(noexcept(Allocator())) : vector(Allocator()) { }
|
||||
explicit vector(const Allocator&) noexcept;
|
||||
explicit vector(size_type n, const Allocator& = Allocator());
|
||||
vector(size_type n, const T& value, const Allocator& = Allocator());
|
||||
vector(size_type n, const T& value, const Allocator& = Allocator());
|
||||
template<class InputIterator, class IteratorCategory = typename InputIterator::iterator_category> vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
|
||||
// use of `iterator_category` makes sure InputIterator is (probably) an iterator, and not an `int` or
|
||||
// similar that should match a different overload (SFINAE).
|
||||
~vector();
|
||||
|
||||
vector& operator=(const vector& x);
|
||||
vector& operator=(vector&& x) noexcept/*(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value)*/;
|
||||
template<class InputIterator, class IteratorCategory = typename InputIterator::iterator_category> void assign(InputIterator first, InputIterator last);
|
||||
// use of `iterator_category` makes sure InputIterator is (probably) an iterator, and not an `int` or
|
||||
// similar that should match a different overload (SFINAE).
|
||||
void assign(size_type n, const T& u);
|
||||
|
||||
iterator begin() noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
@@ -161,6 +217,7 @@ namespace std {
|
||||
iterator insert(const_iterator position, const T& x);
|
||||
iterator insert(const_iterator position, T&& x);
|
||||
iterator insert(const_iterator position, size_type n, const T& x);
|
||||
template<class InputIterator> iterator insert(const_iterator position, InputIterator first, InputIterator last);
|
||||
|
||||
void swap(vector&) noexcept/*(allocator_traits<Allocator>::propagate_on_container_swap::value || allocator_traits<Allocator>::is_always_equal::value)*/;
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ void test_range_based_for_loop_string() {
|
||||
}
|
||||
|
||||
for(std::string::iterator it = s.begin(); it != s.end(); ++it) {
|
||||
sink(*it); // tainted [NOT DETECTED]
|
||||
sink(*it); // tainted [NOT DETECTED by IR]
|
||||
}
|
||||
|
||||
for(char& c : s) {
|
||||
@@ -158,12 +158,12 @@ void test_string_append() {
|
||||
sink(s5); // tainted
|
||||
|
||||
s6 = s3;
|
||||
s6 += s4;
|
||||
sink(s6 += s4); // tainted
|
||||
sink(s6); // tainted
|
||||
|
||||
s7 = s3;
|
||||
s7 += source();
|
||||
s7 += " ";
|
||||
sink(s7 += source()); // tainted
|
||||
sink(s7 += " "); // tainted
|
||||
sink(s7); // tainted
|
||||
|
||||
s8 = s3;
|
||||
@@ -321,3 +321,239 @@ void test_string_substr()
|
||||
sink(a.substr(0, a.length()));
|
||||
sink(b.substr(0, b.length())); // tainted
|
||||
}
|
||||
|
||||
void test_string_at()
|
||||
{
|
||||
std::string a("123");
|
||||
std::string b("123");
|
||||
std::string c("123");
|
||||
|
||||
sink(a);
|
||||
sink(b);
|
||||
sink(c);
|
||||
|
||||
a[0] = ns_char::source();
|
||||
b.at(0) = ns_char::source();
|
||||
c[0] = a[0];
|
||||
|
||||
sink(a); // tainted
|
||||
sink(b); // tainted
|
||||
sink(c); // tainted
|
||||
}
|
||||
|
||||
void test_string_data_more()
|
||||
{
|
||||
std::string str("123");
|
||||
|
||||
str.data()[1] = ns_char::source();
|
||||
sink(str); // tainted
|
||||
sink(str.data()); // tainted
|
||||
}
|
||||
void test_string_iterators() {
|
||||
// string append
|
||||
{
|
||||
std::string s1("hello");
|
||||
std::string s2(source());
|
||||
std::string s3("hello");
|
||||
std::string s4("world");
|
||||
|
||||
sink(s1);
|
||||
sink(s1.append(s2.begin(), s2.end())); // tainted
|
||||
sink(s1); // tainted
|
||||
|
||||
sink(s3);
|
||||
sink(s3.append(s4.begin(), s4.end()));
|
||||
sink(s3);
|
||||
}
|
||||
|
||||
// dereference
|
||||
{
|
||||
std::string s1("hello");
|
||||
std::string s2(source());
|
||||
|
||||
string::iterator iter1 = s1.begin();
|
||||
|
||||
sink(*iter1);
|
||||
sink(iter1[1]);
|
||||
string::iterator iter2 = s2.begin();
|
||||
|
||||
sink(*iter2); // tainted
|
||||
sink(iter2[1]); // tainted
|
||||
}
|
||||
|
||||
// arithmetic operators
|
||||
{
|
||||
std::string s1("hello");
|
||||
std::string s2(source());
|
||||
|
||||
string::iterator i1 = s1.begin();
|
||||
|
||||
string::iterator i2 = s2.begin();
|
||||
string::iterator i3, i4, i5, i6, i7, i8, i9;
|
||||
|
||||
sink(*(i2+1)); //tainted
|
||||
sink(*(i2-1)); // tainted
|
||||
i3 = i2;
|
||||
sink(*(++i3)); // tainted
|
||||
i4 = i2;
|
||||
sink(*(--i4)); // tainted
|
||||
i5 = i2;
|
||||
i5++;
|
||||
sink(*i5); // tainted
|
||||
i6 = i2;
|
||||
i6--;
|
||||
sink(*i6); // tainted
|
||||
i7 = i2;
|
||||
sink(*(i7+=1)); // tainted
|
||||
i8 = i2;
|
||||
sink(*(i8-=1)); // tainted
|
||||
|
||||
i9 = s2.end();
|
||||
--i9;
|
||||
sink(*i9); // tainted
|
||||
}
|
||||
}
|
||||
|
||||
void test_string_insert_more()
|
||||
{
|
||||
std::string s1("aa");
|
||||
std::string s2("bb");
|
||||
char *cs1 = "cc";
|
||||
char *cs2 = source();
|
||||
|
||||
sink(s1.insert(0, cs1));
|
||||
sink(s1);
|
||||
|
||||
sink(s2.insert(0, cs2)); // tainted
|
||||
sink(s2); // tainted
|
||||
}
|
||||
|
||||
void sink(std::string::iterator);
|
||||
|
||||
void test_string_iterator_methods()
|
||||
{
|
||||
{
|
||||
std::string a("aa");
|
||||
std::string b("bb");
|
||||
|
||||
sink(a.insert(a.begin(), 10, 'x'));
|
||||
sink(a);
|
||||
|
||||
sink(b.insert(b.begin(), 10, ns_char::source())); // tainted
|
||||
sink(b); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::string c("cc");
|
||||
std::string d("dd");
|
||||
std::string s1("11");
|
||||
std::string s2(source());
|
||||
|
||||
sink(c.insert(c.end(), s1.begin(), s1.end()));
|
||||
sink(c);
|
||||
|
||||
sink(d.insert(d.end(), s2.begin(), s2.end())); // tainted
|
||||
sink(d); // tainted
|
||||
|
||||
sink(s2.insert(s2.end(), s1.begin(), s1.end())); // tainted
|
||||
sink(s2); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::string e("ee");
|
||||
std::string f("ff");
|
||||
std::string s3("33");
|
||||
std::string s4(source());
|
||||
|
||||
sink(e.append(s3.begin(), s3.end()));
|
||||
sink(e);
|
||||
|
||||
sink(f.append(s4.begin(), s4.end())); // tainted
|
||||
sink(f); // tainted
|
||||
|
||||
sink(s4.append(s3.begin(), s3.end())); // tainted
|
||||
sink(s4); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::string g("gg");
|
||||
std::string h("hh");
|
||||
std::string s5("55");
|
||||
std::string s6(source());
|
||||
|
||||
sink(g.assign(s5.cbegin(), s5.cend()));
|
||||
sink(g);
|
||||
|
||||
sink(h.assign(s6.cbegin(), s6.cend())); // tainted
|
||||
sink(h); // tainted
|
||||
|
||||
sink(s6.assign(s5.cbegin(), s5.cend()));
|
||||
sink(s6); // [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void test_constructors_more() {
|
||||
char *cs1 = "abc";
|
||||
char *cs2 = source();
|
||||
std::string s1(cs1);
|
||||
std::string s2(cs2);
|
||||
std::string s3(s1.begin(), s1.end());
|
||||
std::string s4(s2.begin(), s2.end());
|
||||
|
||||
sink(s1);
|
||||
sink(s2); // tainted
|
||||
sink(s3);
|
||||
sink(s4); // tainted
|
||||
}
|
||||
|
||||
void test_string_front_back() {
|
||||
std::string a("aa");
|
||||
|
||||
sink(a.front());
|
||||
sink(a.back());
|
||||
a.push_back(ns_char::source());
|
||||
sink(a.front()); // [FALSE POSITIVE]
|
||||
sink(a.back()); // tainted
|
||||
}
|
||||
|
||||
void test_string_return_assign() {
|
||||
{
|
||||
std::string a("aa");
|
||||
std::string b("bb");
|
||||
std::string c("cc");
|
||||
std::string d("dd");
|
||||
std::string e("ee");
|
||||
std::string f("ff");
|
||||
|
||||
sink( a += (b += "bb") );
|
||||
sink( c += (d += source()) ); // tainted
|
||||
sink( (e += "ee") += source() ); // tainted
|
||||
sink( (f += source()) += "ff" ); // tainted
|
||||
sink(a);
|
||||
sink(b);
|
||||
sink(c); // tainted
|
||||
sink(d); // tainted
|
||||
sink(e); // tainted
|
||||
sink(f); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::string a("aa");
|
||||
std::string b("bb");
|
||||
std::string c("cc");
|
||||
std::string d("dd");
|
||||
std::string e("ee");
|
||||
std::string f("ff");
|
||||
|
||||
sink( a.assign(b.assign("bb")) );
|
||||
sink( c.assign(d.assign(source())) ); // tainted
|
||||
sink( e.assign("ee").assign(source()) ); // tainted
|
||||
sink( f.assign(source()).assign("ff") );
|
||||
sink(a);
|
||||
sink(b);
|
||||
sink(c); // tainted
|
||||
sink(d); // tainted
|
||||
sink(e); // tainted
|
||||
sink(f); // [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
| arrayassignment.cpp:33:7:33:9 | r_x | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:57:10:57:12 | call to get | arrayassignment.cpp:54:9:54:14 | call to source |
|
||||
| arrayassignment.cpp:67:10:67:12 | call to get | arrayassignment.cpp:64:13:64:18 | call to source |
|
||||
| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source |
|
||||
| arrayassignment.cpp:135:7:135:10 | ref1 | arrayassignment.cpp:134:9:134:14 | call to source |
|
||||
| copyableclass.cpp:40:8:40:9 | s1 | copyableclass.cpp:34:22:34:27 | call to source |
|
||||
| copyableclass.cpp:41:8:41:9 | s2 | copyableclass.cpp:35:24:35:29 | call to source |
|
||||
| copyableclass.cpp:42:8:42:9 | s3 | copyableclass.cpp:34:22:34:27 | call to source |
|
||||
@@ -32,6 +37,12 @@
|
||||
| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source |
|
||||
| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source |
|
||||
| movableclass.cpp:65:11:65:11 | call to operator= | movableclass.cpp:65:13:65:18 | call to source |
|
||||
| standalone_iterators.cpp:40:10:40:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
|
||||
| standalone_iterators.cpp:41:10:41:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
|
||||
| standalone_iterators.cpp:42:10:42:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
|
||||
| standalone_iterators.cpp:46:10:46:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 |
|
||||
| standalone_iterators.cpp:47:10:47:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 |
|
||||
| standalone_iterators.cpp:48:10:48:10 | call to operator* | standalone_iterators.cpp:45:39:45:45 | source1 |
|
||||
| string.cpp:28:7:28:7 | a | string.cpp:24:12:24:17 | call to source |
|
||||
| string.cpp:30:7:30:7 | c | string.cpp:26:16:26:21 | call to source |
|
||||
| string.cpp:32:9:32:13 | call to c_str | string.cpp:26:16:26:21 | call to source |
|
||||
@@ -48,6 +59,7 @@
|
||||
| string.cpp:113:8:113:9 | s1 | string.cpp:109:32:109:37 | call to source |
|
||||
| string.cpp:114:8:114:9 | s2 | string.cpp:111:20:111:25 | call to source |
|
||||
| string.cpp:121:8:121:8 | c | string.cpp:119:16:119:21 | call to source |
|
||||
| string.cpp:125:8:125:8 | call to operator* | string.cpp:119:16:119:21 | call to source |
|
||||
| string.cpp:129:8:129:8 | c | string.cpp:119:16:119:21 | call to source |
|
||||
| string.cpp:134:8:134:8 | c | string.cpp:132:28:132:33 | call to source |
|
||||
| string.cpp:144:11:144:11 | call to operator+ | string.cpp:141:18:141:23 | call to source |
|
||||
@@ -55,8 +67,11 @@
|
||||
| string.cpp:146:11:146:11 | call to operator+ | string.cpp:141:18:141:23 | call to source |
|
||||
| string.cpp:149:11:149:11 | call to operator+ | string.cpp:149:13:149:18 | call to source |
|
||||
| string.cpp:158:8:158:9 | s5 | string.cpp:154:18:154:23 | call to source |
|
||||
| string.cpp:161:11:161:11 | call to operator+= | string.cpp:154:18:154:23 | call to source |
|
||||
| string.cpp:162:8:162:9 | s6 | string.cpp:154:18:154:23 | call to source |
|
||||
| string.cpp:167:8:167:9 | s7 | string.cpp:165:9:165:14 | call to source |
|
||||
| string.cpp:165:11:165:11 | call to operator+= | string.cpp:165:14:165:19 | call to source |
|
||||
| string.cpp:166:11:166:11 | call to operator+= | string.cpp:165:14:165:19 | call to source |
|
||||
| string.cpp:167:8:167:9 | s7 | string.cpp:165:14:165:19 | call to source |
|
||||
| string.cpp:171:8:171:9 | s8 | string.cpp:154:18:154:23 | call to source |
|
||||
| string.cpp:176:8:176:9 | s9 | string.cpp:174:13:174:18 | call to source |
|
||||
| string.cpp:184:8:184:10 | s10 | string.cpp:181:12:181:26 | call to source |
|
||||
@@ -91,6 +106,56 @@
|
||||
| string.cpp:302:7:302:8 | s3 | string.cpp:290:17:290:22 | call to source |
|
||||
| string.cpp:311:9:311:12 | call to data | string.cpp:308:16:308:21 | call to source |
|
||||
| string.cpp:322:9:322:14 | call to substr | string.cpp:319:16:319:21 | call to source |
|
||||
| string.cpp:339:7:339:7 | a | string.cpp:335:9:335:23 | call to source |
|
||||
| string.cpp:340:7:340:7 | b | string.cpp:336:12:336:26 | call to source |
|
||||
| string.cpp:341:7:341:7 | c | string.cpp:335:9:335:23 | call to source |
|
||||
| string.cpp:349:7:349:9 | str | string.cpp:348:18:348:32 | call to source |
|
||||
| string.cpp:350:11:350:14 | call to data | string.cpp:348:18:348:32 | call to source |
|
||||
| string.cpp:361:11:361:16 | call to append | string.cpp:356:18:356:23 | call to source |
|
||||
| string.cpp:362:8:362:9 | s1 | string.cpp:356:18:356:23 | call to source |
|
||||
| string.cpp:380:8:380:8 | call to operator* | string.cpp:372:18:372:23 | call to source |
|
||||
| string.cpp:381:13:381:13 | call to operator[] | string.cpp:372:18:372:23 | call to source |
|
||||
| string.cpp:394:8:394:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:395:8:395:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:397:8:397:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:399:8:399:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:402:8:402:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:405:8:405:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:407:8:407:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:409:8:409:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:413:8:413:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:427:10:427:15 | call to insert | string.cpp:422:14:422:19 | call to source |
|
||||
| string.cpp:428:7:428:8 | s2 | string.cpp:422:14:422:19 | call to source |
|
||||
| string.cpp:442:10:442:15 | call to insert | string.cpp:442:32:442:46 | call to source |
|
||||
| string.cpp:443:8:443:8 | b | string.cpp:442:32:442:46 | call to source |
|
||||
| string.cpp:455:10:455:15 | call to insert | string.cpp:450:18:450:23 | call to source |
|
||||
| string.cpp:456:8:456:8 | d | string.cpp:450:18:450:23 | call to source |
|
||||
| string.cpp:458:11:458:16 | call to insert | string.cpp:450:18:450:23 | call to source |
|
||||
| string.cpp:459:8:459:9 | s2 | string.cpp:450:18:450:23 | call to source |
|
||||
| string.cpp:471:10:471:15 | call to append | string.cpp:466:18:466:23 | call to source |
|
||||
| string.cpp:472:8:472:8 | f | string.cpp:466:18:466:23 | call to source |
|
||||
| string.cpp:474:11:474:16 | call to append | string.cpp:466:18:466:23 | call to source |
|
||||
| string.cpp:475:8:475:9 | s4 | string.cpp:466:18:466:23 | call to source |
|
||||
| string.cpp:487:10:487:15 | call to assign | string.cpp:482:18:482:23 | call to source |
|
||||
| string.cpp:488:8:488:8 | h | string.cpp:482:18:482:23 | call to source |
|
||||
| string.cpp:491:8:491:9 | s6 | string.cpp:482:18:482:23 | call to source |
|
||||
| string.cpp:504:7:504:8 | s2 | string.cpp:497:14:497:19 | call to source |
|
||||
| string.cpp:506:7:506:8 | s4 | string.cpp:497:14:497:19 | call to source |
|
||||
| string.cpp:515:9:515:13 | call to front | string.cpp:514:14:514:28 | call to source |
|
||||
| string.cpp:516:9:516:12 | call to back | string.cpp:514:14:514:28 | call to source |
|
||||
| string.cpp:529:11:529:11 | call to operator+= | string.cpp:529:20:529:25 | call to source |
|
||||
| string.cpp:530:21:530:21 | call to operator+= | string.cpp:530:24:530:29 | call to source |
|
||||
| string.cpp:531:25:531:25 | call to operator+= | string.cpp:531:15:531:20 | call to source |
|
||||
| string.cpp:534:8:534:8 | c | string.cpp:529:20:529:25 | call to source |
|
||||
| string.cpp:535:8:535:8 | d | string.cpp:529:20:529:25 | call to source |
|
||||
| string.cpp:536:8:536:8 | e | string.cpp:530:24:530:29 | call to source |
|
||||
| string.cpp:537:8:537:8 | f | string.cpp:531:15:531:20 | call to source |
|
||||
| string.cpp:549:11:549:16 | call to assign | string.cpp:549:27:549:32 | call to source |
|
||||
| string.cpp:550:24:550:29 | call to assign | string.cpp:550:31:550:36 | call to source |
|
||||
| string.cpp:554:8:554:8 | c | string.cpp:549:27:549:32 | call to source |
|
||||
| string.cpp:555:8:555:8 | d | string.cpp:549:27:549:32 | call to source |
|
||||
| string.cpp:556:8:556:8 | e | string.cpp:550:31:550:36 | call to source |
|
||||
| string.cpp:557:8:557:8 | f | string.cpp:551:18:551:23 | call to source |
|
||||
| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source |
|
||||
| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source |
|
||||
| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source |
|
||||
@@ -198,11 +263,33 @@
|
||||
| taint.cpp:471:7:471:7 | y | taint.cpp:462:6:462:11 | call to source |
|
||||
| taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 |
|
||||
| vector.cpp:20:8:20:8 | x | vector.cpp:16:43:16:49 | source1 |
|
||||
| vector.cpp:24:8:24:8 | call to operator* | vector.cpp:16:43:16:49 | source1 |
|
||||
| vector.cpp:28:8:28:8 | x | vector.cpp:16:43:16:49 | source1 |
|
||||
| vector.cpp:33:8:33:8 | x | vector.cpp:16:43:16:49 | source1 |
|
||||
| vector.cpp:52:7:52:8 | v2 | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:53:9:53:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:54:9:54:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:55:9:55:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:58:7:58:8 | v3 | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:59:9:59:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:60:9:60:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:61:9:61:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:64:7:64:8 | v4 | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:65:9:65:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:66:9:66:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:67:9:67:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:70:7:70:8 | v5 | vector.cpp:69:15:69:20 | call to source |
|
||||
| vector.cpp:71:10:71:14 | call to front | vector.cpp:69:15:69:20 | call to source |
|
||||
| vector.cpp:72:10:72:13 | call to back | vector.cpp:69:15:69:20 | call to source |
|
||||
| vector.cpp:75:7:75:8 | v6 | vector.cpp:74:17:74:22 | call to source |
|
||||
| vector.cpp:76:7:76:18 | access to array | vector.cpp:74:17:74:22 | call to source |
|
||||
| vector.cpp:83:7:83:8 | v7 | vector.cpp:81:17:81:22 | call to source |
|
||||
| vector.cpp:84:10:84:14 | call to front | vector.cpp:81:17:81:22 | call to source |
|
||||
| vector.cpp:85:10:85:13 | call to back | vector.cpp:81:17:81:22 | call to source |
|
||||
| vector.cpp:97:7:97:8 | v9 | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:98:10:98:11 | call to at | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:99:10:99:11 | call to at | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:100:10:100:11 | call to at | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:109:7:109:8 | v1 | vector.cpp:106:15:106:20 | call to source |
|
||||
| vector.cpp:112:7:112:8 | v4 | vector.cpp:107:15:107:20 | call to source |
|
||||
| vector.cpp:117:7:117:8 | v1 | vector.cpp:106:15:106:20 | call to source |
|
||||
@@ -215,3 +302,27 @@
|
||||
| vector.cpp:139:7:139:8 | v1 | vector.cpp:126:15:126:20 | call to source |
|
||||
| vector.cpp:140:7:140:8 | v2 | vector.cpp:127:15:127:20 | call to source |
|
||||
| vector.cpp:141:7:141:8 | v3 | vector.cpp:128:15:128:20 | call to source |
|
||||
| vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source |
|
||||
| vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source |
|
||||
| vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source |
|
||||
| vector.cpp:242:7:242:8 | v2 | vector.cpp:238:17:238:30 | call to source |
|
||||
| vector.cpp:243:7:243:8 | v3 | vector.cpp:239:15:239:20 | call to source |
|
||||
| vector.cpp:258:8:258:9 | v5 | vector.cpp:239:15:239:20 | call to source |
|
||||
| vector.cpp:259:8:259:9 | i1 | vector.cpp:239:15:239:20 | call to source |
|
||||
| vector.cpp:260:8:260:9 | i2 | vector.cpp:239:15:239:20 | call to source |
|
||||
| vector.cpp:261:8:261:9 | v6 | vector.cpp:239:15:239:20 | call to source |
|
||||
| vector.cpp:273:8:273:9 | v7 | vector.cpp:269:18:269:31 | call to source |
|
||||
| vector.cpp:274:8:274:9 | v8 | vector.cpp:270:18:270:35 | call to source |
|
||||
| vector.cpp:275:8:275:9 | v9 | vector.cpp:271:18:271:34 | call to source |
|
||||
| vector.cpp:285:7:285:8 | v1 | vector.cpp:284:15:284:20 | call to source |
|
||||
| vector.cpp:286:10:286:13 | call to data | vector.cpp:284:15:284:20 | call to source |
|
||||
| vector.cpp:287:7:287:18 | access to array | vector.cpp:284:15:284:20 | call to source |
|
||||
| vector.cpp:290:7:290:8 | v2 | vector.cpp:289:17:289:30 | call to source |
|
||||
| vector.cpp:291:10:291:13 | call to data | vector.cpp:289:17:289:30 | call to source |
|
||||
| vector.cpp:292:7:292:18 | access to array | vector.cpp:289:17:289:30 | call to source |
|
||||
| vector.cpp:308:9:308:14 | call to insert | vector.cpp:303:14:303:19 | call to source |
|
||||
| vector.cpp:309:7:309:7 | c | vector.cpp:303:14:303:19 | call to source |
|
||||
| vector.cpp:311:9:311:14 | call to insert | vector.cpp:303:14:303:19 | call to source |
|
||||
| vector.cpp:312:7:312:7 | d | vector.cpp:303:14:303:19 | call to source |
|
||||
| vector.cpp:324:7:324:8 | v2 | vector.cpp:318:15:318:20 | call to source |
|
||||
| vector.cpp:326:7:326:8 | v4 | vector.cpp:318:15:318:20 | call to source |
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
| arrayassignment.cpp:16:7:16:7 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:17:7:17:10 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:18:7:18:11 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:19:7:19:9 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:31:7:31:7 | arrayassignment.cpp:29:8:29:13 | IR only |
|
||||
| arrayassignment.cpp:32:7:32:10 | arrayassignment.cpp:29:8:29:13 | IR only |
|
||||
| arrayassignment.cpp:34:7:34:10 | arrayassignment.cpp:29:8:29:13 | IR only |
|
||||
| arrayassignment.cpp:56:7:56:8 | arrayassignment.cpp:54:9:54:14 | IR only |
|
||||
| arrayassignment.cpp:57:10:57:12 | arrayassignment.cpp:54:9:54:14 | AST only |
|
||||
| arrayassignment.cpp:57:10:57:15 | arrayassignment.cpp:54:9:54:14 | IR only |
|
||||
| arrayassignment.cpp:66:7:66:8 | arrayassignment.cpp:64:13:64:18 | IR only |
|
||||
| arrayassignment.cpp:67:10:67:12 | arrayassignment.cpp:64:13:64:18 | AST only |
|
||||
| arrayassignment.cpp:67:10:67:15 | arrayassignment.cpp:64:13:64:18 | IR only |
|
||||
| arrayassignment.cpp:136:7:136:13 | arrayassignment.cpp:134:9:134:14 | IR only |
|
||||
| arrayassignment.cpp:140:7:140:11 | arrayassignment.cpp:139:10:139:15 | IR only |
|
||||
| arrayassignment.cpp:141:7:141:13 | arrayassignment.cpp:139:10:139:15 | IR only |
|
||||
| arrayassignment.cpp:145:7:145:13 | arrayassignment.cpp:144:12:144:17 | IR only |
|
||||
| arrayassignment.cpp:146:7:146:13 | arrayassignment.cpp:144:12:144:17 | IR only |
|
||||
| copyableclass.cpp:40:8:40:9 | copyableclass.cpp:34:22:34:27 | AST only |
|
||||
| copyableclass.cpp:41:8:41:9 | copyableclass.cpp:35:24:35:29 | AST only |
|
||||
| copyableclass.cpp:42:8:42:9 | copyableclass.cpp:34:22:34:27 | AST only |
|
||||
@@ -30,6 +48,12 @@
|
||||
| movableclass.cpp:55:8:55:9 | movableclass.cpp:52:23:52:28 | AST only |
|
||||
| movableclass.cpp:64:8:64:9 | movableclass.cpp:23:55:23:60 | AST only |
|
||||
| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only |
|
||||
| standalone_iterators.cpp:40:10:40:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
|
||||
| standalone_iterators.cpp:41:10:41:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
|
||||
| standalone_iterators.cpp:42:10:42:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
|
||||
| standalone_iterators.cpp:46:10:46:10 | standalone_iterators.cpp:45:39:45:45 | AST only |
|
||||
| standalone_iterators.cpp:47:10:47:10 | standalone_iterators.cpp:45:39:45:45 | AST only |
|
||||
| standalone_iterators.cpp:48:10:48:10 | standalone_iterators.cpp:45:39:45:45 | AST only |
|
||||
| string.cpp:30:7:30:7 | string.cpp:26:16:26:21 | AST only |
|
||||
| string.cpp:32:9:32:13 | string.cpp:26:16:26:21 | AST only |
|
||||
| string.cpp:38:13:38:17 | string.cpp:14:10:14:15 | AST only |
|
||||
@@ -45,6 +69,7 @@
|
||||
| string.cpp:113:8:113:9 | string.cpp:109:32:109:37 | AST only |
|
||||
| string.cpp:114:8:114:9 | string.cpp:111:20:111:25 | AST only |
|
||||
| string.cpp:121:8:121:8 | string.cpp:119:16:119:21 | AST only |
|
||||
| string.cpp:125:8:125:8 | string.cpp:119:16:119:21 | AST only |
|
||||
| string.cpp:129:8:129:8 | string.cpp:119:16:119:21 | AST only |
|
||||
| string.cpp:134:8:134:8 | string.cpp:132:28:132:33 | AST only |
|
||||
| string.cpp:144:11:144:11 | string.cpp:141:18:141:23 | AST only |
|
||||
@@ -52,8 +77,11 @@
|
||||
| string.cpp:146:11:146:11 | string.cpp:141:18:141:23 | AST only |
|
||||
| string.cpp:149:11:149:11 | string.cpp:149:13:149:18 | AST only |
|
||||
| string.cpp:158:8:158:9 | string.cpp:154:18:154:23 | AST only |
|
||||
| string.cpp:161:11:161:11 | string.cpp:154:18:154:23 | AST only |
|
||||
| string.cpp:162:8:162:9 | string.cpp:154:18:154:23 | AST only |
|
||||
| string.cpp:167:8:167:9 | string.cpp:165:9:165:14 | AST only |
|
||||
| string.cpp:165:11:165:11 | string.cpp:165:14:165:19 | AST only |
|
||||
| string.cpp:166:11:166:11 | string.cpp:165:14:165:19 | AST only |
|
||||
| string.cpp:167:8:167:9 | string.cpp:165:14:165:19 | AST only |
|
||||
| string.cpp:171:8:171:9 | string.cpp:154:18:154:23 | AST only |
|
||||
| string.cpp:176:8:176:9 | string.cpp:174:13:174:18 | AST only |
|
||||
| string.cpp:184:8:184:10 | string.cpp:181:12:181:26 | AST only |
|
||||
@@ -88,6 +116,56 @@
|
||||
| string.cpp:302:7:302:8 | string.cpp:290:17:290:22 | AST only |
|
||||
| string.cpp:311:9:311:12 | string.cpp:308:16:308:21 | AST only |
|
||||
| string.cpp:322:9:322:14 | string.cpp:319:16:319:21 | AST only |
|
||||
| string.cpp:339:7:339:7 | string.cpp:335:9:335:23 | AST only |
|
||||
| string.cpp:340:7:340:7 | string.cpp:336:12:336:26 | AST only |
|
||||
| string.cpp:341:7:341:7 | string.cpp:335:9:335:23 | AST only |
|
||||
| string.cpp:349:7:349:9 | string.cpp:348:18:348:32 | AST only |
|
||||
| string.cpp:350:11:350:14 | string.cpp:348:18:348:32 | AST only |
|
||||
| string.cpp:361:11:361:16 | string.cpp:356:18:356:23 | AST only |
|
||||
| string.cpp:362:8:362:9 | string.cpp:356:18:356:23 | AST only |
|
||||
| string.cpp:380:8:380:8 | string.cpp:372:18:372:23 | AST only |
|
||||
| string.cpp:381:13:381:13 | string.cpp:372:18:372:23 | AST only |
|
||||
| string.cpp:394:8:394:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:395:8:395:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:397:8:397:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:399:8:399:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:402:8:402:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:405:8:405:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:407:8:407:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:409:8:409:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:413:8:413:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:427:10:427:15 | string.cpp:422:14:422:19 | AST only |
|
||||
| string.cpp:428:7:428:8 | string.cpp:422:14:422:19 | AST only |
|
||||
| string.cpp:442:10:442:15 | string.cpp:442:32:442:46 | AST only |
|
||||
| string.cpp:443:8:443:8 | string.cpp:442:32:442:46 | AST only |
|
||||
| string.cpp:455:10:455:15 | string.cpp:450:18:450:23 | AST only |
|
||||
| string.cpp:456:8:456:8 | string.cpp:450:18:450:23 | AST only |
|
||||
| string.cpp:458:11:458:16 | string.cpp:450:18:450:23 | AST only |
|
||||
| string.cpp:459:8:459:9 | string.cpp:450:18:450:23 | AST only |
|
||||
| string.cpp:471:10:471:15 | string.cpp:466:18:466:23 | AST only |
|
||||
| string.cpp:472:8:472:8 | string.cpp:466:18:466:23 | AST only |
|
||||
| string.cpp:474:11:474:16 | string.cpp:466:18:466:23 | AST only |
|
||||
| string.cpp:475:8:475:9 | string.cpp:466:18:466:23 | AST only |
|
||||
| string.cpp:487:10:487:15 | string.cpp:482:18:482:23 | AST only |
|
||||
| string.cpp:488:8:488:8 | string.cpp:482:18:482:23 | AST only |
|
||||
| string.cpp:491:8:491:9 | string.cpp:482:18:482:23 | AST only |
|
||||
| string.cpp:504:7:504:8 | string.cpp:497:14:497:19 | AST only |
|
||||
| string.cpp:506:7:506:8 | string.cpp:497:14:497:19 | AST only |
|
||||
| string.cpp:515:9:515:13 | string.cpp:514:14:514:28 | AST only |
|
||||
| string.cpp:516:9:516:12 | string.cpp:514:14:514:28 | AST only |
|
||||
| string.cpp:529:11:529:11 | string.cpp:529:20:529:25 | AST only |
|
||||
| string.cpp:530:21:530:21 | string.cpp:530:24:530:29 | AST only |
|
||||
| string.cpp:531:25:531:25 | string.cpp:531:15:531:20 | AST only |
|
||||
| string.cpp:534:8:534:8 | string.cpp:529:20:529:25 | AST only |
|
||||
| string.cpp:535:8:535:8 | string.cpp:529:20:529:25 | AST only |
|
||||
| string.cpp:536:8:536:8 | string.cpp:530:24:530:29 | AST only |
|
||||
| string.cpp:537:8:537:8 | string.cpp:531:15:531:20 | AST only |
|
||||
| string.cpp:549:11:549:16 | string.cpp:549:27:549:32 | AST only |
|
||||
| string.cpp:550:24:550:29 | string.cpp:550:31:550:36 | AST only |
|
||||
| string.cpp:554:8:554:8 | string.cpp:549:27:549:32 | AST only |
|
||||
| string.cpp:555:8:555:8 | string.cpp:549:27:549:32 | AST only |
|
||||
| string.cpp:556:8:556:8 | string.cpp:550:31:550:36 | AST only |
|
||||
| string.cpp:557:8:557:8 | string.cpp:551:18:551:23 | AST only |
|
||||
| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only |
|
||||
| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only |
|
||||
| structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only |
|
||||
@@ -133,11 +211,33 @@
|
||||
| taint.cpp:447:9:447:17 | taint.cpp:445:14:445:28 | AST only |
|
||||
| taint.cpp:471:7:471:7 | taint.cpp:462:6:462:11 | AST only |
|
||||
| vector.cpp:20:8:20:8 | vector.cpp:16:43:16:49 | AST only |
|
||||
| vector.cpp:24:8:24:8 | vector.cpp:16:43:16:49 | AST only |
|
||||
| vector.cpp:28:8:28:8 | vector.cpp:16:43:16:49 | AST only |
|
||||
| vector.cpp:33:8:33:8 | vector.cpp:16:43:16:49 | AST only |
|
||||
| vector.cpp:52:7:52:8 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:53:9:53:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:54:9:54:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:55:9:55:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:58:7:58:8 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:59:9:59:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:60:9:60:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:61:9:61:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:64:7:64:8 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:65:9:65:9 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:66:9:66:9 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:67:9:67:9 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:70:7:70:8 | vector.cpp:69:15:69:20 | AST only |
|
||||
| vector.cpp:71:10:71:14 | vector.cpp:69:15:69:20 | AST only |
|
||||
| vector.cpp:72:10:72:13 | vector.cpp:69:15:69:20 | AST only |
|
||||
| vector.cpp:75:7:75:8 | vector.cpp:74:17:74:22 | AST only |
|
||||
| vector.cpp:76:7:76:18 | vector.cpp:74:17:74:22 | AST only |
|
||||
| vector.cpp:83:7:83:8 | vector.cpp:81:17:81:22 | AST only |
|
||||
| vector.cpp:84:10:84:14 | vector.cpp:81:17:81:22 | AST only |
|
||||
| vector.cpp:85:10:85:13 | vector.cpp:81:17:81:22 | AST only |
|
||||
| vector.cpp:97:7:97:8 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:98:10:98:11 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:99:10:99:11 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:100:10:100:11 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:109:7:109:8 | vector.cpp:106:15:106:20 | AST only |
|
||||
| vector.cpp:112:7:112:8 | vector.cpp:107:15:107:20 | AST only |
|
||||
| vector.cpp:117:7:117:8 | vector.cpp:106:15:106:20 | AST only |
|
||||
@@ -150,3 +250,28 @@
|
||||
| vector.cpp:139:7:139:8 | vector.cpp:126:15:126:20 | AST only |
|
||||
| vector.cpp:140:7:140:8 | vector.cpp:127:15:127:20 | AST only |
|
||||
| vector.cpp:141:7:141:8 | vector.cpp:128:15:128:20 | AST only |
|
||||
| vector.cpp:162:8:162:15 | vector.cpp:161:14:161:19 | IR only |
|
||||
| vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only |
|
||||
| vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only |
|
||||
| vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only |
|
||||
| vector.cpp:242:7:242:8 | vector.cpp:238:17:238:30 | AST only |
|
||||
| vector.cpp:243:7:243:8 | vector.cpp:239:15:239:20 | AST only |
|
||||
| vector.cpp:258:8:258:9 | vector.cpp:239:15:239:20 | AST only |
|
||||
| vector.cpp:259:8:259:9 | vector.cpp:239:15:239:20 | AST only |
|
||||
| vector.cpp:260:8:260:9 | vector.cpp:239:15:239:20 | AST only |
|
||||
| vector.cpp:261:8:261:9 | vector.cpp:239:15:239:20 | AST only |
|
||||
| vector.cpp:273:8:273:9 | vector.cpp:269:18:269:31 | AST only |
|
||||
| vector.cpp:274:8:274:9 | vector.cpp:270:18:270:35 | AST only |
|
||||
| vector.cpp:275:8:275:9 | vector.cpp:271:18:271:34 | AST only |
|
||||
| vector.cpp:285:7:285:8 | vector.cpp:284:15:284:20 | AST only |
|
||||
| vector.cpp:286:10:286:13 | vector.cpp:284:15:284:20 | AST only |
|
||||
| vector.cpp:287:7:287:18 | vector.cpp:284:15:284:20 | AST only |
|
||||
| vector.cpp:290:7:290:8 | vector.cpp:289:17:289:30 | AST only |
|
||||
| vector.cpp:291:10:291:13 | vector.cpp:289:17:289:30 | AST only |
|
||||
| vector.cpp:292:7:292:18 | vector.cpp:289:17:289:30 | AST only |
|
||||
| vector.cpp:308:9:308:14 | vector.cpp:303:14:303:19 | AST only |
|
||||
| vector.cpp:309:7:309:7 | vector.cpp:303:14:303:19 | AST only |
|
||||
| vector.cpp:311:9:311:14 | vector.cpp:303:14:303:19 | AST only |
|
||||
| vector.cpp:312:7:312:7 | vector.cpp:303:14:303:19 | AST only |
|
||||
| vector.cpp:324:7:324:8 | vector.cpp:318:15:318:20 | AST only |
|
||||
| vector.cpp:326:7:326:8 | vector.cpp:318:15:318:20 | AST only |
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
| arrayassignment.cpp:16:7:16:7 | x | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:17:7:17:10 | * ... | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:18:7:18:11 | * ... | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:19:7:19:9 | (reference dereference) | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:31:7:31:7 | x | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:32:7:32:10 | * ... | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:33:7:33:9 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:34:7:34:10 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:56:7:56:8 | mi | arrayassignment.cpp:54:9:54:14 | call to source |
|
||||
| arrayassignment.cpp:57:10:57:15 | (reference dereference) | arrayassignment.cpp:54:9:54:14 | call to source |
|
||||
| arrayassignment.cpp:66:7:66:8 | mi | arrayassignment.cpp:64:13:64:18 | call to source |
|
||||
| arrayassignment.cpp:67:10:67:15 | (reference dereference) | arrayassignment.cpp:64:13:64:18 | call to source |
|
||||
| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source |
|
||||
| arrayassignment.cpp:135:7:135:10 | (reference dereference) | arrayassignment.cpp:134:9:134:14 | call to source |
|
||||
| arrayassignment.cpp:136:7:136:13 | access to array | arrayassignment.cpp:134:9:134:14 | call to source |
|
||||
| arrayassignment.cpp:140:7:140:11 | * ... | arrayassignment.cpp:139:10:139:15 | call to source |
|
||||
| arrayassignment.cpp:141:7:141:13 | access to array | arrayassignment.cpp:139:10:139:15 | call to source |
|
||||
| arrayassignment.cpp:145:7:145:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source |
|
||||
| arrayassignment.cpp:146:7:146:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source |
|
||||
| format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | call to source |
|
||||
| format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source |
|
||||
| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source |
|
||||
@@ -79,3 +98,4 @@
|
||||
| taint.cpp:465:7:465:7 | x | taint.cpp:462:6:462:11 | call to source |
|
||||
| taint.cpp:470:7:470:7 | x | taint.cpp:462:6:462:11 | call to source |
|
||||
| taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 |
|
||||
| vector.cpp:162:8:162:15 | access to array | vector.cpp:161:14:161:19 | call to source |
|
||||
|
||||
@@ -5,9 +5,9 @@ using namespace std;
|
||||
|
||||
int source();
|
||||
|
||||
namespace ns_char
|
||||
namespace ns_int
|
||||
{
|
||||
char source();
|
||||
int source();
|
||||
}
|
||||
|
||||
void sink(int);
|
||||
@@ -21,7 +21,7 @@ void test_range_based_for_loop_vector(int source1) {
|
||||
}
|
||||
|
||||
for(std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
|
||||
sink(*it); // tainted [NOT DETECTED]
|
||||
sink(*it); // tainted
|
||||
}
|
||||
|
||||
for(int& x : v) {
|
||||
@@ -49,22 +49,22 @@ void test_element_taint(int x) {
|
||||
sink(v1.back());
|
||||
|
||||
v2[0] = source();
|
||||
sink(v2); // tainted [NOT DETECTED]
|
||||
sink(v2[0]); // tainted [NOT DETECTED]
|
||||
sink(v2[1]);
|
||||
sink(v2); // tainted
|
||||
sink(v2[0]); // tainted
|
||||
sink(v2[1]); // [FALSE POSITIVE]
|
||||
sink(v2[x]); // potentially tainted
|
||||
|
||||
v3 = v2;
|
||||
sink(v3); // tainted [NOT DETECTED]
|
||||
sink(v3[0]); // tainted [NOT DETECTED]
|
||||
sink(v3[1]);
|
||||
sink(v3); // tainted
|
||||
sink(v3[0]); // tainted
|
||||
sink(v3[1]); // [FALSE POSITIVE]
|
||||
sink(v3[x]); // potentially tainted
|
||||
|
||||
v4[x] = source();
|
||||
sink(v4); // tainted [NOT DETECTED]
|
||||
sink(v4); // tainted
|
||||
sink(v4[0]); // potentially tainted
|
||||
sink(v4[1]); // potentially tainted
|
||||
sink(v4[x]); // tainted [NOT DETECTED]
|
||||
sink(v4[x]); // tainted
|
||||
|
||||
v5.push_back(source());
|
||||
sink(v5); // tainted
|
||||
@@ -72,32 +72,32 @@ void test_element_taint(int x) {
|
||||
sink(v5.back()); // tainted
|
||||
|
||||
v6.data()[2] = source();
|
||||
sink(v6); // tainted [NOT DETECTED]
|
||||
sink(v6.data()[2]); // tainted [NOT DETECTED]
|
||||
sink(v6); // tainted
|
||||
sink(v6.data()[2]); // tainted
|
||||
|
||||
|
||||
{
|
||||
const std::vector<int> &v7c = v7; // (workaround because our iterators don't convert to const_iterator)
|
||||
std::vector<int>::const_iterator it = v7c.begin();
|
||||
std::vector<int>::const_iterator it = v7.begin();
|
||||
v7.insert(it, source());
|
||||
}
|
||||
sink(v7); // tainted [NOT DETECTED]
|
||||
sink(v7.front()); // tainted [NOT DETECTED]
|
||||
sink(v7.back());
|
||||
sink(v7); // tainted
|
||||
sink(v7.front()); // tainted
|
||||
sink(v7.back()); // [FALSE POSITIVE]
|
||||
|
||||
{
|
||||
const std::vector<int> &v8c = v8;
|
||||
std::vector<int>::const_iterator it = v8c.begin();
|
||||
v8.insert(it, 10, ns_char::source());
|
||||
v8.insert(it, 10, ns_int::source());
|
||||
}
|
||||
sink(v8); // tainted [NOT DETECTED]
|
||||
sink(v8.front()); // tainted [NOT DETECTED]
|
||||
sink(v8.back());
|
||||
|
||||
v9.at(x) = source();
|
||||
sink(v9); // tainted [NOT DETECTED]
|
||||
sink(v9); // tainted
|
||||
sink(v9.at(0)); // potentially tainted
|
||||
sink(v9.at(1)); // potentially tainted
|
||||
sink(v9.at(x)); // tainted [NOT DETECTED]
|
||||
sink(v9.at(x)); // tainted
|
||||
}
|
||||
|
||||
void test_vector_swap() {
|
||||
@@ -141,3 +141,187 @@ void test_vector_clear() {
|
||||
sink(v3); // [FALSE POSITIVE]
|
||||
sink(v4);
|
||||
}
|
||||
|
||||
struct MyPair
|
||||
{
|
||||
int a, b;
|
||||
};
|
||||
|
||||
struct MyVectorContainer
|
||||
{
|
||||
std::vector<int> vs;
|
||||
};
|
||||
|
||||
void test_nested_vectors()
|
||||
{
|
||||
{
|
||||
int aa[10][20] = {0};
|
||||
|
||||
sink(aa[0][0]);
|
||||
aa[0][0] = source();
|
||||
sink(aa[0][0]); // tainted [IR ONLY]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<std::vector<int> > bb(30);
|
||||
|
||||
bb[0].push_back(0);
|
||||
sink(bb[0][0]);
|
||||
bb[0][0] = source();
|
||||
sink(bb[0][0]); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> cc[40];
|
||||
|
||||
cc[0].push_back(0);
|
||||
sink(cc[0][0]);
|
||||
cc[0][0] = source();
|
||||
sink(cc[0][0]); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<MyPair> dd;
|
||||
MyPair mp = {0, 0};
|
||||
|
||||
dd.push_back(mp);
|
||||
sink(dd[0].a);
|
||||
sink(dd[0].b);
|
||||
dd[0].a = source();
|
||||
sink(dd[0].a); // tainted [NOT DETECTED]
|
||||
sink(dd[0].b);
|
||||
}
|
||||
|
||||
{
|
||||
MyVectorContainer ee;
|
||||
|
||||
ee.vs.push_back(0);
|
||||
sink(ee.vs[0]);
|
||||
ee.vs[0] = source();
|
||||
sink(ee.vs[0]); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<MyVectorContainer> ff;
|
||||
MyVectorContainer mvc;
|
||||
|
||||
mvc.vs.push_back(0);
|
||||
ff.push_back(mvc);
|
||||
sink(ff[0].vs[0]);
|
||||
ff[0].vs[0] = source();
|
||||
sink(ff[0].vs[0]); // tainted [NOT DETECTED]
|
||||
}
|
||||
}
|
||||
|
||||
void sink(std::vector<int>::iterator &);
|
||||
|
||||
typedef int myInt;
|
||||
typedef float myFloat;
|
||||
|
||||
namespace ns_myFloat
|
||||
{
|
||||
myFloat source();
|
||||
}
|
||||
|
||||
namespace ns_ci_ptr
|
||||
{
|
||||
const int *source();
|
||||
}
|
||||
|
||||
void sink(std::vector<myFloat> &);
|
||||
void sink(std::vector<const int *> &);
|
||||
|
||||
void test_vector_assign() {
|
||||
std::vector<int> v1, v2, v3;
|
||||
|
||||
v1.assign(100, 0);
|
||||
v2.assign(100, ns_int::source());
|
||||
v3.push_back(source());
|
||||
|
||||
sink(v1);
|
||||
sink(v2); // tainted
|
||||
sink(v3); // tainted
|
||||
|
||||
{
|
||||
std::vector<int> v4, v5, v6;
|
||||
std::vector<int>::iterator i1, i2;
|
||||
|
||||
v4.assign(v1.begin(), v1.end());
|
||||
v5.assign(v3.begin(), v3.end());
|
||||
i1 = v3.begin();
|
||||
i1++;
|
||||
i2 = i1;
|
||||
i2++;
|
||||
v6.assign(i1, i2);
|
||||
|
||||
sink(v4);
|
||||
sink(v5); // tainted
|
||||
sink(i1); // tainted
|
||||
sink(i2); // tainted
|
||||
sink(v6); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<myInt> v7;
|
||||
std::vector<myFloat> v8;
|
||||
std::vector<const int *> v9;
|
||||
|
||||
v7.assign(100, ns_int::source());
|
||||
v8.assign(100, ns_myFloat::source());
|
||||
v9.assign(100, ns_ci_ptr::source());
|
||||
|
||||
sink(v7); // tainted
|
||||
sink(v8); // tainted
|
||||
sink(v9); // tainted
|
||||
}
|
||||
}
|
||||
|
||||
void sink(int *);
|
||||
|
||||
void test_data_more() {
|
||||
std::vector<int> v1, v2;
|
||||
|
||||
v1.push_back(source());
|
||||
sink(v1); // tainted
|
||||
sink(v1.data()); // tainted
|
||||
sink(v1.data()[2]); // tainted
|
||||
|
||||
*(v2.data()) = ns_int::source();
|
||||
sink(v2); // tainted
|
||||
sink(v2.data()); // tainted
|
||||
sink(v2.data()[2]); // tainted
|
||||
}
|
||||
|
||||
void sink(std::vector<int>::iterator);
|
||||
|
||||
void test_vector_insert() {
|
||||
std::vector<int> a;
|
||||
std::vector<int> b;
|
||||
std::vector<int> c;
|
||||
std::vector<int> d;
|
||||
|
||||
d.push_back(source());
|
||||
|
||||
sink(a.insert(a.end(), b.begin(), b.end()));
|
||||
sink(a);
|
||||
|
||||
sink(c.insert(c.end(), d.begin(), d.end())); // tainted
|
||||
sink(c); // tainted
|
||||
|
||||
sink(d.insert(d.end(), a.begin(), a.end())); // tainted
|
||||
sink(d); // tainted
|
||||
}
|
||||
|
||||
void test_constructors_more() {
|
||||
std::vector<int> v1;
|
||||
std::vector<int> v2;
|
||||
v2.push_back(source());
|
||||
|
||||
std::vector<int> v3(v1.begin(), v1.end());
|
||||
std::vector<int> v4(v2.begin(), v2.end());
|
||||
|
||||
sink(v1);
|
||||
sink(v2); // tainted
|
||||
sink(v3);
|
||||
sink(v4); // tainted
|
||||
}
|
||||
|
||||
@@ -532,6 +532,37 @@
|
||||
| test.c:530:3:530:3 | i | -2147483648 |
|
||||
| test.c:530:10:530:11 | sc | 1 |
|
||||
| test.c:532:7:532:7 | i | -128 |
|
||||
| test.c:539:7:539:7 | n | 0 |
|
||||
| test.c:541:7:541:7 | n | 0 |
|
||||
| test.c:542:9:542:9 | n | 1 |
|
||||
| test.c:545:7:545:7 | n | 0 |
|
||||
| test.c:546:9:546:9 | n | 1 |
|
||||
| test.c:548:9:548:9 | n | 0 |
|
||||
| test.c:551:8:551:8 | n | 0 |
|
||||
| test.c:552:9:552:9 | n | 0 |
|
||||
| test.c:554:9:554:9 | n | 0 |
|
||||
| test.c:557:10:557:10 | n | 0 |
|
||||
| test.c:558:5:558:5 | n | 1 |
|
||||
| test.c:561:7:561:7 | n | 0 |
|
||||
| test.c:565:7:565:7 | n | -32768 |
|
||||
| test.c:568:7:568:7 | n | 0 |
|
||||
| test.c:569:9:569:9 | n | 0 |
|
||||
| test.c:571:9:571:9 | n | 1 |
|
||||
| test.c:574:7:574:7 | n | 0 |
|
||||
| test.c:575:9:575:9 | n | 0 |
|
||||
| test.c:577:9:577:9 | n | 0 |
|
||||
| test.c:580:10:580:10 | n | 0 |
|
||||
| test.c:581:5:581:5 | n | 1 |
|
||||
| test.c:584:7:584:7 | n | 0 |
|
||||
| test.c:588:7:588:7 | n | -32768 |
|
||||
| test.c:589:9:589:9 | n | -32768 |
|
||||
| test.c:590:11:590:11 | n | 0 |
|
||||
| test.c:594:7:594:7 | n | -32768 |
|
||||
| test.c:595:13:595:13 | n | 5 |
|
||||
| test.c:598:9:598:9 | n | 6 |
|
||||
| test.c:601:7:601:7 | n | -32768 |
|
||||
| test.c:601:22:601:22 | n | -32767 |
|
||||
| test.c:602:9:602:9 | n | -32766 |
|
||||
| test.cpp:10:7:10:7 | b | -2147483648 |
|
||||
| test.cpp:11:5:11:5 | x | -2147483648 |
|
||||
| test.cpp:13:10:13:10 | x | -2147483648 |
|
||||
@@ -573,3 +604,15 @@
|
||||
| test.cpp:75:22:75:30 | c_times_2 | 0 |
|
||||
| test.cpp:77:5:77:13 | c_times_2 | 0 |
|
||||
| test.cpp:79:3:79:11 | c_times_2 | 0 |
|
||||
| test.cpp:83:16:83:22 | aliased | -2147483648 |
|
||||
| test.cpp:85:7:85:7 | i | -2147483648 |
|
||||
| test.cpp:86:12:86:12 | i | 2 |
|
||||
| test.cpp:88:7:88:8 | ci | -2147483648 |
|
||||
| test.cpp:89:12:89:13 | ci | 2 |
|
||||
| test.cpp:91:7:91:13 | aliased | -2147483648 |
|
||||
| test.cpp:92:12:92:18 | aliased | -2147483648 |
|
||||
| test.cpp:94:7:94:11 | alias | -2147483648 |
|
||||
| test.cpp:95:12:95:16 | alias | -2147483648 |
|
||||
| test.cpp:97:10:97:10 | i | -2147483648 |
|
||||
| test.cpp:97:22:97:22 | i | -2147483648 |
|
||||
| test.cpp:98:5:98:5 | i | -2147483648 |
|
||||
|
||||
@@ -533,3 +533,72 @@ int mul_by_constant(int i, int j) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int notequal_type_endpoint(unsigned n) {
|
||||
out(n); // 0 ..
|
||||
|
||||
if (n > 0) {
|
||||
out(n); // 1 ..
|
||||
}
|
||||
|
||||
if (n != 0) {
|
||||
out(n); // 1 ..
|
||||
} else {
|
||||
out(n); // 0 .. 0
|
||||
}
|
||||
|
||||
if (!n) {
|
||||
out(n); // 0 .. 0
|
||||
} else {
|
||||
out(n); // 1 .. [BUG: lower bound is deduced to be 0]
|
||||
}
|
||||
|
||||
while (n != 0) {
|
||||
n--; // 1 ..
|
||||
}
|
||||
|
||||
out(n); // 0 .. 0
|
||||
}
|
||||
|
||||
void notequal_refinement(short n) {
|
||||
if (n < 0)
|
||||
return;
|
||||
|
||||
if (n == 0) {
|
||||
out(n); // 0 .. 0
|
||||
} else {
|
||||
out(n); // 1 ..
|
||||
}
|
||||
|
||||
if (n) {
|
||||
out(n); // 1 .. [BUG: lower bound is deduced to be 0]
|
||||
} else {
|
||||
out(n); // 0 .. 0
|
||||
}
|
||||
|
||||
while (n != 0) {
|
||||
n--; // 1 ..
|
||||
}
|
||||
|
||||
out(n); // 0 .. 0
|
||||
}
|
||||
|
||||
void notequal_variations(short n, float f) {
|
||||
if (n != 0) {
|
||||
if (n >= 0) {
|
||||
out(n); // 1 .. [BUG: we can't handle `!=` coming first]
|
||||
}
|
||||
}
|
||||
|
||||
if (n >= 5) {
|
||||
if (2 * n - 10 == 0) { // Same as `n == 10/2` (modulo overflow)
|
||||
return;
|
||||
}
|
||||
out(n); // 6 ..
|
||||
}
|
||||
|
||||
if (n != -32768 && n != -32767) {
|
||||
out(n); // -32766 ..
|
||||
}
|
||||
}
|
||||
@@ -78,3 +78,25 @@ void use_after_cast(unsigned char c)
|
||||
}
|
||||
c_times_2;
|
||||
}
|
||||
|
||||
int ref_to_number(int &i, const int &ci, int &aliased) {
|
||||
int &alias = aliased; // no range analysis for either of the two aliased variables
|
||||
|
||||
if (i >= 2)
|
||||
return i;
|
||||
|
||||
if (ci >= 2)
|
||||
return ci;
|
||||
|
||||
if (aliased >= 2)
|
||||
return aliased;
|
||||
|
||||
if (alias >= 2)
|
||||
return alias;
|
||||
|
||||
for (; i <= 12345; i++) { // test that widening works for references
|
||||
i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -532,6 +532,37 @@
|
||||
| test.c:530:3:530:3 | i | 2147483647 |
|
||||
| test.c:530:10:530:11 | sc | 1 |
|
||||
| test.c:532:7:532:7 | i | 127 |
|
||||
| test.c:539:7:539:7 | n | 4294967295 |
|
||||
| test.c:541:7:541:7 | n | 4294967295 |
|
||||
| test.c:542:9:542:9 | n | 4294967295 |
|
||||
| test.c:545:7:545:7 | n | 4294967295 |
|
||||
| test.c:546:9:546:9 | n | 4294967295 |
|
||||
| test.c:548:9:548:9 | n | 0 |
|
||||
| test.c:551:8:551:8 | n | 4294967295 |
|
||||
| test.c:552:9:552:9 | n | 4294967295 |
|
||||
| test.c:554:9:554:9 | n | 4294967295 |
|
||||
| test.c:557:10:557:10 | n | 4294967295 |
|
||||
| test.c:558:5:558:5 | n | 4294967295 |
|
||||
| test.c:561:7:561:7 | n | 0 |
|
||||
| test.c:565:7:565:7 | n | 32767 |
|
||||
| test.c:568:7:568:7 | n | 32767 |
|
||||
| test.c:569:9:569:9 | n | 0 |
|
||||
| test.c:571:9:571:9 | n | 32767 |
|
||||
| test.c:574:7:574:7 | n | 32767 |
|
||||
| test.c:575:9:575:9 | n | 32767 |
|
||||
| test.c:577:9:577:9 | n | 32767 |
|
||||
| test.c:580:10:580:10 | n | 32767 |
|
||||
| test.c:581:5:581:5 | n | 32767 |
|
||||
| test.c:584:7:584:7 | n | 0 |
|
||||
| test.c:588:7:588:7 | n | 32767 |
|
||||
| test.c:589:9:589:9 | n | 32767 |
|
||||
| test.c:590:11:590:11 | n | 32767 |
|
||||
| test.c:594:7:594:7 | n | 32767 |
|
||||
| test.c:595:13:595:13 | n | 32767 |
|
||||
| test.c:598:9:598:9 | n | 32767 |
|
||||
| test.c:601:7:601:7 | n | 32767 |
|
||||
| test.c:601:22:601:22 | n | 32767 |
|
||||
| test.c:602:9:602:9 | n | 32767 |
|
||||
| test.cpp:10:7:10:7 | b | 2147483647 |
|
||||
| test.cpp:11:5:11:5 | x | 2147483647 |
|
||||
| test.cpp:13:10:13:10 | x | 2147483647 |
|
||||
@@ -573,3 +604,15 @@
|
||||
| test.cpp:75:22:75:30 | c_times_2 | 510 |
|
||||
| test.cpp:77:5:77:13 | c_times_2 | 510 |
|
||||
| test.cpp:79:3:79:11 | c_times_2 | 510 |
|
||||
| test.cpp:83:16:83:22 | aliased | 2147483647 |
|
||||
| test.cpp:85:7:85:7 | i | 2147483647 |
|
||||
| test.cpp:86:12:86:12 | i | 2147483647 |
|
||||
| test.cpp:88:7:88:8 | ci | 2147483647 |
|
||||
| test.cpp:89:12:89:13 | ci | 2147483647 |
|
||||
| test.cpp:91:7:91:13 | aliased | 2147483647 |
|
||||
| test.cpp:92:12:92:18 | aliased | 2147483647 |
|
||||
| test.cpp:94:7:94:11 | alias | 2147483647 |
|
||||
| test.cpp:95:12:95:16 | alias | 2147483647 |
|
||||
| test.cpp:97:10:97:10 | i | 65535 |
|
||||
| test.cpp:97:22:97:22 | i | 32767 |
|
||||
| test.cpp:98:5:98:5 | i | 32767 |
|
||||
|
||||
10
cpp/ql/test/library-tests/specifiers2/cpp20.cpp
Normal file
10
cpp/ql/test/library-tests/specifiers2/cpp20.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// semmle-extractor-options: --edg --clang --edg --c++20
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
class TestConstexpr {
|
||||
constexpr int member_constexpr() { return 0; } // not const in C++ >= 14
|
||||
constexpr int member_const_constexpr() const { return 0; }
|
||||
};
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -1,5 +1,22 @@
|
||||
| Class | specifiers2pp.cpp:8:7:8:13 | MyClass | MyClass | abstract |
|
||||
| Class | specifiers2pp.cpp:24:7:24:14 | MyClass2 | MyClass2 | abstract |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | declared_constexpr |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | inline |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | is_constexpr |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | private |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | const |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | declared_constexpr |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | inline |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | is_constexpr |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | private |
|
||||
| Function | specifiers2.c:11:6:11:6 | f | f | extern |
|
||||
| Function | specifiers2.c:12:13:12:13 | f | f | extern |
|
||||
| Function | specifiers2.c:13:13:13:13 | f | f | extern |
|
||||
@@ -79,6 +96,24 @@
|
||||
| Function | specifiers2pp.cpp:41:16:41:23 | someFun2 | someFun2 | extern |
|
||||
| Function | specifiers2pp.cpp:43:9:43:16 | someFun3 | someFun3 | extern |
|
||||
| Function | specifiers2pp.cpp:44:16:44:23 | someFun4 | someFun4 | static |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | const |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | declared_constexpr |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | inline |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | private |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | const |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | declared_constexpr |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | inline |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | private |
|
||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | c_linkage |
|
||||
|
||||
@@ -58,3 +58,8 @@ template<typename T> using Const = const T;
|
||||
using Const_int = Const<int>;
|
||||
|
||||
typedef volatile Const_int volatile_Const_int;
|
||||
|
||||
class TestConstexpr {
|
||||
constexpr int member_constexpr() { return 0; } // const in C++11
|
||||
constexpr int member_const_constexpr() const { return 0; }
|
||||
};
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.internal.CFG
|
||||
|
||||
class DestructorCallEnhanced extends DestructorCall {
|
||||
override string toString() {
|
||||
if exists(this.getQualifier().(VariableAccess).getTarget().getName())
|
||||
then
|
||||
result =
|
||||
"call to " + this.getQualifier().(VariableAccess).getTarget().getName() + "." +
|
||||
this.getTarget().getName()
|
||||
else result = super.toString()
|
||||
}
|
||||
}
|
||||
|
||||
predicate differentEdge(ControlFlowNode n1, ControlFlowNode n2, string msg) {
|
||||
successors(n1, n2) and
|
||||
not qlCFGSuccessor(n1, n2) and
|
||||
msg = "Standard edge, only from extractor"
|
||||
or
|
||||
not successors(n1, n2) and
|
||||
qlCFGSuccessor(n1, n2) and
|
||||
msg = "Standard edge, only from QL"
|
||||
or
|
||||
truecond_base(n1, n2) and
|
||||
not qlCFGTrueSuccessor(n1, n2) and
|
||||
msg = "True edge, only from extractor"
|
||||
or
|
||||
not truecond_base(n1, n2) and
|
||||
qlCFGTrueSuccessor(n1, n2) and
|
||||
msg = "True edge, only from QL"
|
||||
or
|
||||
falsecond_base(n1, n2) and
|
||||
not qlCFGFalseSuccessor(n1, n2) and
|
||||
msg = "False edge, only from extractor"
|
||||
or
|
||||
not falsecond_base(n1, n2) and
|
||||
qlCFGFalseSuccessor(n1, n2) and
|
||||
msg = "False edge, only from QL"
|
||||
}
|
||||
|
||||
predicate differentScope(Element e) {
|
||||
exists(ControlFlowNode n1 |
|
||||
getScopeElement(n1) = e and
|
||||
differentEdge(n1, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isInFunction(ControlFlowNode x, Function f) {
|
||||
f = x.getControlFlowScope()
|
||||
or
|
||||
exists(ControlFlowNode y |
|
||||
successors(unresolveElement(x), unresolveElement(y))
|
||||
or
|
||||
successors(unresolveElement(y), unresolveElement(x))
|
||||
|
|
||||
isInFunction(y, f)
|
||||
)
|
||||
}
|
||||
|
||||
Element getScopeElement(ControlFlowNode x) {
|
||||
isInFunction(x, result)
|
||||
or
|
||||
not isInFunction(x, _) and
|
||||
result = x.getFile()
|
||||
}
|
||||
|
||||
string getScopeName(ControlFlowNode x) {
|
||||
exists(Function scope | scope = getScopeElement(x) |
|
||||
differentScope(scope) and
|
||||
result =
|
||||
scope.getFile().getBaseName().splitAt(".", 0) + "__" +
|
||||
scope.getQualifiedName().replaceAll("::", "_")
|
||||
)
|
||||
or
|
||||
exists(File scope | scope = getScopeElement(x) |
|
||||
differentScope(scope) and
|
||||
result = scope.getBaseName()
|
||||
)
|
||||
}
|
||||
|
||||
module QLCFG {
|
||||
private predicate isNode(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) {
|
||||
isEdge = false and x = y and label = x.toString()
|
||||
}
|
||||
|
||||
private predicate isSuccessor(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) {
|
||||
exists(string truelabel, string falselabel |
|
||||
isEdge = true and
|
||||
qlCFGSuccessor(x, y) and
|
||||
(if qlCFGTrueSuccessor(x, y) then truelabel = "T" else truelabel = "") and
|
||||
(if qlCFGFalseSuccessor(x, y) then falselabel = "F" else falselabel = "") and
|
||||
label = truelabel + falselabel
|
||||
)
|
||||
}
|
||||
|
||||
predicate qltestGraph(
|
||||
Element scopeElement, string scopeString, boolean isEdge, ControlFlowNode x, ControlFlowNode y,
|
||||
string label
|
||||
) {
|
||||
scopeElement = getScopeElement(x) and
|
||||
scopeString = getScopeName(x) + "_ql" and
|
||||
(
|
||||
isNode(isEdge, x, y, label)
|
||||
or
|
||||
isSuccessor(isEdge, x, y, label)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module ExtractorCFG {
|
||||
predicate isNode(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) {
|
||||
isEdge = false and x = y and label = x.toString()
|
||||
}
|
||||
|
||||
predicate isSuccessor(boolean isEdge, ControlFlowNode x, ControlFlowNode y, string label) {
|
||||
exists(string truelabel, string falselabel |
|
||||
isEdge = true and
|
||||
successors(x, y) and
|
||||
(if truecond_base(x, y) then truelabel = "T" else truelabel = "") and
|
||||
(if falsecond_base(x, y) then falselabel = "F" else falselabel = "") and
|
||||
label = truelabel + falselabel
|
||||
)
|
||||
}
|
||||
|
||||
predicate qltestGraph(
|
||||
Element scopeElement, string scopeString, boolean isEdge, ControlFlowNode x, ControlFlowNode y,
|
||||
string label
|
||||
) {
|
||||
scopeElement = getScopeElement(x) and
|
||||
scopeString = getScopeName(x) + "_extractor" and
|
||||
(
|
||||
isNode(isEdge, x, y, label)
|
||||
or
|
||||
isSuccessor(isEdge, x, y, label)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module AllCFG {
|
||||
predicate qltestGraph(
|
||||
Element scopeElement, string scopeString, boolean isEdge, ControlFlowNode x, ControlFlowNode y,
|
||||
string label
|
||||
) {
|
||||
QLCFG::qltestGraph(scopeElement, scopeString, isEdge, x, y, label)
|
||||
or
|
||||
ExtractorCFG::qltestGraph(scopeElement, scopeString, isEdge, x, y, label)
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,6 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
| builtin.cpp:15:31:15:35 | * ... | ArgumentNode is missing PostUpdateNode. |
|
||||
| conditional_destructors.cpp:30:9:30:13 | call to C1 | ArgumentNode is missing PostUpdateNode. |
|
||||
|
||||
@@ -1473,5 +1473,4 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
| a.c:4:5:4:6 | definition of is | array of {int} | 1 |
|
||||
| a.h:2:12:2:13 | declaration of is | array of 4 {int} | 1 |
|
||||
| file://:0:0:0:0 | definition of fp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | definition of gp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | definition of overflow_arg_area | pointer to {void} | 1 |
|
||||
| file://:0:0:0:0 | definition of reg_save_area | pointer to {void} | 1 |
|
||||
5
cpp/ql/test/library-tests/variables/global/vardecl.ql
Normal file
5
cpp/ql/test/library-tests/variables/global/vardecl.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from VariableDeclarationEntry vd, Type t
|
||||
where t = vd.getType()
|
||||
select vd, t.explain(), count(Type u | u = vd.getType())
|
||||
@@ -1,5 +1,4 @@
|
||||
| a.c:4:5:4:6 | is | array of 4 {int} | 2 |
|
||||
| a.c:4:5:4:6 | is | array of {int} | 2 |
|
||||
| a.c:4:5:4:6 | is | array of {int} | 1 |
|
||||
| file://:0:0:0:0 | fp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | gp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | overflow_arg_area | pointer to {void} | 1 |
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
| hiding.cpp:4:17:4:18 | ii | Local variable 'ii' hides a $@. | hiding.cpp:2:12:2:13 | definition of ii | parameter of the same name |
|
||||
| hiding.cpp:15:15:15:16 | kk | Local variable 'kk' hides a $@. | hiding.cpp:12:25:12:26 | definition of kk | parameter of the same name |
|
||||
| hiding.cpp:28:7:28:7 | a | Local variable 'a' hides a $@. | hiding.cpp:26:21:26:21 | definition of a | parameter of the same name |
|
||||
| hiding.cpp:45:7:45:7 | a | Local variable 'a' hides a $@. | hiding.cpp:43:41:43:41 | definition of a | parameter of the same name |
|
||||
| hiding.cpp:64:11:64:11 | i | Local variable 'i' hides a $@. | hiding.cpp:61:20:61:20 | definition of i | parameter of the same name |
|
||||
| hiding.cpp:78:7:78:10 | arg1 | Local variable 'arg1' hides a $@. | hiding.cpp:74:28:74:31 | definition of arg1 | parameter of the same name |
|
||||
| hiding.cpp:79:5:79:8 | arg2 | Local variable 'arg2' hides a $@. | hiding.cpp:74:36:74:39 | definition of arg2 | parameter of the same name |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
void f(int ii) {
|
||||
if (1) {
|
||||
for(int ii = 1; ii < 10; ii++) {
|
||||
for(int ii = 1; ii < 10; ii++) { // local variable hides parameter of the same name
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace foo {
|
||||
void f2(int ii, int kk) {
|
||||
try {
|
||||
for (ii = 0; ii < 3; ii++) {
|
||||
int kk;
|
||||
int kk; // local variable hides parameter of the same name
|
||||
}
|
||||
}
|
||||
catch (int ee) {
|
||||
@@ -21,4 +21,61 @@ namespace foo {
|
||||
}
|
||||
}
|
||||
|
||||
void myFunction(int a, int b, int c);
|
||||
|
||||
void myFunction(int a, int b, int _c) {
|
||||
{
|
||||
int a = a; // local variable hides parameter of the same name
|
||||
int _b = b;
|
||||
int c = _c;
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
class MyTemplateClass {
|
||||
public:
|
||||
void myMethod(int a, int b, int c);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
void MyTemplateClass<T> :: myMethod(int a, int b, int _c) {
|
||||
{
|
||||
int a = a; // local variable hides parameter of the same name
|
||||
int _b = b;
|
||||
int c = _c;
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
MyTemplateClass<int> mtc_i;
|
||||
|
||||
void test() {
|
||||
mtc_i.myMethod(0, 0, 0);
|
||||
}
|
||||
|
||||
#define MYMACRO for (int i = 0; i < 10; i++) {}
|
||||
|
||||
void testMacro(int i) {
|
||||
MYMACRO;
|
||||
|
||||
for (int i = 0; i < 10; i++) {}; // local variable hides parameter of the same name
|
||||
}
|
||||
|
||||
#include "hiding.h"
|
||||
|
||||
void myClass::myCaller(void) {
|
||||
this->myMethod(5, 6);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void myClass::myMethod(int arg1, T arg2) {
|
||||
{
|
||||
int protoArg1;
|
||||
T protoArg2;
|
||||
int arg1; // local variable hides parameter of the same name
|
||||
T arg2; // local variable hides parameter of the same name
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
class myClass {
|
||||
public:
|
||||
template <typename T>
|
||||
void myMethod(int protoArg1, T protoArg2);
|
||||
void myCaller(void);
|
||||
};
|
||||
2110
cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/old.dbscheme
Normal file
2110
cpp/upgrades/098850d25c4e9d417eb74c1bef9deb2f9d2dc417/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Remove the old CFG tables
|
||||
compatibility: full
|
||||
|
||||
Reference in New Issue
Block a user