mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge branch 'main' into rdmarsh2/cpp/input-iterators-1Merge changes to input/output models for functions that return thisand resolve conflicting changes to taint tests.
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
void test(char *arg1, int *arg2) {
|
||||
if (arg1[0] == 'A') {
|
||||
if (arg2 != NULL) { //maybe redundant
|
||||
*arg2 = 42;
|
||||
}
|
||||
}
|
||||
if (arg1[1] == 'B')
|
||||
{
|
||||
*arg2 = 54; //dereferenced without checking first
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>This rule finds comparisons of a function parameter to null that occur when in another path the parameter is dereferenced without a guard check. It's
|
||||
likely either the check is not required and can be removed, or it should be added before the dereference
|
||||
so that a null pointer dereference does not occur.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>A check should be added to before the dereference, in a way that prevents a null pointer value from
|
||||
being dereferenced. If it's clear that the pointer cannot be null, consider removing the check instead.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<sample src="RedundantNullCheckParam.cpp" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://www.owasp.org/index.php/Null_Dereference">
|
||||
Null Dereference
|
||||
</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @name Redundant null check or missing null check of parameter
|
||||
* @description Checking a parameter for nullness in one path,
|
||||
* and not in another is likely to be a sign that either
|
||||
* the check can be removed, or added in the other case.
|
||||
* @kind problem
|
||||
* @id cpp/redundant-null-check-param
|
||||
* @problem.severity recommendation
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-476
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
predicate blockDominates(Block check, Block access) {
|
||||
check.getLocation().getStartLine() <= access.getLocation().getStartLine() and
|
||||
check.getLocation().getEndLine() >= access.getLocation().getEndLine()
|
||||
}
|
||||
|
||||
predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) {
|
||||
checked = any(VariableAccess va | va.getTarget() = unchecked.getTarget()) and
|
||||
//Simple test if the first access in this code path is dereferenced
|
||||
not dereferenced(checked) and
|
||||
blockDominates(checked.getEnclosingBlock(), unchecked.getEnclosingBlock())
|
||||
}
|
||||
|
||||
predicate candidateResultUnchecked(VariableAccess unchecked) {
|
||||
not isCheckedInstruction(unchecked, _)
|
||||
}
|
||||
|
||||
predicate candidateResultChecked(VariableAccess check, EqualityOperation eqop) {
|
||||
//not dereferenced to check against pointer, not its pointed value
|
||||
not dereferenced(check) and
|
||||
//assert macros are not taken into account
|
||||
not check.isInMacroExpansion() and
|
||||
// is part of a comparison against some constant NULL
|
||||
eqop.getAnOperand() = check and
|
||||
eqop.getAnOperand() instanceof NullValue
|
||||
}
|
||||
|
||||
from VariableAccess unchecked, VariableAccess check, EqualityOperation eqop, Parameter param
|
||||
where
|
||||
// a dereference
|
||||
dereferenced(unchecked) and
|
||||
// for a function parameter
|
||||
unchecked.getTarget() = param and
|
||||
// this function parameter is not overwritten
|
||||
count(param.getAnAssignment()) = 0 and
|
||||
check.getTarget() = param and
|
||||
// which is once checked
|
||||
candidateResultChecked(check, eqop) and
|
||||
// and which has not been checked before in this code path
|
||||
candidateResultUnchecked(unchecked)
|
||||
select check, "This null check is redundant or there is a missing null check before $@ ", unchecked,
|
||||
"where dereferencing happens"
|
||||
@@ -123,8 +123,18 @@ module Consistency {
|
||||
n.getEnclosingCallable() != call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
// This predicate helps the compiler forget that in some languages
|
||||
// it is impossible for a result of `getPreUpdateNode` to be an
|
||||
// instance of `PostUpdateNode`.
|
||||
private Node getPre(PostUpdateNode n) {
|
||||
result = n.getPreUpdateNode()
|
||||
or
|
||||
none()
|
||||
}
|
||||
|
||||
query predicate postIsNotPre(PostUpdateNode n, string msg) {
|
||||
n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node."
|
||||
getPre(n) = n and
|
||||
msg = "PostUpdateNode should not equal its pre-update node."
|
||||
}
|
||||
|
||||
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
|
||||
@@ -152,12 +162,6 @@ module Consistency {
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
query predicate storeIsPostUpdate(Node n, string msg) {
|
||||
storeStep(_, _, n) and
|
||||
not n instanceof PostUpdateNode and
|
||||
msg = "Store targets should be PostUpdateNodes."
|
||||
}
|
||||
|
||||
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
|
||||
not hasPost(n) and
|
||||
not isImmutableOrUnobservable(n) and
|
||||
|
||||
@@ -484,6 +484,17 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// Expr -> Expr
|
||||
exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
or
|
||||
// Assignment -> LValue post-update node
|
||||
//
|
||||
// This is used for assignments whose left-hand side is not a variable
|
||||
// assignment or a storeStep but is still modeled by other means. It could be
|
||||
// a call to `operator*` or `operator[]` where taint should flow to the
|
||||
// post-update node of the qualifier.
|
||||
exists(AssignExpr assign |
|
||||
nodeFrom.asExpr() = assign and
|
||||
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = assign.getLValue()
|
||||
)
|
||||
or
|
||||
// Node -> FlowVar -> VariableAccess
|
||||
exists(FlowVar var |
|
||||
(
|
||||
|
||||
@@ -82,6 +82,19 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
|
||||
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
|
||||
or
|
||||
exprToPartialDefinitionStep(nodeFrom.asExpr(), nodeTo.asPartialDefinition())
|
||||
or
|
||||
// Reverse taint: taint that flows from the post-update node of a reference
|
||||
// returned by a function call, back into the qualifier of that function.
|
||||
// This allows taint to flow 'in' through references returned by a modeled
|
||||
// function such as `operator[]`.
|
||||
exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
inModel.isReturnValueDeref() and
|
||||
outModel.isQualifierObject() and
|
||||
f.hasTaintFlow(inModel, outModel) and
|
||||
nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = call and
|
||||
nodeTo.asDefiningArgument() = call.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -123,8 +123,18 @@ module Consistency {
|
||||
n.getEnclosingCallable() != call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
// This predicate helps the compiler forget that in some languages
|
||||
// it is impossible for a result of `getPreUpdateNode` to be an
|
||||
// instance of `PostUpdateNode`.
|
||||
private Node getPre(PostUpdateNode n) {
|
||||
result = n.getPreUpdateNode()
|
||||
or
|
||||
none()
|
||||
}
|
||||
|
||||
query predicate postIsNotPre(PostUpdateNode n, string msg) {
|
||||
n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node."
|
||||
getPre(n) = n and
|
||||
msg = "PostUpdateNode should not equal its pre-update node."
|
||||
}
|
||||
|
||||
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
|
||||
@@ -152,12 +162,6 @@ module Consistency {
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
query predicate storeIsPostUpdate(Node n, string msg) {
|
||||
storeStep(_, _, n) and
|
||||
not n instanceof PostUpdateNode and
|
||||
msg = "Store targets should be PostUpdateNodes."
|
||||
}
|
||||
|
||||
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
|
||||
not hasPost(n) and
|
||||
not isImmutableOrUnobservable(n) and
|
||||
|
||||
@@ -14,10 +14,7 @@ import semmle.code.cpp.models.interfaces.Taint
|
||||
*/
|
||||
class StdSequenceContainerConstructor extends Constructor, TaintFunction {
|
||||
StdSequenceContainerConstructor() {
|
||||
this.getDeclaringType().hasQualifiedName("std", "vector") or
|
||||
this.getDeclaringType().hasQualifiedName("std", "deque") or
|
||||
this.getDeclaringType().hasQualifiedName("std", "list") or
|
||||
this.getDeclaringType().hasQualifiedName("std", "forward_list")
|
||||
this.getDeclaringType().hasQualifiedName("std", ["vector", "deque", "list", "forward_list"])
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,7 +23,7 @@ class StdSequenceContainerConstructor extends Constructor, TaintFunction {
|
||||
*/
|
||||
int getAValueTypeParameterIndex() {
|
||||
getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||
getDeclaringType().getTemplateArgument(0) // i.e. the `T` of this `std::vector<T>`
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -36,16 +33,32 @@ class StdSequenceContainerConstructor extends Constructor, TaintFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container function `data`.
|
||||
*/
|
||||
class StdSequenceContainerData extends TaintFunction {
|
||||
StdSequenceContainerData() { this.hasQualifiedName("std", ["array", "vector"], "data") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from container itself (qualifier) to return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier (for writes to
|
||||
// `data`)
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `push_back` and `push_front`.
|
||||
*/
|
||||
class StdSequenceContainerPush extends TaintFunction {
|
||||
StdSequenceContainerPush() {
|
||||
this.hasQualifiedName("std", "vector", "push_back") or
|
||||
this.hasQualifiedName("std", "deque", "push_back") or
|
||||
this.hasQualifiedName("std", "deque", "push_front") or
|
||||
this.hasQualifiedName("std", "list", "push_back") or
|
||||
this.hasQualifiedName("std", "list", "push_front") or
|
||||
this.hasQualifiedName("std", "deque", ["push_back", "push_front"]) or
|
||||
this.hasQualifiedName("std", "list", ["push_back", "push_front"]) or
|
||||
this.hasQualifiedName("std", "forward_list", "push_front")
|
||||
}
|
||||
|
||||
@@ -61,14 +74,10 @@ class StdSequenceContainerPush extends TaintFunction {
|
||||
*/
|
||||
class StdSequenceContainerFrontBack extends TaintFunction {
|
||||
StdSequenceContainerFrontBack() {
|
||||
this.hasQualifiedName("std", "array", "front") or
|
||||
this.hasQualifiedName("std", "array", "back") or
|
||||
this.hasQualifiedName("std", "vector", "front") or
|
||||
this.hasQualifiedName("std", "vector", "back") or
|
||||
this.hasQualifiedName("std", "deque", "front") or
|
||||
this.hasQualifiedName("std", "deque", "back") or
|
||||
this.hasQualifiedName("std", "list", "front") or
|
||||
this.hasQualifiedName("std", "list", "back") or
|
||||
this.hasQualifiedName("std", "array", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "vector", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "deque", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "list", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "forward_list", "front")
|
||||
}
|
||||
|
||||
@@ -79,16 +88,36 @@ class StdSequenceContainerFrontBack extends TaintFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container function `assign`.
|
||||
*/
|
||||
class StdSequenceContainerAssign extends TaintFunction {
|
||||
StdSequenceContainerAssign() {
|
||||
this.hasQualifiedName("std", ["vector", "deque", "list", "forward_list"], "assign")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a reference to the
|
||||
* value type of the container.
|
||||
*/
|
||||
int getAValueTypeParameterIndex() {
|
||||
getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameter to string itself (qualifier) and return value
|
||||
input.isParameterDeref(getAValueTypeParameterIndex()) and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container `swap` functions.
|
||||
*/
|
||||
class StdSequenceContainerSwap extends TaintFunction {
|
||||
StdSequenceContainerSwap() {
|
||||
this.hasQualifiedName("std", "array", "swap") or
|
||||
this.hasQualifiedName("std", "vector", "swap") or
|
||||
this.hasQualifiedName("std", "deque", "swap") or
|
||||
this.hasQualifiedName("std", "list", "swap") or
|
||||
this.hasQualifiedName("std", "forward_list", "swap")
|
||||
this.hasQualifiedName("std", ["array", "vector", "deque", "list", "forward_list"], "swap")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -100,3 +129,22 @@ class StdSequenceContainerSwap extends TaintFunction {
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `at` and `operator[]`.
|
||||
*/
|
||||
class StdSequenceContainerAt extends TaintFunction {
|
||||
StdSequenceContainerAt() {
|
||||
this.hasQualifiedName("std", ["vector", "array", "deque"], ["at", "operator[]"])
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from qualifier to referenced return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,18 +15,33 @@ class StdBasicString extends TemplateClass {
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` functions `c_str` and `data`.
|
||||
* The `std::string` function `c_str`.
|
||||
*/
|
||||
class StdStringCStr extends TaintFunction {
|
||||
StdStringCStr() {
|
||||
this.hasQualifiedName("std", "basic_string", "c_str") or
|
||||
this.hasQualifiedName("std", "basic_string", "data")
|
||||
}
|
||||
StdStringCStr() { this.hasQualifiedName("std", "basic_string", "c_str") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string itself (qualifier) to return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` function `data`.
|
||||
*/
|
||||
class StdStringData extends TaintFunction {
|
||||
StdStringData() { this.hasQualifiedName("std", "basic_string", "data") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string itself (qualifier) to return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier (for writes to
|
||||
// `data`)
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,33 +71,31 @@ class StdStringPlus extends TaintFunction {
|
||||
*/
|
||||
class StdStringAppend extends TaintFunction {
|
||||
StdStringAppend() {
|
||||
this.hasQualifiedName("std", "basic_string", "operator+=") or
|
||||
this.hasQualifiedName("std", "basic_string", "append") or
|
||||
this.hasQualifiedName("std", "basic_string", "insert") or
|
||||
this.hasQualifiedName("std", "basic_string", "replace")
|
||||
this.hasQualifiedName("std", "basic_string", ["operator+=", "append", "insert", "replace"])
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameter() {
|
||||
int getAStringParameterIndex() {
|
||||
getParameter(result).getType() instanceof PointerType or
|
||||
getParameter(result).getType() instanceof ReferenceType or
|
||||
getParameter(result).getType() = getDeclaringType().getTemplateArgument(0) // i.e. `std::basic_string::CharT`
|
||||
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 getAnIteratorParameter() { getParameter(result).getType() instanceof Iterator }
|
||||
int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string and parameter to string (qualifier) and return value
|
||||
(
|
||||
input.isQualifierObject() or
|
||||
input.isParameterDeref(getAStringParameter()) or
|
||||
input.isParameter(getAnIteratorParameter())
|
||||
input.isParameterDeref(getAStringParameterIndex()) or
|
||||
input.isParameter(getAnIteratorParameterIndex())
|
||||
) and
|
||||
(
|
||||
output.isQualifierObject() or
|
||||
@@ -101,15 +114,16 @@ class StdStringAssign extends TaintFunction {
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameter() {
|
||||
int getAStringParameterIndex() {
|
||||
getParameter(result).getType() instanceof PointerType or
|
||||
getParameter(result).getType() instanceof ReferenceType or
|
||||
getParameter(result).getType() = getDeclaringType().getTemplateArgument(0) // i.e. `std::basic_string::CharT`
|
||||
getParameter(result).getUnspecifiedType() =
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameter to string itself (qualifier) and return value
|
||||
input.isParameterDeref(getAStringParameter()) and
|
||||
input.isParameterDeref(getAStringParameterIndex()) and
|
||||
(
|
||||
output.isQualifierObject() or
|
||||
output.isReturnValueDeref()
|
||||
@@ -180,3 +194,20 @@ class StdStringSwap extends TaintFunction {
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` functions `at` and `operator[]`.
|
||||
*/
|
||||
class StdStringAt extends TaintFunction {
|
||||
StdStringAt() { this.hasQualifiedName("std", "basic_string", ["at", "operator[]"]) }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from qualifier to referenced return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ private newtype TFunctionInput =
|
||||
TInParameter(ParameterIndex i) or
|
||||
TInParameterDeref(ParameterIndex i) or
|
||||
TInQualifierObject() or
|
||||
TInQualifierAddress()
|
||||
TInQualifierAddress() or
|
||||
TInReturnValueDeref()
|
||||
|
||||
/**
|
||||
* An input to a function. This can be:
|
||||
@@ -106,6 +107,31 @@ class FunctionInput extends TFunctionInput {
|
||||
* (with type `C const *`) on entry to the function.
|
||||
*/
|
||||
predicate isQualifierAddress() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this is the input value pointed to by the return value of a
|
||||
* function, if the function returns a pointer, or the input value referred
|
||||
* to by the return value of a function, if the function returns a reference.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* char* getPointer();
|
||||
* float& getReference();
|
||||
* int getInt();
|
||||
* ```
|
||||
* - `isReturnValueDeref()` holds for the `FunctionInput` that represents the
|
||||
* value of `*getPointer()` (with type `char`).
|
||||
* - `isReturnValueDeref()` holds for the `FunctionInput` that represents the
|
||||
* value of `getReference()` (with type `float`).
|
||||
* - There is no `FunctionInput` of `getInt()` for which
|
||||
* `isReturnValueDeref()` holds because the return type of `getInt()` is
|
||||
* neither a pointer nor a reference.
|
||||
*
|
||||
* Note that data flows in through function return values are relatively
|
||||
* rare, but they do occur when a function returns a reference to itself,
|
||||
* part of itself, or one of its other inputs.
|
||||
*/
|
||||
predicate isReturnValueDeref() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,6 +225,34 @@ class InQualifierAddress extends FunctionInput, TInQualifierAddress {
|
||||
override predicate isQualifierAddress() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The input value pointed to by the return value of a function, if the
|
||||
* function returns a pointer, or the input value referred to by the return
|
||||
* value of a function, if the function returns a reference.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* char* getPointer();
|
||||
* float& getReference();
|
||||
* int getInt();
|
||||
* ```
|
||||
* - `InReturnValueDeref` represents the value of `*getPointer()` (with type
|
||||
* `char`).
|
||||
* - `InReturnValueDeref` represents the value of `getReference()` (with type
|
||||
* `float`).
|
||||
* - `InReturnValueDeref` does not represent the return value of `getInt()`
|
||||
* because the return type of `getInt()` is neither a pointer nor a reference.
|
||||
*
|
||||
* Note that data flows in through function return values are relatively
|
||||
* rare, but they do occur when a function returns a reference to itself,
|
||||
* part of itself, or one of its other inputs.
|
||||
*/
|
||||
class InReturnValueDeref extends FunctionInput, TInReturnValueDeref {
|
||||
override string toString() { result = "InReturnValueDeref" }
|
||||
|
||||
override predicate isReturnValueDeref() { any() }
|
||||
}
|
||||
|
||||
private newtype TFunctionOutput =
|
||||
TOutParameterDeref(ParameterIndex i) or
|
||||
TOutQualifierObject() or
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
* Provides a library for writing QL tests whose success or failure is based on expected results
|
||||
* embedded in the test source code as comments, rather than a `.expected` file.
|
||||
*
|
||||
* To add this framework to a new language:
|
||||
* - Add a file `InlineExpectationsTestPrivate.qll` that defines a `LineComment` class. This class
|
||||
* must support a `getContents` method that returns the contents of the given comment, _excluding_
|
||||
* the comment indicator itself. It should also define `toString` and `getLocation` as usual.
|
||||
*
|
||||
* To create a new inline expectations test:
|
||||
* - Declare a class that extends `InlineExpectationsTest`. In the characteristic predicate of the
|
||||
* new class, bind `this` to a unique string (usually the name of the test).
|
||||
@@ -13,7 +18,7 @@
|
||||
* `hasActualResult()`. Often this is just a single tag.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* ```ql
|
||||
* class ConstantValueTest extends InlineExpectationsTest {
|
||||
* ConstantValueTest() { this = "ConstantValueTest" }
|
||||
*
|
||||
@@ -23,11 +28,11 @@
|
||||
* }
|
||||
*
|
||||
* override predicate hasActualResult(
|
||||
* Location location, string element, string tag, string valuesasas
|
||||
* Location location, string element, string tag, string value
|
||||
* ) {
|
||||
* exists(Expr e |
|
||||
* tag = "const" and // The tag for this test.
|
||||
* valuesasas = e.getValue() and // The expected value. Will only hold for constant expressions.
|
||||
* value = e.getValue() and // The expected value. Will only hold for constant expressions.
|
||||
* location = e.getLocation() and // The location of the result to be reported.
|
||||
* element = e.toString() // The display text for the result.
|
||||
* )
|
||||
@@ -38,10 +43,10 @@
|
||||
* There is no need to write a `select` clause or query predicate. All of the differences between
|
||||
* expected results and actual results will be reported in the `failures()` query predicate.
|
||||
*
|
||||
* To annotate the test source code with an expected result, place a C++-style (`//`) comment on the
|
||||
* To annotate the test source code with an expected result, place a comment on the
|
||||
* same line as the expected result, with text of the following format as the body of the comment:
|
||||
*
|
||||
* `// $tag=expected-value`
|
||||
* `$tag=expected-value`
|
||||
*
|
||||
* Where `tag` is the value of the `tag` parameter from `hasActualResult()`, and `expected-value` is
|
||||
* the value of the `value` parameter from `hasActualResult()`. The `=expected-value` portion may be
|
||||
@@ -53,7 +58,7 @@
|
||||
* "Missing result: tag=expected-value".
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* ```cpp
|
||||
* int i = x + 5; // $const=5
|
||||
* int j = y + (7 - 3) // $const=7 $const=3 $const=4 // The result of the subtraction is a constant.
|
||||
* ```
|
||||
@@ -62,8 +67,8 @@
|
||||
* annotate that a particular expected result is known to be a false positive, or that a particular
|
||||
* missing result is known to be a false negative:
|
||||
*
|
||||
* `// $f+:tag=expected-value` // False positive
|
||||
* `// $f-:tag=expected-value` // False negative
|
||||
* `$f+:tag=expected-value` // False positive
|
||||
* `$f-:tag=expected-value` // False negative
|
||||
*
|
||||
* A false positive expectation is treated as any other expected result, except that if there is no
|
||||
* matching actual result, the message will be of the form "Fixed false positive: tag=value". A
|
||||
@@ -74,14 +79,14 @@
|
||||
* If the same result value is expected for two or more tags on the same line, there is a shorthand
|
||||
* notation available:
|
||||
*
|
||||
* `// $tag1,tag2=expected-value`
|
||||
* `$tag1,tag2=expected-value`
|
||||
*
|
||||
* is equivalent to:
|
||||
*
|
||||
* `// $tag1=expected-value $tag2=expected-value`
|
||||
* `$tag1=expected-value $tag2=expected-value`
|
||||
*/
|
||||
|
||||
import cpp
|
||||
private import InlineExpectationsTestPrivate
|
||||
|
||||
/**
|
||||
* Base class for tests with inline expectations. The test extends this class to provide the actual
|
||||
@@ -150,12 +155,12 @@ abstract class InlineExpectationsTest extends string {
|
||||
}
|
||||
|
||||
/**
|
||||
* RegEx pattern to match a comment containing one or more expected results. The comment must be a
|
||||
* C++-style (`//`) comment with `$` as its first non-whitespace character. Any subsequent character
|
||||
* RegEx pattern to match a comment containing one or more expected results. The comment must have
|
||||
* `$` as its first non-whitespace character. Any subsequent character
|
||||
* is treated as part of the expected results, except that the comment may contain a `//` sequence
|
||||
* to treat the remainder of the line as a regular (non-interpreted) comment.
|
||||
*/
|
||||
private string expectationCommentPattern() { result = "//\\s*(\\$(?:[^/]|/[^/])*)(?://.*)?" }
|
||||
private string expectationCommentPattern() { result = "\\s*(\\$(?:[^/]|/[^/])*)(?://.*)?" }
|
||||
|
||||
/**
|
||||
* RegEx pattern to match a single expected result, not including the leading `$`. It starts with an
|
||||
@@ -166,7 +171,7 @@ private string expectationPattern() {
|
||||
result = "(?:(f(?:\\+|-)):)?((?:[A-Za-z-_]+)(?:\\s*,\\s*[A-Za-z-_]+)*)(?:=(.*))?"
|
||||
}
|
||||
|
||||
private string getAnExpectation(CppStyleComment comment) {
|
||||
private string getAnExpectation(LineComment comment) {
|
||||
result = comment.getContents().regexpCapture(expectationCommentPattern(), 1).splitAt("$").trim() and
|
||||
result != ""
|
||||
}
|
||||
@@ -177,7 +182,7 @@ private newtype TFailureLocatable =
|
||||
) {
|
||||
test.hasActualResult(location, element, tag, value)
|
||||
} or
|
||||
TValidExpectation(CppStyleComment comment, string tag, string value, string knownFailure) {
|
||||
TValidExpectation(LineComment comment, string tag, string value, string knownFailure) {
|
||||
exists(string expectation |
|
||||
expectation = getAnExpectation(comment) and
|
||||
expectation.regexpMatch(expectationPattern()) and
|
||||
@@ -194,7 +199,7 @@ private newtype TFailureLocatable =
|
||||
)
|
||||
)
|
||||
} or
|
||||
TInvalidExpectation(CppStyleComment comment, string expectation) {
|
||||
TInvalidExpectation(LineComment comment, string expectation) {
|
||||
expectation = getAnExpectation(comment) and
|
||||
not expectation.regexpMatch(expectationPattern())
|
||||
}
|
||||
@@ -232,7 +237,7 @@ class ActualResult extends FailureLocatable, TActualResult {
|
||||
}
|
||||
|
||||
abstract private class Expectation extends FailureLocatable {
|
||||
CppStyleComment comment;
|
||||
LineComment comment;
|
||||
|
||||
override string toString() { result = comment.toString() }
|
||||
|
||||
|
||||
23
cpp/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll
Normal file
23
cpp/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll
Normal file
@@ -0,0 +1,23 @@
|
||||
import cpp
|
||||
|
||||
private newtype TLineComment = MkLineComment(CppStyleComment c)
|
||||
|
||||
/**
|
||||
* Represents a line comment in the CPP style.
|
||||
* Unlike the `CppStyleComment` class, however, the string returned by `getContents` does _not_
|
||||
* include the preceding comment marker (`//`).
|
||||
*/
|
||||
class LineComment extends TLineComment {
|
||||
CppStyleComment comment;
|
||||
|
||||
LineComment() { this = MkLineComment(comment) }
|
||||
|
||||
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
string getContents() { result = comment.getContents().suffix(2) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = comment.toString() }
|
||||
|
||||
/** Gets the location of this comment. */
|
||||
Location getLocation() { result = comment.getLocation() }
|
||||
}
|
||||
@@ -14,7 +14,6 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
| lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. |
|
||||
| lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. |
|
||||
|
||||
@@ -29,5 +29,4 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
| example.c:17:19:17:22 | {...} | example.c:26:19:26:24 | coords |
|
||||
| example.c:24:2:24:7 | coords [post update] | example.c:26:2:26:7 | coords |
|
||||
| example.c:24:2:24:7 | coords [post update] | example.c:26:19:26:24 | coords |
|
||||
| example.c:24:2:24:30 | ... = ... | example.c:24:9:24:9 | x [post update] |
|
||||
| example.c:24:13:24:18 | coords [post update] | example.c:24:2:24:7 | coords |
|
||||
| example.c:24:13:24:18 | coords [post update] | example.c:26:2:26:7 | coords |
|
||||
| example.c:24:13:24:18 | coords [post update] | example.c:26:19:26:24 | coords |
|
||||
| example.c:24:13:24:30 | ... = ... | example.c:24:2:24:30 | ... = ... |
|
||||
| example.c:24:13:24:30 | ... = ... | example.c:24:20:24:20 | y [post update] |
|
||||
| example.c:24:24:24:30 | ... + ... | example.c:24:13:24:30 | ... = ... |
|
||||
| example.c:26:2:26:25 | ... = ... | example.c:26:9:26:9 | x [post update] |
|
||||
| example.c:26:13:26:16 | call to getX | example.c:26:2:26:25 | ... = ... |
|
||||
| example.c:26:18:26:24 | ref arg & ... | example.c:26:2:26:7 | coords |
|
||||
| example.c:26:18:26:24 | ref arg & ... | example.c:26:19:26:24 | coords [inner post update] |
|
||||
|
||||
@@ -16,7 +16,6 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
| A.cpp:41:15:41:21 | new | ArgumentNode is missing PostUpdateNode. |
|
||||
| A.cpp:55:12:55:19 | new | ArgumentNode is missing PostUpdateNode. |
|
||||
|
||||
@@ -23,5 +23,4 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
|
||||
int source();
|
||||
void sink(int);
|
||||
void sink(class MyInt);
|
||||
void sink(class MyArray);
|
||||
|
||||
void test_pointer_deref_assignment()
|
||||
{
|
||||
int x = 0;
|
||||
int *p_x = &x;
|
||||
int *p2_x = &x;
|
||||
int &r_x = x;
|
||||
|
||||
*p_x = source();
|
||||
|
||||
sink(x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(*p_x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(*p2_x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(r_x); // tainted [DETECTED BY IR ONLY]
|
||||
}
|
||||
|
||||
void test_reference_deref_assignment()
|
||||
{
|
||||
int x = 0;
|
||||
int *p_x = &x;
|
||||
int &r_x = x;
|
||||
int &r2_x = x;
|
||||
|
||||
r_x = source();
|
||||
|
||||
sink(x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(*p_x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(r_x); // tainted
|
||||
sink(r2_x); // tainted [DETECTED BY IR ONLY]
|
||||
}
|
||||
|
||||
class MyInt
|
||||
{
|
||||
public:
|
||||
MyInt() : i(0) {}
|
||||
|
||||
int &get() { return i; }
|
||||
|
||||
MyInt &operator=(const int &other);
|
||||
MyInt &operator=(const MyInt &other);
|
||||
|
||||
int i;
|
||||
};
|
||||
|
||||
void test_myint_member_assignment()
|
||||
{
|
||||
MyInt mi;
|
||||
|
||||
mi.i = source();
|
||||
|
||||
sink(mi); // tainted [DETECTED BY IR ONLY]
|
||||
sink(mi.get()); // tainted
|
||||
}
|
||||
|
||||
void test_myint_method_assignment()
|
||||
{
|
||||
MyInt mi;
|
||||
|
||||
mi.get() = source();
|
||||
|
||||
sink(mi); // tainted [DETECTED BY IR ONLY]
|
||||
sink(mi.get()); // tainted
|
||||
}
|
||||
|
||||
void test_myint_overloaded_assignment()
|
||||
{
|
||||
MyInt mi, mi2;
|
||||
|
||||
mi = source();
|
||||
mi2 = mi;
|
||||
|
||||
sink(mi); // tainted [NOT DETECTED]
|
||||
sink(mi.get()); // tainted [NOT DETECTED]
|
||||
sink(mi2); // tainted [NOT DETECTED]
|
||||
sink(mi2.get()); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
class MyArray
|
||||
{
|
||||
public:
|
||||
MyArray() : values({0}) {}
|
||||
|
||||
int &get(int i) { return values[i]; }
|
||||
|
||||
int &operator[](int i);
|
||||
|
||||
int values[10];
|
||||
};
|
||||
|
||||
void test_myarray_member_assignment()
|
||||
{
|
||||
MyArray ma;
|
||||
|
||||
ma.values[0] = source();
|
||||
|
||||
sink(ma.values[0]); // tainted
|
||||
}
|
||||
|
||||
void test_myarray_method_assignment()
|
||||
{
|
||||
MyArray ma;
|
||||
|
||||
ma.get(0) = source();
|
||||
|
||||
sink(ma.get(0)); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_myarray_overloaded_assignment()
|
||||
{
|
||||
MyArray ma, ma2;
|
||||
|
||||
ma[0] = source();
|
||||
ma2 = ma;
|
||||
|
||||
sink(ma[0]); // tainted [NOT DETECTED]
|
||||
sink(ma2[0]); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void sink(int *);
|
||||
|
||||
void test_array_reference_assignment()
|
||||
{
|
||||
int arr1[10] = {0};
|
||||
int arr2[10] = {0};
|
||||
int arr3[10] = {0};
|
||||
int &ref1 = arr1[5];
|
||||
int *ptr2, *ptr3;
|
||||
|
||||
ref1 = source();
|
||||
sink(ref1); // tainted
|
||||
sink(arr1[5]); // tainted [DETECTED BY IR ONLY]
|
||||
|
||||
ptr2 = &(arr2[5]);
|
||||
*ptr2 = source();
|
||||
sink(*ptr2); // tainted [DETECTED BY IR ONLY]
|
||||
sink(arr2[5]); // tainted [DETECTED BY IR ONLY]
|
||||
|
||||
ptr3 = arr3;
|
||||
ptr3[5] = source();
|
||||
sink(ptr3[5]); // tainted [DETECTED BY IR ONLY]
|
||||
sink(arr3[5]); // tainted [DETECTED BY IR ONLY]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,12 +8,14 @@ namespace std {
|
||||
|
||||
template<class I> struct iterator_traits;
|
||||
|
||||
template <class iterator_category,
|
||||
template <class Category,
|
||||
class value_type,
|
||||
class difference_type = ptrdiff_t,
|
||||
class pointer_type = value_type*,
|
||||
class reference_type = value_type&>
|
||||
struct iterator {
|
||||
typedef Category iterator_category;
|
||||
|
||||
iterator &operator++();
|
||||
iterator operator++(int);
|
||||
iterator &operator--();
|
||||
@@ -53,6 +55,9 @@ namespace std
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||
class basic_string {
|
||||
public:
|
||||
using value_type = charT;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
typedef typename Allocator::size_type size_type;
|
||||
static const size_type npos = -1;
|
||||
|
||||
@@ -73,6 +78,10 @@ namespace std
|
||||
const_iterator cbegin() const;
|
||||
const_iterator cend() const;
|
||||
|
||||
const_reference operator[](size_type pos) const;
|
||||
reference operator[](size_type pos);
|
||||
const_reference at(size_type n) const;
|
||||
reference at(size_type n);
|
||||
template<class T> basic_string& operator+=(const T& t);
|
||||
basic_string& operator+=(const charT* s);
|
||||
basic_string& append(const basic_string& str);
|
||||
@@ -152,6 +161,10 @@ namespace std {
|
||||
|
||||
vector& operator=(const vector& x);
|
||||
vector& operator=(vector&& x) noexcept/*(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value)*/;
|
||||
template<class InputIterator, class IteratorCategory = typename InputIterator::iterator_category> void assign(InputIterator first, InputIterator last);
|
||||
// use of `iterator_category` makes sure InputIterator is (probably) an iterator, and not an `int` or
|
||||
// similar that should match a different overload (SFINAE).
|
||||
void assign(size_type n, const T& u);
|
||||
|
||||
iterator begin() noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
|
||||
@@ -322,6 +322,33 @@ void test_string_substr()
|
||||
sink(b.substr(0, b.length())); // tainted
|
||||
}
|
||||
|
||||
void test_string_at()
|
||||
{
|
||||
std::string a("123");
|
||||
std::string b("123");
|
||||
std::string c("123");
|
||||
|
||||
sink(a);
|
||||
sink(b);
|
||||
sink(c);
|
||||
|
||||
a[0] = ns_char::source();
|
||||
b.at(0) = ns_char::source();
|
||||
c[0] = a[0];
|
||||
|
||||
sink(a); // tainted
|
||||
sink(b); // tainted
|
||||
sink(c); // tainted
|
||||
}
|
||||
|
||||
void test_string_data_more()
|
||||
{
|
||||
std::string str("123");
|
||||
|
||||
str.data()[1] = ns_char::source();
|
||||
sink(str); // tainted
|
||||
sink(str.data()); // tainted
|
||||
}
|
||||
void test_string_iterators() {
|
||||
// string append
|
||||
{
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
| arrayassignment.cpp:33:7:33:9 | r_x | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:57:10:57:12 | call to get | arrayassignment.cpp:54:9:54:14 | call to source |
|
||||
| arrayassignment.cpp:67:10:67:12 | call to get | arrayassignment.cpp:64:13:64:18 | call to source |
|
||||
| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source |
|
||||
| arrayassignment.cpp:135:7:135:10 | ref1 | arrayassignment.cpp:134:9:134:14 | call to source |
|
||||
| copyableclass.cpp:40:8:40:9 | s1 | copyableclass.cpp:34:22:34:27 | call to source |
|
||||
| copyableclass.cpp:41:8:41:9 | s2 | copyableclass.cpp:35:24:35:29 | call to source |
|
||||
| copyableclass.cpp:42:8:42:9 | s3 | copyableclass.cpp:34:22:34:27 | call to source |
|
||||
@@ -98,19 +103,24 @@
|
||||
| string.cpp:302:7:302:8 | s3 | string.cpp:290:17:290:22 | call to source |
|
||||
| string.cpp:311:9:311:12 | call to data | string.cpp:308:16:308:21 | call to source |
|
||||
| string.cpp:322:9:322:14 | call to substr | string.cpp:319:16:319:21 | call to source |
|
||||
| string.cpp:334:11:334:16 | call to append | string.cpp:329:18:329:23 | call to source |
|
||||
| string.cpp:335:8:335:9 | s1 | string.cpp:329:18:329:23 | call to source |
|
||||
| string.cpp:353:8:353:8 | call to operator* | string.cpp:345:18:345:23 | call to source |
|
||||
| string.cpp:354:13:354:13 | call to operator[] | string.cpp:345:18:345:23 | call to source |
|
||||
| string.cpp:367:8:367:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:368:8:368:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:370:8:370:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:372:8:372:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:375:8:375:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:378:8:378:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:380:8:380:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:382:8:382:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:386:8:386:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:339:7:339:7 | a | string.cpp:335:9:335:23 | call to source |
|
||||
| string.cpp:340:7:340:7 | b | string.cpp:336:12:336:26 | call to source |
|
||||
| string.cpp:341:7:341:7 | c | string.cpp:335:9:335:23 | call to source |
|
||||
| string.cpp:349:7:349:9 | str | string.cpp:348:18:348:32 | call to source |
|
||||
| string.cpp:350:11:350:14 | call to data | string.cpp:348:18:348:32 | call to source |
|
||||
| string.cpp:361:11:361:16 | call to append | string.cpp:356:18:356:23 | call to source |
|
||||
| string.cpp:362:8:362:9 | s1 | string.cpp:356:18:356:23 | call to source |
|
||||
| string.cpp:380:8:380:8 | call to operator* | string.cpp:372:18:372:23 | call to source |
|
||||
| string.cpp:381:13:381:13 | call to operator[] | string.cpp:372:18:372:23 | call to source |
|
||||
| string.cpp:394:8:394:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:395:8:395:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:397:8:397:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:399:8:399:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:402:8:402:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:405:8:405:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:407:8:407:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:409:8:409:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:413:8:413:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| 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 |
|
||||
@@ -220,9 +230,27 @@
|
||||
| vector.cpp:20:8:20:8 | x | vector.cpp:16:43:16:49 | source1 |
|
||||
| vector.cpp:28:8:28:8 | x | vector.cpp:16:43:16:49 | source1 |
|
||||
| vector.cpp:33:8:33:8 | x | vector.cpp:16:43:16:49 | source1 |
|
||||
| vector.cpp:52:7:52:8 | v2 | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:53:9:53:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:54:9:54:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:55:9:55:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:58:7:58:8 | v3 | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:59:9:59:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:60:9:60:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:61:9:61:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:64:7:64:8 | v4 | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:65:9:65:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:66:9:66:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:67:9:67:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:70:7:70:8 | v5 | vector.cpp:69:15:69:20 | call to source |
|
||||
| vector.cpp:71:10:71:14 | call to front | vector.cpp:69:15:69:20 | call to source |
|
||||
| vector.cpp:72:10:72:13 | call to back | vector.cpp:69:15:69:20 | call to source |
|
||||
| vector.cpp:75:7:75:8 | v6 | vector.cpp:74:17:74:22 | call to source |
|
||||
| vector.cpp:76:7:76:18 | access to array | vector.cpp:74:17:74:22 | call to source |
|
||||
| vector.cpp:97:7:97:8 | v9 | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:98:10:98:11 | call to at | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:99:10:99:11 | call to at | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:100:10:100:11 | call to at | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:109:7:109:8 | v1 | vector.cpp:106:15:106:20 | call to source |
|
||||
| vector.cpp:112:7:112:8 | v4 | vector.cpp:107:15:107:20 | call to source |
|
||||
| vector.cpp:117:7:117:8 | v1 | vector.cpp:106:15:106:20 | call to source |
|
||||
@@ -235,3 +263,17 @@
|
||||
| vector.cpp:139:7:139:8 | v1 | vector.cpp:126:15:126:20 | call to source |
|
||||
| vector.cpp:140:7:140:8 | v2 | vector.cpp:127:15:127:20 | call to source |
|
||||
| vector.cpp:141:7:141:8 | v3 | vector.cpp:128:15:128:20 | call to source |
|
||||
| vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source |
|
||||
| vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source |
|
||||
| vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source |
|
||||
| vector.cpp:242:7:242:8 | v2 | vector.cpp:238:17:238:30 | call to source |
|
||||
| vector.cpp:243:7:243:8 | v3 | vector.cpp:239:15:239:20 | call to source |
|
||||
| vector.cpp:273:8:273:9 | v7 | vector.cpp:269:18:269:31 | call to source |
|
||||
| vector.cpp:274:8:274:9 | v8 | vector.cpp:270:18:270:35 | call to source |
|
||||
| vector.cpp:275:8:275:9 | v9 | vector.cpp:271:18:271:34 | call to source |
|
||||
| vector.cpp:285:7:285:8 | v1 | vector.cpp:284:15:284:20 | call to source |
|
||||
| vector.cpp:286:10:286:13 | call to data | vector.cpp:284:15:284:20 | call to source |
|
||||
| vector.cpp:287:7:287:18 | access to array | vector.cpp:284:15:284:20 | call to source |
|
||||
| vector.cpp:290:7:290:8 | v2 | vector.cpp:289:17:289:30 | call to source |
|
||||
| vector.cpp:291:10:291:13 | call to data | vector.cpp:289:17:289:30 | call to source |
|
||||
| vector.cpp:292:7:292:18 | access to array | vector.cpp:289:17:289:30 | call to source |
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
| arrayassignment.cpp:16:7:16:7 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:17:7:17:10 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:18:7:18:11 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:19:7:19:9 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:31:7:31:7 | arrayassignment.cpp:29:8:29:13 | IR only |
|
||||
| arrayassignment.cpp:32:7:32:10 | arrayassignment.cpp:29:8:29:13 | IR only |
|
||||
| arrayassignment.cpp:34:7:34:10 | arrayassignment.cpp:29:8:29:13 | IR only |
|
||||
| arrayassignment.cpp:56:7:56:8 | arrayassignment.cpp:54:9:54:14 | IR only |
|
||||
| arrayassignment.cpp:57:10:57:12 | arrayassignment.cpp:54:9:54:14 | AST only |
|
||||
| arrayassignment.cpp:57:10:57:15 | arrayassignment.cpp:54:9:54:14 | IR only |
|
||||
| arrayassignment.cpp:66:7:66:8 | arrayassignment.cpp:64:13:64:18 | IR only |
|
||||
| arrayassignment.cpp:67:10:67:12 | arrayassignment.cpp:64:13:64:18 | AST only |
|
||||
| arrayassignment.cpp:67:10:67:15 | arrayassignment.cpp:64:13:64:18 | IR only |
|
||||
| arrayassignment.cpp:136:7:136:13 | arrayassignment.cpp:134:9:134:14 | IR only |
|
||||
| arrayassignment.cpp:140:7:140:11 | arrayassignment.cpp:139:10:139:15 | IR only |
|
||||
| arrayassignment.cpp:141:7:141:13 | arrayassignment.cpp:139:10:139:15 | IR only |
|
||||
| arrayassignment.cpp:145:7:145:13 | arrayassignment.cpp:144:12:144:17 | IR only |
|
||||
| arrayassignment.cpp:146:7:146:13 | arrayassignment.cpp:144:12:144:17 | IR only |
|
||||
| copyableclass.cpp:40:8:40:9 | copyableclass.cpp:34:22:34:27 | AST only |
|
||||
| copyableclass.cpp:41:8:41:9 | copyableclass.cpp:35:24:35:29 | AST only |
|
||||
| copyableclass.cpp:42:8:42:9 | copyableclass.cpp:34:22:34:27 | AST only |
|
||||
@@ -95,19 +113,24 @@
|
||||
| string.cpp:302:7:302:8 | string.cpp:290:17:290:22 | AST only |
|
||||
| string.cpp:311:9:311:12 | string.cpp:308:16:308:21 | AST only |
|
||||
| string.cpp:322:9:322:14 | string.cpp:319:16:319:21 | AST only |
|
||||
| string.cpp:334:11:334:16 | string.cpp:329:18:329:23 | AST only |
|
||||
| string.cpp:335:8:335:9 | string.cpp:329:18:329:23 | AST only |
|
||||
| string.cpp:353:8:353:8 | string.cpp:345:18:345:23 | AST only |
|
||||
| string.cpp:354:13:354:13 | string.cpp:345:18:345:23 | AST only |
|
||||
| string.cpp:367:8:367:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:368:8:368:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:370:8:370:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:372:8:372:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:375:8:375:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:378:8:378:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:380:8:380:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:382:8:382:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:386:8:386:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:339:7:339:7 | string.cpp:335:9:335:23 | AST only |
|
||||
| string.cpp:340:7:340:7 | string.cpp:336:12:336:26 | AST only |
|
||||
| string.cpp:341:7:341:7 | string.cpp:335:9:335:23 | AST only |
|
||||
| string.cpp:349:7:349:9 | string.cpp:348:18:348:32 | AST only |
|
||||
| string.cpp:350:11:350:14 | string.cpp:348:18:348:32 | AST only |
|
||||
| string.cpp:361:11:361:16 | string.cpp:356:18:356:23 | AST only |
|
||||
| string.cpp:362:8:362:9 | string.cpp:356:18:356:23 | AST only |
|
||||
| string.cpp:380:8:380:8 | string.cpp:372:18:372:23 | AST only |
|
||||
| string.cpp:381:13:381:13 | string.cpp:372:18:372:23 | AST only |
|
||||
| string.cpp:394:8:394:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:395:8:395:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:397:8:397:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:399:8:399:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:402:8:402:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:405:8:405:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:407:8:407:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:409:8:409:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:413:8:413:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only |
|
||||
| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only |
|
||||
| structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only |
|
||||
@@ -155,9 +178,27 @@
|
||||
| vector.cpp:20:8:20:8 | vector.cpp:16:43:16:49 | AST only |
|
||||
| vector.cpp:28:8:28:8 | vector.cpp:16:43:16:49 | AST only |
|
||||
| vector.cpp:33:8:33:8 | vector.cpp:16:43:16:49 | AST only |
|
||||
| vector.cpp:52:7:52:8 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:53:9:53:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:54:9:54:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:55:9:55:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:58:7:58:8 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:59:9:59:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:60:9:60:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:61:9:61:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:64:7:64:8 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:65:9:65:9 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:66:9:66:9 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:67:9:67:9 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:70:7:70:8 | vector.cpp:69:15:69:20 | AST only |
|
||||
| vector.cpp:71:10:71:14 | vector.cpp:69:15:69:20 | AST only |
|
||||
| vector.cpp:72:10:72:13 | vector.cpp:69:15:69:20 | AST only |
|
||||
| vector.cpp:75:7:75:8 | vector.cpp:74:17:74:22 | AST only |
|
||||
| vector.cpp:76:7:76:18 | vector.cpp:74:17:74:22 | AST only |
|
||||
| vector.cpp:97:7:97:8 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:98:10:98:11 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:99:10:99:11 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:100:10:100:11 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:109:7:109:8 | vector.cpp:106:15:106:20 | AST only |
|
||||
| vector.cpp:112:7:112:8 | vector.cpp:107:15:107:20 | AST only |
|
||||
| vector.cpp:117:7:117:8 | vector.cpp:106:15:106:20 | AST only |
|
||||
@@ -170,3 +211,18 @@
|
||||
| vector.cpp:139:7:139:8 | vector.cpp:126:15:126:20 | AST only |
|
||||
| vector.cpp:140:7:140:8 | vector.cpp:127:15:127:20 | AST only |
|
||||
| vector.cpp:141:7:141:8 | vector.cpp:128:15:128:20 | AST only |
|
||||
| vector.cpp:162:8:162:15 | vector.cpp:161:14:161:19 | IR only |
|
||||
| vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only |
|
||||
| vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only |
|
||||
| vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only |
|
||||
| vector.cpp:242:7:242:8 | vector.cpp:238:17:238:30 | AST only |
|
||||
| vector.cpp:243:7:243:8 | vector.cpp:239:15:239:20 | AST only |
|
||||
| vector.cpp:273:8:273:9 | vector.cpp:269:18:269:31 | AST only |
|
||||
| vector.cpp:274:8:274:9 | vector.cpp:270:18:270:35 | AST only |
|
||||
| vector.cpp:275:8:275:9 | vector.cpp:271:18:271:34 | AST only |
|
||||
| vector.cpp:285:7:285:8 | vector.cpp:284:15:284:20 | AST only |
|
||||
| vector.cpp:286:10:286:13 | vector.cpp:284:15:284:20 | AST only |
|
||||
| vector.cpp:287:7:287:18 | vector.cpp:284:15:284:20 | AST only |
|
||||
| vector.cpp:290:7:290:8 | vector.cpp:289:17:289:30 | AST only |
|
||||
| vector.cpp:291:10:291:13 | vector.cpp:289:17:289:30 | AST only |
|
||||
| vector.cpp:292:7:292:18 | vector.cpp:289:17:289:30 | AST only |
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
| arrayassignment.cpp:16:7:16:7 | x | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:17:7:17:10 | * ... | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:18:7:18:11 | * ... | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:19:7:19:9 | (reference dereference) | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:31:7:31:7 | x | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:32:7:32:10 | * ... | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:33:7:33:9 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:34:7:34:10 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:56:7:56:8 | mi | arrayassignment.cpp:54:9:54:14 | call to source |
|
||||
| arrayassignment.cpp:57:10:57:15 | (reference dereference) | arrayassignment.cpp:54:9:54:14 | call to source |
|
||||
| arrayassignment.cpp:66:7:66:8 | mi | arrayassignment.cpp:64:13:64:18 | call to source |
|
||||
| arrayassignment.cpp:67:10:67:15 | (reference dereference) | arrayassignment.cpp:64:13:64:18 | call to source |
|
||||
| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source |
|
||||
| arrayassignment.cpp:135:7:135:10 | (reference dereference) | arrayassignment.cpp:134:9:134:14 | call to source |
|
||||
| arrayassignment.cpp:136:7:136:13 | access to array | arrayassignment.cpp:134:9:134:14 | call to source |
|
||||
| arrayassignment.cpp:140:7:140:11 | * ... | arrayassignment.cpp:139:10:139:15 | call to source |
|
||||
| arrayassignment.cpp:141:7:141:13 | access to array | arrayassignment.cpp:139:10:139:15 | call to source |
|
||||
| arrayassignment.cpp:145:7:145:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source |
|
||||
| arrayassignment.cpp:146:7:146:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source |
|
||||
| format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | call to source |
|
||||
| format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source |
|
||||
| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source |
|
||||
@@ -79,3 +98,4 @@
|
||||
| taint.cpp:465:7:465:7 | x | taint.cpp:462:6:462:11 | call to source |
|
||||
| taint.cpp:470:7:470:7 | x | taint.cpp:462:6:462:11 | call to source |
|
||||
| taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 |
|
||||
| vector.cpp:162:8:162:15 | access to array | vector.cpp:161:14:161:19 | call to source |
|
||||
|
||||
@@ -5,9 +5,9 @@ using namespace std;
|
||||
|
||||
int source();
|
||||
|
||||
namespace ns_char
|
||||
namespace ns_int
|
||||
{
|
||||
char source();
|
||||
int source();
|
||||
}
|
||||
|
||||
void sink(int);
|
||||
@@ -49,22 +49,22 @@ void test_element_taint(int x) {
|
||||
sink(v1.back());
|
||||
|
||||
v2[0] = source();
|
||||
sink(v2); // tainted [NOT DETECTED]
|
||||
sink(v2[0]); // tainted [NOT DETECTED]
|
||||
sink(v2[1]);
|
||||
sink(v2); // tainted
|
||||
sink(v2[0]); // tainted
|
||||
sink(v2[1]); // [FALSE POSITIVE]
|
||||
sink(v2[x]); // potentially tainted
|
||||
|
||||
v3 = v2;
|
||||
sink(v3); // tainted [NOT DETECTED]
|
||||
sink(v3[0]); // tainted [NOT DETECTED]
|
||||
sink(v3[1]);
|
||||
sink(v3); // tainted
|
||||
sink(v3[0]); // tainted
|
||||
sink(v3[1]); // [FALSE POSITIVE]
|
||||
sink(v3[x]); // potentially tainted
|
||||
|
||||
v4[x] = source();
|
||||
sink(v4); // tainted [NOT DETECTED]
|
||||
sink(v4); // tainted
|
||||
sink(v4[0]); // potentially tainted
|
||||
sink(v4[1]); // potentially tainted
|
||||
sink(v4[x]); // tainted [NOT DETECTED]
|
||||
sink(v4[x]); // tainted
|
||||
|
||||
v5.push_back(source());
|
||||
sink(v5); // tainted
|
||||
@@ -72,8 +72,8 @@ void test_element_taint(int x) {
|
||||
sink(v5.back()); // tainted
|
||||
|
||||
v6.data()[2] = source();
|
||||
sink(v6); // tainted [NOT DETECTED]
|
||||
sink(v6.data()[2]); // tainted [NOT DETECTED]
|
||||
sink(v6); // tainted
|
||||
sink(v6.data()[2]); // tainted
|
||||
|
||||
{
|
||||
const std::vector<int> &v7c = v7; // (workaround because our iterators don't convert to const_iterator)
|
||||
@@ -87,17 +87,17 @@ void test_element_taint(int x) {
|
||||
{
|
||||
const std::vector<int> &v8c = v8;
|
||||
std::vector<int>::const_iterator it = v8c.begin();
|
||||
v8.insert(it, 10, ns_char::source());
|
||||
v8.insert(it, 10, ns_int::source());
|
||||
}
|
||||
sink(v8); // tainted [NOT DETECTED]
|
||||
sink(v8.front()); // tainted [NOT DETECTED]
|
||||
sink(v8.back());
|
||||
|
||||
v9.at(x) = source();
|
||||
sink(v9); // tainted [NOT DETECTED]
|
||||
sink(v9); // tainted
|
||||
sink(v9.at(0)); // potentially tainted
|
||||
sink(v9.at(1)); // potentially tainted
|
||||
sink(v9.at(x)); // tainted [NOT DETECTED]
|
||||
sink(v9.at(x)); // tainted
|
||||
}
|
||||
|
||||
void test_vector_swap() {
|
||||
@@ -141,3 +141,153 @@ void test_vector_clear() {
|
||||
sink(v3); // [FALSE POSITIVE]
|
||||
sink(v4);
|
||||
}
|
||||
|
||||
struct MyPair
|
||||
{
|
||||
int a, b;
|
||||
};
|
||||
|
||||
struct MyVectorContainer
|
||||
{
|
||||
std::vector<int> vs;
|
||||
};
|
||||
|
||||
void test_nested_vectors()
|
||||
{
|
||||
{
|
||||
int aa[10][20] = {0};
|
||||
|
||||
sink(aa[0][0]);
|
||||
aa[0][0] = source();
|
||||
sink(aa[0][0]); // tainted [IR ONLY]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<std::vector<int> > bb(30);
|
||||
|
||||
bb[0].push_back(0);
|
||||
sink(bb[0][0]);
|
||||
bb[0][0] = source();
|
||||
sink(bb[0][0]); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> cc[40];
|
||||
|
||||
cc[0].push_back(0);
|
||||
sink(cc[0][0]);
|
||||
cc[0][0] = source();
|
||||
sink(cc[0][0]); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<MyPair> dd;
|
||||
MyPair mp = {0, 0};
|
||||
|
||||
dd.push_back(mp);
|
||||
sink(dd[0].a);
|
||||
sink(dd[0].b);
|
||||
dd[0].a = source();
|
||||
sink(dd[0].a); // tainted [NOT DETECTED]
|
||||
sink(dd[0].b);
|
||||
}
|
||||
|
||||
{
|
||||
MyVectorContainer ee;
|
||||
|
||||
ee.vs.push_back(0);
|
||||
sink(ee.vs[0]);
|
||||
ee.vs[0] = source();
|
||||
sink(ee.vs[0]); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<MyVectorContainer> ff;
|
||||
MyVectorContainer mvc;
|
||||
|
||||
mvc.vs.push_back(0);
|
||||
ff.push_back(mvc);
|
||||
sink(ff[0].vs[0]);
|
||||
ff[0].vs[0] = source();
|
||||
sink(ff[0].vs[0]); // tainted [NOT DETECTED]
|
||||
}
|
||||
}
|
||||
|
||||
void sink(std::vector<int>::iterator &);
|
||||
|
||||
typedef int myInt;
|
||||
typedef float myFloat;
|
||||
|
||||
namespace ns_myFloat
|
||||
{
|
||||
myFloat source();
|
||||
}
|
||||
|
||||
namespace ns_ci_ptr
|
||||
{
|
||||
const int *source();
|
||||
}
|
||||
|
||||
void sink(std::vector<myFloat> &);
|
||||
void sink(std::vector<const int *> &);
|
||||
|
||||
void test_vector_assign() {
|
||||
std::vector<int> v1, v2, v3;
|
||||
|
||||
v1.assign(100, 0);
|
||||
v2.assign(100, ns_int::source());
|
||||
v3.push_back(source());
|
||||
|
||||
sink(v1);
|
||||
sink(v2); // tainted
|
||||
sink(v3); // tainted
|
||||
|
||||
{
|
||||
std::vector<int> v4, v5, v6;
|
||||
std::vector<int>::iterator i1, i2;
|
||||
|
||||
v4.assign(v1.begin(), v1.end());
|
||||
v5.assign(v3.begin(), v3.end());
|
||||
i1 = v3.begin();
|
||||
i1++;
|
||||
i2 = i1;
|
||||
i2++;
|
||||
v6.assign(i1, i2);
|
||||
|
||||
sink(v4);
|
||||
sink(v5); // tainted [NOT DETECTED]
|
||||
sink(i1); // tainted [NOT DETECTED]
|
||||
sink(i2); // tainted [NOT DETECTED]
|
||||
sink(v6); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<myInt> v7;
|
||||
std::vector<myFloat> v8;
|
||||
std::vector<const int *> v9;
|
||||
|
||||
v7.assign(100, ns_int::source());
|
||||
v8.assign(100, ns_myFloat::source());
|
||||
v9.assign(100, ns_ci_ptr::source());
|
||||
|
||||
sink(v7); // tainted
|
||||
sink(v8); // tainted
|
||||
sink(v9); // tainted
|
||||
}
|
||||
}
|
||||
|
||||
void sink(int *);
|
||||
|
||||
void test_data_more() {
|
||||
std::vector<int> v1, v2;
|
||||
|
||||
v1.push_back(source());
|
||||
sink(v1); // tainted
|
||||
sink(v1.data()); // tainted
|
||||
sink(v1.data()[2]); // tainted
|
||||
|
||||
*(v2.data()) = ns_int::source();
|
||||
sink(v2); // tainted
|
||||
sink(v2.data()); // tainted
|
||||
sink(v2.data()[2]); // tainted
|
||||
}
|
||||
|
||||
10
cpp/ql/test/library-tests/specifiers2/cpp20.cpp
Normal file
10
cpp/ql/test/library-tests/specifiers2/cpp20.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// semmle-extractor-options: --edg --clang --edg --c++20
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
class TestConstexpr {
|
||||
constexpr int member_constexpr() { return 0; } // not const in C++ >= 14
|
||||
constexpr int member_const_constexpr() const { return 0; }
|
||||
};
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -1,5 +1,22 @@
|
||||
| Class | specifiers2pp.cpp:8:7:8:13 | MyClass | MyClass | abstract |
|
||||
| Class | specifiers2pp.cpp:24:7:24:14 | MyClass2 | MyClass2 | abstract |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | declared_constexpr |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | inline |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | is_constexpr |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | private |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | const |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | declared_constexpr |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | inline |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | is_constexpr |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | private |
|
||||
| Function | specifiers2.c:11:6:11:6 | f | f | extern |
|
||||
| Function | specifiers2.c:12:13:12:13 | f | f | extern |
|
||||
| Function | specifiers2.c:13:13:13:13 | f | f | extern |
|
||||
@@ -79,6 +96,24 @@
|
||||
| Function | specifiers2pp.cpp:41:16:41:23 | someFun2 | someFun2 | extern |
|
||||
| Function | specifiers2pp.cpp:43:9:43:16 | someFun3 | someFun3 | extern |
|
||||
| Function | specifiers2pp.cpp:44:16:44:23 | someFun4 | someFun4 | static |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | const |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | declared_constexpr |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | inline |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | private |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | const |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | declared_constexpr |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | inline |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | private |
|
||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | c_linkage |
|
||||
|
||||
@@ -58,3 +58,8 @@ template<typename T> using Const = const T;
|
||||
using Const_int = Const<int>;
|
||||
|
||||
typedef volatile Const_int volatile_Const_int;
|
||||
|
||||
class TestConstexpr {
|
||||
constexpr int member_constexpr() { return 0; } // const in C++11
|
||||
constexpr int member_const_constexpr() const { return 0; }
|
||||
};
|
||||
|
||||
@@ -60,7 +60,6 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
| builtin.cpp:15:31:15:35 | * ... | ArgumentNode is missing PostUpdateNode. |
|
||||
| conditional_destructors.cpp:30:9:30:13 | call to C1 | ArgumentNode is missing PostUpdateNode. |
|
||||
|
||||
@@ -1473,5 +1473,4 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
| a.c:4:5:4:6 | definition of is | array of {int} | 1 |
|
||||
| a.h:2:12:2:13 | declaration of is | array of 4 {int} | 1 |
|
||||
| file://:0:0:0:0 | definition of fp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | definition of gp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | definition of overflow_arg_area | pointer to {void} | 1 |
|
||||
| file://:0:0:0:0 | definition of reg_save_area | pointer to {void} | 1 |
|
||||
5
cpp/ql/test/library-tests/variables/global/vardecl.ql
Normal file
5
cpp/ql/test/library-tests/variables/global/vardecl.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from VariableDeclarationEntry vd, Type t
|
||||
where t = vd.getType()
|
||||
select vd, t.explain(), count(Type u | u = vd.getType())
|
||||
@@ -1,5 +1,4 @@
|
||||
| a.c:4:5:4:6 | is | array of 4 {int} | 2 |
|
||||
| a.c:4:5:4:6 | is | array of {int} | 2 |
|
||||
| a.c:4:5:4:6 | is | array of {int} | 1 |
|
||||
| file://:0:0:0:0 | fp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | gp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | overflow_arg_area | pointer to {void} | 1 |
|
||||
|
||||
Reference in New Issue
Block a user