Merge branch 'main' into mathiasvp/read-step-without-memory-operands

This commit is contained in:
Mathias Vorreiter Pedersen
2020-09-04 17:25:36 +02:00
367 changed files with 12001 additions and 3682 deletions

View File

@@ -4,6 +4,6 @@
"slevesque.vscode-zipexplorer"
],
"settings": {
"codeQL.experimentalBqrsParsing": true
"codeQL.runningQueries.memory": 2048
}
}

11
.github/workflows/labeler.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
name: "Pull Request Labeler"
on:
- pull_request_target
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v2
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -9,7 +9,7 @@ You can use the [interactive query console](https://lgtm.com/help/lgtm/using-que
## Contributing
We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/github/codeql/tree/master/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query.
We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/github/codeql/tree/main/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query.
## License

View File

@@ -19,7 +19,7 @@ The following changes in version 1.26 affect C/C++ analysis in all applications.
## Changes to libraries
* The models library now models some taint flows through `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`.
* The models library now models many taint flows through `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`.
* The models library now models many more taint flows through `std::string`.
* The `SimpleRangeAnalysis` library now supports multiplications of the form
`e1 * e2` and `x *= e2` when `e1` and `e2` are unsigned or constant.

View File

@@ -21,6 +21,10 @@ The following changes in version 1.26 affect C# analysis in all applications.
* Partial method bodies are extracted. Previously, partial method bodies were skipped completely.
* Inferring the lengths of implicitely sized arrays is fixed. Previously, multidimensional arrays were always extracted with the same length for
each dimension. With the fix, the array sizes `2` and `1` are extracted for `new int[,]{{1},{2}}`. Previously `2` and `2` were extracted.
* The extractor is now assembly-insensitive by default. This means that two entities with the same
fully-qualified name are now mapped to the same entity in the resulting database, regardless of
whether they belong to different assemblies. Assembly sensitivity can be reenabled by passing
`--assemblysensitivetrap` to the extractor.
## Changes to libraries

View File

@@ -26,8 +26,10 @@
| **Query** | **Expected impact** | **Change** |
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
| Potentially unsafe external link (`js/unsafe-external-link`) | Fewer results | This query no longer flags URLs constructed using a template system where only the hash or query part of the URL is dynamic. |
| Incomplete URL substring sanitization (`js/incomplete-url-substring-sanitization`) | More results | This query now recognizes additional URLs when the substring check is an inclusion check. |
| Ambiguous HTML id attribute (`js/duplicate-html-id`) | Results no longer shown | Precision tag reduced to "low". The query is no longer run by default. |
| Unused loop iteration variable (`js/unused-loop-variable`) | Fewer results | This query no longer flags variables in a destructuring array assignment that are not the last variable in the destructed array. |
## Changes to libraries

View File

@@ -335,5 +335,50 @@
"java/ql/src/semmle/code/xml/XML.qll",
"javascript/ql/src/semmle/javascript/XML.qll",
"python/ql/src/semmle/python/xml/XML.qll"
],
"DuplicationProblems.qhelp": [
"cpp/ql/src/Metrics/Files/DuplicationProblems.qhelp",
"csharp/ql/src/Metrics/Files/DuplicationProblems.qhelp",
"javascript/ql/src/Metrics/DuplicationProblems.qhelp",
"python/ql/src/Metrics/DuplicationProblems.qhelp"
],
"CommentedOutCodeQuery.qhelp": [
"cpp/ql/src/Documentation/CommentedOutCodeQuery.qhelp",
"python/ql/src/Lexical/CommentedOutCodeQuery.qhelp",
"csharp/ql/src/Bad Practices/Comments/CommentedOutCodeQuery.qhelp",
"java/ql/src/Violations of Best Practice/Comments/CommentedOutCodeQuery.qhelp",
"javascript/ql/src/Comments/CommentedOutCodeQuery.qhelp"
],
"FLinesOfCodeReferences.qhelp": [
"java/ql/src/Metrics/Files/FLinesOfCodeReferences.qhelp",
"javascript/ql/src/Metrics/FLinesOfCodeReferences.qhelp"
],
"FCommentRatioCommon.qhelp": [
"java/ql/src/Metrics/Files/FCommentRatioCommon.qhelp",
"javascript/ql/src/Metrics/FCommentRatioCommon.qhelp"
],
"FLinesOfCodeOverview.qhelp": [
"java/ql/src/Metrics/Files/FLinesOfCodeOverview.qhelp",
"javascript/ql/src/Metrics/FLinesOfCodeOverview.qhelp"
],
"CommentedOutCodeMetricOverview.qhelp": [
"cpp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp",
"csharp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp",
"java/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp",
"javascript/ql/src/Comments/CommentedOutCodeMetricOverview.qhelp",
"python/ql/src/Lexical/CommentedOutCodeMetricOverview.qhelp"
],
"FLinesOfDuplicatedCodeCommon.qhelp": [
"cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp",
"java/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp",
"javascript/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.qhelp",
"python/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.qhelp"
],
"CommentedOutCodeReferences.qhelp": [
"cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp",
"csharp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp",
"java/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp",
"javascript/ql/src/Comments/CommentedOutCodeReferences.qhelp",
"python/ql/src/Lexical/CommentedOutCodeReferences.qhelp"
]
}

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

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

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

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

View File

@@ -3,5 +3,5 @@
"qhelp.dtd">
<qhelp>
<include src="CommentedOutCodeQuery.qhelp" />
<include src="CommentedOutCodeReferences.qhelp" />
<include src="../Metrics/Files/CommentedOutCodeReferences.qhelp" />
</qhelp>

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

View File

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

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

@@ -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, _)
}
}

View File

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

View File

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

View File

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

View File

@@ -44,9 +44,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() }
@@ -57,7 +62,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. */
@@ -392,7 +403,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
@@ -476,20 +487,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 }
@@ -498,6 +515,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 }

View File

@@ -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
@@ -26,9 +27,17 @@ class StdSequenceContainerConstructor extends Constructor, TaintFunction {
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.
}
}
@@ -88,6 +97,43 @@ 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`.
*/
@@ -105,13 +151,41 @@ class StdSequenceContainerAssign extends TaintFunction {
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 string itself (qualifier) and return value
input.isParameterDeref(getAValueTypeParameterIndex()) and
// 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.
*/

View File

@@ -14,6 +14,43 @@ class StdBasicString extends TemplateClass {
StdBasicString() { this.hasQualifiedName("std", "basic_string") }
}
/**
* 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`.
*/
@@ -79,8 +116,8 @@ class StdStringAppend extends TaintFunction {
* character).
*/
int getAStringParameterIndex() {
getParameter(result).getType() instanceof PointerType or
getParameter(result).getType() instanceof ReferenceType or
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`
}
@@ -115,15 +152,23 @@ class StdStringAssign extends TaintFunction {
* character).
*/
int getAStringParameterIndex() {
getParameter(result).getType() instanceof PointerType or
getParameter(result).getType() instanceof ReferenceType or
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(getAStringParameterIndex()) and
(
input.isParameterDeref(getAStringParameterIndex()) or
input.isParameter(getAnIteratorParameterIndex())
) and
(
output.isQualifierObject() or
output.isReturnValueDeref()
@@ -137,14 +182,9 @@ class StdStringAssign extends TaintFunction {
*/
class StdStringBeginEnd extends TaintFunction {
StdStringBeginEnd() {
this.hasQualifiedName("std", "basic_string", "begin") or
this.hasQualifiedName("std", "basic_string", "cbegin") or
this.hasQualifiedName("std", "basic_string", "rbegin") or
this.hasQualifiedName("std", "basic_string", "crbegin") or
this.hasQualifiedName("std", "basic_string", "end") or
this.hasQualifiedName("std", "basic_string", "cend") or
this.hasQualifiedName("std", "basic_string", "rend") or
this.hasQualifiedName("std", "basic_string", "crend")
this
.hasQualifiedName("std", "basic_string",
["begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend"])
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {

View File

@@ -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 |
@@ -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 |
@@ -1501,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`. */
@@ -1533,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 {
/**

View File

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

View File

@@ -245,6 +245,8 @@
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
| format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | |
| format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | |
| format.cpp:16:46:16:51 | format | format.cpp:22:28:22:33 | format | |
@@ -459,12 +461,12 @@
| standalone_iterators.cpp:51:37:51:43 | source1 | standalone_iterators.cpp:53:12:53:18 | source1 | |
| standalone_iterators.cpp:51:37:51:43 | source1 | standalone_iterators.cpp:54:14:54:20 | source1 | |
| standalone_iterators.cpp:53:12:53:18 | ref arg source1 | standalone_iterators.cpp:54:14:54:20 | source1 | |
| stl.h:156:30:156:40 | call to allocator | stl.h:156:21:156:41 | noexcept(...) | TAINT |
| stl.h:156:30:156:40 | call to allocator | stl.h:156:21:156:41 | noexcept(...) | TAINT |
| stl.h:156:30:156:40 | call to allocator | stl.h:156:21:156:41 | noexcept(...) | TAINT |
| stl.h:156:30:156:40 | call to allocator | stl.h:156:21:156:41 | noexcept(...) | TAINT |
| stl.h:156:30:156:40 | call to allocator | stl.h:156:21:156:41 | noexcept(...) | TAINT |
| stl.h:156:53:156:63 | 0 | stl.h:156:46:156:64 | (no string representation) | TAINT |
| stl.h:172:30:172:40 | call to allocator | stl.h:172:21:172:41 | noexcept(...) | TAINT |
| stl.h:172:30:172:40 | call to allocator | stl.h:172:21:172:41 | noexcept(...) | TAINT |
| stl.h:172:30:172:40 | call to allocator | stl.h:172:21:172:41 | noexcept(...) | TAINT |
| stl.h:172:30:172:40 | call to allocator | stl.h:172:21:172:41 | noexcept(...) | TAINT |
| stl.h:172:30:172:40 | call to allocator | stl.h:172:21:172:41 | noexcept(...) | TAINT |
| stl.h:172:53:172:63 | 0 | stl.h:172:46:172:64 | (no string representation) | TAINT |
| string.cpp:24:12:24:17 | call to source | string.cpp:28:7:28:7 | a | |
| string.cpp:25:16:25:20 | 123 | string.cpp:25:16:25:21 | call to basic_string | TAINT |
| string.cpp:25:16:25:21 | call to basic_string | string.cpp:29:7:29:7 | b | |
@@ -527,6 +529,7 @@
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:128:16:128:16 | s | |
| string.cpp:120:15:120:15 | (__begin) | string.cpp:120:15:120:15 | call to operator* | TAINT |
| string.cpp:120:15:120:15 | (__begin) | string.cpp:120:15:120:15 | call to operator++ | TAINT |
| string.cpp:120:15:120:15 | (__end) | string.cpp:120:15:120:15 | call to iterator | |
| string.cpp:120:15:120:15 | (__range) | string.cpp:120:15:120:15 | call to begin | TAINT |
| string.cpp:120:15:120:15 | (__range) | string.cpp:120:15:120:15 | call to end | TAINT |
| string.cpp:120:15:120:15 | call to begin | string.cpp:120:15:120:15 | (__begin) | |
@@ -557,6 +560,7 @@
| string.cpp:125:9:125:10 | it | string.cpp:125:8:125:8 | call to operator* | TAINT |
| string.cpp:128:16:128:16 | (__begin) | string.cpp:128:16:128:16 | call to operator* | TAINT |
| string.cpp:128:16:128:16 | (__begin) | string.cpp:128:16:128:16 | call to operator++ | TAINT |
| string.cpp:128:16:128:16 | (__end) | string.cpp:128:16:128:16 | call to iterator | |
| string.cpp:128:16:128:16 | (__range) | string.cpp:128:16:128:16 | call to begin | TAINT |
| string.cpp:128:16:128:16 | (__range) | string.cpp:128:16:128:16 | call to end | TAINT |
| string.cpp:128:16:128:16 | call to begin | string.cpp:128:16:128:16 | (__begin) | |
@@ -1011,6 +1015,228 @@
| string.cpp:412:5:412:6 | i9 | string.cpp:412:3:412:3 | call to operator-- | TAINT |
| string.cpp:412:5:412:6 | ref arg i9 | string.cpp:413:9:413:10 | i9 | |
| string.cpp:413:9:413:10 | i9 | string.cpp:413:8:413:8 | call to operator* | TAINT |
| string.cpp:419:17:419:20 | aa | string.cpp:419:17:419:21 | call to basic_string | TAINT |
| string.cpp:419:17:419:21 | call to basic_string | string.cpp:424:7:424:8 | s1 | |
| string.cpp:419:17:419:21 | call to basic_string | string.cpp:425:7:425:8 | s1 | |
| string.cpp:420:17:420:20 | bb | string.cpp:420:17:420:21 | call to basic_string | TAINT |
| string.cpp:420:17:420:21 | call to basic_string | string.cpp:427:7:427:8 | s2 | |
| string.cpp:420:17:420:21 | call to basic_string | string.cpp:428:7:428:8 | s2 | |
| string.cpp:421:14:421:17 | cc | string.cpp:424:20:424:22 | cs1 | |
| string.cpp:422:14:422:19 | call to source | string.cpp:427:20:427:22 | cs2 | |
| string.cpp:424:7:424:8 | ref arg s1 | string.cpp:425:7:425:8 | s1 | |
| string.cpp:424:7:424:8 | s1 | string.cpp:424:10:424:15 | call to insert | TAINT |
| string.cpp:424:20:424:22 | cs1 | string.cpp:424:7:424:8 | ref arg s1 | TAINT |
| string.cpp:424:20:424:22 | cs1 | string.cpp:424:10:424:15 | call to insert | TAINT |
| string.cpp:427:7:427:8 | ref arg s2 | string.cpp:428:7:428:8 | s2 | |
| string.cpp:427:7:427:8 | s2 | string.cpp:427:10:427:15 | call to insert | TAINT |
| string.cpp:427:20:427:22 | cs2 | string.cpp:427:7:427:8 | ref arg s2 | TAINT |
| string.cpp:427:20:427:22 | cs2 | string.cpp:427:10:427:15 | call to insert | TAINT |
| string.cpp:436:17:436:20 | aa | string.cpp:436:17:436:21 | call to basic_string | TAINT |
| string.cpp:436:17:436:21 | call to basic_string | string.cpp:439:8:439:8 | a | |
| string.cpp:436:17:436:21 | call to basic_string | string.cpp:439:17:439:17 | a | |
| string.cpp:436:17:436:21 | call to basic_string | string.cpp:440:8:440:8 | a | |
| string.cpp:437:17:437:20 | bb | string.cpp:437:17:437:21 | call to basic_string | TAINT |
| string.cpp:437:17:437:21 | call to basic_string | string.cpp:442:8:442:8 | b | |
| string.cpp:437:17:437:21 | call to basic_string | string.cpp:442:17:442:17 | b | |
| string.cpp:437:17:437:21 | call to basic_string | string.cpp:443:8:443:8 | b | |
| string.cpp:439:8:439:8 | a | string.cpp:439:10:439:15 | call to insert | TAINT |
| string.cpp:439:8:439:8 | ref arg a | string.cpp:440:8:440:8 | a | |
| string.cpp:439:17:439:17 | a | string.cpp:439:19:439:23 | call to begin | TAINT |
| string.cpp:439:17:439:17 | ref arg a | string.cpp:439:8:439:8 | a | |
| string.cpp:439:17:439:17 | ref arg a | string.cpp:440:8:440:8 | a | |
| string.cpp:439:19:439:23 | call to begin | string.cpp:439:17:439:25 | call to iterator | TAINT |
| string.cpp:439:32:439:34 | 120 | string.cpp:439:8:439:8 | ref arg a | TAINT |
| string.cpp:439:32:439:34 | 120 | string.cpp:439:10:439:15 | call to insert | TAINT |
| string.cpp:442:8:442:8 | b | string.cpp:442:10:442:15 | call to insert | TAINT |
| string.cpp:442:8:442:8 | ref arg b | string.cpp:443:8:443:8 | b | |
| string.cpp:442:17:442:17 | b | string.cpp:442:19:442:23 | call to begin | TAINT |
| string.cpp:442:17:442:17 | ref arg b | string.cpp:442:8:442:8 | b | |
| string.cpp:442:17:442:17 | ref arg b | string.cpp:443:8:443:8 | b | |
| string.cpp:442:19:442:23 | call to begin | string.cpp:442:17:442:25 | call to iterator | TAINT |
| string.cpp:442:32:442:46 | call to source | string.cpp:442:8:442:8 | ref arg b | TAINT |
| string.cpp:442:32:442:46 | call to source | string.cpp:442:10:442:15 | call to insert | TAINT |
| string.cpp:447:17:447:20 | cc | string.cpp:447:17:447:21 | call to basic_string | TAINT |
| string.cpp:447:17:447:21 | call to basic_string | string.cpp:452:8:452:8 | c | |
| string.cpp:447:17:447:21 | call to basic_string | string.cpp:452:17:452:17 | c | |
| string.cpp:447:17:447:21 | call to basic_string | string.cpp:453:8:453:8 | c | |
| string.cpp:448:17:448:20 | dd | string.cpp:448:17:448:21 | call to basic_string | TAINT |
| string.cpp:448:17:448:21 | call to basic_string | string.cpp:455:8:455:8 | d | |
| string.cpp:448:17:448:21 | call to basic_string | string.cpp:455:17:455:17 | d | |
| string.cpp:448:17:448:21 | call to basic_string | string.cpp:456:8:456:8 | d | |
| string.cpp:449:18:449:21 | 11 | string.cpp:449:18:449:22 | call to basic_string | TAINT |
| string.cpp:449:18:449:22 | call to basic_string | string.cpp:452:26:452:27 | s1 | |
| string.cpp:449:18:449:22 | call to basic_string | string.cpp:452:38:452:39 | s1 | |
| string.cpp:449:18:449:22 | call to basic_string | string.cpp:458:28:458:29 | s1 | |
| string.cpp:449:18:449:22 | call to basic_string | string.cpp:458:40:458:41 | s1 | |
| string.cpp:450:18:450:23 | call to source | string.cpp:450:18:450:26 | call to basic_string | TAINT |
| string.cpp:450:18:450:26 | call to basic_string | string.cpp:455:26:455:27 | s2 | |
| string.cpp:450:18:450:26 | call to basic_string | string.cpp:455:38:455:39 | s2 | |
| string.cpp:450:18:450:26 | call to basic_string | string.cpp:458:8:458:9 | s2 | |
| string.cpp:450:18:450:26 | call to basic_string | string.cpp:458:18:458:19 | s2 | |
| string.cpp:450:18:450:26 | call to basic_string | string.cpp:459:8:459:9 | s2 | |
| string.cpp:452:8:452:8 | c | string.cpp:452:10:452:15 | call to insert | TAINT |
| string.cpp:452:8:452:8 | ref arg c | string.cpp:453:8:453:8 | c | |
| string.cpp:452:17:452:17 | c | string.cpp:452:19:452:21 | call to end | TAINT |
| string.cpp:452:17:452:17 | ref arg c | string.cpp:452:8:452:8 | c | |
| string.cpp:452:17:452:17 | ref arg c | string.cpp:453:8:453:8 | c | |
| string.cpp:452:19:452:21 | call to end | string.cpp:452:17:452:23 | call to iterator | TAINT |
| string.cpp:452:26:452:27 | ref arg s1 | string.cpp:452:38:452:39 | s1 | |
| string.cpp:452:26:452:27 | ref arg s1 | string.cpp:458:28:458:29 | s1 | |
| string.cpp:452:26:452:27 | ref arg s1 | string.cpp:458:40:458:41 | s1 | |
| string.cpp:452:26:452:27 | s1 | string.cpp:452:29:452:33 | call to begin | TAINT |
| string.cpp:452:29:452:33 | call to begin | string.cpp:452:8:452:8 | ref arg c | TAINT |
| string.cpp:452:29:452:33 | call to begin | string.cpp:452:10:452:15 | call to insert | TAINT |
| string.cpp:452:38:452:39 | ref arg s1 | string.cpp:458:28:458:29 | s1 | |
| string.cpp:452:38:452:39 | ref arg s1 | string.cpp:458:40:458:41 | s1 | |
| string.cpp:452:38:452:39 | s1 | string.cpp:452:41:452:43 | call to end | TAINT |
| string.cpp:452:41:452:43 | call to end | string.cpp:452:8:452:8 | ref arg c | TAINT |
| string.cpp:452:41:452:43 | call to end | string.cpp:452:10:452:15 | call to insert | TAINT |
| string.cpp:455:8:455:8 | d | string.cpp:455:10:455:15 | call to insert | TAINT |
| string.cpp:455:8:455:8 | ref arg d | string.cpp:456:8:456:8 | d | |
| string.cpp:455:17:455:17 | d | string.cpp:455:19:455:21 | call to end | TAINT |
| string.cpp:455:17:455:17 | ref arg d | string.cpp:455:8:455:8 | d | |
| string.cpp:455:17:455:17 | ref arg d | string.cpp:456:8:456:8 | d | |
| string.cpp:455:19:455:21 | call to end | string.cpp:455:17:455:23 | call to iterator | TAINT |
| string.cpp:455:26:455:27 | ref arg s2 | string.cpp:455:38:455:39 | s2 | |
| string.cpp:455:26:455:27 | ref arg s2 | string.cpp:458:8:458:9 | s2 | |
| string.cpp:455:26:455:27 | ref arg s2 | string.cpp:458:18:458:19 | s2 | |
| string.cpp:455:26:455:27 | ref arg s2 | string.cpp:459:8:459:9 | s2 | |
| string.cpp:455:26:455:27 | s2 | string.cpp:455:29:455:33 | call to begin | TAINT |
| string.cpp:455:29:455:33 | call to begin | string.cpp:455:8:455:8 | ref arg d | TAINT |
| string.cpp:455:29:455:33 | call to begin | string.cpp:455:10:455:15 | call to insert | TAINT |
| string.cpp:455:38:455:39 | ref arg s2 | string.cpp:458:8:458:9 | s2 | |
| string.cpp:455:38:455:39 | ref arg s2 | string.cpp:458:18:458:19 | s2 | |
| string.cpp:455:38:455:39 | ref arg s2 | string.cpp:459:8:459:9 | s2 | |
| string.cpp:455:38:455:39 | s2 | string.cpp:455:41:455:43 | call to end | TAINT |
| string.cpp:455:41:455:43 | call to end | string.cpp:455:8:455:8 | ref arg d | TAINT |
| string.cpp:455:41:455:43 | call to end | string.cpp:455:10:455:15 | call to insert | TAINT |
| string.cpp:458:8:458:9 | ref arg s2 | string.cpp:459:8:459:9 | s2 | |
| string.cpp:458:8:458:9 | s2 | string.cpp:458:11:458:16 | call to insert | TAINT |
| string.cpp:458:18:458:19 | ref arg s2 | string.cpp:458:8:458:9 | s2 | |
| string.cpp:458:18:458:19 | ref arg s2 | string.cpp:459:8:459:9 | s2 | |
| string.cpp:458:18:458:19 | s2 | string.cpp:458:21:458:23 | call to end | TAINT |
| string.cpp:458:21:458:23 | call to end | string.cpp:458:18:458:25 | call to iterator | TAINT |
| string.cpp:458:28:458:29 | ref arg s1 | string.cpp:458:40:458:41 | s1 | |
| string.cpp:458:28:458:29 | s1 | string.cpp:458:31:458:35 | call to begin | TAINT |
| string.cpp:458:31:458:35 | call to begin | string.cpp:458:8:458:9 | ref arg s2 | TAINT |
| string.cpp:458:31:458:35 | call to begin | string.cpp:458:11:458:16 | call to insert | TAINT |
| string.cpp:458:40:458:41 | s1 | string.cpp:458:43:458:45 | call to end | TAINT |
| string.cpp:458:43:458:45 | call to end | string.cpp:458:8:458:9 | ref arg s2 | TAINT |
| string.cpp:458:43:458:45 | call to end | string.cpp:458:11:458:16 | call to insert | TAINT |
| string.cpp:463:17:463:20 | ee | string.cpp:463:17:463:21 | call to basic_string | TAINT |
| string.cpp:463:17:463:21 | call to basic_string | string.cpp:468:8:468:8 | e | |
| string.cpp:463:17:463:21 | call to basic_string | string.cpp:469:8:469:8 | e | |
| string.cpp:464:17:464:20 | ff | string.cpp:464:17:464:21 | call to basic_string | TAINT |
| string.cpp:464:17:464:21 | call to basic_string | string.cpp:471:8:471:8 | f | |
| string.cpp:464:17:464:21 | call to basic_string | string.cpp:472:8:472:8 | f | |
| string.cpp:465:18:465:21 | 33 | string.cpp:465:18:465:22 | call to basic_string | TAINT |
| string.cpp:465:18:465:22 | call to basic_string | string.cpp:468:17:468:18 | s3 | |
| string.cpp:465:18:465:22 | call to basic_string | string.cpp:468:29:468:30 | s3 | |
| string.cpp:465:18:465:22 | call to basic_string | string.cpp:474:18:474:19 | s3 | |
| string.cpp:465:18:465:22 | call to basic_string | string.cpp:474:30:474:31 | s3 | |
| string.cpp:466:18:466:23 | call to source | string.cpp:466:18:466:26 | call to basic_string | TAINT |
| string.cpp:466:18:466:26 | call to basic_string | string.cpp:471:17:471:18 | s4 | |
| string.cpp:466:18:466:26 | call to basic_string | string.cpp:471:29:471:30 | s4 | |
| string.cpp:466:18:466:26 | call to basic_string | string.cpp:474:8:474:9 | s4 | |
| string.cpp:466:18:466:26 | call to basic_string | string.cpp:475:8:475:9 | s4 | |
| string.cpp:468:8:468:8 | e | string.cpp:468:10:468:15 | call to append | TAINT |
| string.cpp:468:8:468:8 | ref arg e | string.cpp:469:8:469:8 | e | |
| string.cpp:468:17:468:18 | ref arg s3 | string.cpp:468:29:468:30 | s3 | |
| string.cpp:468:17:468:18 | ref arg s3 | string.cpp:474:18:474:19 | s3 | |
| string.cpp:468:17:468:18 | ref arg s3 | string.cpp:474:30:474:31 | s3 | |
| string.cpp:468:17:468:18 | s3 | string.cpp:468:20:468:24 | call to begin | TAINT |
| string.cpp:468:20:468:24 | call to begin | string.cpp:468:8:468:8 | ref arg e | TAINT |
| string.cpp:468:20:468:24 | call to begin | string.cpp:468:10:468:15 | call to append | TAINT |
| string.cpp:468:29:468:30 | ref arg s3 | string.cpp:474:18:474:19 | s3 | |
| string.cpp:468:29:468:30 | ref arg s3 | string.cpp:474:30:474:31 | s3 | |
| string.cpp:468:29:468:30 | s3 | string.cpp:468:32:468:34 | call to end | TAINT |
| string.cpp:468:32:468:34 | call to end | string.cpp:468:8:468:8 | ref arg e | TAINT |
| string.cpp:468:32:468:34 | call to end | string.cpp:468:10:468:15 | call to append | TAINT |
| string.cpp:471:8:471:8 | f | string.cpp:471:10:471:15 | call to append | TAINT |
| string.cpp:471:8:471:8 | ref arg f | string.cpp:472:8:472:8 | f | |
| string.cpp:471:17:471:18 | ref arg s4 | string.cpp:471:29:471:30 | s4 | |
| string.cpp:471:17:471:18 | ref arg s4 | string.cpp:474:8:474:9 | s4 | |
| string.cpp:471:17:471:18 | ref arg s4 | string.cpp:475:8:475:9 | s4 | |
| string.cpp:471:17:471:18 | s4 | string.cpp:471:20:471:24 | call to begin | TAINT |
| string.cpp:471:20:471:24 | call to begin | string.cpp:471:8:471:8 | ref arg f | TAINT |
| string.cpp:471:20:471:24 | call to begin | string.cpp:471:10:471:15 | call to append | TAINT |
| string.cpp:471:29:471:30 | ref arg s4 | string.cpp:474:8:474:9 | s4 | |
| string.cpp:471:29:471:30 | ref arg s4 | string.cpp:475:8:475:9 | s4 | |
| string.cpp:471:29:471:30 | s4 | string.cpp:471:32:471:34 | call to end | TAINT |
| string.cpp:471:32:471:34 | call to end | string.cpp:471:8:471:8 | ref arg f | TAINT |
| string.cpp:471:32:471:34 | call to end | string.cpp:471:10:471:15 | call to append | TAINT |
| string.cpp:474:8:474:9 | ref arg s4 | string.cpp:475:8:475:9 | s4 | |
| string.cpp:474:8:474:9 | s4 | string.cpp:474:11:474:16 | call to append | TAINT |
| string.cpp:474:18:474:19 | ref arg s3 | string.cpp:474:30:474:31 | s3 | |
| string.cpp:474:18:474:19 | s3 | string.cpp:474:21:474:25 | call to begin | TAINT |
| string.cpp:474:21:474:25 | call to begin | string.cpp:474:8:474:9 | ref arg s4 | TAINT |
| string.cpp:474:21:474:25 | call to begin | string.cpp:474:11:474:16 | call to append | TAINT |
| string.cpp:474:30:474:31 | s3 | string.cpp:474:33:474:35 | call to end | TAINT |
| string.cpp:474:33:474:35 | call to end | string.cpp:474:8:474:9 | ref arg s4 | TAINT |
| string.cpp:474:33:474:35 | call to end | string.cpp:474:11:474:16 | call to append | TAINT |
| string.cpp:479:17:479:20 | gg | string.cpp:479:17:479:21 | call to basic_string | TAINT |
| string.cpp:479:17:479:21 | call to basic_string | string.cpp:484:8:484:8 | g | |
| string.cpp:479:17:479:21 | call to basic_string | string.cpp:485:8:485:8 | g | |
| string.cpp:480:17:480:20 | hh | string.cpp:480:17:480:21 | call to basic_string | TAINT |
| string.cpp:480:17:480:21 | call to basic_string | string.cpp:487:8:487:8 | h | |
| string.cpp:480:17:480:21 | call to basic_string | string.cpp:488:8:488:8 | h | |
| string.cpp:481:18:481:21 | 55 | string.cpp:481:18:481:22 | call to basic_string | TAINT |
| string.cpp:481:18:481:22 | call to basic_string | string.cpp:484:17:484:18 | s5 | |
| string.cpp:481:18:481:22 | call to basic_string | string.cpp:484:30:484:31 | s5 | |
| string.cpp:481:18:481:22 | call to basic_string | string.cpp:490:18:490:19 | s5 | |
| string.cpp:481:18:481:22 | call to basic_string | string.cpp:490:31:490:32 | s5 | |
| string.cpp:482:18:482:23 | call to source | string.cpp:482:18:482:26 | call to basic_string | TAINT |
| string.cpp:482:18:482:26 | call to basic_string | string.cpp:487:17:487:18 | s6 | |
| string.cpp:482:18:482:26 | call to basic_string | string.cpp:487:30:487:31 | s6 | |
| string.cpp:482:18:482:26 | call to basic_string | string.cpp:490:8:490:9 | s6 | |
| string.cpp:482:18:482:26 | call to basic_string | string.cpp:491:8:491:9 | s6 | |
| string.cpp:484:8:484:8 | ref arg g | string.cpp:485:8:485:8 | g | |
| string.cpp:484:17:484:18 | s5 | string.cpp:484:20:484:25 | call to cbegin | TAINT |
| string.cpp:484:20:484:25 | call to cbegin | string.cpp:484:8:484:8 | ref arg g | TAINT |
| string.cpp:484:20:484:25 | call to cbegin | string.cpp:484:10:484:15 | call to assign | TAINT |
| string.cpp:484:30:484:31 | s5 | string.cpp:484:33:484:36 | call to cend | TAINT |
| string.cpp:484:33:484:36 | call to cend | string.cpp:484:8:484:8 | ref arg g | TAINT |
| string.cpp:484:33:484:36 | call to cend | string.cpp:484:10:484:15 | call to assign | TAINT |
| string.cpp:487:8:487:8 | ref arg h | string.cpp:488:8:488:8 | h | |
| string.cpp:487:17:487:18 | s6 | string.cpp:487:20:487:25 | call to cbegin | TAINT |
| string.cpp:487:20:487:25 | call to cbegin | string.cpp:487:8:487:8 | ref arg h | TAINT |
| string.cpp:487:20:487:25 | call to cbegin | string.cpp:487:10:487:15 | call to assign | TAINT |
| string.cpp:487:30:487:31 | s6 | string.cpp:487:33:487:36 | call to cend | TAINT |
| string.cpp:487:33:487:36 | call to cend | string.cpp:487:8:487:8 | ref arg h | TAINT |
| string.cpp:487:33:487:36 | call to cend | string.cpp:487:10:487:15 | call to assign | TAINT |
| string.cpp:490:8:490:9 | ref arg s6 | string.cpp:491:8:491:9 | s6 | |
| string.cpp:490:18:490:19 | s5 | string.cpp:490:21:490:26 | call to cbegin | TAINT |
| string.cpp:490:21:490:26 | call to cbegin | string.cpp:490:8:490:9 | ref arg s6 | TAINT |
| string.cpp:490:21:490:26 | call to cbegin | string.cpp:490:11:490:16 | call to assign | TAINT |
| string.cpp:490:31:490:32 | s5 | string.cpp:490:34:490:37 | call to cend | TAINT |
| string.cpp:490:34:490:37 | call to cend | string.cpp:490:8:490:9 | ref arg s6 | TAINT |
| string.cpp:490:34:490:37 | call to cend | string.cpp:490:11:490:16 | call to assign | TAINT |
| string.cpp:496:14:496:18 | abc | string.cpp:498:17:498:19 | cs1 | |
| string.cpp:497:14:497:19 | call to source | string.cpp:499:17:499:19 | cs2 | |
| string.cpp:498:17:498:19 | cs1 | string.cpp:498:17:498:20 | call to basic_string | TAINT |
| string.cpp:498:17:498:20 | call to basic_string | string.cpp:500:17:500:18 | s1 | |
| string.cpp:498:17:498:20 | call to basic_string | string.cpp:500:29:500:30 | s1 | |
| string.cpp:498:17:498:20 | call to basic_string | string.cpp:503:7:503:8 | s1 | |
| string.cpp:499:17:499:19 | cs2 | string.cpp:499:17:499:20 | call to basic_string | TAINT |
| string.cpp:499:17:499:20 | call to basic_string | string.cpp:501:17:501:18 | s2 | |
| string.cpp:499:17:499:20 | call to basic_string | string.cpp:501:29:501:30 | s2 | |
| string.cpp:499:17:499:20 | call to basic_string | string.cpp:504:7:504:8 | s2 | |
| string.cpp:500:17:500:18 | ref arg s1 | string.cpp:500:29:500:30 | s1 | |
| string.cpp:500:17:500:18 | ref arg s1 | string.cpp:503:7:503:8 | s1 | |
| string.cpp:500:17:500:18 | s1 | string.cpp:500:20:500:24 | call to begin | TAINT |
| string.cpp:500:17:500:37 | call to basic_string | string.cpp:505:7:505:8 | s3 | |
| string.cpp:500:20:500:24 | call to begin | string.cpp:500:17:500:37 | call to basic_string | TAINT |
| string.cpp:500:29:500:30 | ref arg s1 | string.cpp:503:7:503:8 | s1 | |
| string.cpp:500:29:500:30 | s1 | string.cpp:500:32:500:34 | call to end | TAINT |
| string.cpp:500:32:500:34 | call to end | string.cpp:500:17:500:37 | call to basic_string | TAINT |
| string.cpp:501:17:501:18 | ref arg s2 | string.cpp:501:29:501:30 | s2 | |
| string.cpp:501:17:501:18 | ref arg s2 | string.cpp:504:7:504:8 | s2 | |
| string.cpp:501:17:501:18 | s2 | string.cpp:501:20:501:24 | call to begin | TAINT |
| string.cpp:501:17:501:37 | call to basic_string | string.cpp:506:7:506:8 | s4 | |
| string.cpp:501:20:501:24 | call to begin | string.cpp:501:17:501:37 | call to basic_string | TAINT |
| string.cpp:501:29:501:30 | ref arg s2 | string.cpp:504:7:504:8 | s2 | |
| string.cpp:501:29:501:30 | s2 | string.cpp:501:32:501:34 | call to end | TAINT |
| string.cpp:501:32:501:34 | call to end | string.cpp:501:17:501:37 | call to basic_string | TAINT |
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:16:2:16:4 | ss1 | |
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:22:7:22:9 | ss1 | |
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:27:7:27:9 | ss1 | |
@@ -1874,6 +2100,9 @@
| vector.cpp:17:26:17:32 | source1 | vector.cpp:17:21:17:33 | call to vector | TAINT |
| vector.cpp:19:14:19:14 | (__begin) | vector.cpp:19:14:19:14 | call to operator* | TAINT |
| vector.cpp:19:14:19:14 | (__begin) | vector.cpp:19:14:19:14 | call to operator++ | TAINT |
| vector.cpp:19:14:19:14 | (__end) | vector.cpp:19:14:19:14 | call to iterator | |
| vector.cpp:19:14:19:14 | (__range) | vector.cpp:19:14:19:14 | call to begin | TAINT |
| vector.cpp:19:14:19:14 | (__range) | vector.cpp:19:14:19:14 | call to end | TAINT |
| vector.cpp:19:14:19:14 | call to begin | vector.cpp:19:14:19:14 | (__begin) | |
| vector.cpp:19:14:19:14 | call to begin | vector.cpp:19:14:19:14 | (__begin) | |
| vector.cpp:19:14:19:14 | call to begin | vector.cpp:19:14:19:14 | (__begin) | |
@@ -1889,12 +2118,14 @@
| vector.cpp:23:38:23:38 | ref arg v | vector.cpp:23:55:23:55 | v | |
| vector.cpp:23:38:23:38 | ref arg v | vector.cpp:27:15:27:15 | v | |
| vector.cpp:23:38:23:38 | ref arg v | vector.cpp:35:1:35:1 | v | |
| vector.cpp:23:38:23:38 | v | vector.cpp:23:40:23:44 | call to begin | TAINT |
| vector.cpp:23:40:23:44 | call to begin | vector.cpp:23:49:23:50 | it | |
| vector.cpp:23:40:23:44 | call to begin | vector.cpp:23:66:23:67 | it | |
| vector.cpp:23:40:23:44 | call to begin | vector.cpp:24:9:24:10 | it | |
| vector.cpp:23:55:23:55 | ref arg v | vector.cpp:23:55:23:55 | v | |
| vector.cpp:23:55:23:55 | ref arg v | vector.cpp:27:15:27:15 | v | |
| vector.cpp:23:55:23:55 | ref arg v | vector.cpp:35:1:35:1 | v | |
| vector.cpp:23:55:23:55 | v | vector.cpp:23:57:23:59 | call to end | TAINT |
| vector.cpp:23:66:23:67 | it | vector.cpp:23:64:23:64 | call to operator++ | TAINT |
| vector.cpp:23:66:23:67 | ref arg it | vector.cpp:23:49:23:50 | it | |
| vector.cpp:23:66:23:67 | ref arg it | vector.cpp:23:66:23:67 | it | |
@@ -1902,6 +2133,9 @@
| vector.cpp:24:9:24:10 | it | vector.cpp:24:8:24:8 | call to operator* | TAINT |
| vector.cpp:27:15:27:15 | (__begin) | vector.cpp:27:15:27:15 | call to operator* | TAINT |
| vector.cpp:27:15:27:15 | (__begin) | vector.cpp:27:15:27:15 | call to operator++ | TAINT |
| vector.cpp:27:15:27:15 | (__end) | vector.cpp:27:15:27:15 | call to iterator | |
| vector.cpp:27:15:27:15 | (__range) | vector.cpp:27:15:27:15 | call to begin | TAINT |
| vector.cpp:27:15:27:15 | (__range) | vector.cpp:27:15:27:15 | call to end | TAINT |
| vector.cpp:27:15:27:15 | call to begin | vector.cpp:27:15:27:15 | (__begin) | |
| vector.cpp:27:15:27:15 | call to begin | vector.cpp:27:15:27:15 | (__begin) | |
| vector.cpp:27:15:27:15 | call to begin | vector.cpp:27:15:27:15 | (__begin) | |
@@ -1919,6 +2153,8 @@
| vector.cpp:31:38:31:44 | source1 | vector.cpp:31:33:31:45 | call to vector | TAINT |
| vector.cpp:32:21:32:21 | (__begin) | vector.cpp:32:21:32:21 | call to operator* | TAINT |
| vector.cpp:32:21:32:21 | (__begin) | vector.cpp:32:21:32:21 | call to operator++ | TAINT |
| vector.cpp:32:21:32:21 | (__range) | vector.cpp:32:21:32:21 | call to begin | TAINT |
| vector.cpp:32:21:32:21 | (__range) | vector.cpp:32:21:32:21 | call to end | TAINT |
| vector.cpp:32:21:32:21 | call to begin | vector.cpp:32:21:32:21 | (__begin) | |
| vector.cpp:32:21:32:21 | call to begin | vector.cpp:32:21:32:21 | (__begin) | |
| vector.cpp:32:21:32:21 | call to begin | vector.cpp:32:21:32:21 | (__begin) | |
@@ -1977,7 +2213,7 @@
| vector.cpp:38:62:38:64 | call to vector | vector.cpp:75:7:75:8 | v6 | |
| vector.cpp:38:62:38:64 | call to vector | vector.cpp:76:7:76:8 | v6 | |
| vector.cpp:38:62:38:64 | call to vector | vector.cpp:101:1:101:1 | v6 | |
| vector.cpp:38:70:38:72 | call to vector | vector.cpp:79:33:79:34 | v7 | |
| vector.cpp:38:70:38:72 | call to vector | vector.cpp:80:41:80:42 | v7 | |
| vector.cpp:38:70:38:72 | call to vector | vector.cpp:81:3:81:4 | v7 | |
| vector.cpp:38:70:38:72 | call to vector | vector.cpp:83:7:83:8 | v7 | |
| vector.cpp:38:70:38:72 | call to vector | vector.cpp:84:7:84:8 | v7 | |
@@ -2166,12 +2402,21 @@
| vector.cpp:76:7:76:8 | v6 | vector.cpp:76:10:76:13 | call to data | TAINT |
| vector.cpp:76:10:76:13 | call to data | vector.cpp:76:7:76:18 | access to array | TAINT |
| vector.cpp:76:17:76:17 | 2 | vector.cpp:76:7:76:18 | access to array | TAINT |
| vector.cpp:79:33:79:34 | v7 | vector.cpp:80:41:80:43 | v7c | |
| vector.cpp:80:45:80:49 | call to begin | vector.cpp:81:13:81:14 | it | |
| vector.cpp:80:40:80:50 | call to iterator | vector.cpp:81:13:81:14 | it | |
| vector.cpp:80:41:80:42 | ref arg v7 | vector.cpp:81:3:81:4 | v7 | |
| vector.cpp:80:41:80:42 | ref arg v7 | vector.cpp:83:7:83:8 | v7 | |
| vector.cpp:80:41:80:42 | ref arg v7 | vector.cpp:84:7:84:8 | v7 | |
| vector.cpp:80:41:80:42 | ref arg v7 | vector.cpp:85:7:85:8 | v7 | |
| vector.cpp:80:41:80:42 | ref arg v7 | vector.cpp:101:1:101:1 | v7 | |
| vector.cpp:80:41:80:42 | v7 | vector.cpp:80:44:80:48 | call to begin | TAINT |
| vector.cpp:80:44:80:48 | call to begin | vector.cpp:80:40:80:50 | call to iterator | TAINT |
| vector.cpp:81:3:81:4 | ref arg v7 | vector.cpp:83:7:83:8 | v7 | |
| vector.cpp:81:3:81:4 | ref arg v7 | vector.cpp:84:7:84:8 | v7 | |
| vector.cpp:81:3:81:4 | ref arg v7 | vector.cpp:85:7:85:8 | v7 | |
| vector.cpp:81:3:81:4 | ref arg v7 | vector.cpp:101:1:101:1 | v7 | |
| vector.cpp:81:3:81:4 | v7 | vector.cpp:81:6:81:11 | call to insert | TAINT |
| vector.cpp:81:17:81:22 | call to source | vector.cpp:81:3:81:4 | ref arg v7 | TAINT |
| vector.cpp:81:17:81:22 | call to source | vector.cpp:81:6:81:11 | call to insert | TAINT |
| vector.cpp:83:7:83:8 | ref arg v7 | vector.cpp:84:7:84:8 | v7 | |
| vector.cpp:83:7:83:8 | ref arg v7 | vector.cpp:85:7:85:8 | v7 | |
| vector.cpp:83:7:83:8 | ref arg v7 | vector.cpp:101:1:101:1 | v7 | |
@@ -2181,11 +2426,13 @@
| vector.cpp:85:7:85:8 | ref arg v7 | vector.cpp:101:1:101:1 | v7 | |
| vector.cpp:85:7:85:8 | v7 | vector.cpp:85:10:85:13 | call to back | TAINT |
| vector.cpp:88:33:88:34 | v8 | vector.cpp:89:41:89:43 | v8c | |
| vector.cpp:89:41:89:43 | v8c | vector.cpp:89:45:89:49 | call to begin | TAINT |
| vector.cpp:89:45:89:49 | call to begin | vector.cpp:90:13:90:14 | it | |
| vector.cpp:90:3:90:4 | ref arg v8 | vector.cpp:92:7:92:8 | v8 | |
| vector.cpp:90:3:90:4 | ref arg v8 | vector.cpp:93:7:93:8 | v8 | |
| vector.cpp:90:3:90:4 | ref arg v8 | vector.cpp:94:7:94:8 | v8 | |
| vector.cpp:90:3:90:4 | ref arg v8 | vector.cpp:101:1:101:1 | v8 | |
| vector.cpp:90:3:90:4 | v8 | vector.cpp:90:6:90:11 | call to insert | TAINT |
| vector.cpp:92:7:92:8 | ref arg v8 | vector.cpp:93:7:93:8 | v8 | |
| vector.cpp:92:7:92:8 | ref arg v8 | vector.cpp:94:7:94:8 | v8 | |
| vector.cpp:92:7:92:8 | ref arg v8 | vector.cpp:101:1:101:1 | v8 | |
@@ -2563,15 +2810,24 @@
| vector.cpp:249:3:249:4 | ref arg v4 | vector.cpp:262:2:262:2 | v4 | |
| vector.cpp:249:13:249:14 | ref arg v1 | vector.cpp:249:25:249:26 | v1 | |
| vector.cpp:249:13:249:14 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | |
| vector.cpp:249:13:249:14 | v1 | vector.cpp:249:16:249:20 | call to begin | TAINT |
| vector.cpp:249:16:249:20 | call to begin | vector.cpp:249:3:249:4 | ref arg v4 | TAINT |
| vector.cpp:249:25:249:26 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | |
| vector.cpp:249:25:249:26 | v1 | vector.cpp:249:28:249:30 | call to end | TAINT |
| vector.cpp:249:28:249:30 | call to end | vector.cpp:249:3:249:4 | ref arg v4 | TAINT |
| vector.cpp:250:3:250:4 | ref arg v5 | vector.cpp:258:8:258:9 | v5 | |
| vector.cpp:250:3:250:4 | ref arg v5 | vector.cpp:262:2:262:2 | v5 | |
| vector.cpp:250:13:250:14 | ref arg v3 | vector.cpp:250:25:250:26 | v3 | |
| vector.cpp:250:13:250:14 | ref arg v3 | vector.cpp:251:8:251:9 | v3 | |
| vector.cpp:250:13:250:14 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | |
| vector.cpp:250:13:250:14 | v3 | vector.cpp:250:16:250:20 | call to begin | TAINT |
| vector.cpp:250:16:250:20 | call to begin | vector.cpp:250:3:250:4 | ref arg v5 | TAINT |
| vector.cpp:250:25:250:26 | ref arg v3 | vector.cpp:251:8:251:9 | v3 | |
| vector.cpp:250:25:250:26 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | |
| vector.cpp:250:25:250:26 | v3 | vector.cpp:250:28:250:30 | call to end | TAINT |
| vector.cpp:250:28:250:30 | call to end | vector.cpp:250:3:250:4 | ref arg v5 | TAINT |
| vector.cpp:251:8:251:9 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | |
| vector.cpp:251:8:251:9 | v3 | vector.cpp:251:11:251:15 | call to begin | TAINT |
| vector.cpp:251:11:251:15 | call to begin | vector.cpp:251:3:251:17 | ... = ... | |
| vector.cpp:251:11:251:15 | call to begin | vector.cpp:252:3:252:4 | i1 | |
| vector.cpp:251:11:251:15 | call to begin | vector.cpp:253:8:253:9 | i1 | |
@@ -2590,6 +2846,10 @@
| vector.cpp:254:3:254:4 | ref arg i2 | vector.cpp:260:8:260:9 | i2 | |
| vector.cpp:255:3:255:4 | ref arg v6 | vector.cpp:261:8:261:9 | v6 | |
| vector.cpp:255:3:255:4 | ref arg v6 | vector.cpp:262:2:262:2 | v6 | |
| vector.cpp:255:13:255:14 | call to iterator | vector.cpp:255:3:255:4 | ref arg v6 | TAINT |
| vector.cpp:255:13:255:14 | i1 | vector.cpp:255:13:255:14 | call to iterator | |
| vector.cpp:255:17:255:18 | call to iterator | vector.cpp:255:3:255:4 | ref arg v6 | TAINT |
| vector.cpp:255:17:255:18 | i2 | vector.cpp:255:17:255:18 | call to iterator | |
| vector.cpp:257:8:257:9 | ref arg v4 | vector.cpp:262:2:262:2 | v4 | |
| vector.cpp:258:8:258:9 | ref arg v5 | vector.cpp:262:2:262:2 | v5 | |
| vector.cpp:261:8:261:9 | ref arg v6 | vector.cpp:262:2:262:2 | v6 | |
@@ -2661,3 +2921,136 @@
| vector.cpp:292:7:292:8 | v2 | vector.cpp:292:10:292:13 | call to data | TAINT |
| vector.cpp:292:10:292:13 | call to data | vector.cpp:292:7:292:18 | access to array | TAINT |
| vector.cpp:292:17:292:17 | 2 | vector.cpp:292:7:292:18 | access to array | TAINT |
| vector.cpp:298:19:298:19 | call to vector | vector.cpp:305:7:305:7 | a | |
| vector.cpp:298:19:298:19 | call to vector | vector.cpp:305:16:305:16 | a | |
| vector.cpp:298:19:298:19 | call to vector | vector.cpp:306:7:306:7 | a | |
| vector.cpp:298:19:298:19 | call to vector | vector.cpp:311:25:311:25 | a | |
| vector.cpp:298:19:298:19 | call to vector | vector.cpp:311:36:311:36 | a | |
| vector.cpp:298:19:298:19 | call to vector | vector.cpp:313:1:313:1 | a | |
| vector.cpp:299:19:299:19 | call to vector | vector.cpp:305:25:305:25 | b | |
| vector.cpp:299:19:299:19 | call to vector | vector.cpp:305:36:305:36 | b | |
| vector.cpp:299:19:299:19 | call to vector | vector.cpp:313:1:313:1 | b | |
| vector.cpp:300:19:300:19 | call to vector | vector.cpp:308:7:308:7 | c | |
| vector.cpp:300:19:300:19 | call to vector | vector.cpp:308:16:308:16 | c | |
| vector.cpp:300:19:300:19 | call to vector | vector.cpp:309:7:309:7 | c | |
| vector.cpp:300:19:300:19 | call to vector | vector.cpp:313:1:313:1 | c | |
| vector.cpp:301:19:301:19 | call to vector | vector.cpp:303:2:303:2 | d | |
| vector.cpp:301:19:301:19 | call to vector | vector.cpp:308:25:308:25 | d | |
| vector.cpp:301:19:301:19 | call to vector | vector.cpp:308:36:308:36 | d | |
| vector.cpp:301:19:301:19 | call to vector | vector.cpp:311:7:311:7 | d | |
| vector.cpp:301:19:301:19 | call to vector | vector.cpp:311:16:311:16 | d | |
| vector.cpp:301:19:301:19 | call to vector | vector.cpp:312:7:312:7 | d | |
| vector.cpp:301:19:301:19 | call to vector | vector.cpp:313:1:313:1 | d | |
| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:308:25:308:25 | d | |
| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:308:36:308:36 | d | |
| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:311:7:311:7 | d | |
| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:311:16:311:16 | d | |
| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:312:7:312:7 | d | |
| vector.cpp:303:2:303:2 | ref arg d | vector.cpp:313:1:313:1 | d | |
| vector.cpp:303:14:303:19 | call to source | vector.cpp:303:2:303:2 | ref arg d | TAINT |
| vector.cpp:305:7:305:7 | a | vector.cpp:305:9:305:14 | call to insert | TAINT |
| vector.cpp:305:7:305:7 | ref arg a | vector.cpp:306:7:306:7 | a | |
| vector.cpp:305:7:305:7 | ref arg a | vector.cpp:311:25:311:25 | a | |
| vector.cpp:305:7:305:7 | ref arg a | vector.cpp:311:36:311:36 | a | |
| vector.cpp:305:7:305:7 | ref arg a | vector.cpp:313:1:313:1 | a | |
| vector.cpp:305:16:305:16 | a | vector.cpp:305:18:305:20 | call to end | TAINT |
| vector.cpp:305:16:305:16 | ref arg a | vector.cpp:305:7:305:7 | a | |
| vector.cpp:305:16:305:16 | ref arg a | vector.cpp:306:7:306:7 | a | |
| vector.cpp:305:16:305:16 | ref arg a | vector.cpp:311:25:311:25 | a | |
| vector.cpp:305:16:305:16 | ref arg a | vector.cpp:311:36:311:36 | a | |
| vector.cpp:305:16:305:16 | ref arg a | vector.cpp:313:1:313:1 | a | |
| vector.cpp:305:18:305:20 | call to end | vector.cpp:305:16:305:22 | call to iterator | TAINT |
| vector.cpp:305:25:305:25 | b | vector.cpp:305:27:305:31 | call to begin | TAINT |
| vector.cpp:305:25:305:25 | ref arg b | vector.cpp:305:36:305:36 | b | |
| vector.cpp:305:25:305:25 | ref arg b | vector.cpp:313:1:313:1 | b | |
| vector.cpp:305:27:305:31 | call to begin | vector.cpp:305:7:305:7 | ref arg a | TAINT |
| vector.cpp:305:27:305:31 | call to begin | vector.cpp:305:9:305:14 | call to insert | TAINT |
| vector.cpp:305:36:305:36 | b | vector.cpp:305:38:305:40 | call to end | TAINT |
| vector.cpp:305:36:305:36 | ref arg b | vector.cpp:313:1:313:1 | b | |
| vector.cpp:305:38:305:40 | call to end | vector.cpp:305:7:305:7 | ref arg a | TAINT |
| vector.cpp:305:38:305:40 | call to end | vector.cpp:305:9:305:14 | call to insert | TAINT |
| vector.cpp:306:7:306:7 | ref arg a | vector.cpp:311:25:311:25 | a | |
| vector.cpp:306:7:306:7 | ref arg a | vector.cpp:311:36:311:36 | a | |
| vector.cpp:306:7:306:7 | ref arg a | vector.cpp:313:1:313:1 | a | |
| vector.cpp:308:7:308:7 | c | vector.cpp:308:9:308:14 | call to insert | TAINT |
| vector.cpp:308:7:308:7 | ref arg c | vector.cpp:309:7:309:7 | c | |
| vector.cpp:308:7:308:7 | ref arg c | vector.cpp:313:1:313:1 | c | |
| vector.cpp:308:16:308:16 | c | vector.cpp:308:18:308:20 | call to end | TAINT |
| vector.cpp:308:16:308:16 | ref arg c | vector.cpp:308:7:308:7 | c | |
| vector.cpp:308:16:308:16 | ref arg c | vector.cpp:309:7:309:7 | c | |
| vector.cpp:308:16:308:16 | ref arg c | vector.cpp:313:1:313:1 | c | |
| vector.cpp:308:18:308:20 | call to end | vector.cpp:308:16:308:22 | call to iterator | TAINT |
| vector.cpp:308:25:308:25 | d | vector.cpp:308:27:308:31 | call to begin | TAINT |
| vector.cpp:308:25:308:25 | ref arg d | vector.cpp:308:36:308:36 | d | |
| vector.cpp:308:25:308:25 | ref arg d | vector.cpp:311:7:311:7 | d | |
| vector.cpp:308:25:308:25 | ref arg d | vector.cpp:311:16:311:16 | d | |
| vector.cpp:308:25:308:25 | ref arg d | vector.cpp:312:7:312:7 | d | |
| vector.cpp:308:25:308:25 | ref arg d | vector.cpp:313:1:313:1 | d | |
| vector.cpp:308:27:308:31 | call to begin | vector.cpp:308:7:308:7 | ref arg c | TAINT |
| vector.cpp:308:27:308:31 | call to begin | vector.cpp:308:9:308:14 | call to insert | TAINT |
| vector.cpp:308:36:308:36 | d | vector.cpp:308:38:308:40 | call to end | TAINT |
| vector.cpp:308:36:308:36 | ref arg d | vector.cpp:311:7:311:7 | d | |
| vector.cpp:308:36:308:36 | ref arg d | vector.cpp:311:16:311:16 | d | |
| vector.cpp:308:36:308:36 | ref arg d | vector.cpp:312:7:312:7 | d | |
| vector.cpp:308:36:308:36 | ref arg d | vector.cpp:313:1:313:1 | d | |
| vector.cpp:308:38:308:40 | call to end | vector.cpp:308:7:308:7 | ref arg c | TAINT |
| vector.cpp:308:38:308:40 | call to end | vector.cpp:308:9:308:14 | call to insert | TAINT |
| vector.cpp:309:7:309:7 | ref arg c | vector.cpp:313:1:313:1 | c | |
| vector.cpp:311:7:311:7 | d | vector.cpp:311:9:311:14 | call to insert | TAINT |
| vector.cpp:311:7:311:7 | ref arg d | vector.cpp:312:7:312:7 | d | |
| vector.cpp:311:7:311:7 | ref arg d | vector.cpp:313:1:313:1 | d | |
| vector.cpp:311:16:311:16 | d | vector.cpp:311:18:311:20 | call to end | TAINT |
| vector.cpp:311:16:311:16 | ref arg d | vector.cpp:311:7:311:7 | d | |
| vector.cpp:311:16:311:16 | ref arg d | vector.cpp:312:7:312:7 | d | |
| vector.cpp:311:16:311:16 | ref arg d | vector.cpp:313:1:313:1 | d | |
| vector.cpp:311:18:311:20 | call to end | vector.cpp:311:16:311:22 | call to iterator | TAINT |
| vector.cpp:311:25:311:25 | a | vector.cpp:311:27:311:31 | call to begin | TAINT |
| vector.cpp:311:25:311:25 | ref arg a | vector.cpp:311:36:311:36 | a | |
| vector.cpp:311:25:311:25 | ref arg a | vector.cpp:313:1:313:1 | a | |
| vector.cpp:311:27:311:31 | call to begin | vector.cpp:311:7:311:7 | ref arg d | TAINT |
| vector.cpp:311:27:311:31 | call to begin | vector.cpp:311:9:311:14 | call to insert | TAINT |
| vector.cpp:311:36:311:36 | a | vector.cpp:311:38:311:40 | call to end | TAINT |
| vector.cpp:311:36:311:36 | ref arg a | vector.cpp:313:1:313:1 | a | |
| vector.cpp:311:38:311:40 | call to end | vector.cpp:311:7:311:7 | ref arg d | TAINT |
| vector.cpp:311:38:311:40 | call to end | vector.cpp:311:9:311:14 | call to insert | TAINT |
| vector.cpp:312:7:312:7 | ref arg d | vector.cpp:313:1:313:1 | d | |
| vector.cpp:316:19:316:20 | call to vector | vector.cpp:320:22:320:23 | v1 | |
| vector.cpp:316:19:316:20 | call to vector | vector.cpp:320:34:320:35 | v1 | |
| vector.cpp:316:19:316:20 | call to vector | vector.cpp:323:7:323:8 | v1 | |
| vector.cpp:316:19:316:20 | call to vector | vector.cpp:327:1:327:1 | v1 | |
| vector.cpp:317:19:317:20 | call to vector | vector.cpp:318:2:318:3 | v2 | |
| vector.cpp:317:19:317:20 | call to vector | vector.cpp:321:22:321:23 | v2 | |
| vector.cpp:317:19:317:20 | call to vector | vector.cpp:321:34:321:35 | v2 | |
| vector.cpp:317:19:317:20 | call to vector | vector.cpp:324:7:324:8 | v2 | |
| vector.cpp:317:19:317:20 | call to vector | vector.cpp:327:1:327:1 | v2 | |
| vector.cpp:318:2:318:3 | ref arg v2 | vector.cpp:321:22:321:23 | v2 | |
| vector.cpp:318:2:318:3 | ref arg v2 | vector.cpp:321:34:321:35 | v2 | |
| vector.cpp:318:2:318:3 | ref arg v2 | vector.cpp:324:7:324:8 | v2 | |
| vector.cpp:318:2:318:3 | ref arg v2 | vector.cpp:327:1:327:1 | v2 | |
| vector.cpp:318:15:318:20 | call to source | vector.cpp:318:2:318:3 | ref arg v2 | TAINT |
| vector.cpp:320:22:320:23 | ref arg v1 | vector.cpp:320:34:320:35 | v1 | |
| vector.cpp:320:22:320:23 | ref arg v1 | vector.cpp:323:7:323:8 | v1 | |
| vector.cpp:320:22:320:23 | ref arg v1 | vector.cpp:327:1:327:1 | v1 | |
| vector.cpp:320:22:320:23 | v1 | vector.cpp:320:25:320:29 | call to begin | TAINT |
| vector.cpp:320:22:320:42 | call to vector | vector.cpp:325:7:325:8 | v3 | |
| vector.cpp:320:22:320:42 | call to vector | vector.cpp:327:1:327:1 | v3 | |
| vector.cpp:320:25:320:29 | call to begin | vector.cpp:320:22:320:42 | call to vector | TAINT |
| vector.cpp:320:34:320:35 | ref arg v1 | vector.cpp:323:7:323:8 | v1 | |
| vector.cpp:320:34:320:35 | ref arg v1 | vector.cpp:327:1:327:1 | v1 | |
| vector.cpp:320:34:320:35 | v1 | vector.cpp:320:37:320:39 | call to end | TAINT |
| vector.cpp:320:37:320:39 | call to end | vector.cpp:320:22:320:42 | call to vector | TAINT |
| vector.cpp:321:22:321:23 | ref arg v2 | vector.cpp:321:34:321:35 | v2 | |
| vector.cpp:321:22:321:23 | ref arg v2 | vector.cpp:324:7:324:8 | v2 | |
| vector.cpp:321:22:321:23 | ref arg v2 | vector.cpp:327:1:327:1 | v2 | |
| vector.cpp:321:22:321:23 | v2 | vector.cpp:321:25:321:29 | call to begin | TAINT |
| vector.cpp:321:22:321:42 | call to vector | vector.cpp:326:7:326:8 | v4 | |
| vector.cpp:321:22:321:42 | call to vector | vector.cpp:327:1:327:1 | v4 | |
| vector.cpp:321:25:321:29 | call to begin | vector.cpp:321:22:321:42 | call to vector | TAINT |
| vector.cpp:321:34:321:35 | ref arg v2 | vector.cpp:324:7:324:8 | v2 | |
| vector.cpp:321:34:321:35 | ref arg v2 | vector.cpp:327:1:327:1 | v2 | |
| vector.cpp:321:34:321:35 | v2 | vector.cpp:321:37:321:39 | call to end | TAINT |
| vector.cpp:321:37:321:39 | call to end | vector.cpp:321:22:321:42 | call to vector | TAINT |
| vector.cpp:323:7:323:8 | ref arg v1 | vector.cpp:327:1:327:1 | v1 | |
| vector.cpp:324:7:324:8 | ref arg v2 | vector.cpp:327:1:327:1 | v2 | |
| vector.cpp:325:7:325:8 | ref arg v3 | vector.cpp:327:1:327:1 | v3 | |
| vector.cpp:326:7:326:8 | ref arg v4 | vector.cpp:327:1:327:1 | v4 | |

View File

@@ -1,6 +1,16 @@
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 {
@@ -16,6 +26,9 @@ namespace std {
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--();
@@ -45,13 +58,12 @@ namespace std
typedef size_t streamsize;
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:
@@ -63,6 +75,7 @@ namespace std
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;
@@ -87,12 +100,15 @@ namespace std
basic_string& append(const basic_string& str);
basic_string& append(const charT* s);
basic_string& append(size_type n, charT c);
template<class InputIterator>
/* constexpr */ basic_string& append(InputIterator first, InputIterator last);
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;
@@ -156,7 +172,10 @@ 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);
@@ -191,6 +210,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)*/;

View File

@@ -413,3 +413,95 @@ void test_string_iterators() {
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
}

View File

@@ -121,6 +121,23 @@
| 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 |
| 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 |
@@ -228,6 +245,7 @@
| 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 |
@@ -247,6 +265,9 @@
| 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 |
@@ -268,6 +289,10 @@
| 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 |
@@ -277,3 +302,9 @@
| 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 |

View File

@@ -121,6 +121,23 @@
| 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 |
| swap1.cpp:78:12:78:16 | swap1.cpp:69:23:69:23 | AST only |
| swap1.cpp:87:13:87:17 | swap1.cpp:82:16:82:21 | AST only |
| swap1.cpp:88:13:88:17 | swap1.cpp:81:27:81:28 | AST only |
@@ -162,6 +179,7 @@
| 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 |
@@ -181,6 +199,9 @@
| 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 |
@@ -203,6 +224,10 @@
| 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 |
@@ -212,3 +237,9 @@
| 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 |

View File

@@ -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) {
@@ -75,14 +75,14 @@ void test_element_taint(int x) {
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;
@@ -255,10 +255,10 @@ void test_vector_assign() {
v6.assign(i1, i2);
sink(v4);
sink(v5); // tainted [NOT DETECTED]
sink(i1); // tainted [NOT DETECTED]
sink(i2); // tainted [NOT DETECTED]
sink(v6); // tainted [NOT DETECTED]
sink(v5); // tainted
sink(i1); // tainted
sink(i2); // tainted
sink(v6); // tainted
}
{
@@ -291,3 +291,37 @@ void test_data_more() {
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
}

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Remove the old CFG tables
compatibility: full

View File

@@ -345,6 +345,7 @@ namespace Semmle.Autobuild.CSharp.Tests
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = "";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
Actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = isWindows ? "win64" : "linux64";
Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";
Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java";
Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools";
@@ -497,7 +498,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap
[Fact]
public void TestLinuxBuildlessExtractionSuccess()
{
Actions.RunProcess[@"C:\odasa\tools/csharp/Semmle.Extraction.CSharp.Standalone --references:."] = 0;
Actions.RunProcess[@"C:\codeql\csharp/tools/linux64/Semmle.Extraction.CSharp.Standalone --references:."] = 0;
Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0;
Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0;
Actions.FileExists["csharp.log"] = true;
@@ -513,7 +514,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap
[Fact]
public void TestLinuxBuildlessExtractionFailed()
{
Actions.RunProcess[@"C:\odasa\tools/csharp/Semmle.Extraction.CSharp.Standalone --references:."] = 10;
Actions.RunProcess[@"C:\codeql\csharp/tools/linux64/Semmle.Extraction.CSharp.Standalone --references:."] = 10;
Actions.FileExists["csharp.log"] = true;
Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = "";
Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = "";
@@ -527,7 +528,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap
[Fact]
public void TestLinuxBuildlessExtractionSolution()
{
Actions.RunProcess[@"C:\odasa\tools/csharp/Semmle.Extraction.CSharp.Standalone foo.sln --references:."] = 0;
Actions.RunProcess[@"C:\codeql\csharp/tools/linux64/Semmle.Extraction.CSharp.Standalone foo.sln --references:."] = 0;
Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0;
Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0;
Actions.FileExists["csharp.log"] = true;
@@ -835,7 +836,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap
[Fact]
public void TestSkipNugetBuildless()
{
Actions.RunProcess[@"C:\odasa\tools/csharp/Semmle.Extraction.CSharp.Standalone foo.sln --references:. --skip-nuget"] = 0;
Actions.RunProcess[@"C:\codeql\csharp/tools/linux64/Semmle.Extraction.CSharp.Standalone foo.sln --references:. --skip-nuget"] = 0;
Actions.RunProcess[@"C:\codeql\tools\java/bin/java -jar C:\codeql\csharp/tools/extractor-asp.jar ."] = 0;
Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0;
Actions.FileExists["csharp.log"] = true;

View File

@@ -11,10 +11,15 @@ namespace Semmle.Autobuild.CSharp
{
BuildScript GetCommand(string? solution)
{
if (builder.SemmlePlatformTools is null)
string standalone;
if (builder.CodeQLExtractorLangRoot is object && builder.CodeQlPlatform is object) {
standalone = builder.Actions.PathCombine(builder.CodeQLExtractorLangRoot, "tools", builder.CodeQlPlatform, "Semmle.Extraction.CSharp.Standalone");
} else if (builder.SemmlePlatformTools is object) {
standalone = builder.Actions.PathCombine(builder.SemmlePlatformTools, "csharp", "Semmle.Extraction.CSharp.Standalone");
} else {
return BuildScript.Failure;
}
var standalone = builder.Actions.PathCombine(builder.SemmlePlatformTools, "csharp", "Semmle.Extraction.CSharp.Standalone");
var cmd = new CommandBuilder(builder.Actions);
cmd.RunCommand(standalone);

View File

@@ -193,6 +193,8 @@ namespace Semmle.Autobuild.Shared
SemmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST");
SemmlePlatformTools = Actions.GetEnvironmentVariable("SEMMLE_PLATFORM_TOOLS");
CodeQlPlatform = Actions.GetEnvironmentVariable("CODEQL_PLATFORM");
JavaHome =
Actions.GetEnvironmentVariable("CODEQL_JAVA_HOME") ??
Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME") ??
@@ -271,7 +273,7 @@ namespace Semmle.Autobuild.Shared
/// <summary>
/// Value of CODEQL_EXTRACTOR_<LANG>_ROOT environment variable.
/// </summary>
private string? CodeQLExtractorLangRoot { get; }
public string? CodeQLExtractorLangRoot { get; }
/// <summary>
/// Value of SEMMLE_DIST environment variable.
@@ -287,6 +289,11 @@ namespace Semmle.Autobuild.Shared
/// </summary>
public string? SemmlePlatformTools { get; }
/// <summary>
/// Value of CODEQL_PLATFORM environment variable.
/// </summary>
public string? CodeQlPlatform { get; }
/// <summary>
/// The absolute path of the odasa executable.
/// null if we are running in CodeQL.

View File

@@ -141,7 +141,7 @@ namespace Semmle.Extraction.CIL.Entities
trapFile = trapWriter.TrapFile;
if (nocache || !System.IO.File.Exists(trapFile))
{
var cx = extractor.CreateContext(null, trapWriter, null);
var cx = extractor.CreateContext(null, trapWriter, null, false);
ExtractCIL(cx, assemblyPath, extractPdbs);
extracted = true;
}

View File

@@ -25,9 +25,12 @@ namespace Semmle.Extraction.CSharp
public readonly ILogger Logger;
public Analyser(IProgressMonitor pm, ILogger logger)
public readonly bool AddAssemblyTrapPrefix;
public Analyser(IProgressMonitor pm, ILogger logger, bool addAssemblyTrapPrefix)
{
Logger = logger;
AddAssemblyTrapPrefix = addAssemblyTrapPrefix;
Logger.Log(Severity.Info, "EXTRACTION STARTING at {0}", DateTime.Now);
stopWatch.Start();
progressMonitor = pm;
@@ -231,7 +234,7 @@ namespace Semmle.Extraction.CSharp
var projectLayout = layout.LookupProjectOrDefault(assemblyPath);
var trapWriter = projectLayout.CreateTrapWriter(Logger, assemblyPath, true, options.TrapCompression);
compilationTrapFile = trapWriter; // Dispose later
var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath, true));
var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath, true), AddAssemblyTrapPrefix);
compilationEntity = new Entities.Compilation(cx, cwd, args);
}
@@ -286,7 +289,7 @@ namespace Semmle.Extraction.CSharp
if (assembly != null)
{
var cx = extractor.CreateContext(c, trapWriter, new AssemblyScope(assembly, assemblyPath, false));
var cx = extractor.CreateContext(c, trapWriter, new AssemblyScope(assembly, assemblyPath, false), AddAssemblyTrapPrefix);
foreach (var module in assembly.Modules)
{
@@ -372,7 +375,7 @@ namespace Semmle.Extraction.CSharp
if (!upToDate)
{
Context cx = extractor.CreateContext(compilation.Clone(), trapWriter, new SourceScope(tree));
Context cx = extractor.CreateContext(compilation.Clone(), trapWriter, new SourceScope(tree), AddAssemblyTrapPrefix);
Populators.CompilationUnit.Extract(cx, tree.GetRoot());
cx.PopulateAll();
cx.ExtractComments(cx.CommentGenerator);

View File

@@ -77,7 +77,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
public new static Accessor Create(Context cx, IMethodSymbol symbol) =>
AccessorFactory.Instance.CreateEntity(cx, symbol);
AccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
class AccessorFactory : ICachedEntityFactory<IMethodSymbol, Accessor>
{

View File

@@ -35,7 +35,7 @@ namespace Semmle.Extraction.CSharp.Entities
Context.TrapWriter.Writer.commentblock_binding(this, entity, binding);
}
public static CommentBlock Create(Context cx, ICommentBlock block) => CommentBlockFactory.Instance.CreateEntity(cx, block);
public static CommentBlock Create(Context cx, ICommentBlock block) => CommentBlockFactory.Instance.CreateEntity(cx, block, block);
class CommentBlockFactory : ICachedEntityFactory<ICommentBlock, CommentBlock>
{

View File

@@ -129,7 +129,11 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.Write(";commentline");
}
static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) => CommentLineFactory.Instance.CreateEntity(cx, loc, type, text, raw);
static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw)
{
var init = (loc, type, text, raw);
return CommentLineFactory.Instance.CreateEntity(cx, init, init);
}
class CommentLineFactory : ICachedEntityFactory<(Microsoft.CodeAnalysis.Location, CommentLineType, string, string), CommentLine>
{

View File

@@ -104,7 +104,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
case MethodKind.StaticConstructor:
case MethodKind.Constructor:
return ConstructorFactory.Instance.CreateEntity(cx, constructor);
return ConstructorFactory.Instance.CreateEntityFromSymbol(cx, constructor);
default:
throw new InternalError(constructor, "Attempt to create a Constructor from a symbol that isn't a constructor");
}

View File

@@ -11,7 +11,7 @@ namespace Semmle.Extraction.CSharp.Entities
: base(cx, init) { }
public new static Conversion Create(Context cx, IMethodSymbol symbol) =>
ConversionFactory.Instance.CreateEntity(cx, symbol);
ConversionFactory.Instance.CreateEntityFromSymbol(cx, symbol);
public override Microsoft.CodeAnalysis.Location ReportingLocation
{

View File

@@ -24,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
public new static Destructor Create(Context cx, IMethodSymbol symbol) =>
DestructorFactory.Instance.CreateEntity(cx, symbol);
DestructorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
class DestructorFactory : ICachedEntityFactory<IMethodSymbol, Destructor>
{

View File

@@ -60,7 +60,7 @@ namespace Semmle.Extraction.CSharp.Entities
TypeMention.Create(Context, syntaxType, this, type);
}
public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntity(cx, symbol);
public static Event Create(Context cx, IEventSymbol symbol) => EventFactory.Instance.CreateEntityFromSymbol(cx, symbol);
class EventFactory : ICachedEntityFactory<IEventSymbol, Event>
{

View File

@@ -53,7 +53,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
public new static EventAccessor Create(Context cx, IMethodSymbol symbol) =>
EventAccessorFactory.Instance.CreateEntity(cx, symbol);
EventAccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
class EventAccessorFactory : ICachedEntityFactory<IMethodSymbol, EventAccessor>
{

View File

@@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities
type = new Lazy<AnnotatedType>(() => Entities.Type.Create(cx, symbol.GetAnnotatedType()));
}
public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntity(cx, field);
public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntityFromSymbol(cx, field);
// Do not populate backing fields.
// Populate Tuple fields.
@@ -101,6 +101,8 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(Type.Type);
trapFile.Write(" ");
trapFile.WriteSubId(ContainingType);
trapFile.Write('.');
trapFile.Write(symbol.Name);

View File

@@ -71,7 +71,7 @@ namespace Semmle.Extraction.CSharp.Entities
TypeMention.Create(Context, syntax.Type, this, type);
}
public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntity(cx, prop);
public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntityFromSymbol(cx, prop);
public override void WriteId(TextWriter trapFile)
{

View File

@@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.Write('*');
}
public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntity(cx, field);
public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntityFromSymbol(cx, field);
class LocalFunctionFactory : ICachedEntityFactory<IMethodSymbol, LocalFunction>
{

View File

@@ -43,7 +43,7 @@ namespace Semmle.Extraction.CSharp.Entities
public static LocalVariable Create(Context cx, ISymbol local)
{
return LocalVariableFactory.Instance.CreateEntity(cx, local);
return LocalVariableFactory.Instance.CreateEntityFromSymbol(cx, local);
}
void DefineConstantValue(TextWriter trapFile)

View File

@@ -108,6 +108,9 @@ namespace Semmle.Extraction.CSharp.Entities
/// </summary>
protected static void BuildMethodId(Method m, TextWriter trapFile)
{
m.symbol.ReturnType.BuildOrWriteId(m.Context, trapFile, m.symbol);
trapFile.Write(" ");
trapFile.WriteSubId(m.ContainingType);
AddExplicitInterfaceQualifierToId(m.Context, trapFile, m.symbol.ExplicitInterfaceImplementations);
@@ -129,7 +132,7 @@ namespace Semmle.Extraction.CSharp.Entities
// Type arguments with different nullability can result in
// a constructed method with different nullability of its parameters and return type,
// so we need to create a distinct database entity for it.
trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); trapFile.Write((int)ta.Nullability); });
trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { ta.Symbol.BuildOrWriteId(m.Context, tb0, m.symbol); trapFile.Write((int)ta.Nullability); });
trapFile.Write('>');
}
}
@@ -163,65 +166,21 @@ namespace Semmle.Extraction.CSharp.Entities
BuildMethodId(this, trapFile);
}
/// <summary>
/// Adds an appropriate label ID to the trap builder <paramref name="trapFile"/>
/// for the type <paramref name="type"/> belonging to the signature of method
/// <paramref name="method"/>.
///
/// For methods without type parameters this will always add the key of the
/// corresponding type.
///
/// For methods with type parameters, this will add the key of the
/// corresponding type if the type does *not* contain one of the method
/// type parameters, otherwise it will add a textual representation of
/// the type. This distinction is required because type parameter IDs
/// refer to their declaring methods.
///
/// Example:
///
/// <code>
/// int Count&lt;T&gt;(IEnumerable<T> items)
/// </code>
///
/// The label definitions for <code>Count</code> (<code>#4</code>) and <code>T</code>
/// (<code>#5</code>) will look like:
///
/// <code>
/// #1=&lt;label for System.Int32&gt;
/// #2=&lt;label for type containing Count&gt;
/// #3=&lt;label for IEnumerable`1&gt;
/// #4=@"{#1} {#2}.Count`2(#3<T>);method"
/// #5=@"{#4}T;typeparameter"
/// </code>
///
/// Note how <code>int</code> is referenced in the label definition <code>#3</code> for
/// <code>Count</code>, while <code>T[]</code> is represented textually in order
/// to make the reference to <code>#3</code> in the label definition <code>#4</code> for
/// <code>T</code> valid.
/// </summary>
protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type)
{
if (type.ContainsTypeParameters(cx, method))
type.BuildTypeId(cx, trapFile, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0));
else
trapFile.WriteSubId(Type.Create(cx, type));
}
protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method)
{
trapFile.Write('(');
int index = 0;
if (method.MethodKind == MethodKind.ReducedExtension)
{
trapFile.WriteSeparator(",", ref index);
AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType);
}
var @params = method.MethodKind == MethodKind.ReducedExtension
? method.ReducedFrom.Parameters
: method.Parameters;
foreach (var param in method.Parameters)
foreach (var param in @params)
{
trapFile.WriteSeparator(",", ref index);
AddSignatureTypeToId(cx, trapFile, method, param.Type);
param.Type.BuildOrWriteId(cx, trapFile, method);
trapFile.Write(" ");
trapFile.Write(param.Name);
switch (param.RefKind)
{
case RefKind.Out:
@@ -245,9 +204,7 @@ namespace Semmle.Extraction.CSharp.Entities
public static void AddExplicitInterfaceQualifierToId(Context cx, System.IO.TextWriter trapFile, IEnumerable<ISymbol> explicitInterfaceImplementations)
{
if (explicitInterfaceImplementations.Any())
{
trapFile.AppendList(",", explicitInterfaceImplementations.Select(impl => cx.CreateEntity(impl.ContainingType)));
}
}
public virtual string Name => symbol.Name;

View File

@@ -5,37 +5,16 @@ using System.Reflection;
namespace Semmle.Extraction.CSharp.Entities
{
/// <summary>
/// Provide a "Key" object to allow modifiers to exist as entities in the extractor
/// hash map. (Raw strings would work as keys but might clash with other types).
/// </summary>
class ModifierKey : Object
class Modifier : Extraction.CachedEntity<string>
{
public readonly string name;
public ModifierKey(string m)
{
name = m;
}
public override bool Equals(Object obj)
{
return obj.GetType() == GetType() && name == ((ModifierKey)obj).name;
}
public override int GetHashCode() => 13 * name.GetHashCode();
}
class Modifier : Extraction.CachedEntity<ModifierKey>
{
Modifier(Context cx, ModifierKey init)
Modifier(Context cx, string init)
: base(cx, init) { }
public override Microsoft.CodeAnalysis.Location ReportingLocation => null;
public override void WriteId(TextWriter trapFile)
{
trapFile.Write(symbol.name);
trapFile.Write(symbol);
trapFile.Write(";modifier");
}
@@ -43,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
trapFile.modifiers(Label, symbol.name);
trapFile.modifiers(Label, symbol);
}
public static string AccessbilityModifier(Accessibility access)
@@ -152,17 +131,22 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public static Modifier Create(Context cx, string modifier) =>
ModifierFactory.Instance.CreateEntity(cx, new ModifierKey(modifier));
public static Modifier Create(Context cx, string modifier)
{
return ModifierFactory.Instance.CreateEntity(cx, (typeof(Modifier), modifier), modifier);
}
public static Modifier Create(Context cx, Accessibility access) =>
ModifierFactory.Instance.CreateEntity(cx, new ModifierKey(AccessbilityModifier(access)));
public static Modifier Create(Context cx, Accessibility access)
{
var modifier = AccessbilityModifier(access);
return ModifierFactory.Instance.CreateEntity(cx, (typeof(Modifier), modifier), modifier);
}
class ModifierFactory : ICachedEntityFactory<ModifierKey, Modifier>
class ModifierFactory : ICachedEntityFactory<string, Modifier>
{
public static readonly ModifierFactory Instance = new ModifierFactory();
public Modifier Create(Context cx, ModifierKey init) => new Modifier(cx, init);
public Modifier Create(Context cx, string init) => new Modifier(cx, init);
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
}

View File

@@ -34,7 +34,7 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.Write(";namespace");
}
public static Namespace Create(Context cx, INamespaceSymbol ns) => NamespaceFactory.Instance.CreateEntity2(cx, ns);
public static Namespace Create(Context cx, INamespaceSymbol ns) => NamespaceFactory.Instance.CreateEntityFromSymbol(cx, ns);
class NamespaceFactory : ICachedEntityFactory<INamespaceSymbol, Namespace>
{

View File

@@ -51,7 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities
ExtractCompilerGenerated(trapFile);
}
public new static OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntity(cx, method);
public new static OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method);
class OrdinaryMethodFactory : ICachedEntityFactory<IMethodSymbol, OrdinaryMethod>
{

View File

@@ -66,10 +66,10 @@ namespace Semmle.Extraction.CSharp.Entities
}
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) =>
ParameterFactory.Instance.CreateEntity(cx, param, parent, original);
ParameterFactory.Instance.CreateEntity(cx, param, (param, parent, original));
public static Parameter Create(Context cx, IParameterSymbol param) =>
ParameterFactory.Instance.CreateEntity(cx, param, null, null);
ParameterFactory.Instance.CreateEntity(cx, param, (param, null, null));
public override void WriteId(TextWriter trapFile)
{
@@ -202,7 +202,7 @@ namespace Semmle.Extraction.CSharp.Entities
return obj != null && obj.GetType() == typeof(VarargsType);
}
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateNullableEntity(cx, null);
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateEntity(cx, typeof(VarargsType), null);
class VarargsTypeFactory : ICachedEntityFactory<string, VarargsType>
{
@@ -237,7 +237,7 @@ namespace Semmle.Extraction.CSharp.Entities
return obj != null && obj.GetType() == typeof(VarargsParam);
}
public static VarargsParam Create(Context cx, Method method) => VarargsParamFactory.Instance.CreateEntity(cx, method);
public static VarargsParam Create(Context cx, Method method) => VarargsParamFactory.Instance.CreateEntity(cx, typeof(VarargsParam), method);
class VarargsParamFactory : ICachedEntityFactory<Method, VarargsParam>
{
@@ -264,19 +264,8 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.param_location(this, Original.Location);
}
public override int GetHashCode() => symbol.GetHashCode() + 31 * ConstructedType.GetHashCode();
public override bool Equals(object obj)
{
var other = obj as ConstructedExtensionParameter;
if (other == null || other.GetType() != typeof(ConstructedExtensionParameter))
return false;
return SymbolEqualityComparer.Default.Equals(symbol, other.symbol) && SymbolEqualityComparer.Default.Equals(ConstructedType, other.ConstructedType);
}
public static ConstructedExtensionParameter Create(Context cx, Method method, Parameter parameter) =>
ExtensionParamFactory.Instance.CreateEntity(cx, (method, parameter));
ExtensionParamFactory.Instance.CreateEntity(cx, (new SymbolEqualityWrapper(parameter.symbol), new SymbolEqualityWrapper(method.symbol.ReceiverType)), (method, parameter));
class ExtensionParamFactory : ICachedEntityFactory<(Method, Parameter), ConstructedExtensionParameter>
{

View File

@@ -1,3 +1,4 @@
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.CSharp.Entities.Expressions;
@@ -11,10 +12,18 @@ namespace Semmle.Extraction.CSharp.Entities
class Property : CachedSymbol<IPropertySymbol>, IExpressionParentEntity
{
protected Property(Context cx, IPropertySymbol init)
: base(cx, init) { }
: base(cx, init)
{
type = new Lazy<Type>(() => Type.Create(Context, symbol.Type));
}
readonly Lazy<Type> type;
Type Type => type.Value;
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(Type);
trapFile.Write(" ");
trapFile.WriteSubId(ContainingType);
trapFile.Write('.');
Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations);
@@ -31,7 +40,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateNullability(trapFile, symbol.GetAnnotatedType());
PopulateRefKind(trapFile, symbol.RefKind);
var type = Type.Create(Context, symbol.Type);
var type = Type;
trapFile.properties(this, symbol.GetName(), ContainingType, type.TypeRef, Create(Context, symbol.OriginalDefinition));
var getter = symbol.GetMethod;
@@ -113,7 +122,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
bool isIndexer = prop.IsIndexer || prop.Parameters.Any();
return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntity(cx, prop);
return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntityFromSymbol(cx, prop);
}
public void VisitDeclaration(Context cx, PropertyDeclarationSyntax p)

View File

@@ -36,7 +36,7 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.Write(";type");
}
public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntity(cx, symbol);
public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol);
class ArrayTypeFactory : ICachedEntityFactory<IArrayTypeSymbol, ArrayType>
{

View File

@@ -9,7 +9,7 @@ namespace Semmle.Extraction.CSharp.Entities
DynamicType(Context cx, IDynamicTypeSymbol init)
: base(cx, init) { }
public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntity(cx, type);
public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntityFromSymbol(cx, type);
public override Microsoft.CodeAnalysis.Location ReportingLocation => Context.Compilation.ObjectType.Locations.FirstOrDefault();

View File

@@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities
typeArgumentsLazy = new Lazy<Type[]>(() => symbol.TypeArguments.Select(t => Create(cx, t)).ToArray());
}
public static NamedType Create(Context cx, INamedTypeSymbol type) => NamedTypeFactory.Instance.CreateEntity(cx, type);
public static NamedType Create(Context cx, INamedTypeSymbol type) => NamedTypeFactory.Instance.CreateEntityFromSymbol(cx, type);
public override bool NeedsPopulation => base.NeedsPopulation || symbol.TypeKind == TypeKind.Error;
@@ -29,7 +29,8 @@ namespace Semmle.Extraction.CSharp.Entities
return;
}
trapFile.typeref_type((NamedTypeRef)TypeRef, this);
if (UsesTypeRef)
trapFile.typeref_type((NamedTypeRef)TypeRef, this);
if (symbol.IsGenericType)
{
@@ -106,10 +107,25 @@ namespace Semmle.Extraction.CSharp.Entities
public override Microsoft.CodeAnalysis.Location ReportingLocation => GetLocations(symbol).FirstOrDefault();
bool IsAnonymousType() => symbol.IsAnonymousType || symbol.Name.Contains("__AnonymousType");
public override void WriteId(TextWriter trapFile)
{
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
trapFile.Write(";type");
if (IsAnonymousType())
trapFile.Write('*');
else
{
symbol.BuildTypeId(Context, trapFile, symbol);
trapFile.Write(";type");
}
}
public override void WriteQuotedId(TextWriter trapFile)
{
if (IsAnonymousType())
trapFile.Write('*');
else
base.WriteQuotedId(trapFile);
}
/// <summary>
@@ -148,7 +164,13 @@ namespace Semmle.Extraction.CSharp.Entities
public NamedType Create(Context cx, INamedTypeSymbol init) => new NamedType(cx, init);
}
public override Type TypeRef => NamedTypeRef.Create(Context, symbol);
// Do not create typerefs of constructed generics as they are always in the current trap file.
// Create typerefs for constructed error types in case they are fully defined elsewhere.
// We cannot use `!this.NeedsPopulation` because this would not be stable as it would depend on
// the assembly that was being extracted at the time.
bool UsesTypeRef => symbol.TypeKind == TypeKind.Error || SymbolEqualityComparer.Default.Equals(symbol.OriginalDefinition, symbol);
public override Type TypeRef => UsesTypeRef ? (Type)NamedTypeRef.Create(Context, symbol) : this;
}
class NamedTypeRef : Type<INamedTypeSymbol>
@@ -161,7 +183,9 @@ namespace Semmle.Extraction.CSharp.Entities
}
public static NamedTypeRef Create(Context cx, INamedTypeSymbol type) =>
NamedTypeRefFactory.Instance.CreateEntity2(cx, type);
// We need to use a different cache key than `type` to avoid mixing up
// `NamedType`s and `NamedTypeRef`s
NamedTypeRefFactory.Instance.CreateEntity(cx, (typeof(NamedTypeRef), new SymbolEqualityWrapper(type)), type);
class NamedTypeRefFactory : ICachedEntityFactory<INamedTypeSymbol, NamedTypeRef>
{

View File

@@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities
return obj != null && obj.GetType() == typeof(NullType);
}
public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateNullableEntity(cx, null), NullableAnnotation.None);
public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateEntity(cx, typeof(NullType), null), NullableAnnotation.None);
class NullTypeFactory : ICachedEntityFactory<ITypeSymbol, NullType>
{

View File

@@ -127,7 +127,7 @@ namespace Semmle.Extraction.CSharp.Entities
symbol.WriteId(trapFile);
}
public static NullabilityEntity Create(Context cx, Nullability init) => NullabilityFactory.Instance.CreateEntity(cx, init);
public static NullabilityEntity Create(Context cx, Nullability init) => NullabilityFactory.Instance.CreateEntity(cx, init, init);
class NullabilityFactory : ICachedEntityFactory<Nullability, NullabilityEntity>
{

View File

@@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities
public Type PointedAtType { get; private set; }
public static PointerType Create(Context cx, IPointerTypeSymbol symbol) => PointerTypeFactory.Instance.CreateEntity(cx, symbol);
public static PointerType Create(Context cx, IPointerTypeSymbol symbol) => PointerTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol);
class PointerTypeFactory : ICachedEntityFactory<IPointerTypeSymbol, PointerType>
{

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// </summary>
class TupleType : Type<INamedTypeSymbol>
{
public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntity(cx, type);
public static TupleType Create(Context cx, INamedTypeSymbol type) => TupleTypeFactory.Instance.CreateEntityFromSymbol(cx, type);
class TupleTypeFactory : ICachedEntityFactory<INamedTypeSymbol, TupleType>
{
@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
symbol.BuildTypeId(Context, trapFile, symbol);
trapFile.Write(";tuple");
}

View File

@@ -100,19 +100,14 @@ namespace Semmle.Extraction.CSharp.Entities
// Visit base types
var baseTypes = new List<Type>();
if (symbol.BaseType != null)
if (symbol.GetNonObjectBaseType(Context) is INamedTypeSymbol @base)
{
Type baseKey = Create(Context, symbol.BaseType);
Type baseKey = Create(Context, @base);
trapFile.extend(this, baseKey.TypeRef);
if (symbol.TypeKind != TypeKind.Struct)
baseTypes.Add(baseKey);
}
if (symbol.TypeKind == TypeKind.Interface)
{
trapFile.extend(this, Create(Context, Context.Compilation.ObjectType));
}
if (!(base.symbol is IArrayTypeSymbol))
{
foreach (var t in base.symbol.Interfaces.Select(i => Create(Context, i)))
@@ -298,7 +293,9 @@ namespace Semmle.Extraction.CSharp.Entities
: base(cx, init, parent, original) { }
new public static DelegateTypeParameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) =>
DelegateTypeParameterFactory.Instance.CreateEntity(cx, (param, parent, original));
// We need to use a different cache key than `param` to avoid mixing up
// `DelegateTypeParameter`s and `Parameter`s
DelegateTypeParameterFactory.Instance.CreateEntity(cx, (typeof(DelegateTypeParameter), new SymbolEqualityWrapper(param)), (param, parent, original));
class DelegateTypeParameterFactory : ICachedEntityFactory<(IParameterSymbol, IEntity, Parameter), DelegateTypeParameter>
{
@@ -324,6 +321,14 @@ namespace Semmle.Extraction.CSharp.Entities
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
public override bool Equals(object obj)
{
var other = obj as Type;
return other?.GetType() == GetType() && SymbolEqualityComparer.IncludeNullability.Equals(other.symbol, symbol);
}
public override int GetHashCode() => SymbolEqualityComparer.IncludeNullability.GetHashCode(symbol);
}
abstract class Type<T> : Type where T : ITypeSymbol

View File

@@ -38,17 +38,11 @@ namespace Semmle.Extraction.CSharp.Entities
if (symbol.HasUnmanagedTypeConstraint)
trapFile.general_type_parameter_constraints(constraints, 4);
ITypeSymbol baseType = symbol.HasValueTypeConstraint ?
Context.Compilation.GetTypeByMetadataName(valueTypeName) :
Context.Compilation.ObjectType;
if (symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated)
trapFile.general_type_parameter_constraints(constraints, 5);
foreach (var abase in symbol.GetAnnotatedTypeConstraints())
{
if (abase.Symbol.TypeKind != TypeKind.Interface)
baseType = abase.Symbol;
var t = Create(Context, abase.Symbol);
trapFile.specific_type_parameter_constraints(constraints, t.TypeRef);
if (!abase.HasObliviousNullability())
@@ -56,7 +50,6 @@ namespace Semmle.Extraction.CSharp.Entities
}
trapFile.types(this, Kinds.TypeKind.TYPE_PARAMETER, symbol.Name);
trapFile.extend(this, Create(Context, baseType).TypeRef);
Namespace parentNs = Namespace.Create(Context, symbol.TypeParameterKind == TypeParameterKind.Method ? Context.Compilation.GlobalNamespace : symbol.ContainingNamespace);
trapFile.parent_namespace(this, parentNs);
@@ -88,7 +81,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
static public TypeParameter Create(Context cx, ITypeParameterSymbol p) =>
TypeParameterFactory.Instance.CreateEntity(cx, p);
TypeParameterFactory.Instance.CreateEntityFromSymbol(cx, p);
/// <summary>
/// The variance of this type parameter.

View File

@@ -49,13 +49,6 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public override void WriteId(TextWriter trapFile)
{
AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType); // Needed for op_explicit(), which differs only by return type.
trapFile.Write(' ');
BuildMethodId(this, trapFile);
}
/// <summary>
/// For some reason, some operators are missing from the Roslyn database of mscorlib.
/// This method returns <code>true</code> for such operators.
@@ -68,7 +61,7 @@ namespace Semmle.Extraction.CSharp.Entities
if (containingType != null)
{
var containingNamedType = containingType as INamedTypeSymbol;
return containingNamedType == null || !containingNamedType.MemberNames.Contains(symbol.Name);
return containingNamedType == null || !containingNamedType.GetMembers(symbol.Name).Contains(symbol);
}
var pointerType = symbol.Parameters.Select(p => p.Type).OfType<IPointerTypeSymbol>().FirstOrDefault();
@@ -190,7 +183,7 @@ namespace Semmle.Extraction.CSharp.Entities
return result;
}
public new static UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntity(cx, symbol);
public new static UserOperator Create(Context cx, IMethodSymbol symbol) => UserOperatorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
class UserOperatorFactory : ICachedEntityFactory<IMethodSymbol, UserOperator>
{

View File

@@ -76,7 +76,7 @@ namespace Semmle.Extraction.CSharp
return ExitCode.Ok;
}
using (var analyser = new Analyser(new LogProgressMonitor(logger), logger))
using (var analyser = new Analyser(new LogProgressMonitor(logger), logger, commandLineArguments.AssemblySensitiveTrap))
using (var references = new BlockingCollection<MetadataReference>())
{
try
@@ -318,7 +318,7 @@ namespace Semmle.Extraction.CSharp
ILogger logger,
CommonOptions options)
{
using (var analyser = new Analyser(pm, logger))
using (var analyser = new Analyser(pm, logger, false))
using (var references = new BlockingCollection<MetadataReference>())
{
try

View File

@@ -26,6 +26,11 @@ namespace Semmle.Extraction.CSharp
/// </summary>
public bool ClrTracer = false;
/// <summary>
/// Holds if assembly information should be prefixed to TRAP labels.
/// </summary>
public bool AssemblySensitiveTrap = false;
public static Options CreateWithEnvironment(string[] arguments)
{
var options = new Options();
@@ -75,6 +80,9 @@ namespace Semmle.Extraction.CSharp
case "clrtracer":
ClrTracer = value;
return true;
case "assemblysensitivetrap":
AssemblySensitiveTrap = value;
return true;
default:
return base.handleFlag(flag, value);
}

View File

@@ -85,41 +85,62 @@ namespace Semmle.Extraction.CSharp
}
/// <summary>
/// Holds if this type symbol contains a type parameter from the
/// declaring generic <paramref name="declaringGeneric"/>.
/// Holds if the ID generated for `dependant` will contain a reference to
/// the ID for `symbol`. If this is the case, then the ID for `symbol` must
/// not contain a reference back to `dependant`.
/// </summary>
public static bool ContainsTypeParameters(this ITypeSymbol type, Context cx, ISymbol declaringGeneric)
public static bool IdDependsOn(this ITypeSymbol dependant, Context cx, ISymbol symbol)
{
using (cx.StackGuard)
var seen = new HashSet<ITypeSymbol>(SymbolEqualityComparer.Default);
bool IdDependsOnImpl(ITypeSymbol type)
{
switch (type.TypeKind)
if (SymbolEqualityComparer.Default.Equals(type, symbol))
return true;
if (type is null || seen.Contains(type))
return false;
seen.Add(type);
using (cx.StackGuard)
{
case TypeKind.Array:
var array = (IArrayTypeSymbol)type;
return array.ElementType.ContainsTypeParameters(cx, declaringGeneric);
case TypeKind.Class:
case TypeKind.Interface:
case TypeKind.Struct:
case TypeKind.Enum:
case TypeKind.Delegate:
case TypeKind.Error:
var named = (INamedTypeSymbol)type;
if (named.IsTupleType)
named = named.TupleUnderlyingType;
if (named.ContainingType != null && named.ContainingType.ContainsTypeParameters(cx, declaringGeneric))
return true;
return named.TypeArguments.Any(arg => arg.ContainsTypeParameters(cx, declaringGeneric));
case TypeKind.Pointer:
var ptr = (IPointerTypeSymbol)type;
return ptr.PointedAtType.ContainsTypeParameters(cx, declaringGeneric);
case TypeKind.TypeParameter:
var tp = (ITypeParameterSymbol)type;
var declaringGen = tp.TypeParameterKind == TypeParameterKind.Method ? tp.DeclaringMethod : (ISymbol)tp.DeclaringType;
return SymbolEqualityComparer.Default.Equals(declaringGen, declaringGeneric);
default:
return false;
switch (type.TypeKind)
{
case TypeKind.Array:
var array = (IArrayTypeSymbol)type;
return IdDependsOnImpl(array.ElementType);
case TypeKind.Class:
case TypeKind.Interface:
case TypeKind.Struct:
case TypeKind.Enum:
case TypeKind.Delegate:
case TypeKind.Error:
var named = (INamedTypeSymbol)type;
if (named.IsTupleType)
named = named.TupleUnderlyingType;
if (IdDependsOnImpl(named.ContainingType))
return true;
if (IdDependsOnImpl(named.GetNonObjectBaseType(cx)))
return true;
if (IdDependsOnImpl(named.ConstructedFrom))
return true;
return named.TypeArguments.Any(IdDependsOnImpl);
case TypeKind.Pointer:
var ptr = (IPointerTypeSymbol)type;
return IdDependsOnImpl(ptr.PointedAtType);
case TypeKind.TypeParameter:
var tp = (ITypeParameterSymbol)type;
return tp.ContainingSymbol is ITypeSymbol cont
? IdDependsOnImpl(cont)
: SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, symbol);
default:
return false;
}
}
}
return IdDependsOnImpl(dependant);
}
/// <summary>
@@ -130,27 +151,19 @@ namespace Semmle.Extraction.CSharp
/// </summary>
/// <param name="cx">The extraction context.</param>
/// <param name="trapFile">The trap builder used to store the result.</param>
/// <param name="subTermAction">The action to apply to syntactic sub terms of this type.</param>
public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol> subTermAction)
{
if (type.SpecialType != SpecialType.None)
{
/*
* Use the keyword ("int" etc) for the built-in types.
* This makes the IDs shorter and means that all built-in types map to
* the same entities (even when using multiple versions of mscorlib).
*/
trapFile.Write(type.ToDisplayString());
return;
}
/// <param name="symbolBeingDefined">The outer symbol being defined (to avoid recursive ids).</param>
public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined) =>
type.BuildTypeId(cx, trapFile, symbolBeingDefined, true);
static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass)
{
using (cx.StackGuard)
{
switch (type.TypeKind)
{
case TypeKind.Array:
var array = (IArrayTypeSymbol)type;
subTermAction(cx, trapFile, array.ElementType);
array.ElementType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
array.BuildArraySuffix(trapFile);
return;
case TypeKind.Class:
@@ -160,15 +173,17 @@ namespace Semmle.Extraction.CSharp
case TypeKind.Delegate:
case TypeKind.Error:
var named = (INamedTypeSymbol)type;
named.BuildNamedTypeId(cx, trapFile, subTermAction);
named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, addBaseClass);
return;
case TypeKind.Pointer:
var ptr = (IPointerTypeSymbol)type;
subTermAction(cx, trapFile, ptr.PointedAtType);
ptr.PointedAtType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
trapFile.Write('*');
return;
case TypeKind.TypeParameter:
var tp = (ITypeParameterSymbol)type;
tp.ContainingSymbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
trapFile.Write('_');
trapFile.Write(tp.Name);
return;
case TypeKind.Dynamic:
@@ -180,6 +195,42 @@ namespace Semmle.Extraction.CSharp
}
}
static void BuildOrWriteId(this ISymbol symbol, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass)
{
// We need to keep track of the symbol being defined in order to avoid cyclic labels.
// For example, in
//
// ```csharp
// class C<T> : IEnumerable<T> { }
// ```
//
// when we generate the label for ``C`1``, the base class `IEnumerable<T>` has `T` as a type
// argument, which will be qualified with `__self__` instead of the label we are defining.
// In effect, the label will (simplified) look like
//
// ```
// #123 = @"C`1 : IEnumerable<__self___T>"
// ```
if (SymbolEqualityComparer.Default.Equals(symbol, symbolBeingDefined))
trapFile.Write("__self__");
else if (symbol is ITypeSymbol type && type.IdDependsOn(cx, symbolBeingDefined))
type.BuildTypeId(cx, trapFile, symbolBeingDefined, addBaseClass);
else
trapFile.WriteSubId(CreateEntity(cx, symbol));
}
/// <summary>
/// Adds an appropriate ID to the trap builder <paramref name="trapFile"/>
/// for the symbol <paramref name="symbol"/> belonging to
/// <paramref name="symbolBeingDefined"/>.
///
/// This will either write a reference to the ID of the entity belonging to
/// <paramref name="symbol"/> (`{#label}`), or if that will lead to cyclic IDs,
/// it will generate an appropriate ID that encodes the signature of
/// <paramref name="symbol" />.
/// </summary>
public static void BuildOrWriteId(this ISymbol symbol, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined) =>
symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, true);
/// <summary>
/// Constructs an array suffix string for this array type symbol.
@@ -211,11 +262,8 @@ namespace Semmle.Extraction.CSharp
trapFile.Write("::");
}
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol> subTermAction)
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass)
{
bool prefixAssembly = true;
if (named.ContainingAssembly is null) prefixAssembly = false;
if (named.IsTupleType)
{
trapFile.Write('(');
@@ -224,48 +272,71 @@ namespace Semmle.Extraction.CSharp
{
trapFile.Write(f.Name);
trapFile.Write(":");
subTermAction(cx, tb0, f.Type);
f.Type.BuildOrWriteId(cx, tb0, symbolBeingDefined, addBaseClass);
}
);
trapFile.Write(")");
return;
}
if (named.ContainingType != null)
void AddContaining()
{
subTermAction(cx, trapFile, named.ContainingType);
trapFile.Write('.');
}
else if (named.ContainingNamespace != null)
{
if (prefixAssembly)
BuildAssembly(named.ContainingAssembly, trapFile);
named.ContainingNamespace.BuildNamespace(cx, trapFile);
if (named.ContainingType != null)
{
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
trapFile.Write('.');
}
else if (named.ContainingNamespace != null)
{
if (cx.ShouldAddAssemblyTrapPrefix && named.ContainingAssembly is object)
BuildAssembly(named.ContainingAssembly, trapFile);
named.ContainingNamespace.BuildNamespace(cx, trapFile);
}
}
if (named.IsAnonymousType)
named.BuildAnonymousName(cx, trapFile, subTermAction, true);
else if (named.TypeParameters.IsEmpty)
trapFile.Write(named.Name);
else if (IsReallyUnbound(named))
if (named.TypeParameters.IsEmpty)
{
AddContaining();
trapFile.Write(named.Name);
}
else if (named.IsReallyUnbound())
{
AddContaining();
trapFile.Write(named.Name);
trapFile.Write("`");
trapFile.Write(named.TypeParameters.Length);
}
else
{
subTermAction(cx, trapFile, named.ConstructedFrom);
named.ConstructedFrom.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass);
trapFile.Write('<');
// Encode the nullability of the type arguments in the label.
// Type arguments with different nullability can result in
// a constructed type with different nullability of its members and methods,
// so we need to create a distinct database entity for it.
trapFile.BuildList(",", named.GetAnnotatedTypeArguments(),
(ta, tb0) => subTermAction(cx, tb0, ta.Symbol)
(ta, tb0) => ta.Symbol.BuildOrWriteId(cx, tb0, symbolBeingDefined, addBaseClass)
);
trapFile.Write('>');
}
if (addBaseClass && named.GetNonObjectBaseType(cx) is INamedTypeSymbol @base)
{
// We need to limit unfolding of base classes. For example, in
//
// ```csharp
// class C1<T> { }
// class C2<T> : C1<C3<T>> { }
// class C3<T> : C1<C2<T>> { }
// class C4 : C3<C4> { }
// ```
//
// when we generate the label for `C4`, the base class `C3<C4>` has itself `C1<C2<C4>>` as
// a base class, which in turn has `C1<C3<C4>>` as a base class. The latter has the original
// base class `C3<C4>` as a type argument, which would lead to infinite unfolding.
trapFile.Write(" : ");
@base.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass: false);
}
}
static void BuildNamespace(this INamespaceSymbol ns, Context cx, TextWriter trapFile)
@@ -274,22 +345,14 @@ namespace Semmle.Extraction.CSharp
trapFile.Write('.');
}
static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol> subTermAction, bool includeParamName)
static void BuildAnonymousName(this INamedTypeSymbol type, Context cx, TextWriter trapFile)
{
var buildParam = includeParamName
? (prop, tb0) =>
{
tb0.Write(prop.Name);
tb0.Write(' ');
subTermAction(cx, tb0, prop.Type);
}
: (Action<IPropertySymbol, TextWriter>)((prop, tb0) => subTermAction(cx, tb0, prop.Type));
int memberCount = type.GetMembers().OfType<IPropertySymbol>().Count();
int hackTypeNumber = memberCount == 1 ? 1 : 0;
trapFile.Write("<>__AnonType");
trapFile.Write(hackTypeNumber);
trapFile.Write('<');
trapFile.BuildList(",", type.GetMembers().OfType<IPropertySymbol>(), buildParam);
trapFile.BuildList(",", type.GetMembers().OfType<IPropertySymbol>(), (prop, tb0) => BuildDisplayName(prop.Type, cx, tb0));
trapFile.Write('>');
}
@@ -354,11 +417,9 @@ namespace Semmle.Extraction.CSharp
}
if (namedType.IsAnonymousType)
{
namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false);
}
trapFile.Write(namedType.Name);
namedType.BuildAnonymousName(cx, trapFile);
else
trapFile.Write(namedType.Name);
if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any())
{
trapFile.Write('<');
@@ -434,6 +495,13 @@ namespace Semmle.Extraction.CSharp
return true;
}
/// <summary>
/// Gets the base type of `symbol`. Unlike `symbol.BaseType`, this excludes effective base
/// types of type parameters as well as `object` base types.
/// </summary>
public static INamedTypeSymbol GetNonObjectBaseType(this ITypeSymbol symbol, Context cx) =>
symbol is ITypeParameterSymbol || SymbolEqualityComparer.Default.Equals(symbol.BaseType, cx.Compilation.ObjectType) ? null : symbol.BaseType;
public static IEntity CreateEntity(this Context cx, ISymbol symbol)
{
if (symbol == null) return null;

View File

@@ -41,43 +41,13 @@ namespace Semmle.Extraction
/// </summary>
public readonly TrapWriter TrapWriter;
/// <summary>
/// Holds if assembly information should be prefixed to TRAP labels.
/// </summary>
public readonly bool ShouldAddAssemblyTrapPrefix;
int GetNewId() => TrapWriter.IdCounter++;
/// <summary>
/// Creates a new entity using the factory.
/// </summary>
/// <param name="factory">The entity factory.</param>
/// <param name="init">The initializer for the entity.</param>
/// <returns>The new/existing entity.</returns>
public Entity CreateEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity where Type : struct
{
return CreateNonNullEntity(factory, init);
}
/// <summary>
/// Creates a new entity using the factory.
/// </summary>
/// <param name="factory">The entity factory.</param>
/// <param name="init">The initializer for the entity.</param>
/// <returns>The new/existing entity.</returns>
public Entity CreateNullableEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
{
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init);
}
/// <summary>
/// Creates a new entity using the factory.
/// </summary>
/// <param name="factory">The entity factory.</param>
/// <param name="init">The initializer for the entity.</param>
/// <returns>The new/existing entity.</returns>
public Entity CreateEntityFromSymbol<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init)
where Entity : ICachedEntity
where Type : ISymbol
{
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init);
}
// A recursion guard against writing to the trap file whilst writing an id to the trap file.
bool WritingLabel = false;
@@ -102,47 +72,6 @@ namespace Semmle.Extraction
}
}
/// <summary>
/// Creates a new entity using the factory.
/// Uses a different cache to <see cref="CreateEntity{Type, Entity}(ICachedEntityFactory{Type, Entity}, Type)"/>,
/// and can store null values.
/// </summary>
/// <param name="factory">The entity factory.</param>
/// <param name="init">The initializer for the entity.</param>
/// <returns>The new/existing entity.</returns>
public Entity CreateEntity2<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
{
using (StackGuard)
{
var entity = factory.Create(this, init);
if (entityLabelCache.TryGetValue(entity, out var label))
{
entity.Label = label;
}
else
{
label = GetNewLabel();
entity.Label = label;
entityLabelCache[entity] = label;
DefineLabel(entity, TrapWriter.Writer, Extractor);
if (entity.NeedsPopulation)
Populate(init as ISymbol, entity);
#if DEBUG_LABELS
using (var id = new StringWriter())
{
entity.WriteId(id);
CheckEntityHasUniqueLabel(id.ToString(), entity);
}
#endif
}
return entity;
}
}
#if DEBUG_LABELS
private void CheckEntityHasUniqueLabel(string id, ICachedEntity entity)
{
@@ -159,12 +88,27 @@ namespace Semmle.Extraction
public Label GetNewLabel() => new Label(GetNewId());
public Entity CreateNonNullEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init)
public Entity CreateEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, object cacheKey, Type init)
where Entity : ICachedEntity =>
cacheKey is ISymbol s ? CreateEntity(factory, s, init, symbolEntityCache) : CreateEntity(factory, cacheKey, init, objectEntityCache);
public Entity CreateEntityFromSymbol<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init)
where Type : ISymbol
where Entity : ICachedEntity => CreateEntity(factory, init, init, symbolEntityCache);
/// <summary>
/// Creates and populates a new entity, or returns the existing one from the cache.
/// </summary>
/// <param name="factory">The entity factory.</param>
/// <param name="cacheKey">The key used for caching.</param>
/// <param name="init">The initializer for the entity.</param>
/// <param name="dictionary">The dictionary to use for caching.</param>
/// <returns>The new/existing entity.</returns>
Entity CreateEntity<Type, CacheKeyType, Entity>(ICachedEntityFactory<Type, Entity> factory, CacheKeyType cacheKey, Type init, IDictionary<CacheKeyType, ICachedEntity> dictionary)
where CacheKeyType : notnull
where Entity : ICachedEntity
{
if (init is null) throw new ArgumentException("Unexpected null value", nameof(init));
if (objectEntityCache.TryGetValue(init, out var cached))
if (dictionary.TryGetValue(cacheKey, out var cached))
return (Entity)cached;
using (StackGuard)
@@ -173,7 +117,7 @@ namespace Semmle.Extraction
var entity = factory.Create(this, init);
entity.Label = label;
objectEntityCache[init] = entity;
dictionary[cacheKey] = entity;
DefineLabel(entity, TrapWriter.Writer, Extractor);
if (entity.NeedsPopulation)
@@ -227,8 +171,9 @@ namespace Semmle.Extraction
#if DEBUG_LABELS
readonly Dictionary<string, ICachedEntity> idLabelCache = new Dictionary<string, ICachedEntity>();
#endif
readonly Dictionary<object, ICachedEntity> objectEntityCache = new Dictionary<object, ICachedEntity>();
readonly Dictionary<ICachedEntity, Label> entityLabelCache = new Dictionary<ICachedEntity, Label>();
readonly IDictionary<object, ICachedEntity> objectEntityCache = new Dictionary<object, ICachedEntity>();
readonly IDictionary<ISymbol, ICachedEntity> symbolEntityCache = new Dictionary<ISymbol, ICachedEntity>(10000, SymbolEqualityComparer.IncludeNullability);
readonly HashSet<Label> extractedGenerics = new HashSet<Label>();
/// <summary>
@@ -289,12 +234,14 @@ namespace Semmle.Extraction
/// <param name="c">The Roslyn compilation.</param>
/// <param name="extractedEntity">Name of the source/dll file.</param>
/// <param name="scope">Defines which symbols are included in the trap file (e.g. AssemblyScope or SourceScope)</param>
public Context(IExtractor e, Compilation c, TrapWriter trapWriter, IExtractionScope scope)
/// <param name="addAssemblyTrapPrefix">Whether to add assembly prefixes to TRAP labels.</param>
public Context(IExtractor e, Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix)
{
Extractor = e;
Compilation = c;
Scope = scope;
TrapWriter = trapWriter;
ShouldAddAssemblyTrapPrefix = addAssemblyTrapPrefix;
}
public bool FromSource => Scope.FromSource;
@@ -423,8 +370,8 @@ namespace Semmle.Extraction
throw new InternalError("Unexpected TrapStackBehaviour");
}
var a = duplicationGuard ?
(Action)(() => WithDuplicationGuard(new Key(entity, this.Create(entity.ReportingLocation)), () => entity.Populate(TrapWriter.Writer))) :
var a = duplicationGuard && this.Create(entity.ReportingLocation) is NonGeneratedSourceLocation loc ?
(Action)(() => WithDuplicationGuard(new Key(entity, loc), () => entity.Populate(TrapWriter.Writer))) :
(Action)(() => this.Try(null, optionalSymbol, () => entity.Populate(TrapWriter.Writer)));
if (deferred)

View File

@@ -50,7 +50,7 @@ namespace Semmle.Extraction.Entities
return Equals(symbol, other.symbol);
}
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => AssemblyConstructorFactory.Instance.CreateNullableEntity(cx, loc);
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc, loc);
class AssemblyConstructorFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location?, Assembly>
{
@@ -59,11 +59,12 @@ namespace Semmle.Extraction.Entities
public Assembly Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new Assembly(cx, init);
}
static readonly object outputAssemblyCacheKey = new object();
public static Location CreateOutputAssembly(Context cx)
{
if (cx.Extractor.OutputPath == null)
throw new InternalError("Attempting to create the output assembly in standalone extraction mode");
return AssemblyConstructorFactory.Instance.CreateNullableEntity(cx, null);
return AssemblyConstructorFactory.Instance.CreateEntity(cx, outputAssemblyCacheKey, null);
}
public override void WriteId(System.IO.TextWriter trapFile)

View File

@@ -89,7 +89,7 @@ namespace Semmle.Extraction.Entities
public static string PathAsDatabaseString(string path) => path.Replace('\\', '/');
public static File Create(Context cx, string path) => FileFactory.Instance.CreateEntity(cx, path);
public static File Create(Context cx, string path) => FileFactory.Instance.CreateEntity(cx, (typeof(File), path), path);
public static File CreateGenerated(Context cx) => GeneratedFile.Create(cx);
@@ -111,7 +111,7 @@ namespace Semmle.Extraction.Entities
}
public static GeneratedFile Create(Context cx) =>
GeneratedFileFactory.Instance.CreateNullableEntity(cx, null);
GeneratedFileFactory.Instance.CreateEntity(cx, typeof(GeneratedFile), null);
class GeneratedFileFactory : ICachedEntityFactory<string?, GeneratedFile>
{

View File

@@ -43,7 +43,7 @@ namespace Semmle.Extraction.Entities
}
public static Folder Create(Context cx, DirectoryInfo folder) =>
FolderFactory.Instance.CreateEntity2(cx, folder);
FolderFactory.Instance.CreateEntity(cx, folder, folder);
public override Microsoft.CodeAnalysis.Location? ReportingLocation => null;

View File

@@ -28,7 +28,7 @@ namespace Semmle.Extraction.Entities
public override bool Equals(object? obj) => obj != null && obj.GetType() == typeof(GeneratedLocation);
public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateNullableEntity(cx, null);
public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateEntity(cx, typeof(GeneratedLocation), null);
class GeneratedLocationFactory : ICachedEntityFactory<string?, GeneratedLocation>
{

View File

@@ -23,7 +23,7 @@ namespace Semmle.Extraction.Entities
FileEntity = File.Create(Context, Position.Path);
}
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => SourceLocationFactory.Instance.CreateNullableEntity(cx, loc);
public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc, loc);
public override void Populate(TextWriter trapFile)
{
@@ -55,11 +55,11 @@ namespace Semmle.Extraction.Entities
trapFile.Write(Position.Span.End.Character);
}
class SourceLocationFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location?, SourceLocation>
class SourceLocationFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location, SourceLocation>
{
public static readonly SourceLocationFactory Instance = new SourceLocationFactory();
public SourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new NonGeneratedSourceLocation(cx, init);
public SourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location init) => new NonGeneratedSourceLocation(cx, init);
}
}
}

View File

@@ -109,41 +109,33 @@ namespace Semmle.Extraction
public static class ICachedEntityFactoryExtensions
{
public static Entity CreateEntity<Entity, T1, T2>(this ICachedEntityFactory<(T1, T2), Entity> factory, Context cx, T1 t1, T2 t2)
where Entity : ICachedEntity => factory.CreateEntity2(cx, (t1, t2));
public static Entity CreateEntity<Entity, T1, T2, T3>(this ICachedEntityFactory<(T1, T2, T3), Entity> factory, Context cx, T1 t1, T2 t2, T3 t3)
where Entity : ICachedEntity => factory.CreateEntity2(cx, (t1, t2, t3));
public static Entity CreateEntity<Entity, T1, T2, T3, T4>(this ICachedEntityFactory<(T1, T2, T3, T4), Entity> factory, Context cx, T1 t1, T2 t2, T3 t3, T4 t4)
where Entity : ICachedEntity => factory.CreateEntity2(cx, (t1, t2, t3, t4));
/// <summary>
/// Creates and populates a new entity, or returns the existing one from the cache,
/// based on the supplied cache key.
/// </summary>
/// <typeparam name="Type">The type used to construct the entity.</typeparam>
/// <typeparam name="Entity">The type of the entity to create.</typeparam>
/// <param name="factory">The factory used to construct the entity.</param>
/// <param name="cx">The extractor context.</param>
/// <param name="cacheKey">The key used for caching.</param>
/// <param name="init">The initializer for the entity.</param>
/// <returns>The entity.</returns>
public static Entity CreateEntity<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, object cacheKey, Type init)
where Entity : ICachedEntity => cx.CreateEntity(factory, cacheKey, init);
/// <summary>
/// Creates and populates a new entity, or returns the existing one from the cache.
/// Creates and populates a new entity from an `ISymbol`, or returns the existing one
/// from the cache.
/// </summary>
/// <typeparam name="Type">The symbol type used to construct the entity.</typeparam>
/// <typeparam name="Type">The type used to construct the entity.</typeparam>
/// <typeparam name="Entity">The type of the entity to create.</typeparam>
/// <param name="cx">The extractor context.</param>
/// <param name="factory">The factory used to construct the entity.</param>
/// <param name="init">The initializer for the entity, which may not be null.</param>
/// <returns>The entity.</returns>
public static Entity CreateEntity<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init) where Type : notnull
where Entity : ICachedEntity => cx.CreateNonNullEntity(factory, init);
public static Entity CreateNullableEntity<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init)
where Entity : ICachedEntity => cx.CreateNullableEntity(factory, init);
/// <summary>
/// Creates and populates a new entity, but uses a different cache.
/// </summary>
/// <typeparam name="Type">The symbol type used to construct the entity.</typeparam>
/// <typeparam name="Entity">The type of the entity to create.</typeparam>
/// <param name="cx">The extractor context.</param>
/// <param name="factory">The factory used to construct the entity.</param>
/// <param name="init">The initializer for the entity, which may be null.</param>
/// <param name="init">The initializer for the entity.</param>
/// <returns>The entity.</returns>
public static Entity CreateEntity2<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init)
where Entity : ICachedEntity => cx.CreateEntity2(factory, init);
public static Entity CreateEntityFromSymbol<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init)
where Type : ISymbol
where Entity : ICachedEntity => cx.CreateEntityFromSymbol(factory, init);
public static void DefineLabel(this IEntity entity, TextWriter trapFile, IExtractor extractor)
{
@@ -156,7 +148,7 @@ namespace Semmle.Extraction
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
trapFile.WriteLine("\"");
extractor.Message(new Message("Unhandled exception generating id", entity.ToString() ?? "", null, ex.StackTrace));
extractor.Message(new Message($"Unhandled exception generating id: {ex.Message}", entity.ToString() ?? "", null, ex.StackTrace));
}
trapFile.WriteLine();
}

View File

@@ -87,8 +87,9 @@ namespace Semmle.Extraction
/// <param name="c">The C# compilation.</param>
/// <param name="trapWriter">The trap writer.</param>
/// <param name="scope">The extraction scope (what to include in this trap file).</param>
/// <param name="addAssemblyTrapPrefix">Whether to add assembly prefixes to TRAP labels.</param>
/// <returns></returns>
Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope);
Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix);
}
/// <summary>
@@ -187,9 +188,9 @@ namespace Semmle.Extraction
}
}
public Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope)
public Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix)
{
return new Context(this, c, trapWriter, scope);
return new Context(this, c, trapWriter, scope, addAssemblyTrapPrefix);
}
public IEnumerable<string> MissingTypes => missingTypes;

View File

@@ -69,7 +69,6 @@ namespace Semmle.Extraction
}
else
TrapBuilder.Write(arg.ToString());
}
}

View File

@@ -1,4 +1,5 @@
using System.IO;
using Microsoft.CodeAnalysis;
namespace Semmle.Extraction
{
@@ -65,16 +66,6 @@ namespace Semmle.Extraction
get;
}
/// <summary>
/// Runs the given action <paramref name="a"/>, guarding for trap duplication
/// based on the ID an location of this entity.
/// </summary>
protected void WithDuplicationGuard(System.Action a, IEntity location)
{
var key = new Key(this, location);
Context.WithDuplicationGuard(key, a);
}
public override int GetHashCode() => symbol is null ? 0 : symbol.GetHashCode();
public override bool Equals(object? obj)
@@ -85,4 +76,20 @@ namespace Semmle.Extraction
public abstract TrapStackBehaviour TrapStackBehaviour { get; }
}
/// <summary>
/// A class used to wrap an `ISymbol` object, which uses `SymbolEqualityComparer.Default`
/// for comparison.
/// </summary>
public sealed class SymbolEqualityWrapper
{
public ISymbol Symbol { get; }
public SymbolEqualityWrapper(ISymbol symbol) { Symbol = symbol; }
public override bool Equals(object? other) =>
other is SymbolEqualityWrapper sew && SymbolEqualityComparer.Default.Equals(Symbol, sew.Symbol);
public override int GetHashCode() => 11 * Symbol.GetHashCode();
}
}

Some files were not shown because too many files have changed in this diff Show More