Merge branch 'main' into toctou2

This commit is contained in:
Geoffrey White 2021-07-21 16:21:29 +01:00
Родитель 473198a6ef 73ee7409f6
Коммит fa0f5d08a2
1584 изменённых файлов: 105474 добавлений и 28480 удалений

Просмотреть файл

@ -49,19 +49,23 @@ jobs:
gh release download --repo "github/codeql-cli-binaries" --pattern "codeql-linux64.zip"
- name: Unzip CodeQL CLI
run: unzip -d codeql-cli codeql-linux64.zip
- name: Generate CSV files on merge and base of the PR
- name: Generate CSV files on merge commit of the PR
run: |
echo "Running generator on merge"
PATH="$PATH:codeql-cli/codeql" python merge/misc/scripts/library-coverage/generate-report.py ci merge merge
mkdir out_merge
cp framework-coverage-*.csv out_merge/
cp framework-coverage-*.rst out_merge/
- name: Generate CSV files on base commit of the PR
run: |
echo "Running generator on base"
PATH="$PATH:codeql-cli/codeql" python base/misc/scripts/library-coverage/generate-report.py ci base base
mkdir out_base
cp framework-coverage-*.csv out_base/
cp framework-coverage-*.rst out_base/
- name: Generate diff of coverage reports
run: |
python base/misc/scripts/library-coverage/compare-folders.py out_base out_merge comparison.md
- name: Upload CSV package list
uses: actions/upload-artifact@v2
with:
@ -76,6 +80,12 @@ jobs:
path: |
out_base/framework-coverage-*.csv
out_base/framework-coverage-*.rst
- name: Upload comparison results
uses: actions/upload-artifact@v2
with:
name: comparison
path: |
comparison.md
- name: Save PR number
run: |
mkdir -p pr

35
.github/workflows/csv-coverage-pr-comment.yml поставляемый
Просмотреть файл

@ -26,40 +26,9 @@ jobs:
with:
python-version: 3.8
# download artifacts from the PR job:
- name: Download artifact - MERGE
- name: Check coverage difference file and comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RUN_ID: ${{ github.event.workflow_run.id }}
run: |
gh run download --name "csv-framework-coverage-merge" --dir "out_merge" "$RUN_ID"
- name: Download artifact - BASE
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RUN_ID: ${{ github.event.workflow_run.id }}
run: |
gh run download --name "csv-framework-coverage-base" --dir "out_base" "$RUN_ID"
- name: Download artifact - PR
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RUN_ID: ${{ github.event.workflow_run.id }}
run: |
gh run download --name "pr" --dir "pr" "$RUN_ID"
- name: Check coverage files
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RUN_ID: ${{ github.event.workflow_run.id }}
run: |
PR=$(cat "pr/NR")
python misc/scripts/library-coverage/compare-files-comment-pr.py \
out_base out_merge comparison.md "$GITHUB_REPOSITORY" "$PR" "$RUN_ID"
- name: Upload comparison results
uses: actions/upload-artifact@v2
with:
name: comparison
path: |
comparison.md
python misc/scripts/library-coverage/comment-pr.py "$GITHUB_REPOSITORY" "$RUN_ID"

44
.github/workflows/csv-coverage-update.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,44 @@
name: Update framework coverage reports
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
jobs:
update:
name: Update framework coverage report
if: github.event.repository.fork == false
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
run: echo "$GITHUB_CONTEXT"
- name: Clone self (github/codeql)
uses: actions/checkout@v2
with:
path: ql
fetch-depth: 0
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Download CodeQL CLI
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release download --repo "github/codeql-cli-binaries" --pattern "codeql-linux64.zip"
- name: Unzip CodeQL CLI
run: unzip -d codeql-cli codeql-linux64.zip
- name: Generate coverage files
run: |
PATH="$PATH:codeql-cli/codeql" python ql/misc/scripts/library-coverage/generate-report.py ci ql ql
- name: Create pull request with changes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python ql/misc/scripts/library-coverage/create-pr.py ql "$GITHUB_REPOSITORY"

Просмотреть файл

@ -17,3 +17,9 @@
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @github/codeql-java @github/codeql-go
/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @github/codeql-java @github/codeql-go
/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @github/codeql-java @github/codeql-go
# CodeQL tools and associated docs
/docs/codeql-cli/ @github/codeql-cli-reviewers
/docs/codeql-for-visual-studio-code/ @github/codeql-vscode-reviewers
/docs/ql-language-reference/ @github/codeql-frontend-reviewers
/docs/query-*-style-guide.md @github/codeql-analysis-reviewers

Просмотреть файл

@ -448,5 +448,17 @@
"SensitiveDataHeuristics Python/JS": [
"javascript/ql/src/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
"python/ql/src/semmle/python/security/internal/SensitiveDataHeuristics.qll"
],
"ReDoS Util Python/JS": [
"javascript/ql/src/semmle/javascript/security/performance/ReDoSUtil.qll",
"python/ql/src/semmle/python/security/performance/ReDoSUtil.qll"
],
"ReDoS Exponential Python/JS": [
"javascript/ql/src/semmle/javascript/security/performance/ExponentialBackTracking.qll",
"python/ql/src/semmle/python/security/performance/ExponentialBackTracking.qll"
],
"ReDoS Polynomial Python/JS": [
"javascript/ql/src/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
"python/ql/src/semmle/python/security/performance/SuperlinearBackTracking.qll"
]
}

Просмотреть файл

@ -0,0 +1,2 @@
lgtm,codescanning
* The DataFlow libraries have been augmented with support for `Configuration`-specific in-place read steps at, for example, sinks and custom taint steps. This means that it is now possible to specify sinks that accept flow with non-empty access paths.

Просмотреть файл

@ -0,0 +1,2 @@
lgtm
* The 'Uncontrolled data in arithmetic expression' (cpp/uncontrolled-arithmetic) query now recognizes more sources of randomness.

Просмотреть файл

@ -0,0 +1,2 @@
lgtm,codescanning
* The 'Wrong type of arguments to formatting function' (cpp/wrong-type-format-argument) query is now more accepting of the string and character formatting differences between Microsoft and non-Microsoft platforms. There are now fewer false positive results.

Просмотреть файл

@ -7,10 +7,6 @@
import cpp
class AnonymousCompilation extends Compilation {
override string toString() { result = "<compilation>" }
}
string describe(Compilation c) {
if c.getArgument(1) = "--mimic"
then result = "compiler invocation " + concat(int i | i > 1 | c.getArgument(i), " " order by i)
@ -19,4 +15,4 @@ string describe(Compilation c) {
from Compilation c
where not c.normalTermination()
select c, "Extraction aborted for " + describe(c), 2
select "Extraction aborted for " + describe(c)

Просмотреть файл

@ -19,28 +19,32 @@ import cpp
* Holds if the argument corresponding to the `pos` conversion specifier
* of `ffc` is expected to have type `expected`.
*/
pragma[noopt]
private predicate formattingFunctionCallExpectedType(
FormattingFunctionCall ffc, int pos, Type expected
) {
exists(FormattingFunction f, int i, FormatLiteral fl |
ffc instanceof FormattingFunctionCall and
ffc.getTarget() = f and
f.getFormatParameterIndex() = i and
ffc.getArgument(i) = fl and
fl.getConversionType(pos) = expected
)
ffc.getFormat().(FormatLiteral).getConversionType(pos) = expected
}
/**
* Holds if the argument corresponding to the `pos` conversion specifier
* of `ffc` is expected to have type `expected` and the corresponding
* argument `arg` has type `actual`.
* of `ffc` could alternatively have type `expected`, for example on a different
* platform.
*/
private predicate formattingFunctionCallAlternateType(
FormattingFunctionCall ffc, int pos, Type expected
) {
ffc.getFormat().(FormatLiteral).getConversionTypeAlternate(pos) = expected
}
/**
* Holds if the argument corresponding to the `pos` conversion specifier
* of `ffc` is `arg` and has type `actual`.
*/
pragma[noopt]
predicate formatArgType(FormattingFunctionCall ffc, int pos, Type expected, Expr arg, Type actual) {
predicate formattingFunctionCallActualType(
FormattingFunctionCall ffc, int pos, Expr arg, Type actual
) {
exists(Expr argConverted |
formattingFunctionCallExpectedType(ffc, pos, expected) and
ffc.getConversionArgument(pos) = arg and
argConverted = arg.getFullyConverted() and
actual = argConverted.getType()
@ -72,7 +76,8 @@ class ExpectedType extends Type {
ExpectedType() {
exists(Type t |
(
formatArgType(_, _, t, _, _) or
formattingFunctionCallExpectedType(_, _, t) or
formattingFunctionCallAlternateType(_, _, t) or
formatOtherArgType(_, _, t, _, _)
) and
this = t.getUnspecifiedType()
@ -91,7 +96,11 @@ class ExpectedType extends Type {
*/
predicate trivialConversion(ExpectedType expected, Type actual) {
exists(Type exp, Type act |
formatArgType(_, _, exp, _, act) and
(
formattingFunctionCallExpectedType(_, _, exp) or
formattingFunctionCallAlternateType(_, _, exp)
) and
formattingFunctionCallActualType(_, _, _, act) and
expected = exp.getUnspecifiedType() and
actual = act.getUnspecifiedType()
) and
@ -146,9 +155,13 @@ int sizeof_IntType() { exists(IntType it | result = it.getSize()) }
from FormattingFunctionCall ffc, int n, Expr arg, Type expected, Type actual
where
(
formatArgType(ffc, n, expected, arg, actual) and
formattingFunctionCallExpectedType(ffc, n, expected) and
formattingFunctionCallActualType(ffc, n, arg, actual) and
not exists(Type anyExpected |
formatArgType(ffc, n, anyExpected, arg, actual) and
(
formattingFunctionCallExpectedType(ffc, n, anyExpected) or
formattingFunctionCallAlternateType(ffc, n, anyExpected)
) and
trivialConversion(anyExpected.getUnspecifiedType(), actual.getUnspecifiedType())
)
or

Просмотреть файл

@ -41,7 +41,7 @@ DeclStmt declWithNoInit(LocalVariable v) {
result.getADeclaration() = v and
not exists(v.getInitializer()) and
/* The type of the variable is not stack-allocated. */
not allocatedType(v.getType())
exists(Type t | t = v.getType() | not allocatedType(t))
}
class UninitialisedLocalReachability extends StackVariableReachability {

Просмотреть файл

@ -9,7 +9,6 @@
* @tags reliability
* external/cwe/cwe-573
* external/cwe/cwe-252
* @opaque-id SM02344
* @microsoft.severity Important
*/

Просмотреть файл

@ -2,7 +2,7 @@
* @name User-controlled data in arithmetic expression
* @description Arithmetic operations on user-controlled data that is
* not validated can cause overflows.
* @kind problem
* @kind path-problem
* @problem.severity warning
* @security-severity 8.6
* @precision low
@ -16,22 +16,39 @@ import cpp
import semmle.code.cpp.security.Overflow
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.TaintTracking
import TaintedWithPath
import Bounded
from Expr origin, Operation op, Expr e, string effect
where
isUserInput(origin, _) and
tainted(origin, e) and
op.getAnOperand() = e and
(
bindingset[op]
predicate missingGuard(Operation op, Expr e, string effect) {
missingGuardAgainstUnderflow(op, e) and effect = "underflow"
or
missingGuardAgainstOverflow(op, e) and effect = "overflow"
or
not e instanceof VariableAccess and effect = "overflow"
) and
(
}
class Configuration extends TaintTrackingConfiguration {
override predicate isSink(Element e) {
exists(Operation op |
missingGuard(op, e, _) and
op.getAnOperand() = e
|
op instanceof UnaryArithmeticOperation or
op instanceof BinaryArithmeticOperation
)
select e, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
origin, "User-provided value"
}
override predicate isBarrier(Expr e) {
super.isBarrier(e) or bounded(e) or e.getUnspecifiedType().(IntegralType).getSize() <= 1
}
}
from Expr origin, Expr e, string effect, PathNode sourceNode, PathNode sinkNode, Operation op
where
taintedWithPath(origin, e, sourceNode, sinkNode) and
op.getAnOperand() = e and
missingGuard(op, e, effect)
select e, sourceNode, sinkNode,
"$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", origin,
"User-provided value"

Просмотреть файл

@ -15,113 +15,61 @@
import cpp
import semmle.code.cpp.security.Overflow
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.TaintTracking
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
import TaintedWithPath
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.ir.dataflow.TaintTracking
import DataFlow::PathGraph
import Bounded
predicate isUnboundedRandCall(FunctionCall fc) {
exists(Function func | func = fc.getTarget() |
func.hasGlobalOrStdOrBslName("rand") and
not bounded(fc) and
func.getNumberOfParameters() = 0
)
/**
* A function that outputs random data such as `std::rand`.
*/
abstract class RandomFunction extends Function {
/**
* Gets the `FunctionOutput` that describes how this function returns the random data.
*/
FunctionOutput getFunctionOutput() { result.isReturnValue() }
}
/**
* An operand `e` of a division expression (i.e., `e` is an operand of either a `DivExpr` or
* a `AssignDivExpr`) is bounded when `e` is the left-hand side of the division.
* The standard function `std::rand`.
*/
pragma[inline]
predicate boundedDiv(Expr e, Expr left) { e = left }
/**
* An operand `e` of a remainder expression `rem` (i.e., `rem` is either a `RemExpr` or
* an `AssignRemExpr`) with left-hand side `left` and right-hand side `right` is bounded
* when `e` is `left` and `right` is upper bounded by some number that is less than the maximum integer
* allowed by the result type of `rem`.
*/
pragma[inline]
predicate boundedRem(Expr e, Expr rem, Expr left, Expr right) {
e = left and
upperBound(right.getFullyConverted()) < exprMaxVal(rem.getFullyConverted())
private class StdRand extends RandomFunction {
StdRand() {
this.hasGlobalOrStdOrBslName("rand") and
this.getNumberOfParameters() = 0
}
}
/**
* An operand `e` of a bitwise and expression `andExpr` (i.e., `andExpr` is either an `BitwiseAndExpr`
* or an `AssignAndExpr`) with operands `operand1` and `operand2` is the operand that is not `e` is upper
* bounded by some number that is less than the maximum integer allowed by the result type of `andExpr`.
* The Unix function `rand_r`.
*/
pragma[inline]
predicate boundedBitwiseAnd(Expr e, Expr andExpr, Expr operand1, Expr operand2) {
operand1 != operand2 and
e = operand1 and
upperBound(operand2.getFullyConverted()) < exprMaxVal(andExpr.getFullyConverted())
private class RandR extends RandomFunction {
RandR() {
this.hasGlobalName("rand_r") and
this.getNumberOfParameters() = 1
}
}
/**
* Holds if `e` is an arithmetic expression that cannot overflow, or if `e` is an operand of an
* operation that may greatly reduces the range of possible values.
* The Unix function `random`.
*/
predicate bounded(Expr e) {
(
e instanceof UnaryArithmeticOperation or
e instanceof BinaryArithmeticOperation or
e instanceof AssignArithmeticOperation
) and
not convertedExprMightOverflow(e)
or
// For `%` and `&` we require that `e` is bounded by a value that is strictly smaller than the
// maximum possible value of the result type of the operation.
// For example, the function call `rand()` is considered bounded in the following program:
// ```
// int i = rand() % (UINT8_MAX + 1);
// ```
// but not in:
// ```
// unsigned char uc = rand() % (UINT8_MAX + 1);
// ```
exists(RemExpr rem | boundedRem(e, rem, rem.getLeftOperand(), rem.getRightOperand()))
or
exists(AssignRemExpr rem | boundedRem(e, rem, rem.getLValue(), rem.getRValue()))
or
exists(BitwiseAndExpr andExpr |
boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
)
or
exists(AssignAndExpr andExpr |
boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
)
or
// Optimitically assume that a division or right shift always yields a much smaller value.
boundedDiv(e, any(DivExpr div).getLeftOperand())
or
boundedDiv(e, any(AssignDivExpr div).getLValue())
or
boundedDiv(e, any(RShiftExpr shift).getLeftOperand())
or
boundedDiv(e, any(AssignRShiftExpr div).getLValue())
private class Random extends RandomFunction {
Random() {
this.hasGlobalName("random") and
this.getNumberOfParameters() = 1
}
}
predicate isUnboundedRandCallOrParent(Expr e) {
isUnboundedRandCall(e)
or
isUnboundedRandCallOrParent(e.getAChild())
/**
* The Windows `rand_s` function.
*/
private class RandS extends RandomFunction {
RandS() {
this.hasGlobalName("rand_s") and
this.getNumberOfParameters() = 1
}
predicate isUnboundedRandValue(Expr e) {
isUnboundedRandCall(e)
or
exists(MacroInvocation mi |
e = mi.getExpr() and
isUnboundedRandCallOrParent(e)
)
}
class SecurityOptionsArith extends SecurityOptions {
override predicate isUserInput(Expr expr, string cause) {
isUnboundedRandValue(expr) and
cause = "rand"
}
override FunctionOutput getFunctionOutput() { result.isParameterDeref(0) }
}
predicate missingGuard(VariableAccess va, string effect) {
@ -132,16 +80,47 @@ predicate missingGuard(VariableAccess va, string effect) {
)
}
class Configuration extends TaintTrackingConfiguration {
override predicate isSink(Element e) { missingGuard(e, _) }
class UncontrolledArithConfiguration extends TaintTracking::Configuration {
UncontrolledArithConfiguration() { this = "UncontrolledArithConfiguration" }
override predicate isBarrier(Expr e) { super.isBarrier(e) or bounded(e) }
override predicate isSource(DataFlow::Node source) {
exists(RandomFunction rand, Call call | call.getTarget() = rand |
rand.getFunctionOutput().isReturnValue() and
source.asExpr() = call
or
exists(int n |
source.asDefiningArgument() = call.getArgument(n) and
rand.getFunctionOutput().isParameterDeref(n)
)
)
}
from Expr origin, VariableAccess va, string effect, PathNode sourceNode, PathNode sinkNode
override predicate isSink(DataFlow::Node sink) { missingGuard(sink.asExpr(), _) }
override predicate isSanitizer(DataFlow::Node node) {
bounded(node.asExpr())
or
// If this expression is part of bitwise 'and' or 'or' operation it's likely that the value is
// only used as a bit pattern.
node.asExpr() =
any(Operation op |
op instanceof BitwiseOrExpr or
op instanceof BitwiseAndExpr or
op instanceof ComplementExpr
).getAnOperand*()
}
}
/** Gets the expression that corresponds to `node`, if any. */
Expr getExpr(DataFlow::Node node) { result = [node.asExpr(), node.asDefiningArgument()] }
from
UncontrolledArithConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink,
VariableAccess va, string effect
where
taintedWithPath(origin, va, sourceNode, sinkNode) and
config.hasFlowPath(source, sink) and
sink.getNode().asExpr() = va and
missingGuard(va, effect)
select va, sourceNode, sinkNode,
"$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", origin,
"Uncontrolled value"
select sink.getNode(), source, sink,
"$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
getExpr(source.getNode()), "Uncontrolled value"

Просмотреть файл

@ -0,0 +1,55 @@
/**
* This file provides the `bounded` predicate that is used in both `cpp/uncontrolled-arithmetic`
* and `cpp/tainted-arithmetic`.
*/
private import cpp
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
/**
* An operand `e` of a bitwise and expression `andExpr` (i.e., `andExpr` is either an `BitwiseAndExpr`
* or an `AssignAndExpr`) with operands `operand1` and `operand2` is the operand that is not `e` is upper
* bounded by some number that is less than the maximum integer allowed by the result type of `andExpr`.
*/
pragma[inline]
private predicate boundedBitwiseAnd(Expr e, Expr andExpr, Expr operand1, Expr operand2) {
operand1 != operand2 and
e = operand1 and
upperBound(operand2.getFullyConverted()) < exprMaxVal(andExpr.getFullyConverted())
}
/**
* Holds if `e` is an arithmetic expression that cannot overflow, or if `e` is an operand of an
* operation that may greatly reduce the range of possible values.
*/
predicate bounded(Expr e) {
(
e instanceof UnaryArithmeticOperation or
e instanceof BinaryArithmeticOperation or
e instanceof AssignArithmeticOperation
) and
not convertedExprMightOverflow(e)
or
// Optimitically assume that a remainder expression always yields a much smaller value.
e = any(RemExpr rem).getLeftOperand()
or
e = any(AssignRemExpr rem).getLValue()
or
exists(BitwiseAndExpr andExpr |
boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
)
or
exists(AssignAndExpr andExpr |
boundedBitwiseAnd(e, andExpr, andExpr.getAnOperand(), andExpr.getAnOperand())
)
or
// Optimitically assume that a division always yields a much smaller value.
e = any(DivExpr div).getLeftOperand()
or
e = any(AssignDivExpr div).getLValue()
or
e = any(RShiftExpr shift).getLeftOperand()
or
e = any(AssignRShiftExpr div).getLValue()
}

Просмотреть файл

@ -6,7 +6,6 @@
* @kind problem
* @problem.severity warning
* @security-severity 7.8
* @opaque-id SM02313
* @id cpp/conditionally-uninitialized-variable
* @tags security
* external/cwe/cwe-457

Просмотреть файл

@ -4,7 +4,6 @@
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
* lines-of-code
*/
import cpp

Просмотреть файл

@ -0,0 +1,12 @@
intA = ++intA + 1; // BAD: undefined behavior when changing variable `intA`
...
intA++;
intA = intA + 1; // GOOD: correct design
...
char * buff;
...
if(funcAdd(buff)+fucDel(buff)>0) return 1; // BAD: undefined behavior when calling functions to change the `buff` variable
...
intA = funcAdd(buff);
intB = funcDel(buff);
if(intA+intB>0) return 1; // GOOD: correct design

Просмотреть файл

@ -0,0 +1,28 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>In some situations, the code constructs used may be executed in the wrong order in which the developer designed them. For example, if you call multiple functions as part of a single expression, and the functions have the ability to modify a shared resource, then the sequence in which the resource is changed can be unpredictable. These code snippets look suspicious and require the developer's attention.</p>
</overview>
<recommendation>
<p>We recommend that you use more guaranteed, in terms of sequence of execution, coding techniques.</p>
</recommendation>
<example>
<p>The following example demonstrates sections of code with insufficient execution sequence definition.</p>
<sample src="UndefinedOrImplementationDefinedBehavior.c" />
</example>
<references>
<li>
CWE Common Weakness Enumeration:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/EXP10-C.+Do+not+depend+on+the+order+of+evaluation+of+subexpressions+or+the+order+in+which+side+effects+take+place"> EXP10-C. Do not depend on the order of evaluation of subexpressions or the order in which side effects take place</a>.
</li>
</references>
</qhelp>

Просмотреть файл

@ -0,0 +1,166 @@
/**
* @name Errors Of Undefined Program Behavior
* @description --In some situations, the code constructs used may be executed in the wrong order in which the developer designed them.
* --For example, if you call multiple functions as part of a single expression, and the functions have the ability to modify a shared resource, then the sequence in which the resource is changed can be unpredictable.
* --These code snippets look suspicious and require the developer's attention.
* @kind problem
* @id cpp/errors-of-undefined-program-behavior
* @problem.severity warning
* @precision medium
* @tags security
* external/cwe/cwe-758
*/
import cpp
import semmle.code.cpp.valuenumbering.HashCons
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
/**
* Threatening expressions of undefined behavior.
*/
class ExpressionsOfTheSameLevel extends Expr {
Expr exp2;
ExpressionsOfTheSameLevel() {
this != exp2 and
this.getParent() = exp2.getParent()
}
/** Holds if the underlying expression is a function call. */
predicate expressionCall() {
this instanceof FunctionCall and
exp2.getAChild*() instanceof FunctionCall and
not this.getParent() instanceof Operator and
not this.(FunctionCall).hasQualifier()
}
/** Holds if the underlying expression is a call to a function to free resources. */
predicate existsCloseOrFreeCall() {
(
globalValueNumber(this.(FunctionCall).getAnArgument()) =
globalValueNumber(exp2.getAChild*().(FunctionCall).getAnArgument()) or
hashCons(this.(FunctionCall).getAnArgument()) =
hashCons(exp2.getAChild*().(FunctionCall).getAnArgument())
) and
(
this.(FunctionCall).getTarget().hasGlobalOrStdName("close") or
this.(FunctionCall).getTarget().hasGlobalOrStdName("free") or
this.(FunctionCall).getTarget().hasGlobalOrStdName("fclose")
)
}
/** Holds if the arguments in the function can be changed. */
predicate generalArgumentDerivedType() {
exists(Parameter prt1, Parameter prt2, AssignExpr aet1, AssignExpr aet2, int i, int j |
not this.(FunctionCall).getArgument(i).isConstant() and
hashCons(this.(FunctionCall).getArgument(i)) =
hashCons(exp2.getAChild*().(FunctionCall).getArgument(j)) and
prt1 = this.(FunctionCall).getTarget().getParameter(i) and
prt2 = exp2.getAChild*().(FunctionCall).getTarget().getParameter(j) and
prt1.getType() instanceof DerivedType and
(
aet1 = this.(FunctionCall).getTarget().getEntryPoint().getASuccessor*() and
(
aet1.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() =
prt1.getAnAccess().getTarget() or
aet1.getLValue().(VariableAccess).getTarget() = prt1.getAnAccess().getTarget()
)
or
exists(FunctionCall fc1 |
fc1.getTarget().hasGlobalName("memcpy") and
fc1.getArgument(0).(VariableAccess).getTarget() = prt1.getAnAccess().getTarget() and
fc1 = this.(FunctionCall).getTarget().getEntryPoint().getASuccessor*()
)
) and
(
aet2 = exp2.getAChild*().(FunctionCall).getTarget().getEntryPoint().getASuccessor*() and
(
aet2.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() =
prt2.getAnAccess().getTarget() or
aet2.getLValue().(VariableAccess).getTarget() = prt2.getAnAccess().getTarget()
)
or
exists(FunctionCall fc1 |
fc1.getTarget().hasGlobalName("memcpy") and
fc1.getArgument(0).(VariableAccess).getTarget() = prt2.getAnAccess().getTarget() and
fc1 = exp2.(FunctionCall).getTarget().getEntryPoint().getASuccessor*()
)
)
)
}
/** Holds if functions have a common global argument. */
predicate generalGlobalArgument() {
exists(Declaration dl, AssignExpr aet1, AssignExpr aet2 |
dl instanceof GlobalVariable and
(
(
aet1.getLValue().(Access).getTarget() = dl or
aet1.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() = dl
) and
aet1 = this.(FunctionCall).getTarget().getEntryPoint().getASuccessor*() and
not aet1.getRValue().isConstant()
or
exists(FunctionCall fc1 |
fc1.getTarget().hasGlobalName("memcpy") and
fc1.getArgument(0).(VariableAccess).getTarget() = dl and
fc1 = this.(FunctionCall).getTarget().getEntryPoint().getASuccessor*()
)
) and
(
(
aet2.getLValue().(Access).getTarget() = dl or
aet2.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() = dl
) and
aet2 = exp2.(FunctionCall).getTarget().getEntryPoint().getASuccessor*()
or
exists(FunctionCall fc1 |
fc1.getTarget().hasGlobalName("memcpy") and
fc1.getArgument(0).(VariableAccess).getTarget() = dl and
fc1 = exp2.(FunctionCall).getTarget().getEntryPoint().getASuccessor*()
)
)
)
}
/** Holds if sequence point is not present in expression. */
predicate orderOfActionExpressions() {
not this.getParent() instanceof BinaryLogicalOperation and
not this.getParent() instanceof ConditionalExpr and
not this.getParent() instanceof Loop and
not this.getParent() instanceof CommaExpr
}
/** Holds if expression is crement. */
predicate dangerousCrementChanges() {
hashCons(this.(CrementOperation).getOperand()) = hashCons(exp2.(CrementOperation).getOperand())
or
hashCons(this.(CrementOperation).getOperand()) = hashCons(exp2)
or
hashCons(this.(CrementOperation).getOperand()) = hashCons(exp2.(ArrayExpr).getArrayOffset())
or
hashCons(this.(Assignment).getLValue()) = hashCons(exp2.(Assignment).getLValue())
or
not this.getAChild*() instanceof Call and
(
hashCons(this.getAChild*().(CrementOperation).getOperand()) = hashCons(exp2) or
hashCons(this.getAChild*().(CrementOperation).getOperand()) =
hashCons(exp2.(Assignment).getLValue())
)
}
}
from ExpressionsOfTheSameLevel eots
where
eots.orderOfActionExpressions() and
(
eots.expressionCall() and
(
eots.generalArgumentDerivedType() or
eots.generalGlobalArgument() or
eots.existsCloseOrFreeCall()
)
or
eots.dangerousCrementChanges()
)
select eots, "This expression may have undefined behavior."

Просмотреть файл

@ -272,20 +272,16 @@ class File extends Container, @file {
* are compiled by a Microsoft compiler are detected by this predicate.
*/
predicate compiledAsMicrosoft() {
exists(Compilation c |
c.getAFileCompiled() = this and
exists(File f, Compilation c |
c.getAFileCompiled() = f and
(
c.getAnArgument() = "--microsoft" or
c.getAnArgument()
.toLowerCase()
.replaceAll("\\", "/")
.matches(["%/cl.exe", "%/clang-cl.exe"])
)
)
or
exists(File parent |
parent.compiledAsMicrosoft() and
parent.getAnIncludedFile() = this
) and
f.getAnIncludedFile*() = this
)
}
@ -358,6 +354,11 @@ class File extends Container, @file {
string getShortName() { files(underlyingElement(this), _, result, _, _) }
}
/**
* Holds if any file was compiled by a Microsoft compiler.
*/
predicate anyFileCompiledAsMicrosoft() { any(File f).compiledAsMicrosoft() }
/**
* A C/C++ header file, as determined (mainly) by file extension.
*

Просмотреть файл

@ -306,7 +306,7 @@ class FormatLiteral extends Literal {
* Holds if this `FormatLiteral` is in a context that supports
* Microsoft rules and extensions.
*/
predicate isMicrosoft() { any(File f).compiledAsMicrosoft() }
predicate isMicrosoft() { anyFileCompiledAsMicrosoft() }
/**
* Gets the format string, with '%%' and '%@' replaced by '_' (to avoid processing
@ -869,6 +869,33 @@ class FormatLiteral extends Literal {
)
}
/**
* Gets an alternate argument type that would be required by the nth
* conversion specifier on a Microsoft or non-Microsoft platform, opposite
* to that of the snapshot. This may be useful for answering 'what might
* happen' questions.
*/
Type getConversionTypeAlternate(int n) {
exists(string len, string conv |
this.parseConvSpec(n, _, _, _, _, _, len, conv) and
(len != "l" and len != "w" and len != "h") and
getUse().getTarget().(FormattingFunction).getFormatCharType().getSize() > 1 and // wide function
(
conv = "c" and
result = getNonDefaultCharType()
or
conv = "C" and
result = getDefaultCharType()
or
conv = "s" and
result.(PointerType).getBaseType() = getNonDefaultCharType()
or
conv = "S" and
result.(PointerType).getBaseType() = getDefaultCharType()
)
)
}
/**
* Holds if the nth conversion specifier of this format string (if `mode = 2`), it's
* minimum field width (if `mode = 0`) or it's precision (if `mode = 1`) requires a

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -724,7 +724,6 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
read(_, c, _) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
@ -1118,6 +1117,44 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
result = getReturnPosition0(ret, ret.getKind())
}
/**
* Checks whether `inner` can return to `call` in the call context `innercc`.
* Assumes a context of `inner = viableCallableExt(call)`.
*/
bindingset[innercc, inner, call]
predicate checkCallContextReturn(CallContext innercc, DataFlowCallable inner, DataFlowCall call) {
innercc instanceof CallContextAny
or
exists(DataFlowCallable c0, DataFlowCall call0 |
callEnclosingCallable(call0, inner) and
innercc = TReturn(c0, call0) and
c0 = prunedViableImplInCallContextReverse(call0, call)
)
}
/**
* Checks whether `call` can resolve to `calltarget` in the call context `cc`.
* Assumes a context of `calltarget = viableCallableExt(call)`.
*/
bindingset[cc, call, calltarget]
predicate checkCallContextCall(CallContext cc, DataFlowCall call, DataFlowCallable calltarget) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
if reducedViableImplInCallContext(call, _, ctx)
then calltarget = prunedViableImplInCallContext(call, ctx)
else any()
)
or
cc instanceof CallContextSomeCall
or
cc instanceof CallContextAny
or
cc instanceof CallContextReturn
}
/**
* Resolves a return from `callable` in `cc` to `call`. This is equivalent to
* `callable = viableCallableExt(call) and checkCallContextReturn(cc, callable, call)`.
*/
bindingset[cc, callable]
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
cc instanceof CallContextAny and callable = viableCallableExt(call)
@ -1129,6 +1166,10 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
)
}
/**
* Resolves a call from `call` in `cc` to `result`. This is equivalent to
* `result = viableCallableExt(call) and checkCallContextCall(cc, call, result)`.
*/
bindingset[call, cc]
DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -133,46 +133,6 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
*/
predicate jumpStep(Node n1, Node n2) { none() }
private newtype TContent =
TFieldContent(Field f) or
TCollectionContent() or
TArrayContent()
/**
* A reference contained in an object. Examples include instance fields, the
* contents of a collection object, or the contents of an array.
*/
class Content extends TContent {
/** Gets a textual representation of this element. */
abstract string toString();
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
}
}
private class FieldContent extends Content, TFieldContent {
Field f;
FieldContent() { this = TFieldContent(f) }
Field getField() { result = f }
override string toString() { result = f.toString() }
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
}
}
private class CollectionContent extends Content, TCollectionContent {
override string toString() { result = "collection" }
}
private class ArrayContent extends Content, TArrayContent {
override string toString() { result = "array" }
}
/**
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
* Thus, `node2` references an object with a field `f` that contains the

Просмотреть файл

@ -768,6 +768,50 @@ VariableAccess getAnAccessToAssignedVariable(Expr assign) {
)
}
private newtype TContent =
TFieldContent(Field f) or
TCollectionContent() or
TArrayContent()
/**
* A description of the way data may be stored inside an object. Examples
* include instance fields, the contents of a collection object, or the contents
* of an array.
*/
class Content extends TContent {
/** Gets a textual representation of this element. */
abstract string toString();
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
}
}
/** A reference through an instance field. */
class FieldContent extends Content, TFieldContent {
Field f;
FieldContent() { this = TFieldContent(f) }
Field getField() { result = f }
override string toString() { result = f.toString() }
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
f.getLocation().hasLocationInfo(path, sl, sc, el, ec)
}
}
/** A reference through an array. */
private class ArrayContent extends Content, TArrayContent {
override string toString() { result = "[]" }
}
/** A reference through the contents of some collection-like container. */
private class CollectionContent extends Content, TCollectionContent {
override string toString() { result = "<element>" }
}
/**
* A guard that validates some expression.
*

Просмотреть файл

@ -34,6 +34,13 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink)
}
/**
* Holds if default `TaintTracking::Configuration`s should allow implicit reads
* of `c` at sinks and inputs to additional taint steps.
*/
bindingset[node]
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { none() }
/**
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.

Просмотреть файл

@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)
}
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/

Просмотреть файл

@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)
}
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/

Просмотреть файл

@ -231,10 +231,35 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context.
*/
predicate mayBenefitFromCallContext(CallInstruction call, Function f) { none() }
predicate mayBenefitFromCallContext(CallInstruction call, Function f) {
mayBenefitFromCallContext(call, f, _)
}
/**
* Holds if `call` is a call through a function pointer, and the pointer
* value is given as the `arg`'th argument to `f`.
*/
private predicate mayBenefitFromCallContext(
VirtualDispatch::DataSensitiveCall call, Function f, int arg
) {
f = pragma[only_bind_out](call).getEnclosingCallable() and
exists(InitializeParameterInstruction init |
not exists(call.getStaticCallTarget()) and
init.getEnclosingFunction() = f and
call.flowsFrom(DataFlow::instructionNode(init), _) and
init.getParameter().getIndex() = arg
)
}
/**
* Gets a viable dispatch target of `call` in the context `ctx`. This is
* restricted to those `call`s for which a context might make a difference.
*/
Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) { none() }
Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
result = viableCallable(call) and
exists(int i, Function f |
mayBenefitFromCallContext(pragma[only_bind_into](call), f, i) and
f = ctx.getStaticCallTarget() and
result = ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget()
)
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -724,7 +724,6 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
read(_, c, _) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
@ -1118,6 +1117,44 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
result = getReturnPosition0(ret, ret.getKind())
}
/**
* Checks whether `inner` can return to `call` in the call context `innercc`.
* Assumes a context of `inner = viableCallableExt(call)`.
*/
bindingset[innercc, inner, call]
predicate checkCallContextReturn(CallContext innercc, DataFlowCallable inner, DataFlowCall call) {
innercc instanceof CallContextAny
or
exists(DataFlowCallable c0, DataFlowCall call0 |
callEnclosingCallable(call0, inner) and
innercc = TReturn(c0, call0) and
c0 = prunedViableImplInCallContextReverse(call0, call)
)
}
/**
* Checks whether `call` can resolve to `calltarget` in the call context `cc`.
* Assumes a context of `calltarget = viableCallableExt(call)`.
*/
bindingset[cc, call, calltarget]
predicate checkCallContextCall(CallContext cc, DataFlowCall call, DataFlowCallable calltarget) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
if reducedViableImplInCallContext(call, _, ctx)
then calltarget = prunedViableImplInCallContext(call, ctx)
else any()
)
or
cc instanceof CallContextSomeCall
or
cc instanceof CallContextAny
or
cc instanceof CallContextReturn
}
/**
* Resolves a return from `callable` in `cc` to `call`. This is equivalent to
* `callable = viableCallableExt(call) and checkCallContextReturn(cc, callable, call)`.
*/
bindingset[cc, callable]
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
cc instanceof CallContextAny and callable = viableCallableExt(call)
@ -1129,6 +1166,10 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
)
}
/**
* Resolves a call from `call` in `cc` to `result`. This is equivalent to
* `result = viableCallableExt(call) and checkCallContextCall(cc, call, result)`.
*/
bindingset[call, cc]
DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |

Просмотреть файл

@ -184,64 +184,6 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
*/
predicate jumpStep(Node n1, Node n2) { none() }
/**
* Gets a field corresponding to the bit range `[startBit..endBit)` of class `c`, if any.
*/
private Field getAField(Class c, int startBit, int endBit) {
result.getDeclaringType() = c and
startBit = 8 * result.getByteOffset() and
endBit = 8 * result.getType().getSize() + startBit
or
exists(Field f, Class cInner |
f = c.getAField() and
cInner = f.getUnderlyingType() and
result = getAField(cInner, startBit - 8 * f.getByteOffset(), endBit - 8 * f.getByteOffset())
)
}
private newtype TContent =
TFieldContent(Class c, int startBit, int endBit) { exists(getAField(c, startBit, endBit)) } or
TCollectionContent() or
TArrayContent()
/**
* A reference contained in an object. Examples include instance fields, the
* contents of a collection object, or the contents of an array.
*/
class Content extends TContent {
/** Gets a textual representation of this element. */
abstract string toString();
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
}
}
private class FieldContent extends Content, TFieldContent {
Class c;
int startBit;
int endBit;
FieldContent() { this = TFieldContent(c, startBit, endBit) }
// Ensure that there's just 1 result for `toString`.
override string toString() { result = min(Field f | f = getAField() | f.toString()) }
predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit }
Field getAField() { result = getAField(c, startBit, endBit) }
}
private class CollectionContent extends Content, TCollectionContent {
override string toString() { result = "collection" }
}
private class ArrayContent extends Content, TArrayContent {
ArrayContent() { this = TArrayContent() }
override string toString() { result = "array content" }
}
private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) {
exists(StoreInstruction store, Class c |
store = node2.asInstruction() and
@ -288,7 +230,7 @@ private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode n
}
private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) {
a = TArrayContent() and
exists(a) and
exists(ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store |
chi.getPartialOperand() = operand and
store = operand.getDef() and
@ -383,7 +325,7 @@ private predicate fieldReadStep(Node node1, FieldContent f, Node node2) {
* predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path.
*/
predicate suppressArrayRead(Node node1, ArrayContent a, Node node2) {
a = TArrayContent() and
exists(a) and
exists(WriteSideEffectInstruction write, ChiInstruction chi |
node1.asInstruction() = write and
node2.asInstruction() = chi and
@ -412,7 +354,7 @@ private Instruction skipCopyValueInstructions(Operand op) {
}
private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) {
a = TArrayContent() and
exists(a) and
// Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array.
exists(LoadOperand operand, Instruction address |
operand.isDefinitionInexact() and
@ -443,7 +385,7 @@ private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) {
* from the access path.
*/
private predicate exactReadStep(Node node1, ArrayContent a, Node node2) {
a = TArrayContent() and
exists(a) and
exists(WriteSideEffectInstruction write, ChiInstruction chi |
not chi.isResultConflated() and
chi.getPartial() = write and

Просмотреть файл

@ -788,6 +788,66 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
*/
predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
/**
* Gets a field corresponding to the bit range `[startBit..endBit)` of class `c`, if any.
*/
private Field getAField(Class c, int startBit, int endBit) {
result.getDeclaringType() = c and
startBit = 8 * result.getByteOffset() and
endBit = 8 * result.getType().getSize() + startBit
or
exists(Field f, Class cInner |
f = c.getAField() and
cInner = f.getUnderlyingType() and
result = getAField(cInner, startBit - 8 * f.getByteOffset(), endBit - 8 * f.getByteOffset())
)
}
private newtype TContent =
TFieldContent(Class c, int startBit, int endBit) { exists(getAField(c, startBit, endBit)) } or
TCollectionContent() or
TArrayContent()
/**
* A description of the way data may be stored inside an object. Examples
* include instance fields, the contents of a collection object, or the contents
* of an array.
*/
class Content extends TContent {
/** Gets a textual representation of this element. */
abstract string toString();
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
}
}
/** A reference through an instance field. */
class FieldContent extends Content, TFieldContent {
Class c;
int startBit;
int endBit;
FieldContent() { this = TFieldContent(c, startBit, endBit) }
// Ensure that there's just 1 result for `toString`.
override string toString() { result = min(Field f | f = getAField() | f.toString()) }
predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit }
Field getAField() { result = getAField(c, startBit, endBit) }
}
/** A reference through an array. */
class ArrayContent extends Content, TArrayContent {
override string toString() { result = "[]" }
}
/** A reference through the contents of some collection-like container. */
private class CollectionContent extends Content, TCollectionContent {
override string toString() { result = "<element>" }
}
/**
* A guard that validates some instruction.
*

Просмотреть файл

@ -151,6 +151,13 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink)
}
/**
* Holds if default `TaintTracking::Configuration`s should allow implicit reads
* of `c` at sinks and inputs to additional taint steps.
*/
bindingset[node]
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { none() }
/**
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.

Просмотреть файл

@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)
}
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/

Просмотреть файл

@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)
}
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/

Просмотреть файл

@ -105,6 +105,11 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)
}
/**
* Holds if taint may flow from `source` to `sink` for this configuration.
*/

Просмотреть файл

@ -50,7 +50,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
* Holds if this `FormattingFunction` is in a context that supports
* Microsoft rules and extensions.
*/
predicate isMicrosoft() { any(File f).compiledAsMicrosoft() }
predicate isMicrosoft() { anyFileCompiledAsMicrosoft() }
/**
* Holds if the default meaning of `%s` is a `wchar_t *`, rather than

Просмотреть файл

@ -863,16 +863,16 @@ private float getLowerBoundsImpl(Expr expr) {
result = 0
or
// If either input could be negative then the output could be
// negative. If so, the lower bound of `x%y` is `-abs(y)`, which is
// equal to `min(-y,y)`.
// negative. If so, the lower bound of `x%y` is `-abs(y) + 1`, which is
// equal to `min(-y + 1,y - 1)`.
exists(float childLB |
childLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and
not childLB >= 0
|
result = getFullyConvertedLowerBounds(remExpr.getRightOperand())
result = getFullyConvertedLowerBounds(remExpr.getRightOperand()) - 1
or
exists(float rhsUB | rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) |
result = -rhsUB
result = -rhsUB + 1
)
)
)
@ -1058,16 +1058,16 @@ private float getUpperBoundsImpl(Expr expr) {
expr = remExpr and
rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand())
|
result = rhsUB
result = rhsUB - 1
or
// If the right hand side could be negative then we need to take its
// absolute value. Since `abs(x) = max(-x,x)` this is equivalent to
// adding `-rhsLB` to the set of upper bounds.
exists(float rhsLB |
rhsLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and
rhsLB = getFullyConvertedLowerBounds(remExpr.getRightOperand()) and
not rhsLB >= 0
|
result = -rhsLB
result = -rhsLB + 1
)
)
or

Просмотреть файл

@ -0,0 +1,3 @@
| test.c:13:10:13:21 | call to tmpFunction1 | This expression may have undefined behavior. |
| test.c:13:30:13:41 | call to tmpFunction2 | This expression may have undefined behavior. |
| test.c:16:15:16:20 | ... ++ | This expression may have undefined behavior. |

Просмотреть файл

@ -0,0 +1 @@
experimental/Security/CWE/CWE-758/UndefinedOrImplementationDefinedBehavior.ql

Просмотреть файл

@ -0,0 +1,19 @@
char tmpFunction1(char * buf)
{
buf[1]=buf[1] + buf[2] + buf[3];
return buf[1];
}
char tmpFunction2(char * buf)
{
buf[2]=buf[1] + buf[2] + buf[3];
return buf[2];
}
void workFunction_0(char *s, char * buf) {
int intA;
intA = tmpFunction1(buf) + tmpFunction2(buf); // BAD
intA = tmpFunction1(buf); //GOOD
intA += tmpFunction2(buf); // GOOD
buf[intA] = intA++; // BAD
intA++;
buf[intA] = intA; // GOOD
}

Просмотреть файл

@ -58,29 +58,29 @@ edges
| aliasing.cpp:98:3:98:21 | Chi [m1] | aliasing.cpp:100:14:100:14 | Store [m1] |
| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:3:98:21 | Chi [m1] |
| aliasing.cpp:100:14:100:14 | Store [m1] | aliasing.cpp:102:8:102:10 | * ... |
| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] |
| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] |
| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] |
| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] |
| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] |
| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] |
| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | Chi [array content] |
| aliasing.cpp:121:15:121:16 | Chi [array content] | aliasing.cpp:122:8:122:12 | access to array |
| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | aliasing.cpp:121:15:121:16 | Chi [array content] |
| aliasing.cpp:131:15:131:16 | Chi [array content] | aliasing.cpp:132:8:132:14 | * ... |
| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | aliasing.cpp:131:15:131:16 | Chi [array content] |
| aliasing.cpp:136:15:136:17 | Chi [array content] | aliasing.cpp:137:8:137:11 | * ... |
| aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] | aliasing.cpp:136:15:136:17 | Chi [array content] |
| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [[]] |
| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [[]] |
| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [[]] |
| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [[]] |
| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [[]] |
| aliasing.cpp:106:3:106:20 | Chi [[]] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [[]] |
| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | Chi [[]] |
| aliasing.cpp:121:15:121:16 | Chi [[]] | aliasing.cpp:122:8:122:12 | access to array |
| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [[]] | aliasing.cpp:121:15:121:16 | Chi [[]] |
| aliasing.cpp:131:15:131:16 | Chi [[]] | aliasing.cpp:132:8:132:14 | * ... |
| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [[]] | aliasing.cpp:131:15:131:16 | Chi [[]] |
| aliasing.cpp:136:15:136:17 | Chi [[]] | aliasing.cpp:137:8:137:11 | * ... |
| aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [[]] | aliasing.cpp:136:15:136:17 | Chi [[]] |
| aliasing.cpp:175:15:175:22 | Chi | aliasing.cpp:175:15:175:22 | Chi [m1] |
| aliasing.cpp:175:15:175:22 | Chi [m1] | aliasing.cpp:176:13:176:14 | m1 |
| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | aliasing.cpp:175:15:175:22 | Chi |
| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [[]] | aliasing.cpp:175:15:175:22 | Chi |
| aliasing.cpp:187:15:187:22 | Chi | aliasing.cpp:187:15:187:22 | Chi [m1] |
| aliasing.cpp:187:15:187:22 | Chi [m1] | aliasing.cpp:188:13:188:14 | Store [m1] |
| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | aliasing.cpp:187:15:187:22 | Chi |
| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [[]] | aliasing.cpp:187:15:187:22 | Chi |
| aliasing.cpp:188:13:188:14 | Store [m1] | aliasing.cpp:189:15:189:16 | m1 |
| aliasing.cpp:200:15:200:24 | Chi | aliasing.cpp:200:15:200:24 | Chi [m1] |
| aliasing.cpp:200:15:200:24 | Chi [m1] | aliasing.cpp:201:15:201:16 | m1 |
| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | aliasing.cpp:200:15:200:24 | Chi |
| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [[]] | aliasing.cpp:200:15:200:24 | Chi |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... |
@ -108,32 +108,32 @@ edges
| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] |
| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] |
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Chi [a] |
| by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] |
| by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] |
| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | Chi [array content] |
| by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] |
| by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] |
| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | Chi [array content] |
| by_reference.cpp:92:3:92:20 | Chi [[]] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [[]] |
| by_reference.cpp:92:3:92:20 | Chi [[]] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [[]] |
| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | Chi [[]] |
| by_reference.cpp:96:3:96:19 | Chi [[]] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [[]] |
| by_reference.cpp:96:3:96:19 | Chi [[]] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [[]] |
| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | Chi [[]] |
| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a |
| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] |
| by_reference.cpp:104:15:104:22 | Chi | by_reference.cpp:104:15:104:22 | Chi [a] |
| by_reference.cpp:104:15:104:22 | Chi [a] | by_reference.cpp:112:14:112:14 | a |
| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | by_reference.cpp:104:15:104:22 | Chi |
| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [[]] | by_reference.cpp:104:15:104:22 | Chi |
| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a |
| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] |
| by_reference.cpp:108:15:108:24 | Chi | by_reference.cpp:108:15:108:24 | Chi [a] |
| by_reference.cpp:108:15:108:24 | Chi [a] | by_reference.cpp:116:16:116:16 | a |
| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | by_reference.cpp:108:15:108:24 | Chi |
| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [[]] | by_reference.cpp:108:15:108:24 | Chi |
| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a |
| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] |
| by_reference.cpp:124:15:124:21 | Chi | by_reference.cpp:124:15:124:21 | Chi [a] |
| by_reference.cpp:124:15:124:21 | Chi [a] | by_reference.cpp:132:14:132:14 | a |
| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | by_reference.cpp:124:15:124:21 | Chi |
| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [[]] | by_reference.cpp:124:15:124:21 | Chi |
| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a |
| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] |
| by_reference.cpp:128:15:128:23 | Chi | by_reference.cpp:128:15:128:23 | Chi [a] |
| by_reference.cpp:128:15:128:23 | Chi [a] | by_reference.cpp:136:16:136:16 | a |
| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | by_reference.cpp:128:15:128:23 | Chi |
| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [[]] | by_reference.cpp:128:15:128:23 | Chi |
| complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:42:16:42:16 | f indirection [a_] |
| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:42:16:42:16 | f indirection [b_] |
| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:43:16:43:16 | f indirection [b_] |
@ -304,29 +304,29 @@ nodes
| aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:100:14:100:14 | Store [m1] | semmle.label | Store [m1] |
| aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... |
| aliasing.cpp:106:3:106:20 | Chi [array content] | semmle.label | Chi [array content] |
| aliasing.cpp:106:3:106:20 | Chi [[]] | semmle.label | Chi [[]] |
| aliasing.cpp:106:9:106:18 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:121:15:121:16 | Chi [array content] | semmle.label | Chi [array content] |
| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
| aliasing.cpp:121:15:121:16 | Chi [[]] | semmle.label | Chi [[]] |
| aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:122:8:122:12 | access to array | semmle.label | access to array |
| aliasing.cpp:131:15:131:16 | Chi [array content] | semmle.label | Chi [array content] |
| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
| aliasing.cpp:131:15:131:16 | Chi [[]] | semmle.label | Chi [[]] |
| aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:132:8:132:14 | * ... | semmle.label | * ... |
| aliasing.cpp:136:15:136:17 | Chi [array content] | semmle.label | Chi [array content] |
| aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
| aliasing.cpp:136:15:136:17 | Chi [[]] | semmle.label | Chi [[]] |
| aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:137:8:137:11 | * ... | semmle.label | * ... |
| aliasing.cpp:175:15:175:22 | Chi | semmle.label | Chi |
| aliasing.cpp:175:15:175:22 | Chi [m1] | semmle.label | Chi [m1] |
| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:176:13:176:14 | m1 | semmle.label | m1 |
| aliasing.cpp:187:15:187:22 | Chi | semmle.label | Chi |
| aliasing.cpp:187:15:187:22 | Chi [m1] | semmle.label | Chi [m1] |
| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:188:13:188:14 | Store [m1] | semmle.label | Store [m1] |
| aliasing.cpp:189:15:189:16 | m1 | semmle.label | m1 |
| aliasing.cpp:200:15:200:24 | Chi | semmle.label | Chi |
| aliasing.cpp:200:15:200:24 | Chi [m1] | semmle.label | Chi [m1] |
| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 |
| arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array |
@ -360,20 +360,20 @@ nodes
| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:92:3:92:20 | Chi [array content] | semmle.label | Chi [array content] |
| by_reference.cpp:92:3:92:20 | Chi [[]] | semmle.label | Chi [[]] |
| by_reference.cpp:92:9:92:18 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:96:3:96:19 | Chi [array content] | semmle.label | Chi [array content] |
| by_reference.cpp:96:3:96:19 | Chi [[]] | semmle.label | Chi [[]] |
| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] |
| by_reference.cpp:104:15:104:22 | Chi | semmle.label | Chi |
| by_reference.cpp:104:15:104:22 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] |
| by_reference.cpp:108:15:108:24 | Chi | semmle.label | Chi |
| by_reference.cpp:108:15:108:24 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] |
| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [[]] | semmle.label | taint_a_ptr output argument [[]] |
| by_reference.cpp:110:27:110:27 | a | semmle.label | a |
| by_reference.cpp:112:14:112:14 | a | semmle.label | a |
| by_reference.cpp:114:29:114:29 | a | semmle.label | a |
@ -382,12 +382,12 @@ nodes
| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] |
| by_reference.cpp:124:15:124:21 | Chi | semmle.label | Chi |
| by_reference.cpp:124:15:124:21 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] |
| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [[]] | semmle.label | taint_a_ref output argument [[]] |
| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] |
| by_reference.cpp:128:15:128:23 | Chi | semmle.label | Chi |
| by_reference.cpp:128:15:128:23 | Chi [a] | semmle.label | Chi [a] |
| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] |
| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [[]] | semmle.label | taint_a_ref output argument [[]] |
| by_reference.cpp:130:27:130:27 | a | semmle.label | a |
| by_reference.cpp:132:14:132:14 | a | semmle.label | a |
| by_reference.cpp:134:29:134:29 | a | semmle.label | a |

Просмотреть файл

@ -592,6 +592,8 @@
| test.c:654:9:654:9 | i | -2147483648 |
| test.c:658:7:658:7 | u | 0 |
| test.c:659:9:659:9 | u | 0 |
| test.c:664:12:664:12 | s | -2147483648 |
| test.c:665:7:665:8 | s2 | -4 |
| test.cpp:10:7:10:7 | b | -2147483648 |
| test.cpp:11:5:11:5 | x | -2147483648 |
| test.cpp:13:10:13:10 | x | -2147483648 |

Просмотреть файл

@ -659,3 +659,8 @@ void guard_bound_out_of_range(void) {
out(u); // unreachable [BUG: is 0 .. +max]
}
}
void test_mod(int s) {
int s2 = s % 5;
out(s2); // -4 .. 4
}

Просмотреть файл

@ -592,6 +592,8 @@
| test.c:654:9:654:9 | i | 2147483647 |
| test.c:658:7:658:7 | u | 0 |
| test.c:659:9:659:9 | u | 4294967295 |
| test.c:664:12:664:12 | s | 2147483647 |
| test.c:665:7:665:8 | s2 | 4 |
| test.cpp:10:7:10:7 | b | 2147483647 |
| test.cpp:11:5:11:5 | x | 2147483647 |
| test.cpp:13:10:13:10 | x | 2147483647 |

Просмотреть файл

@ -3,12 +3,8 @@
| tests.cpp:21:15:21:21 | Hello | This argument should be of type 'char16_t *' but is of type 'char *' |
| tests.cpp:21:15:21:21 | Hello | This argument should be of type 'wchar_t *' but is of type 'char *' |
| tests.cpp:26:17:26:24 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
| tests.cpp:27:17:27:24 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
| tests.cpp:29:17:29:23 | Hello | This argument should be of type 'wchar_t *' but is of type 'char *' |
| tests.cpp:30:17:30:24 | Hello | This argument should be of type 'wchar_t *' but is of type 'char16_t *' |
| tests.cpp:34:36:34:43 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
| tests.cpp:35:36:35:43 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
| tests.cpp:37:36:37:42 | Hello | This argument should be of type 'char16_t *' but is of type 'char *' |
| tests.cpp:39:36:39:43 | Hello | This argument should be of type 'char16_t *' but is of type 'wchar_t *' |
| tests.cpp:42:37:42:44 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
| tests.cpp:43:37:43:44 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |

Просмотреть файл

@ -24,17 +24,17 @@ void tests() {
wprintf(L"%s", "Hello"); // GOOD
wprintf(L"%s", u"Hello"); // BAD: expecting char
wprintf(L"%s", L"Hello"); // BAD: expecting char
wprintf(L"%s", L"Hello"); // BAD: expecting char [NOT DETECTED; correct on Microsoft platforms]
wprintf(L"%S", "Hello"); // BAD: expecting wchar_t
wprintf(L"%S", "Hello"); // BAD: expecting wchar_t [NOT DETECTED; correct on Microsoft platforms]
wprintf(L"%S", u"Hello"); // BAD: expecting wchar_t
wprintf(L"%S", L"Hello"); // GOOD
swprintf(buffer, BUF_SIZE, u"%s", "Hello"); // GOOD
swprintf(buffer, BUF_SIZE, u"%s", u"Hello"); // BAD: expecting char
swprintf(buffer, BUF_SIZE, u"%s", u"Hello"); // BAD: expecting char [NOT DETECTED; correct on Microsoft platforms]
swprintf(buffer, BUF_SIZE, u"%s", L"Hello"); // BAD: expecting char
swprintf(buffer, BUF_SIZE, u"%S", "Hello"); // BAD: expecting char16_t
swprintf(buffer, BUF_SIZE, u"%S", "Hello"); // BAD: expecting char16_t [NOT DETECTED; correct on Microsoft platforms]
swprintf(buffer, BUF_SIZE, u"%S", u"Hello"); // GOOD
swprintf(buffer, BUF_SIZE, u"%S", L"Hello"); // BAD: expecting char16_t

Просмотреть файл

@ -1,3 +1,2 @@
| printf.cpp:31:31:31:37 | test | This argument should be of type 'char *' but is of type 'char16_t *' |
| printf.cpp:43:29:43:35 | test | This argument should be of type 'char *' but is of type 'char16_t *' |
| printf.cpp:50:29:50:35 | test | This argument should be of type 'char16_t *' but is of type 'wchar_t *' |

Просмотреть файл

@ -28,7 +28,7 @@ int sprintf(char *dest, char *format, ...);
void test1() {
WCHAR string[20];
swprintf(string, u"test %s", u"test"); // BAD: `char16_t` string parameter read as `char` string
swprintf(string, u"test %s", u"test"); // BAD: `char16_t` string parameter read as `char` string [NOT DETECTED; correct on Microsoft platforms]
}
void test2() {

Просмотреть файл

@ -11,8 +11,6 @@
| printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
| printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
| printf1.h:130:18:130:18 | 0 | This argument should be of type 'void *' but is of type 'int' |
| printf1.h:154:18:154:19 | wc | This argument should be of type 'char *' but is of type 'wchar_t *' |
| printf1.h:155:18:155:18 | c | This argument should be of type 'wchar_t *' but is of type 'char *' |
| printf1.h:168:19:168:19 | i | This argument should be of type 'long long' but is of type 'int' |
| printf1.h:169:19:169:20 | ui | This argument should be of type 'unsigned long long' but is of type 'unsigned int' |
| real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' |

Просмотреть файл

@ -151,8 +151,8 @@ void test_chars(char c, wchar_t wc, wint_t wt)
void test_ws(char *c, wchar_t *wc)
{
wprintf(L"%s", c); // GOOD
wprintf(L"%s", wc); // BAD
wprintf(L"%S", c); // BAD
wprintf(L"%s", wc); // BAD [NOT DETECTED; correct on Microsoft platforms]
wprintf(L"%S", c); // BAD [NOT DETECTED; correct on Microsoft platforms]
wprintf(L"%S", wc); // GOOD
}

Просмотреть файл

@ -19,8 +19,6 @@
| printf1.h:116:16:116:24 | myString3 | This argument should be of type '__wchar_t *' but is of type 'int *' |
| printf1.h:117:16:117:24 | myString4 | This argument should be of type '__wchar_t *' but is of type 'int *' |
| printf1.h:130:18:130:18 | 0 | This argument should be of type 'void *' but is of type 'int' |
| printf1.h:153:18:153:18 | c | This argument should be of type '__wchar_t *' but is of type 'char *' |
| printf1.h:156:18:156:19 | wc | This argument should be of type 'char *' but is of type '__wchar_t *' |
| printf1.h:181:21:181:22 | ll | This argument should be of type 'int' but is of type 'long long' |
| printf1.h:182:21:182:23 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
| printf1.h:185:21:185:23 | i64 | This argument should be of type 'int' but is of type 'long long' |

Просмотреть файл

@ -150,10 +150,10 @@ void test_chars(char c, wchar_t wc, wint_t wt)
void test_ws(char *c, wchar_t *wc, wint_t *wt)
{
wprintf(L"%s", c); // BAD
wprintf(L"%s", c); // BAD [NOT DETECTED; correct on non-Microsoft platforms]
wprintf(L"%s", wc); // GOOD
wprintf(L"%S", c); // GOOD
wprintf(L"%S", wc); // BAD
wprintf(L"%S", wc); // BAD [NOT DETECTED; correct on non-Microsoft platforms]
}
void fun4()

Просмотреть файл

@ -59,20 +59,20 @@ edges
| test.cpp:237:24:237:37 | (const char *)... | test.cpp:247:2:247:8 | local_size |
| test.cpp:245:2:245:9 | local_size | test.cpp:224:23:224:23 | s |
| test.cpp:247:2:247:8 | local_size | test.cpp:230:21:230:21 | s |
| test.cpp:251:2:251:32 | Chi [array content] | test.cpp:289:17:289:20 | get_size output argument [array content] |
| test.cpp:251:2:251:32 | Chi [array content] | test.cpp:305:18:305:21 | get_size output argument [array content] |
| test.cpp:251:18:251:23 | call to getenv | test.cpp:251:2:251:32 | Chi [array content] |
| test.cpp:251:18:251:31 | (const char *)... | test.cpp:251:2:251:32 | Chi [array content] |
| test.cpp:251:2:251:32 | Chi [[]] | test.cpp:289:17:289:20 | get_size output argument [[]] |
| test.cpp:251:2:251:32 | Chi [[]] | test.cpp:305:18:305:21 | get_size output argument [[]] |
| test.cpp:251:18:251:23 | call to getenv | test.cpp:251:2:251:32 | Chi [[]] |
| test.cpp:251:18:251:31 | (const char *)... | test.cpp:251:2:251:32 | Chi [[]] |
| test.cpp:259:20:259:25 | call to getenv | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:259:20:259:25 | call to getenv | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:259:20:259:33 | (const char *)... | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:259:20:259:33 | (const char *)... | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:289:17:289:20 | Chi | test.cpp:291:11:291:28 | ... * ... |
| test.cpp:289:17:289:20 | Chi | test.cpp:291:11:291:28 | ... * ... |
| test.cpp:289:17:289:20 | get_size output argument [array content] | test.cpp:289:17:289:20 | Chi |
| test.cpp:289:17:289:20 | get_size output argument [[]] | test.cpp:289:17:289:20 | Chi |
| test.cpp:305:18:305:21 | Chi | test.cpp:308:10:308:27 | ... * ... |
| test.cpp:305:18:305:21 | Chi | test.cpp:308:10:308:27 | ... * ... |
| test.cpp:305:18:305:21 | get_size output argument [array content] | test.cpp:305:18:305:21 | Chi |
| test.cpp:305:18:305:21 | get_size output argument [[]] | test.cpp:305:18:305:21 | Chi |
nodes
| test.cpp:40:21:40:24 | argv | semmle.label | argv |
| test.cpp:40:21:40:24 | argv | semmle.label | argv |
@ -136,7 +136,7 @@ nodes
| test.cpp:241:9:241:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
| test.cpp:245:2:245:9 | local_size | semmle.label | local_size |
| test.cpp:247:2:247:8 | local_size | semmle.label | local_size |
| test.cpp:251:2:251:32 | Chi [array content] | semmle.label | Chi [array content] |
| test.cpp:251:2:251:32 | Chi [[]] | semmle.label | Chi [[]] |
| test.cpp:251:2:251:32 | ChiPartial | semmle.label | ChiPartial |
| test.cpp:251:18:251:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:251:18:251:31 | (const char *)... | semmle.label | (const char *)... |
@ -146,12 +146,12 @@ nodes
| test.cpp:263:11:263:29 | ... * ... | semmle.label | ... * ... |
| test.cpp:263:11:263:29 | ... * ... | semmle.label | ... * ... |
| test.cpp:289:17:289:20 | Chi | semmle.label | Chi |
| test.cpp:289:17:289:20 | get_size output argument [array content] | semmle.label | get_size output argument [array content] |
| test.cpp:289:17:289:20 | get_size output argument [[]] | semmle.label | get_size output argument [[]] |
| test.cpp:291:11:291:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:291:11:291:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:291:11:291:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:305:18:305:21 | Chi | semmle.label | Chi |
| test.cpp:305:18:305:21 | get_size output argument [array content] | semmle.label | get_size output argument [array content] |
| test.cpp:305:18:305:21 | get_size output argument [[]] | semmle.label | get_size output argument [[]] |
| test.cpp:308:10:308:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:308:10:308:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:308:10:308:27 | ... * ... | semmle.label | ... * ... |

Просмотреть файл

@ -1,9 +1,68 @@
| test2.cpp:14:11:14:11 | v | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
| test2.cpp:14:11:14:11 | v | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
| test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
| test5.cpp:19:6:19:6 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
| test5.cpp:19:6:19:6 | y | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:11:29:11:32 | argv | User-provided value |
| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
| test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
| test.c:54:7:54:10 | len3 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value |
edges
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
| test2.cpp:25:22:25:23 | & ... | test2.cpp:27:2:27:11 | v |
| test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:2:27:11 | v |
| test2.cpp:27:2:27:11 | v | test2.cpp:12:21:12:21 | v |
| test5.cpp:9:7:9:9 | buf | test5.cpp:10:9:10:27 | Store |
| test5.cpp:9:7:9:9 | gets output argument | test5.cpp:10:9:10:27 | Store |
| test5.cpp:10:9:10:27 | Store | test5.cpp:17:6:17:18 | call to getTaintedInt |
| test5.cpp:10:9:10:27 | Store | test5.cpp:17:6:17:18 | call to getTaintedInt |
| test5.cpp:10:9:10:27 | Store | test5.cpp:18:6:18:18 | call to getTaintedInt |
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y |
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y |
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
nodes
| test2.cpp:12:21:12:21 | v | semmle.label | v |
| test2.cpp:14:11:14:11 | v | semmle.label | v |
| test2.cpp:14:11:14:11 | v | semmle.label | v |
| test2.cpp:14:11:14:11 | v | semmle.label | v |
| test2.cpp:25:22:25:23 | & ... | semmle.label | & ... |
| test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument |
| test2.cpp:27:2:27:11 | v | semmle.label | v |
| test5.cpp:9:7:9:9 | buf | semmle.label | buf |
| test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument |
| test5.cpp:10:9:10:27 | Store | semmle.label | Store |
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
| test5.cpp:19:6:19:6 | y | semmle.label | y |
| test5.cpp:19:6:19:6 | y | semmle.label | y |
| test5.cpp:19:6:19:6 | y | semmle.label | y |
| test.c:11:29:11:32 | argv | semmle.label | argv |
| test.c:11:29:11:32 | argv | semmle.label | argv |
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
| test.c:41:17:41:20 | argv | semmle.label | argv |
| test.c:41:17:41:20 | argv | semmle.label | argv |
| test.c:44:7:44:10 | len2 | semmle.label | len2 |
| test.c:44:7:44:10 | len2 | semmle.label | len2 |
| test.c:44:7:44:10 | len2 | semmle.label | len2 |
| test.c:51:17:51:20 | argv | semmle.label | argv |
| test.c:51:17:51:20 | argv | semmle.label | argv |
| test.c:54:7:54:10 | len3 | semmle.label | len3 |
| test.c:54:7:54:10 | len3 | semmle.label | len3 |
| test.c:54:7:54:10 | len3 | semmle.label | len3 |
#select
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
| test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | buf | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | buf | test5.cpp:19:6:19:6 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | buf | test5.cpp:19:6:19:6 | y | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
| test.c:14:15:14:28 | maxConnections | test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:11:29:11:32 | argv | User-provided value |
| test.c:14:15:14:28 | maxConnections | test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
| test.c:44:7:44:10 | len2 | test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
| test.c:54:7:54:10 | len3 | test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value |

Просмотреть файл

@ -1,97 +1,60 @@
edges
| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r |
| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r |
| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r |
| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r |
| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r |
| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r |
| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r |
| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r |
| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r |
| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r |
| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r |
| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r |
| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r |
| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r |
| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r |
| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r |
| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r |
| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r |
| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r |
| test.c:75:13:75:19 | call to rand | test.c:77:9:77:9 | r |
| test.c:75:13:75:19 | call to rand | test.c:77:9:77:9 | r |
| test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r |
| test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r |
| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r |
| test.cpp:8:9:8:12 | Store | test.cpp:24:11:24:18 | call to get_rand |
| test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store |
| test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store |
| test.cpp:13:2:13:15 | Chi [array content] | test.cpp:30:13:30:14 | get_rand2 output argument [array content] |
| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi [array content] |
| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi [array content] |
| test.cpp:18:2:18:14 | Chi [array content] | test.cpp:36:13:36:13 | get_rand3 output argument [array content] |
| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [array content] |
| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [array content] |
| test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r |
| test.cpp:13:2:13:15 | Chi [[]] | test.cpp:30:13:30:14 | get_rand2 output argument [[]] |
| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi [[]] |
| test.cpp:18:2:18:14 | Chi [[]] | test.cpp:36:13:36:13 | get_rand3 output argument [[]] |
| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [[]] |
| test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r |
| test.cpp:30:13:30:14 | Chi | test.cpp:31:7:31:7 | r |
| test.cpp:30:13:30:14 | Chi | test.cpp:31:7:31:7 | r |
| test.cpp:30:13:30:14 | get_rand2 output argument [array content] | test.cpp:30:13:30:14 | Chi |
| test.cpp:30:13:30:14 | get_rand2 output argument [[]] | test.cpp:30:13:30:14 | Chi |
| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r |
| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r |
| test.cpp:36:13:36:13 | get_rand3 output argument [array content] | test.cpp:36:13:36:13 | Chi |
| test.cpp:36:13:36:13 | get_rand3 output argument [[]] | test.cpp:36:13:36:13 | Chi |
nodes
| test.c:18:13:18:16 | call to rand | semmle.label | call to rand |
| test.c:18:13:18:16 | call to rand | semmle.label | call to rand |
| test.c:21:17:21:17 | r | semmle.label | r |
| test.c:21:17:21:17 | r | semmle.label | r |
| test.c:21:17:21:17 | r | semmle.label | r |
| test.c:34:13:34:18 | call to rand | semmle.label | call to rand |
| test.c:34:13:34:18 | call to rand | semmle.label | call to rand |
| test.c:35:5:35:5 | r | semmle.label | r |
| test.c:35:5:35:5 | r | semmle.label | r |
| test.c:35:5:35:5 | r | semmle.label | r |
| test.c:44:13:44:16 | call to rand | semmle.label | call to rand |
| test.c:44:13:44:16 | call to rand | semmle.label | call to rand |
| test.c:45:5:45:5 | r | semmle.label | r |
| test.c:45:5:45:5 | r | semmle.label | r |
| test.c:45:5:45:5 | r | semmle.label | r |
| test.c:75:13:75:19 | ... ^ ... | semmle.label | ... ^ ... |
| test.c:75:13:75:19 | ... ^ ... | semmle.label | ... ^ ... |
| test.c:77:9:77:9 | r | semmle.label | r |
| test.c:77:9:77:9 | r | semmle.label | r |
| test.c:75:13:75:19 | call to rand | semmle.label | call to rand |
| test.c:75:13:75:19 | call to rand | semmle.label | call to rand |
| test.c:77:9:77:9 | r | semmle.label | r |
| test.c:81:14:81:17 | call to rand | semmle.label | call to rand |
| test.c:81:23:81:26 | call to rand | semmle.label | call to rand |
| test.c:83:9:83:9 | r | semmle.label | r |
| test.c:99:14:99:19 | call to rand | semmle.label | call to rand |
| test.c:99:14:99:19 | call to rand | semmle.label | call to rand |
| test.c:100:5:100:5 | r | semmle.label | r |
| test.c:100:5:100:5 | r | semmle.label | r |
| test.c:100:5:100:5 | r | semmle.label | r |
| test.cpp:8:9:8:12 | Store | semmle.label | Store |
| test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand |
| test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand |
| test.cpp:13:2:13:15 | Chi [array content] | semmle.label | Chi [array content] |
| test.cpp:13:2:13:15 | ChiPartial | semmle.label | ChiPartial |
| test.cpp:13:2:13:15 | Chi [[]] | semmle.label | Chi [[]] |
| test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand |
| test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand |
| test.cpp:18:2:18:14 | Chi [array content] | semmle.label | Chi [array content] |
| test.cpp:18:2:18:14 | ChiPartial | semmle.label | ChiPartial |
| test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand |
| test.cpp:18:2:18:14 | Chi [[]] | semmle.label | Chi [[]] |
| test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand |
| test.cpp:24:11:24:18 | call to get_rand | semmle.label | call to get_rand |
| test.cpp:25:7:25:7 | r | semmle.label | r |
| test.cpp:25:7:25:7 | r | semmle.label | r |
| test.cpp:25:7:25:7 | r | semmle.label | r |
| test.cpp:30:13:30:14 | Chi | semmle.label | Chi |
| test.cpp:30:13:30:14 | get_rand2 output argument [array content] | semmle.label | get_rand2 output argument [array content] |
| test.cpp:31:7:31:7 | r | semmle.label | r |
| test.cpp:31:7:31:7 | r | semmle.label | r |
| test.cpp:30:13:30:14 | get_rand2 output argument [[]] | semmle.label | get_rand2 output argument [[]] |
| test.cpp:31:7:31:7 | r | semmle.label | r |
| test.cpp:36:13:36:13 | Chi | semmle.label | Chi |
| test.cpp:36:13:36:13 | get_rand3 output argument [array content] | semmle.label | get_rand3 output argument [array content] |
| test.cpp:37:7:37:7 | r | semmle.label | r |
| test.cpp:37:7:37:7 | r | semmle.label | r |
| test.cpp:36:13:36:13 | get_rand3 output argument [[]] | semmle.label | get_rand3 output argument [[]] |
| test.cpp:37:7:37:7 | r | semmle.label | r |
#select
| test.c:21:17:21:17 | r | test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:18:13:18:16 | call to rand | Uncontrolled value |
| test.c:35:5:35:5 | r | test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:34:13:34:18 | call to rand | Uncontrolled value |
| test.c:45:5:45:5 | r | test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:44:13:44:16 | call to rand | Uncontrolled value |
| test.c:77:9:77:9 | r | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | ... ^ ... | Uncontrolled value |
| test.c:77:9:77:9 | r | test.c:75:13:75:19 | call to rand | test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | call to rand | Uncontrolled value |
| test.c:77:9:77:9 | r | test.c:75:13:75:19 | call to rand | test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | call to rand | Uncontrolled value |
| test.c:83:9:83:9 | r | test.c:81:14:81:17 | call to rand | test.c:83:9:83:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:14:81:17 | call to rand | Uncontrolled value |
| test.c:83:9:83:9 | r | test.c:81:23:81:26 | call to rand | test.c:83:9:83:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:23:81:26 | call to rand | Uncontrolled value |
| test.c:100:5:100:5 | r | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:99:14:99:19 | call to rand | Uncontrolled value |
| test.cpp:25:7:25:7 | r | test.cpp:8:9:8:12 | call to rand | test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value |
| test.cpp:31:7:31:7 | r | test.cpp:13:10:13:13 | call to rand | test.cpp:31:7:31:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:13:10:13:13 | call to rand | Uncontrolled value |

Просмотреть файл

@ -80,7 +80,7 @@ void randomTester() {
{
int r = (rand() ^ rand());
r = r - 100; // BAD [NOT DETECTED]
r = r - 100; // BAD
}
{
@ -110,3 +110,12 @@ void randomTester() {
void add_100(int r) {
r += 100; // GOOD
}
void randomTester2(int bound, int min, int max) {
int r1 = rand() % bound;
r1 += 100; // GOOD (`bound` may possibly be MAX_INT in which case this could
// still overflow, but it's most likely fine)
int r2 = (rand() % (max - min + 1)) + min;
r2 += 100; // GOOD (This is a common way to clamp the random value between [min, max])
}

Просмотреть файл

@ -0,0 +1,2 @@
lgtm,codescanning
* The DataFlow libraries have been augmented with support for `Configuration`-specific in-place read steps at, for example, sinks and custom taint steps. This means that it is now possible to specify sinks that accept flow with non-empty access paths.

Просмотреть файл

@ -0,0 +1,2 @@
package,sink,source,summary,sink:html,sink:xss,source:local,summary:taint
System,5,3,13,4,1,3,13
1 package sink source summary sink:html sink:xss source:local summary:taint
2 System 5 3 13 4 1 3 13

Просмотреть файл

@ -0,0 +1,12 @@
C# framework & library support
================================
.. csv-table::
:header-rows: 1
:class: fullWidthTable
:widths: auto
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
System,"``System.*``, ``System``",3,13,5,5
Totals,,3,13,5,5

Просмотреть файл

@ -0,0 +1,2 @@
CWE,Sink identifier,Label
CWE-079,html xss,Cross-site scripting
1 CWE Sink identifier Label
2 CWE-079 html xss Cross-site scripting

Просмотреть файл

@ -0,0 +1,2 @@
Framework name,URL,Namespace prefixes
System,,System.* System
1 Framework name URL Namespace prefixes
2 System System.* System

Просмотреть файл

@ -108,7 +108,10 @@ namespace Semmle.BuildAnalyser
new[] { options.SolutionFile } :
sourceDir.GetFiles("*.sln", SearchOption.AllDirectories).Select(d => d.FullName);
if (options.UseNuGet)
{
RestoreSolutions(solutions);
}
dllDirNames.Add(packageDirectory.DirInfo.FullName);
assemblyCache = new BuildAnalyser.AssemblyCache(dllDirNames, progress);
AnalyseSolutions(solutions);
@ -324,7 +327,16 @@ namespace Semmle.BuildAnalyser
private void Restore(string projectOrSolution)
{
var exit = DotNet.RestoreToDirectory(projectOrSolution, packageDirectory.DirInfo.FullName);
int exit;
try
{
exit = DotNet.RestoreToDirectory(projectOrSolution, packageDirectory.DirInfo.FullName);
}
catch (FileNotFoundException)
{
exit = 2;
}
switch (exit)
{
case 0:

Просмотреть файл

@ -42,7 +42,5 @@ namespace Semmle.Extraction.CSharp.Entities
public override CommentBlock Create(Context cx, Comments.CommentBlock init) => new CommentBlock(cx, init);
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}

Просмотреть файл

@ -87,8 +87,6 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.Write(";compilation");
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
public override Location ReportingLocation => throw new NotImplementedException();
public override bool NeedsPopulation => Context.IsAssemblyScope;

Просмотреть файл

@ -4,8 +4,6 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class Diagnostic : FreshEntity
{
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
private readonly Microsoft.CodeAnalysis.Diagnostic diagnostic;
public Diagnostic(Context cx, Microsoft.CodeAnalysis.Diagnostic diag) : base(cx)

Просмотреть файл

@ -71,7 +71,5 @@ namespace Semmle.Extraction.CSharp.Entities
public override Event Create(Context cx, IEventSymbol init) => new Event(cx, init);
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}

Просмотреть файл

@ -43,8 +43,6 @@ namespace Semmle.Extraction.CSharp.Entities
public override Namespace Create(Context cx, INamespaceSymbol init) => new Namespace(cx, init);
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
public override int GetHashCode() => QualifiedName.GetHashCode();
private string QualifiedName => Symbol.ToDisplayString();

Просмотреть файл

@ -60,8 +60,6 @@ namespace Semmle.Extraction.CSharp.Entities
new NamespaceDeclaration(cx, init.decl, init.parent);
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
public override Microsoft.CodeAnalysis.Location ReportingLocation => node.Name.GetLocation();
public override bool NeedsPopulation => true;

Просмотреть файл

@ -5,14 +5,24 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class DefineDirective : PreprocessorDirective<DefineDirectiveTriviaSyntax>
{
public DefineDirective(Context cx, DefineDirectiveTriviaSyntax trivia)
private DefineDirective(Context cx, DefineDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_defines(this, trivia.Name.ToString());
trapFile.directive_defines(this, Symbol.Name.ToString());
}
public static DefineDirective Create(Context cx, DefineDirectiveTriviaSyntax def) =>
DefineDirectiveFactory.Instance.CreateEntity(cx, def, def);
private class DefineDirectiveFactory : CachedEntityFactory<DefineDirectiveTriviaSyntax, DefineDirective>
{
public static DefineDirectiveFactory Instance { get; } = new DefineDirectiveFactory();
public override DefineDirective Create(Context cx, DefineDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

Просмотреть файл

@ -8,21 +8,41 @@ namespace Semmle.Extraction.CSharp.Entities
private readonly IfDirective start;
private readonly int index;
public ElifDirective(Context cx, ElifDirectiveTriviaSyntax trivia, IfDirective start, int index)
: base(cx, trivia, populateFromBase: false)
private ElifDirective(Context cx, ElifDirectiveTriviaSyntax trivia, IfDirective start, int index)
: base(cx, trivia)
{
this.start = start;
this.index = index;
TryPopulate();
}
public bool IsTopLevelParent => true;
public override void WriteId(EscapingTextWriter trapFile)
{
trapFile.WriteSubId(Context.CreateLocation(ReportingLocation));
trapFile.Write(Symbol.IsActive);
trapFile.Write(',');
trapFile.Write(Symbol.BranchTaken);
trapFile.Write(',');
trapFile.Write(Symbol.ConditionValue);
trapFile.Write(";trivia");
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_elifs(this, trivia.BranchTaken, trivia.ConditionValue, start, index);
trapFile.directive_elifs(this, Symbol.BranchTaken, Symbol.ConditionValue, start, index);
Expression.Create(Context, trivia.Condition, this, 0);
Expression.Create(Context, Symbol.Condition, this, 0);
}
public static ElifDirective Create(Context cx, ElifDirectiveTriviaSyntax elif, IfDirective start, int index) =>
ElifDirectiveFactory.Instance.CreateEntity(cx, elif, (elif, start, index));
private class ElifDirectiveFactory : CachedEntityFactory<(ElifDirectiveTriviaSyntax elif, IfDirective start, int index), ElifDirective>
{
public static ElifDirectiveFactory Instance { get; } = new ElifDirectiveFactory();
public override ElifDirective Create(Context cx, (ElifDirectiveTriviaSyntax elif, IfDirective start, int index) init) => new(cx, init.elif, init.start, init.index);
}
}
}

Просмотреть файл

@ -8,17 +8,35 @@ namespace Semmle.Extraction.CSharp.Entities
private readonly IfDirective start;
private readonly int index;
public ElseDirective(Context cx, ElseDirectiveTriviaSyntax trivia, IfDirective start, int index)
: base(cx, trivia, populateFromBase: false)
private ElseDirective(Context cx, ElseDirectiveTriviaSyntax trivia, IfDirective start, int index)
: base(cx, trivia)
{
this.start = start;
this.index = index;
TryPopulate();
}
public override void WriteId(EscapingTextWriter trapFile)
{
trapFile.WriteSubId(Context.CreateLocation(ReportingLocation));
trapFile.Write(Symbol.IsActive);
trapFile.Write(',');
trapFile.Write(Symbol.BranchTaken);
trapFile.Write(";trivia");
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_elses(this, trivia.BranchTaken, start, index);
trapFile.directive_elses(this, Symbol.BranchTaken, start, index);
}
public static ElseDirective Create(Context cx, ElseDirectiveTriviaSyntax @else, IfDirective start, int index) =>
ElseDirectiveFactory.Instance.CreateEntity(cx, @else, (@else, start, index));
private class ElseDirectiveFactory : CachedEntityFactory<(ElseDirectiveTriviaSyntax @else, IfDirective start, int index), ElseDirective>
{
public static ElseDirectiveFactory Instance { get; } = new ElseDirectiveFactory();
public override ElseDirective Create(Context cx, (ElseDirectiveTriviaSyntax @else, IfDirective start, int index) init) => new(cx, init.@else, init.start, init.index);
}
}
}

Просмотреть файл

@ -7,16 +7,25 @@ namespace Semmle.Extraction.CSharp.Entities
{
private readonly IfDirective start;
public EndIfDirective(Context cx, EndIfDirectiveTriviaSyntax trivia, IfDirective start)
: base(cx, trivia, populateFromBase: false)
private EndIfDirective(Context cx, EndIfDirectiveTriviaSyntax trivia, IfDirective start)
: base(cx, trivia)
{
this.start = start;
TryPopulate();
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_endifs(this, start);
}
public static EndIfDirective Create(Context cx, EndIfDirectiveTriviaSyntax endif, IfDirective start) =>
EndIfDirectiveFactory.Instance.CreateEntity(cx, endif, (endif, start));
private class EndIfDirectiveFactory : CachedEntityFactory<(EndIfDirectiveTriviaSyntax endif, IfDirective start), EndIfDirective>
{
public static EndIfDirectiveFactory Instance { get; } = new EndIfDirectiveFactory();
public override EndIfDirective Create(Context cx, (EndIfDirectiveTriviaSyntax endif, IfDirective start) init) => new(cx, init.endif, init.start);
}
}
}

Просмотреть файл

@ -7,16 +7,25 @@ namespace Semmle.Extraction.CSharp.Entities
{
private readonly RegionDirective region;
public EndRegionDirective(Context cx, EndRegionDirectiveTriviaSyntax trivia, RegionDirective region)
: base(cx, trivia, populateFromBase: false)
private EndRegionDirective(Context cx, EndRegionDirectiveTriviaSyntax trivia, RegionDirective region)
: base(cx, trivia)
{
this.region = region;
TryPopulate();
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_endregions(this, region);
}
public static EndRegionDirective Create(Context cx, EndRegionDirectiveTriviaSyntax end, RegionDirective start) =>
EndRegionDirectiveFactory.Instance.CreateEntity(cx, end, (end, start));
private class EndRegionDirectiveFactory : CachedEntityFactory<(EndRegionDirectiveTriviaSyntax end, RegionDirective start), EndRegionDirective>
{
public static EndRegionDirectiveFactory Instance { get; } = new EndRegionDirectiveFactory();
public override EndRegionDirective Create(Context cx, (EndRegionDirectiveTriviaSyntax end, RegionDirective start) init) => new(cx, init.end, init.start);
}
}
}

Просмотреть файл

@ -5,14 +5,24 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class ErrorDirective : PreprocessorDirective<ErrorDirectiveTriviaSyntax>
{
public ErrorDirective(Context cx, ErrorDirectiveTriviaSyntax trivia)
private ErrorDirective(Context cx, ErrorDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_errors(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString());
trapFile.directive_errors(this, Symbol.EndOfDirectiveToken.LeadingTrivia.ToString());
}
public static ErrorDirective Create(Context cx, ErrorDirectiveTriviaSyntax error) =>
ErrorDirectiveFactory.Instance.CreateEntity(cx, error, error);
private class ErrorDirectiveFactory : CachedEntityFactory<ErrorDirectiveTriviaSyntax, ErrorDirective>
{
public static ErrorDirectiveFactory Instance { get; } = new ErrorDirectiveFactory();
public override ErrorDirective Create(Context cx, ErrorDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

Просмотреть файл

@ -5,18 +5,39 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class IfDirective : PreprocessorDirective<IfDirectiveTriviaSyntax>, IExpressionParentEntity
{
public IfDirective(Context cx, IfDirectiveTriviaSyntax trivia)
private IfDirective(Context cx, IfDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
public bool IsTopLevelParent => true;
public override void WriteId(EscapingTextWriter trapFile)
{
trapFile.WriteSubId(Context.CreateLocation(ReportingLocation));
trapFile.Write(Symbol.IsActive);
trapFile.Write(',');
trapFile.Write(Symbol.BranchTaken);
trapFile.Write(',');
trapFile.Write(Symbol.ConditionValue);
trapFile.Write(";trivia");
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_ifs(this, trivia.BranchTaken, trivia.ConditionValue);
trapFile.directive_ifs(this, Symbol.BranchTaken, Symbol.ConditionValue);
Expression.Create(Context, trivia.Condition, this, 0);
Expression.Create(Context, Symbol.Condition, this, 0);
}
public static IfDirective Create(Context cx, IfDirectiveTriviaSyntax @if) =>
IfDirectiveFactory.Instance.CreateEntity(cx, @if, @if);
private class IfDirectiveFactory : CachedEntityFactory<IfDirectiveTriviaSyntax, IfDirective>
{
public static IfDirectiveFactory Instance { get; } = new IfDirectiveFactory();
public override IfDirective Create(Context cx, IfDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

Просмотреть файл

@ -7,34 +7,44 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class LineDirective : PreprocessorDirective<LineDirectiveTriviaSyntax>
{
public LineDirective(Context cx, LineDirectiveTriviaSyntax trivia)
private LineDirective(Context cx, LineDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
var type = trivia.Line.Kind() switch
var type = Symbol.Line.Kind() switch
{
SyntaxKind.DefaultKeyword => 0,
SyntaxKind.HiddenKeyword => 1,
SyntaxKind.NumericLiteralToken => 2,
_ => throw new InternalError(trivia, "Unhandled line token kind")
_ => throw new InternalError(Symbol, "Unhandled line token kind")
};
trapFile.directive_lines(this, type);
if (trivia.Line.IsKind(SyntaxKind.NumericLiteralToken))
if (Symbol.Line.IsKind(SyntaxKind.NumericLiteralToken))
{
var value = (int)trivia.Line.Value!;
var value = (int)Symbol.Line.Value!;
trapFile.directive_line_value(this, value);
if (!string.IsNullOrWhiteSpace(trivia.File.ValueText))
if (!string.IsNullOrWhiteSpace(Symbol.File.ValueText))
{
var file = File.Create(Context, trivia.File.ValueText);
var file = File.Create(Context, Symbol.File.ValueText);
trapFile.directive_line_file(this, file);
}
}
}
public static LineDirective Create(Context cx, LineDirectiveTriviaSyntax line) =>
LineDirectiveFactory.Instance.CreateEntity(cx, line, line);
private class LineDirectiveFactory : CachedEntityFactory<LineDirectiveTriviaSyntax, LineDirective>
{
public static LineDirectiveFactory Instance { get; } = new LineDirectiveFactory();
public override LineDirective Create(Context cx, LineDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

Просмотреть файл

@ -6,30 +6,40 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class NullableDirective : PreprocessorDirective<NullableDirectiveTriviaSyntax>
{
public NullableDirective(Context cx, NullableDirectiveTriviaSyntax trivia)
private NullableDirective(Context cx, NullableDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
var setting = trivia.SettingToken.Kind() switch
var setting = Symbol.SettingToken.Kind() switch
{
SyntaxKind.DisableKeyword => 0,
SyntaxKind.EnableKeyword => 1,
SyntaxKind.RestoreKeyword => 2,
_ => throw new InternalError(trivia, "Unhandled setting token kind")
_ => throw new InternalError(Symbol, "Unhandled setting token kind")
};
var target = trivia.TargetToken.Kind() switch
var target = Symbol.TargetToken.Kind() switch
{
SyntaxKind.None => 0,
SyntaxKind.AnnotationsKeyword => 1,
SyntaxKind.WarningsKeyword => 2,
_ => throw new InternalError(trivia, "Unhandled target token kind")
_ => throw new InternalError(Symbol, "Unhandled target token kind")
};
trapFile.directive_nullables(this, setting, target);
}
public static NullableDirective Create(Context cx, NullableDirectiveTriviaSyntax nullable) =>
NullableDirectiveFactory.Instance.CreateEntity(cx, nullable, nullable);
private class NullableDirectiveFactory : CachedEntityFactory<NullableDirectiveTriviaSyntax, NullableDirective>
{
public static NullableDirectiveFactory Instance { get; } = new NullableDirectiveFactory();
public override NullableDirective Create(Context cx, NullableDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

Просмотреть файл

@ -5,15 +5,25 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class PragmaChecksumDirective : PreprocessorDirective<PragmaChecksumDirectiveTriviaSyntax>
{
public PragmaChecksumDirective(Context cx, PragmaChecksumDirectiveTriviaSyntax trivia)
private PragmaChecksumDirective(Context cx, PragmaChecksumDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
var file = File.Create(Context, trivia.File.ValueText);
trapFile.pragma_checksums(this, file, trivia.Guid.ToString(), trivia.Bytes.ToString());
var file = File.Create(Context, Symbol.File.ValueText);
trapFile.pragma_checksums(this, file, Symbol.Guid.ToString(), Symbol.Bytes.ToString());
}
public static PragmaChecksumDirective Create(Context cx, PragmaChecksumDirectiveTriviaSyntax p) =>
PragmaChecksumDirectiveFactory.Instance.CreateEntity(cx, p, p);
private class PragmaChecksumDirectiveFactory : CachedEntityFactory<PragmaChecksumDirectiveTriviaSyntax, PragmaChecksumDirective>
{
public static PragmaChecksumDirectiveFactory Instance { get; } = new PragmaChecksumDirectiveFactory();
public override PragmaChecksumDirective Create(Context cx, PragmaChecksumDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

Просмотреть файл

@ -7,20 +7,30 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class PragmaWarningDirective : PreprocessorDirective<PragmaWarningDirectiveTriviaSyntax>
{
public PragmaWarningDirective(Context cx, PragmaWarningDirectiveTriviaSyntax trivia)
private PragmaWarningDirective(Context cx, PragmaWarningDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.pragma_warnings(this, trivia.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword) ? 0 : 1);
trapFile.pragma_warnings(this, Symbol.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword) ? 0 : 1);
var childIndex = 0;
foreach (var code in trivia.ErrorCodes)
foreach (var code in Symbol.ErrorCodes)
{
trapFile.pragma_warning_error_codes(this, code.ToString(), childIndex++);
}
}
public static PragmaWarningDirective Create(Context cx, PragmaWarningDirectiveTriviaSyntax p) =>
PragmaWarningDirectiveFactory.Instance.CreateEntity(cx, p, p);
private class PragmaWarningDirectiveFactory : CachedEntityFactory<PragmaWarningDirectiveTriviaSyntax, PragmaWarningDirective>
{
public static PragmaWarningDirectiveFactory Instance { get; } = new PragmaWarningDirectiveFactory();
public override PragmaWarningDirective Create(Context cx, PragmaWarningDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

Просмотреть файл

@ -4,25 +4,16 @@ using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal abstract class PreprocessorDirective<TDirective> : FreshEntity where TDirective : DirectiveTriviaSyntax
internal abstract class PreprocessorDirective<TDirective> : CachedEntity<TDirective> where TDirective : DirectiveTriviaSyntax
{
protected readonly TDirective trivia;
protected PreprocessorDirective(Context cx, TDirective trivia)
: base(cx, trivia) { }
protected PreprocessorDirective(Context cx, TDirective trivia, bool populateFromBase = true)
: base(cx)
{
this.trivia = trivia;
if (populateFromBase)
{
TryPopulate();
}
}
protected sealed override void Populate(TextWriter trapFile)
public sealed override void Populate(TextWriter trapFile)
{
PopulatePreprocessor(trapFile);
trapFile.preprocessor_directive_active(this, trivia.IsActive);
trapFile.preprocessor_directive_active(this, Symbol.IsActive);
trapFile.preprocessor_directive_location(this, Context.CreateLocation(ReportingLocation));
if (!Context.Extractor.Standalone)
@ -34,8 +25,17 @@ namespace Semmle.Extraction.CSharp.Entities
protected abstract void PopulatePreprocessor(TextWriter trapFile);
public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => trivia.GetLocation();
public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => Symbol.GetLocation();
public override bool NeedsPopulation => true;
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
public override void WriteId(EscapingTextWriter trapFile)
{
trapFile.WriteSubId(Context.CreateLocation(ReportingLocation));
trapFile.Write(Symbol.IsActive);
trapFile.Write(";trivia");
}
}
}

Просмотреть файл

@ -6,14 +6,24 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class RegionDirective : PreprocessorDirective<RegionDirectiveTriviaSyntax>
{
public RegionDirective(Context cx, RegionDirectiveTriviaSyntax trivia)
private RegionDirective(Context cx, RegionDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_regions(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString());
trapFile.directive_regions(this, Symbol.EndOfDirectiveToken.LeadingTrivia.ToString());
}
public static RegionDirective Create(Context cx, RegionDirectiveTriviaSyntax region) =>
RegionDirectiveFactory.Instance.CreateEntity(cx, region, region);
private class RegionDirectiveFactory : CachedEntityFactory<RegionDirectiveTriviaSyntax, RegionDirective>
{
public static RegionDirectiveFactory Instance { get; } = new RegionDirectiveFactory();
public override RegionDirective Create(Context cx, RegionDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

Просмотреть файл

@ -5,14 +5,24 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class UndefineDirective : PreprocessorDirective<UndefDirectiveTriviaSyntax>
{
public UndefineDirective(Context cx, UndefDirectiveTriviaSyntax trivia)
private UndefineDirective(Context cx, UndefDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_undefines(this, trivia.Name.ToString());
trapFile.directive_undefines(this, Symbol.Name.ToString());
}
public static UndefineDirective Create(Context cx, UndefDirectiveTriviaSyntax undef) =>
UndefineDirectiveFactory.Instance.CreateEntity(cx, undef, undef);
private class UndefineDirectiveFactory : CachedEntityFactory<UndefDirectiveTriviaSyntax, UndefineDirective>
{
public static UndefineDirectiveFactory Instance { get; } = new UndefineDirectiveFactory();
public override UndefineDirective Create(Context cx, UndefDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

Просмотреть файл

@ -5,14 +5,24 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class WarningDirective : PreprocessorDirective<WarningDirectiveTriviaSyntax>
{
public WarningDirective(Context cx, WarningDirectiveTriviaSyntax trivia)
private WarningDirective(Context cx, WarningDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_warnings(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString());
trapFile.directive_warnings(this, Symbol.EndOfDirectiveToken.LeadingTrivia.ToString());
}
public static WarningDirective Create(Context cx, WarningDirectiveTriviaSyntax warning) =>
WarningDirectiveFactory.Instance.CreateEntity(cx, warning, warning);
private class WarningDirectiveFactory : CachedEntityFactory<WarningDirectiveTriviaSyntax, WarningDirective>
{
public static WarningDirectiveFactory Instance { get; } = new WarningDirectiveFactory();
public override WarningDirective Create(Context cx, WarningDirectiveTriviaSyntax init) => new(cx, init);
}
}
}

Просмотреть файл

@ -2,7 +2,6 @@ using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.CSharp.Entities.Expressions;
using Semmle.Extraction.Entities;
using Semmle.Extraction.Kinds;
using System.IO;
using System.Linq;

Просмотреть файл

@ -341,8 +341,6 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
public override bool Equals(object? obj)
{
var other = obj as Type;

Просмотреть файл

@ -7,8 +7,6 @@ namespace Semmle.Extraction.CSharp.Entities
public TypeParameterConstraints(Context cx)
: base(cx) { }
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
protected override void Populate(TextWriter trapFile)
{
}

Просмотреть файл

@ -54,7 +54,5 @@ namespace Semmle.Extraction.CSharp.Entities
}
public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => node.GetLocation();
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}

Просмотреть файл

@ -212,8 +212,13 @@ namespace Semmle.Extraction.CSharp
Entities.File.Create(cx, root.SyntaxTree.FilePath);
var csNode = (CSharpSyntaxNode)root;
var directiveVisitor = new DirectiveVisitor(cx);
csNode.Accept(directiveVisitor);
foreach (var branch in directiveVisitor.BranchesTaken)
{
cx.TrapStackSuffix.Add(branch);
}
csNode.Accept(new CompilationUnitVisitor(cx));
csNode.Accept(new DirectiveVisitor(cx));
cx.PopulateAll();
CommentPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator);
cx.PopulateAll();

Просмотреть файл

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@ -8,6 +9,13 @@ namespace Semmle.Extraction.CSharp.Populators
internal class DirectiveVisitor : CSharpSyntaxWalker
{
private readonly Context cx;
private readonly List<IEntity> branchesTaken = new();
/// <summary>
/// Gets a list of `#if`, `#elif`, and `#else` entities where the branch
/// is taken.
/// </summary>
public IEnumerable<IEntity> BranchesTaken => branchesTaken;
public DirectiveVisitor(Context cx) : base(SyntaxWalkerDepth.StructuredTrivia)
{
@ -16,49 +24,49 @@ namespace Semmle.Extraction.CSharp.Populators
public override void VisitPragmaWarningDirectiveTrivia(PragmaWarningDirectiveTriviaSyntax node)
{
new Entities.PragmaWarningDirective(cx, node);
Entities.PragmaWarningDirective.Create(cx, node);
}
public override void VisitPragmaChecksumDirectiveTrivia(PragmaChecksumDirectiveTriviaSyntax node)
{
new Entities.PragmaChecksumDirective(cx, node);
Entities.PragmaChecksumDirective.Create(cx, node);
}
public override void VisitDefineDirectiveTrivia(DefineDirectiveTriviaSyntax node)
{
new Entities.DefineDirective(cx, node);
Entities.DefineDirective.Create(cx, node);
}
public override void VisitUndefDirectiveTrivia(UndefDirectiveTriviaSyntax node)
{
new Entities.UndefineDirective(cx, node);
Entities.UndefineDirective.Create(cx, node);
}
public override void VisitWarningDirectiveTrivia(WarningDirectiveTriviaSyntax node)
{
new Entities.WarningDirective(cx, node);
Entities.WarningDirective.Create(cx, node);
}
public override void VisitErrorDirectiveTrivia(ErrorDirectiveTriviaSyntax node)
{
new Entities.ErrorDirective(cx, node);
Entities.ErrorDirective.Create(cx, node);
}
public override void VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node)
{
new Entities.NullableDirective(cx, node);
Entities.NullableDirective.Create(cx, node);
}
public override void VisitLineDirectiveTrivia(LineDirectiveTriviaSyntax node)
{
new Entities.LineDirective(cx, node);
Entities.LineDirective.Create(cx, node);
}
private readonly Stack<Entities.RegionDirective> regionStarts = new Stack<Entities.RegionDirective>();
public override void VisitRegionDirectiveTrivia(RegionDirectiveTriviaSyntax node)
{
var region = new Entities.RegionDirective(cx, node);
var region = Entities.RegionDirective.Create(cx, node);
regionStarts.Push(region);
}
@ -72,7 +80,7 @@ namespace Semmle.Extraction.CSharp.Populators
}
var start = regionStarts.Pop();
new Entities.EndRegionDirective(cx, node, start);
Entities.EndRegionDirective.Create(cx, node, start);
}
private class IfDirectiveStackElement
@ -91,8 +99,10 @@ namespace Semmle.Extraction.CSharp.Populators
public override void VisitIfDirectiveTrivia(IfDirectiveTriviaSyntax node)
{
var ifStart = new Entities.IfDirective(cx, node);
var ifStart = Entities.IfDirective.Create(cx, node);
ifStarts.Push(new IfDirectiveStackElement(ifStart));
if (node.BranchTaken)
branchesTaken.Add(ifStart);
}
public override void VisitEndIfDirectiveTrivia(EndIfDirectiveTriviaSyntax node)
@ -105,7 +115,7 @@ namespace Semmle.Extraction.CSharp.Populators
}
var start = ifStarts.Pop();
new Entities.EndIfDirective(cx, node, start.Entity);
Entities.EndIfDirective.Create(cx, node, start.Entity);
}
public override void VisitElifDirectiveTrivia(ElifDirectiveTriviaSyntax node)
@ -118,7 +128,9 @@ namespace Semmle.Extraction.CSharp.Populators
}
var start = ifStarts.Peek();
new Entities.ElifDirective(cx, node, start.Entity, start.SiblingCount++);
var elIf = Entities.ElifDirective.Create(cx, node, start.Entity, start.SiblingCount++);
if (node.BranchTaken)
branchesTaken.Add(elIf);
}
public override void VisitElseDirectiveTrivia(ElseDirectiveTriviaSyntax node)
@ -131,7 +143,9 @@ namespace Semmle.Extraction.CSharp.Populators
}
var start = ifStarts.Peek();
new Entities.ElseDirective(cx, node, start.Entity, start.SiblingCount++);
var @else = Entities.ElseDirective.Create(cx, node, start.Entity, start.SiblingCount++);
if (node.BranchTaken)
branchesTaken.Add(@else);
}
}
}

Просмотреть файл

@ -30,6 +30,8 @@ namespace Semmle.Extraction
/// </summary>
public bool ShouldAddAssemblyTrapPrefix { get; }
public IList<object> TrapStackSuffix { get; } = new List<object>();
private int GetNewId() => TrapWriter.IdCounter++;
// A recursion guard against writing to the trap file whilst writing an id to the trap file.
@ -270,8 +272,7 @@ namespace Semmle.Extraction
return;
}
bool duplicationGuard;
bool deferred;
bool duplicationGuard, deferred;
switch (entity.TrapStackBehaviour)
{
@ -291,14 +292,24 @@ namespace Semmle.Extraction
break;
case TrapStackBehaviour.PushesLabel:
duplicationGuard = true;
deferred = tagStack.Any();
deferred = duplicationGuard && tagStack.Any();
break;
default:
throw new InternalError("Unexpected TrapStackBehaviour");
}
var a = duplicationGuard && IsEntityDuplicationGuarded(entity, out var loc)
? (Action)(() => WithDuplicationGuard(new Key(entity, loc), () => entity.Populate(TrapWriter.Writer)))
? (() =>
{
var args = new object[TrapStackSuffix.Count + 2];
args[0] = entity;
args[1] = loc;
for (var i = 0; i < TrapStackSuffix.Count; i++)
{
args[i + 2] = TrapStackSuffix[i];
}
WithDuplicationGuard(new Key(args), () => entity.Populate(TrapWriter.Writer));
})
: (Action)(() => this.Try(null, optionalSymbol, () => entity.Populate(TrapWriter.Writer)));
if (deferred)

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше