diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f1844da86cf..7f218e99da4 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,7 +2,13 @@ name: "Code scanning - action" on: push: + branches: + - main + - 'rc/*' pull_request: + branches: + - main + - 'rc/*' schedule: - cron: '0 9 * * 1' @@ -14,16 +20,7 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index 031bf97e728..e3af19c6dea 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -50,7 +50,7 @@ jobs: uses: ammaraskar/sphinx-action@8b4f60114d7fd1faeba1a712269168508d4750d2 # v0.4 with: docs-folder: "query-help/" - pre-build-command: "python -m pip install --upgrade recommonmark" + pre-build-command: "python -m pip install --upgrade recommonmark && python -m pip install --upgrade sphinx-markdown-tables" build-command: "sphinx-build -b dirhtml . _build" - name: Upload HTML artifacts uses: actions/upload-artifact@v2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 39552ad0bd9..f9f6fe310a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,7 +49,11 @@ If you have an idea for a query that you would like to share with other CodeQL u - The query must have at least one true positive result on some revision of a real project. -Experimental queries and libraries may not be actively maintained as the [supported](docs/supported-queries.md) libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings. +6. **Query help files and unit tests** + + - Query help (`.qhelp`) files and unit tests are optional (but strongly encouraged!) for queries in the `experimental` directories. For more information about contributing query help files and unit tests, see [Supported CodeQL queries and libraries](docs/supported-queries.md). + +Experimental queries and libraries may not be actively maintained as the supported libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings. After the experimental query is merged, we welcome pull requests to improve it. Before a query can be moved out of the `experimental` subdirectory, it must satisfy [the requirements for being a supported query](docs/supported-queries.md). diff --git a/config/identical-files.json b/config/identical-files.json index 5a8efc3405a..d68dabba861 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -356,6 +356,7 @@ ], "Inline Test Expectations": [ "cpp/ql/test/TestUtilities/InlineExpectationsTest.qll", + "java/ql/test/TestUtilities/InlineExpectationsTest.qll", "python/ql/test/TestUtilities/InlineExpectationsTest.qll" ], "C++ ExternalAPIs": [ diff --git a/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md b/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md new file mode 100644 index 00000000000..d4a6ebafa0c --- /dev/null +++ b/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md @@ -0,0 +1,2 @@ +lgtm +* A new query (`cpp/unsigned-difference-expression-compared-zero`) is run but not yet displayed on LGTM. The query finds unsigned subtractions used in relational comparisons with the value 0. This query was originally submitted as an experimental query by @ihsinme in https://github.com/github/codeql/pull/4745. diff --git a/cpp/config/suites/cpp/correctness b/cpp/config/suites/cpp/correctness index bcdf94c94ce..55678a1dd37 100644 --- a/cpp/config/suites/cpp/correctness +++ b/cpp/config/suites/cpp/correctness @@ -10,6 +10,7 @@ + semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Security/CWE/CWE-253/HResultBooleanConversion.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Likely Bugs/OO/UnsafeUseOfThis.ql: /Correctness/Dangerous Conversions ++ semmlecode-cpp-queries/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql: /Correctness/Dangerous Conversions # Consistent Use + semmlecode-cpp-queries/Critical/ReturnValueIgnored.ql: /Correctness/Consistent Use + semmlecode-cpp-queries/Likely Bugs/InconsistentCheckReturnNull.ql: /Correctness/Consistent Use diff --git a/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll b/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll index 788baeddbff..9ca598f86d6 100644 --- a/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll +++ b/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll @@ -46,7 +46,7 @@ class UntrustedDataToExternalAPIConfig extends TaintTracking::Configuration { UntrustedDataToExternalAPIConfig() { this = "UntrustedDataToExternalAPIConfig" } override predicate isSource(DataFlow::Node source) { - exists(RemoteFlowFunction remoteFlow | + exists(RemoteFlowSourceFunction remoteFlow | remoteFlow = source.asExpr().(Call).getTarget() and remoteFlow.hasRemoteFlowSource(_, _) ) diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql index 24484a9dcaf..d1e2fa12913 100644 --- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql +++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql @@ -34,6 +34,10 @@ class Configuration extends TaintTrackingConfiguration { override predicate isSink(Element tainted) { exists(PrintStdoutCall call | call.getAnArgument() = tainted) } + + override predicate isBarrier(Expr e) { + super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType + } } from QueryString query, Element printedArg, PathNode sourceNode, PathNode sinkNode diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c new file mode 100644 index 00000000000..d2f2b76fddc --- /dev/null +++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c @@ -0,0 +1,5 @@ +unsigned limit = get_limit(); +unsigned total = 0; +while (limit - total > 0) { // wrong: if `total` is greater than `limit` this will underflow and continue executing the loop. + total += get_data(); +} \ No newline at end of file diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp new file mode 100644 index 00000000000..965429bda8a --- /dev/null +++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp @@ -0,0 +1,31 @@ + + + +

+This rule finds relational comparisons between the result of an unsigned subtraction and the value 0. +Such comparisons are likely to be wrong as the value of an unsigned subtraction can never be negative. So the +relational comparison ends up checking whether the result of the subtraction is equal to 0. +This is probably not what the programmer intended. +

+
+ + +

If a relational comparison is intended, consider casting the result of the subtraction to a signed type. + If the intention was to test for equality, consider replacing the relational comparison with an equality test. +

+ +
+ + + + + + +
  • SEI CERT C Coding Standard: +INT02-C. Understand integer conversion rules. +
  • + +
    +
    diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql new file mode 100644 index 00000000000..007a4fd746d --- /dev/null +++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql @@ -0,0 +1,49 @@ +/** + * @name Unsigned difference expression compared to zero + * @description A subtraction with an unsigned result can never be negative. Using such an expression in a relational comparison with `0` is likely to be wrong. + * @kind problem + * @id cpp/unsigned-difference-expression-compared-zero + * @problem.severity warning + * @precision medium + * @tags security + * correctness + * external/cwe/cwe-191 + */ + +import cpp +import semmle.code.cpp.commons.Exclusions +import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import semmle.code.cpp.controlflow.Guards + +/** Holds if `sub` is guarded by a condition which ensures that `left >= right`. */ +pragma[noinline] +predicate isGuarded(SubExpr sub, Expr left, Expr right) { + exists(GuardCondition guard | + guard.controls(sub.getBasicBlock(), true) and + guard.ensuresLt(left, right, 0, sub.getBasicBlock(), false) + ) +} + +/** Holds if `sub` will never be negative. */ +predicate nonNegative(SubExpr sub) { + not exprMightOverflowNegatively(sub.getFullyConverted()) + or + // The subtraction is guarded by a check of the form `left >= right`. + exists(GVN left, GVN right | + // This is basically a poor man's version of a directional unbind operator. + strictcount([left, globalValueNumber(sub.getLeftOperand())]) = 1 and + strictcount([right, globalValueNumber(sub.getRightOperand())]) = 1 and + isGuarded(sub, left.getAnExpr(), right.getAnExpr()) + ) +} + +from RelationalOperation ro, SubExpr sub +where + not isFromMacroDefinition(ro) and + not isFromMacroDefinition(sub) and + ro.getLesserOperand().getValue().toInt() = 0 and + ro.getGreaterOperand() = sub and + sub.getFullyConverted().getUnspecifiedType().(IntegralType).isUnsigned() and + not nonNegative(sub) +select ro, "Unsigned subtraction can never be negative." diff --git a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll index 1a186cc4c5e..4739c7ad5cf 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll +++ b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll @@ -353,7 +353,9 @@ class InitializationFunction extends Function { // Destination range is zeroed out on failure, assuming first two parameters are valid "memcpy_s", // This zeroes the memory unconditionally - "SeCreateAccessState" + "SeCreateAccessState", + // Argument initialization is optional, but always succeeds + "KeGetCurrentProcessorNumberEx" ] ) } diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c deleted file mode 100644 index f6054226848..00000000000 --- a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c +++ /dev/null @@ -1,11 +0,0 @@ -unsigned long sizeArray; - -// BAD: let's consider several values, taking ULONG_MAX =18446744073709551615 -// sizeArray = 60; (sizeArray - 10) = 50; true -// sizeArray = 10; (sizeArray - 10) = 0; false -// sizeArray = 1; (sizeArray - 10) = 18446744073709551607; true -// sizeArray = 0; (sizeArray - 10) = 18446744073709551606; true -if (sizeArray - 10 > 0) - -// GOOD: Prevent overflow by checking the input -if (sizeArray > 10) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp deleted file mode 100644 index 3bf28d13df4..00000000000 --- a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp +++ /dev/null @@ -1,33 +0,0 @@ - - - -

    The code compares the unsigned difference with zero. -It is highly probable that the condition is wrong if the difference expression has the unsigned type. -The condition holds in all the cases when difference is not equal to zero. -It means that we may use condition not equal. But the programmer probably wanted to compare the difference of elements.

    - -

    False positives include code in which the first difference element is always greater than or equal to the second. -For comparison, ">" such conditions are equivalent to "! =", And are recommended for replacement. -For comparison "> =", the conditions are always true and are recommended to be excluded.

    - -
    - - -

    Use a simple comparison of two elements, instead of comparing their difference to zero.

    - -
    - -

    The following example demonstrates an erroneous and corrected use of comparison.

    - - -
    - - -
  • CERT C Coding Standard: -INT02-C. Understand integer conversion rules. -
  • - -
    -
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql deleted file mode 100644 index 300b2f944b5..00000000000 --- a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @name Unsigned difference expression compared to zero - * @description It is highly probable that the condition is wrong if the difference expression has the unsigned type. - * The condition holds in all the cases when difference is not equal to zero. It means that we may use condition not equal. - * But the programmer probably wanted to compare the difference of elements. - * @kind problem - * @id cpp/unsigned-difference-expression-compared-zero - * @problem.severity warning - * @precision medium - * @tags security - * external/cwe/cwe-191 - */ - -import cpp -import semmle.code.cpp.commons.Exclusions - -from RelationalOperation ro, SubExpr sub -where - not isFromMacroDefinition(ro) and - ro.getLesserOperand().getValue().toInt() = 0 and - ro.getGreaterOperand() = sub and - sub.getFullyConverted().getUnspecifiedType().(IntegralType).isUnsigned() -select ro, "Difference in condition is always greater than or equal to zero" diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp new file mode 100644 index 00000000000..df69886e97b --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp @@ -0,0 +1,35 @@ +// BAD: on memory allocation error, the program terminates. +void badFunction(const int *source, std::size_t length) noexcept { + int * dest = new int[length]; + std::memset(dest, 0, length); +// .. +} +// GOOD: memory allocation error will be handled. +void goodFunction(const int *source, std::size_t length) noexcept { + try { + int * dest = new int[length]; + } catch(std::bad_alloc) { + // ... + } + std::memset(dest, 0, length); +// .. +} +// BAD: memory allocation error will not be handled. +void badFunction(const int *source, std::size_t length) noexcept { + try { + int * dest = new (std::nothrow) int[length]; + } catch(std::bad_alloc) { + // ... + } + std::memset(dest, 0, length); +// .. +} +// GOOD: memory allocation error will be handled. +void goodFunction(const int *source, std::size_t length) noexcept { + int * dest = new (std::nothrow) int[length]; + if (!dest) { + return; + } + std::memset(dest, 0, length); +// .. +} diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp new file mode 100644 index 00000000000..9e6cb2d89ce --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp @@ -0,0 +1,27 @@ + + + +

    When using the new operator to allocate memory, you need to pay attention to the different ways of detecting errors. ::operator new(std::size_t) throws an exception on error, whereas ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. The programmer can get confused and check the error that occurs when allocating memory incorrectly. That can lead to an unhandled program termination or to a violation of the program logic.

    + +
    + + +

    Use the correct error detection method corresponding with the memory allocation.

    + +
    + +

    The following example demonstrates various approaches to detecting memory allocation errors using the new operator.

    + + +
    + + +
  • + CERT C++ Coding Standard: +MEM52-CPP. Detect and handle memory allocation errors. +
  • + +
    +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql new file mode 100644 index 00000000000..dd9c16fac11 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql @@ -0,0 +1,87 @@ +/** + * @name Detect And Handle Memory Allocation Errors + * @description --::operator new(std::size_t) throws an exception on error, and ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. + * --the programmer can get confused when check the error that occurs when allocating memory incorrectly. + * @kind problem + * @id cpp/detect-and-handle-memory-allocation-errors + * @problem.severity warning + * @precision medium + * @tags correctness + * security + * external/cwe/cwe-570 + */ + +import cpp + +/** + * Lookup if condition compare with 0 + */ +class IfCompareWithZero extends IfStmt { + IfCompareWithZero() { + this.getCondition().(EQExpr).getAChild().getValue() = "0" + or + this.getCondition().(NEExpr).getAChild().getValue() = "0" and + this.hasElse() + or + this.getCondition().(NEExpr).getAChild().getValue() = "0" and + this.getThen().getAChild*() instanceof ReturnStmt + } +} + +/** + * lookup for calls to `operator new`, with incorrect error handling. + */ +class WrongCheckErrorOperatorNew extends FunctionCall { + Expr exp; + + WrongCheckErrorOperatorNew() { + this = exp.(NewOrNewArrayExpr).getAChild().(FunctionCall) and + ( + this.getTarget().hasGlobalOrStdName("operator new") + or + this.getTarget().hasGlobalOrStdName("operator new[]") + ) + } + + /** + * Holds if handler `try ... catch` exists. + */ + predicate isExistsTryCatchBlock() { + exists(TryStmt ts | this.getEnclosingStmt() = ts.getStmt().getAChild*()) + } + + /** + * Holds if results call `operator new` check in `operator if`. + */ + predicate isExistsIfCondition() { + exists(IfCompareWithZero ifc, AssignExpr aex, Initializer it | + // call `operator new` directly from the condition of `operator if`. + this = ifc.getCondition().getAChild*() + or + // check results call `operator new` with variable appropriation + postDominates(ifc, this) and + aex.getAChild() = exp and + ifc.getCondition().getAChild().(VariableAccess).getTarget() = + aex.getLValue().(VariableAccess).getTarget() + or + // check results call `operator new` with declaration variable + postDominates(ifc, this) and + exp = it.getExpr() and + it.getDeclaration() = ifc.getCondition().getAChild().(VariableAccess).getTarget() + ) + } + + /** + * Holds if `(std::nothrow)` exists in call `operator new`. + */ + predicate isExistsNothrow() { this.getAChild().toString() = "nothrow" } +} + +from WrongCheckErrorOperatorNew op +where + // use call `operator new` with `(std::nothrow)` and checking error using `try ... catch` block and not `operator if` + op.isExistsNothrow() and not op.isExistsIfCondition() and op.isExistsTryCatchBlock() + or + // use call `operator new` without `(std::nothrow)` and checking error using `operator if` and not `try ... catch` block + not op.isExistsNothrow() and not op.isExistsTryCatchBlock() and op.isExistsIfCondition() +select op, "memory allocation error check is incorrect or missing" diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.c b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.c new file mode 100644 index 00000000000..ba78d4b97d1 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.c @@ -0,0 +1,9 @@ +// BAD: if buffer does not have a terminal zero, then access outside the allocated memory is possible. + +buffer[strlen(buffer)] = 0; + + +// GOOD: we will eliminate dangerous behavior if we use a different method of calculating the length. +size_t len; +... +buffer[len] = 0 diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp new file mode 100644 index 00000000000..51424ce7619 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp @@ -0,0 +1,31 @@ + + + +

    Potentially dangerous use of the strlen function to calculate the length of a string. +The expression buffer[strlen(buffer)] = 0 is potentially dangerous, if the variable buffer does not have a terminal zero, then access beyond the bounds of the allocated memory is possible, which will lead to undefined behavior. +If terminal zero is present, then the specified expression is meaningless.

    + +

    False positives include heavily nested strlen. This situation is unlikely.

    + +
    + + +

    We recommend using another method for calculating the string length

    + +
    + +

    The following example demonstrates an erroneous and corrected use of the strlen function.

    + + +
    + + +
  • + CERT C Coding Standard: + STR32-C. Do not pass a non-null-terminated character sequence to a library function that expects a string. +
  • + +
    +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql new file mode 100644 index 00000000000..012109074e9 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql @@ -0,0 +1,34 @@ +/** + * @name Access Of Memory Location After End Of Buffer + * @description The expression `buffer [strlen (buffer)] = 0` is potentially dangerous, if the variable `buffer` does not have a terminal zero, then access beyond the bounds of the allocated memory is possible, which will lead to undefined behavior. + * If terminal zero is present, then the specified expression is meaningless. + * @kind problem + * @id cpp/access-memory-location-after-end-buffer + * @problem.severity warning + * @precision medium + * @tags correctness + * security + * external/cwe/cwe-788 + */ + +import cpp +import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.dataflow.DataFlow + +from StrlenCall fc, AssignExpr expr, ArrayExpr exprarr +where + exprarr = expr.getLValue() and + expr.getRValue().getValue().toInt() = 0 and + globalValueNumber(exprarr.getArrayOffset()) = globalValueNumber(fc) and + not exists(Expr exptmp | + ( + DataFlow::localExprFlow(fc, exptmp) or + exptmp.getAChild*() = fc.getArgument(0).(VariableAccess).getTarget().getAnAccess() + ) and + dominates(exptmp, expr) and + postDominates(exptmp, fc) and + not exptmp.getEnclosingStmt() = fc.getEnclosingStmt() and + not exptmp.getEnclosingStmt() = expr.getEnclosingStmt() + ) and + globalValueNumber(fc.getArgument(0)) = globalValueNumber(exprarr.getArrayBase()) +select expr, "potential unsafe or redundant assignment." diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 35ae092780d..7ac79fd99c1 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -139,6 +139,19 @@ class Declaration extends Locatable, @declaration { this.hasQualifiedName("std", "", name) } + /** + * Holds if this declaration has the given name in the global namespace, + * the `std` namespace or the `bsl` namespace. + * We treat `std` and `bsl` as the same in some of our models. + */ + predicate hasGlobalOrStdOrBslName(string name) { + this.hasGlobalName(name) + or + this.hasQualifiedName("std", "", name) + or + this.hasQualifiedName("bsl", "", name) + } + /** Gets a specifier of this declaration. */ Specifier getASpecifier() { none() } // overridden in subclasses diff --git a/cpp/ql/src/semmle/code/cpp/Element.qll b/cpp/ql/src/semmle/code/cpp/Element.qll index f4c1bd972c6..66f23ea110f 100644 --- a/cpp/ql/src/semmle/code/cpp/Element.qll +++ b/cpp/ql/src/semmle/code/cpp/Element.qll @@ -270,7 +270,12 @@ private predicate isFromUninstantiatedTemplateRec(Element e, Element template) { } /** - * A C++11 `static_assert` or C11 `_Static_assert` construct. + * A C++11 `static_assert` or C11 `_Static_assert` construct. For example each + * line in the following example contains a static assert: + * ``` + * static_assert(sizeof(MyStruct) <= 4096); + * static_assert(sizeof(MyStruct) <= 4096, "MyStruct is too big!"); + * ``` */ class StaticAssert extends Locatable, @static_assert { override string toString() { result = "static_assert(..., \"" + getMessage() + "\")" } diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 4ddf852f49f..ac345e8a29a 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -680,7 +680,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { /** * A C/C++ non-member function (a function that is not a member of any - * class). For example the in the following code, `MyFunction` is a + * class). For example, in the following code, `MyFunction` is a * `TopLevelFunction` but `MyMemberFunction` is not: * ``` * void MyFunction() { diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index 6172c3af50c..d46abc6b4db 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -7,8 +7,21 @@ import semmle.code.cpp.Type import semmle.code.cpp.metrics.MetricNamespace /** - * A C++ namespace. + * A C++ namespace. For example the (single) namespace `A` in the following + * code: + * ``` + * namespace A + * { + * // ... + * } * + * // ... + * + * namespace A + * { + * // ... + * } + * ``` * Note that namespaces are somewhat nebulous entities, as they do not in * general have a single well-defined location in the source code. The * related notion of a `NamespaceDeclarationEntry` is rather more concrete, @@ -96,10 +109,22 @@ class Namespace extends NameQualifyingElement, @namespace { } /** - * A declaration of (part of) a C++ namespace. + * A declaration of (part of) a C++ namespace. This corresponds to a single + * `namespace N { ... }` occurrence in the source code. For example the two + * mentions of `A` in the following code: + * ``` + * namespace A + * { + * // ... + * } * - * This corresponds to a single `namespace N { ... }` occurrence in the - * source code. + * // ... + * + * namespace A + * { + * // ... + * } + * ``` */ class NamespaceDeclarationEntry extends Locatable, @namespace_decl { /** @@ -143,8 +168,9 @@ class UsingEntry extends Locatable, @using { /** * A C++ `using` declaration. For example: - * - * `using std::string;` + * ``` + * using std::string; + * ``` */ class UsingDeclarationEntry extends UsingEntry { UsingDeclarationEntry() { @@ -162,8 +188,9 @@ class UsingDeclarationEntry extends UsingEntry { /** * A C++ `using` directive. For example: - * - * `using namespace std;` + * ``` + * using namespace std; + * ``` */ class UsingDirectiveEntry extends UsingEntry { UsingDirectiveEntry() { diff --git a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll index a9609922b74..2389db07f2a 100644 --- a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll +++ b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll @@ -2,9 +2,14 @@ import semmle.code.cpp.Location import semmle.code.cpp.Element /** - * A C/C++ preprocessor directive. - * - * For example: `#ifdef`, `#line`, or `#pragma`. + * A C/C++ preprocessor directive. For example each of the following lines of + * code contains a `PreprocessorDirective`: + * ``` + * #pragma once + * #ifdef MYDEFINE + * #include "myfile.h" + * #line 1 "source.c" + * ``` */ class PreprocessorDirective extends Locatable, @preprocdirect { override string toString() { result = "Preprocessor directive" } @@ -98,9 +103,9 @@ class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBr * A C/C++ preprocessor branching directive: `#if`, `#ifdef`, `#ifndef`, or * `#elif`. * - * A branching directive can have its condition evaluated at compile-time, - * and as a result, the preprocessor will either take the branch, or not - * take the branch. + * A branching directive has a condition and that condition may be evaluated + * at compile-time. As a result, the preprocessor will either take the + * branch, or not take the branch. * * However, there are also situations in which a branch's condition isn't * evaluated. The obvious case of this is when the directive is contained @@ -136,8 +141,13 @@ class PreprocessorBranch extends PreprocessorBranchDirective, @ppd_branch { } /** - * A C/C++ preprocessor `#if` directive. - * + * A C/C++ preprocessor `#if` directive. For example there is a + * `PreprocessorIf` on the first line of the following code: + * ``` + * #if defined(MYDEFINE) + * // ... + * #endif + * ``` * For the related notion of a directive which causes branching (which * includes `#if`, plus also `#ifdef`, `#ifndef`, and `#elif`), see * `PreprocessorBranch`. @@ -147,8 +157,13 @@ class PreprocessorIf extends PreprocessorBranch, @ppd_if { } /** - * A C/C++ preprocessor `#ifdef` directive. - * + * A C/C++ preprocessor `#ifdef` directive. For example there is a + * `PreprocessorIfdef` on the first line of the following code: + * ``` + * #ifdef MYDEFINE + * // ... + * #endif + * ``` * The syntax `#ifdef X` is shorthand for `#if defined(X)`. */ class PreprocessorIfdef extends PreprocessorBranch, @ppd_ifdef { @@ -158,8 +173,13 @@ class PreprocessorIfdef extends PreprocessorBranch, @ppd_ifdef { } /** - * A C/C++ preprocessor `#ifndef` directive. - * + * A C/C++ preprocessor `#ifndef` directive. For example there is a + * `PreprocessorIfndef` on the first line of the following code: + * ``` + * #ifndef MYDEFINE + * // ... + * #endif + * ``` * The syntax `#ifndef X` is shorthand for `#if !defined(X)`. */ class PreprocessorIfndef extends PreprocessorBranch, @ppd_ifndef { @@ -167,42 +187,80 @@ class PreprocessorIfndef extends PreprocessorBranch, @ppd_ifndef { } /** - * A C/C++ preprocessor `#else` directive. + * A C/C++ preprocessor `#else` directive. For example there is a + * `PreprocessorElse` on the fifth line of the following code: + * ``` + * #ifdef MYDEFINE1 + * // ... + * #elif MYDEFINE2 + * // ... + * #else + * // ... + * #endif + * ``` */ class PreprocessorElse extends PreprocessorBranchDirective, @ppd_else { override string toString() { result = "#else" } } /** - * A C/C++ preprocessor `#elif` directive. + * A C/C++ preprocessor `#elif` directive. For example there is a + * `PreprocessorElif` on the third line of the following code: + * ``` + * #ifdef MYDEFINE1 + * // ... + * #elif MYDEFINE2 + * // ... + * #else + * // ... + * #endif + * ``` */ class PreprocessorElif extends PreprocessorBranch, @ppd_elif { override string toString() { result = "#elif " + this.getHead() } } /** - * A C/C++ preprocessor `#endif` directive. + * A C/C++ preprocessor `#endif` directive. For example there is a + * `PreprocessorEndif` on the third line of the following code: + * ``` + * #ifdef MYDEFINE + * // ... + * #endif + * ``` */ class PreprocessorEndif extends PreprocessorBranchDirective, @ppd_endif { override string toString() { result = "#endif" } } /** - * A C/C++ preprocessor `#warning` directive. + * A C/C++ preprocessor `#warning` directive. For example: + * ``` + * #warning "This configuration is not supported." + * ``` */ class PreprocessorWarning extends PreprocessorDirective, @ppd_warning { override string toString() { result = "#warning " + this.getHead() } } /** - * A C/C++ preprocessor `#error` directive. + * A C/C++ preprocessor `#error` directive. For example: + * ``` + * #error "This configuration is not implemented." + * ``` */ class PreprocessorError extends PreprocessorDirective, @ppd_error { override string toString() { result = "#error " + this.getHead() } } /** - * A C/C++ preprocessor `#undef` directive. + * A C/C++ preprocessor `#undef` directive. For example there is a + * `PreprocessorUndef` on the second line of the following code: + * ``` + * #ifdef MYMACRO + * #undef MYMACRO + * #endif + * ``` */ class PreprocessorUndef extends PreprocessorDirective, @ppd_undef { override string toString() { result = "#undef " + this.getHead() } @@ -214,7 +272,10 @@ class PreprocessorUndef extends PreprocessorDirective, @ppd_undef { } /** - * A C/C++ preprocessor `#pragma` directive. + * A C/C++ preprocessor `#pragma` directive. For example: + * ``` + * #pragma once + * ``` */ class PreprocessorPragma extends PreprocessorDirective, @ppd_pragma { override string toString() { @@ -223,7 +284,10 @@ class PreprocessorPragma extends PreprocessorDirective, @ppd_pragma { } /** - * A C/C++ preprocessor `#line` directive. + * A C/C++ preprocessor `#line` directive. For example: + * ``` + * #line 1 "source.c" + * ``` */ class PreprocessorLine extends PreprocessorDirective, @ppd_line { override string toString() { result = "#line " + this.getHead() } diff --git a/cpp/ql/src/semmle/code/cpp/Specifier.qll b/cpp/ql/src/semmle/code/cpp/Specifier.qll index 3d68fb374f1..1c1eb0c090a 100644 --- a/cpp/ql/src/semmle/code/cpp/Specifier.qll +++ b/cpp/ql/src/semmle/code/cpp/Specifier.qll @@ -171,8 +171,11 @@ class StdAttribute extends Attribute, @stdattribute { } /** - * An attribute introduced by Microsoft's `__declspec(name)` syntax, for - * example: `__declspec(dllimport)`. + * An attribute introduced by Microsoft's `__declspec(name)` syntax. For + * example the attribute on the following declaration: + * ``` + * __declspec(dllimport) void myFunction(); + * ``` */ class Declspec extends Attribute, @declspec { } @@ -186,8 +189,13 @@ class MicrosoftAttribute extends Attribute, @msattribute { } /** - * A C++11 `alignas` construct. - * + * A C++11 `alignas` construct. For example the attribute in the following + * code: + * ``` + * struct alignas(16) MyStruct { + * int x; + * }; + * ``` * Though it doesn't use the attribute syntax, `alignas(...)` is presented * as an `Attribute` for consistency with the `[[align(...)]]` attribute. */ @@ -197,7 +205,11 @@ class AlignAs extends Attribute, @alignas { /** * A GNU `format` attribute of the form `__attribute__((format(archetype, format-index, first-arg)))` - * that declares a function to accept a `printf` style format string. + * that declares a function to accept a `printf` style format string. For example the attribute + * on the following declaration: + * ``` + * int myPrintf(const char *format, ...) __attribute__((format(printf, 1, 2))); + * ``` */ class FormatAttribute extends GnuAttribute { FormatAttribute() { getName() = "format" } @@ -242,7 +254,11 @@ class FormatAttribute extends GnuAttribute { } /** - * An argument to an `Attribute`. + * An argument to an `Attribute`. For example the argument "dllimport" on the + * attribute in the following code: + * ``` + * __declspec(dllimport) void myFunction(); + * ``` */ class AttributeArgument extends Element, @attribute_arg { /** diff --git a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll index cf230beb8d2..8d9ad5c77e4 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll @@ -53,7 +53,12 @@ predicate primitiveVariadicFormatter( ( if type = "" then outputParamIndex = -1 else outputParamIndex = 0 // Conveniently, these buffer parameters are all at index 0. ) and - not exists(f.getBlock()) // exclude functions with an implementation in the snapshot as they may not be standard implementations. + not ( + // exclude functions with an implementation in the snapshot source + // directory, as they may not be standard implementations. + exists(f.getBlock()) and + exists(f.getFile().getRelativePath()) + ) } private predicate callsVariadicFormatter( diff --git a/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll b/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll index 4b75bbe27d2..461030f389d 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll @@ -34,10 +34,10 @@ class Scanf extends ScanfFunction { Scanf() { this instanceof TopLevelFunction and ( - hasName("scanf") or // scanf(format, args...) - hasName("wscanf") or // wscanf(format, args...) - hasName("_scanf_l") or // _scanf_l(format, locale, args...) - hasName("_wscanf_l") // _wscanf_l(format, locale, args...) + hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...) + hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...) + hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...) + hasGlobalName("_wscanf_l") // _wscanf_l(format, locale, args...) ) } @@ -53,10 +53,10 @@ class Fscanf extends ScanfFunction { Fscanf() { this instanceof TopLevelFunction and ( - hasName("fscanf") or // fscanf(src_stream, format, args...) - hasName("fwscanf") or // fwscanf(src_stream, format, args...) - hasName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...) - hasName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...) + hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...) + hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...) + hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...) + hasGlobalName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...) ) } @@ -72,10 +72,10 @@ class Sscanf extends ScanfFunction { Sscanf() { this instanceof TopLevelFunction and ( - hasName("sscanf") or // sscanf(src_stream, format, args...) - hasName("swscanf") or // swscanf(src, format, args...) - hasName("_sscanf_l") or // _sscanf_l(src, format, locale, args...) - hasName("_swscanf_l") // _swscanf_l(src, format, locale, args...) + hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...) + hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...) + hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...) + hasGlobalName("_swscanf_l") // _swscanf_l(src, format, locale, args...) ) } @@ -91,10 +91,10 @@ class Snscanf extends ScanfFunction { Snscanf() { this instanceof TopLevelFunction and ( - hasName("_snscanf") or // _snscanf(src, max_amount, format, args...) - hasName("_snwscanf") or // _snwscanf(src, max_amount, format, args...) - hasName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...) - hasName("_snwscanf_l") // _snwscanf_l(src, max_amount, format, locale, args...) + hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...) + hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...) + hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...) + hasGlobalName("_snwscanf_l") // _snwscanf_l(src, max_amount, format, locale, args...) // note that the max_amount is not a limit on the output length, it's an input length // limit used with non null-terminated strings. ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 68b31a732f4..762ce8d47b4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -2,7 +2,6 @@ private import cpp private import DataFlowUtil private import semmle.code.cpp.ir.IR private import DataFlowDispatch -private import semmle.code.cpp.models.interfaces.DataFlow /** * A data flow node that occurs as the argument of a call and is passed as-is @@ -210,13 +209,6 @@ private class FieldContent extends Content, TFieldContent { predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit } Field getAField() { result = getAField(c, startBit, endBit) } - - pragma[noinline] - Field getADirectField() { - c = result.getDeclaringType() and - this.getAField() = result and - this.hasOffset(c, _, _) - } } private class CollectionContent extends Content, TCollectionContent { @@ -229,101 +221,69 @@ private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array content" } } -/** - * A store step from the value of a `StoreInstruction` to the "innermost" field of the destination. - * This predicate only holds when there is no `ChiInsturction` that merges the result of the - * `StoreInstruction` into a larger memory. - */ -private predicate instrToFieldNodeStoreStepNoChi( - Node node1, FieldContent f, PartialDefinitionNode node2 -) { - exists(StoreInstruction store, PartialFieldDefinition pd | - pd = node2.getPartialDefinition() and - not exists(ChiInstruction chi | chi.getPartial() = store) and - pd.getPreUpdateNode() = GetFieldNode::fromInstruction(store.getDestinationAddress()) and +private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) { + exists(StoreInstruction store, Class c | + store = node2.asInstruction() and store.getSourceValueOperand() = node1.asOperand() and - f.getADirectField() = pd.getPreUpdateNode().getField() + getWrittenField(store, f.(FieldContent).getAField(), c) and + f.hasOffset(c, _, _) ) } -/** - * A store step from a `StoreInstruction` to the "innermost" field - * of the destination. This predicate only holds when there exists a `ChiInstruction` that merges the - * result of the `StoreInstruction` into a larger memory. - */ -private predicate instrToFieldNodeStoreStepChi( - Node node1, FieldContent f, PartialDefinitionNode node2 -) { - exists( - ChiPartialOperand operand, StoreInstruction store, ChiInstruction chi, PartialFieldDefinition pd - | - pd = node2.getPartialDefinition() and - not chi.isResultConflated() and - node1.asOperand() = operand and +private FieldAddressInstruction getFieldInstruction(Instruction instr) { + result = instr or + result = instr.(CopyValueInstruction).getUnary() +} + +pragma[noinline] +private predicate getWrittenField(Instruction instr, Field f, Class c) { + exists(FieldAddressInstruction fa | + fa = + getFieldInstruction([ + instr.(StoreInstruction).getDestinationAddress(), + instr.(WriteSideEffectInstruction).getDestinationAddress() + ]) and + f = fa.getField() and + c = f.getDeclaringType() + ) +} + +private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode node2) { + exists(ChiPartialOperand operand, ChiInstruction chi | chi.getPartialOperand() = operand and - store = operand.getDef() and - pd.getPreUpdateNode() = GetFieldNode::fromInstruction(store.getDestinationAddress()) and - f.getADirectField() = pd.getPreUpdateNode().getField() - ) -} - -private predicate callableWithoutDefinitionStoreStep( - Node node1, FieldContent f, PartialDefinitionNode node2 -) { - exists( - WriteSideEffectInstruction write, ChiInstruction chi, PartialFieldDefinition pd, - Function callable, CallInstruction call - | - chi.getPartial() = write and - not chi.isResultConflated() and - pd = node2.getPartialDefinition() and - pd.getPreUpdateNode() = GetFieldNode::fromInstruction(write.getDestinationAddress()) and - f.getADirectField() = pd.getPreUpdateNode().getField() and - call = write.getPrimaryInstruction() and - callable = call.getStaticCallTarget() and - not callable.hasDefinition() - | - exists(OutParameterDeref out | out.getIndex() = write.getIndex() | - callable.(DataFlowFunction).hasDataFlow(_, out) and - node1.asInstruction() = write - ) - or - // Ideally we shouldn't need to do a store step from a read side effect, but if we don't have a - // model for the callee there might not be flow to the write side effect (since the callee has no - // definition). This case ensures that we propagate dataflow when a field is passed into a - // function that has a write side effect, even though the write side effect doesn't have incoming - // flow. - not callable instanceof DataFlowFunction and - exists(ReadSideEffectInstruction read | call = read.getPrimaryInstruction() | - node1.asInstruction() = read.getSideEffectOperand().getAnyDef() + node1.asOperand() = operand and + node2.asInstruction() = chi and + exists(Class c | + c = chi.getResultType() and + exists(int startBit, int endBit | + chi.getUpdatedInterval(startBit, endBit) and + f.hasOffset(c, startBit, endBit) + ) + or + getWrittenField(operand.getDef(), f.getAField(), c) and + f.hasOffset(c, _, _) ) ) } -/** - * A store step from a `StoreInstruction` to the `ChiInstruction` generated from assigning - * to a pointer or array indirection - */ -private predicate arrayStoreStepChi(Node node1, ArrayContent a, PartialDefinitionNode node2) { +private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) { a = TArrayContent() and - exists( - ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store, PartialDefinition pd - | - pd = node2.getPartialDefinition() and + exists(ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store | chi.getPartialOperand() = operand and store = operand.getDef() and node1.asOperand() = operand and // This `ChiInstruction` will always have a non-conflated result because both `ArrayStoreNode` // and `PointerStoreNode` require it in their characteristic predicates. - pd.getPreUpdateNode().asOperand() = chi.getTotalOperand() - | - // `x[i] = taint()` - // This matches the characteristic predicate in `ArrayStoreNode`. - store.getDestinationAddress() instanceof PointerAddInstruction - or - // `*p = taint()` - // This matches the characteristic predicate in `PointerStoreNode`. - store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction + node2.asInstruction() = chi and + ( + // `x[i] = taint()` + // This matches the characteristic predicate in `ArrayStoreNode`. + store.getDestinationAddress() instanceof PointerAddInstruction + or + // `*p = taint()` + // This matches the characteristic predicate in `PointerStoreNode`. + store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction + ) ) } @@ -333,10 +293,82 @@ private predicate arrayStoreStepChi(Node node1, ArrayContent a, PartialDefinitio * value of `node1`. */ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { - instrToFieldNodeStoreStepNoChi(node1, f, node2) or - instrToFieldNodeStoreStepChi(node1, f, node2) or + fieldStoreStepNoChi(node1, f, node2) or + fieldStoreStepChi(node1, f, node2) or arrayStoreStepChi(node1, f, node2) or - callableWithoutDefinitionStoreStep(node1, f, node2) + fieldStoreStepAfterArraySuppression(node1, f, node2) +} + +// This predicate pushes the correct `FieldContent` onto the access path when the +// `suppressArrayRead` predicate has popped off an `ArrayContent`. +private predicate fieldStoreStepAfterArraySuppression( + Node node1, FieldContent f, PostUpdateNode node2 +) { + exists(WriteSideEffectInstruction write, ChiInstruction chi, Class c | + not chi.isResultConflated() and + node1.asInstruction() = chi and + node2.asInstruction() = chi and + chi.getPartial() = write and + getWrittenField(write, f.getAField(), c) and + f.hasOffset(c, _, _) + ) +} + +bindingset[result, i] +private int unbindInt(int i) { i <= result and i >= result } + +pragma[noinline] +private predicate getLoadedField(LoadInstruction load, Field f, Class c) { + exists(FieldAddressInstruction fa | + fa = load.getSourceAddress() and + f = fa.getField() and + c = f.getDeclaringType() + ) +} + +/** + * Holds if data can flow from `node1` to `node2` via a read of `f`. + * Thus, `node1` references an object with a field `f` whose value ends up in + * `node2`. + */ +private predicate fieldReadStep(Node node1, FieldContent f, Node node2) { + exists(LoadOperand operand | + node2.asOperand() = operand and + node1.asInstruction() = operand.getAnyDef() and + exists(Class c | + c = operand.getAnyDef().getResultType() and + exists(int startBit, int endBit | + operand.getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and + f.hasOffset(c, startBit, endBit) + ) + or + getLoadedField(operand.getUse(), f.getAField(), c) and + f.hasOffset(c, _, _) + ) + ) +} + +/** + * When a store step happens in a function that looks like an array write such as: + * ```cpp + * void f(int* pa) { + * pa = source(); + * } + * ``` + * it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is + * the case, the `ArrayContent` that was written by the call to `f` should be popped off the access + * path, and a `FieldContent` containing `x` should be pushed instead. + * So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression` + * 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(WriteSideEffectInstruction write, ChiInstruction chi | + node1.asInstruction() = write and + node2.asInstruction() = chi and + chi.getPartial() = write and + getWrittenField(write, _, _) + ) } private class ArrayToPointerConvertInstruction extends ConvertInstruction { @@ -346,96 +378,34 @@ private class ArrayToPointerConvertInstruction extends ConvertInstruction { } } -private class InexactLoadOperand extends LoadOperand { - InexactLoadOperand() { this.isDefinitionInexact() } -} - -/** Get the result type of `i`, if it is a `PointerType`. */ -private PointerType getPointerType(Instruction i) { - // We are done if the type is a pointer type that is not a glvalue - i.getResultLanguageType().hasType(result, false) +private Instruction skipOneCopyValueInstructionRec(CopyValueInstruction copy) { + copy.getUnary() = result and not result instanceof CopyValueInstruction or - // Some instructions produce a glvalue. Recurse past those to get the actual `PointerType`. - result = getPointerType(i.(PointerOffsetInstruction).getLeft()) + result = skipOneCopyValueInstructionRec(copy.getUnary()) } -pragma[noinline] -private predicate deconstructLoad( - LoadInstruction load, InexactLoadOperand loadOperand, Instruction addressInstr -) { - load.getSourceAddress() = addressInstr and - load.getSourceValueOperand() = loadOperand +private Instruction skipCopyValueInstructions(Operand op) { + not result instanceof CopyValueInstruction and result = op.getDef() + or + result = skipOneCopyValueInstructionRec(op.getDef()) } private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { a = TArrayContent() and // Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array. - exists(InexactLoadOperand loadOperand, LoadInstruction load, Instruction address | - deconstructLoad(load, loadOperand, address) and - node1.asInstruction() = loadOperand.getAnyDef() and - not node1.asInstruction().isResultConflated() and - loadOperand = node2.asOperand() and - // Ensure that the load is actually loading from an array or a pointer. - getPointerType(address).getBaseType() = load.getResultType() - ) -} - -/** Step from the value loaded by a `LoadInstruction` to the "outermost" loaded field. */ -private predicate instrToFieldNodeReadStep(FieldNode node1, FieldContent f, Node node2) { - ( - node1.getNextNode() = node2 - or - not exists(node1.getNextNode()) and - ( - exists(LoadInstruction load | - node2.asInstruction() = load and - node1 = GetFieldNode::fromInstruction(load.getSourceAddress()) - ) - or - exists(ReadSideEffectInstruction read | - node2.asOperand() = read.getSideEffectOperand() and - node1 = GetFieldNode::fromInstruction(read.getArgumentDef()) - ) - ) - ) and - f.getADirectField() = node1.getField() -} - -bindingset[result, i] -private int unbindInt(int i) { i <= result and i >= result } - -pragma[noinline] -private FieldNode getFieldNodeFromLoadOperand(LoadOperand loadOperand) { - result = GetFieldNode::fromOperand(loadOperand.getAddressOperand()) -} - -/** - * Sometimes there's no explicit field dereference. In such cases we use the IR alias analysis to - * determine the offset being, and deduce the field from this information. - */ -private predicate aliasedReadStep(Node node1, FieldContent f, Node node2) { - exists(LoadOperand operand, Class c, int startBit, int endBit | - // Ensure that we don't already catch this store step using a `FieldNode`. - not instrToFieldNodeReadStep(getFieldNodeFromLoadOperand(operand), f, _) and + exists(LoadOperand operand, Instruction address | + operand.isDefinitionInexact() and node1.asInstruction() = operand.getAnyDef() and - node2.asOperand() = operand and - not node1.asInstruction().isResultConflated() and - c = operand.getAnyDef().getResultType() and - f.hasOffset(c, startBit, endBit) and - operand.getUsedInterval(unbindInt(startBit), unbindInt(endBit)) + operand = node2.asOperand() and + address = skipCopyValueInstructions(operand.getAddressOperand()) and + ( + address instanceof LoadInstruction or + address instanceof ArrayToPointerConvertInstruction or + address instanceof PointerOffsetInstruction + ) ) } -/** Get the result type of an `Instruction` i, if it is a `ReferenceType`. */ -private ReferenceType getReferenceType(Instruction i) { - i.getResultLanguageType().hasType(result, false) -} - -pragma[noinline] -Type getResultTypeOfSourceValue(CopyValueInstruction copy) { - result = copy.getSourceValue().getResultType() -} - /** * In cases such as: * ```cpp @@ -447,25 +417,21 @@ Type getResultTypeOfSourceValue(CopyValueInstruction copy) { * f(&x); * use(x); * ``` - * the store to `*pa` in `f` will push `ArrayContent` onto the access path. The `innerRead` predicate - * pops the `ArrayContent` off the access path when a value-to-pointer or value-to-reference conversion - * happens on the argument that is ends up as the target of such a store. + * the load on `x` in `use(x)` will exactly overlap with its definition (in this case the definition + * is a `WriteSideEffect`). This predicate pops the `ArrayContent` (pushed by the store in `f`) + * from the access path. */ -private predicate innerReadStep(Node node1, Content a, Node node2) { +private predicate exactReadStep(Node node1, ArrayContent a, Node node2) { a = TArrayContent() and - exists(WriteSideEffectInstruction write, CallInstruction call, CopyValueInstruction copyValue | - write.getPrimaryInstruction() = call and + exists(WriteSideEffectInstruction write, ChiInstruction chi | + not chi.isResultConflated() and + chi.getPartial() = write and node1.asInstruction() = write and - ( - not exists(ChiInstruction chi | chi.getPartial() = write) - or - exists(ChiInstruction chi | chi.getPartial() = write and not chi.isResultConflated()) - ) and - node2.asInstruction() = write and - copyValue = call.getArgument(write.getIndex()) and - // Check that `copyValue` is actually doing a T to a T* conversion. - [getPointerType(copyValue).getBaseType(), getReferenceType(copyValue).getBaseType()].stripType() = - getResultTypeOfSourceValue(copyValue).stripType() + node2.asInstruction() = chi and + // To distinquish this case from the `arrayReadStep` case we require that the entire variable was + // overwritten by the `WriteSideEffectInstruction` (i.e., there is a load that reads the + // entire variable). + exists(LoadInstruction load | load.getSourceValue() = chi) ) } @@ -475,10 +441,10 @@ private predicate innerReadStep(Node node1, Content a, Node node2) { * `node2`. */ predicate readStep(Node node1, Content f, Node node2) { - aliasedReadStep(node1, f, node2) or + fieldReadStep(node1, f, node2) or arrayReadStep(node1, f, node2) or - instrToFieldNodeReadStep(node1, f, node2) or - innerReadStep(node1, f, node2) + exactReadStep(node1, f, node2) or + suppressArrayRead(node1, f, node2) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index aba8e3bceec..cbc44ac920d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -15,11 +15,7 @@ cached private newtype TIRDataFlowNode = TInstructionNode(Instruction i) or TOperandNode(Operand op) or - TVariableNode(Variable var) or - // `FieldNodes` are used as targets of certain `storeStep`s to implement handling of stores to - // nested structs. - TFieldNode(FieldAddressInstruction field) or - TPartialDefinitionNode(PartialDefinition pd) + TVariableNode(Variable var) /** * A node in a data flow graph. @@ -32,22 +28,7 @@ class Node extends TIRDataFlowNode { /** * INTERNAL: Do not use. */ - final Declaration getEnclosingCallable() { - result = unique(Declaration d | d = this.getEnclosingCallableImpl() | d) - } - - final private Declaration getEnclosingCallableImpl() { - result = this.asInstruction().getEnclosingFunction() or - result = this.asOperand().getUse().getEnclosingFunction() or - // When flow crosses from one _enclosing callable_ to another, the - // interprocedural data-flow library discards call contexts and inserts a - // node in the big-step relation used for human-readable path explanations. - // Therefore we want a distinct enclosing callable for each `VariableNode`, - // and that can be the `Variable` itself. - result = this.asVariable() or - result = this.(FieldNode).getFieldInstruction().getEnclosingFunction() or - result = this.(PartialDefinitionNode).getPreUpdateNode().getFunction() - } + Declaration getEnclosingCallable() { none() } // overridden in subclasses /** Gets the function to which this node belongs, if any. */ Function getFunction() { none() } // overridden in subclasses @@ -152,6 +133,8 @@ class InstructionNode extends Node, TInstructionNode { /** Gets the instruction corresponding to this node. */ Instruction getInstruction() { result = instr } + override Declaration getEnclosingCallable() { result = this.getFunction() } + override Function getFunction() { result = instr.getEnclosingFunction() } override IRType getType() { result = instr.getResultIRType() } @@ -176,6 +159,8 @@ class OperandNode extends Node, TOperandNode { /** Gets the operand corresponding to this node. */ Operand getOperand() { result = op } + override Declaration getEnclosingCallable() { result = this.getFunction() } + override Function getFunction() { result = op.getUse().getEnclosingFunction() } override IRType getType() { result = op.getIRType() } @@ -185,139 +170,6 @@ class OperandNode extends Node, TOperandNode { override string toString() { result = this.getOperand().toString() } } -/** - * INTERNAL: do not use. Encapsulates the details of getting a `FieldNode` from - * an `Instruction` or an `Operand`. - */ -module GetFieldNode { - /** An abstract class that defines conversion-like instructions. */ - abstract private class SkippableInstruction extends Instruction { - abstract Instruction getSourceInstruction(); - } - - /** - * Gets the instruction that is propaged through a non-empty sequence of conversion-like instructions. - */ - private Instruction skipSkippableInstructionsRec(SkippableInstruction skip) { - result = skip.getSourceInstruction() and not result instanceof SkippableInstruction - or - result = skipSkippableInstructionsRec(skip.getSourceInstruction()) - } - - /** - * Gets the instruction that is propagated through a (possibly empty) sequence of conversion-like - * instructions. - */ - private Instruction skipSkippableInstructions(Instruction instr) { - result = instr and not result instanceof SkippableInstruction - or - result = skipSkippableInstructionsRec(instr) - } - - private class SkippableCopyValueInstruction extends SkippableInstruction, CopyValueInstruction { - override Instruction getSourceInstruction() { result = this.getSourceValue() } - } - - private class SkippableConvertInstruction extends SkippableInstruction, ConvertInstruction { - override Instruction getSourceInstruction() { result = this.getUnary() } - } - - private class SkippableCheckedConvertInstruction extends SkippableInstruction, - CheckedConvertOrNullInstruction { - override Instruction getSourceInstruction() { result = this.getUnary() } - } - - private class SkippableInheritanceConversionInstruction extends SkippableInstruction, - InheritanceConversionInstruction { - override Instruction getSourceInstruction() { result = this.getUnary() } - } - - /** - * INTERNAL: do not use. Gets the `FieldNode` corresponding to `instr`, if - * `instr` is an instruction that propagates an address of a `FieldAddressInstruction`. - */ - FieldNode fromInstruction(Instruction instr) { - result.getFieldInstruction() = skipSkippableInstructions(instr) - } - - /** - * INTERNAL: do not use. Gets the `FieldNode` corresponding to `op`, if the definition - * of `op` is an instruction that propagates an address of a `FieldAddressInstruction`. - */ - FieldNode fromOperand(Operand op) { result = fromInstruction(op.getDef()) } -} - -/** - * INTERNAL: do not use. A `FieldNode` represents the state of a field before any partial definitions - * of the field. For instance, in the snippet: - * ```cpp - * struct A { struct B { int c; } b; }; - * // ... - * A a; - * f(a.b.c); - * ``` - * there are two `FieldNode`s: one corresponding to `c`, and one corresponding to `b`. Similarly, - * in `a.b.c = x` there are two `FieldNode`s: one for `c` and one for `b`. - */ -class FieldNode extends Node, TFieldNode { - FieldAddressInstruction field; - - FieldNode() { this = TFieldNode(field) } - - /** Gets the `Field` of this `FieldNode`. */ - Field getField() { result = getFieldInstruction().getField() } - - /** Gets the `FieldAddressInstruction` of this `FieldNode`. */ - FieldAddressInstruction getFieldInstruction() { result = field } - - /** - * Gets the `FieldNode` corresponding to the parent field of this `FieldNode`, if any. - * - * For example, if `f` is the `FieldNode` for `c` in the expression `a.b.c`, then `f.getObjectNode()` - * gives the `FieldNode` of `b`, and `f.getObjectNode().getObjectNode()` has no result as `a` is - * not a field. - */ - FieldNode getObjectNode() { result = GetFieldNode::fromInstruction(field.getObjectAddress()) } - - /** - * Gets the `FieldNode` that has this `FieldNode` as parent, if any. - * - * For example, if `f` is the `FieldNode` corresponding to `b` in `a.b.c`, then `f.getNextNode()` - * gives the `FieldNode` corresponding to `c`, and `f.getNextNode().getNextNode()`. - */ - FieldNode getNextNode() { result.getObjectNode() = this } - - /** Gets the class where the field of this node is declared. */ - Class getDeclaringType() { result = getField().getDeclaringType() } - - override Function getFunction() { result = field.getEnclosingFunction() } - - override IRType getType() { result = field.getResultIRType() } - - override Location getLocation() { result = field.getLocation() } - - override string toString() { result = this.getField().toString() } -} - -/** - * INTERNAL: do not use. A partial definition of a `FieldNode`. - */ -class PartialFieldDefinition extends FieldNode, PartialDefinition { - /** - * The pre-update node of a partial definition of a `FieldNode` is the `FieldNode` itself. This ensures - * that the data flow library's reverse read mechanism builds up the correct access path for nested - * fields. - * For instance, in `a.b.c = x` there is a partial definition for `c` (let's call it `post[c]`) and a - * partial definition for `b` (let's call it `post[b]`), and there is a read step from `b` to `c` - * (using `instrToFieldNodeReadStep`), so there is a store step from `post[c]` to `post[b]`. - */ - override FieldNode getPreUpdateNode() { result = this } - - override Expr getDefinedExpr() { - result = this.getFieldInstruction().getObjectAddress().getUnconvertedResultExpression() - } -} - /** * An expression, viewed as a node in a data flow graph. */ @@ -455,26 +307,11 @@ deprecated class UninitializedNode extends Node { * This class exists to match the interface used by Java. There are currently no non-abstract * classes that extend it. When we implement field flow, we can revisit this. */ -abstract class PostUpdateNode extends Node { +abstract class PostUpdateNode extends InstructionNode { /** * Gets the node before the state update. */ abstract Node getPreUpdateNode(); - - override Function getFunction() { result = getPreUpdateNode().getFunction() } - - override IRType getType() { result = getPreUpdateNode().getType() } - - override Location getLocation() { result = getPreUpdateNode().getLocation() } -} - -/** INTERNAL: do not use. A partial definition of a node. */ -abstract class PartialDefinition extends Node { - /** Gets the node before the state update. */ - abstract Node getPreUpdateNode(); - - /** Gets the expression that is partially defined by this node. */ - abstract Expr getDefinedExpr(); } /** @@ -490,40 +327,112 @@ abstract class PartialDefinition extends Node { * setY(&x); // a partial definition of the object `x`. * ``` */ -class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode { - PartialDefinition pd; +abstract private class PartialDefinitionNode extends PostUpdateNode { + abstract Expr getDefinedExpr(); +} - PartialDefinitionNode() { this = TPartialDefinitionNode(pd) } +private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { + override ChiInstruction instr; + StoreInstruction store; - /** Gets the expression that is partially defined by this node, if any. */ - Expr getDefinedExpr() { result = pd.getDefinedExpr() } + ExplicitFieldStoreQualifierNode() { + not instr.isResultConflated() and + instr.getPartial() = store and + ( + instr.getUpdatedInterval(_, _) or + store.getDestinationAddress() instanceof FieldAddressInstruction + ) + } - override Node getPreUpdateNode() { result = pd.getPreUpdateNode() } + // By using an operand as the result of this predicate we avoid the dataflow inconsistency errors + // caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause + // a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node + // into a big step. + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } - /** Gets the `PartialDefinition` associated with this node. */ - PartialDefinition getPartialDefinition() { result = pd } + override Expr getDefinedExpr() { + result = + store + .getDestinationAddress() + .(FieldAddressInstruction) + .getObjectAddress() + .getUnconvertedResultExpression() + } +} - override string toString() { result = getPreUpdateNode().toString() + " [post update]" } +/** + * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. + * For instance, an update to a field of a struct containing only one field. For these cases we + * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case + * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. + */ +private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { + override StoreInstruction instr; + + ExplicitSingleFieldStoreQualifierNode() { + not exists(ChiInstruction chi | chi.getPartial() = instr) and + // Without this condition any store would create a `PostUpdateNode`. + instr.getDestinationAddress() instanceof FieldAddressInstruction + } + + override Node getPreUpdateNode() { none() } + + override Expr getDefinedExpr() { + result = + instr + .getDestinationAddress() + .(FieldAddressInstruction) + .getObjectAddress() + .getUnconvertedResultExpression() + } +} + +private FieldAddressInstruction getFieldInstruction(Instruction instr) { + result = instr or + result = instr.(CopyValueInstruction).getUnary() +} + +/** + * The target of a `fieldStoreStepAfterArraySuppression` store step, which is used to convert + * an `ArrayContent` to a `FieldContent` when the `WriteSideEffect` instruction stores + * into a field. See the QLDoc for `suppressArrayRead` for an example of where such a conversion + * is inserted. + */ +private class WriteSideEffectFieldStoreQualifierNode extends PartialDefinitionNode { + override ChiInstruction instr; + WriteSideEffectInstruction write; + FieldAddressInstruction field; + + WriteSideEffectFieldStoreQualifierNode() { + not instr.isResultConflated() and + instr.getPartial() = write and + field = getFieldInstruction(write.getDestinationAddress()) + } + + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } } /** * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. */ -private class ArrayStoreNode extends InstructionNode, PartialDefinition { - ChiInstruction chi; +private class ArrayStoreNode extends PartialDefinitionNode { + override ChiInstruction instr; PointerAddInstruction add; ArrayStoreNode() { - chi = this.getInstruction() and - not chi.isResultConflated() and + not instr.isResultConflated() and exists(StoreInstruction store | - chi.getPartial() = store and + instr.getPartial() = store and add = store.getDestinationAddress() ) } - override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() } + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } override Expr getDefinedExpr() { result = add.getLeft().getUnconvertedResultExpression() } } @@ -532,24 +441,18 @@ private class ArrayStoreNode extends InstructionNode, PartialDefinition { * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. */ -private class PointerStoreNode extends InstructionNode, PartialDefinition { - ChiInstruction chi; - LoadInstruction load; +private class PointerStoreNode extends PostUpdateNode { + override ChiInstruction instr; PointerStoreNode() { - chi = this.getInstruction() and - not chi.isResultConflated() and + not instr.isResultConflated() and exists(StoreInstruction store | - chi.getPartial() = store and - load = store.getDestinationAddress().(CopyValueInstruction).getUnary() + instr.getPartial() = store and + store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction ) } - override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() } - - override Expr getDefinedExpr() { - result = load.getSourceAddress().getUnconvertedResultExpression() - } + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } } /** @@ -562,7 +465,7 @@ private class PointerStoreNode extends InstructionNode, PartialDefinition { * returned. This node will have its `getArgument()` equal to `&x` and its * `getVariableAccess()` equal to `x`. */ -class DefinitionByReferenceNode extends InstructionNode, PostUpdateNode { +class DefinitionByReferenceNode extends InstructionNode { override WriteSideEffectInstruction instr; /** Gets the unconverted argument corresponding to this node. */ @@ -590,22 +493,6 @@ class DefinitionByReferenceNode extends InstructionNode, PostUpdateNode { not exists(instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget()) and result = "output argument" } - - override Function getFunction() { result = instr.getEnclosingFunction() } - - override IRType getType() { result = instr.getResultIRType() } - - override Location getLocation() { result = instr.getLocation() } - - // Make the read side effect's side effect operand the pre update node of this write side effect. - // This ensures that we match up the parameter index of the parameter indirection's modification. - override Node getPreUpdateNode() { - exists(ReadSideEffectInstruction read | - read.getPrimaryInstruction() = instr.getPrimaryInstruction() and - read.getArgumentDef() = instr.getDestinationAddress() and - result.asOperand() = read.getSideEffectOperand() - ) - } } /** @@ -623,6 +510,15 @@ class VariableNode extends Node, TVariableNode { override Function getFunction() { none() } + override Declaration getEnclosingCallable() { + // When flow crosses from one _enclosing callable_ to another, the + // interprocedural data-flow library discards call contexts and inserts a + // node in the big-step relation used for human-readable path explanations. + // Therefore we want a distinct enclosing callable for each `VariableNode`, + // and that can be the `Variable` itself. + result = v + } + override IRType getType() { result.getCanonicalLanguageType().hasUnspecifiedType(v.getType(), _) } override Location getLocation() { result = v.getLocation() } @@ -689,69 +585,6 @@ Node uninitializedNode(LocalVariable v) { none() } */ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) } -private predicate flowOutOfPostUpdate(PartialDefinitionNode nodeFrom, Node nodeTo) { - // flow from the "outermost" field to the `ChiInstruction`, or `StoreInstruction` - // if no `ChiInstruction` exists. - exists(AddressOperand addressOperand, PartialFieldDefinition pd | - pd = nodeFrom.getPartialDefinition() and - not exists(pd.getPreUpdateNode().getObjectNode()) and - pd.getPreUpdateNode().getNextNode*() = GetFieldNode::fromOperand(addressOperand) and - ( - exists(ChiInstruction chi | - nodeTo.asInstruction() = chi and - chi.getPartial().getAnOperand() = addressOperand - ) - or - exists(StoreInstruction store | - not exists(ChiInstruction chi | chi.getPartial() = store) and - nodeTo.asInstruction() = store and - store.getDestinationAddressOperand() = addressOperand - ) - ) - ) - or - // Note: This partial definition cannot be a `PostUpdateFieldNode` since these nodes do not have an - // operand node as their pre update node. - exists(PartialDefinition pd | - pd = nodeFrom.getPartialDefinition() and - nodeTo.asInstruction().(ChiInstruction).getTotalOperand() = pd.getPreUpdateNode().asOperand() - ) -} - -/** - * Gets the `FieldNode` corresponding to the outermost field that is used to compute `address`. - */ -private FieldNode getOutermostFieldNode(Instruction address) { - not exists(result.getObjectNode()) and - result.getNextNode*() = GetFieldNode::fromInstruction(address) -} - -private predicate flowIntoReadNode(Node nodeFrom, FieldNode nodeTo) { - // flow from the memory of a load to the "outermost" field of that load. - exists(LoadInstruction load | - nodeTo = getOutermostFieldNode(load.getSourceAddress()) and - not nodeFrom.asInstruction().isResultConflated() and - nodeFrom.asInstruction() = load.getSourceValueOperand().getAnyDef() - ) - or - // We need this to make stores look like loads for the dataflow library. So when there's a store - // of the form x->y = z we need to make the field node corresponding to y look like it's reading - // from the memory of x. - exists(StoreInstruction store, ChiInstruction chi | - chi.getPartial() = store and - nodeTo = getOutermostFieldNode(store.getDestinationAddress()) and - not nodeFrom.asInstruction().isResultConflated() and - nodeFrom.asInstruction() = chi.getTotal() - ) - or - exists(ReadSideEffectInstruction read, SideEffectOperand sideEffect | - sideEffect = read.getSideEffectOperand() and - not sideEffect.getAnyDef().isResultConflated() and - nodeTo = getOutermostFieldNode(read.getArgumentDef()) and - nodeFrom.asOperand() = sideEffect - ) -} - /** * INTERNAL: do not use. * @@ -765,10 +598,6 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { or // Instruction -> Operand flow simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand()) - or - flowIntoReadNode(nodeFrom, nodeTo) - or - flowOutOfPostUpdate(nodeFrom, nodeTo) } pragma[noinline] @@ -911,27 +740,6 @@ private predicate modelFlow(Operand opFrom, Instruction iTo) { ) ) ) - or - impliedModelFlow(opFrom, iTo) -} - -/** - * When a `DataFlowFunction` specifies dataflow from a parameter `p` to the return value there should - * also be dataflow from the parameter dereference (i.e., `*p`) to the return value dereference. - */ -private predicate impliedModelFlow(Operand opFrom, Instruction iTo) { - exists( - CallInstruction call, DataFlowFunction func, FunctionInput modelIn, FunctionOutput modelOut, - int index - | - call.getStaticCallTarget() = func and - func.hasDataFlow(modelIn, modelOut) - | - modelIn.isParameterOrQualifierAddress(index) and - modelOut.isReturnValue() and - opFrom = getSideEffectFor(call, index).(ReadSideEffectInstruction).getSideEffectOperand() and - iTo = call // TODO: Add write side effects for return values - ) } /** diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index 7ec66b3a2e9..c36c1da9bcd 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -28,3 +28,5 @@ private import implementations.Swap private import implementations.GetDelim private import implementations.SmartPointer private import implementations.Sscanf +private import implementations.Send +private import implementations.Recv diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll index 91ec1525834..25dae1c2fd1 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll @@ -15,7 +15,7 @@ private class MallocAllocationFunction extends AllocationFunction { MallocAllocationFunction() { // --- C library allocation - hasGlobalOrStdName("malloc") and // malloc(size) + hasGlobalOrStdOrBslName("malloc") and // malloc(size) sizeArg = 0 or hasGlobalName([ @@ -104,7 +104,7 @@ private class CallocAllocationFunction extends AllocationFunction { CallocAllocationFunction() { // --- C library allocation - hasGlobalOrStdName("calloc") and // calloc(num, size) + hasGlobalOrStdOrBslName("calloc") and // calloc(num, size) sizeArg = 1 and multArg = 0 } @@ -124,7 +124,7 @@ private class ReallocAllocationFunction extends AllocationFunction { ReallocAllocationFunction() { // --- C library allocation - hasGlobalOrStdName("realloc") and // realloc(ptr, size) + hasGlobalOrStdOrBslName("realloc") and // realloc(ptr, size) sizeArg = 1 and reallocArg = 0 or diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll index b56c8c21949..6bd2916b733 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll @@ -13,9 +13,13 @@ private class StandardDeallocationFunction extends DeallocationFunction { int freedArg; StandardDeallocationFunction() { - hasGlobalName([ + hasGlobalOrStdOrBslName([ // --- C library allocation - "free", "realloc", + "free", "realloc" + ]) and + freedArg = 0 + or + hasGlobalName([ // --- OpenSSL memory allocation "CRYPTO_free", "CRYPTO_secure_free" ]) and diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll index 11568c8a974..df2d92fbc4f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll @@ -1,8 +1,8 @@ import semmle.code.cpp.models.interfaces.Alias import semmle.code.cpp.models.interfaces.FlowSource -private class Fread extends AliasFunction, RemoteFlowFunction { - Fread() { this.hasGlobalName("fread") } +private class Fread extends AliasFunction, RemoteFlowSourceFunction { + Fread() { this.hasGlobalOrStdOrBslName("fread") } override predicate parameterNeverEscapes(int n) { n = 0 or diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll index 3561caee7fb..e2015406346 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll @@ -7,7 +7,7 @@ import semmle.code.cpp.models.interfaces.FlowSource * The standard functions `getdelim`, `getwdelim` and the glibc variant `__getdelim`. */ private class GetDelimFunction extends TaintFunction, AliasFunction, SideEffectFunction, - RemoteFlowFunction { + RemoteFlowSourceFunction { GetDelimFunction() { hasGlobalName(["getdelim", "getwdelim", "__getdelim"]) } override predicate hasTaintFlow(FunctionInput i, FunctionOutput o) { diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll index 9761a4293a8..87e191241d2 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll @@ -8,8 +8,8 @@ import semmle.code.cpp.models.interfaces.FlowSource /** * The POSIX function `getenv`. */ -class Getenv extends LocalFlowFunction { - Getenv() { this.hasGlobalName("getenv") } +class Getenv extends LocalFlowSourceFunction { + Getenv() { this.hasGlobalOrStdOrBslName("getenv") } override predicate hasLocalFlowSource(FunctionOutput output, string description) { ( diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index 91653cd6b37..08222c2cd6a 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -14,12 +14,12 @@ import semmle.code.cpp.models.interfaces.FlowSource * The standard functions `gets` and `fgets`. */ private class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction, - SideEffectFunction, RemoteFlowFunction { + SideEffectFunction, RemoteFlowSourceFunction { GetsFunction() { // gets(str) // fgets(str, num, stream) // fgetws(wstr, num, stream) - hasGlobalOrStdName(["gets", "fgets", "fgetws"]) + hasGlobalOrStdOrBslName(["gets", "fgets", "fgetws"]) } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { @@ -54,13 +54,13 @@ private class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunctio } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { - not hasGlobalOrStdName("gets") and + not hasName("gets") and bufParam = 0 and countParam = 1 } override predicate hasArrayWithUnknownSize(int bufParam) { - hasGlobalOrStdName("gets") and + hasName("gets") and bufParam = 0 } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll index 0178cd0f7ec..60afd2b25ef 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll @@ -6,12 +6,9 @@ import semmle.code.cpp.models.interfaces.SideEffect /** * The standard function templates `std::move` and `std::forward`. */ -private class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFunction { - IdentityFunction() { - this.getNamespace().getParentNamespace() instanceof GlobalNamespace and - this.getNamespace().getName() = "std" and - this.getName() = ["move", "forward"] - } +private class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFunction, + FunctionTemplateInstantiation { + IdentityFunction() { this.hasQualifiedName("std", ["move", "forward"]) } override predicate hasOnlySpecificReadSideEffects() { any() } @@ -32,5 +29,7 @@ private class IdentityFunction extends DataFlowFunction, SideEffectFunction, Ali override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // These functions simply return the argument value. input.isParameter(0) and output.isReturnValue() + or + input.isParameterDeref(0) and output.isReturnValueDeref() } } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll index 3a789a6aa25..24d5456293f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll @@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.Iterator */ private class IteratorTraits extends Class { IteratorTraits() { - this.hasQualifiedName("std", "iterator_traits") and + this.hasQualifiedName(["std", "bsl"], "iterator_traits") and not this instanceof TemplateClass and exists(TypedefType t | this.getAMember() = t and @@ -26,6 +26,14 @@ private class IteratorTraits extends Class { Type getIteratorType() { result = this.getTemplateArgument(0) } } +/** + * A type that is deduced to be an iterator because there is a corresponding + * `std::iterator_traits` instantiation for it. + */ +private class IteratorByTraits extends Iterator { + IteratorByTraits() { exists(IteratorTraits it | it.getIteratorType() = this) } +} + /** * A type which has the typedefs expected for an iterator. */ @@ -36,7 +44,7 @@ private class IteratorByTypedefs extends Iterator, Class { this.getAMember().(TypedefType).hasName("pointer") and this.getAMember().(TypedefType).hasName("reference") and this.getAMember().(TypedefType).hasName("iterator_category") and - not this.hasQualifiedName("std", "iterator_traits") + not this.hasQualifiedName(["std", "bsl"], "iterator_traits") } } @@ -44,17 +52,13 @@ private class IteratorByTypedefs extends Iterator, Class { * The `std::iterator` class. */ private class StdIterator extends Iterator, Class { - StdIterator() { this.hasQualifiedName("std", "iterator") } + StdIterator() { this.hasQualifiedName(["std", "bsl"], "iterator") } } /** - * A type that is deduced to be an iterator because there is a corresponding - * `std::iterator_traits` instantiation for it. + * Gets the `FunctionInput` corresponding to an iterator parameter to + * user-defined operator `op`, at `index`. */ -private class IteratorByTraits extends Iterator { - IteratorByTraits() { exists(IteratorTraits it | it.getIteratorType() = this) } -} - private FunctionInput getIteratorArgumentInput(Operator op, int index) { exists(Type t | t = @@ -109,6 +113,8 @@ private class IteratorCrementOperator extends Operator, DataFlowFunction { override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input = iteratorInput and output.isReturnValue() + or + input.isParameterDeref(0) and output.isReturnValueDeref() } } @@ -153,7 +159,7 @@ private class IteratorSubOperator extends Operator, TaintFunction { private class IteratorAssignArithmeticOperator extends Operator, DataFlowFunction, TaintFunction { IteratorAssignArithmeticOperator() { this.hasName(["operator+=", "operator-="]) and - this.getDeclaringType() instanceof Iterator + exists(getIteratorArgumentInput(this, 0)) } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { @@ -162,6 +168,12 @@ private class IteratorAssignArithmeticOperator extends Operator, DataFlowFunctio } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isParameterDeref(0) and output.isReturnValueDeref() + or + // reverse flow from returned reference to the object referenced by the first parameter + input.isReturnValueDeref() and + output.isParameterDeref(0) + or input.isParameterDeref(1) and output.isParameterDeref(0) } @@ -173,8 +185,7 @@ private class IteratorAssignArithmeticOperator extends Operator, DataFlowFunctio class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction, IteratorReferenceFunction { IteratorPointerDereferenceMemberOperator() { - this.hasName("operator*") and - this.getDeclaringType() instanceof Iterator + this.getClassAndName("operator*") instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -191,8 +202,7 @@ class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunc */ private class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction { IteratorCrementMemberOperator() { - this.hasName(["operator++", "operator--"]) and - this.getDeclaringType() instanceof Iterator + this.getClassAndName(["operator++", "operator--"]) instanceof Iterator } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { @@ -201,6 +211,9 @@ private class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunc or input.isReturnValueDeref() and output.isQualifierObject() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -213,10 +226,7 @@ private class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunc * A member `operator->` function for an iterator type. */ private class IteratorFieldMemberOperator extends Operator, TaintFunction { - IteratorFieldMemberOperator() { - this.hasName("operator->") and - this.getDeclaringType() instanceof Iterator - } + IteratorFieldMemberOperator() { this.getClassAndName("operator->") instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and @@ -229,8 +239,7 @@ private class IteratorFieldMemberOperator extends Operator, TaintFunction { */ private class IteratorBinaryArithmeticMemberOperator extends MemberFunction, TaintFunction { IteratorBinaryArithmeticMemberOperator() { - this.hasName(["operator+", "operator-"]) and - this.getDeclaringType() instanceof Iterator + this.getClassAndName(["operator+", "operator-"]) instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -245,21 +254,24 @@ private class IteratorBinaryArithmeticMemberOperator extends MemberFunction, Tai private class IteratorAssignArithmeticMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction { IteratorAssignArithmeticMemberOperator() { - this.hasName(["operator+=", "operator-="]) and - this.getDeclaringType() instanceof Iterator + this.getClassAndName(["operator+=", "operator-="]) instanceof Iterator } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input.isQualifierAddress() and output.isReturnValue() - or - input.isReturnValueDeref() and - output.isQualifierObject() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and output.isReturnValueDeref() + or + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() + or + input.isParameterDeref(0) and + output.isQualifierObject() } } @@ -268,10 +280,7 @@ private class IteratorAssignArithmeticMemberOperator extends MemberFunction, Dat */ private class IteratorArrayMemberOperator extends MemberFunction, TaintFunction, IteratorReferenceFunction { - IteratorArrayMemberOperator() { - this.hasName("operator[]") and - this.getDeclaringType() instanceof Iterator - } + IteratorArrayMemberOperator() { this.getClassAndName("operator[]") instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and @@ -288,8 +297,7 @@ private class IteratorArrayMemberOperator extends MemberFunction, TaintFunction, */ private class IteratorAssignmentMemberOperator extends MemberFunction, TaintFunction { IteratorAssignmentMemberOperator() { - this.hasName("operator=") and - this.getDeclaringType() instanceof Iterator and + this.getClassAndName("operator=") instanceof Iterator and not this instanceof CopyAssignmentOperator and not this instanceof MoveAssignmentOperator } @@ -330,7 +338,7 @@ private class BeginOrEndFunction extends MemberFunction, TaintFunction, GetItera */ private class InserterIteratorFunction extends GetIteratorFunction { InserterIteratorFunction() { - this.hasQualifiedName("std", ["front_inserter", "inserter", "back_inserter"]) + this.hasQualifiedName(["std", "bsl"], ["front_inserter", "inserter", "back_inserter"]) } override predicate getsIterator(FunctionInput input, FunctionOutput output) { diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll index 02fa810142f..b7d8aed60fa 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll @@ -20,7 +20,7 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect // memcpy(dest, src, num) // memmove(dest, src, num) // memmove(dest, src, num, remaining) - this.hasGlobalOrStdName(["memcpy", "memmove"]) + this.hasGlobalOrStdOrBslName(["memcpy", "memmove"]) or // bcopy(src, dest, num) // mempcpy(dest, src, num) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index 6636b34fe9d..d646be0363d 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -15,7 +15,9 @@ import semmle.code.cpp.models.interfaces.SideEffect private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction, SideEffectFunction { MemsetFunction() { - this.hasGlobalOrStdName(["memset", "wmemset"]) + this.hasGlobalOrStdOrBslName("memset") + or + this.hasGlobalOrStdName("wmemset") or this.hasGlobalName([bzero(), "__builtin_memset", "__builtin_memset_chk"]) } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index 1767261efac..ed201a14587 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -15,7 +15,7 @@ private class Printf extends FormattingFunction, AliasFunction { Printf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdName(["printf", "wprintf"]) or + hasGlobalOrStdOrBslName(["printf", "wprintf"]) or hasGlobalName(["printf_s", "wprintf_s", "g_printf"]) ) and not exists(getDefinition().getFile().getRelativePath()) @@ -23,10 +23,7 @@ private class Printf extends FormattingFunction, AliasFunction { override int getFormatParameterIndex() { result = 0 } - deprecated override predicate isWideCharDefault() { - hasGlobalOrStdName("wprintf") or - hasGlobalName("wprintf_s") - } + deprecated override predicate isWideCharDefault() { hasName(["wprintf", "wprintf_s"]) } override predicate isOutputGlobal() { any() } @@ -44,7 +41,7 @@ private class Fprintf extends FormattingFunction { Fprintf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdName(["fprintf", "fwprintf"]) or + hasGlobalOrStdOrBslName(["fprintf", "fwprintf"]) or hasGlobalName("g_fprintf") ) and not exists(getDefinition().getFile().getRelativePath()) @@ -52,7 +49,7 @@ private class Fprintf extends FormattingFunction { override int getFormatParameterIndex() { result = 1 } - deprecated override predicate isWideCharDefault() { hasGlobalOrStdName("fwprintf") } + deprecated override predicate isWideCharDefault() { hasName("fwprintf") } override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = true } } @@ -64,7 +61,7 @@ private class Sprintf extends FormattingFunction { Sprintf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdName([ + hasGlobalOrStdOrBslName([ "sprintf", // sprintf(dst, format, args...) "wsprintf" // wsprintf(dst, format, args...) ]) @@ -90,22 +87,20 @@ private class Sprintf extends FormattingFunction { } override int getFormatParameterIndex() { - hasGlobalName("g_strdup_printf") and result = 0 + hasName("g_strdup_printf") and result = 0 or - hasGlobalName("__builtin___sprintf_chk") and result = 3 + hasName("__builtin___sprintf_chk") and result = 3 or not getName() = ["g_strdup_printf", "__builtin___sprintf_chk"] and result = 1 } override int getOutputParameterIndex(boolean isStream) { - not hasGlobalName("g_strdup_printf") and result = 0 and isStream = false + not hasName("g_strdup_printf") and result = 0 and isStream = false } override int getFirstFormatArgumentIndex() { - if hasGlobalName("__builtin___sprintf_chk") - then result = 4 - else result = getNumberOfParameters() + if hasName("__builtin___sprintf_chk") then result = 4 else result = getNumberOfParameters() } } @@ -116,7 +111,7 @@ private class SnprintfImpl extends Snprintf { SnprintfImpl() { this instanceof TopLevelFunction and ( - hasGlobalOrStdName([ + hasGlobalOrStdOrBslName([ "snprintf", // C99 defines snprintf "swprintf" // The s version of wide-char printf is also always the n version ]) @@ -163,10 +158,7 @@ private class SnprintfImpl extends Snprintf { } override predicate returnsFullFormatLength() { - ( - hasGlobalOrStdName("snprintf") or - hasGlobalName(["g_snprintf", "__builtin___snprintf_chk", "snprintf_s"]) - ) and + hasName(["snprintf", "g_snprintf", "__builtin___snprintf_chk", "snprintf_s"]) and not exists(getDefinition().getFile().getRelativePath()) } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index 0dfa7fe6d76..d81ac80deb8 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -7,7 +7,7 @@ import semmle.code.cpp.models.interfaces.SideEffect private class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { PureStrFunction() { - hasGlobalOrStdName([ + hasGlobalOrStdOrBslName([ atoi(), "strcasestr", "strchnul", "strchr", "strchrnul", "strstr", "strpbrk", "strrchr", "strspn", strtol(), strrev(), strcmp(), strlwr(), strupr() ]) @@ -92,7 +92,7 @@ private string strcmp() { /** String standard `strlen` function, and related functions for computing string lengths. */ private class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFunction { StrLenFunction() { - hasGlobalOrStdName(["strlen", "strnlen", "wcslen"]) + hasGlobalOrStdOrBslName(["strlen", "strnlen", "wcslen"]) or hasGlobalName(["_mbslen", "_mbslen_l", "_mbstrlen", "_mbstrlen_l"]) } @@ -125,7 +125,7 @@ private class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFun /** Pure functions. */ private class PureFunction extends TaintFunction, SideEffectFunction { - PureFunction() { hasGlobalOrStdName(["abs", "labs"]) } + PureFunction() { hasGlobalOrStdOrBslName(["abs", "labs"]) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { exists(ParameterIndex i | @@ -144,7 +144,7 @@ private class PureFunction extends TaintFunction, SideEffectFunction { private class PureMemFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { PureMemFunction() { - hasGlobalOrStdName([ + hasGlobalOrStdOrBslName([ "memchr", "__builtin_memchr", "memrchr", "rawmemchr", "memcmp", "__builtin_memcmp", "memmem" ]) or this.hasGlobalName("memfrob") diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll new file mode 100644 index 00000000000..691ba528f42 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll @@ -0,0 +1,88 @@ +/** + * Provides implementation classes modeling `recv` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.interfaces.ArrayFunction +import semmle.code.cpp.models.interfaces.Alias +import semmle.code.cpp.models.interfaces.FlowSource +import semmle.code.cpp.models.interfaces.SideEffect + +/** The function `recv` and its assorted variants */ +private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction, + RemoteFlowSourceFunction { + Recv() { + this.hasGlobalName([ + "recv", // recv(socket, dest, len, flags) + "recvfrom", // recvfrom(socket, dest, len, flags, from, fromlen) + "recvmsg", // recvmsg(socket, msg, flags) + "read", // read(socket, dest, len) + "pread", // pread(socket, dest, len, offset) + "readv", // readv(socket, dest, len) + "preadv", // readv(socket, dest, len, offset) + "preadv2" // readv2(socket, dest, len, offset, flags) + ]) + } + + override predicate parameterNeverEscapes(int index) { + this.getParameter(index).getUnspecifiedType() instanceof PointerType + } + + override predicate parameterEscapesOnlyViaReturn(int index) { none() } + + override predicate parameterIsAlwaysReturned(int index) { none() } + + override predicate hasArrayWithVariableSize(int bufParam, int countParam) { + not this.hasGlobalName("recvmsg") and + bufParam = 1 and + countParam = 2 + } + + override predicate hasArrayInput(int bufParam) { this.hasGlobalName("recvfrom") and bufParam = 4 } + + override predicate hasArrayOutput(int bufParam) { + bufParam = 1 + or + this.hasGlobalName("recvfrom") and bufParam = 4 + } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + this.hasGlobalName("recvfrom") and + ( + i = 4 and buffer = true + or + i = 5 and buffer = false + ) + or + this.hasGlobalName("recvmsg") and + i = 1 and + buffer = true + } + + override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 } + + override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { + i = 1 and buffer = true and mustWrite = false + or + this.hasGlobalName("recvfrom") and + ( + i = 4 and buffer = true and mustWrite = false + or + i = 5 and buffer = false and mustWrite = false + ) + } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { any() } + + override predicate hasRemoteFlowSource(FunctionOutput output, string description) { + ( + output.isParameterDeref(1) + or + this.hasGlobalName("recvfrom") and output.isParameterDeref([4, 5]) + ) and + description = "Buffer read by " + this.getName() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll new file mode 100644 index 00000000000..6086bc7748f --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll @@ -0,0 +1,63 @@ +/** + * Provides implementation classes modeling `send` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.interfaces.ArrayFunction +import semmle.code.cpp.models.interfaces.Alias +import semmle.code.cpp.models.interfaces.FlowSource +import semmle.code.cpp.models.interfaces.SideEffect + +/** The function `send` and its assorted variants */ +private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, RemoteFlowSinkFunction { + Send() { + this.hasGlobalName([ + "send", // send(socket, buf, len, flags) + "sendto", // sendto(socket, buf, len, flags, to, tolen) + "sendmsg", // sendmsg(socket, msg, flags) + "write", // write(socket, buf, len) + "writev", // writev(socket, buf, len) + "pwritev", // pwritev(socket, buf, len, offset) + "pwritev2" // pwritev2(socket, buf, len, offset, flags) + ]) + } + + override predicate parameterNeverEscapes(int index) { + this.getParameter(index).getUnspecifiedType() instanceof PointerType + } + + override predicate parameterEscapesOnlyViaReturn(int index) { none() } + + override predicate parameterIsAlwaysReturned(int index) { none() } + + override predicate hasArrayWithVariableSize(int bufParam, int countParam) { + not this.hasGlobalName("sendmsg") and + bufParam = 1 and + countParam = 2 + } + + override predicate hasArrayInput(int bufParam) { bufParam = 1 } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { any() } + + override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { + none() + } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + i = 1 and buffer = true + or + this.hasGlobalName("sendto") and i = 4 and buffer = false + or + this.hasGlobalName("sendmsg") and i = 1 and buffer = true + } + + override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 } + + override predicate hasRemoteFlowSink(FunctionInput input, string description) { + input.isParameterDeref(1) and description = "Buffer sent by " + this.getName() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll index b13b4a8801d..c6152624792 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll @@ -4,14 +4,14 @@ import semmle.code.cpp.models.interfaces.Taint * The `std::shared_ptr` and `std::unique_ptr` template classes. */ private class UniqueOrSharedPtr extends Class { - UniqueOrSharedPtr() { this.hasQualifiedName("std", ["shared_ptr", "unique_ptr"]) } + UniqueOrSharedPtr() { this.hasQualifiedName(["std", "bsl"], ["shared_ptr", "unique_ptr"]) } } /** * The `std::make_shared` and `std::make_unique` template functions. */ private class MakeUniqueOrShared extends TaintFunction { - MakeUniqueOrShared() { this.hasQualifiedName("std", ["make_shared", "make_unique"]) } + MakeUniqueOrShared() { this.hasQualifiedName(["bsl", "std"], ["make_shared", "make_unique"]) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // Exclude the specializations of `std::make_shared` and `std::make_unique` that allocate arrays diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll index 7a38ede5fc6..367db1613fc 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -5,6 +5,41 @@ import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.Iterator +/** + * The `std::array` template class. + */ +private class Array extends Class { + Array() { this.hasQualifiedName(["std", "bsl"], "array") } +} + +/** + * The `std::deque` template class. + */ +private class Deque extends Class { + Deque() { this.hasQualifiedName(["std", "bsl"], "deque") } +} + +/** + * The `std::forward_list` template class. + */ +private class ForwardList extends Class { + ForwardList() { this.hasQualifiedName(["std", "bsl"], "forward_list") } +} + +/** + * The `std::list` template class. + */ +private class List extends Class { + List() { this.hasQualifiedName(["std", "bsl"], "list") } +} + +/** + * The `std::vector` template class. + */ +private class Vector extends Class { + Vector() { this.hasQualifiedName(["std", "bsl"], "vector") } +} + /** * Additional model for standard container constructors that reference the * value type of the container (that is, the `T` in `std::vector`). For @@ -15,7 +50,10 @@ import semmle.code.cpp.models.interfaces.Iterator */ private class StdSequenceContainerConstructor extends Constructor, TaintFunction { StdSequenceContainerConstructor() { - this.getDeclaringType().hasQualifiedName("std", ["vector", "deque", "list", "forward_list"]) + this.getDeclaringType() instanceof Vector or + this.getDeclaringType() instanceof Deque or + this.getDeclaringType() instanceof List or + this.getDeclaringType() instanceof ForwardList } /** @@ -50,7 +88,10 @@ private class StdSequenceContainerConstructor extends Constructor, TaintFunction * The standard container function `data`. */ private class StdSequenceContainerData extends TaintFunction { - StdSequenceContainerData() { this.hasQualifiedName("std", ["array", "vector"], "data") } + StdSequenceContainerData() { + this.getClassAndName("data") instanceof Array or + this.getClassAndName("data") instanceof Vector + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from container itself (qualifier) to return value @@ -69,8 +110,10 @@ private class StdSequenceContainerData extends TaintFunction { */ private class StdSequenceContainerPush extends TaintFunction { StdSequenceContainerPush() { - this.hasQualifiedName("std", ["vector", "deque", "list"], "push_back") or - this.hasQualifiedName("std", ["deque", "list", "forward_list"], "push_front") + this.getClassAndName("push_back") instanceof Vector or + this.getClassAndName(["push_back", "push_front"]) instanceof Deque or + this.getClassAndName("push_front") instanceof ForwardList or + this.getClassAndName(["push_back", "push_front"]) instanceof List } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -85,8 +128,11 @@ private class StdSequenceContainerPush extends TaintFunction { */ private class StdSequenceContainerFrontBack extends TaintFunction { StdSequenceContainerFrontBack() { - this.hasQualifiedName("std", ["array", "vector", "deque", "list", "forward_list"], "front") or - this.hasQualifiedName("std", ["array", "vector", "deque", "list"], "back") + this.getClassAndName(["front", "back"]) instanceof Array or + this.getClassAndName(["front", "back"]) instanceof Deque or + this.getClassAndName("front") instanceof ForwardList or + this.getClassAndName(["front", "back"]) instanceof List or + this.getClassAndName(["front", "back"]) instanceof Vector } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -101,8 +147,10 @@ private class StdSequenceContainerFrontBack extends TaintFunction { */ private class StdSequenceContainerInsert extends TaintFunction { StdSequenceContainerInsert() { - this.hasQualifiedName("std", ["vector", "deque", "list"], "insert") or - this.hasQualifiedName("std", "forward_list", "insert_after") + this.getClassAndName("insert") instanceof Deque or + this.getClassAndName("insert") instanceof List or + this.getClassAndName("insert") instanceof Vector or + this.getClassAndName("insert_after") instanceof ForwardList } /** @@ -138,7 +186,10 @@ private class StdSequenceContainerInsert extends TaintFunction { */ private class StdSequenceContainerAssign extends TaintFunction { StdSequenceContainerAssign() { - this.hasQualifiedName("std", ["vector", "deque", "list", "forward_list"], "assign") + this.getClassAndName("assign") instanceof Deque or + this.getClassAndName("assign") instanceof ForwardList or + this.getClassAndName("assign") instanceof List or + this.getClassAndName("assign") instanceof Vector } /** @@ -170,7 +221,9 @@ private class StdSequenceContainerAssign extends TaintFunction { */ private class StdSequenceContainerAt extends TaintFunction { StdSequenceContainerAt() { - this.hasQualifiedName("std", ["vector", "array", "deque"], ["at", "operator[]"]) + this.getClassAndName(["at", "operator[]"]) instanceof Array or + this.getClassAndName(["at", "operator[]"]) instanceof Deque or + this.getClassAndName(["at", "operator[]"]) instanceof Vector } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -188,12 +241,12 @@ private class StdSequenceContainerAt extends TaintFunction { * The standard vector `emplace` function. */ class StdVectorEmplace extends TaintFunction { - StdVectorEmplace() { this.hasQualifiedName("std", "vector", "emplace") } + StdVectorEmplace() { this.getClassAndName("emplace") instanceof Vector } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter except the position iterator to qualifier and return value // (here we assume taint flow from any constructor parameter to the constructed object) - input.isParameter([1 .. getNumberOfParameters() - 1]) and + input.isParameterDeref([1 .. getNumberOfParameters() - 1]) and ( output.isQualifierObject() or output.isReturnValue() @@ -205,12 +258,12 @@ class StdVectorEmplace extends TaintFunction { * The standard vector `emplace_back` function. */ class StdVectorEmplaceBack extends TaintFunction { - StdVectorEmplaceBack() { this.hasQualifiedName("std", "vector", "emplace_back") } + StdVectorEmplaceBack() { this.getClassAndName("emplace_back") instanceof Vector } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter to qualifier // (here we assume taint flow from any constructor parameter to the constructed object) - input.isParameter([0 .. getNumberOfParameters() - 1]) and + input.isParameterDeref([0 .. getNumberOfParameters() - 1]) and output.isQualifierObject() } } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll index f261038735d..aecd98981e8 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll @@ -5,14 +5,18 @@ import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.Iterator +/** + * The `std::map` and `std::unordered_map` template classes. + */ +private class MapOrUnorderedMap extends Class { + MapOrUnorderedMap() { this.hasQualifiedName(["std", "bsl"], ["map", "unordered_map"]) } +} + /** * Additional model for map constructors using iterator inputs. */ private class StdMapConstructor extends Constructor, TaintFunction { - StdMapConstructor() { - this.hasQualifiedName("std", "map", "map") or - this.hasQualifiedName("std", "unordered_map", "unordered_map") - } + StdMapConstructor() { this.getDeclaringType() instanceof MapOrUnorderedMap } /** * Gets the index of a parameter to this function that is an iterator. @@ -37,7 +41,7 @@ private class StdMapConstructor extends Constructor, TaintFunction { */ private class StdMapInsert extends TaintFunction { StdMapInsert() { - this.hasQualifiedName("std", ["map", "unordered_map"], ["insert", "insert_or_assign"]) + this.getClassAndName(["insert", "insert_or_assign"]) instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -55,9 +59,7 @@ private class StdMapInsert extends TaintFunction { * The standard map `emplace` and `emplace_hint` functions. */ private class StdMapEmplace extends TaintFunction { - StdMapEmplace() { - this.hasQualifiedName("std", ["map", "unordered_map"], ["emplace", "emplace_hint"]) - } + StdMapEmplace() { this.getClassAndName(["emplace", "emplace_hint"]) instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from the last parameter (which may be the value part used to @@ -79,7 +81,7 @@ private class StdMapEmplace extends TaintFunction { * The standard map `try_emplace` function. */ private class StdMapTryEmplace extends TaintFunction { - StdMapTryEmplace() { this.hasQualifiedName("std", ["map", "unordered_map"], "try_emplace") } + StdMapTryEmplace() { this.getClassAndName("try_emplace") instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter apart from the key to qualifier and return value @@ -106,7 +108,7 @@ private class StdMapTryEmplace extends TaintFunction { * The standard map `merge` function. */ private class StdMapMerge extends TaintFunction { - StdMapMerge() { this.hasQualifiedName("std", ["map", "unordered_map"], "merge") } + StdMapMerge() { this.getClassAndName("merge") instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // container1.merge(container2) @@ -119,7 +121,7 @@ private class StdMapMerge extends TaintFunction { * The standard map functions `at` and `operator[]`. */ private class StdMapAt extends TaintFunction { - StdMapAt() { this.hasQualifiedName("std", ["map", "unordered_map"], ["at", "operator[]"]) } + StdMapAt() { this.getClassAndName(["at", "operator[]"]) instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to referenced return value @@ -136,7 +138,7 @@ private class StdMapAt extends TaintFunction { * The standard map `find` function. */ private class StdMapFind extends TaintFunction { - StdMapFind() { this.hasQualifiedName("std", ["map", "unordered_map"], "find") } + StdMapFind() { this.getClassAndName("find") instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and @@ -148,7 +150,7 @@ private class StdMapFind extends TaintFunction { * The standard map `erase` function. */ private class StdMapErase extends TaintFunction { - StdMapErase() { this.hasQualifiedName("std", ["map", "unordered_map"], "erase") } + StdMapErase() { this.getClassAndName("erase") instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to iterator return value @@ -163,8 +165,7 @@ private class StdMapErase extends TaintFunction { */ private class StdMapEqualRange extends TaintFunction { StdMapEqualRange() { - this.hasQualifiedName("std", ["map", "unordered_map"], - ["lower_bound", "upper_bound", "equal_range"]) + this.getClassAndName(["lower_bound", "upper_bound", "equal_range"]) instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll index 41867e71acc..755f6a48520 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll @@ -7,10 +7,16 @@ import semmle.code.cpp.models.interfaces.Taint /** * An instantiation of `std::pair`. */ -class StdPairClass extends ClassTemplateInstantiation { - StdPairClass() { getTemplate().hasQualifiedName("std", "pair") } +private class StdPair extends ClassTemplateInstantiation { + StdPair() { this.hasQualifiedName(["std", "bsl"], "pair") } } +/** + * DEPRECATED: This is now called `StdPair` and is a private part of the + * library implementation. + */ +deprecated class StdPairClass = StdPair; + /** * Any of the single-parameter constructors of `std::pair` that takes a reference to an * instantiation of `std::pair`. These constructors allow conversion between pair types when the @@ -18,9 +24,9 @@ class StdPairClass extends ClassTemplateInstantiation { */ class StdPairCopyishConstructor extends Constructor, TaintFunction { StdPairCopyishConstructor() { - this.getDeclaringType() instanceof StdPairClass and + this.getDeclaringType() instanceof StdPair and this.getNumberOfParameters() = 1 and - this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdPairClass + this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdPair } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -38,7 +44,7 @@ class StdPairCopyishConstructor extends Constructor, TaintFunction { * Additional model for `std::pair` constructors. */ private class StdPairConstructor extends Constructor, TaintFunction { - StdPairConstructor() { this.hasQualifiedName("std", "pair", "pair") } + StdPairConstructor() { this.getDeclaringType() instanceof StdPair } /** * Gets the index of a parameter to this function that is a reference to diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll index 9fac9ae75f8..d2e9892abcb 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll @@ -5,14 +5,18 @@ import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.Iterator +/** + * An instantiation of `std::set` or `std::unordered_set`. + */ +private class StdSet extends ClassTemplateInstantiation { + StdSet() { this.hasQualifiedName(["std", "bsl"], ["set", "unordered_set"]) } +} + /** * Additional model for set constructors using iterator inputs. */ private class StdSetConstructor extends Constructor, TaintFunction { - StdSetConstructor() { - this.hasQualifiedName("std", "set", "set") or - this.hasQualifiedName("std", "unordered_set", "unordered_set") - } + StdSetConstructor() { this.getDeclaringType() instanceof StdSet } /** * Gets the index of a parameter to this function that is an iterator. @@ -36,7 +40,7 @@ private class StdSetConstructor extends Constructor, TaintFunction { * The standard set `insert` and `insert_or_assign` functions. */ private class StdSetInsert extends TaintFunction { - StdSetInsert() { this.hasQualifiedName("std", ["set", "unordered_set"], "insert") } + StdSetInsert() { this.getClassAndName("insert") instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from last parameter to qualifier and return value @@ -53,9 +57,7 @@ private class StdSetInsert extends TaintFunction { * The standard set `emplace` and `emplace_hint` functions. */ private class StdSetEmplace extends TaintFunction { - StdSetEmplace() { - this.hasQualifiedName("std", ["set", "unordered_set"], ["emplace", "emplace_hint"]) - } + StdSetEmplace() { this.getClassAndName(["emplace", "emplace_hint"]) instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter to qualifier and return value @@ -76,7 +78,7 @@ private class StdSetEmplace extends TaintFunction { * The standard set `merge` function. */ private class StdSetMerge extends TaintFunction { - StdSetMerge() { this.hasQualifiedName("std", ["set", "unordered_set"], "merge") } + StdSetMerge() { this.getClassAndName("merge") instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // container1.merge(container2) @@ -89,7 +91,7 @@ private class StdSetMerge extends TaintFunction { * The standard set `find` function. */ private class StdSetFind extends TaintFunction { - StdSetFind() { this.hasQualifiedName("std", ["set", "unordered_set"], "find") } + StdSetFind() { this.getClassAndName("find") instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and @@ -101,7 +103,7 @@ private class StdSetFind extends TaintFunction { * The standard set `erase` function. */ private class StdSetErase extends TaintFunction { - StdSetErase() { this.hasQualifiedName("std", ["set", "unordered_set"], "erase") } + StdSetErase() { this.getClassAndName("erase") instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to iterator return value @@ -116,8 +118,7 @@ private class StdSetErase extends TaintFunction { */ private class StdSetEqualRange extends TaintFunction { StdSetEqualRange() { - this.hasQualifiedName("std", ["set", "unordered_set"], - ["lower_bound", "upper_bound", "equal_range"]) + this.getClassAndName(["lower_bound", "upper_bound", "equal_range"]) instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll index 8fd2f79cfdd..73a0f6edf26 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -12,7 +12,7 @@ import semmle.code.cpp.models.interfaces.DataFlow * The `std::basic_string` template class instantiations. */ private class StdBasicString extends ClassTemplateInstantiation { - StdBasicString() { this.hasQualifiedName("std", "basic_string") } + StdBasicString() { this.hasQualifiedName(["std", "bsl"], "basic_string") } } /** @@ -127,7 +127,7 @@ private class StdStringFrontBack extends TaintFunction { */ private class StdStringPlus extends TaintFunction { StdStringPlus() { - this.hasQualifiedName("std", "operator+") and + this.hasQualifiedName(["std", "bsl"], "operator+") and this.getUnspecifiedType() instanceof StdBasicString } @@ -252,13 +252,6 @@ private class StdStringSubstr extends TaintFunction { } } -/** - * The `std::basic_stringstream` template class instantiations. - */ -private class StdBasicStringStream extends ClassTemplateInstantiation { - StdBasicStringStream() { this.hasQualifiedName("std", "basic_stringstream") } -} - /** * The `std::string` functions `at` and `operator[]`. */ @@ -280,7 +273,7 @@ private class StdStringAt extends TaintFunction { * The `std::basic_istream` template class instantiations. */ private class StdBasicIStream extends ClassTemplateInstantiation { - StdBasicIStream() { this.hasQualifiedName("std", "basic_istream") } + StdBasicIStream() { this.hasQualifiedName(["std", "bsl"], "basic_istream") } } /** @@ -293,6 +286,9 @@ private class StdIStreamIn extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -311,7 +307,7 @@ private class StdIStreamIn extends DataFlowFunction, TaintFunction { */ private class StdIStreamInNonMember extends DataFlowFunction, TaintFunction { StdIStreamInNonMember() { - this.hasQualifiedName("std", "operator>>") and + this.hasQualifiedName(["std", "bsl"], "operator>>") and this.getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdBasicIStream } @@ -319,6 +315,9 @@ private class StdIStreamInNonMember extends DataFlowFunction, TaintFunction { // flow from first parameter to return value input.isParameter(0) and output.isReturnValue() + or + input.isParameterDeref(0) and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -361,6 +360,9 @@ private class StdIStreamRead extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -397,6 +399,9 @@ private class StdIStreamPutBack extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -430,6 +435,9 @@ private class StdIStreamGetLine extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -447,12 +455,15 @@ private class StdIStreamGetLine extends DataFlowFunction, TaintFunction { * The (non-member) function `std::getline`. */ private class StdGetLine extends DataFlowFunction, TaintFunction { - StdGetLine() { this.hasQualifiedName("std", "getline") } + StdGetLine() { this.hasQualifiedName(["std", "bsl"], "getline") } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // flow from first parameter to return value input.isParameter(0) and output.isReturnValue() + or + input.isParameterDeref(0) and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -470,7 +481,7 @@ private class StdGetLine extends DataFlowFunction, TaintFunction { * The `std::basic_ostream` template class instantiations. */ private class StdBasicOStream extends ClassTemplateInstantiation { - StdBasicOStream() { this.hasQualifiedName("std", "basic_ostream") } + StdBasicOStream() { this.hasQualifiedName(["std", "bsl"], "basic_ostream") } } /** @@ -486,6 +497,9 @@ private class StdOStreamOut extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -514,7 +528,7 @@ private class StdOStreamOut extends DataFlowFunction, TaintFunction { */ private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { StdOStreamOutNonMember() { - this.hasQualifiedName("std", "operator<<") and + this.hasQualifiedName(["std", "bsl"], "operator<<") and this.getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdBasicOStream } @@ -522,6 +536,9 @@ private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { // flow from first parameter to return value input.isParameter(0) and output.isReturnValue() + or + input.isParameterDeref(0) and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -539,6 +556,13 @@ private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { } } +/** + * The `std::basic_stringstream` template class instantiations. + */ +private class StdBasicStringStream extends ClassTemplateInstantiation { + StdBasicStringStream() { this.hasQualifiedName(["std", "bsl"], "basic_stringstream") } +} + /** * Additional model for `std::stringstream` constructors that take a string * input parameter. @@ -585,7 +609,7 @@ private class StdStringStreamStr extends TaintFunction { * The `std::basic_ios` template class instantiations. */ private class StdBasicIOS extends ClassTemplateInstantiation { - StdBasicIOS() { this.hasQualifiedName("std", "basic_ios") } + StdBasicIOS() { this.hasQualifiedName(["std", "bsl"], "basic_ios") } } /** @@ -605,6 +629,9 @@ private class StdStreamFunction extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index f31d688d010..ee9af547582 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.SideEffect */ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction { StrcatFunction() { - this.hasGlobalOrStdName([ + this.hasGlobalOrStdOrBslName([ "strcat", // strcat(dst, src) "strncat", // strncat(dst, src, max_amount) "wcscat", // wcscat(dst, src) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll index e01d364c5a7..432fbf999ef 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll @@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.SideEffect */ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction { StrcpyFunction() { - this.hasGlobalOrStdName([ + this.hasGlobalOrStdOrBslName([ "strcpy", // strcpy(dst, src) "wcscpy", // wcscpy(dst, src) "strncpy", // strncpy(dst, src, max_amount) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll index 659494ef2dd..f2cb6498819 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll @@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.Taint */ private class Strtok extends ArrayFunction, AliasFunction, TaintFunction, SideEffectFunction { Strtok() { - this.hasGlobalOrStdName("strtok") or + this.hasGlobalOrStdOrBslName("strtok") or this.hasGlobalName(["strtok_r", "_strtok_l", "wcstok", "_wcstok_l", "_mbstok", "_mbstok_l"]) } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Swap.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Swap.qll index 285d20b8660..b79f7afe5d9 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Swap.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Swap.qll @@ -9,7 +9,7 @@ import semmle.code.cpp.models.interfaces.Alias * ``` */ private class Swap extends DataFlowFunction { - Swap() { this.hasQualifiedName("std", "swap") } + Swap() { this.hasQualifiedName(["std", "bsl"], "swap") } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input.isParameterDeref(0) and diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll index c0c95b38756..8c80377c8ec 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll @@ -1,9 +1,9 @@ /** - * Provides a class for modeling functions that return data from potentially untrusted sources. To use - * this QL library, create a QL class extending `DataFlowFunction` with a + * Provides classes for modeling functions that return data from (or send data to) potentially untrusted + * sources. To use this QL library, create a QL class extending `DataFlowFunction` with a * characteristic predicate that selects the function or set of functions you * are modeling. Within that class, override the predicates provided by - * `RemoteFlowFunction` to match the flow within that function. + * `RemoteFlowSourceFunction` or `RemoteFlowSinkFunction` to match the flow within that function. */ import cpp @@ -13,19 +13,42 @@ import semmle.code.cpp.models.Models /** * A library function that returns data that may be read from a network connection. */ -abstract class RemoteFlowFunction extends Function { +abstract class RemoteFlowSourceFunction extends Function { /** * Holds if remote data described by `description` flows from `output` of a call to this function. */ abstract predicate hasRemoteFlowSource(FunctionOutput output, string description); } +/** + * DEPRECATED: Use `RemoteFlowSourceFunction` instead. + * + * A library function that returns data that may be read from a network connection. + */ +deprecated class RemoteFlowFunction = RemoteFlowSourceFunction; + /** * A library function that returns data that is directly controlled by a user. */ -abstract class LocalFlowFunction extends Function { +abstract class LocalFlowSourceFunction extends Function { /** * Holds if data described by `description` flows from `output` of a call to this function. */ abstract predicate hasLocalFlowSource(FunctionOutput output, string description); } + +/** + * DEPRECATED: Use `LocalFlowSourceFunction` instead. + * + * A library function that returns data that is directly controlled by a user. + */ +deprecated class LocalFlowFunction = LocalFlowSourceFunction; + +/** A library function that sends data over a network connection. */ +abstract class RemoteFlowSinkFunction extends Function { + /** + * Holds if data described by `description` flows into `input` to a call to this function, and is then + * send over a network connection. + */ + abstract predicate hasRemoteFlowSink(FunctionInput input, string description); +} diff --git a/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll index c8bad67352b..b080651951f 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll @@ -23,7 +23,7 @@ private class RemoteReturnSource extends RemoteFlowSource { string sourceType; RemoteReturnSource() { - exists(RemoteFlowFunction func, CallInstruction instr, FunctionOutput output | + exists(RemoteFlowSourceFunction func, CallInstruction instr, FunctionOutput output | asInstruction() = instr and instr.getStaticCallTarget() = func and func.hasRemoteFlowSource(output, sourceType) and @@ -42,7 +42,7 @@ private class RemoteParameterSource extends RemoteFlowSource { string sourceType; RemoteParameterSource() { - exists(RemoteFlowFunction func, WriteSideEffectInstruction instr, FunctionOutput output | + exists(RemoteFlowSourceFunction func, WriteSideEffectInstruction instr, FunctionOutput output | asInstruction() = instr and instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() = func and func.hasRemoteFlowSource(output, sourceType) and @@ -57,7 +57,7 @@ private class LocalReturnSource extends LocalFlowSource { string sourceType; LocalReturnSource() { - exists(LocalFlowFunction func, CallInstruction instr, FunctionOutput output | + exists(LocalFlowSourceFunction func, CallInstruction instr, FunctionOutput output | asInstruction() = instr and instr.getStaticCallTarget() = func and func.hasLocalFlowSource(output, sourceType) and @@ -76,7 +76,7 @@ private class LocalParameterSource extends LocalFlowSource { string sourceType; LocalParameterSource() { - exists(LocalFlowFunction func, WriteSideEffectInstruction instr, FunctionOutput output | + exists(LocalFlowSourceFunction func, WriteSideEffectInstruction instr, FunctionOutput output | asInstruction() = instr and instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() = func and func.hasLocalFlowSource(output, sourceType) and @@ -98,3 +98,31 @@ private class ArgvSource extends LocalFlowSource { override string getSourceType() { result = "a command-line argument" } } + +/** A remote data flow sink. */ +abstract class RemoteFlowSink extends DataFlow::Node { + /** Gets a string that describes the type of this flow sink. */ + abstract string getSinkType(); +} + +private class RemoteParameterSink extends RemoteFlowSink { + string sourceType; + + RemoteParameterSink() { + exists(RemoteFlowSinkFunction func, FunctionInput input, CallInstruction call, int index | + func.hasRemoteFlowSink(input, sourceType) and call.getStaticCallTarget() = func + | + exists(ReadSideEffectInstruction read | + call = read.getPrimaryInstruction() and + read.getIndex() = index and + this.asOperand() = read.getSideEffectOperand() and + input.isParameterDerefOrQualifierObject(index) + ) + or + input.isParameterOrQualifierAddress(index) and + this.asOperand() = call.getArgumentOperand(index) + ) + } + + override string getSinkType() { result = sourceType } +} diff --git a/cpp/ql/src/semmle/code/cpp/security/Security.qll b/cpp/ql/src/semmle/code/cpp/security/Security.qll index 16dc89d9a6e..d39c13a25a0 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Security.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Security.qll @@ -6,6 +6,7 @@ import semmle.code.cpp.exprs.Expr import semmle.code.cpp.commons.Environment import semmle.code.cpp.security.SecurityOptions +import semmle.code.cpp.models.interfaces.FlowSource /** * Extend this class to customize the security queries for @@ -59,14 +60,14 @@ class SecurityOptions extends string { or functionCall.getTarget().hasGlobalName(fname) and exists(functionCall.getArgument(arg)) and - ( - fname = ["read", "recv", "recvmsg"] and arg = 1 - or - fname = "getaddrinfo" and arg = 3 - or - fname = "recvfrom" and - (arg = 1 or arg = 4 or arg = 5) - ) + fname = "getaddrinfo" and + arg = 3 + ) + or + exists(RemoteFlowSourceFunction remote, FunctionOutput output | + functionCall.getTarget() = remote and + output.isParameterDerefOrQualifierObject(arg) and + remote.hasRemoteFlowSource(output, _) ) } @@ -81,6 +82,12 @@ class SecurityOptions extends string { userInputReturn(fname) ) ) + or + exists(RemoteFlowSourceFunction remote, FunctionOutput output | + functionCall.getTarget() = remote and + (output.isReturnValue() or output.isReturnValueDeref()) and + remote.hasRemoteFlowSource(output, _) + ) } /** diff --git a/cpp/ql/test/README.md b/cpp/ql/test/README.md index 417d7bbe19d..9de2b10e1b8 100644 --- a/cpp/ql/test/README.md +++ b/cpp/ql/test/README.md @@ -1,6 +1,6 @@ # C/C++ CodeQL tests -This document provides additional information about the C/C++ CodeQL Tests located in `cpp/ql/test`. See [Contributing to CodeQL](/CONTRIBUTING.md) for general information about contributing to this repository. +This document provides additional information about the C/C++ CodeQL tests located in `cpp/ql/test`. The principles under "Copying code", below, also apply to any other C/C++ code in this repository, such as examples linked from query `.qhelp` files in `cpp/ql/src`. For more general information about contributing to this repository, see [Contributing to CodeQL](/CONTRIBUTING.md). The tests can be run through Visual Studio Code. Advanced users may also use the `codeql test run` command. diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected new file mode 100644 index 00000000000..80e82cff212 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected @@ -0,0 +1,5 @@ +| test.cpp:30:15:30:26 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:38:9:38:20 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:50:13:50:38 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:51:22:51:47 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:53:18:53:43 | call to operator new[] | memory allocation error check is incorrect or missing | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.qlref new file mode 100644 index 00000000000..fc3252ef122 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp new file mode 100644 index 00000000000..e4aa8cf2976 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp @@ -0,0 +1,97 @@ +#define NULL ((void*)0) +class exception {}; + +namespace std{ + struct nothrow_t {}; + typedef unsigned long size_t; + class bad_alloc{ + const char* what() const throw(); + }; + extern const std::nothrow_t nothrow; +} + +using namespace std; + +void* operator new(std::size_t _Size); +void* operator new[](std::size_t _Size); +void* operator new( std::size_t count, const std::nothrow_t& tag ); +void* operator new[]( std::size_t count, const std::nothrow_t& tag ); + +void badNew_0_0() +{ + while (true) { + new int[100]; // BAD [NOT DETECTED] + if(!(new int[100])) // BAD [NOT DETECTED] + return; + } +} +void badNew_0_1() +{ + int * i = new int[100]; // BAD + if(i == 0) + return; + if(!i) + return; + if(i == NULL) + return; + int * j; + j = new int[100]; // BAD + if(j == 0) + return; + if(!j) + return; + if(j == NULL) + return; +} +void badNew_1_0() +{ + try { + while (true) { + new(std::nothrow) int[100]; // BAD + int* p = new(std::nothrow) int[100]; // BAD + int* p1; + p1 = new(std::nothrow) int[100]; // BAD + } + } catch (const exception &){//const std::bad_alloc& e) { +// std::cout << e.what() << '\n'; + } +} +void badNew_1_1() +{ + while (true) { + int* p = new(std::nothrow) int[100]; // BAD [NOT DETECTED] + new(std::nothrow) int[100]; // BAD [NOT DETECTED] + } +} + +void goodNew_0_0() +{ + try { + while (true) { + new int[100]; // GOOD + } + } catch (const exception &){//const std::bad_alloc& e) { +// std::cout << e.what() << '\n'; + } +} + +void goodNew_1_0() +{ + while (true) { + int* p = new(std::nothrow) int[100]; // GOOD + if (p == nullptr) { +// std::cout << "Allocation returned nullptr\n"; + break; + } + int* p1; + p1 = new(std::nothrow) int[100]; // GOOD + if (p1 == nullptr) { +// std::cout << "Allocation returned nullptr\n"; + break; + } + if (new(std::nothrow) int[100] == nullptr) { // GOOD +// std::cout << "Allocation returned nullptr\n"; + break; + } + } +} diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected new file mode 100644 index 00000000000..103afd8ffd9 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected @@ -0,0 +1,9 @@ +| test.c:42:3:42:24 | ... = ... | potential unsafe or redundant assignment. | +| test.c:43:3:43:40 | ... = ... | potential unsafe or redundant assignment. | +| test.c:44:3:44:40 | ... = ... | potential unsafe or redundant assignment. | +| test.c:45:3:45:44 | ... = ... | potential unsafe or redundant assignment. | +| test.c:46:3:46:44 | ... = ... | potential unsafe or redundant assignment. | +| test.c:47:3:47:48 | ... = ... | potential unsafe or redundant assignment. | +| test.c:48:3:48:48 | ... = ... | potential unsafe or redundant assignment. | +| test.c:49:3:49:50 | ... = ... | potential unsafe or redundant assignment. | +| test.c:50:3:50:50 | ... = ... | potential unsafe or redundant assignment. | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref new file mode 100644 index 00000000000..6ba005d087a --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c index c3347e1fd65..d986bb3b13c 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c @@ -26,3 +26,48 @@ void workFunction_2_1(char *s) { strncat(buf, s, len-strlen(buf)-1); // GOOD strncat(buf, s, len-strlen(buf)); // GOOD } + +struct buffers +{ + unsigned char buff1[50]; + unsigned char *buff2; +} globalBuff1,*globalBuff2,globalBuff1_c,*globalBuff2_c; + + +void badFunc0(){ + unsigned char buff1[12]; + struct buffers buffAll; + struct buffers * buffAll1; + + buff1[strlen(buff1)]=0; // BAD + buffAll.buff1[strlen(buffAll.buff1)]=0; // BAD + buffAll.buff2[strlen(buffAll.buff2)]=0; // BAD + buffAll1->buff1[strlen(buffAll1->buff1)]=0; // BAD + buffAll1->buff2[strlen(buffAll1->buff2)]=0; // BAD + globalBuff1.buff1[strlen(globalBuff1.buff1)]=0; // BAD + globalBuff1.buff2[strlen(globalBuff1.buff2)]=0; // BAD + globalBuff2->buff1[strlen(globalBuff2->buff1)]=0; // BAD + globalBuff2->buff2[strlen(globalBuff2->buff2)]=0; // BAD +} +void noBadFunc0(){ + unsigned char buff1[12],buff1_c[12]; + struct buffers buffAll,buffAll_c; + struct buffers * buffAll1,*buffAll1_c; + + buff1[strlen(buff1_c)]=0; // GOOD + buffAll.buff1[strlen(buffAll_c.buff1)]=0; // GOOD + buffAll.buff2[strlen(buffAll.buff1)]=0; // GOOD + buffAll1->buff1[strlen(buffAll1_c->buff1)]=0; // GOOD + buffAll1->buff2[strlen(buffAll1->buff1)]=0; // GOOD + globalBuff1.buff1[strlen(globalBuff1_c.buff1)]=0; // GOOD + globalBuff1.buff2[strlen(globalBuff1.buff1)]=0; // GOOD + globalBuff2->buff1[strlen(globalBuff2_c->buff1)]=0; // GOOD + globalBuff2->buff2[strlen(globalBuff2->buff1)]=0; // GOOD +} +void goodFunc0(){ + unsigned char buffer[12]; + int i; + for(i = 0; i < 6; i++) + buffer[i] = 'A'; + buffer[i]=0; +} diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp index b24efc1dc8e..020a2f90b9e 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp @@ -216,3 +216,46 @@ void test_pointers2() sink(ptr4); // clean sink(*ptr4); // $ MISSING: ast,ir } + +// --- recv --- + +int recv(int s, char* buf, int len, int flags); + +void test_recv() { + char buffer[1024]; + recv(0, buffer, sizeof(buffer), 0); + sink(buffer); // $ ast,ir + sink(*buffer); // $ ast,ir +} + +// --- send and related functions --- + +int send(int, const void*, int, int); + +void test_send(char* buffer, int length) { + send(0, buffer, length, 0); // $ remote +} + +struct iovec { + void *iov_base; + unsigned iov_len; +}; + +int readv(int, const struct iovec*, int); +int writev(int, const struct iovec*, int); + +void sink(const iovec* iovs); +void sink(iovec); + +int test_readv_and_writev(iovec* iovs) { + readv(0, iovs, 16); + sink(iovs); // $ast,ir + sink(iovs[0]); // $ast MISSING: ir + sink(*iovs); // $ast MISSING: ir + + char* p = (char*)iovs[1].iov_base; + sink(p); // $ MISSING: ast,ir + sink(*p); // $ MISSING: ast,ir + + writev(0, iovs, 16); // $ remote +} diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.ql b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.ql new file mode 100644 index 00000000000..4fbbe8fa3bf --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.ql @@ -0,0 +1,20 @@ +/** This tests that we are able to detect remote flow sinks. */ + +import cpp +import TestUtilities.InlineExpectationsTest +import semmle.code.cpp.security.FlowSources + +class RemoteFlowSinkTest extends InlineExpectationsTest { + RemoteFlowSinkTest() { this = "RemoteFlowSinkTest" } + + override string getARelevantTag() { result = "remote" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "remote" and + value = "" and + exists(RemoteFlowSink node | + location = node.getLocation() and + element = node.toString() + ) + } +} diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index b9f6f717c80..fc6c97aa2a6 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -26,21 +26,60 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| dispatch.cpp:15:8:15:8 | Top output argument | PostUpdateNode should have one pre-update node but has 0. | -| dispatch.cpp:21:8:21:8 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | -| dispatch.cpp:60:18:60:29 | Bottom output argument | PostUpdateNode should have one pre-update node but has 0. | -| dispatch.cpp:61:18:61:29 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | -| dispatch.cpp:65:10:65:21 | Bottom output argument | PostUpdateNode should have one pre-update node but has 0. | -| test.cpp:384:10:384:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | -| test.cpp:391:10:391:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | -| test.cpp:400:10:400:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | -| test.cpp:407:10:407:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| test.cpp:384:10:384:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | -| test.cpp:391:10:391:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | -| test.cpp:400:10:400:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | -| test.cpp:407:10:407:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | +| BarrierGuard.cpp:49:3:49:17 | Chi | PostUpdateNode should not be the target of local flow. | +| BarrierGuard.cpp:60:3:60:18 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:28:3:28:34 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:34:22:34:27 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:34:32:34:37 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:39:32:39:37 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:39:42:39:47 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:43:35:43:40 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:43:51:43:51 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:49:25:49:30 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:49:35:49:40 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:50:3:50:26 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:17:19:17:22 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:17:21:17:21 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:24:2:24:30 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:24:13:24:30 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:26:2:26:25 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:13:12:13:12 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:13:15:13:15 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:28:10:31:2 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:28:10:31:2 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:43:3:43:14 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:11:5:11:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:20:5:20:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:22:7:22:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:24:7:24:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:29:5:29:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:31:7:31:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:39:7:39:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:44:5:44:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:46:7:46:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:48:7:48:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:75:5:75:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:83:5:83:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:87:7:87:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:89:7:89:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:94:5:94:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:96:7:96:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:104:7:104:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:109:5:109:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:113:7:113:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:115:7:115:17 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:91:3:91:18 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:115:3:115:17 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:120:3:120:10 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:125:3:125:11 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:359:5:359:20 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:373:5:373:20 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:465:3:465:15 | Chi | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp index 774ecddeab2..f59552aa2dd 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp @@ -362,7 +362,7 @@ class FlowThroughFields { int f() { sink(field); // tainted or clean? Not sure. taintField(); - sink(field); // $ ast,ir + sink(field); // $ ast MISSING: ir } int calledAfterTaint() { diff --git a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp index 833e85600a6..500bbed53a9 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp @@ -204,32 +204,4 @@ void deep_member_field_arrow(S2 *ps2) { void deep_member_field_arrow_different_fields(S2 *ps2) { taint_a_ptr(&ps2->s.m1); sink(ps2->s.m2); -} - -void test_deep_struct_fields() { - S2 s2; - s2.s.m1 = user_input(); - S s = s2.s; - sink(s.m1); // $ ast,ir -} - -void test_deep_struct_fields_no_flow() { - S2 s2; - s2.s.m1 = user_input(); - S s = s2.s; - sink(s.m2); -} - -void test_deep_struct_fields_taint_through_call() { - S2 s2; - taint_a_ptr(&s2.s.m1); - S s = s2.s; - sink(s.m1); // $ ast,ir -} - -void test_deep_struct_fields_taint_through_call_no_flow() { - S2 s2; - taint_a_ptr(&s2.s.m1); - S s = s2.s; - sink(s.m2); } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index 46abcd62c07..8e84d39be3b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -1,4 +1,4 @@ -void sink(void *o); void sink(const char *o); +void sink(void *o); void *user_input(void); struct S { @@ -135,13 +135,3 @@ void test_outer_with_ref(Outer *pouter) { sink(pouter->inner_ptr->a); // $ ast MISSING: ir sink(pouter->a); // $ ast,ir } - -void taint_a_ptr(const char **pa) { - *pa = (char*)user_input(); -} - -void test_const_char_ref() { - const char* s; - taint_a_ptr(&s); - sink(s); // $ ast ir=140:9 ir=140:16 -} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index 500faa38eb1..c6528723d22 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -89,10 +89,6 @@ postWithInFlow | aliasing.cpp:194:21:194:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:200:23:200:24 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:205:23:205:24 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:211:8:211:9 | m1 [post update] | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:218:8:218:9 | m1 [post update] | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:225:21:225:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:232:21:232:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | | arrays.cpp:6:3:6:5 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | | arrays.cpp:6:3:6:8 | access to array [post update] | PostUpdateNode should not be the target of local flow. | | arrays.cpp:15:3:15:10 | * ... [post update] | PostUpdateNode should not be the target of local flow. | @@ -123,9 +119,6 @@ postWithInFlow | by_reference.cpp:108:24:108:24 | a [inner post update] | PostUpdateNode should not be the target of local flow. | | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | | by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:140:3:140:5 | * ... [post update] | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:140:4:140:5 | pa [inner post update] | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:145:16:145:16 | s [inner post update] | PostUpdateNode should not be the target of local flow. | | complex.cpp:11:22:11:23 | a_ [post update] | PostUpdateNode should not be the target of local flow. | | complex.cpp:12:22:12:23 | b_ [post update] | PostUpdateNode should not be the target of local flow. | | conflated.cpp:10:3:10:7 | * ... [post update] | PostUpdateNode should not be the target of local flow. | @@ -159,6 +152,5 @@ postWithInFlow | simple.cpp:65:7:65:7 | i [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:83:12:83:13 | f1 [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. | -| simple.cpp:104:9:104:9 | i [post update] | PostUpdateNode should not be the target of local flow. | | struct_init.c:24:11:24:12 | ab [inner post update] | PostUpdateNode should not be the target of local flow. | | struct_init.c:36:17:36:24 | nestedAB [inner post update] | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 0a03ccef569..63d3b2c0f48 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -20,71 +20,145 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| A.cpp:9:9:9:9 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:14:9:14:9 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:31:14:31:21 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:38:7:38:8 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:39:7:39:8 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:41:15:41:21 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:47:12:47:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:54:12:54:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:55:12:55:19 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:57:11:57:24 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:57:17:57:23 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:62:13:62:19 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:64:21:64:28 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:71:13:71:19 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:73:25:73:32 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:89:15:89:21 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:99:14:99:21 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:116:12:116:19 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:126:12:126:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:130:12:130:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:142:14:142:20 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:143:25:143:31 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:150:12:150:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:151:12:151:24 | D output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:159:12:159:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:160:18:160:60 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:160:32:160:59 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:161:18:161:40 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:162:18:162:40 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | -| B.cpp:7:16:7:35 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| B.cpp:8:16:8:27 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| B.cpp:16:16:16:38 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| B.cpp:17:16:17:27 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| C.cpp:18:12:18:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:29:15:29:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:29:24:29:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:36:15:36:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:36:24:36:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:43:15:43:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:43:24:43:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:50:15:50:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:50:24:50:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:57:16:57:42 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:57:25:57:41 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:22:11:22:17 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:25:7:25:7 | Bar output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:48:9:48:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:49:9:49:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:50:9:50:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:51:9:51:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | -| conflated.cpp:59:20:59:39 | LinkedList output argument | PostUpdateNode should have one pre-update node but has 0. | -| constructors.cpp:34:11:34:26 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| constructors.cpp:35:11:35:26 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| constructors.cpp:36:11:36:37 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| constructors.cpp:37:11:37:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| realistic.cpp:54:16:54:47 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | -| realistic.cpp:60:16:60:18 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | -| simple.cpp:34:11:34:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| simple.cpp:35:11:35:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| simple.cpp:36:11:36:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| simple.cpp:37:11:37:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:92:5:92:22 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| realistic.cpp:54:16:54:47 | memcpy output argument | PostUpdateNode should not be the target of local flow. | -| realistic.cpp:60:16:60:18 | memcpy output argument | PostUpdateNode should not be the target of local flow. | +| A.cpp:25:7:25:17 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:27:22:27:32 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:98:12:98:18 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:100:5:100:13 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:142:7:142:20 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:143:7:143:31 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:183:7:183:20 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:184:7:184:23 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:6:15:6:24 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:15:15:15:27 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:35:7:35:22 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:36:7:36:22 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:46:7:46:21 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:22:12:22:21 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:22:12:22:21 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:24:5:24:25 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:24:16:24:25 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:9:21:9:28 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:11:29:11:36 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:16:21:16:27 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:18:29:18:35 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:28:15:28:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:35:15:35:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:42:15:42:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:49:15:49:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:56:15:56:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:57:5:57:42 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:9:3:9:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:13:3:13:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:17:3:17:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:21:12:21:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:21:15:21:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:22:12:22:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:22:15:22:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:23:12:23:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:23:15:23:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:35:12:35:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:35:15:35:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:37:3:37:24 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:40:12:40:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:40:15:40:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:42:3:42:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:47:12:47:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:47:15:47:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:49:3:49:25 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:52:12:52:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:52:15:52:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:54:3:54:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:59:12:59:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:59:15:59:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:60:3:60:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:70:19:70:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:70:22:70:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:72:3:72:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:77:19:77:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:77:22:77:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:79:3:79:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:84:19:84:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:84:22:84:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:86:3:86:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:91:19:91:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:91:22:91:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:92:3:92:23 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:98:3:98:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:106:3:106:20 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:111:15:111:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:147:15:147:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:175:15:175:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:181:15:181:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:187:15:187:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:194:15:194:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:200:15:200:24 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:205:15:205:24 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:5:18:5:23 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:5:21:5:21 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:6:3:6:23 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:14:18:14:23 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:14:21:14:21 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:15:3:15:25 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:36:3:36:37 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:12:5:12:16 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:16:5:16:19 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:84:3:84:25 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:88:3:88:24 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:92:3:92:20 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:96:3:96:19 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:102:21:102:39 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:104:15:104:22 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:106:21:106:41 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:108:15:108:24 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:122:21:122:38 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:124:15:124:21 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:126:21:126:40 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:128:15:128:23 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:11:22:11:27 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:12:22:12:27 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:14:26:14:26 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:14:33:14:33 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:22:11:22:17 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:25:7:25:7 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:42:16:42:16 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:43:16:43:16 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:53:12:53:12 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:54:12:54:12 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:55:12:55:12 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:56:12:56:12 | Chi | PostUpdateNode should not be the target of local flow. | +| conflated.cpp:45:39:45:42 | Chi | PostUpdateNode should not be the target of local flow. | +| conflated.cpp:53:3:53:27 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:20:24:20:29 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:21:24:21:29 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:23:28:23:28 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:23:35:23:35 | Chi | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:9:30:9:44 | Chi | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:12:49:12:64 | Chi | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:13:51:13:65 | Chi | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:39:12:39:95 | Chi | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:49:9:49:64 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:20:24:20:29 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:21:24:21:29 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:23:28:23:28 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:23:35:23:35 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:65:5:65:22 | Store | PostUpdateNode should not be the target of local flow. | +| simple.cpp:83:9:83:28 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:92:5:92:22 | Store | PostUpdateNode should not be the target of local flow. | +| struct_init.c:20:20:20:29 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:20:34:20:34 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:27:7:27:16 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:27:21:27:21 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:28:5:28:7 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:36:10:36:24 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:40:20:40:29 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:40:34:40:34 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:42:7:42:16 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:42:21:42:21 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:43:5:43:7 | Chi | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 0f25daa307d..c8b70a74b3a 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -4,62 +4,50 @@ edges | A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | set output argument [c] | | A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:28:57:30 | call to get | | A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] | -| A.cpp:98:12:98:18 | new | A.cpp:100:9:100:9 | a [post update] [a] | -| A.cpp:100:9:100:9 | a [post update] [a] | A.cpp:103:14:103:14 | *c [a] | -| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a [a] | -| A.cpp:107:16:107:16 | a [a] | A.cpp:107:16:107:16 | a | +| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Chi [a] | +| A.cpp:100:5:100:13 | Chi [a] | A.cpp:103:14:103:14 | *c [a] | +| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | | A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] | | A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] | -| A.cpp:126:5:126:5 | set output argument [c] | A.cpp:131:8:131:8 | f7 output argument [c] | | A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] | -| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:132:13:132:13 | c [c] | -| A.cpp:132:13:132:13 | c [c] | A.cpp:132:13:132:13 | c | +| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | +| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:10:142:10 | c [post update] [c] | A.cpp:142:7:142:20 | Chi [c] | -| A.cpp:142:10:142:10 | c [post update] [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:14:142:20 | new | A.cpp:142:10:142:10 | c [post update] [c] | +| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Chi [c] | | A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:143:13:143:13 | b [post update] [b] | A.cpp:143:7:143:31 | Chi [b] | -| A.cpp:143:25:143:31 | new | A.cpp:143:13:143:13 | b [post update] [b] | +| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Chi [b] | | A.cpp:150:12:150:18 | new | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:152:13:152:13 | b [b] | -| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:154:13:154:13 | c [c] | -| A.cpp:152:13:152:13 | b [b] | A.cpp:152:13:152:13 | b | -| A.cpp:154:13:154:13 | c [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | +| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:151:12:151:24 | Chi [b] | +| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | | C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:27:8:27:11 | *#this [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:27:8:27:11 | *#this [s3] | -| C.cpp:22:9:22:22 | s1 [post update] [s1] | C.cpp:24:5:24:25 | Chi [s1] | -| C.cpp:22:12:22:21 | new | C.cpp:22:9:22:22 | s1 [post update] [s1] | +| C.cpp:22:12:22:21 | Chi [s1] | C.cpp:24:5:24:25 | Chi [s1] | +| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Chi [s1] | | C.cpp:24:5:24:25 | Chi [s1] | C.cpp:18:12:18:18 | C output argument [s1] | | C.cpp:24:5:24:25 | Chi [s3] | C.cpp:18:12:18:18 | C output argument [s3] | -| C.cpp:24:11:24:12 | s3 [post update] [s3] | C.cpp:24:5:24:25 | Chi [s3] | -| C.cpp:24:16:24:25 | new | C.cpp:24:11:24:12 | s3 [post update] [s3] | -| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 [s1] | -| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 [s3] | -| C.cpp:29:10:29:11 | s1 [s1] | C.cpp:29:10:29:11 | s1 | -| C.cpp:31:10:31:11 | s3 [s3] | C.cpp:31:10:31:11 | s3 | +| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Chi [s3] | +| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | +| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | aliasing.cpp:9:3:9:22 | Chi [m1] | -| aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Chi [m1] | | aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | aliasing.cpp:13:3:13:21 | Chi [m1] | -| aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | -| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:29:11:29:12 | m1 [m1] | -| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:30:11:30:12 | m1 [m1] | -| aliasing.cpp:29:11:29:12 | m1 [m1] | aliasing.cpp:29:11:29:12 | m1 | -| aliasing.cpp:30:11:30:12 | m1 [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | -| aliasing.cpp:60:6:60:7 | m1 [post update] [m1] | aliasing.cpp:62:14:62:15 | m1 [m1] | -| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:6:60:7 | m1 [post update] [m1] | -| aliasing.cpp:62:14:62:15 | m1 [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | +| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Chi [m1] | +| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | -| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | aliasing.cpp:100:14:100:14 | Store [m1] | -| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | +| 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:126:15:126:20 | taint_a_ptr output argument [array content] | @@ -70,19 +58,7 @@ edges | 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:3:106:20 | Chi [array content] | aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:106:3:106:20 | Chi [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:158:15:158:20 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | ChiTotal [post update] [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:126:15:126:20 | Chi [array content] | aliasing.cpp:127:8:127:16 | * ... | @@ -95,37 +71,16 @@ edges | aliasing.cpp:158:15:158:20 | taint_a_ptr output argument [array content] | aliasing.cpp:158:15:158:20 | Chi [array content] | | aliasing.cpp:164:15:164:20 | Chi [array content] | aliasing.cpp:165:8:165:16 | access to array | | aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | aliasing.cpp:164:15:164:20 | Chi [array content] | -| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument | aliasing.cpp:175:21:175:22 | m1 [post update] [m1] | -| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument | -| aliasing.cpp:175:19:175:19 | s [post update] [s, m1] | aliasing.cpp:176:11:176:11 | s [s, m1] | -| aliasing.cpp:175:21:175:22 | m1 [post update] [m1] | aliasing.cpp:175:19:175:19 | s [post update] [s, m1] | -| aliasing.cpp:176:11:176:11 | s [s, m1] | aliasing.cpp:176:13:176:14 | m1 [m1] | -| aliasing.cpp:176:13:176:14 | m1 [m1] | aliasing.cpp:176:13:176:14 | m1 | -| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | aliasing.cpp:187:21:187:22 | m1 [post update] [m1] | -| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | -| aliasing.cpp:187:19:187:19 | s [post update] [s, m1] | aliasing.cpp:189:13:189:13 | s [s, m1] | -| aliasing.cpp:187:21:187:22 | m1 [post update] [m1] | aliasing.cpp:187:19:187:19 | s [post update] [s, m1] | -| aliasing.cpp:189:13:189:13 | s [s, m1] | aliasing.cpp:189:15:189:16 | m1 [m1] | -| aliasing.cpp:189:15:189:16 | m1 [m1] | aliasing.cpp:189:15:189:16 | m1 | -| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | aliasing.cpp:200:23:200:24 | m1 [post update] [m1] | -| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | -| aliasing.cpp:200:21:200:21 | s [post update] [s, m1] | aliasing.cpp:201:13:201:13 | s [s, m1] | -| aliasing.cpp:200:23:200:24 | m1 [post update] [m1] | aliasing.cpp:200:21:200:21 | s [post update] [s, m1] | -| aliasing.cpp:201:13:201:13 | s [s, m1] | aliasing.cpp:201:15:201:16 | m1 [m1] | -| aliasing.cpp:201:15:201:16 | m1 [m1] | aliasing.cpp:201:15:201:16 | m1 | -| aliasing.cpp:211:6:211:6 | s [post update] [s, m1] | aliasing.cpp:212:12:212:12 | s [s, m1] | -| aliasing.cpp:211:8:211:9 | m1 [post update] [m1] | aliasing.cpp:211:6:211:6 | s [post update] [s, m1] | -| aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:211:8:211:9 | m1 [post update] [m1] | -| aliasing.cpp:212:12:212:12 | s [m1] | aliasing.cpp:213:10:213:11 | m1 [m1] | -| aliasing.cpp:212:12:212:12 | s [s, m1] | aliasing.cpp:212:12:212:12 | s [m1] | -| aliasing.cpp:213:10:213:11 | m1 [m1] | aliasing.cpp:213:10:213:11 | m1 | -| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument | aliasing.cpp:225:21:225:22 | m1 [post update] [m1] | -| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | aliasing.cpp:225:15:225:22 | taint_a_ptr output argument | -| aliasing.cpp:225:19:225:19 | s [post update] [s, m1] | aliasing.cpp:226:12:226:12 | s [s, m1] | -| aliasing.cpp:225:21:225:22 | m1 [post update] [m1] | aliasing.cpp:225:19:225:19 | s [post update] [s, m1] | -| aliasing.cpp:226:12:226:12 | s [m1] | aliasing.cpp:227:10:227:11 | m1 [m1] | -| aliasing.cpp:226:12:226:12 | s [s, m1] | aliasing.cpp:226:12:226:12 | s [m1] | -| aliasing.cpp:227:10:227:11 | m1 [m1] | aliasing.cpp:227:10:227:11 | m1 | +| 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: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: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 | | 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 | * ... | @@ -141,126 +96,65 @@ edges | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:10:84:10 | a [post update] [a] | by_reference.cpp:84:3:84:25 | Chi [a] | -| by_reference.cpp:84:10:84:10 | a [post update] [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:10:84:10 | a [post update] [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:10:84:10 | a [post update] [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Chi [a] | | 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:9:88:9 | a [post update] [a] | by_reference.cpp:88:3:88:24 | Chi [a] | -| by_reference.cpp:88:9:88:9 | a [post update] [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:9:88:9 | a [post update] [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:9:88:9 | a [post update] [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:3:92:20 | ChiTotal [post update] [array content] | by_reference.cpp:92:3:92:20 | Chi [array content] | -| by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | -| by_reference.cpp:92:3:92:20 | ChiTotal [post update] [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 | ChiTotal [post update] [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:3:96:19 | ChiTotal [post update] [array content] | by_reference.cpp:96:3:96:19 | Chi [array content] | -| by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | -| by_reference.cpp:96:3:96:19 | ChiTotal [post update] [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 | ChiTotal [post update] [array content] | -| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:28:102:39 | inner_nested [post update] [a, a] | -| by_reference.cpp:102:28:102:39 | inner_nested [post update] [a, a] | by_reference.cpp:110:14:110:25 | inner_nested [a, a] | -| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument | by_reference.cpp:104:22:104:22 | a [post update] [a] | -| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument | -| by_reference.cpp:104:22:104:22 | a [post update] [a] | by_reference.cpp:112:14:112:14 | a [a] | -| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:30:106:41 | inner_nested [post update] [a, a] | -| by_reference.cpp:106:30:106:41 | inner_nested [post update] [a, a] | by_reference.cpp:114:16:114:27 | inner_nested [a, a] | -| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument | by_reference.cpp:108:24:108:24 | a [post update] [a] | -| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument | -| by_reference.cpp:108:24:108:24 | a [post update] [a] | by_reference.cpp:116:16:116:16 | a [a] | -| by_reference.cpp:110:14:110:25 | inner_nested [a, a] | by_reference.cpp:110:27:110:27 | a [a] | -| by_reference.cpp:110:27:110:27 | a [a] | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:112:14:112:14 | a [a] | by_reference.cpp:112:14:112:14 | a | -| by_reference.cpp:114:16:114:27 | inner_nested [a, a] | by_reference.cpp:114:29:114:29 | a [a] | -| by_reference.cpp:114:29:114:29 | a [a] | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:116:16:116:16 | a [a] | by_reference.cpp:116:16:116:16 | a | -| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:27:122:38 | inner_nested [post update] [a, a] | -| by_reference.cpp:122:27:122:38 | inner_nested [post update] [a, a] | by_reference.cpp:130:14:130:25 | inner_nested [a, a] | -| by_reference.cpp:124:15:124:21 | taint_a_ref output argument | by_reference.cpp:124:21:124:21 | a [post update] [a] | -| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument | -| by_reference.cpp:124:21:124:21 | a [post update] [a] | by_reference.cpp:132:14:132:14 | a [a] | -| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:29:126:40 | inner_nested [post update] [a, a] | -| by_reference.cpp:126:29:126:40 | inner_nested [post update] [a, a] | by_reference.cpp:134:16:134:27 | inner_nested [a, a] | -| by_reference.cpp:128:15:128:23 | taint_a_ref output argument | by_reference.cpp:128:23:128:23 | a [post update] [a] | -| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument | -| by_reference.cpp:128:23:128:23 | a [post update] [a] | by_reference.cpp:136:16:136:16 | a [a] | -| by_reference.cpp:130:14:130:25 | inner_nested [a, a] | by_reference.cpp:130:27:130:27 | a [a] | -| by_reference.cpp:130:27:130:27 | a [a] | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:132:14:132:14 | a [a] | by_reference.cpp:132:14:132:14 | a | -| by_reference.cpp:134:16:134:27 | inner_nested [a, a] | by_reference.cpp:134:29:134:29 | a [a] | -| by_reference.cpp:134:29:134:29 | a [a] | by_reference.cpp:134:29:134:29 | a | -| by_reference.cpp:136:16:136:16 | a [a] | by_reference.cpp:136:16:136:16 | a | -| by_reference.cpp:140:3:140:27 | Chi [array content] | by_reference.cpp:145:15:145:16 | taint_a_ptr output argument [array content] | -| by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | by_reference.cpp:140:3:140:27 | Chi [array content] | -| by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | by_reference.cpp:145:15:145:16 | taint_a_ptr output argument [array content] | -| by_reference.cpp:140:9:140:27 | (char *)... | by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | -| by_reference.cpp:140:9:140:27 | (const char *)... | by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | -| by_reference.cpp:140:16:140:25 | call to user_input | by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | -| by_reference.cpp:145:15:145:16 | taint_a_ptr output argument | by_reference.cpp:146:8:146:8 | s | -| by_reference.cpp:145:15:145:16 | taint_a_ptr output argument [array content] | by_reference.cpp:145:15:145:16 | taint_a_ptr output argument | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | Chi [array content] | +| 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: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: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: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 | | complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:42:18:42:18 | call to a | +| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:42:16:42:16 | Chi [b_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:42:16:42:16 | a output argument [b_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:43:18:43:18 | call to b | -| complex.cpp:40:17:40:17 | *b [f, f, a_] | complex.cpp:42:10:42:14 | inner [f, f, a_] | -| complex.cpp:40:17:40:17 | *b [f, f, b_] | complex.cpp:42:10:42:14 | inner [f, f, b_] | -| complex.cpp:40:17:40:17 | *b [f, f, b_] | complex.cpp:42:16:42:16 | a output argument [f, f, b_] | -| complex.cpp:40:17:40:17 | *b [f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | -| complex.cpp:40:17:40:17 | *b [f, f, f, f, a_] | complex.cpp:42:10:42:14 | inner [f, f, f, f, a_] | -| complex.cpp:42:10:42:14 | inner [f, f, a_] | complex.cpp:42:16:42:16 | f [f, a_] | -| complex.cpp:42:10:42:14 | inner [f, f, b_] | complex.cpp:42:16:42:16 | f [f, b_] | -| complex.cpp:42:10:42:14 | inner [f, f, f, f, a_] | complex.cpp:42:16:42:16 | f [f, f, f, a_] | -| complex.cpp:42:10:42:14 | inner [post update] [f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | -| complex.cpp:42:10:42:14 | inner [post update] [f, f, f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, f, f, b_] | -| complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:42:16:42:16 | f [post update] [f, b_] | +| complex.cpp:42:16:42:16 | Chi [b_] | complex.cpp:43:18:43:18 | call to b | +| complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:42:16:42:16 | Chi [b_] | | complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:43:18:43:18 | call to b | -| complex.cpp:42:16:42:16 | a output argument [f, f, b_] | complex.cpp:42:16:42:16 | f [post update] [f, f, f, b_] | -| complex.cpp:42:16:42:16 | a output argument [f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | -| complex.cpp:42:16:42:16 | f [f, a_] | complex.cpp:42:18:42:18 | call to a | -| complex.cpp:42:16:42:16 | f [f, b_] | complex.cpp:42:16:42:16 | a output argument [b_] | -| complex.cpp:42:16:42:16 | f [f, f, f, a_] | complex.cpp:42:10:42:14 | inner [f, f, a_] | -| complex.cpp:42:16:42:16 | f [post update] [f, b_] | complex.cpp:42:10:42:14 | inner [post update] [f, f, b_] | -| complex.cpp:42:16:42:16 | f [post update] [f, f, f, b_] | complex.cpp:42:10:42:14 | inner [post update] [f, f, f, f, b_] | -| complex.cpp:43:10:43:14 | inner [f, f, b_] | complex.cpp:43:16:43:16 | f [f, b_] | -| complex.cpp:43:10:43:14 | inner [f, f, f, f, b_] | complex.cpp:43:16:43:16 | f [f, f, f, b_] | -| complex.cpp:43:16:43:16 | f [f, b_] | complex.cpp:43:18:43:18 | call to b | -| complex.cpp:43:16:43:16 | f [f, f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | -| complex.cpp:53:6:53:10 | inner [post update] [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | -| complex.cpp:53:12:53:12 | f [post update] [f, a_] | complex.cpp:53:6:53:10 | inner [post update] [f, f, a_] | +| complex.cpp:53:12:53:12 | Chi [a_] | complex.cpp:40:17:40:17 | *b [a_] | | complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:53:12:53:12 | f [post update] [f, a_] | +| complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:53:12:53:12 | Chi [a_] | | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:53:12:53:12 | setA output argument [a_] | -| complex.cpp:54:6:54:10 | inner [post update] [f, f, b_] | complex.cpp:40:17:40:17 | *b [f, f, b_] | -| complex.cpp:54:12:54:12 | f [post update] [f, b_] | complex.cpp:54:6:54:10 | inner [post update] [f, f, b_] | +| complex.cpp:54:12:54:12 | Chi [b_] | complex.cpp:40:17:40:17 | *b [b_] | | complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:40:17:40:17 | *b [b_] | -| complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:54:12:54:12 | f [post update] [f, b_] | +| complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:54:12:54:12 | Chi [b_] | | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:54:12:54:12 | setB output argument [b_] | -| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | -| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | complex.cpp:56:6:56:10 | inner [f, f, a_] | -| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | -| complex.cpp:55:12:55:12 | f [post update] [f, a_] | complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | +| complex.cpp:55:12:55:12 | Chi [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:55:12:55:12 | Chi [a_] | complex.cpp:56:12:56:12 | Chi [a_] | +| complex.cpp:55:12:55:12 | Chi [a_] | complex.cpp:56:12:56:12 | setB output argument [a_] | | complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:55:12:55:12 | f [post update] [f, a_] | +| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:55:12:55:12 | Chi [a_] | +| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:56:12:56:12 | Chi [a_] | | complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:56:12:56:12 | setB output argument [a_] | | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:55:12:55:12 | setA output argument [a_] | -| complex.cpp:56:6:56:10 | inner [f, f, a_] | complex.cpp:56:12:56:12 | f [f, a_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, b_] | complex.cpp:40:17:40:17 | *b [f, f, b_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, f, f, a_] | -| complex.cpp:56:12:56:12 | f [f, a_] | complex.cpp:56:12:56:12 | setB output argument [a_] | -| complex.cpp:56:12:56:12 | f [post update] [f, a_] | complex.cpp:56:6:56:10 | inner [post update] [f, f, a_] | -| complex.cpp:56:12:56:12 | f [post update] [f, b_] | complex.cpp:56:6:56:10 | inner [post update] [f, f, b_] | -| complex.cpp:56:12:56:12 | f [post update] [f, f, f, a_] | complex.cpp:56:6:56:10 | inner [post update] [f, f, f, f, a_] | +| complex.cpp:56:12:56:12 | Chi [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:56:12:56:12 | Chi [b_] | complex.cpp:40:17:40:17 | *b [b_] | | complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:56:12:56:12 | f [post update] [f, a_] | +| complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:56:12:56:12 | Chi [a_] | | complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:40:17:40:17 | *b [b_] | -| complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:56:12:56:12 | f [post update] [f, b_] | -| complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | -| complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | complex.cpp:56:12:56:12 | f [post update] [f, f, f, a_] | +| complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:56:12:56:12 | Chi [b_] | | complex.cpp:56:19:56:28 | call to user_input | complex.cpp:56:12:56:12 | setB output argument [b_] | | constructors.cpp:26:15:26:15 | *f [a_] | constructors.cpp:28:12:28:12 | call to a | | constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:28:10:28:10 | a output argument [b_] | @@ -288,25 +182,21 @@ edges | simple.cpp:42:5:42:5 | setB output argument [a_] | simple.cpp:26:15:26:15 | *f [a_] | | simple.cpp:42:5:42:5 | setB output argument [b_] | simple.cpp:26:15:26:15 | *f [b_] | | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | setB output argument [b_] | -| simple.cpp:65:7:65:7 | i [post update] [i] | simple.cpp:67:13:67:13 | i [i] | -| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:7:65:7 | i [post update] [i] | -| simple.cpp:67:13:67:13 | i [i] | simple.cpp:67:13:67:13 | i | -| simple.cpp:83:9:83:10 | f2 [post update] [f1, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | -| simple.cpp:83:12:83:13 | f1 [post update] [f1] | simple.cpp:83:9:83:10 | f2 [post update] [f1, f1] | -| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:12:83:13 | f1 [post update] [f1] | -| simple.cpp:92:7:92:7 | i [post update] [i] | simple.cpp:94:13:94:13 | i [i] | -| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:7:92:7 | i [post update] [i] | -| simple.cpp:94:13:94:13 | i [i] | simple.cpp:94:13:94:13 | i | -| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a [a] | -| struct_init.c:15:12:15:12 | a [a] | struct_init.c:15:12:15:12 | a | -| struct_init.c:20:17:20:36 | a [post update] [a] | struct_init.c:14:24:14:25 | *ab [a] | -| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | a [post update] [a] | +| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | +| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | +| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Chi [f1] | +| simple.cpp:92:5:92:22 | Store [i] | simple.cpp:93:20:93:20 | Store [i] | +| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | Store [i] | +| simple.cpp:93:20:93:20 | Store [i] | simple.cpp:94:13:94:13 | i | +| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | +| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:14:24:14:25 | *ab [a] | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Chi [a] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | -| struct_init.c:26:23:29:3 | nestedAB [post update] [nestedAB, a] | struct_init.c:36:17:36:24 | nestedAB [nestedAB, a] | -| struct_init.c:27:5:27:23 | a [post update] [a] | struct_init.c:26:23:29:3 | nestedAB [post update] [nestedAB, a] | -| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | a [post update] [a] | +| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:14:24:14:25 | *ab [a] | +| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Chi [a] | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | -| struct_init.c:36:17:36:24 | nestedAB [nestedAB, a] | struct_init.c:14:24:14:25 | *ab [a] | nodes | A.cpp:55:5:55:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:55:12:55:19 | (C *)... | semmle.label | (C *)... | @@ -316,75 +206,66 @@ nodes | A.cpp:57:17:57:23 | new | semmle.label | new | | A.cpp:57:28:57:30 | call to get | semmle.label | call to get | | A.cpp:98:12:98:18 | new | semmle.label | new | -| A.cpp:100:9:100:9 | a [post update] [a] | semmle.label | a [post update] [a] | +| A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | | A.cpp:107:16:107:16 | a | semmle.label | a | -| A.cpp:107:16:107:16 | a [a] | semmle.label | a [a] | | A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] | | A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:126:12:126:18 | new | semmle.label | new | +| A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] | | A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] | | A.cpp:132:13:132:13 | c | semmle.label | c | -| A.cpp:132:13:132:13 | c [c] | semmle.label | c [c] | | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | -| A.cpp:142:10:142:10 | c [post update] [c] | semmle.label | c [post update] [c] | | A.cpp:142:14:142:20 | new | semmle.label | new | | A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] | -| A.cpp:143:13:143:13 | b [post update] [b] | semmle.label | b [post update] [b] | | A.cpp:143:25:143:31 | new | semmle.label | new | | A.cpp:150:12:150:18 | new | semmle.label | new | +| A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] | | A.cpp:151:12:151:24 | D output argument [b] | semmle.label | D output argument [b] | +| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | | A.cpp:152:13:152:13 | b | semmle.label | b | -| A.cpp:152:13:152:13 | b [b] | semmle.label | b [b] | | A.cpp:154:13:154:13 | c | semmle.label | c | -| A.cpp:154:13:154:13 | c [c] | semmle.label | c [c] | | C.cpp:18:12:18:18 | C output argument [s1] | semmle.label | C output argument [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | semmle.label | C output argument [s3] | -| C.cpp:22:9:22:22 | s1 [post update] [s1] | semmle.label | s1 [post update] [s1] | +| C.cpp:22:12:22:21 | Chi [s1] | semmle.label | Chi [s1] | | C.cpp:22:12:22:21 | new | semmle.label | new | | C.cpp:24:5:24:25 | Chi [s1] | semmle.label | Chi [s1] | | C.cpp:24:5:24:25 | Chi [s3] | semmle.label | Chi [s3] | -| C.cpp:24:11:24:12 | s3 [post update] [s3] | semmle.label | s3 [post update] [s3] | | C.cpp:24:16:24:25 | new | semmle.label | new | | C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] | | C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] | | C.cpp:29:10:29:11 | s1 | semmle.label | s1 | -| C.cpp:29:10:29:11 | s1 [s1] | semmle.label | s1 [s1] | | C.cpp:31:10:31:11 | s3 | semmle.label | s3 | -| C.cpp:31:10:31:11 | s3 [s3] | semmle.label | s3 [s3] | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | | aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | | aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | -| aliasing.cpp:29:11:29:12 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | -| aliasing.cpp:30:11:30:12 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | -| aliasing.cpp:60:6:60:7 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | +| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | -| aliasing.cpp:62:14:62:15 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | -| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | +| aliasing.cpp:98:3:98:21 | Chi [m1] | semmle.label | Chi [m1] | | 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 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | 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] | @@ -404,42 +285,19 @@ nodes | aliasing.cpp:164:15:164:20 | Chi [array content] | semmle.label | Chi [array content] | | aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | | aliasing.cpp:165:8:165:16 | access to array | semmle.label | access to array | -| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| 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:19:175:19 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | -| aliasing.cpp:175:21:175:22 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | -| aliasing.cpp:176:11:176:11 | s [s, m1] | semmle.label | s [s, m1] | | aliasing.cpp:176:13:176:14 | m1 | semmle.label | m1 | -| aliasing.cpp:176:13:176:14 | m1 [m1] | semmle.label | m1 [m1] | -| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| 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:19:187:19 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | -| aliasing.cpp:187:21:187:22 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | -| aliasing.cpp:189:13:189:13 | s [s, m1] | semmle.label | s [s, m1] | +| aliasing.cpp:188:13:188:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:189:15:189:16 | m1 | semmle.label | m1 | -| aliasing.cpp:189:15:189:16 | m1 [m1] | semmle.label | m1 [m1] | -| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| 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:21:200:21 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | -| aliasing.cpp:200:23:200:24 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | -| aliasing.cpp:201:13:201:13 | s [s, m1] | semmle.label | s [s, m1] | | aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 | -| aliasing.cpp:201:15:201:16 | m1 [m1] | semmle.label | m1 [m1] | -| aliasing.cpp:211:6:211:6 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | -| aliasing.cpp:211:8:211:9 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | -| aliasing.cpp:211:13:211:22 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:212:12:212:12 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:212:12:212:12 | s [s, m1] | semmle.label | s [s, m1] | -| aliasing.cpp:213:10:213:11 | m1 | semmle.label | m1 | -| aliasing.cpp:213:10:213:11 | m1 [m1] | semmle.label | m1 [m1] | -| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | -| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| aliasing.cpp:225:19:225:19 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | -| aliasing.cpp:225:21:225:22 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | -| aliasing.cpp:226:12:226:12 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:226:12:226:12 | s [s, m1] | semmle.label | s [s, m1] | -| aliasing.cpp:227:10:227:11 | m1 | semmle.label | m1 | -| aliasing.cpp:227:10:227:11 | m1 [m1] | semmle.label | m1 [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 | | arrays.cpp:9:8:9:11 | * ... | semmle.label | * ... | @@ -461,111 +319,60 @@ nodes | by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | | by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:84:10:84:10 | a [post update] [a] | semmle.label | a [post update] [a] | | 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:9:88:9 | a [post update] [a] | semmle.label | a [post update] [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 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | 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 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | 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:102:28:102:39 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | -| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| 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:22:104:22 | a [post update] [a] | semmle.label | a [post update] [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:106:30:106:41 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | -| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| 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:24:108:24 | a [post update] [a] | semmle.label | a [post update] [a] | -| by_reference.cpp:110:14:110:25 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:110:27:110:27 | a | semmle.label | a | -| by_reference.cpp:110:27:110:27 | a [a] | semmle.label | a [a] | | by_reference.cpp:112:14:112:14 | a | semmle.label | a | -| by_reference.cpp:112:14:112:14 | a [a] | semmle.label | a [a] | -| by_reference.cpp:114:16:114:27 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:114:29:114:29 | a | semmle.label | a | -| by_reference.cpp:114:29:114:29 | a [a] | semmle.label | a [a] | | by_reference.cpp:116:16:116:16 | a | semmle.label | a | -| by_reference.cpp:116:16:116:16 | a [a] | semmle.label | a [a] | +| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:122:27:122:38 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | -| by_reference.cpp:124:15:124:21 | taint_a_ref output argument | semmle.label | taint_a_ref output argument | +| 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:21:124:21 | a [post update] [a] | semmle.label | a [post update] [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:126:29:126:40 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | -| by_reference.cpp:128:15:128:23 | taint_a_ref output argument | semmle.label | taint_a_ref output argument | +| 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:23:128:23 | a [post update] [a] | semmle.label | a [post update] [a] | -| by_reference.cpp:130:14:130:25 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | -| by_reference.cpp:130:27:130:27 | a [a] | semmle.label | a [a] | | by_reference.cpp:132:14:132:14 | a | semmle.label | a | -| by_reference.cpp:132:14:132:14 | a [a] | semmle.label | a [a] | -| by_reference.cpp:134:16:134:27 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | -| by_reference.cpp:134:29:134:29 | a [a] | semmle.label | a [a] | | by_reference.cpp:136:16:136:16 | a | semmle.label | a | -| by_reference.cpp:136:16:136:16 | a [a] | semmle.label | a [a] | -| by_reference.cpp:140:3:140:27 | Chi [array content] | semmle.label | Chi [array content] | -| by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | -| by_reference.cpp:140:9:140:27 | (char *)... | semmle.label | (char *)... | -| by_reference.cpp:140:9:140:27 | (const char *)... | semmle.label | (const char *)... | -| by_reference.cpp:140:16:140:25 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:145:15:145:16 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | -| by_reference.cpp:145:15:145:16 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| by_reference.cpp:146:8:146:8 | s | semmle.label | s | | complex.cpp:40:17:40:17 | *b [a_] | semmle.label | *b [a_] | | complex.cpp:40:17:40:17 | *b [b_] | semmle.label | *b [b_] | -| complex.cpp:40:17:40:17 | *b [f, f, a_] | semmle.label | *b [f, f, a_] | -| complex.cpp:40:17:40:17 | *b [f, f, b_] | semmle.label | *b [f, f, b_] | -| complex.cpp:40:17:40:17 | *b [f, f, f, f, a_] | semmle.label | *b [f, f, f, f, a_] | -| complex.cpp:42:10:42:14 | inner [f, f, a_] | semmle.label | inner [f, f, a_] | -| complex.cpp:42:10:42:14 | inner [f, f, b_] | semmle.label | inner [f, f, b_] | -| complex.cpp:42:10:42:14 | inner [f, f, f, f, a_] | semmle.label | inner [f, f, f, f, a_] | -| complex.cpp:42:10:42:14 | inner [post update] [f, f, b_] | semmle.label | inner [post update] [f, f, b_] | -| complex.cpp:42:10:42:14 | inner [post update] [f, f, f, f, b_] | semmle.label | inner [post update] [f, f, f, f, b_] | +| complex.cpp:42:16:42:16 | Chi [b_] | semmle.label | Chi [b_] | | complex.cpp:42:16:42:16 | a output argument [b_] | semmle.label | a output argument [b_] | -| complex.cpp:42:16:42:16 | a output argument [f, f, b_] | semmle.label | a output argument [f, f, b_] | -| complex.cpp:42:16:42:16 | f [f, a_] | semmle.label | f [f, a_] | -| complex.cpp:42:16:42:16 | f [f, b_] | semmle.label | f [f, b_] | -| complex.cpp:42:16:42:16 | f [f, f, f, a_] | semmle.label | f [f, f, f, a_] | -| complex.cpp:42:16:42:16 | f [post update] [f, b_] | semmle.label | f [post update] [f, b_] | -| complex.cpp:42:16:42:16 | f [post update] [f, f, f, b_] | semmle.label | f [post update] [f, f, f, b_] | | complex.cpp:42:18:42:18 | call to a | semmle.label | call to a | -| complex.cpp:43:10:43:14 | inner [f, f, b_] | semmle.label | inner [f, f, b_] | -| complex.cpp:43:10:43:14 | inner [f, f, f, f, b_] | semmle.label | inner [f, f, f, f, b_] | -| complex.cpp:43:16:43:16 | f [f, b_] | semmle.label | f [f, b_] | -| complex.cpp:43:16:43:16 | f [f, f, f, b_] | semmle.label | f [f, f, f, b_] | | complex.cpp:43:18:43:18 | call to b | semmle.label | call to b | -| complex.cpp:53:6:53:10 | inner [post update] [f, f, a_] | semmle.label | inner [post update] [f, f, a_] | -| complex.cpp:53:12:53:12 | f [post update] [f, a_] | semmle.label | f [post update] [f, a_] | +| complex.cpp:53:12:53:12 | Chi [a_] | semmle.label | Chi [a_] | | complex.cpp:53:12:53:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | | complex.cpp:53:19:53:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:54:6:54:10 | inner [post update] [f, f, b_] | semmle.label | inner [post update] [f, f, b_] | -| complex.cpp:54:12:54:12 | f [post update] [f, b_] | semmle.label | f [post update] [f, b_] | +| complex.cpp:54:12:54:12 | Chi [b_] | semmle.label | Chi [b_] | | complex.cpp:54:12:54:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | | complex.cpp:54:19:54:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | semmle.label | inner [post update] [f, f, a_] | -| complex.cpp:55:12:55:12 | f [post update] [f, a_] | semmle.label | f [post update] [f, a_] | +| complex.cpp:55:12:55:12 | Chi [a_] | semmle.label | Chi [a_] | | complex.cpp:55:12:55:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | | complex.cpp:55:19:55:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:56:6:56:10 | inner [f, f, a_] | semmle.label | inner [f, f, a_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, a_] | semmle.label | inner [post update] [f, f, a_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, b_] | semmle.label | inner [post update] [f, f, b_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, f, f, a_] | semmle.label | inner [post update] [f, f, f, f, a_] | -| complex.cpp:56:12:56:12 | f [f, a_] | semmle.label | f [f, a_] | -| complex.cpp:56:12:56:12 | f [post update] [f, a_] | semmle.label | f [post update] [f, a_] | -| complex.cpp:56:12:56:12 | f [post update] [f, b_] | semmle.label | f [post update] [f, b_] | -| complex.cpp:56:12:56:12 | f [post update] [f, f, f, a_] | semmle.label | f [post update] [f, f, f, a_] | +| complex.cpp:56:12:56:12 | Chi [a_] | semmle.label | Chi [a_] | +| complex.cpp:56:12:56:12 | Chi [b_] | semmle.label | Chi [b_] | | complex.cpp:56:12:56:12 | setB output argument [a_] | semmle.label | setB output argument [a_] | | complex.cpp:56:12:56:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | -| complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | semmle.label | setB output argument [f, f, a_] | | complex.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | | constructors.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | | constructors.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | @@ -594,29 +401,25 @@ nodes | simple.cpp:42:5:42:5 | setB output argument [a_] | semmle.label | setB output argument [a_] | | simple.cpp:42:5:42:5 | setB output argument [b_] | semmle.label | setB output argument [b_] | | simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:65:7:65:7 | i [post update] [i] | semmle.label | i [post update] [i] | +| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | -| simple.cpp:67:13:67:13 | i [i] | semmle.label | i [i] | -| simple.cpp:83:9:83:10 | f2 [post update] [f1, f1] | semmle.label | f2 [post update] [f1, f1] | -| simple.cpp:83:12:83:13 | f1 [post update] [f1] | semmle.label | f1 [post update] [f1] | +| simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | -| simple.cpp:92:7:92:7 | i [post update] [i] | semmle.label | i [post update] [i] | +| simple.cpp:92:5:92:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:93:20:93:20 | Store [i] | semmle.label | Store [i] | | simple.cpp:94:13:94:13 | i | semmle.label | i | -| simple.cpp:94:13:94:13 | i [i] | semmle.label | i [i] | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | -| struct_init.c:15:12:15:12 | a [a] | semmle.label | a [a] | -| struct_init.c:20:17:20:36 | a [post update] [a] | semmle.label | a [post update] [a] | +| struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | -| struct_init.c:26:23:29:3 | nestedAB [post update] [nestedAB, a] | semmle.label | nestedAB [post update] [nestedAB, a] | -| struct_init.c:27:5:27:23 | a [post update] [a] | semmle.label | a [post update] [a] | +| struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | | struct_init.c:31:23:31:23 | a | semmle.label | a | -| struct_init.c:36:17:36:24 | nestedAB [nestedAB, a] | semmle.label | nestedAB [nestedAB, a] | #select | A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... | | A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | @@ -646,8 +449,6 @@ nodes | aliasing.cpp:176:13:176:14 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:176:13:176:14 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:189:15:189:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:189:15:189:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:201:15:201:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:201:15:201:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | -| aliasing.cpp:213:10:213:11 | m1 | aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:213:10:213:11 | m1 | m1 flows from $@ | aliasing.cpp:211:13:211:22 | call to user_input | call to user_input | -| aliasing.cpp:227:10:227:11 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:227:10:227:11 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | 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:7:8:7:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:9:8:9:11 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:10:8:10:15 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | @@ -665,9 +466,6 @@ nodes | by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | -| by_reference.cpp:146:8:146:8 | s | by_reference.cpp:140:9:140:27 | (char *)... | by_reference.cpp:146:8:146:8 | s | s flows from $@ | by_reference.cpp:140:9:140:27 | (char *)... | (char *)... | -| by_reference.cpp:146:8:146:8 | s | by_reference.cpp:140:9:140:27 | (const char *)... | by_reference.cpp:146:8:146:8 | s | s flows from $@ | by_reference.cpp:140:9:140:27 | (const char *)... | (const char *)... | -| by_reference.cpp:146:8:146:8 | s | by_reference.cpp:140:16:140:25 | call to user_input | by_reference.cpp:146:8:146:8 | s | s flows from $@ | by_reference.cpp:140:16:140:25 | call to user_input | call to user_input | | complex.cpp:42:18:42:18 | call to a | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:53:19:53:28 | call to user_input | call to user_input | | complex.cpp:42:18:42:18 | call to a | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:55:19:55:28 | call to user_input | call to user_input | | complex.cpp:43:18:43:18 | call to b | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:43:18:43:18 | call to b | call to b flows from $@ | complex.cpp:54:19:54:28 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index d7939750db6..996836a65b4 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -1,12 +1,12 @@ | A.cpp:25:13:25:13 | c | AST only | | A.cpp:27:28:27:28 | c | AST only | -| A.cpp:28:29:28:29 | this | IR only | | A.cpp:31:20:31:20 | c | AST only | | A.cpp:40:5:40:6 | cc | AST only | | A.cpp:41:5:41:6 | ct | AST only | | A.cpp:42:10:42:12 | & ... | AST only | | A.cpp:43:10:43:12 | & ... | AST only | | A.cpp:48:20:48:20 | c | AST only | +| A.cpp:49:10:49:10 | b | AST only | | A.cpp:49:13:49:13 | c | AST only | | A.cpp:55:5:55:5 | b | AST only | | A.cpp:56:10:56:10 | b | AST only | @@ -14,11 +14,15 @@ | A.cpp:57:28:57:30 | call to get | AST only | | A.cpp:64:10:64:15 | this | AST only | | A.cpp:64:17:64:18 | b1 | AST only | +| A.cpp:65:10:65:11 | b1 | AST only | | A.cpp:65:14:65:14 | c | AST only | +| A.cpp:66:10:66:11 | b2 | AST only | | A.cpp:66:14:66:14 | c | AST only | | A.cpp:73:10:73:19 | this | AST only | | A.cpp:73:21:73:22 | b1 | AST only | +| A.cpp:74:10:74:11 | b1 | AST only | | A.cpp:74:14:74:14 | c | AST only | +| A.cpp:75:10:75:11 | b2 | AST only | | A.cpp:75:14:75:14 | c | AST only | | A.cpp:81:10:81:15 | this | AST only | | A.cpp:81:17:81:18 | b1 | AST only | @@ -30,61 +34,85 @@ | A.cpp:100:9:100:9 | a | AST only | | A.cpp:101:5:101:6 | this | AST only | | A.cpp:101:8:101:9 | c1 | AST only | +| A.cpp:107:12:107:13 | c1 | AST only | | A.cpp:107:16:107:16 | a | AST only | +| A.cpp:120:12:120:13 | c1 | AST only | | A.cpp:120:16:120:16 | a | AST only | | A.cpp:126:5:126:5 | b | AST only | | A.cpp:131:5:131:6 | this | AST only | | A.cpp:131:8:131:8 | b | AST only | +| A.cpp:132:10:132:10 | b | AST only | | A.cpp:132:13:132:13 | c | AST only | | A.cpp:142:10:142:10 | c | AST only | | A.cpp:143:13:143:13 | b | AST only | | A.cpp:151:18:151:18 | b | AST only | | A.cpp:151:21:151:21 | this | AST only | +| A.cpp:152:10:152:10 | d | AST only | | A.cpp:152:13:152:13 | b | AST only | +| A.cpp:153:10:153:10 | d | AST only | +| A.cpp:153:13:153:13 | b | AST only | | A.cpp:153:16:153:16 | c | AST only | +| A.cpp:154:10:154:10 | b | AST only | | A.cpp:154:13:154:13 | c | AST only | | A.cpp:160:29:160:29 | b | AST only | | A.cpp:161:38:161:39 | l1 | AST only | | A.cpp:162:38:162:39 | l2 | AST only | +| A.cpp:163:10:163:11 | l3 | AST only | | A.cpp:163:14:163:17 | head | AST only | +| A.cpp:164:10:164:11 | l3 | AST only | +| A.cpp:164:14:164:17 | next | AST only | | A.cpp:164:20:164:23 | head | AST only | +| A.cpp:165:10:165:11 | l3 | AST only | +| A.cpp:165:14:165:17 | next | AST only | +| A.cpp:165:20:165:23 | next | AST only | | A.cpp:165:26:165:29 | head | AST only | +| A.cpp:166:10:166:11 | l3 | AST only | +| A.cpp:166:14:166:17 | next | AST only | +| A.cpp:166:20:166:23 | next | AST only | +| A.cpp:166:26:166:29 | next | AST only | | A.cpp:166:32:166:35 | head | AST only | -| A.cpp:167:47:167:50 | l | IR only | +| A.cpp:169:12:169:12 | l | AST only | | A.cpp:169:15:169:18 | head | AST only | | A.cpp:183:7:183:10 | head | AST only | | A.cpp:184:13:184:16 | next | AST only | | B.cpp:7:25:7:25 | e | AST only | | B.cpp:8:25:8:26 | b1 | AST only | +| B.cpp:9:10:9:11 | b2 | AST only | +| B.cpp:9:14:9:17 | box1 | AST only | | B.cpp:9:20:9:24 | elem1 | AST only | +| B.cpp:10:10:10:11 | b2 | AST only | +| B.cpp:10:14:10:17 | box1 | AST only | | B.cpp:10:20:10:24 | elem2 | AST only | | B.cpp:16:37:16:37 | e | AST only | | B.cpp:17:25:17:26 | b1 | AST only | +| B.cpp:18:10:18:11 | b2 | AST only | +| B.cpp:18:14:18:17 | box1 | AST only | | B.cpp:18:20:18:24 | elem1 | AST only | +| B.cpp:19:10:19:11 | b2 | AST only | +| B.cpp:19:14:19:17 | box1 | AST only | | B.cpp:19:20:19:24 | elem2 | AST only | | B.cpp:35:13:35:17 | elem1 | AST only | | B.cpp:36:13:36:17 | elem2 | AST only | | B.cpp:46:13:46:16 | box1 | AST only | | C.cpp:19:5:19:5 | c | AST only | | C.cpp:24:11:24:12 | s3 | AST only | -| C.cpp:29:10:29:11 | this | IR only | -| C.cpp:30:10:30:11 | this | IR only | -| C.cpp:31:10:31:11 | this | IR only | | D.cpp:9:21:9:24 | elem | AST only | -| D.cpp:10:30:10:33 | this | IR only | | D.cpp:11:29:11:32 | elem | AST only | | D.cpp:16:21:16:23 | box | AST only | -| D.cpp:17:30:17:32 | this | IR only | | D.cpp:18:29:18:31 | box | AST only | | D.cpp:22:10:22:11 | b2 | AST only | | D.cpp:22:14:22:20 | call to getBox1 | AST only | | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:30:5:30:5 | b | AST only | +| D.cpp:30:8:30:10 | box | AST only | | D.cpp:30:13:30:16 | elem | AST only | | D.cpp:31:14:31:14 | b | AST only | +| D.cpp:37:5:37:5 | b | AST only | | D.cpp:37:8:37:10 | box | AST only | | D.cpp:37:21:37:21 | e | AST only | | D.cpp:38:14:38:14 | b | AST only | | D.cpp:44:5:44:5 | b | AST only | +| D.cpp:44:8:44:14 | call to getBox1 | AST only | | D.cpp:44:19:44:22 | elem | AST only | | D.cpp:45:14:45:14 | b | AST only | | D.cpp:51:5:51:5 | b | AST only | @@ -92,14 +120,26 @@ | D.cpp:51:27:51:27 | e | AST only | | D.cpp:52:14:52:14 | b | AST only | | D.cpp:57:5:57:12 | boxfield | AST only | +| D.cpp:58:5:58:12 | boxfield | AST only | +| D.cpp:58:5:58:12 | this | AST only | +| D.cpp:58:15:58:17 | box | AST only | | D.cpp:58:20:58:23 | elem | AST only | | D.cpp:59:5:59:7 | this | AST only | +| D.cpp:64:10:64:17 | boxfield | AST only | +| D.cpp:64:10:64:17 | this | AST only | +| D.cpp:64:20:64:22 | box | AST only | | D.cpp:64:25:64:28 | elem | AST only | +| E.cpp:21:10:21:10 | p | AST only | +| E.cpp:21:13:21:16 | data | AST only | | E.cpp:21:18:21:23 | buffer | AST only | | E.cpp:28:21:28:23 | raw | AST only | +| E.cpp:29:21:29:21 | b | AST only | | E.cpp:29:24:29:29 | buffer | AST only | +| E.cpp:30:21:30:21 | p | AST only | +| E.cpp:30:23:30:26 | data | AST only | | E.cpp:30:28:30:33 | buffer | AST only | | E.cpp:31:10:31:12 | raw | AST only | +| E.cpp:32:10:32:10 | b | AST only | | E.cpp:32:13:32:18 | buffer | AST only | | E.cpp:33:18:33:19 | & ... | AST only | | aliasing.cpp:9:6:9:7 | m1 | AST only | @@ -107,92 +147,79 @@ | aliasing.cpp:17:5:17:6 | m1 | AST only | | aliasing.cpp:25:17:25:19 | & ... | AST only | | aliasing.cpp:26:19:26:20 | s2 | AST only | -| aliasing.cpp:29:11:29:12 | s1 | IR only | -| aliasing.cpp:30:11:30:12 | s2 | IR only | -| aliasing.cpp:31:11:31:12 | s3 | IR only | | aliasing.cpp:37:8:37:9 | m1 | AST only | -| aliasing.cpp:38:11:38:12 | s1 | IR only | | aliasing.cpp:42:6:42:7 | m1 | AST only | -| aliasing.cpp:43:13:43:14 | ref2 | IR only | | aliasing.cpp:49:9:49:10 | m1 | AST only | -| aliasing.cpp:50:11:50:12 | s1 | IR only | | aliasing.cpp:54:6:54:7 | m1 | AST only | -| aliasing.cpp:55:14:55:15 | copy2 | IR only | | aliasing.cpp:60:6:60:7 | m1 | AST only | -| aliasing.cpp:62:14:62:15 | copy2 | IR only | -| aliasing.cpp:71:11:71:11 | w | IR only | | aliasing.cpp:72:5:72:6 | m1 | AST only | -| aliasing.cpp:73:10:73:10 | w | IR only | -| aliasing.cpp:73:12:73:13 | s | IR only | -| aliasing.cpp:78:13:78:13 | w | IR only | | aliasing.cpp:79:6:79:7 | m1 | AST only | -| aliasing.cpp:80:10:80:10 | w | IR only | -| aliasing.cpp:80:12:80:13 | s | IR only | -| aliasing.cpp:85:12:85:12 | w | IR only | | aliasing.cpp:86:5:86:6 | m1 | AST only | -| aliasing.cpp:87:10:87:10 | w | IR only | -| aliasing.cpp:87:12:87:13 | s | IR only | +| aliasing.cpp:92:3:92:3 | w | AST only | | aliasing.cpp:92:7:92:8 | m1 | AST only | -| aliasing.cpp:93:10:93:10 | w | IR only | -| aliasing.cpp:93:12:93:13 | s | IR only | | aliasing.cpp:98:5:98:6 | m1 | AST only | -| aliasing.cpp:101:21:101:22 | s_copy | IR only | | aliasing.cpp:106:3:106:5 | * ... | AST only | | aliasing.cpp:111:15:111:19 | & ... | AST only | -| aliasing.cpp:112:10:112:11 | s | IR only | | aliasing.cpp:121:15:121:16 | xs | AST only | | aliasing.cpp:126:15:126:20 | ... - ... | AST only | | aliasing.cpp:131:15:131:16 | xs | AST only | | aliasing.cpp:136:15:136:17 | + ... | AST only | +| aliasing.cpp:141:15:141:15 | s | AST only | | aliasing.cpp:141:17:141:20 | data | AST only | -| aliasing.cpp:143:10:143:13 | s | IR only | | aliasing.cpp:147:15:147:22 | & ... | AST only | -| aliasing.cpp:148:13:148:14 | access to array | IR only | +| aliasing.cpp:158:15:158:15 | s | AST only | | aliasing.cpp:158:17:158:20 | data | AST only | -| aliasing.cpp:159:11:159:14 | s | IR only | +| aliasing.cpp:164:15:164:15 | s | AST only | | aliasing.cpp:164:17:164:20 | data | AST only | -| aliasing.cpp:165:10:165:13 | s | IR only | | aliasing.cpp:175:15:175:22 | & ... | AST only | -| aliasing.cpp:176:11:176:11 | s2 | IR only | -| aliasing.cpp:176:13:176:14 | s | IR only | +| aliasing.cpp:175:16:175:17 | s2 | AST only | | aliasing.cpp:181:15:181:22 | & ... | AST only | -| aliasing.cpp:182:11:182:11 | s2 | IR only | -| aliasing.cpp:182:13:182:14 | s | IR only | +| aliasing.cpp:181:16:181:17 | s2 | AST only | | aliasing.cpp:187:15:187:22 | & ... | AST only | -| aliasing.cpp:189:13:189:13 | s2_2 | IR only | -| aliasing.cpp:189:15:189:16 | s | IR only | +| aliasing.cpp:187:16:187:17 | s2 | AST only | | aliasing.cpp:194:15:194:22 | & ... | AST only | -| aliasing.cpp:196:13:196:13 | s2_2 | IR only | -| aliasing.cpp:196:15:196:16 | s | IR only | +| aliasing.cpp:194:16:194:17 | s2 | AST only | | aliasing.cpp:200:15:200:24 | & ... | AST only | -| aliasing.cpp:201:13:201:13 | ps2 | IR only | -| aliasing.cpp:201:15:201:16 | s | IR only | +| aliasing.cpp:200:16:200:18 | ps2 | AST only | | aliasing.cpp:205:15:205:24 | & ... | AST only | -| aliasing.cpp:206:13:206:13 | ps2 | IR only | -| aliasing.cpp:206:15:206:16 | s | IR only | -| aliasing.cpp:211:8:211:9 | m1 | AST only | -| aliasing.cpp:212:12:212:12 | s2 | IR only | -| aliasing.cpp:213:10:213:11 | s | IR only | -| aliasing.cpp:218:8:218:9 | m1 | AST only | -| aliasing.cpp:219:12:219:12 | s2 | IR only | -| aliasing.cpp:220:10:220:11 | s | IR only | -| aliasing.cpp:225:15:225:22 | & ... | AST only | -| aliasing.cpp:226:12:226:12 | s2 | IR only | -| aliasing.cpp:227:10:227:11 | s | IR only | -| aliasing.cpp:232:15:232:22 | & ... | AST only | -| aliasing.cpp:233:12:233:12 | s2 | IR only | -| aliasing.cpp:234:10:234:11 | s | IR only | +| aliasing.cpp:205:16:205:18 | ps2 | AST only | | arrays.cpp:6:3:6:8 | access to array | AST only | | arrays.cpp:6:3:6:23 | arr | IR only | | arrays.cpp:15:3:15:10 | * ... | AST only | +| arrays.cpp:36:3:36:3 | o | AST only | +| arrays.cpp:36:5:36:10 | nested | AST only | | arrays.cpp:36:19:36:22 | data | AST only | +| arrays.cpp:37:8:37:8 | o | AST only | +| arrays.cpp:37:8:37:22 | access to array | AST only | +| arrays.cpp:37:10:37:15 | nested | AST only | | arrays.cpp:37:24:37:27 | data | AST only | +| arrays.cpp:38:8:38:8 | o | AST only | +| arrays.cpp:38:8:38:22 | access to array | AST only | +| arrays.cpp:38:10:38:15 | nested | AST only | | arrays.cpp:38:24:38:27 | data | AST only | +| arrays.cpp:42:3:42:3 | o | AST only | +| arrays.cpp:42:3:42:20 | access to array | AST only | +| arrays.cpp:42:5:42:12 | indirect | AST only | | arrays.cpp:42:22:42:25 | data | AST only | +| arrays.cpp:43:8:43:8 | o | AST only | +| arrays.cpp:43:8:43:25 | access to array | AST only | +| arrays.cpp:43:10:43:17 | indirect | AST only | | arrays.cpp:43:27:43:30 | data | AST only | +| arrays.cpp:44:8:44:8 | o | AST only | +| arrays.cpp:44:8:44:25 | access to array | AST only | +| arrays.cpp:44:10:44:17 | indirect | AST only | | arrays.cpp:44:27:44:30 | data | AST only | +| arrays.cpp:48:3:48:3 | o | AST only | +| arrays.cpp:48:3:48:20 | access to array | AST only | +| arrays.cpp:48:5:48:12 | indirect | AST only | | arrays.cpp:48:22:48:25 | data | AST only | +| arrays.cpp:49:8:49:8 | o | AST only | +| arrays.cpp:49:8:49:25 | access to array | AST only | +| arrays.cpp:49:10:49:17 | indirect | AST only | | arrays.cpp:49:27:49:30 | data | AST only | +| arrays.cpp:50:8:50:8 | o | AST only | +| arrays.cpp:50:8:50:25 | access to array | AST only | +| arrays.cpp:50:10:50:17 | indirect | AST only | | arrays.cpp:50:27:50:30 | data | AST only | | by_reference.cpp:12:8:12:8 | a | AST only | | by_reference.cpp:16:11:16:11 | a | AST only | @@ -200,8 +227,6 @@ | by_reference.cpp:20:23:20:27 | value | AST only | | by_reference.cpp:24:19:24:22 | this | AST only | | by_reference.cpp:24:25:24:29 | value | AST only | -| by_reference.cpp:32:15:32:15 | s | IR only | -| by_reference.cpp:36:18:36:18 | this | IR only | | by_reference.cpp:50:3:50:3 | s | AST only | | by_reference.cpp:50:17:50:26 | call to user_input | AST only | | by_reference.cpp:51:10:51:20 | call to getDirectly | AST only | @@ -219,63 +244,87 @@ | by_reference.cpp:92:3:92:5 | * ... | AST only | | by_reference.cpp:96:3:96:4 | pa | AST only | | by_reference.cpp:102:21:102:39 | & ... | AST only | +| by_reference.cpp:103:21:103:25 | outer | AST only | | by_reference.cpp:103:27:103:35 | inner_ptr | AST only | | by_reference.cpp:104:15:104:22 | & ... | AST only | | by_reference.cpp:106:21:106:41 | & ... | AST only | +| by_reference.cpp:107:21:107:26 | pouter | AST only | | by_reference.cpp:107:29:107:37 | inner_ptr | AST only | | by_reference.cpp:108:15:108:24 | & ... | AST only | +| by_reference.cpp:110:8:110:12 | outer | AST only | +| by_reference.cpp:110:14:110:25 | inner_nested | AST only | | by_reference.cpp:110:27:110:27 | a | AST only | +| by_reference.cpp:111:8:111:12 | outer | AST only | +| by_reference.cpp:111:14:111:22 | inner_ptr | AST only | | by_reference.cpp:111:25:111:25 | a | AST only | +| by_reference.cpp:112:8:112:12 | outer | AST only | | by_reference.cpp:112:14:112:14 | a | AST only | +| by_reference.cpp:114:8:114:13 | pouter | AST only | +| by_reference.cpp:114:16:114:27 | inner_nested | AST only | | by_reference.cpp:114:29:114:29 | a | AST only | +| by_reference.cpp:115:8:115:13 | pouter | AST only | +| by_reference.cpp:115:16:115:24 | inner_ptr | AST only | | by_reference.cpp:115:27:115:27 | a | AST only | +| by_reference.cpp:116:8:116:13 | pouter | AST only | | by_reference.cpp:116:16:116:16 | a | AST only | | by_reference.cpp:122:27:122:38 | inner_nested | AST only | | by_reference.cpp:123:21:123:36 | * ... | AST only | +| by_reference.cpp:123:22:123:26 | outer | AST only | | by_reference.cpp:124:21:124:21 | a | AST only | | by_reference.cpp:126:29:126:40 | inner_nested | AST only | | by_reference.cpp:127:21:127:38 | * ... | AST only | +| by_reference.cpp:127:22:127:27 | pouter | AST only | | by_reference.cpp:128:23:128:23 | a | AST only | +| by_reference.cpp:130:8:130:12 | outer | AST only | +| by_reference.cpp:130:14:130:25 | inner_nested | AST only | | by_reference.cpp:130:27:130:27 | a | AST only | +| by_reference.cpp:131:8:131:12 | outer | AST only | +| by_reference.cpp:131:14:131:22 | inner_ptr | AST only | | by_reference.cpp:131:25:131:25 | a | AST only | +| by_reference.cpp:132:8:132:12 | outer | AST only | | by_reference.cpp:132:14:132:14 | a | AST only | +| by_reference.cpp:134:8:134:13 | pouter | AST only | +| by_reference.cpp:134:16:134:27 | inner_nested | AST only | | by_reference.cpp:134:29:134:29 | a | AST only | +| by_reference.cpp:135:8:135:13 | pouter | AST only | +| by_reference.cpp:135:16:135:24 | inner_ptr | AST only | | by_reference.cpp:135:27:135:27 | a | AST only | +| by_reference.cpp:136:8:136:13 | pouter | AST only | | by_reference.cpp:136:16:136:16 | a | AST only | -| by_reference.cpp:140:3:140:5 | * ... | AST only | -| by_reference.cpp:145:15:145:16 | & ... | AST only | -| complex.cpp:9:20:9:21 | this | IR only | -| complex.cpp:10:20:10:21 | this | IR only | | complex.cpp:11:22:11:23 | a_ | AST only | | complex.cpp:12:22:12:23 | b_ | AST only | +| complex.cpp:42:8:42:8 | b | AST only | | complex.cpp:42:16:42:16 | f | AST only | +| complex.cpp:43:8:43:8 | b | AST only | | complex.cpp:43:16:43:16 | f | AST only | +| complex.cpp:53:3:53:4 | b1 | AST only | | complex.cpp:53:12:53:12 | f | AST only | +| complex.cpp:54:3:54:4 | b2 | AST only | | complex.cpp:54:12:54:12 | f | AST only | +| complex.cpp:55:3:55:4 | b3 | AST only | | complex.cpp:55:12:55:12 | f | AST only | +| complex.cpp:56:3:56:4 | b3 | AST only | | complex.cpp:56:12:56:12 | f | AST only | | complex.cpp:59:7:59:8 | b1 | AST only | | complex.cpp:62:7:62:8 | b2 | AST only | | complex.cpp:65:7:65:8 | b3 | AST only | | complex.cpp:68:7:68:8 | b4 | AST only | | conflated.cpp:10:3:10:7 | * ... | AST only | -| conflated.cpp:11:12:11:12 | ra | IR only | +| conflated.cpp:10:4:10:5 | ra | AST only | | conflated.cpp:19:19:19:21 | raw | AST only | | conflated.cpp:20:8:20:10 | raw | AST only | +| conflated.cpp:29:3:29:4 | pa | AST only | | conflated.cpp:29:7:29:7 | x | AST only | -| conflated.cpp:30:12:30:12 | pa | IR only | +| conflated.cpp:36:3:36:4 | pa | AST only | | conflated.cpp:36:7:36:7 | x | AST only | -| conflated.cpp:37:12:37:12 | pa | IR only | | conflated.cpp:53:7:53:10 | next | AST only | +| conflated.cpp:54:3:54:4 | ll | AST only | +| conflated.cpp:54:7:54:10 | next | AST only | | conflated.cpp:54:13:54:13 | y | AST only | -| conflated.cpp:55:12:55:15 | ll | IR only | -| conflated.cpp:55:18:55:18 | next | IR only | | conflated.cpp:59:35:59:38 | next | AST only | +| conflated.cpp:60:3:60:4 | ll | AST only | +| conflated.cpp:60:7:60:10 | next | AST only | | conflated.cpp:60:13:60:13 | y | AST only | -| conflated.cpp:61:12:61:15 | ll | IR only | -| conflated.cpp:61:18:61:18 | next | IR only | -| constructors.cpp:18:22:18:23 | this | IR only | -| constructors.cpp:19:22:19:23 | this | IR only | | constructors.cpp:20:24:20:25 | a_ | AST only | | constructors.cpp:21:24:21:25 | b_ | AST only | | constructors.cpp:28:10:28:10 | f | AST only | @@ -287,55 +336,68 @@ | qualifiers.cpp:9:36:9:36 | a | AST only | | qualifiers.cpp:12:56:12:56 | a | AST only | | qualifiers.cpp:13:57:13:57 | a | AST only | -| qualifiers.cpp:18:32:18:36 | this | IR only | | qualifiers.cpp:22:5:22:9 | outer | AST only | +| qualifiers.cpp:22:11:22:18 | call to getInner | AST only | | qualifiers.cpp:22:23:22:23 | a | AST only | +| qualifiers.cpp:23:10:23:14 | outer | AST only | +| qualifiers.cpp:23:16:23:20 | inner | AST only | | qualifiers.cpp:23:23:23:23 | a | AST only | | qualifiers.cpp:27:5:27:9 | outer | AST only | | qualifiers.cpp:27:11:27:18 | call to getInner | AST only | | qualifiers.cpp:27:28:27:37 | call to user_input | AST only | +| qualifiers.cpp:28:10:28:14 | outer | AST only | +| qualifiers.cpp:28:16:28:20 | inner | AST only | | qualifiers.cpp:28:23:28:23 | a | AST only | | qualifiers.cpp:32:17:32:21 | outer | AST only | | qualifiers.cpp:32:23:32:30 | call to getInner | AST only | | qualifiers.cpp:32:35:32:44 | call to user_input | AST only | +| qualifiers.cpp:33:10:33:14 | outer | AST only | +| qualifiers.cpp:33:16:33:20 | inner | AST only | | qualifiers.cpp:33:23:33:23 | a | AST only | | qualifiers.cpp:37:19:37:35 | * ... | AST only | | qualifiers.cpp:37:20:37:24 | outer | AST only | | qualifiers.cpp:37:38:37:47 | call to user_input | AST only | +| qualifiers.cpp:38:10:38:14 | outer | AST only | +| qualifiers.cpp:38:16:38:20 | inner | AST only | | qualifiers.cpp:38:23:38:23 | a | AST only | +| qualifiers.cpp:42:6:42:22 | * ... | AST only | | qualifiers.cpp:42:7:42:11 | outer | AST only | | qualifiers.cpp:42:25:42:25 | a | AST only | +| qualifiers.cpp:43:10:43:14 | outer | AST only | +| qualifiers.cpp:43:16:43:20 | inner | AST only | | qualifiers.cpp:43:23:43:23 | a | AST only | | qualifiers.cpp:47:6:47:11 | & ... | AST only | +| qualifiers.cpp:47:15:47:22 | call to getInner | AST only | | qualifiers.cpp:47:27:47:27 | a | AST only | +| qualifiers.cpp:48:10:48:14 | outer | AST only | +| qualifiers.cpp:48:16:48:20 | inner | AST only | | qualifiers.cpp:48:23:48:23 | a | AST only | | realistic.cpp:26:5:26:10 | offset | AST only | | realistic.cpp:42:20:42:20 | o | AST only | +| realistic.cpp:49:9:49:11 | foo | AST only | | realistic.cpp:49:20:49:22 | baz | AST only | +| realistic.cpp:53:9:53:11 | foo | AST only | +| realistic.cpp:53:9:53:18 | access to array | AST only | +| realistic.cpp:53:20:53:22 | baz | AST only | +| realistic.cpp:53:25:53:33 | userInput | AST only | | realistic.cpp:53:35:53:43 | bufferLen | AST only | +| realistic.cpp:54:16:54:18 | foo | AST only | +| realistic.cpp:54:16:54:25 | access to array | AST only | +| realistic.cpp:54:27:54:29 | baz | AST only | +| realistic.cpp:54:32:54:40 | userInput | AST only | | realistic.cpp:54:42:54:47 | buffer | AST only | -| realistic.cpp:55:16:55:18 | foo | IR only | -| realistic.cpp:55:23:55:25 | access to array | IR only | -| realistic.cpp:55:28:55:36 | baz | IR only | -| realistic.cpp:55:38:55:46 | userInput | IR only | -| realistic.cpp:57:92:57:94 | foo | IR only | -| realistic.cpp:57:99:57:101 | access to array | IR only | -| realistic.cpp:57:104:57:112 | baz | IR only | -| realistic.cpp:57:114:57:122 | userInput | IR only | | realistic.cpp:60:16:60:18 | dst | AST only | -| realistic.cpp:60:25:60:27 | foo | IR only | -| realistic.cpp:60:32:60:34 | access to array | IR only | -| realistic.cpp:60:37:60:45 | baz | IR only | -| realistic.cpp:60:47:60:52 | userInput | IR only | -| realistic.cpp:60:59:60:61 | foo | IR only | -| realistic.cpp:60:66:60:68 | access to array | IR only | -| realistic.cpp:60:71:60:79 | baz | IR only | -| realistic.cpp:60:81:60:89 | userInput | IR only | +| realistic.cpp:61:21:61:23 | foo | AST only | +| realistic.cpp:61:21:61:30 | access to array | AST only | +| realistic.cpp:61:32:61:34 | baz | AST only | +| realistic.cpp:61:37:61:45 | userInput | AST only | | realistic.cpp:61:47:61:55 | bufferLen | AST only | +| realistic.cpp:65:21:65:23 | foo | AST only | +| realistic.cpp:65:21:65:30 | access to array | AST only | +| realistic.cpp:65:32:65:34 | baz | AST only | +| realistic.cpp:65:37:65:45 | userInput | AST only | | realistic.cpp:65:47:65:52 | buffer | AST only | | realistic.cpp:66:21:66:23 | dst | AST only | -| simple.cpp:18:22:18:23 | this | IR only | -| simple.cpp:19:22:19:23 | this | IR only | | simple.cpp:20:24:20:25 | a_ | AST only | | simple.cpp:21:24:21:25 | b_ | AST only | | simple.cpp:28:10:28:10 | f | AST only | @@ -349,24 +411,31 @@ | simple.cpp:51:9:51:9 | h | AST only | | simple.cpp:54:9:54:9 | i | AST only | | simple.cpp:65:7:65:7 | i | AST only | -| simple.cpp:67:13:67:13 | a2 | IR only | -| simple.cpp:79:16:79:17 | this | IR only | -| simple.cpp:79:19:79:20 | f2 | IR only | +| simple.cpp:83:9:83:10 | this | AST only | | simple.cpp:83:12:83:13 | f1 | AST only | | simple.cpp:84:14:84:20 | this | AST only | | simple.cpp:92:7:92:7 | i | AST only | -| simple.cpp:94:13:94:13 | a2 | IR only | -| simple.cpp:104:9:104:9 | i | AST only | -| simple.cpp:106:13:106:13 | b2 | IR only | -| simple.cpp:106:15:106:15 | a | IR only | +| struct_init.c:15:8:15:9 | ab | AST only | | struct_init.c:15:12:15:12 | a | AST only | +| struct_init.c:16:8:16:9 | ab | AST only | | struct_init.c:16:12:16:12 | b | AST only | +| struct_init.c:22:8:22:9 | ab | AST only | | struct_init.c:22:11:22:11 | a | AST only | +| struct_init.c:23:8:23:9 | ab | AST only | | struct_init.c:23:11:23:11 | b | AST only | | struct_init.c:24:10:24:12 | & ... | AST only | +| struct_init.c:31:8:31:12 | outer | AST only | +| struct_init.c:31:14:31:21 | nestedAB | AST only | | struct_init.c:31:23:31:23 | a | AST only | +| struct_init.c:32:8:32:12 | outer | AST only | +| struct_init.c:32:14:32:21 | nestedAB | AST only | | struct_init.c:32:23:32:23 | b | AST only | +| struct_init.c:33:8:33:12 | outer | AST only | +| struct_init.c:33:14:33:22 | pointerAB | AST only | | struct_init.c:33:25:33:25 | a | AST only | +| struct_init.c:34:8:34:12 | outer | AST only | +| struct_init.c:34:14:34:22 | pointerAB | AST only | | struct_init.c:34:25:34:25 | b | AST only | | struct_init.c:36:10:36:24 | & ... | AST only | +| struct_init.c:46:10:46:14 | outer | AST only | | struct_init.c:46:16:46:24 | pointerAB | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index 437a36cc2ba..294c46a5694 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -1,338 +1,72 @@ | A.cpp:25:7:25:10 | this | | A.cpp:27:22:27:25 | this | -| A.cpp:28:23:28:26 | this | -| A.cpp:49:10:49:10 | b | -| A.cpp:65:10:65:11 | b1 | -| A.cpp:66:10:66:11 | b2 | -| A.cpp:74:10:74:11 | b1 | -| A.cpp:75:10:75:11 | b2 | | A.cpp:100:5:100:6 | c1 | -| A.cpp:107:12:107:13 | c1 | -| A.cpp:120:12:120:13 | c1 | -| A.cpp:132:10:132:10 | b | | A.cpp:142:7:142:7 | b | | A.cpp:143:7:143:10 | this | -| A.cpp:152:10:152:10 | d | -| A.cpp:153:10:153:10 | d | -| A.cpp:153:13:153:13 | b | -| A.cpp:154:10:154:10 | b | -| A.cpp:163:10:163:11 | l3 | -| A.cpp:164:10:164:11 | l3 | -| A.cpp:164:14:164:17 | next | -| A.cpp:165:10:165:11 | l3 | -| A.cpp:165:14:165:17 | next | -| A.cpp:165:20:165:23 | next | -| A.cpp:166:10:166:11 | l3 | -| A.cpp:166:14:166:17 | next | -| A.cpp:166:20:166:23 | next | -| A.cpp:166:26:166:29 | next | -| A.cpp:167:44:167:44 | l | -| A.cpp:169:12:169:12 | l | | A.cpp:183:7:183:10 | this | | A.cpp:184:7:184:10 | this | -| B.cpp:9:10:9:11 | b2 | -| B.cpp:9:14:9:17 | box1 | -| B.cpp:10:10:10:11 | b2 | -| B.cpp:10:14:10:17 | box1 | -| B.cpp:18:10:18:11 | b2 | -| B.cpp:18:14:18:17 | box1 | -| B.cpp:19:10:19:11 | b2 | -| B.cpp:19:14:19:17 | box1 | | B.cpp:35:7:35:10 | this | | B.cpp:36:7:36:10 | this | | B.cpp:46:7:46:10 | this | | C.cpp:24:5:24:8 | this | -| C.cpp:29:10:29:11 | this | -| C.cpp:30:10:30:11 | this | -| C.cpp:31:10:31:11 | this | | D.cpp:9:21:9:24 | this | -| D.cpp:10:30:10:33 | this | | D.cpp:11:29:11:32 | this | | D.cpp:16:21:16:23 | this | -| D.cpp:17:30:17:32 | this | | D.cpp:18:29:18:31 | this | -| D.cpp:30:5:30:5 | b | -| D.cpp:30:8:30:10 | box | -| D.cpp:37:5:37:5 | b | -| D.cpp:44:8:44:14 | call to getBox1 | | D.cpp:57:5:57:12 | this | -| D.cpp:58:5:58:12 | boxfield | -| D.cpp:58:5:58:12 | this | -| D.cpp:58:15:58:17 | box | -| D.cpp:64:10:64:17 | boxfield | -| D.cpp:64:10:64:17 | this | -| D.cpp:64:20:64:22 | box | -| E.cpp:21:10:21:10 | p | -| E.cpp:21:13:21:16 | data | -| E.cpp:29:21:29:21 | b | -| E.cpp:30:21:30:21 | p | -| E.cpp:30:23:30:26 | data | -| E.cpp:32:10:32:10 | b | | aliasing.cpp:9:3:9:3 | s | | aliasing.cpp:13:3:13:3 | s | | aliasing.cpp:17:3:17:3 | s | -| aliasing.cpp:29:8:29:9 | s1 | -| aliasing.cpp:30:8:30:9 | s2 | -| aliasing.cpp:31:8:31:9 | s3 | | aliasing.cpp:37:3:37:6 | ref1 | -| aliasing.cpp:38:8:38:9 | s1 | | aliasing.cpp:42:3:42:4 | s2 | -| aliasing.cpp:43:8:43:11 | ref2 | | aliasing.cpp:49:3:49:7 | copy1 | -| aliasing.cpp:50:8:50:9 | s1 | | aliasing.cpp:54:3:54:4 | s2 | -| aliasing.cpp:55:8:55:12 | copy2 | | aliasing.cpp:60:3:60:4 | s2 | -| aliasing.cpp:62:8:62:12 | copy2 | -| aliasing.cpp:71:9:71:9 | w | | aliasing.cpp:72:3:72:3 | s | -| aliasing.cpp:73:8:73:8 | w | -| aliasing.cpp:73:10:73:10 | s | -| aliasing.cpp:78:11:78:11 | w | | aliasing.cpp:79:3:79:3 | s | -| aliasing.cpp:80:8:80:8 | w | -| aliasing.cpp:80:10:80:10 | s | -| aliasing.cpp:85:10:85:10 | w | | aliasing.cpp:86:3:86:3 | s | -| aliasing.cpp:87:8:87:8 | w | -| aliasing.cpp:87:10:87:10 | s | -| aliasing.cpp:92:3:92:3 | w | | aliasing.cpp:92:5:92:5 | s | -| aliasing.cpp:93:8:93:8 | w | -| aliasing.cpp:93:10:93:10 | s | | aliasing.cpp:98:3:98:3 | s | -| aliasing.cpp:101:14:101:19 | s_copy | | aliasing.cpp:111:16:111:16 | s | -| aliasing.cpp:112:8:112:8 | s | -| aliasing.cpp:141:15:141:15 | s | -| aliasing.cpp:143:8:143:8 | s | | aliasing.cpp:147:16:147:19 | access to array | -| aliasing.cpp:148:8:148:11 | access to array | -| aliasing.cpp:158:15:158:15 | s | -| aliasing.cpp:159:9:159:9 | s | -| aliasing.cpp:164:15:164:15 | s | -| aliasing.cpp:165:8:165:8 | s | -| aliasing.cpp:175:16:175:17 | s2 | | aliasing.cpp:175:19:175:19 | s | -| aliasing.cpp:176:8:176:9 | s2 | -| aliasing.cpp:176:11:176:11 | s | -| aliasing.cpp:181:16:181:17 | s2 | | aliasing.cpp:181:19:181:19 | s | -| aliasing.cpp:182:8:182:9 | s2 | -| aliasing.cpp:182:11:182:11 | s | -| aliasing.cpp:187:16:187:17 | s2 | | aliasing.cpp:187:19:187:19 | s | -| aliasing.cpp:189:8:189:11 | s2_2 | -| aliasing.cpp:189:13:189:13 | s | -| aliasing.cpp:194:16:194:17 | s2 | | aliasing.cpp:194:19:194:19 | s | -| aliasing.cpp:196:8:196:11 | s2_2 | -| aliasing.cpp:196:13:196:13 | s | -| aliasing.cpp:200:16:200:18 | ps2 | | aliasing.cpp:200:21:200:21 | s | -| aliasing.cpp:201:8:201:10 | ps2 | -| aliasing.cpp:201:13:201:13 | s | -| aliasing.cpp:205:16:205:18 | ps2 | | aliasing.cpp:205:21:205:21 | s | -| aliasing.cpp:206:8:206:10 | ps2 | -| aliasing.cpp:206:13:206:13 | s | -| aliasing.cpp:211:3:211:4 | s2 | -| aliasing.cpp:211:6:211:6 | s | -| aliasing.cpp:212:9:212:10 | s2 | -| aliasing.cpp:213:8:213:8 | s | -| aliasing.cpp:218:3:218:4 | s2 | -| aliasing.cpp:218:6:218:6 | s | -| aliasing.cpp:219:9:219:10 | s2 | -| aliasing.cpp:220:8:220:8 | s | -| aliasing.cpp:225:16:225:17 | s2 | -| aliasing.cpp:225:19:225:19 | s | -| aliasing.cpp:226:9:226:10 | s2 | -| aliasing.cpp:227:8:227:8 | s | -| aliasing.cpp:232:16:232:17 | s2 | -| aliasing.cpp:232:19:232:19 | s | -| aliasing.cpp:233:9:233:10 | s2 | -| aliasing.cpp:234:8:234:8 | s | | arrays.cpp:6:3:6:5 | arr | -| arrays.cpp:36:3:36:3 | o | | arrays.cpp:36:3:36:17 | access to array | -| arrays.cpp:36:5:36:10 | nested | -| arrays.cpp:37:8:37:8 | o | -| arrays.cpp:37:8:37:22 | access to array | -| arrays.cpp:37:10:37:15 | nested | -| arrays.cpp:38:8:38:8 | o | -| arrays.cpp:38:8:38:22 | access to array | -| arrays.cpp:38:10:38:15 | nested | -| arrays.cpp:42:3:42:3 | o | -| arrays.cpp:42:3:42:20 | access to array | -| arrays.cpp:42:5:42:12 | indirect | -| arrays.cpp:43:8:43:8 | o | -| arrays.cpp:43:8:43:25 | access to array | -| arrays.cpp:43:10:43:17 | indirect | -| arrays.cpp:44:8:44:8 | o | -| arrays.cpp:44:8:44:25 | access to array | -| arrays.cpp:44:10:44:17 | indirect | -| arrays.cpp:48:3:48:3 | o | -| arrays.cpp:48:3:48:20 | access to array | -| arrays.cpp:48:5:48:12 | indirect | -| arrays.cpp:49:8:49:8 | o | -| arrays.cpp:49:8:49:25 | access to array | -| arrays.cpp:49:10:49:17 | indirect | -| arrays.cpp:50:8:50:8 | o | -| arrays.cpp:50:8:50:25 | access to array | -| arrays.cpp:50:10:50:17 | indirect | | by_reference.cpp:12:5:12:5 | s | | by_reference.cpp:16:5:16:8 | this | -| by_reference.cpp:32:12:32:12 | s | -| by_reference.cpp:36:12:36:15 | this | | by_reference.cpp:84:3:84:7 | inner | | by_reference.cpp:88:3:88:7 | inner | | by_reference.cpp:102:22:102:26 | outer | -| by_reference.cpp:103:21:103:25 | outer | | by_reference.cpp:104:16:104:20 | outer | | by_reference.cpp:106:22:106:27 | pouter | -| by_reference.cpp:107:21:107:26 | pouter | | by_reference.cpp:108:16:108:21 | pouter | -| by_reference.cpp:110:8:110:12 | outer | -| by_reference.cpp:110:14:110:25 | inner_nested | -| by_reference.cpp:111:8:111:12 | outer | -| by_reference.cpp:111:14:111:22 | inner_ptr | -| by_reference.cpp:112:8:112:12 | outer | -| by_reference.cpp:114:8:114:13 | pouter | -| by_reference.cpp:114:16:114:27 | inner_nested | -| by_reference.cpp:115:8:115:13 | pouter | -| by_reference.cpp:115:16:115:24 | inner_ptr | -| by_reference.cpp:116:8:116:13 | pouter | | by_reference.cpp:122:21:122:25 | outer | -| by_reference.cpp:123:22:123:26 | outer | | by_reference.cpp:124:15:124:19 | outer | | by_reference.cpp:126:21:126:26 | pouter | -| by_reference.cpp:127:22:127:27 | pouter | | by_reference.cpp:128:15:128:20 | pouter | -| by_reference.cpp:130:8:130:12 | outer | -| by_reference.cpp:130:14:130:25 | inner_nested | -| by_reference.cpp:131:8:131:12 | outer | -| by_reference.cpp:131:14:131:22 | inner_ptr | -| by_reference.cpp:132:8:132:12 | outer | -| by_reference.cpp:134:8:134:13 | pouter | -| by_reference.cpp:134:16:134:27 | inner_nested | -| by_reference.cpp:135:8:135:13 | pouter | -| by_reference.cpp:135:16:135:24 | inner_ptr | -| by_reference.cpp:136:8:136:13 | pouter | -| complex.cpp:9:20:9:21 | this | -| complex.cpp:10:20:10:21 | this | | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | this | -| complex.cpp:42:8:42:8 | b | | complex.cpp:42:10:42:14 | inner | -| complex.cpp:43:8:43:8 | b | | complex.cpp:43:10:43:14 | inner | -| complex.cpp:53:3:53:4 | b1 | | complex.cpp:53:6:53:10 | inner | -| complex.cpp:54:3:54:4 | b2 | | complex.cpp:54:6:54:10 | inner | -| complex.cpp:55:3:55:4 | b3 | | complex.cpp:55:6:55:10 | inner | -| complex.cpp:56:3:56:4 | b3 | | complex.cpp:56:6:56:10 | inner | -| conflated.cpp:10:4:10:5 | ra | -| conflated.cpp:11:9:11:10 | ra | -| conflated.cpp:29:3:29:4 | pa | -| conflated.cpp:30:8:30:9 | pa | -| conflated.cpp:36:3:36:4 | pa | -| conflated.cpp:37:8:37:9 | pa | | conflated.cpp:53:3:53:4 | ll | -| conflated.cpp:54:3:54:4 | ll | -| conflated.cpp:54:7:54:10 | next | -| conflated.cpp:55:8:55:9 | ll | -| conflated.cpp:55:12:55:15 | next | -| conflated.cpp:60:3:60:4 | ll | -| conflated.cpp:60:7:60:10 | next | -| conflated.cpp:61:8:61:9 | ll | -| conflated.cpp:61:12:61:15 | next | -| constructors.cpp:18:22:18:23 | this | -| constructors.cpp:19:22:19:23 | this | | constructors.cpp:20:24:20:25 | this | | constructors.cpp:21:24:21:25 | this | | qualifiers.cpp:9:30:9:33 | this | | qualifiers.cpp:12:49:12:53 | inner | | qualifiers.cpp:13:51:13:55 | inner | -| qualifiers.cpp:18:32:18:36 | this | -| qualifiers.cpp:22:11:22:18 | call to getInner | -| qualifiers.cpp:23:10:23:14 | outer | -| qualifiers.cpp:23:16:23:20 | inner | -| qualifiers.cpp:28:10:28:14 | outer | -| qualifiers.cpp:28:16:28:20 | inner | -| qualifiers.cpp:33:10:33:14 | outer | -| qualifiers.cpp:33:16:33:20 | inner | -| qualifiers.cpp:38:10:38:14 | outer | -| qualifiers.cpp:38:16:38:20 | inner | -| qualifiers.cpp:42:6:42:22 | * ... | -| qualifiers.cpp:43:10:43:14 | outer | -| qualifiers.cpp:43:16:43:20 | inner | -| qualifiers.cpp:47:15:47:22 | call to getInner | -| qualifiers.cpp:48:10:48:14 | outer | -| qualifiers.cpp:48:16:48:20 | inner | -| realistic.cpp:49:9:49:11 | foo | | realistic.cpp:49:9:49:18 | access to array | -| realistic.cpp:53:9:53:11 | foo | -| realistic.cpp:53:9:53:18 | access to array | -| realistic.cpp:53:20:53:22 | baz | -| realistic.cpp:53:25:53:33 | userInput | -| realistic.cpp:54:16:54:18 | foo | -| realistic.cpp:54:16:54:25 | access to array | -| realistic.cpp:54:27:54:29 | baz | -| realistic.cpp:54:32:54:40 | userInput | -| realistic.cpp:55:12:55:14 | foo | -| realistic.cpp:55:12:55:21 | access to array | -| realistic.cpp:55:23:55:25 | baz | -| realistic.cpp:55:28:55:36 | userInput | -| realistic.cpp:57:88:57:90 | foo | -| realistic.cpp:57:88:57:97 | access to array | -| realistic.cpp:57:99:57:101 | baz | -| realistic.cpp:57:104:57:112 | userInput | -| realistic.cpp:60:21:60:23 | foo | -| realistic.cpp:60:21:60:30 | access to array | -| realistic.cpp:60:32:60:34 | baz | -| realistic.cpp:60:37:60:45 | userInput | -| realistic.cpp:60:55:60:57 | foo | -| realistic.cpp:60:55:60:64 | access to array | -| realistic.cpp:60:66:60:68 | baz | -| realistic.cpp:60:71:60:79 | userInput | -| realistic.cpp:61:21:61:23 | foo | -| realistic.cpp:61:21:61:30 | access to array | -| realistic.cpp:61:32:61:34 | baz | -| realistic.cpp:61:37:61:45 | userInput | -| realistic.cpp:65:21:65:23 | foo | -| realistic.cpp:65:21:65:30 | access to array | -| realistic.cpp:65:32:65:34 | baz | -| realistic.cpp:65:37:65:45 | userInput | -| simple.cpp:18:22:18:23 | this | -| simple.cpp:19:22:19:23 | this | | simple.cpp:20:24:20:25 | this | | simple.cpp:21:24:21:25 | this | | simple.cpp:65:5:65:5 | a | -| simple.cpp:67:10:67:11 | a2 | -| simple.cpp:79:16:79:17 | f2 | -| simple.cpp:79:16:79:17 | this | | simple.cpp:83:9:83:10 | f2 | -| simple.cpp:83:9:83:10 | this | | simple.cpp:92:5:92:5 | a | -| simple.cpp:94:10:94:11 | a2 | -| simple.cpp:104:5:104:5 | b | -| simple.cpp:104:7:104:7 | a | -| simple.cpp:106:10:106:11 | b2 | -| simple.cpp:106:13:106:13 | a | -| struct_init.c:15:8:15:9 | ab | -| struct_init.c:16:8:16:9 | ab | -| struct_init.c:22:8:22:9 | ab | -| struct_init.c:23:8:23:9 | ab | -| struct_init.c:31:8:31:12 | outer | -| struct_init.c:31:14:31:21 | nestedAB | -| struct_init.c:32:8:32:12 | outer | -| struct_init.c:32:14:32:21 | nestedAB | -| struct_init.c:33:8:33:12 | outer | -| struct_init.c:33:14:33:22 | pointerAB | -| struct_init.c:34:8:34:12 | outer | -| struct_init.c:34:14:34:22 | pointerAB | | struct_init.c:36:11:36:15 | outer | -| struct_init.c:46:10:46:14 | outer | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected index 9821d527b87..9b03e4f8039 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -220,18 +220,6 @@ | aliasing.cpp:205:15:205:24 | & ... | | aliasing.cpp:205:16:205:18 | ps2 | | aliasing.cpp:205:21:205:21 | s | -| aliasing.cpp:211:3:211:4 | s2 | -| aliasing.cpp:211:6:211:6 | s | -| aliasing.cpp:211:8:211:9 | m1 | -| aliasing.cpp:218:3:218:4 | s2 | -| aliasing.cpp:218:6:218:6 | s | -| aliasing.cpp:218:8:218:9 | m1 | -| aliasing.cpp:225:15:225:22 | & ... | -| aliasing.cpp:225:16:225:17 | s2 | -| aliasing.cpp:225:19:225:19 | s | -| aliasing.cpp:232:15:232:22 | & ... | -| aliasing.cpp:232:16:232:17 | s2 | -| aliasing.cpp:232:19:232:19 | s | | arrays.cpp:6:3:6:8 | access to array | | arrays.cpp:15:3:15:10 | * ... | | arrays.cpp:36:3:36:3 | o | @@ -352,8 +340,6 @@ | by_reference.cpp:135:27:135:27 | a | | by_reference.cpp:136:8:136:13 | pouter | | by_reference.cpp:136:16:136:16 | a | -| by_reference.cpp:140:3:140:5 | * ... | -| by_reference.cpp:145:15:145:16 | & ... | | complex.cpp:11:22:11:23 | a_ | | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | b_ | @@ -498,9 +484,6 @@ | simple.cpp:84:14:84:20 | this | | simple.cpp:92:5:92:5 | a | | simple.cpp:92:7:92:7 | i | -| simple.cpp:104:5:104:5 | b | -| simple.cpp:104:7:104:7 | a | -| simple.cpp:104:9:104:9 | i | | struct_init.c:15:8:15:9 | ab | | struct_init.c:15:12:15:12 | a | | struct_init.c:16:8:16:9 | ab | diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected index 6ea374d0ddf..6604dde87d4 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -160,7 +160,6 @@ edges | aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:175:15:175:22 | ref arg & ... | | aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:187:15:187:22 | ref arg & ... | | aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:200:15:200:24 | ref arg & ... | -| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:225:15:225:22 | ref arg & ... | | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:4:106:5 | pa [inner post update] | | aliasing.cpp:158:15:158:15 | s [post update] [data] | aliasing.cpp:159:9:159:9 | s [data] | | aliasing.cpp:158:17:158:20 | ref arg data | aliasing.cpp:158:15:158:15 | s [post update] [data] | @@ -188,20 +187,6 @@ edges | aliasing.cpp:200:23:200:24 | m1 [inner post update] | aliasing.cpp:200:21:200:21 | s [post update] [m1] | | aliasing.cpp:201:8:201:10 | ps2 [s, m1] | aliasing.cpp:201:13:201:13 | s [m1] | | aliasing.cpp:201:13:201:13 | s [m1] | aliasing.cpp:201:15:201:16 | m1 | -| aliasing.cpp:211:3:211:4 | s2 [post update] [s, m1] | aliasing.cpp:212:9:212:10 | s2 [s, m1] | -| aliasing.cpp:211:3:211:24 | ... = ... | aliasing.cpp:211:6:211:6 | s [post update] [m1] | -| aliasing.cpp:211:6:211:6 | s [post update] [m1] | aliasing.cpp:211:3:211:4 | s2 [post update] [s, m1] | -| aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:211:3:211:24 | ... = ... | -| aliasing.cpp:212:9:212:10 | s2 [s, m1] | aliasing.cpp:212:12:212:12 | s [m1] | -| aliasing.cpp:212:12:212:12 | s [m1] | aliasing.cpp:213:8:213:8 | s [m1] | -| aliasing.cpp:213:8:213:8 | s [m1] | aliasing.cpp:213:10:213:11 | m1 | -| aliasing.cpp:225:15:225:22 | ref arg & ... | aliasing.cpp:225:21:225:22 | m1 [inner post update] | -| aliasing.cpp:225:16:225:17 | s2 [post update] [s, m1] | aliasing.cpp:226:9:226:10 | s2 [s, m1] | -| aliasing.cpp:225:19:225:19 | s [post update] [m1] | aliasing.cpp:225:16:225:17 | s2 [post update] [s, m1] | -| aliasing.cpp:225:21:225:22 | m1 [inner post update] | aliasing.cpp:225:19:225:19 | s [post update] [m1] | -| aliasing.cpp:226:9:226:10 | s2 [s, m1] | aliasing.cpp:226:12:226:12 | s [m1] | -| aliasing.cpp:226:12:226:12 | s [m1] | aliasing.cpp:227:8:227:8 | s [m1] | -| aliasing.cpp:227:8:227:8 | s [m1] | aliasing.cpp:227:10:227:11 | m1 | | 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:8:8:8:13 | access to array | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | @@ -323,9 +308,6 @@ edges | by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] | | by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a | | by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a | -| by_reference.cpp:140:4:140:5 | pa [inner post update] | by_reference.cpp:145:15:145:16 | ref arg & ... | -| by_reference.cpp:140:16:140:25 | call to user_input | by_reference.cpp:140:4:140:5 | pa [inner post update] | -| by_reference.cpp:145:15:145:16 | ref arg & ... | by_reference.cpp:146:8:146:8 | s | | complex.cpp:40:17:40:17 | b [inner, f, a_] | complex.cpp:42:8:42:8 | b [inner, f, a_] | | complex.cpp:40:17:40:17 | b [inner, f, b_] | complex.cpp:43:8:43:8 | b [inner, f, b_] | | complex.cpp:42:8:42:8 | b [inner, f, a_] | complex.cpp:42:10:42:14 | inner [f, a_] | @@ -467,12 +449,6 @@ edges | simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] | | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | | simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i | -| simple.cpp:104:5:104:5 | b [post update] [a, i] | simple.cpp:106:10:106:11 | b2 [a, i] | -| simple.cpp:104:5:104:24 | ... = ... | simple.cpp:104:7:104:7 | a [post update] [i] | -| simple.cpp:104:7:104:7 | a [post update] [i] | simple.cpp:104:5:104:5 | b [post update] [a, i] | -| simple.cpp:104:13:104:22 | call to user_input | simple.cpp:104:5:104:24 | ... = ... | -| simple.cpp:106:10:106:11 | b2 [a, i] | simple.cpp:106:13:106:13 | a [i] | -| simple.cpp:106:13:106:13 | a [i] | simple.cpp:106:15:106:15 | i | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | @@ -713,22 +689,6 @@ nodes | aliasing.cpp:201:8:201:10 | ps2 [s, m1] | semmle.label | ps2 [s, m1] | | aliasing.cpp:201:13:201:13 | s [m1] | semmle.label | s [m1] | | aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 | -| aliasing.cpp:211:3:211:4 | s2 [post update] [s, m1] | semmle.label | s2 [post update] [s, m1] | -| aliasing.cpp:211:3:211:24 | ... = ... | semmle.label | ... = ... | -| aliasing.cpp:211:6:211:6 | s [post update] [m1] | semmle.label | s [post update] [m1] | -| aliasing.cpp:211:13:211:22 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:212:9:212:10 | s2 [s, m1] | semmle.label | s2 [s, m1] | -| aliasing.cpp:212:12:212:12 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:213:8:213:8 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:213:10:213:11 | m1 | semmle.label | m1 | -| aliasing.cpp:225:15:225:22 | ref arg & ... | semmle.label | ref arg & ... | -| aliasing.cpp:225:16:225:17 | s2 [post update] [s, m1] | semmle.label | s2 [post update] [s, m1] | -| aliasing.cpp:225:19:225:19 | s [post update] [m1] | semmle.label | s [post update] [m1] | -| aliasing.cpp:225:21:225:22 | m1 [inner post update] | semmle.label | m1 [inner post update] | -| aliasing.cpp:226:9:226:10 | s2 [s, m1] | semmle.label | s2 [s, m1] | -| aliasing.cpp:226:12:226:12 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:227:8:227:8 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:227:10:227:11 | 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 | | arrays.cpp:8:8:8:13 | access to array | semmle.label | access to array | @@ -858,10 +818,6 @@ nodes | by_reference.cpp:135:27:135:27 | a | semmle.label | a | | by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] | | by_reference.cpp:136:16:136:16 | a | semmle.label | a | -| by_reference.cpp:140:4:140:5 | pa [inner post update] | semmle.label | pa [inner post update] | -| by_reference.cpp:140:16:140:25 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:145:15:145:16 | ref arg & ... | semmle.label | ref arg & ... | -| by_reference.cpp:146:8:146:8 | s | semmle.label | s | | complex.cpp:40:17:40:17 | b [inner, f, a_] | semmle.label | b [inner, f, a_] | | complex.cpp:40:17:40:17 | b [inner, f, b_] | semmle.label | b [inner, f, b_] | | complex.cpp:42:8:42:8 | b [inner, f, a_] | semmle.label | b [inner, f, a_] | @@ -1024,13 +980,6 @@ nodes | simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] | | simple.cpp:94:13:94:13 | i | semmle.label | i | -| simple.cpp:104:5:104:5 | b [post update] [a, i] | semmle.label | b [post update] [a, i] | -| simple.cpp:104:5:104:24 | ... = ... | semmle.label | ... = ... | -| simple.cpp:104:7:104:7 | a [post update] [i] | semmle.label | a [post update] [i] | -| simple.cpp:104:13:104:22 | call to user_input | semmle.label | call to user_input | -| simple.cpp:106:10:106:11 | b2 [a, i] | semmle.label | b2 [a, i] | -| simple.cpp:106:13:106:13 | a [i] | semmle.label | a [i] | -| simple.cpp:106:15:106:15 | i | semmle.label | i | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -1096,8 +1045,6 @@ nodes | aliasing.cpp:176:13:176:14 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:176:13:176:14 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:189:15:189:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:189:15:189:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:201:15:201:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:201:15:201:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | -| aliasing.cpp:213:10:213:11 | m1 | aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:213:10:213:11 | m1 | m1 flows from $@ | aliasing.cpp:211:13:211:22 | call to user_input | call to user_input | -| aliasing.cpp:227:10:227:11 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:227:10:227:11 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | 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:7:8:7:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:8:8:8:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:9:8:9:11 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | @@ -1124,7 +1071,6 @@ nodes | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | -| by_reference.cpp:146:8:146:8 | s | by_reference.cpp:140:16:140:25 | call to user_input | by_reference.cpp:146:8:146:8 | s | s flows from $@ | by_reference.cpp:140:16:140:25 | call to user_input | call to user_input | | complex.cpp:42:18:42:18 | call to a | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:53:19:53:28 | call to user_input | call to user_input | | complex.cpp:42:18:42:18 | call to a | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:55:19:55:28 | call to user_input | call to user_input | | complex.cpp:43:18:43:18 | call to b | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:43:18:43:18 | call to b | call to b flows from $@ | complex.cpp:54:19:54:28 | call to user_input | call to user_input | @@ -1152,7 +1098,6 @@ nodes | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | | simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input | -| simple.cpp:106:15:106:15 | i | simple.cpp:104:13:104:22 | call to user_input | simple.cpp:106:15:106:15 | i | i flows from $@ | simple.cpp:104:13:104:22 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 829974a1b67..e4d4f70edb0 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -94,16 +94,4 @@ void single_field_test_typedef(A_typedef a) sink(a2.i); //$ ast,ir } -struct B { - A a; -}; - -void single_field_test_depth_2() -{ - B b; - b.a.i = user_input(); - B b2 = b; - sink(b2.a.i); //$ ast MISSING: ir -} - } // namespace Simple diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index 9f038101d67..56f3dceecf9 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3197,6 +3197,56 @@ | standalone_iterators.cpp:90:8:90:8 | call to operator-- | standalone_iterators.cpp:90:5:90:5 | call to operator* | TAINT | | standalone_iterators.cpp:90:8:90:8 | ref arg call to operator-- | standalone_iterators.cpp:90:6:90:7 | ref arg i2 | | | standalone_iterators.cpp:90:13:90:13 | 0 | standalone_iterators.cpp:90:5:90:5 | ref arg call to operator* | TAINT | +| standalone_iterators.cpp:98:15:98:16 | call to container | standalone_iterators.cpp:101:6:101:7 | c1 | | +| standalone_iterators.cpp:98:15:98:16 | call to container | standalone_iterators.cpp:102:6:102:7 | c1 | | +| standalone_iterators.cpp:98:15:98:16 | call to container | standalone_iterators.cpp:106:6:106:7 | c1 | | +| standalone_iterators.cpp:98:15:98:16 | call to container | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:101:6:101:7 | c1 | standalone_iterators.cpp:101:9:101:13 | call to begin | TAINT | +| standalone_iterators.cpp:101:6:101:7 | ref arg c1 | standalone_iterators.cpp:102:6:102:7 | c1 | | +| standalone_iterators.cpp:101:6:101:7 | ref arg c1 | standalone_iterators.cpp:106:6:106:7 | c1 | | +| standalone_iterators.cpp:101:6:101:7 | ref arg c1 | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:101:9:101:13 | call to begin | standalone_iterators.cpp:101:2:101:15 | ... = ... | | +| standalone_iterators.cpp:101:9:101:13 | call to begin | standalone_iterators.cpp:103:3:103:3 | a | | +| standalone_iterators.cpp:101:9:101:13 | call to begin | standalone_iterators.cpp:104:7:104:7 | a | | +| standalone_iterators.cpp:102:6:102:7 | c1 | standalone_iterators.cpp:102:9:102:13 | call to begin | TAINT | +| standalone_iterators.cpp:102:6:102:7 | ref arg c1 | standalone_iterators.cpp:106:6:106:7 | c1 | | +| standalone_iterators.cpp:102:6:102:7 | ref arg c1 | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:102:9:102:13 | call to begin | standalone_iterators.cpp:102:2:102:15 | ... = ... | | +| standalone_iterators.cpp:102:9:102:13 | call to begin | standalone_iterators.cpp:107:7:107:7 | b | | +| standalone_iterators.cpp:103:2:103:2 | ref arg call to operator* | standalone_iterators.cpp:103:3:103:3 | ref arg a | TAINT | +| standalone_iterators.cpp:103:2:103:2 | ref arg call to operator* | standalone_iterators.cpp:106:6:106:7 | c1 | | +| standalone_iterators.cpp:103:2:103:2 | ref arg call to operator* | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:103:3:103:3 | a | standalone_iterators.cpp:103:2:103:2 | call to operator* | TAINT | +| standalone_iterators.cpp:103:3:103:3 | ref arg a | standalone_iterators.cpp:104:7:104:7 | a | | +| standalone_iterators.cpp:103:7:103:12 | call to source | standalone_iterators.cpp:103:2:103:2 | ref arg call to operator* | TAINT | +| standalone_iterators.cpp:104:7:104:7 | a [post update] | standalone_iterators.cpp:106:6:106:7 | c1 | | +| standalone_iterators.cpp:104:7:104:7 | a [post update] | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:106:6:106:7 | c1 | standalone_iterators.cpp:106:9:106:13 | call to begin | TAINT | +| standalone_iterators.cpp:106:6:106:7 | ref arg c1 | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:106:9:106:13 | call to begin | standalone_iterators.cpp:106:2:106:15 | ... = ... | | +| standalone_iterators.cpp:106:9:106:13 | call to begin | standalone_iterators.cpp:108:7:108:7 | c | | +| standalone_iterators.cpp:107:7:107:7 | b [post update] | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:108:7:108:7 | c [post update] | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:113:15:113:16 | call to container | standalone_iterators.cpp:116:7:116:8 | c1 | | +| standalone_iterators.cpp:113:15:113:16 | call to container | standalone_iterators.cpp:122:7:122:8 | c1 | | +| standalone_iterators.cpp:116:7:116:8 | c1 | standalone_iterators.cpp:116:10:116:14 | call to begin | TAINT | +| standalone_iterators.cpp:116:7:116:8 | ref arg c1 | standalone_iterators.cpp:122:7:122:8 | c1 | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:116:2:116:16 | ... = ... | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:117:7:117:8 | it | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:118:2:118:3 | it | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:119:7:119:8 | it | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:120:2:120:3 | it | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:121:7:121:8 | it | | +| standalone_iterators.cpp:117:7:117:8 | it [post update] | standalone_iterators.cpp:122:7:122:8 | c1 | | +| standalone_iterators.cpp:118:2:118:3 | it | standalone_iterators.cpp:118:5:118:5 | call to operator+= | | +| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:119:7:119:8 | it | | +| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:120:2:120:3 | it | | +| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | | +| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:122:7:122:8 | c1 | | +| standalone_iterators.cpp:118:8:118:8 | 1 | standalone_iterators.cpp:118:2:118:3 | ref arg it | TAINT | +| standalone_iterators.cpp:120:2:120:3 | it | standalone_iterators.cpp:120:5:120:5 | call to operator+= | | +| standalone_iterators.cpp:120:2:120:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | | +| standalone_iterators.cpp:120:8:120:13 | call to source | standalone_iterators.cpp:120:2:120:3 | ref arg it | TAINT | | stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT | | stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT | | stl.h:75:8:75:8 | this | stl.h:75:8:75:8 | constructor init of field container [pre-this] | | @@ -3876,12 +3926,12 @@ | string.cpp:408:8:408:9 | i2 | string.cpp:409:10:409:11 | i7 | | | string.cpp:409:10:409:11 | i7 | string.cpp:409:12:409:12 | call to operator+= | | | string.cpp:409:12:409:12 | call to operator+= | string.cpp:409:8:409:8 | call to operator* | TAINT | -| string.cpp:409:14:409:14 | 1 | string.cpp:409:12:409:12 | call to operator+= | | +| string.cpp:409:14:409:14 | 1 | string.cpp:409:10:409:11 | ref arg i7 | TAINT | | string.cpp:410:8:410:9 | i2 | string.cpp:410:3:410:9 | ... = ... | | | string.cpp:410:8:410:9 | i2 | string.cpp:411:10:411:11 | i8 | | | string.cpp:411:10:411:11 | i8 | string.cpp:411:12:411:12 | call to operator-= | | | string.cpp:411:12:411:12 | call to operator-= | string.cpp:411:8:411:8 | call to operator* | TAINT | -| string.cpp:411:14:411:14 | 1 | string.cpp:411:12:411:12 | call to operator-= | | +| string.cpp:411:14:411:14 | 1 | string.cpp:411:10:411:11 | ref arg i8 | TAINT | | string.cpp:413:8:413:9 | s2 | string.cpp:413:11:413:13 | call to end | TAINT | | string.cpp:413:11:413:13 | call to end | string.cpp:413:3:413:15 | ... = ... | | | string.cpp:413:11:413:13 | call to end | string.cpp:414:5:414:6 | i9 | | @@ -6042,6 +6092,21 @@ | taint.cpp:631:6:631:14 | call to _strnextc | taint.cpp:631:2:631:18 | ... = ... | | | taint.cpp:631:6:631:14 | call to _strnextc | taint.cpp:632:7:632:7 | c | | | taint.cpp:631:16:631:17 | | taint.cpp:631:6:631:14 | call to _strnextc | TAINT | +| taint.cpp:640:9:640:12 | this | taint.cpp:640:25:640:29 | this | | +| taint.cpp:643:33:643:38 | source | taint.cpp:645:20:645:25 | source | | +| taint.cpp:644:30:644:30 | c | taint.cpp:645:10:645:10 | c | | +| taint.cpp:644:30:644:30 | c | taint.cpp:646:8:646:8 | c | | +| taint.cpp:645:10:645:10 | ref arg c | taint.cpp:646:8:646:8 | c | | +| taint.cpp:645:12:645:15 | call to data | taint.cpp:645:3:645:8 | call to memcpy | | +| taint.cpp:645:20:645:25 | source | taint.cpp:645:3:645:8 | call to memcpy | TAINT | +| taint.cpp:645:20:645:25 | source | taint.cpp:645:12:645:15 | ref arg call to data | TAINT | +| taint.cpp:652:9:652:12 | this | taint.cpp:652:31:652:35 | this | | +| taint.cpp:655:35:655:40 | source | taint.cpp:657:20:657:25 | source | | +| taint.cpp:656:27:656:27 | c | taint.cpp:657:10:657:10 | c | | +| taint.cpp:656:27:656:27 | c | taint.cpp:658:8:658:8 | c | | +| taint.cpp:657:12:657:15 | call to data | taint.cpp:657:3:657:8 | call to memcpy | | +| taint.cpp:657:20:657:25 | source | taint.cpp:657:3:657:8 | call to memcpy | TAINT | +| taint.cpp:657:20:657:25 | source | taint.cpp:657:12:657:15 | ref arg call to data | TAINT | | vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | | | vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | | | vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | | @@ -7481,3 +7546,64 @@ | vector.cpp:496:25:496:30 | call to source | vector.cpp:496:2:496:3 | ref arg v2 | TAINT | | vector.cpp:496:25:496:30 | call to source | vector.cpp:496:5:496:11 | call to emplace | TAINT | | vector.cpp:497:7:497:8 | ref arg v2 | vector.cpp:498:1:498:1 | v2 | | +| vector.cpp:503:18:503:21 | {...} | vector.cpp:506:8:506:9 | as | | +| vector.cpp:503:18:503:21 | {...} | vector.cpp:507:8:507:9 | as | | +| vector.cpp:503:18:503:21 | {...} | vector.cpp:509:9:509:10 | as | | +| vector.cpp:503:18:503:21 | {...} | vector.cpp:515:8:515:9 | as | | +| vector.cpp:503:20:503:20 | 0 | vector.cpp:503:18:503:21 | {...} | TAINT | +| vector.cpp:506:8:506:9 | as | vector.cpp:506:8:506:12 | access to array | | +| vector.cpp:506:11:506:11 | 1 | vector.cpp:506:8:506:12 | access to array | TAINT | +| vector.cpp:507:8:507:9 | as | vector.cpp:507:8:507:19 | access to array | | +| vector.cpp:507:11:507:16 | call to source | vector.cpp:507:8:507:19 | access to array | TAINT | +| vector.cpp:509:9:509:10 | as | vector.cpp:509:3:509:10 | ... = ... | | +| vector.cpp:509:9:509:10 | as | vector.cpp:510:9:510:11 | ptr | | +| vector.cpp:509:9:509:10 | as | vector.cpp:511:3:511:5 | ptr | | +| vector.cpp:510:9:510:11 | ptr | vector.cpp:510:8:510:11 | * ... | TAINT | +| vector.cpp:511:3:511:5 | ptr | vector.cpp:511:3:511:10 | ... += ... | TAINT | +| vector.cpp:511:3:511:10 | ... += ... | vector.cpp:512:9:512:11 | ptr | | +| vector.cpp:511:3:511:10 | ... += ... | vector.cpp:513:3:513:5 | ptr | | +| vector.cpp:511:10:511:10 | 1 | vector.cpp:511:3:511:10 | ... += ... | TAINT | +| vector.cpp:512:9:512:11 | ptr | vector.cpp:512:8:512:11 | * ... | TAINT | +| vector.cpp:513:3:513:5 | ptr | vector.cpp:513:3:513:17 | ... += ... | TAINT | +| vector.cpp:513:3:513:17 | ... += ... | vector.cpp:514:9:514:11 | ptr | | +| vector.cpp:513:10:513:15 | call to source | vector.cpp:513:3:513:17 | ... += ... | TAINT | +| vector.cpp:514:9:514:11 | ptr | vector.cpp:514:8:514:11 | * ... | TAINT | +| vector.cpp:515:8:515:9 | as | vector.cpp:515:8:515:12 | access to array | | +| vector.cpp:515:11:515:11 | 1 | vector.cpp:515:8:515:12 | access to array | TAINT | +| vector.cpp:520:25:520:31 | call to vector | vector.cpp:523:8:523:9 | vs | | +| vector.cpp:520:25:520:31 | call to vector | vector.cpp:524:8:524:9 | vs | | +| vector.cpp:520:25:520:31 | call to vector | vector.cpp:526:8:526:9 | vs | | +| vector.cpp:520:25:520:31 | call to vector | vector.cpp:532:8:532:9 | vs | | +| vector.cpp:520:25:520:31 | call to vector | vector.cpp:533:2:533:2 | vs | | +| vector.cpp:520:30:520:30 | 0 | vector.cpp:520:25:520:31 | call to vector | TAINT | +| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:524:8:524:9 | vs | | +| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | | +| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | | +| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | | +| vector.cpp:523:8:523:9 | vs | vector.cpp:523:10:523:10 | call to operator[] | TAINT | +| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | | +| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | | +| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | | +| vector.cpp:524:8:524:9 | vs | vector.cpp:524:10:524:10 | call to operator[] | TAINT | +| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | | +| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | | +| vector.cpp:526:8:526:9 | vs | vector.cpp:526:11:526:15 | call to begin | TAINT | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:526:3:526:17 | ... = ... | | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:527:9:527:10 | it | | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:528:3:528:4 | it | | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:529:9:529:10 | it | | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:530:3:530:4 | it | | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:531:9:531:10 | it | | +| vector.cpp:527:9:527:10 | it | vector.cpp:527:8:527:8 | call to operator* | TAINT | +| vector.cpp:528:3:528:4 | it | vector.cpp:528:6:528:6 | call to operator+= | | +| vector.cpp:528:3:528:4 | ref arg it | vector.cpp:529:9:529:10 | it | | +| vector.cpp:528:3:528:4 | ref arg it | vector.cpp:530:3:530:4 | it | | +| vector.cpp:528:3:528:4 | ref arg it | vector.cpp:531:9:531:10 | it | | +| vector.cpp:528:9:528:9 | 1 | vector.cpp:528:3:528:4 | ref arg it | TAINT | +| vector.cpp:529:9:529:10 | it | vector.cpp:529:8:529:8 | call to operator* | TAINT | +| vector.cpp:530:3:530:4 | it | vector.cpp:530:6:530:6 | call to operator+= | | +| vector.cpp:530:3:530:4 | ref arg it | vector.cpp:531:9:531:10 | it | | +| vector.cpp:530:9:530:14 | call to source | vector.cpp:530:3:530:4 | ref arg it | TAINT | +| vector.cpp:531:9:531:10 | it | vector.cpp:531:8:531:8 | call to operator* | TAINT | +| vector.cpp:532:8:532:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | | +| vector.cpp:532:8:532:9 | vs | vector.cpp:532:10:532:10 | call to operator[] | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp index 3fb8c738305..362784eeb1a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp @@ -90,3 +90,34 @@ void test_insert_iterator() { *i2-- = 0; sink(c2); // clean } + +void sink(insert_iterator_by_trait); +insert_iterator_by_trait &operator+=(insert_iterator_by_trait &it, int amount); + +void test_assign_through_iterator() { + container c1; + insert_iterator_by_trait a, b, c; + + a = c1.begin(); + b = c1.begin(); + *a = source(); + sink(a); // $ ast MISSING: ir + + c = c1.begin(); + sink(b); // MISSING: ast,ir + sink(c); // $ ast MISSING: ir + sink(c1); // $ ast MISSING: ir +} + +void test_nonmember_iterator() { + container c1; + insert_iterator_by_trait it; + + it = c1.begin(); + sink(it); + it += 1; + sink(it); + it += source(); + sink(it); // $ ast,ir + sink(c1); +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp index 44d84c0c0b0..9a55aaaaaba 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -630,4 +630,30 @@ void test__strnextc(const char* source) { } while(c != '\0'); c = _strnextc(""); sink(c); +} + +// --- taint through const specified function --- + +class C_no_const_member_function { + char* data_; +public: + char* data() { return data_; } +}; + +void test_no_const_member(char* source) { + C_no_const_member_function c; + memcpy(c.data(), source, 16); + sink(c.data()); // $ ast MISSING: ir +} + +class C_const_member_function { + char* data_; +public: + char* data() const { return data_; } +}; + +void test_with_const_member(char* source) { + C_const_member_function c; + memcpy(c.data(), source, 16); + sink(c.data()); // $ MISSING: ast, ir } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp index 7e7fc8176ce..4f0c8fab414 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -491,8 +491,44 @@ void test_vector_emplace() { std::vector v1(10), v2(10); v1.emplace_back(source()); - sink(v1); // $ ast MISSING: ir + sink(v1); // $ ast,ir v2.emplace(v2.begin(), source()); - sink(v2); // $ ast MISSING: ir + sink(v2); // $ ast,ir +} + +void test_vector_iterator() { + { + // array behaviour, for comparison + short as[100] = {0}; + short *ptr; + + sink(as[1]); + sink(as[source()]); // $ ast,ir + + ptr = as; + sink(*ptr); + ptr += 1; + sink(*ptr); + ptr += source(); + sink(*ptr); // $ ast,ir + sink(as[1]); + } + + { + // iterator behaviour + std::vector vs(100, 0); + std::vector::iterator it; + + sink(vs[1]); + sink(vs[source()]); // $ MISSING: ast,ir + + it = vs.begin(); + sink(*it); + it += 1; + sink(*it); + it += source(); + sink(*it); // $ ast,ir + sink(vs[1]); + } } diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index 4f709d960cc..6aeadb2f174 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -1464,93 +1464,117 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| allocators.cpp:16:14:16:36 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:16:19:16:20 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:26:23:26:24 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:41:22:41:23 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:48:22:48:24 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:48:34:48:36 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:48:52:48:53 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:30:9:30:13 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:30:18:30:22 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:33:9:33:13 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:33:18:33:22 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:39:9:39:13 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:39:18:39:22 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:42:9:42:13 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:42:18:42:22 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| constructorinitializer.cpp:8:6:8:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:77:19:77:21 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:82:11:82:14 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:82:17:82:55 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:82:45:82:48 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:82:51:82:51 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:88:25:88:30 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:88:33:88:38 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp17.cpp:15:5:15:45 | HasTwoArgCtor output argument | PostUpdateNode should have one pre-update node but has 0. | -| destructors.cpp:50:9:50:13 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| destructors.cpp:51:36:51:38 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| file://:0:0:0:0 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:616:12:616:13 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:617:15:617:22 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:619:16:619:30 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:662:9:662:19 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:663:5:663:5 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:736:5:736:19 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:745:8:745:8 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:748:10:748:10 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:757:12:757:12 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:757:12:757:12 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:766:13:766:13 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:766:13:766:13 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:775:15:775:15 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:775:15:775:15 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:784:15:784:15 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:784:15:784:15 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:793:15:793:15 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:793:15:793:15 | MiddleVB1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:793:15:793:15 | MiddleVB2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:793:15:793:15 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:800:8:800:8 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:801:10:801:10 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:802:11:802:11 | Derived output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:809:7:809:13 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:810:7:810:26 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:823:7:823:13 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:824:7:824:26 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:846:8:846:8 | PolymorphicBase output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:850:19:850:19 | PolymorphicBase output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:851:22:851:22 | PolymorphicDerived output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:868:3:868:12 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:944:3:944:14 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:945:3:945:27 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ms_assume.cpp:28:18:28:23 | fgets output argument | PostUpdateNode should have one pre-update node but has 0. | -| ms_try_mix.cpp:11:12:11:15 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| ms_try_mix.cpp:28:12:28:15 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| ms_try_mix.cpp:48:10:48:13 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| newexpr.cpp:8:2:8:20 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| ops.cpp:26:31:26:53 | C_with_constr_destr output argument | PostUpdateNode should have one pre-update node but has 0. | -| parameterinitializer.cpp:25:5:25:8 | c output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:31:10:31:11 | MyClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:236:7:236:7 | MyConstructorClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:240:7:240:7 | MyConstructorClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:249:21:249:23 | MyConstructorClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:250:17:250:19 | MyDerivedClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:251:20:251:23 | MyContainingClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| stmt_expr.cpp:13:18:13:19 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| try_catch.cpp:7:8:7:8 | exception output argument | PostUpdateNode should have one pre-update node but has 0. | -| try_catch.cpp:7:8:7:8 | exception output argument | PostUpdateNode should have one pre-update node but has 0. | -| try_catch.cpp:13:5:13:16 | exn1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should have one pre-update node but has 0. | +| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:531:14:531:14 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| cpp11.cpp:77:19:77:21 | Val output argument | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:82:11:82:14 | Val output argument | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:82:45:82:48 | Val output argument | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:82:51:82:51 | Val output argument | PostUpdateNode should not be the target of local flow. | -| ir.cpp:809:7:809:13 | Base output argument | PostUpdateNode should not be the target of local flow. | -| ir.cpp:810:7:810:26 | Base output argument | PostUpdateNode should not be the target of local flow. | -| ir.cpp:823:7:823:13 | Base output argument | PostUpdateNode should not be the target of local flow. | -| ir.cpp:824:7:824:26 | Base output argument | PostUpdateNode should not be the target of local flow. | +| aggregateinitializer.c:3:14:3:18 | Chi | PostUpdateNode should not be the target of local flow. | +| aggregateinitializer.c:3:21:3:25 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:3:27:3:27 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:3:35:3:35 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:4:11:4:23 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:4:17:4:23 | Chi | PostUpdateNode should not be the target of local flow. | +| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should not be the target of local flow. | +| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:26:14:26 | Chi | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:29:14:29 | Chi | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:32:14:32 | Chi | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:35:14:35 | Chi | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:3:5:3:22 | Chi | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:3:21:3:21 | Chi | PostUpdateNode should not be the target of local flow. | +| conditional_destructors.cpp:6:13:6:19 | Chi | PostUpdateNode should not be the target of local flow. | +| conditional_destructors.cpp:18:13:18:19 | Chi | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:17:82:55 | Chi | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:17:82:55 | Chi | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:45:82:48 | Chi | PostUpdateNode should not be the target of local flow. | +| defdestructordeleteexpr.cpp:4:9:4:15 | Chi | PostUpdateNode should not be the target of local flow. | +| deleteexpr.cpp:7:9:7:15 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:177:5:177:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:178:5:178:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:183:5:183:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:184:5:184:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:342:5:342:10 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:428:5:428:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:429:5:429:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:504:19:504:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:504:22:504:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:505:16:505:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:505:19:505:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:506:16:506:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:506:16:506:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:513:14:513:16 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:513:14:513:16 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:514:14:514:26 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:514:19:514:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:514:22:514:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:19:515:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:22:515:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:29:515:29 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:32:515:32 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:17:516:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:19:516:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:24:516:28 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:26:516:26 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:521:19:521:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:521:22:521:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:521:25:521:25 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:522:16:522:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:522:19:522:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:531:14:531:14 | Store | PostUpdateNode should not be the target of local flow. | +| ir.cpp:577:16:577:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:577:19:577:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:578:19:578:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:578:22:578:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:579:16:579:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:579:19:579:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:643:9:643:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:644:9:644:23 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:645:9:645:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:659:9:659:14 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:660:13:660:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:661:9:661:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:662:9:662:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:663:5:663:5 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:745:8:745:8 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:745:8:745:8 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:748:10:748:10 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:754:8:754:8 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:757:12:757:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:763:8:763:8 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:766:13:766:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:775:15:775:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:784:15:784:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:793:15:793:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:943:3:943:11 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:947:3:947:25 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:26:962:30 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:41:962:45 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:130:5:130:11 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:131:5:131:13 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:32:154:32 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:35:154:35 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:40:154:40 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:43:154:43 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:157:14:157:18 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:158:14:158:18 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:160:31:160:33 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:160:31:160:33 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:220:3:223:3 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:221:10:221:10 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:222:10:222:10 | Chi | PostUpdateNode should not be the target of local flow. | +| range_analysis.c:102:5:102:15 | Chi | PostUpdateNode should not be the target of local flow. | +| static_init_templates.cpp:3:2:3:8 | Chi | PostUpdateNode should not be the target of local flow. | +| static_init_templates.cpp:21:2:21:12 | Chi | PostUpdateNode should not be the target of local flow. | +| static_init_templates.cpp:240:7:240:7 | Chi | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected index 6f08104489e..de3326e74a5 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected @@ -8,14 +8,14 @@ edges | search.c:22:24:22:28 | *query | search.c:23:39:23:43 | query | | search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | | search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | -| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | *query | -| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | *query | -| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | query | -| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | query | -| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | *query | -| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | *query | -| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | query | -| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | query | +| search.c:51:21:51:26 | call to getenv | search.c:14:24:14:28 | *query | +| search.c:51:21:51:26 | call to getenv | search.c:14:24:14:28 | *query | +| search.c:51:21:51:26 | call to getenv | search.c:14:24:14:28 | query | +| search.c:51:21:51:26 | call to getenv | search.c:14:24:14:28 | query | +| search.c:51:21:51:26 | call to getenv | search.c:22:24:22:28 | *query | +| search.c:51:21:51:26 | call to getenv | search.c:22:24:22:28 | *query | +| search.c:51:21:51:26 | call to getenv | search.c:22:24:22:28 | query | +| search.c:51:21:51:26 | call to getenv | search.c:22:24:22:28 | query | nodes | search.c:14:24:14:28 | *query | semmle.label | *query | | search.c:14:24:14:28 | query | semmle.label | query | @@ -29,12 +29,12 @@ nodes | search.c:23:39:23:43 | query | semmle.label | query | | search.c:23:39:23:43 | query | semmle.label | query | | search.c:23:39:23:43 | query | semmle.label | query | -| search.c:41:21:41:26 | call to getenv | semmle.label | call to getenv | -| search.c:41:21:41:26 | call to getenv | semmle.label | call to getenv | -| search.c:45:5:45:15 | Argument 0 | semmle.label | Argument 0 | -| search.c:45:17:45:25 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| search.c:47:5:47:15 | Argument 0 | semmle.label | Argument 0 | -| search.c:47:17:47:25 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv | +| search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv | +| search.c:55:5:55:15 | Argument 0 | semmle.label | Argument 0 | +| search.c:55:17:55:25 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| search.c:57:5:57:15 | Argument 0 | semmle.label | Argument 0 | +| search.c:57:17:57:25 | Argument 0 indirection | semmle.label | Argument 0 indirection | #select -| search.c:17:8:17:12 | query | search.c:41:21:41:26 | call to getenv | search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | -| search.c:23:39:23:43 | query | search.c:41:21:41:26 | call to getenv | search.c:23:39:23:43 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | +| search.c:17:8:17:12 | query | search.c:51:21:51:26 | call to getenv | search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:51:21:51:26 | call to getenv | this query data | +| search.c:23:39:23:43 | query | search.c:51:21:51:26 | call to getenv | search.c:23:39:23:43 | query | Cross-site scripting vulnerability due to $@. | search.c:51:21:51:26 | call to getenv | this query data | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c index df9a09ded59..77c830985d2 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c @@ -26,7 +26,7 @@ void bad_server2(char* query) { puts(do_search(query)); } -void good_server(char* query) { +void good_server1(char* query) { puts("

    Query results for "); // GOOD: Escape HTML characters before adding to a page char* query_escaped = escape_html(query); @@ -37,14 +37,25 @@ void good_server(char* query) { puts(do_search(query)); } -int main(int argc, char** argv) { - char* raw_query = getenv("QUERY_STRING"); - if (strcmp("good", argv[0]) == 0) { - good_server(raw_query); - } else if (strcmp("bad1", argv[0]) == 0) { - bad_server1(raw_query); - } else { - bad_server2(raw_query); - } +int sscanf(const char *s, const char *format, ...); + +void good_server2(char* query) { + puts("

    Query results for "); + // GOOD: Only an integer is added to the page. + int i = 0; + sscanf(query, "value=%i", &i); + printf("\n

    %i

    \n", i); } +int main(int argc, char** argv) { + char* raw_query = getenv("QUERY_STRING"); + if (strcmp("good1", argv[0]) == 0) { + good_server1(raw_query); + } else if (strcmp("bad1", argv[0]) == 0) { + bad_server1(raw_query); + } else if (strcmp("bad2", argv[0]) == 0) { + bad_server2(raw_query); + } else if (strcmp("good2", argv[0]) == 0) { + good_server2(raw_query); + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index 0299afff063..9876b9695ad 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -59,21 +59,18 @@ edges | test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size | | test.cpp:241:2:241:32 | Chi [array content] | test.cpp:279:17:279:20 | get_size output argument [array content] | | test.cpp:241:2:241:32 | Chi [array content] | test.cpp:295:18:295:21 | get_size output argument [array content] | -| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | test.cpp:241:2:241:32 | Chi [array content] | -| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | test.cpp:279:17:279:20 | get_size output argument [array content] | -| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | test.cpp:295:18:295:21 | get_size output argument [array content] | -| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | -| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | +| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi [array content] | +| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi [array content] | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument [array content] | test.cpp:279:17:279:20 | get_size output argument | -| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument [array content] | test.cpp:295:18:295:21 | get_size output argument | +| test.cpp:279:17:279:20 | Chi | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | Chi | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument [array content] | test.cpp:279:17:279:20 | Chi | +| test.cpp:295:18:295:21 | Chi | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | Chi | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument [array content] | test.cpp:295:18:295:21 | Chi | | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | | test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | @@ -147,7 +144,6 @@ nodes | test.cpp:237:2:237:8 | Argument 0 | semmle.label | Argument 0 | | test.cpp:241:2:241:32 | Chi [array content] | semmle.label | Chi [array content] | | test.cpp:241:2:241:32 | ChiPartial | semmle.label | ChiPartial | -| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | test.cpp:241:18:241:23 | call to getenv | semmle.label | call to getenv | | test.cpp:241:18:241:31 | (const char *)... | semmle.label | (const char *)... | | test.cpp:249:20:249:25 | call to getenv | semmle.label | call to getenv | @@ -155,12 +151,12 @@ nodes | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:279:17:279:20 | Chi | semmle.label | Chi | | test.cpp:279:17:279:20 | get_size output argument [array content] | semmle.label | get_size output argument [array content] | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:295:18:295:21 | Chi | semmle.label | Chi | | test.cpp:295:18:295:21 | get_size output argument [array content] | semmle.label | get_size output argument [array content] | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected index c684f1da6ce..ca8dd38fc3b 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected @@ -43,23 +43,19 @@ edges | 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:2:13:15 | ChiTotal [post update] [array content] | test.cpp:13:2:13:15 | Chi [array content] | -| test.cpp:13:2:13:15 | ChiTotal [post update] [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 | ChiTotal [post update] [array content] | -| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | ChiTotal [post update] [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:2:18:14 | ChiTotal [post update] [array content] | test.cpp:18:2:18:14 | Chi [array content] | -| test.cpp:18:2:18:14 | ChiTotal [post update] [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 | ChiTotal [post update] [array content] | -| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | ChiTotal [post update] [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:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r | -| test.cpp:30:13:30:14 | get_rand2 output argument | test.cpp:31:7:31:7 | r | -| test.cpp:30:13:30:14 | get_rand2 output argument | 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 | get_rand2 output argument | -| test.cpp:36:13:36:13 | get_rand3 output argument | test.cpp:37:7:37:7 | r | -| test.cpp:36:13:36:13 | get_rand3 output argument | 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 | get_rand3 output argument | +| 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: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 | 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 | @@ -114,24 +110,22 @@ nodes | 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 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | 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:2:18:14 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand | | 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 | get_rand2 output argument | semmle.label | get_rand2 output argument | +| 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:31:7:31:7 | r | semmle.label | r | -| test.cpp:36:13:36:13 | get_rand3 output argument | semmle.label | get_rand3 output argument | +| 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 | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected new file mode 100644 index 00000000000..2d28795d126 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected @@ -0,0 +1,10 @@ +| test.cpp:6:5:6:13 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:10:8:10:24 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:15:9:15:25 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:32:12:32:20 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:39:12:39:20 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:47:5:47:13 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:55:5:55:13 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:62:5:62:13 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:69:5:69:13 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:75:8:75:16 | ... > ... | Unsigned subtraction can never be negative. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref new file mode 100644 index 00000000000..9681978c0ad --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp new file mode 100644 index 00000000000..11de69e8c62 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp @@ -0,0 +1,77 @@ +int getAnInt(); + +bool cond(); + +void test(unsigned x, unsigned y, bool unknown) { + if(x - y > 0) { } // BAD + + unsigned total = getAnInt(); + unsigned limit = getAnInt(); + while(limit - total > 0) { // BAD + total += getAnInt(); + } + + if(total <= limit) { + while(limit - total > 0) { // GOOD [FALSE POSITIVE] + total += getAnInt(); + if(total > limit) break; + } + } + + if(x >= y) { + bool b = x - y > 0; // GOOD + } + + if((int)(x - y) >= 0) { } // GOOD. Maybe an overflow happened, but the result is converted to the "likely intended" result before the comparison + + if(unknown) { + y = x & 0xFF; + } else { + y = x; + } + bool b1 = x - y > 0; // GOOD [FALSE POSITIVE] + + x = getAnInt(); + y = getAnInt(); + if(y > x) { + y = x - 1; + } + bool b2 = x - y > 0; // GOOD [FALSE POSITIVE] + + int N = getAnInt(); + y = x; + while(cond()) { + if(unknown) { y--; } + } + + if(x - y > 0) { } // GOOD [FALSE POSITIVE] + + x = y; + while(cond()) { + if(unknown) break; + y--; + } + + if(x - y > 0) { } // GOOD [FALSE POSITIVE] + + y = 0; + for(int i = 0; i < x; ++i) { + if(unknown) { ++y; } + } + + if(x - y > 0) { } // GOOD [FALSE POSITIVE] + + x = y; + while(cond()) { + if(unknown) { x++; } + } + + if(x - y > 0) { } // GOOD [FALSE POSITIVE] + + int n = getAnInt(); + if (n > x - y) { n = x - y; } + if (n > 0) { + y += n; // NOTE: `n` is at most `x - y` at this point. + if (x - y > 0) {} // GOOD [FALSE POSITIVE] + } +} \ No newline at end of file diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs index 2f16872dd74..c5d65794fb5 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs @@ -45,6 +45,7 @@ namespace Semmle.Autobuild.Shared private readonly SolutionFile? solution; private readonly IEnumerable includedProjects; + public override IEnumerable IncludedProjects => includedProjects; public IEnumerable Configurations => @@ -84,8 +85,12 @@ namespace Semmle.Autobuild.Shared .ToArray(); } - private IEnumerable ToolsVersions => includedProjects.Where(p => p.ValidToolsVersion).Select(p => p.ToolsVersion); + private IEnumerable ToolsVersions => includedProjects + .Where(p => p.ValidToolsVersion) + .Select(p => p.ToolsVersion); - public Version ToolsVersion => ToolsVersions.Any() ? ToolsVersions.Max() : new Version(); + public Version ToolsVersion => ToolsVersions.Any() + ? ToolsVersions.Max() + : new Version(); } } diff --git a/csharp/change-notes/2021-02-01-Preprocessor-directives.md b/csharp/change-notes/2021-02-01-Preprocessor-directives.md new file mode 100644 index 00000000000..d81979c36cd --- /dev/null +++ b/csharp/change-notes/2021-02-01-Preprocessor-directives.md @@ -0,0 +1,8 @@ +lgtm,codescanning +* The `PreprocessorDirective` class and its base classes have been added to support +preprocessor directives, such as `#if`, `#define`, `#undef`, `#line`, `#region`, +`#warning`, `#error`, `#pragma warning`, `#pragma checksum` and `#nullable`. Furthermore, +`#line` directives are now taken into account when querying the location of any +code construct. Files referenced in preprocessor directives are also included in the +extraction sources. This change is expected to lead to better error reporting locations +in generated code, such as generated code from `.cshtml` files in ASP.NET Core. diff --git a/csharp/change-notes/2021-02-02-foreach-underlying-methods.md b/csharp/change-notes/2021-02-02-foreach-underlying-methods.md new file mode 100644 index 00000000000..a9e934a0e5d --- /dev/null +++ b/csharp/change-notes/2021-02-02-foreach-underlying-methods.md @@ -0,0 +1,3 @@ +lgtm,codescanning +* The underlying methods of `foreach` statements are now explicitly extracted and +they are made available on the `ForeachStmt` class. diff --git a/csharp/change-notes/2021-02-04-Records.md b/csharp/change-notes/2021-02-04-Records.md new file mode 100644 index 00000000000..069737e5239 --- /dev/null +++ b/csharp/change-notes/2021-02-04-Records.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Record types (`Record`) are extracted. diff --git a/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs b/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs index 9964ff5bf0c..75405d562fe 100644 --- a/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs +++ b/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs @@ -163,7 +163,7 @@ namespace Semmle.Extraction.CIL.Driver } private readonly HashSet filesAnalyzed = new HashSet(); - public HashSet MissingReferences {get;} = new HashSet(); + public HashSet MissingReferences { get; } = new HashSet(); } /// diff --git a/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs b/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs index dd09727f3c0..36e420e3628 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs @@ -95,11 +95,11 @@ namespace Semmle.Extraction.CIL /// The handle of the entity. /// The generic context. /// - public IExtractedEntity CreateGeneric(GenericContext genericContext, Handle h) => genericHandleFactory[genericContext, h]; + public IExtractedEntity CreateGeneric(IGenericContext genericContext, Handle h) => genericHandleFactory[genericContext, h]; - private readonly GenericContext defaultGenericContext; + private readonly IGenericContext defaultGenericContext; - private IExtractedEntity CreateGenericHandle(GenericContext gc, Handle handle) + private IExtractedEntity CreateGenericHandle(IGenericContext gc, Handle handle) { IExtractedEntity entity; switch (handle.Kind) @@ -136,7 +136,7 @@ namespace Semmle.Extraction.CIL return entity; } - private IExtractedEntity Create(GenericContext gc, MemberReferenceHandle handle) + private IExtractedEntity Create(IGenericContext gc, MemberReferenceHandle handle) { var mr = MdReader.GetMemberReference(handle); switch (mr.GetKind()) @@ -228,7 +228,7 @@ namespace Semmle.Extraction.CIL #endregion - private readonly CachedFunction genericHandleFactory; + private readonly CachedFunction genericHandleFactory; /// /// Gets the short name of a member, without the preceding interface qualifier. diff --git a/csharp/extractor/Semmle.Extraction.CIL/Context.cs b/csharp/extractor/Semmle.Extraction.CIL/Context.cs index ae662f2e87c..99113714b7c 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Context.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Context.cs @@ -37,7 +37,7 @@ namespace Semmle.Extraction.CIL globalNamespace = new Lazy(() => Populate(new Entities.Namespace(this, "", null))); systemNamespace = new Lazy(() => Populate(new Entities.Namespace(this, "System"))); - genericHandleFactory = new CachedFunction(CreateGenericHandle); + genericHandleFactory = new CachedFunction(CreateGenericHandle); namespaceFactory = new CachedFunction(n => CreateNamespace(MdReader.GetString(n))); namespaceDefinitionFactory = new CachedFunction(CreateNamespace); sourceFiles = new CachedFunction(path => new Entities.PdbSourceFile(this, path)); diff --git a/csharp/extractor/Semmle.Extraction.CIL/EmptyContext.cs b/csharp/extractor/Semmle.Extraction.CIL/EmptyContext.cs index 70c73be1151..1105bc39cba 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/EmptyContext.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/EmptyContext.cs @@ -5,14 +5,18 @@ namespace Semmle.Extraction.CIL /// /// A generic context which does not contain any type parameters. /// - public class EmptyContext : GenericContext + public class EmptyContext : IGenericContext { - public EmptyContext(Context cx) : base(cx) + public EmptyContext(Context cx) { + Cx = cx; } - public override IEnumerable TypeParameters { get { yield break; } } + public Context Cx { get; } + + public IEnumerable TypeParameters { get { yield break; } } + + public IEnumerable MethodParameters { get { yield break; } } - public override IEnumerable MethodParameters { get { yield break; } } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs index 8a843f1672d..ba332b2db97 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs @@ -40,6 +40,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(FullName); trapFile.Write("#file:///"); trapFile.Write(Cx.AssemblyPath.Replace("\\", "/")); + trapFile.Write(";assembly"); } public override bool Equals(object? obj) @@ -49,8 +50,6 @@ namespace Semmle.Extraction.CIL.Entities public override int GetHashCode() => 7 * file.GetHashCode(); - public override string IdSuffix => ";assembly"; - private string FullName => assemblyName.GetPublicKey() is null ? assemblyName.FullName + ", PublicKeyToken=null" : assemblyName.FullName; public override IEnumerable Contents @@ -136,7 +135,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile = trapWriter.TrapFile; if (nocache || !System.IO.File.Exists(trapFile)) { - var cx = extractor.CreateContext(null, trapWriter, null, false); + var cx = new Extraction.Context(extractor, trapWriter); ExtractCIL(cx, assemblyPath, extractPdbs); extracted = true; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs index c862bc3fc4e..d79215f0adf 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs @@ -12,9 +12,9 @@ namespace Semmle.Extraction.CIL.Entities { private readonly CustomAttributeHandle handle; private readonly CustomAttribute attrib; - private readonly IEntity @object; + private readonly IExtractedEntity @object; - public Attribute(Context cx, IEntity @object, CustomAttributeHandle handle) : base(cx) + public Attribute(Context cx, IExtractedEntity @object, CustomAttributeHandle handle) : base(cx) { attrib = cx.MdReader.GetCustomAttribute(handle); this.handle = handle; @@ -80,7 +80,7 @@ namespace Semmle.Extraction.CIL.Entities return value?.ToString() ?? "null"; } - public static IEnumerable Populate(Context cx, IEntity @object, CustomAttributeHandleCollection attributes) + public static IEnumerable Populate(Context cx, IExtractedEntity @object, CustomAttributeHandleCollection attributes) { foreach (var attrib in attributes) { diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractedEntity.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractedEntity.cs new file mode 100644 index 00000000000..080227a63b9 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractedEntity.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Semmle.Extraction.CIL +{ + /// + /// A CIL entity which has been extracted. + /// + public interface IExtractedEntity : IExtractionProduct, IEntity + { + /// + /// The contents of the entity. + /// + + IEnumerable Contents { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractionProduct.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractionProduct.cs new file mode 100644 index 00000000000..6383d7e1b4c --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractionProduct.cs @@ -0,0 +1,24 @@ +namespace Semmle.Extraction.CIL +{ + /// + /// Something that is extracted from an entity. + /// + /// + /// + /// The extraction algorithm proceeds as follows: + /// - Construct entity + /// - Call Extract() + /// - IExtractedEntity check if already extracted + /// - Enumerate Contents to produce more extraction products + /// - Extract these until there is nothing left to extract + /// + public interface IExtractionProduct + { + /// + /// Perform further extraction/population of this item as necessary. + /// + /// + /// The extraction context. + void Extract(Context cx); + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IGenericContext.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IGenericContext.cs new file mode 100644 index 00000000000..21c69f7aeb4 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IGenericContext.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Semmle.Extraction.CIL +{ + /// + /// When we decode a type/method signature, we need access to + /// generic parameters. + /// + public interface IGenericContext + { + Context Cx { get; } + + /// + /// The list of generic type parameters/arguments, including type parameters/arguments of + /// containing types. + /// + IEnumerable TypeParameters { get; } + + /// + /// The list of generic method parameters/arguments. + /// + IEnumerable MethodParameters { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/LabelledEntity.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/LabelledEntity.cs new file mode 100644 index 00000000000..a66ecbb1fab --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/LabelledEntity.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Semmle.Extraction.CIL +{ + /// + /// An entity that needs to be populated during extraction. + /// This assigns a key and optionally extracts its contents. + /// + public abstract class LabelledEntity : Extraction.LabelledEntity, IExtractedEntity + { + // todo: with .NET 5 this can override the base context, and change the return type. + public Context Cx { get; } + + protected LabelledEntity(Context cx) : base(cx.Cx) + { + this.Cx = cx; + } + + public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException(); + + public void Extract(Context cx2) + { + cx2.Populate(this); + } + + public override string ToString() + { + using var writer = new StringWriter(); + WriteQuotedId(writer); + return writer.ToString(); + } + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public abstract IEnumerable Contents { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/Tuple.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/Tuple.cs new file mode 100644 index 00000000000..5657f072c9c --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/Tuple.cs @@ -0,0 +1,22 @@ +namespace Semmle.Extraction.CIL +{ + /// + /// A tuple that is an extraction product. + /// + internal class Tuple : IExtractionProduct + { + private readonly Extraction.Tuple tuple; + + public Tuple(string name, params object[] args) + { + tuple = new Extraction.Tuple(name, args); + } + + public void Extract(Context cx) + { + cx.Cx.Emit(tuple); + } + + public override string ToString() => tuple.ToString(); + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/UnlabelledEntity.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/UnlabelledEntity.cs new file mode 100644 index 00000000000..d8c18d291eb --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/UnlabelledEntity.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; + +namespace Semmle.Extraction.CIL +{ + /// + /// An entity that has contents to extract. There is no need to populate + /// a key as it's done in the contructor. + /// + public abstract class UnlabelledEntity : Extraction.UnlabelledEntity, IExtractedEntity + { + // todo: with .NET 5 this can override the base context, and change the return type. + public Context Cx { get; } + + protected UnlabelledEntity(Context cx) : base(cx.Cx) + { + Cx = cx; + } + + public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException(); + + public void Extract(Context cx2) + { + cx2.Extract(this); + } + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public abstract IEnumerable Contents { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/ConstructedType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/ConstructedType.cs index 5be671055eb..be2ab5da4d8 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/ConstructedType.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/ConstructedType.cs @@ -1,5 +1,4 @@ using System; -using Microsoft.CodeAnalysis; using System.Linq; using System.Collections.Generic; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs index 175da806597..8ff7fcf24bf 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CIL.Entities public override IList? LocalVariables => locals; - public DefinitionMethod(GenericContext gc, MethodDefinitionHandle handle) : base(gc) + public DefinitionMethod(IGenericContext gc, MethodDefinitionHandle handle) : base(gc) { md = Cx.MdReader.GetMethodDefinition(handle); this.gc = gc; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs index e2e27484a4c..a6ca9364e0f 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs @@ -25,10 +25,9 @@ namespace Semmle.Extraction.CIL.Entities parent.WriteId(trapFile); trapFile.Write('.'); trapFile.Write(Cx.ShortName(ed.Name)); + trapFile.Write(";cil-event"); } - public override string IdSuffix => ";cil-event"; - public override bool Equals(object? obj) { return obj is Event e && handle.Equals(e.handle); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs index 75303e7903b..3026ff03030 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs @@ -7,13 +7,13 @@ namespace Semmle.Extraction.CIL.Entities /// internal class ExceptionRegion : UnlabelledEntity { - private readonly GenericContext gc; + private readonly IGenericContext gc; private readonly MethodImplementation method; private readonly int index; private readonly System.Reflection.Metadata.ExceptionRegion r; private readonly Dictionary jump_table; - public ExceptionRegion(GenericContext gc, MethodImplementation method, int index, System.Reflection.Metadata.ExceptionRegion r, Dictionary jump_table) : base(gc.Cx) + public ExceptionRegion(IGenericContext gc, MethodImplementation method, int index, System.Reflection.Metadata.ExceptionRegion r, Dictionary jump_table) : base(gc.Cx) { this.gc = gc; this.method = method; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs index 3f051796887..8decef24128 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs @@ -8,40 +8,27 @@ namespace Semmle.Extraction.CIL.Entities /// /// An entity representing a field. /// - internal abstract class Field : GenericContext, IMember, ICustomModifierReceiver + internal abstract class Field : LabelledEntity, IGenericContext, IMember, ICustomModifierReceiver { protected Field(Context cx) : base(cx) { } - public Label Label { get; set; } - - public void WriteId(TextWriter trapFile) + public override void WriteId(TextWriter trapFile) { trapFile.WriteSubId(DeclaringType); trapFile.Write('.'); trapFile.Write(Name); + trapFile.Write(";cil-field"); } - public void WriteQuotedId(TextWriter trapFile) - { - trapFile.Write("@\""); - WriteId(trapFile); - trapFile.Write(idSuffix); - trapFile.Write('\"'); - } - - private const string idSuffix = ";cil-field"; - public abstract string Name { get; } public abstract Type DeclaringType { get; } - public Location ReportingLocation => throw new NotImplementedException(); - public abstract Type Type { get; } - public virtual IEnumerable Contents + public override IEnumerable Contents { get { @@ -55,11 +42,8 @@ namespace Semmle.Extraction.CIL.Entities } } - public void Extract(Context cx2) - { - cx2.Populate(this); - } + public abstract IEnumerable TypeParameters { get; } - TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; + public abstract IEnumerable MethodParameters { get; } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs index d5cb10a43db..4b612ae86af 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs @@ -17,6 +17,7 @@ namespace Semmle.Extraction.CIL.Entities public override void WriteId(TextWriter trapFile) { trapFile.Write(TransformedPath.DatabaseId); + trapFile.Write(";sourcefile"); } public override bool Equals(object? obj) @@ -39,7 +40,5 @@ namespace Semmle.Extraction.CIL.Entities yield return Tuples.files(this, TransformedPath.Value, TransformedPath.NameWithoutExtension, TransformedPath.Extension); } } - - public override string IdSuffix => ";sourcefile"; } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs index 6121792600a..2294a525e4b 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs @@ -15,10 +15,9 @@ namespace Semmle.Extraction.CIL.Entities public override void WriteId(TextWriter trapFile) { trapFile.Write(transformedPath.DatabaseId); + trapFile.Write(";folder"); } - public override string IdSuffix => ";folder"; - public override IEnumerable Contents { get diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/ITypeSignature.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/ITypeSignature.cs index 81dcf7b7804..beaecdfab6f 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/ITypeSignature.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/ITypeSignature.cs @@ -4,6 +4,6 @@ namespace Semmle.Extraction.CIL.Entities { internal interface ITypeSignature { - void WriteId(TextWriter trapFile, GenericContext gc); + void WriteId(TextWriter trapFile, IGenericContext gc); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs index 9512cfc5690..033010e18a3 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL.Entities /// /// A CIL instruction. /// - internal class Instruction : UnlabelledEntity, IEntity + internal class Instruction : UnlabelledEntity { /// /// The additional data following the opcode, if any. @@ -289,11 +289,6 @@ namespace Semmle.Extraction.CIL.Entities } } - Label IEntity.Label - { - get; set; - } - private readonly byte[] data; private int PayloadSize => payloadSizes[(int)PayloadType]; @@ -481,7 +476,7 @@ namespace Semmle.Extraction.CIL.Entities // TODO: Find a solution to this. // For now, just log the error - Cx.Cx.ExtractionError("A CIL instruction jumps outside the current method", "", Extraction.Entities.GeneratedLocation.Create(Cx.Cx), "", Util.Logging.Severity.Warning); + Cx.Cx.ExtractionError("A CIL instruction jumps outside the current method", null, Extraction.Entities.GeneratedLocation.Create(Cx.Cx), "", Util.Logging.Severity.Warning); } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/LocalVariable.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/LocalVariable.cs index d96c430f3c9..5d7a00c64c9 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/LocalVariable.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/LocalVariable.cs @@ -21,10 +21,9 @@ namespace Semmle.Extraction.CIL.Entities trapFile.WriteSubId(method); trapFile.Write('_'); trapFile.Write(index); + trapFile.Write(";cil-local"); } - public override string IdSuffix => ";cil-local"; - public override IEnumerable Contents { get diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceField.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceField.cs index f8017a729e8..136ece10a8c 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceField.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceField.cs @@ -8,10 +8,10 @@ namespace Semmle.Extraction.CIL.Entities { private readonly MemberReferenceHandle handle; private readonly MemberReference mr; - private readonly GenericContext gc; + private readonly IGenericContext gc; private readonly Type declType; - public MemberReferenceField(GenericContext gc, MemberReferenceHandle handle) : base(gc.Cx) + public MemberReferenceField(IGenericContext gc, MemberReferenceHandle handle) : base(gc.Cx) { this.handle = handle; this.gc = gc; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceMethod.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceMethod.cs index cacbc6ab874..703bb717cee 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceMethod.cs @@ -12,10 +12,10 @@ namespace Semmle.Extraction.CIL.Entities private readonly MemberReferenceHandle handle; private readonly MemberReference mr; private readonly Type declaringType; - private readonly GenericContext parent; + private readonly IGenericContext parent; private readonly Method? sourceDeclaration; - public MemberReferenceMethod(GenericContext gc, MemberReferenceHandle handle) : base(gc) + public MemberReferenceMethod(IGenericContext gc, MemberReferenceHandle handle) : base(gc) { this.handle = handle; this.gc = gc; @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CIL.Entities signature = mr.DecodeMethodSignature(new SignatureDecoder(), gc); - parent = (GenericContext)Cx.CreateGeneric(gc, mr.Parent); + parent = (IGenericContext)Cx.CreateGeneric(gc, mr.Parent); var declType = parent is Method parentMethod ? parentMethod.DeclaringType diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs index 30e94c8e16a..d1302837c16 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs @@ -12,10 +12,10 @@ namespace Semmle.Extraction.CIL.Entities internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver, IParameterizable { protected MethodTypeParameter[]? genericParams; - protected GenericContext gc; + protected IGenericContext gc; protected MethodSignature signature; - protected Method(GenericContext gc) : base(gc.Cx) + protected Method(IGenericContext gc) : base(gc.Cx) { this.gc = gc; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodSpecificationMethod.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodSpecificationMethod.cs index 26811ce6c80..a3f87b14a8e 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodSpecificationMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodSpecificationMethod.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CIL.Entities private readonly Method unboundMethod; private readonly ImmutableArray typeParams; - public MethodSpecificationMethod(GenericContext gc, MethodSpecificationHandle handle) : base(gc) + public MethodSpecificationMethod(IGenericContext gc, MethodSpecificationHandle handle) : base(gc) { this.handle = handle; ms = Cx.MdReader.GetMethodSpecification(handle); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodTypeParameter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodTypeParameter.cs index db5e56acb17..1795eb29269 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodTypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodTypeParameter.cs @@ -21,7 +21,7 @@ namespace Semmle.Extraction.CIL.Entities public override string Name => "!" + index; - public MethodTypeParameter(GenericContext gc, Method m, int index) : base(gc) + public MethodTypeParameter(IGenericContext gc, Method m, int index) : base(gc) { method = m; this.index = index; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/NamedTypeIdWriter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/NamedTypeIdWriter.cs index 35881b67257..98f9e94ec82 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/NamedTypeIdWriter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/NamedTypeIdWriter.cs @@ -1,4 +1,3 @@ -using Microsoft.CodeAnalysis; using System.Linq; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs index e916fd0020f..5d498c5ac54 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs @@ -14,9 +14,6 @@ namespace Semmle.Extraction.CIL.Entities public bool IsGlobalNamespace => ParentNamespace is null; - public override string IdSuffix => ";namespace"; - - public override void WriteId(TextWriter trapFile) { if (ParentNamespace != null && !ParentNamespace.IsGlobalNamespace) @@ -27,6 +24,8 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(Name); } + public override string IdSuffix => ";namespacee"; + public override bool Equals(object? obj) { if (obj is Namespace ns && Name == ns.Name) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.FullyQualifiedNameParser.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.FullyQualifiedNameParser.cs index d7940be6cc5..999259e9ad6 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.FullyQualifiedNameParser.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.FullyQualifiedNameParser.cs @@ -22,7 +22,7 @@ namespace Semmle.Extraction.CIL.Entities private class FullyQualifiedNameParser { public string ShortName { get; internal set; } - public string? AssemblyName { get; internal set; } + public string? AssemblyName { get; private set; } public IEnumerable? TypeArguments { get; internal set; } public string? UnboundGenericTypeName { get; internal set; } public string ContainerName { get; internal set; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs index fde969d12b9..c1259534f79 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs @@ -66,7 +66,7 @@ namespace Semmle.Extraction.CIL.Entities private void Populate() { - if (isContainerNamespace) + if (ContainingNamespace is object) { Cx.Populate(ContainingNamespace); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs index 90452fe9265..9cf96412309 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs @@ -8,41 +8,40 @@ namespace Semmle.Extraction.CIL.Entities /// internal sealed class Parameter : LabelledEntity { - private readonly IParameterizable method; + private readonly IParameterizable parameterizable; private readonly int index; private readonly Type type; - public Parameter(Context cx, IParameterizable m, int i, Type t) : base(cx) + public Parameter(Context cx, IParameterizable p, int i, Type t) : base(cx) { - method = m; + parameterizable = p; index = i; type = t; } public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(method); + trapFile.WriteSubId(parameterizable); trapFile.Write('_'); trapFile.Write(index); + trapFile.Write(";cil-parameter"); } public override bool Equals(object? obj) { - return obj is Parameter param && method.Equals(param.method) && index == param.index; + return obj is Parameter param && parameterizable.Equals(param.parameterizable) && index == param.index; } public override int GetHashCode() { - return 23 * method.GetHashCode() + index; + return 23 * parameterizable.GetHashCode() + index; } - public override string IdSuffix => ";cil-parameter"; - public override IEnumerable Contents { get { - yield return Tuples.cil_parameter(this, method, index, type); + yield return Tuples.cil_parameter(this, parameterizable, index, type); } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs index 5fb22b40409..e605468827a 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs @@ -13,10 +13,9 @@ namespace Semmle.Extraction.CIL.Entities private readonly Handle handle; private readonly Type type; private readonly PropertyDefinition pd; - public override string IdSuffix => ";cil-property"; - private readonly GenericContext gc; + private readonly IGenericContext gc; - public Property(GenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.Cx) + public Property(IGenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.Cx) { this.gc = gc; this.handle = handle; @@ -38,6 +37,7 @@ namespace Semmle.Extraction.CIL.Entities param.WriteId(trapFile, gc); } trapFile.Write(")"); + trapFile.Write(";cil-property"); } public override bool Equals(object? obj) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs index a80f456df72..308846ff30a 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs @@ -1,7 +1,6 @@ using System.Reflection.Metadata; using System.Collections.Immutable; using System.IO; -using System.Linq; namespace Semmle.Extraction.CIL.Entities { @@ -18,7 +17,7 @@ namespace Semmle.Extraction.CIL.Entities this.shape = shape; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { elementType.WriteId(trapFile, gc); trapFile.Write('['); @@ -39,7 +38,7 @@ namespace Semmle.Extraction.CIL.Entities this.elementType = elementType; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { elementType.WriteId(trapFile, gc); trapFile.Write('&'); @@ -55,7 +54,7 @@ namespace Semmle.Extraction.CIL.Entities this.signature = signature; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { FunctionPointerType.WriteName( trapFile.Write, @@ -85,7 +84,7 @@ namespace Semmle.Extraction.CIL.Entities this.typeArguments = typeArguments; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { genericType.WriteId(trapFile, gc); trapFile.Write('<'); @@ -113,7 +112,7 @@ namespace Semmle.Extraction.CIL.Entities this.index = index; } - public void WriteId(TextWriter trapFile, GenericContext outerGc) + public void WriteId(TextWriter trapFile, IGenericContext outerGc) { if (!ReferenceEquals(innerGc, outerGc) && innerGc is Method method) { @@ -133,7 +132,7 @@ namespace Semmle.Extraction.CIL.Entities this.index = index; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { trapFile.Write("T!"); trapFile.Write(index); @@ -159,7 +158,7 @@ namespace Semmle.Extraction.CIL.Entities this.isRequired = isRequired; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { unmodifiedType.WriteId(trapFile, gc); trapFile.Write(isRequired ? " modreq(" : " modopt("); @@ -187,7 +186,7 @@ namespace Semmle.Extraction.CIL.Entities this.elementType = elementType; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { elementType.WriteId(trapFile, gc); trapFile.Write('*'); @@ -208,7 +207,7 @@ namespace Semmle.Extraction.CIL.Entities this.typeCode = typeCode; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { trapFile.Write(typeCode.Id()); } @@ -228,7 +227,7 @@ namespace Semmle.Extraction.CIL.Entities this.elementType = elementType; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { elementType.WriteId(trapFile, gc); trapFile.Write("[]"); @@ -249,7 +248,7 @@ namespace Semmle.Extraction.CIL.Entities this.handle = handle; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { var type = (Type)gc.Cx.Create(handle); type.WriteId(trapFile); @@ -270,7 +269,7 @@ namespace Semmle.Extraction.CIL.Entities this.handle = handle; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { var type = (Type)gc.Cx.Create(handle); type.WriteId(trapFile); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs index f0f1667bca2..318cac14930 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs @@ -26,6 +26,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(location.EndLine); trapFile.Write(','); trapFile.Write(location.EndColumn); + trapFile.Write(";sourcelocation"); } public override bool Equals(object? obj) @@ -43,7 +44,5 @@ namespace Semmle.Extraction.CIL.Entities yield return Tuples.locations_default(this, file, location.StartLine, location.StartColumn, location.EndLine, location.EndColumn); } } - - public override string IdSuffix => ";sourcelocation"; } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs index edeb1a54136..ad5a6ababaa 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs @@ -11,7 +11,6 @@ namespace Semmle.Extraction.CIL.Entities /// public abstract class Type : TypeContainer, IMember { - public override string IdSuffix => ";cil-type"; internal const string AssemblyTypeNameSeparator = "::"; internal const string PrimitiveTypePrefix = "builtin" + AssemblyTypeNameSeparator + "System."; @@ -48,6 +47,8 @@ namespace Semmle.Extraction.CIL.Entities public sealed override void WriteId(TextWriter trapFile) => WriteId(trapFile, false); + public override string IdSuffix => ";cil-type"; + /// /// Returns the friendly qualified name of types, such as /// ``"System.Collection.Generic.List`1"`` or @@ -198,7 +199,7 @@ namespace Semmle.Extraction.CIL.Entities public sealed override IEnumerable MethodParameters => Enumerable.Empty(); - public static Type DecodeType(GenericContext gc, TypeSpecificationHandle handle) => + public static Type DecodeType(IGenericContext gc, TypeSpecificationHandle handle) => gc.Cx.MdReader.GetTypeSpecification(handle).DecodeSignature(gc.Cx.TypeSignatureDecoder, gc); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs index a7b7a006af6..106b6fe83be 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs @@ -1,5 +1,3 @@ -using System; -using Microsoft.CodeAnalysis; using System.Collections.Generic; using System.IO; @@ -8,17 +6,15 @@ namespace Semmle.Extraction.CIL.Entities /// /// Base class for all type containers (namespaces, types, methods). /// - public abstract class TypeContainer : GenericContext, IExtractedEntity + public abstract class TypeContainer : LabelledEntity, IGenericContext { protected TypeContainer(Context cx) : base(cx) { } - public virtual Label Label { get; set; } + public abstract string IdSuffix { get; } - public abstract void WriteId(TextWriter trapFile); - - public void WriteQuotedId(TextWriter trapFile) + public override void WriteQuotedId(TextWriter trapFile) { trapFile.Write("@\""); WriteId(trapFile); @@ -26,21 +22,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write('\"'); } - public abstract string IdSuffix { get; } - - Location IEntity.ReportingLocation => throw new NotImplementedException(); - - public void Extract(Context cx2) { cx2.Populate(this); } - - public abstract IEnumerable Contents { get; } - - public override string ToString() - { - using var writer = new StringWriter(); - WriteQuotedId(writer); - return writer.ToString(); - } - - TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; + public abstract IEnumerable MethodParameters { get; } + public abstract IEnumerable TypeParameters { get; } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeDefinitionType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeDefinitionType.cs index 44bb9020813..461141ae719 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeDefinitionType.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeDefinitionType.cs @@ -1,12 +1,10 @@ using System; -using Microsoft.CodeAnalysis; -using System.Reflection.Metadata; -using System.Collections.Immutable; using System.Linq; using System.Collections.Generic; using System.Reflection; using System.IO; using System.Reflection.Metadata.Ecma335; +using System.Reflection.Metadata; namespace Semmle.Extraction.CIL.Entities { diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeParameter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeParameter.cs index 7c8d2222fa5..fd18374ed2d 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeParameter.cs @@ -9,9 +9,9 @@ namespace Semmle.Extraction.CIL.Entities { internal abstract class TypeParameter : Type { - protected readonly GenericContext gc; + protected readonly IGenericContext gc; - protected TypeParameter(GenericContext gc) : base(gc.Cx) + protected TypeParameter(IGenericContext gc) : base(gc.Cx) { this.gc = gc; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeReferenceType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeReferenceType.cs index 2ffa9e9e5d8..49a15965dd0 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeReferenceType.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeReferenceType.cs @@ -1,7 +1,5 @@ using System; -using Microsoft.CodeAnalysis; using System.Reflection.Metadata; -using System.Collections.Immutable; using System.Linq; using System.Collections.Generic; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs index dcb986f1526..4417becc58d 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs @@ -1,13 +1,14 @@ using System; using System.Reflection.Metadata; using System.Collections.Immutable; +using System.Linq; namespace Semmle.Extraction.CIL.Entities { /// /// Decodes a type signature and produces a Type, for use by DecodeSignature() and friends. /// - public class TypeSignatureDecoder : ISignatureTypeProvider + public class TypeSignatureDecoder : ISignatureTypeProvider { private readonly Context cx; @@ -22,22 +23,22 @@ namespace Semmle.Extraction.CIL.Entities Type IConstructedTypeProvider.GetByReferenceType(Type elementType) => new ByRefType(cx, elementType); - Type ISignatureTypeProvider.GetFunctionPointerType(MethodSignature signature) => + Type ISignatureTypeProvider.GetFunctionPointerType(MethodSignature signature) => cx.Populate(new FunctionPointerType(cx, signature)); Type IConstructedTypeProvider.GetGenericInstantiation(Type genericType, ImmutableArray typeArguments) => genericType.Construct(typeArguments); - Type ISignatureTypeProvider.GetGenericMethodParameter(GenericContext genericContext, int index) => - genericContext.GetGenericMethodParameter(index); + Type ISignatureTypeProvider.GetGenericMethodParameter(IGenericContext genericContext, int index) => + genericContext.MethodParameters.ElementAt(index); - Type ISignatureTypeProvider.GetGenericTypeParameter(GenericContext genericContext, int index) => - genericContext.GetGenericTypeParameter(index); + Type ISignatureTypeProvider.GetGenericTypeParameter(IGenericContext genericContext, int index) => + genericContext.TypeParameters.ElementAt(index); - Type ISignatureTypeProvider.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) => + Type ISignatureTypeProvider.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) => new ModifiedType(cx, unmodifiedType, modifier, isRequired); - Type ISignatureTypeProvider.GetPinnedType(Type elementType) => elementType; + Type ISignatureTypeProvider.GetPinnedType(Type elementType) => elementType; Type IConstructedTypeProvider.GetPointerType(Type elementType) => cx.Populate(new PointerType(cx, elementType)); @@ -53,7 +54,7 @@ namespace Semmle.Extraction.CIL.Entities Type ISimpleTypeProvider.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) => (Type)cx.Create(handle); - Type ISignatureTypeProvider.GetTypeFromSpecification(MetadataReader reader, GenericContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind) => + Type ISignatureTypeProvider.GetTypeFromSpecification(MetadataReader reader, IGenericContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind) => throw new NotImplementedException(); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs b/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs deleted file mode 100644 index 52415af9349..00000000000 --- a/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace Semmle.Extraction.CIL -{ - /// - /// Something that is extracted from an entity. - /// - /// - /// - /// The extraction algorithm proceeds as follows: - /// - Construct entity - /// - Call Extract() - /// - IExtractedEntity check if already extracted - /// - Enumerate Contents to produce more extraction products - /// - Extract these until there is nothing left to extract - /// - public interface IExtractionProduct - { - /// - /// Perform further extraction/population of this item as necessary. - /// - /// - /// The extraction context. - void Extract(Context cx); - } - - /// - /// An entity which has been extracted. - /// - public interface IExtractedEntity : IEntity, IExtractionProduct - { - /// - /// The contents of the entity. - /// - IEnumerable Contents { get; } - } - - /// - /// An entity that has contents to extract. There is no need to populate - /// a key as it's done in the contructor. - /// - public abstract class UnlabelledEntity : IExtractedEntity - { - public abstract IEnumerable Contents { get; } - public Label Label { get; set; } - - public void WriteId(System.IO.TextWriter trapFile) - { - trapFile.Write('*'); - } - - public void WriteQuotedId(TextWriter trapFile) - { - WriteId(trapFile); - } - - public Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException(); - - public virtual void Extract(Context cx2) - { - cx2.Extract(this); - } - - public Context Cx { get; } - - protected UnlabelledEntity(Context cx) - { - this.Cx = cx; - cx.Cx.AddFreshLabel(this); - } - - TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; - } - - /// - /// An entity that needs to be populated during extraction. - /// This assigns a key and optionally extracts its contents. - /// - public abstract class LabelledEntity : IExtractedEntity - { - public abstract IEnumerable Contents { get; } - public Label Label { get; set; } - public Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException(); - - public abstract void WriteId(System.IO.TextWriter trapFile); - - public abstract string IdSuffix { get; } - - public void WriteQuotedId(TextWriter trapFile) - { - trapFile.Write("@\""); - WriteId(trapFile); - trapFile.Write(IdSuffix); - trapFile.Write('\"'); - } - - public void Extract(Context cx2) - { - cx2.Populate(this); - } - - public Context Cx { get; } - - protected LabelledEntity(Context cx) - { - this.Cx = cx; - } - - public override string ToString() - { - using var writer = new StringWriter(); - WriteQuotedId(writer); - return writer.ToString(); - } - - TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; - } - - /// - /// A tuple that is an extraction product. - /// - internal class Tuple : IExtractionProduct - { - private readonly Extraction.Tuple tuple; - - public Tuple(string name, params object[] args) - { - tuple = new Extraction.Tuple(name, args); - } - - public void Extract(Context cx) - { - cx.Cx.Emit(tuple); - } - - public override string ToString() => tuple.ToString(); - } -} diff --git a/csharp/extractor/Semmle.Extraction.CIL/GenericContext.cs b/csharp/extractor/Semmle.Extraction.CIL/GenericContext.cs deleted file mode 100644 index 6db62bf5bbf..00000000000 --- a/csharp/extractor/Semmle.Extraction.CIL/GenericContext.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Semmle.Extraction.CIL -{ - /// - /// When we decode a type/method signature, we need access to - /// generic parameters. - /// - public abstract class GenericContext - { - public Context Cx { get; } - - protected GenericContext(Context cx) - { - this.Cx = cx; - } - - /// - /// The list of generic type parameters/arguments, including type parameters/arguments of - /// containing types. - /// - public abstract IEnumerable TypeParameters { get; } - - /// - /// The list of generic method parameters. - /// - public abstract IEnumerable MethodParameters { get; } - - /// - /// Gets the `p`th type parameter. - /// - /// The index of the parameter. - /// - /// For constructed types, the supplied type. - /// For unbound types, the type parameter. - /// - public Entities.Type GetGenericTypeParameter(int p) - { - return TypeParameters.ElementAt(p); - } - - /// - /// Gets the `p`th method type parameter. - /// - /// The index of the parameter. - /// - /// For constructed types, the supplied type. - /// For unbound types, the type parameter. - /// - public Entities.Type GetGenericMethodParameter(int p) - { - return MethodParameters.ElementAt(p); - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/MdProvider.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/MdProvider.cs index c6c943032a6..fc22f1f6e94 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/MdProvider.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/MdProvider.cs @@ -2,6 +2,8 @@ using System; using Microsoft.DiaSymReader; using System.Reflection; +#pragma warning disable IDE0060, CA1822 + namespace Semmle.Extraction.PDB { /// @@ -31,3 +33,5 @@ namespace Semmle.Extraction.PDB throw new NotImplementedException(); } } + +#pragma warning restore diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs index c6d02a119dc..81c91946657 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs @@ -76,7 +76,7 @@ namespace Semmle.Extraction.PDB out provider, out _)) { - return new MetadataPdbReader(provider); + return new MetadataPdbReader(provider!); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/Method.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/Method.cs index e0d41bed77a..6a534a4dd20 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/Method.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Reflection.Metadata; using System.Linq; namespace Semmle.Extraction.PDB diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs index 6d49dd8fd85..0a8479fb454 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs @@ -6,7 +6,6 @@ using Microsoft.DiaSymReader; using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata; using System.IO; -using System.Reflection; namespace Semmle.Extraction.PDB { diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs index c84cd6a824f..1f0f1b455dc 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs @@ -1,9 +1,8 @@ -using System.Linq; -using System.Reflection.PortableExecutable; +using System.Reflection.PortableExecutable; namespace Semmle.Extraction.PDB { - internal class PdbReader + internal static class PdbReader { /// /// Returns the PDB information associated with an assembly. diff --git a/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs b/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs index 0ae92386c3e..c8ed3445c6f 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs @@ -14,10 +14,10 @@ namespace Semmle.Extraction.CIL internal static Tuple cil_adder(Event member, Method method) => new Tuple("cil_adder", member, method); - internal static Tuple cil_access(Instruction i, IEntity m) => + internal static Tuple cil_access(Instruction i, IExtractedEntity m) => new Tuple("cil_access", i, m); - internal static Tuple cil_attribute(Attribute attribute, IEntity @object, Method constructor) => + internal static Tuple cil_attribute(Attribute attribute, IExtractedEntity @object, Method constructor) => new Tuple("cil_attribute", attribute, @object, constructor); internal static Tuple cil_attribute_named_argument(Attribute attribute, string name, string value) => @@ -197,7 +197,7 @@ namespace Semmle.Extraction.CIL internal static Tuple cil_custom_modifiers(ICustomModifierReceiver receiver, Type modifier, bool isRequired) => new Tuple("cil_custom_modifiers", receiver, modifier, isRequired ? 1 : 0); - internal static Tuple cil_type_annotation(IEntity receiver, TypeAnnotation annotation) => + internal static Tuple cil_type_annotation(IExtractedEntity receiver, TypeAnnotation annotation) => new Tuple("cil_type_annotation", receiver, (int)annotation); internal static Tuple containerparent(Folder parent, IFileOrFolder child) => @@ -215,7 +215,7 @@ namespace Semmle.Extraction.CIL internal static Tuple locations_default(PdbSourceLocation label, File file, int startLine, int startCol, int endLine, int endCol) => new Tuple("locations_default", label, file, startLine, startCol, endLine, endCol); - internal static Tuple metadata_handle(IEntity entity, Assembly assembly, int handleValue) => + internal static Tuple metadata_handle(IExtractedEntity entity, Assembly assembly, int handleValue) => new Tuple("metadata_handle", entity, assembly, handleValue); internal static Tuple namespaces(Namespace ns, string name) => diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs index 5806bd375b1..1c4142097fe 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs @@ -3,7 +3,7 @@ namespace Semmle.Extraction.CSharp /// /// A command-line driver for the extractor. /// - public class Driver + public static class Driver { public static int Main(string[] args) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index 1222403515f..b04b429993d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp /// public sealed class Analyser : IDisposable { - private IExtractor extractor; + private Extraction.Extractor extractor; private CSharpCompilation compilation; private Layout layout; private bool init; @@ -215,14 +215,12 @@ namespace Semmle.Extraction.CSharp /// /// Extracts compilation-wide entities, such as compilations and compiler diagnostics. /// - public void AnalyseCompilation(string cwd, string[] args) + public void AnalyseCompilation() { - extractionTasks.Add(() => DoAnalyseCompilation(cwd, args)); + extractionTasks.Add(() => DoAnalyseCompilation()); } - - - private void DoAnalyseCompilation(string cwd, string[] args) + private void DoAnalyseCompilation() { try { @@ -232,9 +230,9 @@ namespace Semmle.Extraction.CSharp var projectLayout = layout.LookupProjectOrDefault(transformedAssemblyPath); var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedAssemblyPath, options.TrapCompression, discardDuplicates: false); compilationTrapFile = trapWriter; // Dispose later - var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); + var cx = new Context(extractor, compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); - compilationEntity = new Entities.Compilation(cx, cwd, args); + compilationEntity = Entities.Compilation.Create(cx); } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { @@ -287,7 +285,7 @@ namespace Semmle.Extraction.CSharp if (c.GetAssemblyOrModuleSymbol(r) is IAssemblySymbol assembly) { - var cx = extractor.CreateContext(c, trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); + var cx = new Context(extractor, c, trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); foreach (var module in assembly.Modules) { @@ -373,10 +371,16 @@ namespace Semmle.Extraction.CSharp if (!upToDate) { - var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new SourceScope(tree), AddAssemblyTrapPrefix); - Populators.CompilationUnit.Extract(cx, tree.GetRoot()); + var cx = new Context(extractor, compilation.Clone(), trapWriter, new SourceScope(tree), AddAssemblyTrapPrefix); + // Ensure that the file itself is populated in case the source file is totally empty + var root = tree.GetRoot(); + Extraction.Entities.File.Create(cx, root.SyntaxTree.FilePath); + + var csNode = (CSharpSyntaxNode)root; + csNode.Accept(new CompilationUnitVisitor(cx)); + csNode.Accept(new DirectiveVisitor(cx)); cx.PopulateAll(); - cx.ExtractComments(cx.CommentGenerator); + CommentPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator); cx.PopulateAll(); } } @@ -389,7 +393,7 @@ namespace Semmle.Extraction.CSharp } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { - extractor.Message(new Message("Unhandled exception processing syntax tree", tree.FilePath, null, ex.StackTrace)); + extractor.Message(new Message($"Unhandled exception processing syntax tree. {ex.Message}", tree.FilePath, null, ex.StackTrace)); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs index 08782ec36a7..d5a20e8eef6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Accessor.cs @@ -29,9 +29,9 @@ namespace Semmle.Extraction.CSharp.Entities /// /// Gets the property symbol associated with this accessor. /// - private IPropertySymbol PropertySymbol => GetPropertySymbol(symbol); + private IPropertySymbol PropertySymbol => GetPropertySymbol(Symbol); - public new Accessor OriginalDefinition => Create(Context, symbol.OriginalDefinition); + public new Accessor OriginalDefinition => Create(Context, Symbol.OriginalDefinition); public override void Populate(TextWriter trapFile) { @@ -42,42 +42,42 @@ namespace Semmle.Extraction.CSharp.Entities var prop = PropertySymbol; if (prop == null) { - Context.ModelError(symbol, "Unhandled accessor associated symbol"); + Context.ModelError(Symbol, "Unhandled accessor associated symbol"); return; } var parent = Property.Create(Context, prop); int kind; Accessor unboundAccessor; - if (SymbolEqualityComparer.Default.Equals(symbol, prop.GetMethod)) + if (SymbolEqualityComparer.Default.Equals(Symbol, prop.GetMethod)) { kind = 1; unboundAccessor = Create(Context, prop.OriginalDefinition.GetMethod); } - else if (SymbolEqualityComparer.Default.Equals(symbol, prop.SetMethod)) + else if (SymbolEqualityComparer.Default.Equals(Symbol, prop.SetMethod)) { kind = 2; unboundAccessor = Create(Context, prop.OriginalDefinition.SetMethod); } else { - Context.ModelError(symbol, "Unhandled accessor kind"); + Context.ModelError(Symbol, "Unhandled accessor kind"); return; } - trapFile.accessors(this, kind, symbol.Name, parent, unboundAccessor); + trapFile.accessors(this, kind, Symbol.Name, parent, unboundAccessor); foreach (var l in Locations) trapFile.accessor_location(this, l); Overrides(trapFile); - if (symbol.FromSource() && Block == null) + if (Symbol.FromSource() && Block == null) { trapFile.compiler_generated(this); } - if (symbol.IsInitOnly) + if (Symbol.IsInitOnly) { trapFile.init_only_accessors(this); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs index 9fef80b383a..ba1d2093765 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs @@ -47,7 +47,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate(TextWriter trapFile) { - var type = Type.Create(Context, symbol.AttributeClass); + var type = Type.Create(Context, Symbol.AttributeClass); trapFile.attributes(this, type.TypeRef, entity); trapFile.attribute_location(this, Location); @@ -69,10 +69,10 @@ namespace Semmle.Extraction.CSharp.Entities var ctorArguments = attributeSyntax?.ArgumentList?.Arguments.Where(a => a.NameEquals == null).ToList(); var childIndex = 0; - for (var i = 0; i < symbol.ConstructorArguments.Length; i++) + for (var i = 0; i < Symbol.ConstructorArguments.Length; i++) { - var constructorArgument = symbol.ConstructorArguments[i]; - var paramName = symbol.AttributeConstructor?.Parameters[i].Name; + var constructorArgument = Symbol.ConstructorArguments[i]; + var paramName = Symbol.AttributeConstructor?.Parameters[i].Name; var argSyntax = ctorArguments?.SingleOrDefault(a => a.NameColon != null && a.NameColon.Name.Identifier.Text == paramName); if (argSyntax == null && // couldn't find named argument @@ -89,7 +89,7 @@ namespace Semmle.Extraction.CSharp.Entities childIndex++); } - foreach (var namedArgument in symbol.NamedArguments) + foreach (var namedArgument in Symbol.NamedArguments) { var expr = CreateExpressionFromArgument( namedArgument.Value, @@ -118,7 +118,7 @@ namespace Semmle.Extraction.CSharp.Entities private Semmle.Extraction.Entities.Location location; private Semmle.Extraction.Entities.Location Location => - location ?? (location = Semmle.Extraction.Entities.Location.Create(Context, attributeSyntax is null ? entity.ReportingLocation : attributeSyntax.Name.GetLocation())); + location ?? (location = Context.CreateLocation(attributeSyntax is null ? entity.ReportingLocation : attributeSyntax.Name.GetLocation())); public override bool NeedsPopulation => true; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CallTypeExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CallTypeExtensions.cs new file mode 100644 index 00000000000..6b9564e49dc --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CallTypeExtensions.cs @@ -0,0 +1,27 @@ +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal static class CallTypeExtensions + { + /// + /// Adjust the expression kind to match this call type. + /// + public static ExprKind AdjustKind(this Expression.CallType ct, ExprKind k) + { + if (k == ExprKind.ADDRESS_OF) + { + return k; + } + + switch (ct) + { + case Expression.CallType.Dynamic: + case Expression.CallType.UserOperator: + return ExprKind.OPERATOR_INVOCATION; + default: + return k; + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs index ab6802cf457..e06b6aebe7f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs @@ -13,8 +13,8 @@ namespace Semmle.Extraction.CSharp.Entities { trapFile.commentblock(this); var child = 0; - trapFile.commentblock_location(this, Context.Create(symbol.Location)); - foreach (var l in symbol.CommentLines) + trapFile.commentblock_location(this, Context.CreateLocation(Symbol.Location)); + foreach (var l in Symbol.CommentLines) { trapFile.commentblock_child(this, (CommentLine)l, child++); } @@ -24,11 +24,11 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(Context.Create(symbol.Location)); + trapFile.WriteSubId(Context.CreateLocation(Symbol.Location)); trapFile.Write(";commentblock"); } - public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol.Location; + public override Microsoft.CodeAnalysis.Location ReportingLocation => Symbol.Location; public void BindTo(Label entity, CommentBinding binding) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs index ba1770f20e5..102ea262b39 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs @@ -1,6 +1,4 @@ using Semmle.Extraction.CommentProcessing; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Semmle.Extraction.Entities; using System.IO; @@ -15,123 +13,32 @@ namespace Semmle.Extraction.CSharp.Entities RawText = raw; } - public Microsoft.CodeAnalysis.Location Location => symbol.Item1; + public Microsoft.CodeAnalysis.Location Location => Symbol.Item1; public CommentLineType Type { get; private set; } - public string Text { get { return symbol.Item2; } } + public string Text { get { return Symbol.Item2; } } public string RawText { get; private set; } - public static void Extract(Context cx, SyntaxTrivia trivia) - { - switch (trivia.Kind()) - { - case SyntaxKind.SingleLineDocumentationCommentTrivia: - /* - This is actually a multi-line comment consisting of /// lines. - So split it up. - */ - - var text = trivia.ToFullString(); - - var split = text.Split('\n'); - var currentLocation = trivia.GetLocation().SourceSpan.Start - 3; - - for (var line = 0; line < split.Length - 1; ++line) - { - var fullLine = split[line]; - var nextLineLocation = currentLocation + fullLine.Length + 1; - fullLine = fullLine.TrimEnd('\r'); - var trimmedLine = fullLine; - - var leadingSpaces = trimmedLine.IndexOf('/'); - if (leadingSpaces != -1) - { - fullLine = fullLine.Substring(leadingSpaces); - currentLocation += leadingSpaces; - trimmedLine = trimmedLine.Substring(leadingSpaces + 3); // Remove leading spaces and the "///" - trimmedLine = trimmedLine.Trim(); - - var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(currentLocation, currentLocation + fullLine.Length); - var location = Microsoft.CodeAnalysis.Location.Create(trivia.SyntaxTree, span); - var commentType = CommentLineType.XmlDoc; - cx.CommentGenerator.AddComment(Create(cx, location, commentType, trimmedLine, fullLine)); - } - else - { - cx.ModelError("Unexpected comment format"); - } - currentLocation = nextLineLocation; - } - break; - - case SyntaxKind.SingleLineCommentTrivia: - { - var contents = trivia.ToString().Substring(2); - var commentType = CommentLineType.Singleline; - if (contents.Length > 0 && contents[0] == '/') - { - commentType = CommentLineType.XmlDoc; - contents = contents.Substring(1); // An XML comment. - } - cx.CommentGenerator.AddComment(Create(cx, trivia.GetLocation(), commentType, contents.Trim(), trivia.ToFullString())); - } - break; - case SyntaxKind.MultiLineDocumentationCommentTrivia: - case SyntaxKind.MultiLineCommentTrivia: - /* We receive a single SyntaxTrivia for a multiline block spanning several lines. - So we split it into separate lines - */ - text = trivia.ToFullString(); - - split = text.Split('\n'); - currentLocation = trivia.GetLocation().SourceSpan.Start; - - for (var line = 0; line < split.Length; ++line) - { - var fullLine = split[line]; - var nextLineLocation = currentLocation + fullLine.Length + 1; - fullLine = fullLine.TrimEnd('\r'); - var trimmedLine = fullLine; - if (line == 0) - trimmedLine = trimmedLine.Substring(2); - if (line == split.Length - 1) - trimmedLine = trimmedLine.Substring(0, trimmedLine.Length - 2); - trimmedLine = trimmedLine.Trim(); - - var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(currentLocation, currentLocation + fullLine.Length); - var location = Microsoft.CodeAnalysis.Location.Create(trivia.SyntaxTree, span); - var commentType = line == 0 ? CommentLineType.Multiline : CommentLineType.MultilineContinuation; - cx.CommentGenerator.AddComment(Create(cx, location, commentType, trimmedLine, fullLine)); - currentLocation = nextLineLocation; - } - break; - // Strangely, these are reported as SingleLineCommentTrivia. - case SyntaxKind.DocumentationCommentExteriorTrivia: - cx.ModelError($"Unhandled comment type {trivia.Kind()} for {trivia}"); - break; - } - } - - private Extraction.Entities.Location location; + private Location location; public override void Populate(TextWriter trapFile) { - location = Context.Create(Location); + location = Context.CreateLocation(Location); trapFile.commentline(this, Type == CommentLineType.MultilineContinuation ? CommentLineType.Multiline : Type, Text, RawText); trapFile.commentline_location(this, location); } - public override Microsoft.CodeAnalysis.Location ReportingLocation => location.symbol; + public override Microsoft.CodeAnalysis.Location ReportingLocation => location.Symbol; public override bool NeedsPopulation => true; public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(Context.Create(Location)); + trapFile.WriteSubId(Context.CreateLocation(Location)); trapFile.Write(";commentline"); } - private static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) + internal static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) { var init = (loc, type, text, raw); return CommentLineFactory.Instance.CreateEntity(cx, init, init); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs deleted file mode 100644 index d4f0da99a28..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs +++ /dev/null @@ -1,125 +0,0 @@ -using Microsoft.CodeAnalysis; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Semmle.Util; - -namespace Semmle.Extraction.CSharp.Entities -{ - internal class Compilation : FreshEntity - { - private readonly string cwd; - private readonly string[] args; - - public Compilation(Context cx, string cwd, string[] args) : base(cx) - { - this.cwd = cwd; - this.args = args; - TryPopulate(); - } - - protected override void Populate(TextWriter trapFile) - { - var assembly = Extraction.Entities.Assembly.CreateOutputAssembly(cx); - - trapFile.compilations(this, FileUtils.ConvertToUnix(cwd)); - trapFile.compilation_assembly(this, assembly); - - // Arguments - var index = 0; - foreach (var arg in args) - { - trapFile.compilation_args(this, index++, arg); - } - - // Files - index = 0; - foreach (var file in cx.Compilation.SyntaxTrees.Select(tree => Extraction.Entities.File.Create(cx, tree.FilePath))) - { - trapFile.compilation_compiling_files(this, index++, file); - } - - // References - index = 0; - foreach (var file in cx.Compilation.References.OfType().Select(r => Extraction.Entities.File.Create(cx, r.FilePath))) - { - trapFile.compilation_referencing_files(this, index++, file); - } - - // Diagnostics - index = 0; - foreach (var diag in cx.Compilation.GetDiagnostics().Select(d => new Diagnostic(cx, d))) - { - trapFile.diagnostic_for(diag, this, 0, index++); - } - } - - public void PopulatePerformance(PerformanceMetrics p) - { - var trapFile = cx.TrapWriter.Writer; - var index = 0; - foreach (var metric in p.Metrics) - { - trapFile.compilation_time(this, -1, index++, metric); - } - trapFile.compilation_finished(this, (float)p.Total.Cpu.TotalSeconds, (float)p.Total.Elapsed.TotalSeconds); - } - - public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; - } - - 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) - { - diagnostic = diag; - TryPopulate(); - } - - protected override void Populate(TextWriter trapFile) - { - trapFile.diagnostics(this, (int)diagnostic.Severity, diagnostic.Id, diagnostic.Descriptor.Title.ToString(), - diagnostic.GetMessage(), Extraction.Entities.Location.Create(cx, diagnostic.Location)); - } - } - - public struct Timings - { - public TimeSpan Elapsed { get; set; } - public TimeSpan Cpu { get; set; } - public TimeSpan User { get; set; } - } - - /// - /// The various performance metrics to log. - /// - public struct PerformanceMetrics - { - public Timings Frontend { get; set; } - public Timings Extractor { get; set; } - public Timings Total { get; set; } - public long PeakWorkingSet { get; set; } - - /// - /// These are in database order (0 indexed) - /// - public IEnumerable Metrics - { - get - { - yield return (float)Frontend.Cpu.TotalSeconds; - yield return (float)Frontend.Elapsed.TotalSeconds; - yield return (float)Extractor.Cpu.TotalSeconds; - yield return (float)Extractor.Elapsed.TotalSeconds; - yield return (float)Frontend.User.TotalSeconds; - yield return (float)Extractor.User.TotalSeconds; - yield return PeakWorkingSet / 1024.0f / 1024.0f; - } - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs new file mode 100644 index 00000000000..800e35d5ff4 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs @@ -0,0 +1,105 @@ +using Microsoft.CodeAnalysis; +using System; +using System.IO; +using System.Linq; +using Semmle.Util; + +namespace Semmle.Extraction.CSharp.Entities +{ + public class Compilation : CachedEntity + { + private static (string Cwd, string[] Args) settings; + private static int hashCode; + + public static (string Cwd, string[] Args) Settings + { + get { return settings; } + set + { + settings = value; + hashCode = settings.Cwd.GetHashCode(); + for (var i = 0; i < settings.Args.Length; i++) + { + hashCode = HashCode.Combine(hashCode, settings.Args[i].GetHashCode()); + } + } + } + + private Compilation(Context cx) : base(cx, null) + { + } + + public override void Populate(TextWriter trapFile) + { + var assembly = Extraction.Entities.Assembly.CreateOutputAssembly(Context); + + trapFile.compilations(this, FileUtils.ConvertToUnix(Compilation.Settings.Cwd)); + trapFile.compilation_assembly(this, assembly); + + // Arguments + var index = 0; + foreach (var arg in Compilation.Settings.Args) + { + trapFile.compilation_args(this, index++, arg); + } + + // Files + index = 0; + foreach (var file in Context.Compilation.SyntaxTrees.Select(tree => Extraction.Entities.File.Create(Context, tree.FilePath))) + { + trapFile.compilation_compiling_files(this, index++, file); + } + + // References + index = 0; + foreach (var file in Context.Compilation.References + .OfType() + .Select(r => Extraction.Entities.File.Create(Context, r.FilePath))) + { + trapFile.compilation_referencing_files(this, index++, file); + } + + // Diagnostics + index = 0; + foreach (var diag in Context.Compilation.GetDiagnostics().Select(d => new Diagnostic(Context, d))) + { + trapFile.diagnostic_for(diag, this, 0, index++); + } + } + + public void PopulatePerformance(PerformanceMetrics p) + { + var trapFile = Context.TrapWriter.Writer; + var index = 0; + foreach (var metric in p.Metrics) + { + trapFile.compilation_time(this, -1, index++, metric); + } + trapFile.compilation_finished(this, (float)p.Total.Cpu.TotalSeconds, (float)p.Total.Elapsed.TotalSeconds); + } + + public override void WriteId(TextWriter trapFile) + { + trapFile.Write(hashCode); + trapFile.Write(";compilation"); + } + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public override Location ReportingLocation => throw new NotImplementedException(); + + public override bool NeedsPopulation => Context.IsAssemblyScope; + + private class CompilationFactory : ICachedEntityFactory + { + public static CompilationFactory Instance { get; } = new CompilationFactory(); + + public Compilation Create(Context cx, object init) => new Compilation(cx); + } + + private static readonly object compilationCacheKey = new object(); + + public static Compilation Create(Context cx) + => CompilationFactory.Instance.CreateEntity(cx, compilationCacheKey, null); + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs new file mode 100644 index 00000000000..def6edbf5ad --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs @@ -0,0 +1,23 @@ +using System.IO; + +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) + { + diagnostic = diag; + TryPopulate(); + } + + protected override void Populate(TextWriter trapFile) + { + trapFile.diagnostics(this, (int)diagnostic.Severity, diagnostic.Id, diagnostic.Descriptor.Title.ToString(), + diagnostic.GetMessage(), Context.CreateLocation(diagnostic.Location)); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/PerformanceMetrics.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/PerformanceMetrics.cs new file mode 100644 index 00000000000..67aa2f25a88 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/PerformanceMetrics.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// The various performance metrics to log. + /// + public struct PerformanceMetrics + { + public Timings Frontend { get; set; } + public Timings Extractor { get; set; } + public Timings Total { get; set; } + public long PeakWorkingSet { get; set; } + + /// + /// These are in database order (0 indexed) + /// + public IEnumerable Metrics + { + get + { + yield return (float)Frontend.Cpu.TotalSeconds; + yield return (float)Frontend.Elapsed.TotalSeconds; + yield return (float)Extractor.Cpu.TotalSeconds; + yield return (float)Extractor.Elapsed.TotalSeconds; + yield return (float)Frontend.User.TotalSeconds; + yield return (float)Extractor.User.TotalSeconds; + yield return PeakWorkingSet / 1024.0f / 1024.0f; + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Timings.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Timings.cs new file mode 100644 index 00000000000..43f22922309 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Timings.cs @@ -0,0 +1,11 @@ +using System; + +namespace Semmle.Extraction.CSharp.Entities +{ + public struct Timings + { + public TimeSpan Elapsed { get; set; } + public TimeSpan Cpu { get; set; } + public TimeSpan User { get; set; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs index 499e6ec418a..d04e80324ff 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -19,10 +19,10 @@ namespace Semmle.Extraction.CSharp.Entities PopulateModifiers(trapFile); ContainingType.PopulateGenerics(); - trapFile.constructors(this, symbol.ContainingType.Name, ContainingType, (Constructor)OriginalDefinition); + trapFile.constructors(this, Symbol.ContainingType.Name, ContainingType, (Constructor)OriginalDefinition); trapFile.constructor_location(this, Location); - if (symbol.IsImplicitlyDeclared) + if (Symbol.IsImplicitlyDeclared) { var lineCounts = new LineCounts() { Total = 2, Code = 1, Comment = 0 }; trapFile.numlines(this, lineCounts); @@ -48,10 +48,10 @@ namespace Semmle.Extraction.CSharp.Entities switch (initializer.Kind()) { case SyntaxKind.BaseConstructorInitializer: - initializerType = symbol.ContainingType.BaseType; + initializerType = Symbol.ContainingType.BaseType; break; case SyntaxKind.ThisConstructorInitializer: - initializerType = symbol.ContainingType; + initializerType = Symbol.ContainingType; break; default: Context.ModelError(initializer, "Unknown initializer"); @@ -60,7 +60,7 @@ namespace Semmle.Extraction.CSharp.Entities var initInfo = new ExpressionInfo(Context, AnnotatedTypeSymbol.CreateNotAnnotated(initializerType), - Context.Create(initializer.ThisOrBaseKeyword.GetLocation()), + Context.CreateLocation(initializer.ThisOrBaseKeyword.GetLocation()), Kinds.ExprKind.CONSTRUCTOR_INIT, this, -1, @@ -73,7 +73,7 @@ namespace Semmle.Extraction.CSharp.Entities if (target == null) { - Context.ModelError(symbol, "Unable to resolve call"); + Context.ModelError(Symbol, "Unable to resolve call"); return; } @@ -90,7 +90,7 @@ namespace Semmle.Extraction.CSharp.Entities { get { - return symbol.DeclaringSyntaxReferences + return Symbol.DeclaringSyntaxReferences .Select(r => r.GetSyntax()) .OfType() .FirstOrDefault(); @@ -114,15 +114,15 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - if (symbol.IsStatic) + if (Symbol.IsStatic) trapFile.Write("static"); trapFile.WriteSubId(ContainingType); - AddParametersToId(Context, trapFile, symbol); + AddParametersToId(Context, trapFile, Symbol); trapFile.Write(";constructor"); } private ConstructorDeclarationSyntax GetSyntax() => - symbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax()).OfType().FirstOrDefault(); + Symbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax()).OfType().FirstOrDefault(); public override Microsoft.CodeAnalysis.Location FullLocation => ReportingLocation; @@ -136,12 +136,12 @@ namespace Semmle.Extraction.CSharp.Entities return syn.Identifier.GetLocation(); } - if (symbol.IsImplicitlyDeclared) + if (Symbol.IsImplicitlyDeclared) { return ContainingType.ReportingLocation; } - return symbol.ContainingType.Locations.FirstOrDefault(); + return Symbol.ContainingType.Locations.FirstOrDefault(); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs index aa125cae0a1..05a752cb35c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Conversion.cs @@ -17,11 +17,11 @@ namespace Semmle.Extraction.CSharp.Entities { get { - return symbol.DeclaringSyntaxReferences + return Symbol.DeclaringSyntaxReferences .Select(r => r.GetSyntax()) .OfType() .Select(s => s.FixedLocation()) - .Concat(symbol.Locations) + .Concat(Symbol.Locations) .FirstOrDefault(); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs index a5c4acc3c03..0862baa3600 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Destructor.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulateModifiers(trapFile); ContainingType.PopulateGenerics(); - trapFile.destructors(this, string.Format("~{0}", symbol.ContainingType.Name), ContainingType, OriginalDefinition(Context, this, symbol)); + trapFile.destructors(this, string.Format("~{0}", Symbol.ContainingType.Name), ContainingType, OriginalDefinition(Context, this, Symbol)); trapFile.destructor_location(this, Location); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs index 5c24cf97655..fe095ed4462 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs @@ -14,20 +14,20 @@ namespace Semmle.Extraction.CSharp.Entities { trapFile.WriteSubId(ContainingType); trapFile.Write('.'); - Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations); - trapFile.Write(symbol.Name); + Method.AddExplicitInterfaceQualifierToId(Context, trapFile, Symbol.ExplicitInterfaceImplementations); + trapFile.Write(Symbol.Name); trapFile.Write(";event"); } public override void Populate(TextWriter trapFile) { - PopulateNullability(trapFile, symbol.GetAnnotatedType()); + PopulateNullability(trapFile, Symbol.GetAnnotatedType()); - var type = Type.Create(Context, symbol.Type); - trapFile.events(this, symbol.GetName(), ContainingType, type.TypeRef, Create(Context, symbol.OriginalDefinition)); + var type = Type.Create(Context, Symbol.Type); + trapFile.events(this, Symbol.GetName(), ContainingType, type.TypeRef, Create(Context, Symbol.OriginalDefinition)); - var adder = symbol.AddMethod; - var remover = symbol.RemoveMethod; + var adder = Symbol.AddMethod; + var remover = Symbol.RemoveMethod; if (!(adder is null)) Method.Create(Context, adder); @@ -39,10 +39,10 @@ namespace Semmle.Extraction.CSharp.Entities BindComments(); var declSyntaxReferences = IsSourceDeclaration - ? symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).ToArray() + ? Symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).ToArray() : Enumerable.Empty(); - foreach (var explicitInterface in symbol.ExplicitInterfaceImplementations.Select(impl => Type.Create(Context, impl.ContainingType))) + foreach (var explicitInterface in Symbol.ExplicitInterfaceImplementations.Select(impl => Type.Create(Context, impl.ContainingType))) { trapFile.explicitly_implements(this, explicitInterface.TypeRef); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs index c75b6766dc7..82be6a6e406 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs @@ -11,7 +11,7 @@ namespace Semmle.Extraction.CSharp.Entities /// /// Gets the event symbol associated with this accessor. /// - private IEventSymbol EventSymbol => symbol.AssociatedSymbol as IEventSymbol; + private IEventSymbol EventSymbol => Symbol.AssociatedSymbol as IEventSymbol; public override void Populate(TextWriter trapFile) { @@ -21,30 +21,30 @@ namespace Semmle.Extraction.CSharp.Entities var @event = EventSymbol; if (@event == null) { - Context.ModelError(symbol, "Unhandled event accessor associated symbol"); + Context.ModelError(Symbol, "Unhandled event accessor associated symbol"); return; } var parent = Event.Create(Context, @event); int kind; EventAccessor unboundAccessor; - if (SymbolEqualityComparer.Default.Equals(symbol, @event.AddMethod)) + if (SymbolEqualityComparer.Default.Equals(Symbol, @event.AddMethod)) { kind = 1; unboundAccessor = Create(Context, @event.OriginalDefinition.AddMethod); } - else if (SymbolEqualityComparer.Default.Equals(symbol, @event.RemoveMethod)) + else if (SymbolEqualityComparer.Default.Equals(Symbol, @event.RemoveMethod)) { kind = 2; unboundAccessor = Create(Context, @event.OriginalDefinition.RemoveMethod); } else { - Context.ModelError(symbol, "Undhandled event accessor kind"); + Context.ModelError(Symbol, "Undhandled event accessor kind"); return; } - trapFile.event_accessors(this, kind, symbol.Name, parent, unboundAccessor); + trapFile.event_accessors(this, kind, Symbol.Name, parent, unboundAccessor); foreach (var l in Locations) trapFile.event_accessor_location(this, l); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index 9d701d242a3..fe62bf8323b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -2,8 +2,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Entities.Expressions; -using Semmle.Extraction.CSharp.Populators; -using Semmle.Extraction.Entities; using Semmle.Extraction.Kinds; using System; using System.IO; @@ -11,14 +9,6 @@ using System.Linq; namespace Semmle.Extraction.CSharp.Entities { - public interface IExpressionParentEntity : IEntity - { - /// - /// Whether this entity is the parent of a top-level expression. - /// - bool IsTopLevelParent { get; } - } - internal class Expression : FreshEntity, IExpressionParentEntity { private readonly IExpressionInfo info; @@ -39,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities protected sealed override void Populate(TextWriter trapFile) { - var type = Type.HasValue ? Entities.Type.Create(cx, Type.Value) : NullType.Create(cx); + var type = Type.HasValue ? Entities.Type.Create(Context, Type.Value) : NullType.Create(Context); trapFile.expressions(this, Kind, type.TypeRef); if (info.Parent.IsTopLevelParent) trapFile.expr_parent_top_level(this, info.Child, info.Parent); @@ -49,7 +39,7 @@ namespace Semmle.Extraction.CSharp.Entities if (Type.HasValue && !Type.Value.HasObliviousNullability()) { - var n = NullabilityEntity.Create(cx, Nullability.Create(Type.Value)); + var n = NullabilityEntity.Create(Context, Nullability.Create(Type.Value)); trapFile.type_nullability(this, n); } @@ -67,7 +57,7 @@ namespace Semmle.Extraction.CSharp.Entities type.PopulateGenerics(); } - public override Microsoft.CodeAnalysis.Location ReportingLocation => Location.symbol; + public override Microsoft.CodeAnalysis.Location ReportingLocation => Location.Symbol; bool IExpressionParentEntity.IsTopLevelParent => false; @@ -180,10 +170,10 @@ namespace Semmle.Extraction.CSharp.Entities /// The expression. public void OperatorCall(TextWriter trapFile, ExpressionSyntax node) { - var @operator = cx.GetSymbolInfo(node); + var @operator = Context.GetSymbolInfo(node); if (@operator.Symbol is IMethodSymbol method) { - var callType = GetCallType(cx, node); + var callType = GetCallType(Context, node); if (callType == CallType.Dynamic) { UserOperator.OperatorSymbol(method.Name, out var operatorName); @@ -191,7 +181,7 @@ namespace Semmle.Extraction.CSharp.Entities return; } - trapFile.expr_call(this, Method.Create(cx, method)); + trapFile.expr_call(this, Method.Create(Context, method)); } } @@ -277,7 +267,7 @@ namespace Semmle.Extraction.CSharp.Entities private void PopulateArgument(TextWriter trapFile, ArgumentSyntax arg, int child) { - var expr = Create(cx, arg.Expression, this, child); + var expr = Create(Context, arg.Expression, this, child); int mode; switch (arg.RefOrOutKeyword.Kind()) { @@ -308,290 +298,4 @@ namespace Semmle.Extraction.CSharp.Entities public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } - - internal static class CallTypeExtensions - { - /// - /// Adjust the expression kind to match this call type. - /// - public static ExprKind AdjustKind(this Expression.CallType ct, ExprKind k) - { - if (k == ExprKind.ADDRESS_OF) - { - return k; - } - - switch (ct) - { - case Expression.CallType.Dynamic: - case Expression.CallType.UserOperator: - return ExprKind.OPERATOR_INVOCATION; - default: - return k; - } - } - } - - internal abstract class Expression : Expression - where TExpressionSyntax : ExpressionSyntax - { - public TExpressionSyntax Syntax { get; } - - protected Expression(ExpressionNodeInfo info) - : base(info) - { - Syntax = (TExpressionSyntax)info.Node; - } - - /// - /// Populates expression-type specific relations in the trap file. The general relations - /// expressions and expr_location are populated by the constructor - /// (should not fail), so even if expression-type specific population fails (e.g., in - /// standalone extraction), the expression created via - /// will - /// still be valid. - /// - protected abstract void PopulateExpression(TextWriter trapFile); - - protected new Expression TryPopulate() - { - cx.Try(Syntax, null, () => PopulateExpression(cx.TrapWriter.Writer)); - return this; - } - } - - /// - /// Holds all information required to create an Expression entity. - /// - internal interface IExpressionInfo - { - Context Context { get; } - - /// - /// The type of the expression. - /// - AnnotatedTypeSymbol? Type { get; } - - /// - /// The location of the expression. - /// - Extraction.Entities.Location Location { get; } - - /// - /// The kind of the expression. - /// - ExprKind Kind { get; } - - /// - /// The parent of the expression. - /// - IExpressionParentEntity Parent { get; } - - /// - /// The child index of the expression. - /// - int Child { get; } - - /// - /// Holds if this is an implicit expression. - /// - bool IsCompilerGenerated { get; } - - /// - /// Gets a string representation of the value. - /// null is encoded as the string "null". - /// If the expression does not have a value, then this - /// is null. - /// - string ExprValue { get; } - - NullableFlowState FlowState { get; } - } - - /// - /// Explicitly constructed expression information. - /// - internal class ExpressionInfo : IExpressionInfo - { - public Context Context { get; } - public AnnotatedTypeSymbol? Type { get; } - public Extraction.Entities.Location Location { get; } - public ExprKind Kind { get; } - public IExpressionParentEntity Parent { get; } - public int Child { get; } - public bool IsCompilerGenerated { get; } - public string ExprValue { get; } - - public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Extraction.Entities.Location location, ExprKind kind, - IExpressionParentEntity parent, int child, bool isCompilerGenerated, string value) - { - Context = cx; - Type = type; - Location = location; - Kind = kind; - Parent = parent; - Child = child; - ExprValue = value; - IsCompilerGenerated = isCompilerGenerated; - } - - // Synthetic expressions don't have a flow state. - public NullableFlowState FlowState => NullableFlowState.None; - } - - /// - /// Expression information constructed from a syntax node. - /// - internal class ExpressionNodeInfo : IExpressionInfo - { - public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child) : - this(cx, node, parent, child, cx.GetTypeInfo(node)) - { - } - - public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child, TypeInfo typeInfo) - { - Context = cx; - Node = node; - Parent = parent; - Child = child; - TypeInfo = typeInfo; - Conversion = cx.GetModel(node).GetConversion(node); - } - - public Context Context { get; } - public ExpressionSyntax Node { get; private set; } - public IExpressionParentEntity Parent { get; set; } - public int Child { get; set; } - public TypeInfo TypeInfo { get; } - public Microsoft.CodeAnalysis.CSharp.Conversion Conversion { get; } - - public AnnotatedTypeSymbol ResolvedType => new AnnotatedTypeSymbol(TypeInfo.Type.DisambiguateType(), TypeInfo.Nullability.Annotation); - public AnnotatedTypeSymbol ConvertedType => new AnnotatedTypeSymbol(TypeInfo.ConvertedType.DisambiguateType(), TypeInfo.ConvertedNullability.Annotation); - - private AnnotatedTypeSymbol? cachedType; - private bool cachedTypeSet; - public AnnotatedTypeSymbol? Type - { - get - { - if (cachedTypeSet) - return cachedType; - - var type = ResolvedType; - - if (type.Symbol == null) - type.Symbol = (TypeInfo.Type ?? TypeInfo.ConvertedType).DisambiguateType(); - - // Roslyn workaround: It can't work out the type of "new object[0]" - // Clearly a bug. - if (type.Symbol?.TypeKind == Microsoft.CodeAnalysis.TypeKind.Error) - { - if (Node is ArrayCreationExpressionSyntax arrayCreation) - { - var elementType = Context.GetType(arrayCreation.Type.ElementType); - - if (elementType.Symbol != null) - // There seems to be no way to create an array with a nullable element at present. - return new AnnotatedTypeSymbol(Context.Compilation.CreateArrayTypeSymbol(elementType.Symbol, arrayCreation.Type.RankSpecifiers.Count), NullableAnnotation.NotAnnotated); - } - - Context.ModelError(Node, "Failed to determine type"); - } - - cachedType = type; - cachedTypeSet = true; - - return type; - } - } - - private Microsoft.CodeAnalysis.Location location; - - public Microsoft.CodeAnalysis.Location CodeAnalysisLocation - { - get - { - if (location == null) - location = Node.FixedLocation(); - return location; - } - set - { - location = value; - } - } - - public SemanticModel Model => Context.GetModel(Node); - - public string ExprValue - { - get - { - var c = Model.GetConstantValue(Node); - return c.HasValue ? Expression.ValueAsString(c.Value) : null; - } - } - - private Extraction.Entities.Location cachedLocation; - - public Extraction.Entities.Location Location - { - get - { - if (cachedLocation == null) - cachedLocation = Context.Create(CodeAnalysisLocation); - return cachedLocation; - } - - set - { - cachedLocation = value; - } - } - - public ExprKind Kind { get; set; } = ExprKind.UNKNOWN; - - public bool IsCompilerGenerated { get; set; } - - public ExpressionNodeInfo SetParent(IExpressionParentEntity parent, int child) - { - Parent = parent; - Child = child; - return this; - } - - public ExpressionNodeInfo SetKind(ExprKind kind) - { - Kind = kind; - return this; - } - - public ExpressionNodeInfo SetType(AnnotatedTypeSymbol? type) - { - cachedType = type; - cachedTypeSet = true; - return this; - } - - public ExpressionNodeInfo SetNode(ExpressionSyntax node) - { - Node = node; - return this; - } - - private SymbolInfo cachedSymbolInfo; - - public SymbolInfo SymbolInfo - { - get - { - if (cachedSymbolInfo.Symbol == null && cachedSymbolInfo.CandidateReason == CandidateReason.None) - cachedSymbolInfo = Model.GetSymbolInfo(Node); - return cachedSymbolInfo; - } - } - - public NullableFlowState FlowState => TypeInfo.Nullability.FlowState; - } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs new file mode 100644 index 00000000000..feb1eaa2d93 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs @@ -0,0 +1,36 @@ +using Microsoft.CodeAnalysis; +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// Explicitly constructed expression information. + /// + internal class ExpressionInfo : IExpressionInfo + { + public Context Context { get; } + public AnnotatedTypeSymbol? Type { get; } + public Extraction.Entities.Location Location { get; } + public ExprKind Kind { get; } + public IExpressionParentEntity Parent { get; } + public int Child { get; } + public bool IsCompilerGenerated { get; } + public string ExprValue { get; } + + public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Extraction.Entities.Location location, ExprKind kind, + IExpressionParentEntity parent, int child, bool isCompilerGenerated, string value) + { + Context = cx; + Type = type; + Location = location; + Kind = kind; + Parent = parent; + Child = child; + ExprValue = value; + IsCompilerGenerated = isCompilerGenerated; + } + + // Synthetic expressions don't have a flow state. + public NullableFlowState FlowState => NullableFlowState.None; + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs new file mode 100644 index 00000000000..6968ca65abb --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs @@ -0,0 +1,189 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.CSharp.Populators; +using Semmle.Extraction.Entities; +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// Expression information constructed from a syntax node. + /// + internal class ExpressionNodeInfo : IExpressionInfo + { + public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child) : + this(cx, node, parent, child, cx.GetTypeInfo(node)) + { + } + + public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child, TypeInfo typeInfo) + { + Context = cx; + Node = node; + Parent = parent; + Child = child; + TypeInfo = typeInfo; + Conversion = cx.GetModel(node).GetConversion(node); + } + + public Context Context { get; } + public ExpressionSyntax Node { get; private set; } + public IExpressionParentEntity Parent { get; set; } + public int Child { get; set; } + public TypeInfo TypeInfo { get; } + public Microsoft.CodeAnalysis.CSharp.Conversion Conversion { get; } + + public AnnotatedTypeSymbol ResolvedType => new AnnotatedTypeSymbol(TypeInfo.Type.DisambiguateType(), TypeInfo.Nullability.Annotation); + public AnnotatedTypeSymbol ConvertedType => new AnnotatedTypeSymbol(TypeInfo.ConvertedType.DisambiguateType(), TypeInfo.ConvertedNullability.Annotation); + + private AnnotatedTypeSymbol? cachedType; + private bool cachedTypeSet; + public AnnotatedTypeSymbol? Type + { + get + { + if (cachedTypeSet) + return cachedType; + + var type = ResolvedType; + + if (type.Symbol == null) + type.Symbol = (TypeInfo.Type ?? TypeInfo.ConvertedType).DisambiguateType(); + + // Roslyn workaround: It can't work out the type of "new object[0]" + // Clearly a bug. + if (type.Symbol?.TypeKind == Microsoft.CodeAnalysis.TypeKind.Error) + { + if (Node is ArrayCreationExpressionSyntax arrayCreation) + { + var elementType = Context.GetType(arrayCreation.Type.ElementType); + + if (elementType.Symbol != null) + // There seems to be no way to create an array with a nullable element at present. + return new AnnotatedTypeSymbol(Context.Compilation.CreateArrayTypeSymbol(elementType.Symbol, arrayCreation.Type.RankSpecifiers.Count), NullableAnnotation.NotAnnotated); + } + + Context.ModelError(Node, "Failed to determine type"); + } + + cachedType = type; + cachedTypeSet = true; + + return type; + } + } + + private Microsoft.CodeAnalysis.Location location; + + public Microsoft.CodeAnalysis.Location CodeAnalysisLocation + { + get + { + if (location == null) + location = Node.FixedLocation(); + return location; + } + set + { + location = value; + } + } + + public SemanticModel Model => Context.GetModel(Node); + + public string ExprValue + { + get + { + var c = Model.GetConstantValue(Node); + if (c.HasValue) + { + return Expression.ValueAsString(c.Value); + } + + if (TryGetBoolValueFromLiteral(out var val)) + { + return Expression.ValueAsString(val); + } + + return null; + } + } + + private Extraction.Entities.Location cachedLocation; + + public Extraction.Entities.Location Location + { + get + { + if (cachedLocation == null) + cachedLocation = Context.CreateLocation(CodeAnalysisLocation); + return cachedLocation; + } + + set + { + cachedLocation = value; + } + } + + public ExprKind Kind { get; set; } = ExprKind.UNKNOWN; + + public bool IsCompilerGenerated { get; set; } + + public ExpressionNodeInfo SetParent(IExpressionParentEntity parent, int child) + { + Parent = parent; + Child = child; + return this; + } + + public ExpressionNodeInfo SetKind(ExprKind kind) + { + Kind = kind; + return this; + } + + public ExpressionNodeInfo SetType(AnnotatedTypeSymbol? type) + { + cachedType = type; + cachedTypeSet = true; + return this; + } + + public ExpressionNodeInfo SetNode(ExpressionSyntax node) + { + Node = node; + return this; + } + + private SymbolInfo cachedSymbolInfo; + + public SymbolInfo SymbolInfo + { + get + { + if (cachedSymbolInfo.Symbol == null && cachedSymbolInfo.CandidateReason == CandidateReason.None) + cachedSymbolInfo = Model.GetSymbolInfo(Node); + return cachedSymbolInfo; + } + } + + public NullableFlowState FlowState => TypeInfo.Nullability.FlowState; + + private bool TryGetBoolValueFromLiteral(out bool val) + { + var isTrue = Node.IsKind(SyntaxKind.TrueLiteralExpression); + var isFalse = Node.IsKind(SyntaxKind.FalseLiteralExpression); + + val = isTrue; + return isTrue || isFalse; + } + + public bool IsBoolLiteral() + { + return TryGetBoolValueFromLiteral(out var _); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs new file mode 100644 index 00000000000..6c027076472 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs @@ -0,0 +1,34 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal abstract class Expression : Expression + where TExpressionSyntax : ExpressionSyntax + { + public TExpressionSyntax Syntax { get; } + + protected Expression(ExpressionNodeInfo info) + : base(info) + { + Syntax = (TExpressionSyntax)info.Node; + } + + /// + /// Populates expression-type specific relations in the trap file. The general relations + /// expressions and expr_location are populated by the constructor + /// (should not fail), so even if expression-type specific population fails (e.g., in + /// standalone extraction), the expression created via + /// will + /// still be valid. + /// + protected abstract void PopulateExpression(TextWriter trapFile); + + protected new Expression TryPopulate() + { + Context.Try(Syntax, null, () => PopulateExpression(Context.TrapWriter.Writer)); + return this; + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs index d4d4c86c507..8ef72f8085c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs @@ -47,12 +47,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { if (!(target is null)) { - cx.TrapWriter.Writer.expr_access(this, target); + Context.TrapWriter.Writer.expr_access(this, target); } if (implicitThis && !symbol.IsStatic) { - This.CreateImplicit(cx, symbol.ContainingType, Location, this, -1); + This.CreateImplicit(Context, symbol.ContainingType, Location, this, -1); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs index ea818862d80..3d6d3b95722 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs @@ -31,7 +31,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (TypeSyntax is null) { - cx.ModelError(Syntax, "Array has unexpected type syntax"); + Context.ModelError(Syntax, "Array has unexpected type syntax"); } var firstLevelSizes = TypeSyntax.RankSpecifiers.First()?.Sizes ?? SyntaxFactory.SeparatedList(); @@ -44,20 +44,20 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { for (var sizeIndex = 0; sizeIndex < firstLevelSizes.Count; sizeIndex++) { - Create(cx, firstLevelSizes[sizeIndex], this, sizeIndex); + Create(Context, firstLevelSizes[sizeIndex], this, sizeIndex); } explicitlySized = true; } if (!(Initializer is null)) { - ArrayInitializer.Create(new ExpressionNodeInfo(cx, Initializer, this, InitializerIndex)); + ArrayInitializer.Create(new ExpressionNodeInfo(Context, Initializer, this, InitializerIndex)); } if (explicitlySized) trapFile.explicitly_sized_array_creation(this); - TypeMention.Create(cx, TypeSyntax, this, Type); + TypeMention.Create(Context, TypeSyntax, this, Type); } private void SetArraySizes(InitializerExpressionSyntax initializer, int rank) @@ -69,7 +69,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return; } - Literal.CreateGenerated(cx, this, level, cx.Compilation.GetSpecialType(SpecialType.System_Int32), initializer.Expressions.Count, Location); + Literal.CreateGenerated(Context, this, level, Context.Compilation.GetSpecialType(SpecialType.System_Int32), initializer.Expressions.Count, Location); initializer = initializer.Expressions.FirstOrDefault() as InitializerExpressionSyntax; } @@ -143,7 +143,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - ArrayInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, InitializerIndex)); + ArrayInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, InitializerIndex)); trapFile.implicitly_typed_array_creation(this); trapFile.stackalloc_array_creation(this); } @@ -159,7 +159,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { if (Syntax.Initializer != null) { - ArrayInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, InitializerIndex)); + ArrayInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, InitializerIndex)); } trapFile.implicitly_typed_array_creation(this); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs index f785ce65da3..3325c8075a3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs @@ -26,17 +26,17 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (operatorKind.HasValue) { // Convert assignment such as `a += b` into `a = a + b`. - var simpleAssignExpr = new Expression(new ExpressionInfo(cx, Type, Location, ExprKind.SIMPLE_ASSIGN, this, 2, false, null)); - Create(cx, Syntax.Left, simpleAssignExpr, 1); - var opexpr = new Expression(new ExpressionInfo(cx, Type, Location, operatorKind.Value, simpleAssignExpr, 0, false, null)); - Create(cx, Syntax.Left, opexpr, 0); - Create(cx, Syntax.Right, opexpr, 1); + var simpleAssignExpr = new Expression(new ExpressionInfo(Context, Type, Location, ExprKind.SIMPLE_ASSIGN, this, 2, false, null)); + Create(Context, Syntax.Left, simpleAssignExpr, 1); + var opexpr = new Expression(new ExpressionInfo(Context, Type, Location, operatorKind.Value, simpleAssignExpr, 0, false, null)); + Create(Context, Syntax.Left, opexpr, 0); + Create(Context, Syntax.Right, opexpr, 1); opexpr.OperatorCall(trapFile, Syntax); } else { - Create(cx, Syntax.Left, this, 1); - Create(cx, Syntax.Right, this, 0); + Create(Context, Syntax.Left, this, 1); + Create(Context, Syntax.Right, this, 0); if (Kind == ExprKind.ADD_EVENT || Kind == ExprKind.REMOVE_EVENT) { @@ -148,12 +148,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case ExprKind.ASSIGN_COALESCE: return ExprKind.NULL_COALESCING; default: - cx.ModelError(Syntax, "Couldn't unfold assignment of type " + kind); + Context.ModelError(Syntax, "Couldn't unfold assignment of type " + kind); return ExprKind.UNKNOWN; } } } - public new CallType CallType => GetCallType(cx, Syntax); + public new CallType CallType => GetCallType(Context, Syntax); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs index 2f8726c8070..34088d9564a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs index 32ee3be5f73..74dcc9ff85f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs @@ -17,8 +17,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { OperatorCall(trapFile, Syntax); - CreateDeferred(cx, Syntax.Left, this, 0); - CreateDeferred(cx, Syntax.Right, this, 1); + CreateDeferred(Context, Syntax.Left, this, 0); + CreateDeferred(Context, Syntax.Right, this, 1); } private static ExprKind GetKind(Context cx, BinaryExpressionSyntax node) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs index 6f2551ec904..2afe7a9b37e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs @@ -16,17 +16,17 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, ExpressionIndex); + Create(Context, Syntax.Expression, this, ExpressionIndex); if (Kind == ExprKind.CAST) { // Type cast - TypeAccess.Create(new ExpressionNodeInfo(cx, Syntax.Type, this, TypeAccessIndex)); + TypeAccess.Create(new ExpressionNodeInfo(Context, Syntax.Type, this, TypeAccessIndex)); } else { // Type conversion OperatorCall(trapFile, Syntax); - TypeMention.Create(cx, Syntax.Type, this, Type); + TypeMention.Create(Context, Syntax.Type, this, Type); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs index e6958c4511c..4be8b378937 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs index bfa4a836feb..193c88b112a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs @@ -12,9 +12,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Condition, this, 0); - Create(cx, Syntax.WhenTrue, this, 1); - Create(cx, Syntax.WhenFalse, this, 2); + Create(Context, Syntax.Condition, this, 0); + Create(Context, Syntax.WhenTrue, this, 1); + Create(Context, Syntax.WhenFalse, this, 2); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs index 326516bba1b..9e1b42834b1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - TypeAccess.Create(cx, Syntax.Type, this, 0); + TypeAccess.Create(Context, Syntax.Type, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/DefineSymbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/DefineSymbol.cs new file mode 100644 index 00000000000..d0111c010b2 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/DefineSymbol.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.Kinds; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities.Expressions +{ + internal class DefineSymbol : Expression + { + private DefineSymbol(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.DEFINE_SYMBOL)) { } + + public static Expression Create(ExpressionNodeInfo info) => new DefineSymbol(info).TryPopulate(); + + protected override void PopulateExpression(TextWriter trapFile) + { + trapFile.directive_define_symbols(this, Syntax.Identifier.Text); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs index ef35f901b92..4f2eecca9da 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions } private Discard(Context cx, CSharpSyntaxNode syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, cx.GetType(syntax), cx.Create(syntax.GetLocation()), ExprKind.DISCARD, parent, child, false, null)) + base(new ExpressionInfo(cx, cx.GetType(syntax), cx.CreateLocation(syntax.GetLocation()), ExprKind.DISCARD, parent, child, false, null)) { } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index afc4cd2cd93..e860731ece3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -22,26 +22,22 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { if (Kind == ExprKind.POINTER_INDIRECTION) { - var qualifierInfo = new ExpressionNodeInfo(cx, qualifier, this, 0); - var add = new Expression(new ExpressionInfo(cx, qualifierInfo.Type, Location, ExprKind.ADD, this, 0, false, null)); + var qualifierInfo = new ExpressionNodeInfo(Context, qualifier, this, 0); + var add = new Expression(new ExpressionInfo(Context, qualifierInfo.Type, Location, ExprKind.ADD, this, 0, false, null)); qualifierInfo.SetParent(add, 0); CreateFromNode(qualifierInfo); PopulateArguments(trapFile, argumentList, 1); } else { - var child = -1; - Create(cx, qualifier, this, child++); - foreach (var a in argumentList.Arguments) - { - cx.Extract(a, this, child++); - } + Create(Context, qualifier, this, -1); + PopulateArguments(trapFile, argumentList, 0); - var symbolInfo = cx.GetSymbolInfo(base.Syntax); + var symbolInfo = Context.GetSymbolInfo(base.Syntax); if (symbolInfo.Symbol is IPropertySymbol indexer) { - trapFile.expr_access(this, Indexer.Create(cx, indexer)); + trapFile.expr_access(this, Indexer.Create(Context, indexer)); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs index eccead4a4de..96d8dec039a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions public ImplicitCast(ExpressionNodeInfo info) : base(new ExpressionInfo(info.Context, info.ConvertedType, info.Location, ExprKind.CAST, info.Parent, info.Child, true, info.ExprValue)) { - Expr = Factory.Create(new ExpressionNodeInfo(cx, info.Node, this, 0)); + Expr = Factory.Create(new ExpressionNodeInfo(Context, info.Node, this, 0)); } public ImplicitCast(ExpressionNodeInfo info, IMethodSymbol method) @@ -22,11 +22,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { Expr = Factory.Create(info.SetParent(this, 0)); - var target = Method.Create(cx, method); + var target = Method.Create(Context, method); if (target != null) - cx.TrapWriter.Writer.expr_call(this, target); + Context.TrapWriter.Writer.expr_call(this, target); else - cx.ModelError(info.Node, "Failed to resolve target for operator invocation"); + Context.ModelError(info.Node, "Failed to resolve target for operator invocation"); } /// diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs index d96a44527d8..7e36d1ac789 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs @@ -26,12 +26,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (e.Kind() == SyntaxKind.ArrayInitializerExpression) { // Recursively create another array initializer - Create(new ExpressionNodeInfo(cx, (InitializerExpressionSyntax)e, this, child++)); + Create(new ExpressionNodeInfo(Context, (InitializerExpressionSyntax)e, this, child++)); } else { // Create the expression normally. - Create(cx, e, this, child++); + Create(Context, e, this, child++); } } } @@ -61,7 +61,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - ArrayInitializer.Create(new ExpressionNodeInfo(cx, Syntax, this, -1)); + ArrayInitializer.Create(new ExpressionNodeInfo(Context, Syntax, this, -1)); trapFile.implicitly_typed_array_creation(this); } } @@ -81,9 +81,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { if (init is AssignmentExpressionSyntax assignment) { - var assignmentInfo = new ExpressionNodeInfo(cx, init, this, child++).SetKind(ExprKind.SIMPLE_ASSIGN); + var assignmentInfo = new ExpressionNodeInfo(Context, init, this, child++).SetKind(ExprKind.SIMPLE_ASSIGN); var assignmentEntity = new Expression(assignmentInfo); - var typeInfoRight = cx.GetTypeInfo(assignment.Right); + var typeInfoRight = Context.GetTypeInfo(assignment.Right); if (typeInfoRight.Type is null) // The type may be null for nested initializers such as // ```csharp @@ -92,15 +92,15 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions // In this case we take the type from the assignment // `As = { [0] = a }` instead typeInfoRight = assignmentInfo.TypeInfo; - CreateFromNode(new ExpressionNodeInfo(cx, assignment.Right, assignmentEntity, 0, typeInfoRight)); + CreateFromNode(new ExpressionNodeInfo(Context, assignment.Right, assignmentEntity, 0, typeInfoRight)); - var target = cx.GetSymbolInfo(assignment.Left); + var target = Context.GetSymbolInfo(assignment.Left); // If the target is null, then assume that this is an array initializer (of the form `[...] = ...`) var access = target.Symbol is null ? - new Expression(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1).SetKind(ExprKind.ARRAY_ACCESS)) : - Access.Create(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1), target.Symbol, false, cx.CreateEntity(target.Symbol)); + new Expression(new ExpressionNodeInfo(Context, assignment.Left, assignmentEntity, 1).SetKind(ExprKind.ARRAY_ACCESS)) : + Access.Create(new ExpressionNodeInfo(Context, assignment.Left, assignmentEntity, 1), target.Symbol, false, Context.CreateEntity(target.Symbol)); if (assignment.Left is ImplicitElementAccessSyntax iea) { @@ -109,14 +109,14 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var indexChild = 0; foreach (var arg in iea.ArgumentList.Arguments) { - Expression.Create(cx, arg.Expression, access, indexChild++); + Expression.Create(Context, arg.Expression, access, indexChild++); } } } else { - cx.ModelError(init, "Unexpected object initialization"); - Create(cx, init, this, child++); + Context.ModelError(init, "Unexpected object initialization"); + Create(Context, init, this, child++); } } } @@ -133,16 +133,16 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var child = 0; foreach (var i in Syntax.Expressions) { - var collectionInfo = cx.GetModel(Syntax).GetCollectionInitializerSymbolInfo(i); - var addMethod = Method.Create(cx, collectionInfo.Symbol as IMethodSymbol); - var voidType = AnnotatedTypeSymbol.CreateNotAnnotated(cx.Compilation.GetSpecialType(SpecialType.System_Void)); + var collectionInfo = Context.GetModel(Syntax).GetCollectionInitializerSymbolInfo(i); + var addMethod = Method.Create(Context, collectionInfo.Symbol as IMethodSymbol); + var voidType = AnnotatedTypeSymbol.CreateNotAnnotated(Context.Compilation.GetSpecialType(SpecialType.System_Void)); - var invocation = new Expression(new ExpressionInfo(cx, voidType, cx.Create(i.GetLocation()), ExprKind.METHOD_INVOCATION, this, child++, false, null)); + var invocation = new Expression(new ExpressionInfo(Context, voidType, Context.CreateLocation(i.GetLocation()), ExprKind.METHOD_INVOCATION, this, child++, false, null)); if (addMethod != null) trapFile.expr_call(invocation, addMethod); else - cx.ModelError(Syntax, "Unable to find an Add() method for collection initializer"); + Context.ModelError(Syntax, "Unable to find an Add() method for collection initializer"); if (i.Kind() == SyntaxKind.ComplexElementInitializerExpression) { @@ -154,12 +154,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var addChild = 0; foreach (var arg in init.Expressions) { - Create(cx, arg, invocation, addChild++); + Create(Context, arg, invocation, addChild++); } } else { - Create(cx, i, invocation, 0); + Create(Context, i, invocation, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs index 152ff145897..ee69580f83a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs @@ -22,12 +22,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { case SyntaxKind.Interpolation: var interpolation = (InterpolationSyntax)c; - Create(cx, interpolation.Expression, this, child++); + Create(Context, interpolation.Expression, this, child++); break; case SyntaxKind.InterpolatedStringText: // Create a string literal var interpolatedText = (InterpolatedStringTextSyntax)c; - new Expression(new ExpressionInfo(cx, Type, cx.Create(c.GetLocation()), ExprKind.STRING_LITERAL, this, child++, false, interpolatedText.TextToken.Text)); + new Expression(new ExpressionInfo(Context, Type, Context.CreateLocation(c.GetLocation()), ExprKind.STRING_LITERAL, this, child++, false, interpolatedText.TextToken.Text)); break; default: throw new InternalError(c, $"Unhandled interpolation kind {c.Kind()}"); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs index 638822f3d27..408556dff63 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs @@ -37,15 +37,15 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions memberName = memberAccess.Name.Identifier.Text; if (Syntax.Expression.Kind() == SyntaxKind.SimpleMemberAccessExpression) // Qualified method call; `x.M()` - Create(cx, memberAccess.Expression, this, child++); + Create(Context, memberAccess.Expression, this, child++); else // Pointer member access; `x->M()` - Create(cx, Syntax.Expression, this, child++); + Create(Context, Syntax.Expression, this, child++); break; case MemberBindingExpressionSyntax memberBinding: // Conditionally qualified method call; `x?.M()` memberName = memberBinding.Name.Identifier.Text; - Create(cx, FindConditionalQualifier(memberBinding), this, child++); + Create(Context, FindConditionalQualifier(memberBinding), this, child++); MakeConditional(trapFile); break; case SimpleNameSyntax simpleName when (Kind == ExprKind.METHOD_INVOCATION): @@ -55,10 +55,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { // Implicit `this` qualifier; add explicitly - if (cx.GetModel(Syntax).GetEnclosingSymbol(Location.symbol.SourceSpan.Start) is IMethodSymbol callingMethod) - This.CreateImplicit(cx, callingMethod.ContainingType, Location, this, child++); + if (Context.GetModel(Syntax).GetEnclosingSymbol(Location.Symbol.SourceSpan.Start) is IMethodSymbol callingMethod) + This.CreateImplicit(Context, callingMethod.ContainingType, Location, this, child++); else - cx.ModelError(Syntax, "Couldn't determine implicit this type"); + Context.ModelError(Syntax, "Couldn't determine implicit this type"); } else { @@ -68,7 +68,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions break; default: // Delegate or function pointer call; `d()` - Create(cx, Syntax.Expression, this, child++); + Create(Context, Syntax.Expression, this, child++); break; } @@ -78,7 +78,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (memberName != null) trapFile.dynamic_member_name(this, memberName); else - cx.ModelError(Syntax, "Unable to get name for dynamic call."); + Context.ModelError(Syntax, "Unable to get name for dynamic call."); } PopulateArguments(trapFile, Syntax.ArgumentList, child); @@ -86,11 +86,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (target == null) { if (!isDynamicCall && !IsDelegateLikeCall(info)) - cx.ModelError(Syntax, "Unable to resolve target for call. (Compilation error?)"); + Context.ModelError(Syntax, "Unable to resolve target for call. (Compilation error?)"); return; } - var targetKey = Method.Create(cx, target); + var targetKey = Method.Create(Context, target); trapFile.expr_call(this, targetKey); } @@ -125,7 +125,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions .Where(method => method.Parameters.Length >= Syntax.ArgumentList.Arguments.Count) .Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= Syntax.ArgumentList.Arguments.Count); - return cx.Extractor.Standalone ? + return Context.Extractor.Standalone ? candidates.FirstOrDefault() : candidates.SingleOrDefault(); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs index 741d108ba01..1c335474a68 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs @@ -12,8 +12,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); - Expressions.Pattern.Create(cx, Syntax.Pattern, this, 1); + Create(Context, Syntax.Expression, this, 0); + Expressions.Pattern.Create(Context, Syntax.Pattern, this, 1); } public static Expression Create(ExpressionNodeInfo info) => new IsPattern(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs index 40f200ef5ef..2cd23101b1c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs @@ -17,34 +17,34 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private void VisitParameter(ParameterSyntax p) { - var symbol = cx.GetModel(p).GetDeclaredSymbol(p); - Parameter.Create(cx, symbol, this); + var symbol = Context.GetModel(p).GetDeclaredSymbol(p); + Parameter.Create(Context, symbol, this); } private Lambda(ExpressionNodeInfo info, CSharpSyntaxNode body, IEnumerable @params) : base(info) { - if (cx.GetModel(info.Node).GetSymbolInfo(info.Node).Symbol is IMethodSymbol symbol) + if (Context.GetModel(info.Node).GetSymbolInfo(info.Node).Symbol is IMethodSymbol symbol) { - Modifier.ExtractModifiers(cx, info.Context.TrapWriter.Writer, this, symbol); + Modifier.ExtractModifiers(Context, info.Context.TrapWriter.Writer, this, symbol); } else { - cx.ModelError(info.Node, "Unknown declared symbol"); + Context.ModelError(info.Node, "Unknown declared symbol"); } // No need to use `Populate` as the population happens later - cx.PopulateLater(() => + Context.PopulateLater(() => { foreach (var param in @params) VisitParameter(param); if (body is ExpressionSyntax exprBody) - Create(cx, exprBody, this, 0); + Create(Context, exprBody, this, 0); else if (body is BlockSyntax blockBody) - Statements.Block.Create(cx, blockBody, this, 0); + Statements.Block.Create(Context, blockBody, this, 0); else - cx.ModelError(body, "Unhandled lambda body"); + Context.ModelError(body, "Unhandled lambda body"); }); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs index ad63cc26ac6..51acebef5c8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs @@ -25,6 +25,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return ExprKind.NULL_LITERAL; } + // short circuit bool literals, because they have no type in `#if A = true` + if (info.IsBoolLiteral()) + { + return ExprKind.BOOL_LITERAL; + } + var type = info.Type?.Symbol; return GetExprKind(type, info.Node, info.Context); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs index 751d6b6e92c..66f2fd8676a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs index 7d2777540f0..fa9d3c9a6dd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs @@ -9,16 +9,16 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private MemberAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, ISymbol target) : base(info) { var trapFile = info.Context.TrapWriter.Writer; - Qualifier = Create(cx, qualifier, this, -1); + Qualifier = Create(Context, qualifier, this, -1); if (target == null) { if (info.Kind != ExprKind.DYNAMIC_MEMBER_ACCESS) - cx.ModelError(info.Node, "Could not determine target for member access"); + Context.ModelError(info.Node, "Could not determine target for member access"); } else { - var t = cx.CreateEntity(target); + var t = Context.CreateEntity(target); trapFile.expr_access(this, t); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs index d44c85d6ddc..faf5c9e2bd1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs @@ -1,5 +1,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Linq; namespace Semmle.Extraction.CSharp.Entities.Expressions @@ -26,6 +27,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (target == null) { + if (IsInsideIfDirective(info.Node)) + { + return DefineSymbol.Create(info); + } + info.Context.ModelError(info.Node, "Failed to resolve name"); return new Unknown(info); } @@ -64,5 +70,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions throw new InternalError(info.Node, $"Unhandled identifier kind '{target.Kind}'"); } } + + private static bool IsInsideIfDirective(ExpressionSyntax node) + { + return node.Ancestors().Any(a => a is ElifDirectiveTriviaSyntax || a is IfDirectiveTriviaSyntax); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs index 5703c3101a2..df291c4e9fd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs @@ -17,32 +17,32 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - var target = cx.GetSymbolInfo(Syntax); + var target = Context.GetSymbolInfo(Syntax); var method = (IMethodSymbol)target.Symbol; if (method != null) { - trapFile.expr_call(this, Method.Create(cx, method)); + trapFile.expr_call(this, Method.Create(Context, method)); } var child = 0; var objectInitializer = Syntax.Initializers.Any() ? - new Expression(new ExpressionInfo(cx, Type, Location, ExprKind.OBJECT_INIT, this, -1, false, null)) : + new Expression(new ExpressionInfo(Context, Type, Location, ExprKind.OBJECT_INIT, this, -1, false, null)) : null; foreach (var init in Syntax.Initializers) { // Create an "assignment" - var property = cx.GetModel(init).GetDeclaredSymbol(init); - var propEntity = Property.Create(cx, property); + var property = Context.GetModel(init).GetDeclaredSymbol(init); + var propEntity = Property.Create(Context, property); var type = property.GetAnnotatedType(); - var loc = cx.Create(init.GetLocation()); + var loc = Context.CreateLocation(init.GetLocation()); - var assignment = new Expression(new ExpressionInfo(cx, type, loc, ExprKind.SIMPLE_ASSIGN, objectInitializer, child++, false, null)); - Create(cx, init.Expression, assignment, 0); - Property.Create(cx, property); + var assignment = new Expression(new ExpressionInfo(Context, type, loc, ExprKind.SIMPLE_ASSIGN, objectInitializer, child++, false, null)); + Create(Context, init.Expression, assignment, 0); + Property.Create(Context, property); - var access = new Expression(new ExpressionInfo(cx, type, loc, ExprKind.PROPERTY_ACCESS, assignment, 1, false, null)); + var access = new Expression(new ExpressionInfo(Context, type, loc, ExprKind.PROPERTY_ACCESS, assignment, 1, false, null)); trapFile.expr_access(access, propEntity); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/BaseObjectCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/BaseObjectCreation.cs index 10f4df8bf7f..6f2c38b63db 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/BaseObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/BaseObjectCreation.cs @@ -22,22 +22,22 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions PopulateArguments(trapFile, Syntax.ArgumentList, 0); } - var target = cx.GetModel(Syntax).GetSymbolInfo(Syntax); + var target = Context.GetModel(Syntax).GetSymbolInfo(Syntax); if (target.Symbol is IMethodSymbol method) { - trapFile.expr_call(this, Method.Create(cx, method)); + trapFile.expr_call(this, Method.Create(Context, method)); } - if (IsDynamicObjectCreation(cx, Syntax)) + if (IsDynamicObjectCreation(Context, Syntax)) { - if (cx.GetModel(Syntax).GetTypeInfo(Syntax).Type is INamedTypeSymbol type && + if (Context.GetModel(Syntax).GetTypeInfo(Syntax).Type is INamedTypeSymbol type && !string.IsNullOrEmpty(type.Name)) { trapFile.dynamic_member_name(this, type.Name); } else { - cx.ModelError(Syntax, "Unable to get name for dynamic object creation."); + Context.ModelError(Syntax, "Unable to get name for dynamic object creation."); } } @@ -46,13 +46,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions switch (Syntax.Initializer.Kind()) { case SyntaxKind.CollectionInitializerExpression: - CollectionInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1).SetType(Type)); + CollectionInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, -1).SetType(Type)); break; case SyntaxKind.ObjectInitializerExpression: - ObjectInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1).SetType(Type)); + ObjectInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, -1).SetType(Type)); break; default: - cx.ModelError("Unhandled initializer in object creation"); + Context.ModelError("Unhandled initializer in object creation"); break; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/ExplicitObjectCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/ExplicitObjectCreation.cs index 51b2db20a9e..f51ab0cb810 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/ExplicitObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/ExplicitObjectCreation.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { base.PopulateExpression(trapFile); - TypeMention.Create(cx, Syntax.Type, this, Type); + TypeMention.Create(Context, Syntax.Type, this, Type); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/BinaryPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/BinaryPattern.cs index 33ea47d057b..2d0292ae720 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/BinaryPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/BinaryPattern.cs @@ -9,7 +9,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class BinaryPattern : Expression { public BinaryPattern(Context cx, BinaryPatternSyntax syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), GetKind(syntax.OperatorToken, syntax), parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(syntax.GetLocation()), GetKind(syntax.OperatorToken, syntax), parent, child, false, null)) { Pattern.Create(cx, syntax.Left, this, 0); Pattern.Create(cx, syntax.Right, this, 1); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs index 65912ba12f1..05f3aab2526 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs @@ -34,7 +34,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (cx.GetModel(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol) { var type = symbol.GetAnnotatedType(); - return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.Create(syntax.GetLocation()), false, parent, child); + return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.CreateLocation(syntax.GetLocation()), false, parent, child); } if (designation is DiscardDesignationSyntax) { @@ -61,7 +61,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var type = symbol.GetAnnotatedType(); - return VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), true, parent, child); + return VariableDeclaration.Create(cx, symbol, type, null, cx.CreateLocation(syntax.GetLocation()), true, parent, child); } throw new InternalError(varPattern, "Unable to get the declared symbol of the var pattern designation."); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PositionalPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PositionalPattern.cs index 0f3c2bf8800..f0ae03ae9dc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PositionalPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PositionalPattern.cs @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class PositionalPattern : Expression { internal PositionalPattern(Context cx, PositionalPatternClauseSyntax posPc, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(posPc.GetLocation()), ExprKind.POSITIONAL_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(posPc.GetLocation()), ExprKind.POSITIONAL_PATTERN, parent, child, false, null)) { child = 0; foreach (var sub in posPc.Subpatterns) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PropertyPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PropertyPattern.cs index ed947990045..7bd13e7a8a3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PropertyPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PropertyPattern.cs @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class PropertyPattern : Expression { internal PropertyPattern(Context cx, PropertyPatternClauseSyntax pp, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(pp.GetLocation()), ExprKind.PROPERTY_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(pp.GetLocation()), ExprKind.PROPERTY_PATTERN, parent, child, false, null)) { child = 0; var trapFile = cx.TrapWriter.Writer; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs index 02246311648..d29292b3073 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs @@ -16,7 +16,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions /// The parent pattern/expression. /// The child index of this pattern. public RecursivePattern(Context cx, RecursivePatternSyntax syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), ExprKind.RECURSIVE_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(syntax.GetLocation()), ExprKind.RECURSIVE_PATTERN, parent, child, false, null)) { // Extract the type access if (syntax.Type is TypeSyntax t) @@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var type = symbol.GetAnnotatedType(); - VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), false, this, 0); + VariableDeclaration.Create(cx, symbol, type, null, cx.CreateLocation(syntax.GetLocation()), false, this, 0); } if (syntax.PositionalPatternClause is PositionalPatternClauseSyntax posPc) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs index 77efd5668c4..c1a140005dc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs @@ -9,7 +9,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class RelationalPattern : Expression { public RelationalPattern(Context cx, RelationalPatternSyntax syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), GetKind(syntax.OperatorToken), parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(syntax.GetLocation()), GetKind(syntax.OperatorToken), parent, child, false, null)) { Expression.Create(cx, syntax.Expression, this, 0); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs index d80c390efff..ce2cf773a92 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class UnaryPattern : Expression { public UnaryPattern(Context cx, UnaryPatternSyntax syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), ExprKind.NOT_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(syntax.GetLocation()), ExprKind.NOT_PATTERN, parent, child, false, null)) { Pattern.Create(cx, syntax.Pattern, this, 0); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs index 01df338d1b3..a8ea0a30780 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); // !! We do not currently look at the member (or store the member name). } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs index 30c6058d95f..24d07441964 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs @@ -20,7 +20,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, operand, this, 0); + Create(Context, operand, this, 0); OperatorCall(trapFile, Syntax); if ((operatorKind == ExprKind.POST_INCR || operatorKind == ExprKind.POST_DECR) && diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs index 1db6c39fef2..f919aaca568 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { public QueryCall(Context cx, IMethodSymbol method, SyntaxNode clause, IExpressionParentEntity parent, int child) : base(new ExpressionInfo(cx, method?.GetAnnotatedReturnType(), - cx.Create(clause.GetLocation()), + cx.CreateLocation(clause.GetLocation()), ExprKind.METHOD_INVOCATION, parent, child, false, null)) { if (method != null) @@ -89,7 +89,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions variableSymbol, declType, declTypeSyntax, - cx.Create(node.GetLocation()), + cx.CreateLocation(node.GetLocation()), true, parent, child @@ -97,7 +97,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions Expression.Create(cx, Expr, decl, 0); - var nameLoc = cx.Create(name.GetLocation()); + var nameLoc = cx.CreateLocation(name.GetLocation()); var access = new Expression(new ExpressionInfo(cx, type, nameLoc, ExprKind.LOCAL_VARIABLE_ACCESS, decl, 1, false, null)); cx.TrapWriter.Writer.expr_access(access, LocalVariable.Create(cx, variableSymbol)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs index db5cd138155..2011f4ae367 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs @@ -13,9 +13,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { if (!(Syntax.LeftOperand is null)) - Expression.Create(cx, Syntax.LeftOperand, this, 0); + Expression.Create(Context, Syntax.LeftOperand, this, 0); if (!(Syntax.RightOperand is null)) - Expression.Create(cx, Syntax.RightOperand, this, 1); + Expression.Create(Context, Syntax.RightOperand, this, 1); } public static Expression Create(ExpressionNodeInfo info) => new RangeExpression(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs index 5b38b9b8ee6..ef28f5d7e25 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs index 37f7e2a3f76..815a5928f51 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs index 2372cc4bb09..7d9187533ae 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs @@ -12,8 +12,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); - Create(cx, Syntax.Type, this, 1); // A type-access + Create(Context, Syntax.Expression, this, 0); + Create(Context, Syntax.Type, this, 1); // A type-access } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs index a4b89928e00..d55fe1781ce 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - TypeAccess.Create(cx, Syntax.Type, this, 0); + TypeAccess.Create(Context, Syntax.Type, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs index 5fdc08c66d3..3dbe496cd4c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs @@ -17,10 +17,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - SwitchedExpr = Expression.Create(cx, Syntax.GoverningExpression, this, -1); + SwitchedExpr = Expression.Create(Context, Syntax.GoverningExpression, this, -1); for (var i = 0; i < Syntax.Arms.Count; i++) { - new SwitchCase(cx, Syntax.Arms[i], this, i); + new SwitchCase(Context, Syntax.Arms[i], this, i); } } } @@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { internal SwitchCase(Context cx, SwitchExpressionArmSyntax arm, Switch parent, int child) : base(new ExpressionInfo( - cx, cx.GetType(arm.Expression), cx.Create(arm.GetLocation()), + cx, cx.GetType(arm.Expression), cx.CreateLocation(arm.GetLocation()), ExprKind.SWITCH_CASE, parent, child, false, null)) { Expressions.Pattern.Create(cx, arm.Pattern, this, 0); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs index 5ef8feaebb6..36d0b34bf95 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs index f2911bdcf75..726f8f540d7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var child = 0; foreach (var argument in Syntax.Arguments.Select(a => a.Expression)) { - Expression.Create(cx, argument, this, child++); + Expression.Create(Context, argument, this, child++); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs index e5c0fd3ac66..54b9730e3d7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs @@ -18,17 +18,17 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (Type?.Symbol.ContainingType is null) { // namespace qualifier - TypeMention.Create(cx, maes.Name, this, Type, Syntax.GetLocation()); + TypeMention.Create(Context, maes.Name, this, Type, Syntax.GetLocation()); } else { // type qualifier - TypeMention.Create(cx, maes.Name, this, Type); - Create(cx, maes.Expression, this, -1); + TypeMention.Create(Context, maes.Name, this, Type); + Create(Context, maes.Expression, this, -1); } return; default: - TypeMention.Create(cx, (TypeSyntax)Syntax, this, Type); + TypeMention.Create(Context, (TypeSyntax)Syntax, this, Type); return; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs index 686e4156528..6e5dc3e05f1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - TypeAccess.Create(cx, Syntax.Type, this, TypeAccessIndex); + TypeAccess.Create(Context, Syntax.Type, this, TypeAccessIndex); } public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, Extraction.Entities.Location location) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs index f3c2c73b074..8cad73d6565 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Operand, this, 0); + Create(Context, Syntax.Operand, this, 0); OperatorCall(trapFile, Syntax); if ((operatorKind == ExprKind.PRE_INCR || operatorKind == ExprKind.PRE_DECR) && diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs index 5ffcf414132..016c3fcefc8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs index 349236e893a..674f45b3f21 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs @@ -50,7 +50,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions public static Expression CreateParenthesized(Context cx, DeclarationExpressionSyntax node, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child) { AnnotatedTypeSymbol? type = null; // Should ideally be a corresponding tuple type - var tuple = new Expression(new ExpressionInfo(cx, type, cx.Create(node.GetLocation()), ExprKind.TUPLE, parent, child, false, null)); + var tuple = new Expression(new ExpressionInfo(cx, type, cx.CreateLocation(node.GetLocation()), ExprKind.TUPLE, parent, child, false, null)); cx.Try(null, null, () => { @@ -65,7 +65,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPattern, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child) { AnnotatedTypeSymbol? type = null; // Should ideally be a corresponding tuple type - var tuple = new Expression(new ExpressionInfo(cx, type, cx.Create(varPattern.GetLocation()), ExprKind.TUPLE, parent, child, false, null)); + var tuple = new Expression(new ExpressionInfo(cx, type, cx.CreateLocation(varPattern.GetLocation()), ExprKind.TUPLE, parent, child, false, null)); cx.Try(null, null, () => { @@ -123,7 +123,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions Create(cx, node, node.Designation, parent, child); public static VariableDeclaration Create(Context cx, CSharpSyntaxNode c, AnnotatedTypeSymbol? type, IExpressionParentEntity parent, int child) => - new VariableDeclaration(new ExpressionInfo(cx, type, cx.Create(c.FixedLocation()), ExprKind.LOCAL_VAR_DECL, parent, child, false, null)); + new VariableDeclaration(new ExpressionInfo(cx, type, cx.CreateLocation(c.FixedLocation()), ExprKind.LOCAL_VAR_DECL, parent, child, false, null)); public static VariableDeclaration Create(Context cx, CatchDeclarationSyntax d, bool isVar, IExpressionParentEntity parent, int child) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs index aadd9d2fbab..1c435ebd7d1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities private Field(Context cx, IFieldSymbol init) : base(cx, init) { - type = new Lazy(() => Entities.Type.Create(cx, symbol.Type)); + type = new Lazy(() => Entities.Type.Create(cx, Symbol.Type)); } public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntityFromSymbol(cx, field); @@ -22,78 +22,78 @@ namespace Semmle.Extraction.CSharp.Entities // Do not populate backing fields. // Populate Tuple fields. public override bool NeedsPopulation => - (base.NeedsPopulation && !symbol.IsImplicitlyDeclared) || symbol.ContainingType.IsTupleType; + (base.NeedsPopulation && !Symbol.IsImplicitlyDeclared) || Symbol.ContainingType.IsTupleType; public override void Populate(TextWriter trapFile) { PopulateMetadataHandle(trapFile); PopulateAttributes(); ContainingType.PopulateGenerics(); - PopulateNullability(trapFile, symbol.GetAnnotatedType()); + PopulateNullability(trapFile, Symbol.GetAnnotatedType()); - var unboundFieldKey = Field.Create(Context, symbol.OriginalDefinition); - trapFile.fields(this, (symbol.IsConst ? 2 : 1), symbol.Name, ContainingType, Type.TypeRef, unboundFieldKey); + var unboundFieldKey = Field.Create(Context, Symbol.OriginalDefinition); + trapFile.fields(this, (Symbol.IsConst ? 2 : 1), Symbol.Name, ContainingType, Type.TypeRef, unboundFieldKey); PopulateModifiers(trapFile); - if (symbol.IsVolatile) + if (Symbol.IsVolatile) Modifier.HasModifier(Context, trapFile, this, "volatile"); - if (symbol.IsConst) + if (Symbol.IsConst) { Modifier.HasModifier(Context, trapFile, this, "const"); - if (symbol.HasConstantValue) + if (Symbol.HasConstantValue) { - trapFile.constant_value(this, Expression.ValueAsString(symbol.ConstantValue)); + trapFile.constant_value(this, Expression.ValueAsString(Symbol.ConstantValue)); } } foreach (var l in Locations) trapFile.field_location(this, l); - if (!IsSourceDeclaration || !symbol.FromSource()) + if (!IsSourceDeclaration || !Symbol.FromSource()) return; - Context.BindComments(this, Location.symbol); + Context.BindComments(this, Location.Symbol); var child = 0; - foreach (var initializer in symbol.DeclaringSyntaxReferences + foreach (var initializer in Symbol.DeclaringSyntaxReferences .Select(n => n.GetSyntax()) .OfType() .Where(n => n.Initializer != null)) { Context.PopulateLater(() => { - var loc = Context.Create(initializer.GetLocation()); + var loc = Context.CreateLocation(initializer.GetLocation()); var fieldAccess = AddInitializerAssignment(trapFile, initializer.Initializer.Value, loc, null, ref child); - if (!symbol.IsStatic) + if (!Symbol.IsStatic) { - This.CreateImplicit(Context, symbol.ContainingType, Location, fieldAccess, -1); + This.CreateImplicit(Context, Symbol.ContainingType, Location, fieldAccess, -1); } }); } - foreach (var initializer in symbol.DeclaringSyntaxReferences + foreach (var initializer in Symbol.DeclaringSyntaxReferences .Select(n => n.GetSyntax()) .OfType() .Where(n => n.EqualsValue != null)) { // Mark fields that have explicit initializers. - var constValue = symbol.HasConstantValue - ? Expression.ValueAsString(symbol.ConstantValue) + var constValue = Symbol.HasConstantValue + ? Expression.ValueAsString(Symbol.ConstantValue) : null; - var loc = Context.Create(initializer.GetLocation()); + var loc = Context.CreateLocation(initializer.GetLocation()); AddInitializerAssignment(trapFile, initializer.EqualsValue.Value, loc, constValue, ref child); } if (IsSourceDeclaration) { - foreach (var syntax in symbol.DeclaringSyntaxReferences + foreach (var syntax in Symbol.DeclaringSyntaxReferences .Select(d => d.GetSyntax()) .OfType() .Select(d => d.Parent) @@ -107,7 +107,7 @@ namespace Semmle.Extraction.CSharp.Entities private Expression AddInitializerAssignment(TextWriter trapFile, ExpressionSyntax initializer, Extraction.Entities.Location loc, string constValue, ref int child) { - var type = symbol.GetAnnotatedType(); + var type = Symbol.GetAnnotatedType(); var simpleAssignExpr = new Expression(new ExpressionInfo(Context, type, loc, ExprKind.SIMPLE_ASSIGN, this, child++, false, constValue)); Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer, simpleAssignExpr, 0)); var access = new Expression(new ExpressionInfo(Context, type, Location, ExprKind.FIELD_ACCESS, simpleAssignExpr, 1, false, constValue)); @@ -124,7 +124,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.Write(" "); trapFile.WriteSubId(ContainingType); trapFile.Write('.'); - trapFile.Write(symbol.Name); + trapFile.Write(Symbol.Name); trapFile.Write(";field"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs new file mode 100644 index 00000000000..1a43a6fbd02 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs @@ -0,0 +1,53 @@ +using Microsoft.CodeAnalysis; +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// Holds all information required to create an Expression entity. + /// + internal interface IExpressionInfo + { + Context Context { get; } + + /// + /// The type of the expression. + /// + AnnotatedTypeSymbol? Type { get; } + + /// + /// The location of the expression. + /// + Extraction.Entities.Location Location { get; } + + /// + /// The kind of the expression. + /// + ExprKind Kind { get; } + + /// + /// The parent of the expression. + /// + IExpressionParentEntity Parent { get; } + + /// + /// The child index of the expression. + /// + int Child { get; } + + /// + /// Holds if this is an implicit expression. + /// + bool IsCompilerGenerated { get; } + + /// + /// Gets a string representation of the value. + /// null is encoded as the string "null". + /// If the expression does not have a value, then this + /// is null. + /// + string ExprValue { get; } + + NullableFlowState FlowState { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionParentEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionParentEntity.cs new file mode 100644 index 00000000000..a8e4df3d6ca --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionParentEntity.cs @@ -0,0 +1,10 @@ +namespace Semmle.Extraction.CSharp.Entities +{ + public interface IExpressionParentEntity : IEntity + { + /// + /// Whether this entity is the parent of a top-level expression. + /// + bool IsTopLevelParent { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/IStatementParentEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IStatementParentEntity.cs new file mode 100644 index 00000000000..40bc0f218c0 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IStatementParentEntity.cs @@ -0,0 +1,10 @@ +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// Whether this entity is the parent of a top-level statement. + /// + public interface IStatementParentEntity : IEntity + { + bool IsTopLevelParent { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs index 70b15a6fe16..04bc319c93e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs @@ -10,22 +10,22 @@ namespace Semmle.Extraction.CSharp.Entities protected Indexer(Context cx, IPropertySymbol init) : base(cx, init) { } - private Indexer OriginalDefinition => IsSourceDeclaration ? this : Create(Context, symbol.OriginalDefinition); + private Indexer OriginalDefinition => IsSourceDeclaration ? this : Create(Context, Symbol.OriginalDefinition); public override void Populate(TextWriter trapFile) { - PopulateNullability(trapFile, symbol.GetAnnotatedType()); + PopulateNullability(trapFile, Symbol.GetAnnotatedType()); - var type = Type.Create(Context, symbol.Type); - trapFile.indexers(this, symbol.GetName(useMetadataName: true), ContainingType, type.TypeRef, OriginalDefinition); + var type = Type.Create(Context, Symbol.Type); + trapFile.indexers(this, Symbol.GetName(useMetadataName: true), ContainingType, type.TypeRef, OriginalDefinition); foreach (var l in Locations) trapFile.indexer_location(this, l); - var getter = symbol.GetMethod; - var setter = symbol.SetMethod; + var getter = Symbol.GetMethod; + var setter = Symbol.SetMethod; if (getter is null && setter is null) - Context.ModelError(symbol, "No indexer accessor defined"); + Context.ModelError(Symbol, "No indexer accessor defined"); if (!(getter is null)) Method.Create(Context, getter); @@ -33,10 +33,10 @@ namespace Semmle.Extraction.CSharp.Entities if (!(setter is null)) Method.Create(Context, setter); - for (var i = 0; i < symbol.Parameters.Length; ++i) + for (var i = 0; i < Symbol.Parameters.Length; ++i) { - var original = Parameter.Create(Context, symbol.OriginalDefinition.Parameters[i], OriginalDefinition); - Parameter.Create(Context, symbol.Parameters[i], this, original); + var original = Parameter.Create(Context, Symbol.OriginalDefinition.Parameters[i], OriginalDefinition); + Parameter.Create(Context, Symbol.Parameters[i], this, original); } if (IsSourceDeclaration) @@ -46,7 +46,7 @@ namespace Semmle.Extraction.CSharp.Entities { // The expression may need to reference parameters in the getter. // So we need to arrange that the expression is populated after the getter. - Context.PopulateLater(() => Expression.CreateFromNode(new ExpressionNodeInfo(Context, expressionBody, this, 0).SetType(symbol.GetAnnotatedType()))); + Context.PopulateLater(() => Expression.CreateFromNode(new ExpressionNodeInfo(Context, expressionBody, this, 0).SetType(Symbol.GetAnnotatedType()))); } } @@ -54,11 +54,11 @@ namespace Semmle.Extraction.CSharp.Entities BindComments(); var declSyntaxReferences = IsSourceDeclaration - ? symbol.DeclaringSyntaxReferences. + ? Symbol.DeclaringSyntaxReferences. Select(d => d.GetSyntax()).OfType().ToArray() : Enumerable.Empty(); - foreach (var explicitInterface in symbol.ExplicitInterfaceImplementations.Select(impl => Type.Create(Context, impl.ContainingType))) + foreach (var explicitInterface in Symbol.ExplicitInterfaceImplementations.Select(impl => Type.Create(Context, impl.ContainingType))) { trapFile.explicitly_implements(this, explicitInterface.TypeRef); @@ -77,9 +77,9 @@ namespace Semmle.Extraction.CSharp.Entities { trapFile.WriteSubId(ContainingType); trapFile.Write('.'); - trapFile.Write(symbol.MetadataName); + trapFile.Write(Symbol.MetadataName); trapFile.Write('('); - trapFile.BuildList(",", symbol.Parameters, (p, tb0) => tb0.WriteSubId(Type.Create(Context, p.Type))); + trapFile.BuildList(",", Symbol.Parameters, (p, tb0) => tb0.WriteSubId(Type.Create(Context, p.Type))); trapFile.Write(");indexer"); } @@ -87,11 +87,11 @@ namespace Semmle.Extraction.CSharp.Entities { get { - return symbol.DeclaringSyntaxReferences + return Symbol.DeclaringSyntaxReferences .Select(r => r.GetSyntax()) .OfType() .Select(s => s.GetLocation()) - .Concat(symbol.Locations) + .Concat(Symbol.Locations) .First(); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs index 921036250d1..efc50f7f85f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs @@ -1,8 +1,6 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.IO; -using System.Linq; namespace Semmle.Extraction.CSharp.Entities { @@ -36,10 +34,10 @@ namespace Semmle.Extraction.CSharp.Entities PopulateMethod(trapFile); PopulateModifiers(trapFile); - var originalDefinition = IsSourceDeclaration ? this : Create(Context, symbol.OriginalDefinition); - var returnType = Type.Create(Context, symbol.ReturnType); - trapFile.local_functions(this, symbol.Name, returnType, originalDefinition); - ExtractRefReturn(trapFile, symbol, this); + var originalDefinition = IsSourceDeclaration ? this : Create(Context, Symbol.OriginalDefinition); + var returnType = Type.Create(Context, Symbol.ReturnType); + trapFile.local_functions(this, Symbol.Name, returnType, originalDefinition); + ExtractRefReturn(trapFile, Symbol, this); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NeedsLabel; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs index e988ec2c815..4f9a0c4f7f6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs @@ -23,12 +23,12 @@ namespace Semmle.Extraction.CSharp.Entities public void PopulateManual(Expression parent, bool isVar) { var trapFile = Context.TrapWriter.Writer; - var (kind, type) = symbol is ILocalSymbol l + var (kind, type) = Symbol is ILocalSymbol l ? (l.IsRef ? 3 : l.IsConst ? 2 : 1, l.GetAnnotatedType()) : (1, parent.Type); - trapFile.localvars(this, kind, symbol.Name, isVar ? 1 : 0, Type.Create(Context, type).TypeRef, parent); + trapFile.localvars(this, kind, Symbol.Name, isVar ? 1 : 0, Type.Create(Context, type).TypeRef, parent); - if (symbol is ILocalSymbol local) + if (Symbol is ILocalSymbol local) { PopulateNullability(trapFile, local.GetAnnotatedType()); if (local.IsRef) @@ -47,7 +47,7 @@ namespace Semmle.Extraction.CSharp.Entities private void DefineConstantValue(TextWriter trapFile) { - if (symbol is ILocalSymbol local && local.HasConstantValue) + if (Symbol is ILocalSymbol local && local.HasConstantValue) { trapFile.constant_value(this, Expression.ValueAsString(local.ConstantValue)); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 6a52087e384..8a1572796bc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Populators; using System.Collections.Generic; @@ -15,8 +16,8 @@ namespace Semmle.Extraction.CSharp.Entities protected void PopulateParameters() { var originalMethod = OriginalDefinition; - IEnumerable parameters = symbol.Parameters; - IEnumerable originalParameters = originalMethod.symbol.Parameters; + IEnumerable parameters = Symbol.Parameters; + IEnumerable originalParameters = originalMethod.Symbol.Parameters; if (IsReducedExtension) { @@ -24,14 +25,14 @@ namespace Semmle.Extraction.CSharp.Entities { // Non-generic reduced extensions must be extracted exactly like the // non-reduced counterparts - parameters = symbol.ReducedFrom.Parameters; + parameters = Symbol.ReducedFrom.Parameters; } else { // Constructed reduced extensions are special because their non-reduced // counterparts are not constructed. Therefore, we need to manually add // the `this` parameter based on the type of the receiver - var originalThisParamSymbol = originalMethod.symbol.Parameters.First(); + var originalThisParamSymbol = originalMethod.Symbol.Parameters.First(); var originalThisParam = Parameter.Create(Context, originalThisParamSymbol, originalMethod); ConstructedExtensionParameter.Create(Context, this, originalThisParam); originalParameters = originalParameters.Skip(1); @@ -46,7 +47,7 @@ namespace Semmle.Extraction.CSharp.Entities Parameter.Create(Context, p.paramSymbol, this, original); } - if (symbol.IsVararg) + if (Symbol.IsVararg) { // Mono decided that "__arglist" should be an explicit parameter, // so now we need to populate it. @@ -83,14 +84,24 @@ namespace Semmle.Extraction.CSharp.Entities else Expression.Create(Context, expr, this, 0); - Context.NumberOfLines(trapFile, BodyDeclaringSymbol, this); + NumberOfLines(trapFile, BodyDeclaringSymbol, this); }); } } + public static void NumberOfLines(TextWriter trapFile, ISymbol symbol, IEntity callable) + { + foreach (var decl in symbol.DeclaringSyntaxReferences) + { + var node = (CSharpSyntaxNode)decl.GetSyntax(); + var lineCounts = node.Accept(new AstLineCounter()); + trapFile.numlines(callable, lineCounts); + } + } + public void Overrides(TextWriter trapFile) { - foreach (var explicitInterface in symbol.ExplicitInterfaceImplementations + foreach (var explicitInterface in Symbol.ExplicitInterfaceImplementations .Where(sym => sym.MethodKind == MethodKind.Ordinary) .Select(impl => Type.Create(Context, impl.ContainingType))) { @@ -98,14 +109,14 @@ namespace Semmle.Extraction.CSharp.Entities if (IsSourceDeclaration) { - foreach (var syntax in symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).OfType()) + foreach (var syntax in Symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).OfType()) TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier.Name, this, explicitInterface); } } - if (symbol.OverriddenMethod != null) + if (Symbol.OverriddenMethod != null) { - trapFile.overrides(this, Method.Create(Context, symbol.OverriddenMethod)); + trapFile.overrides(this, Method.Create(Context, Symbol.OverriddenMethod)); } } @@ -114,22 +125,22 @@ namespace Semmle.Extraction.CSharp.Entities /// private static void BuildMethodId(Method m, TextWriter trapFile) { - m.symbol.ReturnType.BuildOrWriteId(m.Context, trapFile, m.symbol); + m.Symbol.ReturnType.BuildOrWriteId(m.Context, trapFile, m.Symbol); trapFile.Write(" "); trapFile.WriteSubId(m.ContainingType); - AddExplicitInterfaceQualifierToId(m.Context, trapFile, m.symbol.ExplicitInterfaceImplementations); + AddExplicitInterfaceQualifierToId(m.Context, trapFile, m.Symbol.ExplicitInterfaceImplementations); trapFile.Write("."); - trapFile.Write(m.symbol.Name); + trapFile.Write(m.Symbol.Name); - if (m.symbol.IsGenericMethod) + if (m.Symbol.IsGenericMethod) { - if (SymbolEqualityComparer.Default.Equals(m.symbol, m.symbol.OriginalDefinition)) + if (SymbolEqualityComparer.Default.Equals(m.Symbol, m.Symbol.OriginalDefinition)) { trapFile.Write('`'); - trapFile.Write(m.symbol.TypeParameters.Length); + trapFile.Write(m.Symbol.TypeParameters.Length); } else { @@ -138,13 +149,13 @@ namespace Semmle.Extraction.CSharp.Entities // Type arguments with different nullability can result in // a constructed method with different nullability of its parameters and return type, // so we need to create a distinct database entity for it. - trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { ta.Symbol.BuildOrWriteId(m.Context, tb0, m.symbol); trapFile.Write((int)ta.Nullability); }); + trapFile.BuildList(",", m.Symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { ta.Symbol.BuildOrWriteId(m.Context, tb0, m.Symbol); trapFile.Write((int)ta.Nullability); }); trapFile.Write('>'); } } - AddParametersToId(m.Context, trapFile, m.symbol); - switch (m.symbol.MethodKind) + AddParametersToId(m.Context, trapFile, m.Symbol); + switch (m.Symbol.MethodKind) { case MethodKind.PropertyGet: trapFile.Write(";getter"); @@ -213,7 +224,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.AppendList(",", explicitInterfaceImplementations.Select(impl => cx.CreateEntity(impl.ContainingType))); } - public virtual string Name => symbol.Name; + public virtual string Name => Symbol.Name; /// /// Creates a method of the appropriate subtype. @@ -267,28 +278,28 @@ namespace Semmle.Extraction.CSharp.Entities public Method OriginalDefinition => IsReducedExtension - ? Create(Context, symbol.ReducedFrom) - : Create(Context, symbol.OriginalDefinition); + ? Create(Context, Symbol.ReducedFrom) + : Create(Context, Symbol.OriginalDefinition); public override Microsoft.CodeAnalysis.Location FullLocation => ReportingLocation; - public override bool IsSourceDeclaration => symbol.IsSourceDeclaration(); + public override bool IsSourceDeclaration => Symbol.IsSourceDeclaration(); /// /// Whether this method has type parameters. /// - public bool IsGeneric => symbol.IsGenericMethod; + public bool IsGeneric => Symbol.IsGenericMethod; /// /// Whether this method has unbound type parameters. /// - public bool IsUnboundGeneric => IsGeneric && SymbolEqualityComparer.Default.Equals(symbol.ConstructedFrom, symbol); + public bool IsUnboundGeneric => IsGeneric && SymbolEqualityComparer.Default.Equals(Symbol.ConstructedFrom, Symbol); public bool IsBoundGeneric => IsGeneric && !IsUnboundGeneric; - private bool IsReducedExtension => symbol.MethodKind == MethodKind.ReducedExtension; + private bool IsReducedExtension => Symbol.MethodKind == MethodKind.ReducedExtension; - protected IMethodSymbol ConstructedFromSymbol => symbol.ConstructedFrom.ReducedFrom ?? symbol.ConstructedFrom; + protected IMethodSymbol ConstructedFromSymbol => Symbol.ConstructedFrom.ReducedFrom ?? Symbol.ConstructedFrom; bool IExpressionParentEntity.IsTopLevelParent => true; @@ -305,19 +316,19 @@ namespace Semmle.Extraction.CSharp.Entities if (isFullyConstructed) { trapFile.constructed_generic(this, Method.Create(Context, ConstructedFromSymbol)); - foreach (var tp in symbol.GetAnnotatedTypeArguments()) + foreach (var tp in Symbol.GetAnnotatedTypeArguments()) { trapFile.type_arguments(Type.Create(Context, tp.Symbol), child, this); child++; } - var nullability = new Nullability(symbol); + var nullability = new Nullability(Symbol); if (!nullability.IsOblivious) trapFile.type_nullability(this, NullabilityEntity.Create(Context, nullability)); } else { - foreach (var typeParam in symbol.TypeParameters.Select(tp => TypeParameter.Create(Context, tp))) + foreach (var typeParam in Symbol.TypeParameters.Select(tp => TypeParameter.Create(Context, tp))) { trapFile.type_parameters(typeParam, child, this); child++; @@ -343,7 +354,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulateMethodBody(trapFile); PopulateGenerics(trapFile); PopulateMetadataHandle(trapFile); - PopulateNullability(trapFile, symbol.GetAnnotatedReturnType()); + PopulateNullability(trapFile, Symbol.GetAnnotatedReturnType()); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.PushesLabel; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs index 4b2725b89f3..b644558f799 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - trapFile.Write(symbol); + trapFile.Write(Symbol); trapFile.Write(";modifier"); } @@ -20,7 +20,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate(TextWriter trapFile) { - trapFile.modifiers(Label, symbol); + trapFile.modifiers(Label, Symbol); } public static string AccessbilityModifier(Accessibility access) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs index 6ae31c82b64..31e66656eb3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Namespace.cs @@ -12,11 +12,11 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate(TextWriter trapFile) { - trapFile.namespaces(this, symbol.Name); + trapFile.namespaces(this, Symbol.Name); - if (symbol.ContainingNamespace != null) + if (Symbol.ContainingNamespace != null) { - var parent = Create(Context, symbol.ContainingNamespace); + var parent = Create(Context, Symbol.ContainingNamespace); trapFile.parent_namespace(this, parent); } } @@ -25,11 +25,11 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - if (!symbol.IsGlobalNamespace) + if (!Symbol.IsGlobalNamespace) { - trapFile.WriteSubId(Create(Context, symbol.ContainingNamespace)); + trapFile.WriteSubId(Create(Context, Symbol.ContainingNamespace)); trapFile.Write('.'); - trapFile.Write(symbol.Name); + trapFile.Write(Symbol.Name); } trapFile.Write(";namespace"); } @@ -47,7 +47,7 @@ namespace Semmle.Extraction.CSharp.Entities public override int GetHashCode() => QualifiedName.GetHashCode(); - private string QualifiedName => symbol.ToDisplayString(); + private string QualifiedName => Symbol.ToDisplayString(); public override bool Equals(object obj) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs index 17f9a198a39..3a19417008a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs @@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(Context.Create(ReportingLocation)); + trapFile.WriteSubId(Context.CreateLocation(ReportingLocation)); trapFile.Write(";namespacedeclaration"); } @@ -31,7 +31,7 @@ namespace Semmle.Extraction.CSharp.Entities var @namespace = (INamespaceSymbol)Context.GetModel(node).GetSymbolInfo(node.Name).Symbol; var ns = Namespace.Create(Context, @namespace); trapFile.namespace_declarations(this, ns); - trapFile.namespace_declaration_location(this, Context.Create(node.Name.GetLocation())); + trapFile.namespace_declaration_location(this, Context.CreateLocation(node.Name.GetLocation())); var visitor = new Populators.TypeOrNamespaceVisitor(Context, trapFile, this); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs index d81fc25f72b..90f17d70ea4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs @@ -11,20 +11,20 @@ namespace Semmle.Extraction.CSharp.Entities private OrdinaryMethod(Context cx, IMethodSymbol init) : base(cx, init) { } - public override string Name => symbol.GetName(); + public override string Name => Symbol.GetName(); - protected override IMethodSymbol BodyDeclaringSymbol => symbol.PartialImplementationPart ?? symbol; + protected override IMethodSymbol BodyDeclaringSymbol => Symbol.PartialImplementationPart ?? Symbol; public IMethodSymbol SourceDeclaration { get { - var reducedFrom = symbol.ReducedFrom ?? symbol; + var reducedFrom = Symbol.ReducedFrom ?? Symbol; return reducedFrom.OriginalDefinition; } } - public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol.GetSymbolLocation(); + public override Microsoft.CodeAnalysis.Location ReportingLocation => Symbol.GetSymbolLocation(); public override void Populate(TextWriter trapFile) { @@ -32,12 +32,12 @@ namespace Semmle.Extraction.CSharp.Entities PopulateModifiers(trapFile); ContainingType.PopulateGenerics(); - var returnType = Type.Create(Context, symbol.ReturnType); + var returnType = Type.Create(Context, Symbol.ReturnType); trapFile.methods(this, Name, ContainingType, returnType.TypeRef, OriginalDefinition); if (IsSourceDeclaration) { - foreach (var declaration in symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax()).OfType()) + foreach (var declaration in Symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax()).OfType()) { Context.BindComments(this, declaration.Identifier.GetLocation()); TypeMention.Create(Context, declaration.ReturnType, this, returnType); @@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulateGenerics(trapFile); Overrides(trapFile); - ExtractRefReturn(trapFile, symbol, this); + ExtractRefReturn(trapFile, Symbol, this); ExtractCompilerGenerated(trapFile); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index c42a3edd236..b1b7a5444fe 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -19,7 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities Original = original ?? this; } - public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol.GetSymbolLocation(); + public override Microsoft.CodeAnalysis.Location ReportingLocation => Symbol.GetSymbolLocation(); public enum Kind { @@ -35,9 +35,9 @@ namespace Semmle.Extraction.CSharp.Entities // actually numbered from 1. // This is to be consistent from the original (unreduced) extension method. var isReducedExtension = - symbol.ContainingSymbol is IMethodSymbol method && + Symbol.ContainingSymbol is IMethodSymbol method && method.MethodKind == MethodKind.ReducedExtension; - return symbol.Ordinal + (isReducedExtension ? 1 : 0); + return Symbol.Ordinal + (isReducedExtension ? 1 : 0); } } @@ -45,7 +45,7 @@ namespace Semmle.Extraction.CSharp.Entities { get { - switch (symbol.RefKind) + switch (Symbol.RefKind) { case RefKind.Out: return Kind.Out; @@ -54,12 +54,12 @@ namespace Semmle.Extraction.CSharp.Entities case RefKind.In: return Kind.In; default: - if (symbol.IsParams) + if (Symbol.IsParams) return Kind.Params; if (Ordinal == 0) { - if (symbol.ContainingSymbol is IMethodSymbol method && method.IsExtensionMethod) + if (Symbol.ContainingSymbol is IMethodSymbol method && method.IsExtensionMethod) return Kind.This; } return Kind.None; @@ -76,7 +76,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { if (Parent == null) - Parent = Method.Create(Context, symbol.ContainingSymbol as IMethodSymbol); + Parent = Method.Create(Context, Symbol.ContainingSymbol as IMethodSymbol); trapFile.WriteSubId(Parent); trapFile.Write('_'); trapFile.Write(Ordinal); @@ -92,34 +92,42 @@ namespace Semmle.Extraction.CSharp.Entities // Very rarely, two parameters have the same name according to the data model. // This breaks our database constraints. // Generate an impossible name to ensure that it doesn't conflict. - var conflictingCount = symbol.ContainingSymbol.GetParameters().Count(p => p.Ordinal < symbol.Ordinal && p.Name == symbol.Name); - return conflictingCount > 0 ? symbol.Name + "`" + conflictingCount : symbol.Name; + var conflictingCount = Symbol.ContainingSymbol.GetParameters().Count(p => p.Ordinal < Symbol.Ordinal && p.Name == Symbol.Name); + return conflictingCount > 0 ? Symbol.Name + "`" + conflictingCount : Symbol.Name; } } public override void Populate(TextWriter trapFile) { PopulateAttributes(); - PopulateNullability(trapFile, symbol.GetAnnotatedType()); - PopulateRefKind(trapFile, symbol.RefKind); + PopulateNullability(trapFile, Symbol.GetAnnotatedType()); + PopulateRefKind(trapFile, Symbol.RefKind); - if (symbol.Name != Original.symbol.Name) - Context.ModelError(symbol, "Inconsistent parameter declaration"); + if (Symbol.Name != Original.Symbol.Name) + Context.ModelError(Symbol, "Inconsistent parameter declaration"); - var type = Type.Create(Context, symbol.Type); + var type = Type.Create(Context, Symbol.Type); trapFile.@params(this, Name, type.TypeRef, Ordinal, ParamKind, Parent, Original); - foreach (var l in symbol.Locations) - trapFile.param_location(this, Context.Create(l)); + foreach (var l in Symbol.Locations) + trapFile.param_location(this, Context.CreateLocation(l)); - if (!IsSourceDeclaration || !symbol.FromSource()) + if (!Symbol.Locations.Any() && + Symbol.ContainingSymbol is IMethodSymbol ms && + ms.Name == WellKnownMemberNames.TopLevelStatementsEntryPointMethodName && + ms.ContainingType.Name == WellKnownMemberNames.TopLevelStatementsEntryPointTypeName) + { + trapFile.param_location(this, Context.CreateLocation()); + } + + if (!IsSourceDeclaration || !Symbol.FromSource()) return; BindComments(); if (IsSourceDeclaration) { - foreach (var syntax in symbol.DeclaringSyntaxReferences + foreach (var syntax in Symbol.DeclaringSyntaxReferences .Select(d => d.GetSyntax()) .OfType() .Where(s => s.Type != null)) @@ -128,21 +136,21 @@ namespace Semmle.Extraction.CSharp.Entities } } - if (symbol.HasExplicitDefaultValue && Context.Defines(symbol)) + if (Symbol.HasExplicitDefaultValue && Context.Defines(Symbol)) { // This is a slight bug in the dbscheme // We should really define param_default(param, string) // And use parameter child #0 to encode the default expression. - var defaultValue = GetParameterDefaultValue(symbol); + var defaultValue = GetParameterDefaultValue(Symbol); if (defaultValue == null) { // In case this parameter belongs to an accessor of an indexer, we need // to get the default value from the corresponding parameter belonging // to the indexer itself - var method = (IMethodSymbol)symbol.ContainingSymbol; + var method = (IMethodSymbol)Symbol.ContainingSymbol; if (method != null) { - var i = method.Parameters.IndexOf(symbol); + var i = method.Parameters.IndexOf(Symbol); var indexer = (IPropertySymbol)method.AssociatedSymbol; if (indexer != null) defaultValue = GetParameterDefaultValue(indexer.Parameters[i]); @@ -159,7 +167,7 @@ namespace Semmle.Extraction.CSharp.Entities } } - public override bool IsSourceDeclaration => symbol.IsSourceDeclaration(); + public override bool IsSourceDeclaration => Symbol.IsSourceDeclaration(); bool IExpressionParentEntity.IsTopLevelParent => true; @@ -231,7 +239,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.param_location(this, GeneratedLocation.Create(Context)); } - protected override int Ordinal => ((Method)Parent).OriginalDefinition.symbol.Parameters.Length; + protected override int Ordinal => ((Method)Parent).OriginalDefinition.Symbol.Parameters.Length; public override int GetHashCode() { @@ -258,20 +266,20 @@ namespace Semmle.Extraction.CSharp.Entities private readonly ITypeSymbol constructedType; private ConstructedExtensionParameter(Context cx, Method method, Parameter original) - : base(cx, original.symbol, method, original) + : base(cx, original.Symbol, method, original) { - constructedType = method.symbol.ReceiverType; + constructedType = method.Symbol.ReceiverType; } public override void Populate(TextWriter trapFile) { var typeKey = Type.Create(Context, constructedType); - trapFile.@params(this, Original.symbol.Name, typeKey.TypeRef, 0, Kind.This, Parent, Original); + trapFile.@params(this, Original.Symbol.Name, typeKey.TypeRef, 0, Kind.This, Parent, Original); trapFile.param_location(this, Original.Location); } public static ConstructedExtensionParameter Create(Context cx, Method method, Parameter parameter) => - ExtensionParamFactory.Instance.CreateEntity(cx, (new SymbolEqualityWrapper(parameter.symbol), new SymbolEqualityWrapper(method.symbol.ReceiverType)), (method, parameter)); + ExtensionParamFactory.Instance.CreateEntity(cx, (new SymbolEqualityWrapper(parameter.Symbol), new SymbolEqualityWrapper(method.Symbol.ReceiverType)), (method, parameter)); private class ExtensionParamFactory : ICachedEntityFactory<(Method, Parameter), ConstructedExtensionParameter> { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs new file mode 100644 index 00000000000..2ca967a4864 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class DefineDirective : PreprocessorDirective + { + public DefineDirective(Context cx, DefineDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_defines(this, trivia.Name.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs new file mode 100644 index 00000000000..ece87fd1f42 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs @@ -0,0 +1,28 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class ElifDirective : PreprocessorDirective, IIfSiblingDirective, IExpressionParentEntity + { + private readonly IfDirective start; + private readonly int index; + + public ElifDirective(Context cx, ElifDirectiveTriviaSyntax trivia, IfDirective start, int index) + : base(cx, trivia, populateFromBase: false) + { + this.start = start; + this.index = index; + TryPopulate(); + } + + public bool IsTopLevelParent => true; + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_elifs(this, trivia.BranchTaken, trivia.ConditionValue, start, index); + + Expression.Create(Context, trivia.Condition, this, 0); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs new file mode 100644 index 00000000000..7ab7d45b6e9 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs @@ -0,0 +1,24 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class ElseDirective : PreprocessorDirective, IIfSiblingDirective + { + private readonly IfDirective start; + private readonly int index; + + public ElseDirective(Context cx, ElseDirectiveTriviaSyntax trivia, IfDirective start, int index) + : base(cx, trivia, populateFromBase: false) + { + this.start = start; + this.index = index; + TryPopulate(); + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_elses(this, trivia.BranchTaken, start, index); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs new file mode 100644 index 00000000000..9c349844dc6 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs @@ -0,0 +1,22 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class EndIfDirective : PreprocessorDirective + { + private readonly IfDirective start; + + public EndIfDirective(Context cx, EndIfDirectiveTriviaSyntax trivia, IfDirective start) + : base(cx, trivia, populateFromBase: false) + { + this.start = start; + TryPopulate(); + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_endifs(this, start); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs new file mode 100644 index 00000000000..d4d75470a97 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs @@ -0,0 +1,22 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class EndRegionDirective : PreprocessorDirective + { + private readonly RegionDirective region; + + public EndRegionDirective(Context cx, EndRegionDirectiveTriviaSyntax trivia, RegionDirective region) + : base(cx, trivia, populateFromBase: false) + { + this.region = region; + TryPopulate(); + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_endregions(this, region); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs new file mode 100644 index 00000000000..2917d077839 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class ErrorDirective : PreprocessorDirective + { + public ErrorDirective(Context cx, ErrorDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_errors(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IIfSiblingDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IIfSiblingDirective.cs new file mode 100644 index 00000000000..7a849962f09 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IIfSiblingDirective.cs @@ -0,0 +1,4 @@ +namespace Semmle.Extraction.CSharp.Entities +{ + internal interface IIfSiblingDirective { } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs new file mode 100644 index 00000000000..29c6f741620 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs @@ -0,0 +1,22 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class IfDirective : PreprocessorDirective, IExpressionParentEntity + { + public IfDirective(Context cx, IfDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + public bool IsTopLevelParent => true; + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_ifs(this, trivia.BranchTaken, trivia.ConditionValue); + + Expression.Create(Context, trivia.Condition, this, 0); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs new file mode 100644 index 00000000000..470f54f379a --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs @@ -0,0 +1,40 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class LineDirective : PreprocessorDirective + { + public LineDirective(Context cx, LineDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + var type = trivia.Line.Kind() switch + { + SyntaxKind.DefaultKeyword => 0, + SyntaxKind.HiddenKeyword => 1, + SyntaxKind.NumericLiteralToken => 2, + _ => throw new InternalError(trivia, "Unhandled line token kind") + }; + + trapFile.directive_lines(this, type); + + if (trivia.Line.IsKind(SyntaxKind.NumericLiteralToken)) + { + var value = (int)trivia.Line.Value; + trapFile.directive_line_value(this, value); + + if (!string.IsNullOrWhiteSpace(trivia.File.ValueText)) + { + var file = Extraction.Entities.File.Create(Context, trivia.File.ValueText); + trapFile.directive_line_file(this, file); + } + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs new file mode 100644 index 00000000000..e6bb4e79fed --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs @@ -0,0 +1,35 @@ +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class NullableDirective : PreprocessorDirective + { + public NullableDirective(Context cx, NullableDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + var setting = trivia.SettingToken.Kind() switch + { + SyntaxKind.DisableKeyword => 0, + SyntaxKind.EnableKeyword => 1, + SyntaxKind.RestoreKeyword => 2, + _ => throw new InternalError(trivia, "Unhandled setting token kind") + }; + + var target = trivia.TargetToken.Kind() switch + { + SyntaxKind.None => 0, + SyntaxKind.AnnotationsKeyword => 1, + SyntaxKind.WarningsKeyword => 2, + _ => throw new InternalError(trivia, "Unhandled target token kind") + }; + + trapFile.directive_nullables(this, setting, target); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs new file mode 100644 index 00000000000..572b77e2c73 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs @@ -0,0 +1,19 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class PragmaChecksumDirective : PreprocessorDirective + { + public PragmaChecksumDirective(Context cx, PragmaChecksumDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + var file = Extraction.Entities.File.Create(Context, trivia.File.ValueText); + trapFile.pragma_checksums(this, file, trivia.Guid.ToString(), trivia.Bytes.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs new file mode 100644 index 00000000000..4502fa4a87a --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs @@ -0,0 +1,26 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class PragmaWarningDirective : PreprocessorDirective + { + public 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); + + var childIndex = 0; + foreach (var code in trivia.ErrorCodes) + { + trapFile.pragma_warning_error_codes(this, code.ToString(), childIndex++); + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs new file mode 100644 index 00000000000..13e702603ab --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs @@ -0,0 +1,41 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.Entities; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal abstract class PreprocessorDirective : FreshEntity where TDirective : DirectiveTriviaSyntax + { + protected readonly TDirective 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) + { + PopulatePreprocessor(trapFile); + + trapFile.preprocessor_directive_active(this, trivia.IsActive); + trapFile.preprocessor_directive_location(this, Context.CreateLocation(ReportingLocation)); + + if (!Context.Extractor.Standalone) + { + var compilation = Compilation.Create(Context); + trapFile.preprocessor_directive_compilation(this, compilation); + } + } + + protected abstract void PopulatePreprocessor(TextWriter trapFile); + + public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => trivia.GetLocation(); + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs new file mode 100644 index 00000000000..b2f017688a3 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs @@ -0,0 +1,19 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class RegionDirective : PreprocessorDirective + { + public RegionDirective(Context cx, RegionDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_regions(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs new file mode 100644 index 00000000000..d4b976d50c0 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class UndefineDirective : PreprocessorDirective + { + public UndefineDirective(Context cx, UndefDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_undefines(this, trivia.Name.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs new file mode 100644 index 00000000000..1511be8d28c --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class WarningDirective : PreprocessorDirective + { + public WarningDirective(Context cx, WarningDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_warnings(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index 08d5ae47c5e..085047d0812 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities protected Property(Context cx, IPropertySymbol init) : base(cx, init) { - type = new Lazy(() => Type.Create(Context, symbol.Type)); + type = new Lazy(() => Type.Create(base.Context, Symbol.Type)); } private readonly Lazy type; @@ -27,8 +27,8 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.Write(" "); trapFile.WriteSubId(ContainingType); trapFile.Write('.'); - Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations); - trapFile.Write(symbol.Name); + Method.AddExplicitInterfaceQualifierToId(Context, trapFile, Symbol.ExplicitInterfaceImplementations); + trapFile.Write(Symbol.Name); trapFile.Write(";property"); } @@ -38,14 +38,14 @@ namespace Semmle.Extraction.CSharp.Entities PopulateAttributes(); PopulateModifiers(trapFile); BindComments(); - PopulateNullability(trapFile, symbol.GetAnnotatedType()); - PopulateRefKind(trapFile, symbol.RefKind); + PopulateNullability(trapFile, Symbol.GetAnnotatedType()); + PopulateRefKind(trapFile, Symbol.RefKind); var type = Type; - trapFile.properties(this, symbol.GetName(), ContainingType, type.TypeRef, Create(Context, symbol.OriginalDefinition)); + trapFile.properties(this, Symbol.GetName(), ContainingType, type.TypeRef, Create(Context, Symbol.OriginalDefinition)); - var getter = symbol.GetMethod; - var setter = symbol.SetMethod; + var getter = Symbol.GetMethod; + var setter = Symbol.SetMethod; if (!(getter is null)) Method.Create(Context, getter); @@ -54,11 +54,11 @@ namespace Semmle.Extraction.CSharp.Entities Method.Create(Context, setter); var declSyntaxReferences = IsSourceDeclaration ? - symbol.DeclaringSyntaxReferences. + Symbol.DeclaringSyntaxReferences. Select(d => d.GetSyntax()).OfType().ToArray() : Enumerable.Empty(); - foreach (var explicitInterface in symbol.ExplicitInterfaceImplementations.Select(impl => Type.Create(Context, impl.ContainingType))) + foreach (var explicitInterface in Symbol.ExplicitInterfaceImplementations.Select(impl => Type.Create(Context, impl.ContainingType))) { trapFile.explicitly_implements(this, explicitInterface.TypeRef); @@ -69,7 +69,7 @@ namespace Semmle.Extraction.CSharp.Entities foreach (var l in Locations) trapFile.property_location(this, l); - if (IsSourceDeclaration && symbol.FromSource()) + if (IsSourceDeclaration && Symbol.FromSource()) { var expressionBody = ExpressionBody; if (expressionBody != null) @@ -84,15 +84,15 @@ namespace Semmle.Extraction.CSharp.Entities { Context.PopulateLater(() => { - var loc = Context.Create(initializer.GetLocation()); - var annotatedType = AnnotatedTypeSymbol.CreateNotAnnotated(symbol.Type); + var loc = Context.CreateLocation(initializer.GetLocation()); + var annotatedType = AnnotatedTypeSymbol.CreateNotAnnotated(Symbol.Type); var simpleAssignExpr = new Expression(new ExpressionInfo(Context, annotatedType, loc, ExprKind.SIMPLE_ASSIGN, this, child++, false, null)); Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer.Value, simpleAssignExpr, 0)); var access = new Expression(new ExpressionInfo(Context, annotatedType, Location, ExprKind.PROPERTY_ACCESS, simpleAssignExpr, 1, false, null)); trapFile.expr_access(access, this); - if (!symbol.IsStatic) + if (!Symbol.IsStatic) { - This.CreateImplicit(Context, symbol.ContainingType, Location, access, -1); + This.CreateImplicit(Context, Symbol.ContainingType, Location, access, -1); } }); } @@ -106,11 +106,11 @@ namespace Semmle.Extraction.CSharp.Entities { get { - return symbol.DeclaringSyntaxReferences + return Symbol.DeclaringSyntaxReferences .Select(r => r.GetSyntax()) .OfType() .Select(s => s.GetLocation()) - .Concat(symbol.Locations) + .Concat(Symbol.Locations) .First(); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs index 44bd7f80583..94ab9a7ce61 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs @@ -1,24 +1,41 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using Microsoft.CodeAnalysis.CSharp; -using Semmle.Extraction.Entities; using System.IO; namespace Semmle.Extraction.CSharp.Entities { - /// - /// Whether this entity is the parent of a top-level statement. - /// - public interface IStatementParentEntity : IEntity - { - bool IsTopLevelParent { get; } - } - internal abstract class Statement : FreshEntity, IExpressionParentEntity, IStatementParentEntity { - protected Statement(Context cx) : base(cx) { } + private readonly int child; + private readonly Kinds.StmtKind kind; + private readonly IStatementParentEntity parent; - public static Statement Create(Context cx, StatementSyntax node, Statement parent, int child) => + protected Statement(Context cx, Kinds.StmtKind kind, IStatementParentEntity parent, int child) + : base(cx) + { + this.kind = kind; + this.parent = parent; + this.child = child; + } + + protected override void Populate(TextWriter trapFile) + { + trapFile.statements(this, kind); + if (parent.IsTopLevelParent) + { + trapFile.stmt_parent_top_level(this, child, parent); + } + else + { + trapFile.stmt_parent(this, child, parent); + } + + PopulateStatement(trapFile); + } + + protected abstract void PopulateStatement(TextWriter trapFile); + + public static Statement Create(Context cx, StatementSyntax node, IStatementParentEntity parent, int child) => Statements.Factory.Create(cx, node, parent, child); /// @@ -27,54 +44,10 @@ namespace Semmle.Extraction.CSharp.Entities /// public virtual int NumberOfStatements => 1; - public override Microsoft.CodeAnalysis.Location ReportingLocation => GetStatementSyntax().GetLocation(); - bool IExpressionParentEntity.IsTopLevelParent => false; bool IStatementParentEntity.IsTopLevelParent => false; - protected abstract CSharpSyntaxNode GetStatementSyntax(); - public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NeedsLabel; } - - internal abstract class Statement : Statement where TSyntax : CSharpSyntaxNode - { - protected readonly TSyntax Stmt; - private readonly int child; - private readonly Kinds.StmtKind kind; - private readonly IStatementParentEntity parent; - private readonly Location location; - - protected override CSharpSyntaxNode GetStatementSyntax() => Stmt; - - protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child, Location location) - : base(cx) - { - Stmt = stmt; - this.parent = parent; - this.child = child; - this.location = location; - this.kind = kind; - cx.BindComments(this, location.symbol); - } - - protected sealed override void Populate(TextWriter trapFile) - { - trapFile.statements(this, kind); - if (parent.IsTopLevelParent) - trapFile.stmt_parent_top_level(this, child, parent); - else - trapFile.stmt_parent(this, child, parent); - trapFile.stmt_location(this, location); - PopulateStatement(trapFile); - } - - protected abstract void PopulateStatement(TextWriter trapFile); - - protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child) - : this(cx, stmt, kind, parent, child, cx.Create(stmt.FixedLocation())) { } - - public override string ToString() => Label.ToString(); - } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs new file mode 100644 index 00000000000..21dd32e17cf --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs @@ -0,0 +1,35 @@ +using Semmle.Extraction.CSharp.Populators; +using Microsoft.CodeAnalysis.CSharp; +using Semmle.Extraction.Entities; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal abstract class Statement : Statement where TSyntax : CSharpSyntaxNode + { + protected readonly TSyntax Stmt; + private readonly Location location; + + protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child, Location location) + : base(cx, kind, parent, child) + { + Stmt = stmt; + this.location = location; + cx.BindComments(this, location.Symbol); + } + + protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child) + : this(cx, stmt, kind, parent, child, cx.CreateLocation(stmt.FixedLocation())) { } + + protected sealed override void Populate(TextWriter trapFile) + { + base.Populate(trapFile); + + trapFile.stmt_location(this, location); + } + + public override Microsoft.CodeAnalysis.Location ReportingLocation => Stmt.GetLocation(); + + public override string ToString() => Label.ToString(); + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs index c3e2e15baf3..c50cad9b6cd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs @@ -20,7 +20,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { var child = 0; - foreach (var childStmt in Stmt.Statements.Select(c => Statement.Create(cx, c, this, child))) + foreach (var childStmt in Stmt.Statements.Select(c => Statement.Create(Context, c, this, child))) { child += childStmt.NumberOfStatements; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs index e2a712c006b..73a2582060b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs @@ -10,7 +10,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements internal abstract class Case : Statement where TSyntax : SwitchLabelSyntax { protected Case(Context cx, TSyntax node, Switch parent, int child) - : base(cx, node, StmtKind.CASE, parent, child, cx.Create(node.GetLocation())) { } + : base(cx, node, StmtKind.CASE, parent, child, cx.CreateLocation(node.GetLocation())) { } public static Statement Create(Context cx, SwitchLabelSyntax node, Switch parent, int child) { @@ -36,8 +36,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { var value = Stmt.Value; - Expression.Create(cx, value, this, 0); - Switch.LabelForValue(cx.GetModel(Stmt).GetConstantValue(value).Value); + Expression.Create(Context, value, this, 0); + Switch.LabelForValue(Context.GetModel(Stmt).GetConstantValue(value).Value); } public static CaseLabel Create(Context cx, CaseSwitchLabelSyntax node, Switch parent, int child) @@ -70,11 +70,11 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expressions.Pattern.Create(cx, Stmt.Pattern, this, 0); + Expressions.Pattern.Create(Context, Stmt.Pattern, this, 0); if (Stmt.WhenClause != null) { - Expression.Create(cx, Stmt.WhenClause.Condition, this, 1); + Expression.Create(Context, Stmt.WhenClause.Condition, this, 1); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs index db1a0d413c1..f7484c72d56 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs @@ -10,7 +10,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements private static readonly string systemExceptionName = typeof(System.Exception).ToString(); private Catch(Context cx, CatchClauseSyntax node, Try parent, int child) - : base(cx, node, StmtKind.CATCH, parent, child, cx.Create(node.GetLocation())) { } + : base(cx, node, StmtKind.CATCH, parent, child, cx.CreateLocation(node.GetLocation())) { } protected override void PopulateStatement(TextWriter trapFile) { @@ -19,26 +19,26 @@ namespace Semmle.Extraction.CSharp.Entities.Statements if (hasVariableDeclaration) // A catch clause of the form 'catch(Ex ex) { ... }' { - var decl = Expressions.VariableDeclaration.Create(cx, Stmt.Declaration, false, this, 0); - trapFile.catch_type(this, Type.Create(cx, decl.Type).TypeRef, true); + var decl = Expressions.VariableDeclaration.Create(Context, Stmt.Declaration, false, this, 0); + trapFile.catch_type(this, Type.Create(Context, decl.Type).TypeRef, true); } else if (isSpecificCatchClause) // A catch clause of the form 'catch(Ex) { ... }' { - trapFile.catch_type(this, Type.Create(cx, cx.GetType(Stmt.Declaration.Type)).TypeRef, true); + trapFile.catch_type(this, Type.Create(Context, Context.GetType(Stmt.Declaration.Type)).TypeRef, true); } else // A catch clause of the form 'catch { ... }' { - var exception = Type.Create(cx, cx.Compilation.GetTypeByMetadataName(systemExceptionName)); + var exception = Type.Create(Context, Context.Compilation.GetTypeByMetadataName(systemExceptionName)); trapFile.catch_type(this, exception, false); } if (Stmt.Filter != null) { // For backward compatibility, the catch filter clause is child number 2. - Expression.Create(cx, Stmt.Filter.FilterExpression, this, 2); + Expression.Create(Context, Stmt.Filter.FilterExpression, this, 2); } - Create(cx, Stmt.Block, this, 1); + Create(Context, Stmt.Block, this, 1); } public static Catch Create(Context cx, CatchClauseSyntax node, Try parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs index 4ce000bed3f..0f5766fad23 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Statement.Create(cx, Stmt.Block, this, 0); + Statement.Create(Context, Stmt.Block, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs index a0cd9da7372..e3518505270 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements internal class Do : Statement { private Do(Context cx, DoStatementSyntax node, IStatementParentEntity parent, int child) - : base(cx, node, StmtKind.DO, parent, child, cx.Create(node.GetLocation())) { } + : base(cx, node, StmtKind.DO, parent, child, cx.CreateLocation(node.GetLocation())) { } public static Do Create(Context cx, DoStatementSyntax node, IStatementParentEntity parent, int child) { @@ -19,8 +19,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Create(cx, Stmt.Statement, this, 1); - Expression.Create(cx, Stmt.Condition, this, 0); + Create(Context, Stmt.Statement, this, 1); + Expression.Create(Context, Stmt.Condition, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs index 252e867efa9..76d369bde23 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs @@ -18,9 +18,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { if (Stmt.Expression != null) - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); else - cx.ModelError(Stmt, "Invalid expression statement"); + Context.ModelError(Stmt, "Invalid expression statement"); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs index 69ebdca1c16..2960982061e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs @@ -5,7 +5,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { internal static class Factory { - internal static Statement Create(Context cx, StatementSyntax node, Statement parent, int child) + internal static Statement Create(Context cx, StatementSyntax node, IStatementParentEntity parent, int child) { switch (node.Kind()) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs index 7cd8350c7d1..1d01b1708f2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs @@ -19,8 +19,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - VariableDeclarations.Populate(cx, Stmt.Declaration, this, -1, childIncrement: -1); - Create(cx, Stmt.Statement, this, 0); + VariableDeclarations.Populate(Context, Stmt.Declaration, this, -1, childIncrement: -1); + Create(Context, Stmt.Statement, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs index 15c7151a8a6..678373168f6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs @@ -22,25 +22,25 @@ namespace Semmle.Extraction.CSharp.Entities.Statements var child = -1; if (Stmt.Declaration != null) - VariableDeclarations.Populate(cx, Stmt.Declaration, this, child, childIncrement: -1); + VariableDeclarations.Populate(Context, Stmt.Declaration, this, child, childIncrement: -1); foreach (var init in Stmt.Initializers) { - Expression.Create(cx, init, this, child--); + Expression.Create(Context, init, this, child--); } if (Stmt.Condition != null) { - Expression.Create(cx, Stmt.Condition, this, 0); + Expression.Create(Context, Stmt.Condition, this, 0); } child = 1; foreach (var inc in Stmt.Incrementors) { - Expression.Create(cx, inc, this, child++); + Expression.Create(Context, inc, this, child++); } - Statement.Create(cx, Stmt.Statement, this, 1 + Stmt.Incrementors.Count); + Statement.Create(Context, Stmt.Statement, this, 1 + Stmt.Incrementors.Count); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs index 262b3f0e328..bd9b1528a13 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs @@ -8,6 +8,15 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { internal class ForEach : Statement { + internal enum ForeachSymbolType + { + GetEnumeratorMethod = 1, + CurrentProperty, + MoveNextMethod, + DisposeMethod, + ElementType + } + private ForEach(Context cx, ForEachStatementSyntax stmt, IStatementParentEntity parent, int child) : base(cx, stmt, StmtKind.FOREACH, parent, child) { } @@ -18,18 +27,59 @@ namespace Semmle.Extraction.CSharp.Entities.Statements return ret; } - protected override void PopulateStatement(TextWriter _) + protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Expression, this, 1); + Expression.Create(Context, Stmt.Expression, this, 1); - var typeSymbol = cx.GetModel(Stmt).GetDeclaredSymbol(Stmt); + var semanticModel = Context.GetModel(Stmt); + var typeSymbol = semanticModel.GetDeclaredSymbol(Stmt); var type = typeSymbol.GetAnnotatedType(); - var location = cx.Create(Stmt.Identifier.GetLocation()); + var location = Context.CreateLocation(Stmt.Identifier.GetLocation()); - Expressions.VariableDeclaration.Create(cx, typeSymbol, type, Stmt.Type, location, Stmt.Type.IsVar, this, 0); + Expressions.VariableDeclaration.Create(Context, typeSymbol, type, Stmt.Type, location, Stmt.Type.IsVar, this, 0); - Statement.Create(cx, Stmt.Statement, this, 2); + Statement.Create(Context, Stmt.Statement, this, 2); + + var info = semanticModel.GetForEachStatementInfo(Stmt); + + if (info.Equals(default)) + { + Context.ExtractionError("Could not get foreach statement info", null, Context.CreateLocation(this.ReportingLocation), severity: Util.Logging.Severity.Info); + return; + } + + trapFile.foreach_stmt_info(this, info.IsAsynchronous); + + if (info.GetEnumeratorMethod != null) + { + var m = Method.Create(Context, info.GetEnumeratorMethod); + trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.GetEnumeratorMethod); + } + + if (info.MoveNextMethod != null) + { + var m = Method.Create(Context, info.MoveNextMethod); + trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.MoveNextMethod); + } + + if (info.DisposeMethod != null) + { + var m = Method.Create(Context, info.DisposeMethod); + trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.DisposeMethod); + } + + if (info.CurrentProperty != null) + { + var p = Property.Create(Context, info.CurrentProperty); + trapFile.foreach_stmt_desugar(this, p, ForeachSymbolType.CurrentProperty); + } + + if (info.ElementType != null) + { + var t = Type.Create(Context, info.ElementType); + trapFile.foreach_stmt_desugar(this, t, ForeachSymbolType.ElementType); + } } } @@ -47,9 +97,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Variable, this, 0); - Expression.Create(cx, Stmt.Expression, this, 1); - Statement.Create(cx, Stmt.Statement, this, 2); + Expression.Create(Context, Stmt.Variable, this, 0); + Expression.Create(Context, Stmt.Expression, this, 1); + Statement.Create(Context, Stmt.Statement, this, 2); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs new file mode 100644 index 00000000000..011437fac9b --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs @@ -0,0 +1,42 @@ +using Semmle.Extraction.Kinds; +using System.Linq; +using System.IO; +using Semmle.Extraction.Entities; + +namespace Semmle.Extraction.CSharp.Entities.Statements +{ + internal class GlobalStatementsBlock : Statement + { + private readonly Method parent; + + private GlobalStatementsBlock(Context cx, Method parent) + : base(cx, StmtKind.BLOCK, parent, 0) + { + this.parent = parent; + } + + public override Microsoft.CodeAnalysis.Location ReportingLocation + { + get + { + return parent.Symbol + ?.DeclaringSyntaxReferences + .FirstOrDefault() + ?.GetSyntax() + .GetLocation(); + } + } + + public static GlobalStatementsBlock Create(Context cx, Method parent) + { + var ret = new GlobalStatementsBlock(cx, parent); + ret.TryPopulate(); + return ret; + } + + protected override void PopulateStatement(TextWriter trapFile) + { + trapFile.stmt_location(this, Context.CreateLocation(ReportingLocation)); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs index 772d69cff7c..20548dd056a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs @@ -40,8 +40,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements trapFile.exprorstmt_name(this, target); break; case StmtKind.GOTO_CASE: - Expr = Expression.Create(cx, Stmt.Expression, this, 0); - ConstantValue = Switch.LabelForValue(cx.GetModel(Stmt).GetConstantValue(Stmt.Expression).Value); + Expr = Expression.Create(Context, Stmt.Expression, this, 0); + ConstantValue = Switch.LabelForValue(Context.GetModel(Stmt).GetConstantValue(Stmt.Expression).Value); break; case StmtKind.GOTO_DEFAULT: ConstantValue = Switch.DefaultLabel; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs index b132c6ebe54..010cd9a793b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs @@ -18,12 +18,12 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Condition, this, 0); + Expression.Create(Context, Stmt.Condition, this, 0); - Create(cx, Stmt.Statement, this, 1); + Create(Context, Stmt.Statement, this, 1); if (Stmt.Else != null) - Create(cx, Stmt.Else.Statement, this, 2); + Create(Context, Stmt.Else.Statement, this, 2); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs index 1fce622b347..d549008daaf 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs @@ -6,17 +6,18 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { internal class Labeled : Statement { - private readonly Statement parent; + private readonly IStatementParentEntity parent; private readonly int child; + private Statement labelledStmt; - private Labeled(Context cx, LabeledStatementSyntax stmt, Statement parent, int child) + private Labeled(Context cx, LabeledStatementSyntax stmt, IStatementParentEntity parent, int child) : base(cx, stmt, StmtKind.LABEL, parent, child) { this.parent = parent; this.child = child; } - public static Labeled Create(Context cx, LabeledStatementSyntax node, Statement parent, int child) + public static Labeled Create(Context cx, LabeledStatementSyntax node, IStatementParentEntity parent, int child) { var ret = new Labeled(cx, node, parent, child); ret.TryPopulate(); @@ -27,13 +28,11 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { trapFile.exprorstmt_name(this, Stmt.Identifier.ToString()); - // For compatilibty with the Mono extractor, make insert the labelled statement into the same block + // For compatibility with the Mono extractor, make insert the labelled statement into the same block // as this one. The parent MUST be a block statement. - labelledStmt = Statement.Create(cx, Stmt.Statement, parent, child + 1); + labelledStmt = Statement.Create(Context, Stmt.Statement, parent, child + 1); } - private Statement labelledStmt; - public override int NumberOfStatements => 1 + labelledStmt.NumberOfStatements; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs index 87559681fd8..b147e5693ca 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs @@ -30,8 +30,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - VariableDeclarations.Populate(cx, Stmt.Declaration, this, 0); - cx.BindComments(this, Stmt.GetLocation()); + VariableDeclarations.Populate(Context, Stmt.Declaration, this, 0); + Context.BindComments(this, Stmt.GetLocation()); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs index eb81f27cb3a..aaebd538c67 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs @@ -10,7 +10,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements internal class LocalFunction : Statement { private LocalFunction(Context cx, LocalFunctionStatementSyntax node, IStatementParentEntity parent, int child) - : base(cx, node, StmtKind.LOCAL_FUNCTION, parent, child, cx.Create(node.GetLocation())) { } + : base(cx, node, StmtKind.LOCAL_FUNCTION, parent, child, cx.CreateLocation(node.GetLocation())) { } public static LocalFunction Create(Context cx, LocalFunctionStatementSyntax node, IStatementParentEntity parent, int child) { @@ -26,7 +26,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { get { - var m = cx.GetModel(Stmt); + var m = Context.GetModel(Stmt); return m.GetDeclaredSymbol(Stmt) as IMethodSymbol; } } @@ -34,7 +34,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements /// /// Gets the function defined by this local statement. /// - private Entities.LocalFunction Function => Entities.LocalFunction.Create(cx, Symbol); + private Entities.LocalFunction Function => Entities.LocalFunction.Create(Context, Symbol); protected override void PopulateStatement(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs index fbcb346b367..141edcea63a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs @@ -18,8 +18,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Expression, this, 0); - Statement.Create(cx, Stmt.Statement, this, 1); + Expression.Create(Context, Stmt.Expression, this, 0); + Statement.Create(Context, Stmt.Statement, this, 1); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs index 2ff04b82b87..64692630b4c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs @@ -19,7 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { if (Stmt.Expression != null) - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs index f64067be9c4..df73554f389 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs @@ -30,17 +30,17 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); var childIndex = 0; foreach (var section in Stmt.Sections) { - foreach (var stmt in section.Labels.Select(label => Case.Create(cx, label, this, childIndex))) + foreach (var stmt in section.Labels.Select(label => Case.Create(Context, label, this, childIndex))) { childIndex += stmt.NumberOfStatements; } - foreach (var stmt in section.Statements.Select(s => Create(cx, s, this, childIndex))) + foreach (var stmt in section.Statements.Select(s => Create(Context, s, this, childIndex))) { childIndex += stmt.NumberOfStatements; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs index c550b1f1e39..dbff60d890b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs @@ -19,7 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { if (Stmt.Expression != null) - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs index 5a6937790c2..bb17c2beaa2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs @@ -22,14 +22,14 @@ namespace Semmle.Extraction.CSharp.Entities.Statements var child = 1; foreach (var c in Stmt.Catches) { - Catch.Create(cx, c, this, child++); + Catch.Create(Context, c, this, child++); } - Create(cx, Stmt.Block, this, 0); + Create(Context, Stmt.Block, this, 0); if (Stmt.Finally != null) { - Create(cx, Stmt.Finally.Block, this, -1); + Create(Context, Stmt.Finally.Block, this, -1); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs index 2d69bdc8d4c..37de04f870b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Statement.Create(cx, Stmt.Block, this, 0); + Statement.Create(Context, Stmt.Block, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs index 4e371604333..936c5e84296 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Create(cx, Stmt.Block, this, 0); + Create(Context, Stmt.Block, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs index 93d0f6a88ff..b62e6556a8c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs @@ -20,13 +20,13 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { if (Stmt.Declaration != null) - VariableDeclarations.Populate(cx, Stmt.Declaration, this, -1, childIncrement: -1); + VariableDeclarations.Populate(Context, Stmt.Declaration, this, -1, childIncrement: -1); if (Stmt.Expression != null) - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); if (Stmt.Statement != null) - Statement.Create(cx, Stmt.Statement, this, 1); + Statement.Create(Context, Stmt.Statement, this, 1); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs index 8def91a8418..99e96e7b683 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs @@ -18,8 +18,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Condition, this, 0); - Create(cx, Stmt.Statement, this, 1); + Expression.Create(Context, Stmt.Condition, this, 0); + Create(Context, Stmt.Statement, this, 1); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs index 9aace8e0b83..605a7cacdbc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs @@ -20,7 +20,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { if (Stmt.Expression != null) { - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs index 5e0850ba8c8..2ac5c6e90e5 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs @@ -14,18 +14,18 @@ namespace Semmle.Extraction.CSharp.Entities protected CachedSymbol(Context cx, T init) : base(cx, init) { } - public virtual Type ContainingType => symbol.ContainingType != null ? Type.Create(Context, symbol.ContainingType) : null; + public virtual Type ContainingType => Symbol.ContainingType != null ? Type.Create(Context, Symbol.ContainingType) : null; public void PopulateModifiers(TextWriter trapFile) { - Modifier.ExtractModifiers(Context, trapFile, this, symbol); + Modifier.ExtractModifiers(Context, trapFile, this, Symbol); } protected void PopulateAttributes() { // Only extract attributes for source declarations - if (ReferenceEquals(symbol, symbol.OriginalDefinition)) - Attribute.ExtractAttributes(Context, symbol, this); + if (ReferenceEquals(Symbol, Symbol.OriginalDefinition)) + Attribute.ExtractAttributes(Context, Symbol, this); } protected void PopulateNullability(TextWriter trapFile, AnnotatedTypeSymbol type) @@ -55,7 +55,7 @@ namespace Semmle.Extraction.CSharp.Entities protected void ExtractCompilerGenerated(TextWriter trapFile) { - if (symbol.IsImplicitlyDeclared) + if (Symbol.IsImplicitlyDeclared) trapFile.compiler_generated(this); } @@ -63,12 +63,12 @@ namespace Semmle.Extraction.CSharp.Entities /// The location which is stored in the database and is used when highlighing source code. /// It's generally short, e.g. a method name. /// - public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol.Locations.FirstOrDefault(); + public override Microsoft.CodeAnalysis.Location ReportingLocation => Symbol.Locations.FirstOrDefault(); /// /// The full text span of the entity, e.g. for binding comments. /// - public virtual Microsoft.CodeAnalysis.Location FullLocation => symbol.Locations.FirstOrDefault(); + public virtual Microsoft.CodeAnalysis.Location FullLocation => Symbol.Locations.FirstOrDefault(); public virtual IEnumerable Locations { @@ -78,7 +78,7 @@ namespace Semmle.Extraction.CSharp.Entities if (loc != null) { // Some built in operators lack locations, so loc is null. - yield return Context.Create(ReportingLocation); + yield return Context.CreateLocation(ReportingLocation); if (Context.Extractor.OutputPath != null && loc.Kind == LocationKind.SourceFile) yield return Assembly.CreateOutputAssembly(Context); } @@ -91,11 +91,11 @@ namespace Semmle.Extraction.CSharp.Entities /// protected void BindComments() { - if (!symbol.IsImplicitlyDeclared && IsSourceDeclaration && symbol.FromSource()) + if (!Symbol.IsImplicitlyDeclared && IsSourceDeclaration && Symbol.FromSource()) Context.BindComments(this, FullLocation); } - protected virtual T BodyDeclaringSymbol => symbol; + protected virtual T BodyDeclaringSymbol => Symbol; public BlockSyntax Block { @@ -120,11 +120,11 @@ namespace Semmle.Extraction.CSharp.Entities } } - public virtual bool IsSourceDeclaration => symbol.IsSourceDeclaration(); + public virtual bool IsSourceDeclaration => Symbol.IsSourceDeclaration(); - public override bool NeedsPopulation => Context.Defines(symbol); + public override bool NeedsPopulation => Context.Defines(Symbol); - public Extraction.Entities.Location Location => Context.Create(ReportingLocation); + public Extraction.Entities.Location Location => Context.CreateLocation(ReportingLocation); protected void PopulateMetadataHandle(TextWriter trapFile) { @@ -143,15 +143,15 @@ namespace Semmle.Extraction.CSharp.Entities { get { - var handleProp = GetPropertyInfo(symbol, "Handle"); - object handleObj = symbol; + var handleProp = GetPropertyInfo(Symbol, "Handle"); + object handleObj = Symbol; if (handleProp is null) { - var underlyingSymbolProp = GetPropertyInfo(symbol, "UnderlyingSymbol"); + var underlyingSymbolProp = GetPropertyInfo(Symbol, "UnderlyingSymbol"); if (underlyingSymbolProp is object) { - if (underlyingSymbolProp.GetValue(symbol) is object underlying) + if (underlyingSymbolProp.GetValue(Symbol) is object underlying) { handleProp = GetPropertyInfo(underlying, "Handle"); handleObj = underlying; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs index 8d6074f3e8d..e2fd72eae56 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities case NullableTypeSyntax nts: // int[]? -> int[] -> int // int? -> int? - return cx.GetTypeInfo(nts.ElementType).Type.IsReferenceType + return Context.GetTypeInfo(nts.ElementType).Type.IsReferenceType ? GetArrayElementType(nts.ElementType) : nts; case PointerTypeSyntax pts: @@ -48,8 +48,8 @@ namespace Semmle.Extraction.CSharp.Entities { case ArrayType at: return GetArrayElementType(at.ElementType); - case NamedType nt when nt.symbol.IsBoundSpan() || - nt.symbol.IsBoundReadOnlySpan(): + case NamedType nt when nt.Symbol.IsBoundSpan() || + nt.Symbol.IsBoundReadOnlySpan(): return nt.TypeArguments.Single(); case PointerType pt: return GetArrayElementType(pt.PointedAtType); @@ -65,48 +65,48 @@ namespace Semmle.Extraction.CSharp.Entities case SyntaxKind.ArrayType: case SyntaxKind.PointerType: Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); - Create(cx, GetArrayElementType(syntax), this, GetArrayElementType(type)); + Create(Context, GetArrayElementType(syntax), this, GetArrayElementType(type)); return; case SyntaxKind.NullableType: var nts = (NullableTypeSyntax)syntax; if (type is NamedType nt) { - if (!nt.symbol.IsReferenceType) + if (!nt.Symbol.IsReferenceType) { Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); - Create(cx, nts.ElementType, this, nt.TypeArguments[0]); + Create(Context, nts.ElementType, this, nt.TypeArguments[0]); } else { - Create(cx, nts.ElementType, parent, type); + Create(Context, nts.ElementType, parent, type); } } else if (type is ArrayType) { - Create(cx, nts.ElementType, parent, type); + Create(Context, nts.ElementType, parent, type); } return; case SyntaxKind.TupleType: var tts = (TupleTypeSyntax)syntax; var tt = (TupleType)type; Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); - tts.Elements.Zip(tt.TupleElements, (s, t) => Create(cx, s.Type, this, t.Type)).Enumerate(); + tts.Elements.Zip(tt.TupleElements, (s, t) => Create(Context, s.Type, this, t.Type)).Enumerate(); return; case SyntaxKind.GenericName: Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); - cx.PopulateLater(() => + Context.PopulateLater(() => ((GenericNameSyntax)syntax) .TypeArgumentList .Arguments - .Zip(type.TypeMentions, (s, t) => Create(cx, s, this, t)).Enumerate()); + .Zip(type.TypeMentions, (s, t) => Create(Context, s, this, t)).Enumerate()); return; case SyntaxKind.QualifiedName: var qns = (QualifiedNameSyntax)syntax; - var right = Create(cx, qns.Right, parent, type); + var right = Create(Context, qns.Right, parent, type); if (type.ContainingType is object) { // Type qualifier - Create(cx, qns.Left, right, type.ContainingType); + Create(Context, qns.Left, right, type.ContainingType); } return; default: @@ -118,7 +118,7 @@ namespace Semmle.Extraction.CSharp.Entities private void Emit(TextWriter trapFile, Microsoft.CodeAnalysis.Location loc, IEntity parent, Type type) { trapFile.type_mention(this, type.TypeRef, parent); - trapFile.type_mention_location(this, cx.Create(loc)); + trapFile.type_mention_location(this, Context.CreateLocation(loc)); } public static TypeMention Create(Context cx, TypeSyntax syntax, IEntity parent, Type type, Microsoft.CodeAnalysis.Location loc = null) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs index 4ec1db558e5..62a10396b4b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs @@ -9,12 +9,12 @@ namespace Semmle.Extraction.CSharp.Entities private ArrayType(Context cx, IArrayTypeSymbol init) : base(cx, init) { - elementLazy = new Lazy(() => Create(cx, symbol.ElementType)); + elementLazy = new Lazy(() => Create(cx, Symbol.ElementType)); } private readonly Lazy elementLazy; - public int Rank => symbol.Rank; + public int Rank => Symbol.Rank; public Type ElementType => elementLazy.Value; @@ -33,7 +33,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { trapFile.WriteSubId(ElementType); - symbol.BuildArraySuffix(trapFile); + Symbol.BuildArraySuffix(trapFile); trapFile.Write(";type"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/FunctionPointerType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/FunctionPointerType.cs index 1bf68a4c3c2..903de837a73 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/FunctionPointerType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/FunctionPointerType.cs @@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, symbol); + Symbol.BuildTypeId(Context, trapFile, Symbol); trapFile.Write(";functionpointertype"); } @@ -21,8 +21,8 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate(TextWriter trapFile) { - trapFile.function_pointer_calling_conventions(this, (int)symbol.Signature.CallingConvention); - foreach (var (conv, i) in symbol.Signature.UnmanagedCallingConventionTypes.Select((nt, i) => (Create(Context, nt), i))) + trapFile.function_pointer_calling_conventions(this, (int)Symbol.Signature.CallingConvention); + foreach (var (conv, i) in Symbol.Signature.UnmanagedCallingConventionTypes.Select((nt, i) => (Create(Context, nt), i))) { trapFile.has_unmanaged_calling_conventions(this, i, conv.TypeRef); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index bded5f60c57..4c250e22692 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities private NamedType(Context cx, INamedTypeSymbol init, bool constructUnderlyingTupleType) : base(cx, init) { - typeArgumentsLazy = new Lazy(() => symbol.TypeArguments.Select(t => Create(cx, t)).ToArray()); + typeArgumentsLazy = new Lazy(() => Symbol.TypeArguments.Select(t => Create(cx, t)).ToArray()); this.constructUnderlyingTupleType = constructUnderlyingTupleType; } @@ -30,32 +30,32 @@ namespace Semmle.Extraction.CSharp.Entities public static NamedType CreateNamedTypeFromTupleType(Context cx, INamedTypeSymbol type) => UnderlyingTupleTypeFactory.Instance.CreateEntity(cx, (new SymbolEqualityWrapper(type), typeof(TupleType)), type); - public override bool NeedsPopulation => base.NeedsPopulation || symbol.TypeKind == TypeKind.Error; + public override bool NeedsPopulation => base.NeedsPopulation || Symbol.TypeKind == TypeKind.Error; public override void Populate(TextWriter trapFile) { - if (symbol.TypeKind == TypeKind.Error) + if (Symbol.TypeKind == TypeKind.Error) { - Context.Extractor.MissingType(symbol.ToString(), Context.FromSource); + Context.Extractor.MissingType(Symbol.ToString(), Context.FromSource); return; } if (UsesTypeRef) trapFile.typeref_type((NamedTypeRef)TypeRef, this); - if (symbol.IsGenericType) + if (Symbol.IsGenericType) { - if (symbol.IsBoundNullable()) + if (Symbol.IsBoundNullable()) { // An instance of Nullable - trapFile.nullable_underlying_type(this, Create(Context, symbol.TypeArguments[0]).TypeRef); + trapFile.nullable_underlying_type(this, Create(Context, Symbol.TypeArguments[0]).TypeRef); } - else if (symbol.IsReallyUnbound()) + else if (Symbol.IsReallyUnbound()) { - for (var i = 0; i < symbol.TypeParameters.Length; ++i) + for (var i = 0; i < Symbol.TypeParameters.Length; ++i) { - TypeParameter.Create(Context, symbol.TypeParameters[i]); - var param = symbol.TypeParameters[i]; + TypeParameter.Create(Context, Symbol.TypeParameters[i]); + var param = Symbol.TypeParameters[i]; var typeParameter = TypeParameter.Create(Context, param); trapFile.type_parameters(typeParameter, i, this); } @@ -63,11 +63,11 @@ namespace Semmle.Extraction.CSharp.Entities else { var unbound = constructUnderlyingTupleType - ? CreateNamedTypeFromTupleType(Context, symbol.ConstructedFrom) - : Type.Create(Context, symbol.ConstructedFrom); + ? CreateNamedTypeFromTupleType(Context, Symbol.ConstructedFrom) + : Type.Create(Context, Symbol.ConstructedFrom); trapFile.constructed_generic(this, unbound.TypeRef); - for (var i = 0; i < symbol.TypeArguments.Length; ++i) + for (var i = 0; i < Symbol.TypeArguments.Length; ++i) { trapFile.type_arguments(TypeArguments[i].TypeRef, i, this); } @@ -76,19 +76,19 @@ namespace Semmle.Extraction.CSharp.Entities PopulateType(trapFile, constructUnderlyingTupleType); - if (symbol.EnumUnderlyingType != null) + if (Symbol.EnumUnderlyingType != null) { - trapFile.enum_underlying_type(this, Type.Create(Context, symbol.EnumUnderlyingType).TypeRef); + trapFile.enum_underlying_type(this, Type.Create(Context, Symbol.EnumUnderlyingType).TypeRef); } // Class location - if (!symbol.IsGenericType || symbol.IsReallyUnbound()) + if (!Symbol.IsGenericType || Symbol.IsReallyUnbound()) { foreach (var l in Locations) trapFile.type_location(this, l); } - if (symbol.IsAnonymousType) + if (Symbol.IsAnonymousType) { trapFile.anonymous_types(this); } @@ -105,10 +105,10 @@ namespace Semmle.Extraction.CSharp.Entities { get { - foreach (var l in GetLocations(symbol)) - yield return Context.Create(l); + foreach (var l in GetLocations(Symbol)) + yield return Context.CreateLocation(l); - if (Context.Extractor.OutputPath != null && symbol.DeclaringSyntaxReferences.Any()) + if (Context.Extractor.OutputPath != null && Symbol.DeclaringSyntaxReferences.Any()) yield return Assembly.CreateOutputAssembly(Context); } } @@ -124,9 +124,9 @@ namespace Semmle.Extraction.CSharp.Entities ); } - public override Microsoft.CodeAnalysis.Location ReportingLocation => GetLocations(symbol).FirstOrDefault(); + public override Microsoft.CodeAnalysis.Location ReportingLocation => GetLocations(Symbol).FirstOrDefault(); - private bool IsAnonymousType() => symbol.IsAnonymousType || symbol.Name.Contains("__AnonymousType"); + private bool IsAnonymousType() => Symbol.IsAnonymousType || Symbol.Name.Contains("__AnonymousType"); public override void WriteId(TextWriter trapFile) { @@ -136,7 +136,7 @@ namespace Semmle.Extraction.CSharp.Entities } else { - symbol.BuildTypeId(Context, trapFile, symbol, constructUnderlyingTupleType); + Symbol.BuildTypeId(Context, trapFile, Symbol, constructUnderlyingTupleType); trapFile.Write(";type"); } } @@ -167,9 +167,9 @@ namespace Semmle.Extraction.CSharp.Entities // Create typerefs for constructed error types in case they are fully defined elsewhere. // We cannot use `!this.NeedsPopulation` because this would not be stable as it would depend on // the assembly that was being extracted at the time. - private bool UsesTypeRef => symbol.TypeKind == TypeKind.Error || SymbolEqualityComparer.Default.Equals(symbol.OriginalDefinition, symbol); + private bool UsesTypeRef => Symbol.TypeKind == TypeKind.Error || SymbolEqualityComparer.Default.Equals(Symbol.OriginalDefinition, Symbol); - public override Type TypeRef => UsesTypeRef ? (Type)NamedTypeRef.Create(Context, symbol) : this; + public override Type TypeRef => UsesTypeRef ? (Type)NamedTypeRef.Create(Context, Symbol) : this; } internal class NamedTypeRef : Type @@ -203,7 +203,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate(TextWriter trapFile) { - trapFile.typerefs(this, symbol.Name); + trapFile.typerefs(this, Symbol.Name); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs index 106efdd0cde..a0d9e2a1f8c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs @@ -110,10 +110,10 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate(TextWriter trapFile) { - trapFile.nullability(this, symbol.Annotation); + trapFile.nullability(this, Symbol.Annotation); var i = 0; - foreach (var s in symbol.NullableParameters) + foreach (var s in Symbol.NullableParameters) { trapFile.nullability_parent(Create(Context, s), i, this); i++; @@ -122,7 +122,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - symbol.WriteId(trapFile); + Symbol.WriteId(trapFile); } public static NullabilityEntity Create(Context cx, Nullability init) => NullabilityFactory.Instance.CreateEntity(cx, init, init); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs index e2fbb8677cc..dd9b749f53e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/PointerType.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.CSharp.Entities private PointerType(Context cx, IPointerTypeSymbol init) : base(cx, init) { - PointedAtType = Create(cx, symbol.PointedAtType); + PointedAtType = Create(cx, Symbol.PointedAtType); } public override void WriteId(TextWriter trapFile) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index 4ddc258f5c7..18321f84d32 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -24,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Entities private TupleType(Context cx, INamedTypeSymbol init) : base(cx, init) { - tupleElementsLazy = new Lazy(() => symbol.TupleElements.Select(t => Field.Create(cx, t)).ToArray()); + tupleElementsLazy = new Lazy(() => Symbol.TupleElements.Select(t => Field.Create(cx, t)).ToArray()); } // All tuple types are "local types" @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, symbol); + Symbol.BuildTypeId(Context, trapFile, Symbol); trapFile.Write(";tuple"); } @@ -41,7 +41,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulateType(trapFile); PopulateGenerics(); - var underlyingType = NamedType.CreateNamedTypeFromTupleType(Context, symbol.TupleUnderlyingType ?? symbol); + var underlyingType = NamedType.CreateNamedTypeFromTupleType(Context, Symbol.TupleUnderlyingType ?? Symbol); trapFile.tuple_underlying_type(this, underlyingType); @@ -52,8 +52,8 @@ namespace Semmle.Extraction.CSharp.Entities // Note: symbol.Locations seems to be very inconsistent // about what locations are available for a tuple type. // Sometimes it's the source code, and sometimes it's empty. - foreach (var l in symbol.Locations) - trapFile.type_location(this, Context.Create(l)); + foreach (var l in Symbol.Locations) + trapFile.type_location(this, Context.CreateLocation(l)); } private readonly Lazy tupleElementsLazy; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 8c96a334565..3931c6ef1d8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -15,7 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities public override bool NeedsPopulation => - base.NeedsPopulation || symbol.TypeKind == TypeKind.Dynamic || symbol.TypeKind == TypeKind.TypeParameter; + base.NeedsPopulation || Symbol.TypeKind == TypeKind.Dynamic || Symbol.TypeKind == TypeKind.TypeParameter; public static bool ConstructedOrParentIsConstructed(INamedTypeSymbol symbol) { @@ -75,24 +75,24 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.Write("types("); trapFile.WriteColumn(this); trapFile.Write(','); - trapFile.WriteColumn((int)GetClassType(Context, symbol, constructUnderlyingTupleType)); + trapFile.WriteColumn((int)GetClassType(Context, Symbol, constructUnderlyingTupleType)); trapFile.Write(",\""); - symbol.BuildDisplayName(Context, trapFile, constructUnderlyingTupleType); + Symbol.BuildDisplayName(Context, trapFile, constructUnderlyingTupleType); trapFile.WriteLine("\")"); // Visit base types var baseTypes = new List(); - if (symbol.GetNonObjectBaseType(Context) is INamedTypeSymbol @base) + if (Symbol.GetNonObjectBaseType(Context) is INamedTypeSymbol @base) { var baseKey = Create(Context, @base); trapFile.extend(this, baseKey.TypeRef); - if (symbol.TypeKind != TypeKind.Struct) + if (Symbol.TypeKind != TypeKind.Struct) baseTypes.Add(baseKey); } - if (!(base.symbol is IArrayTypeSymbol)) + if (!(base.Symbol is IArrayTypeSymbol)) { - foreach (var t in base.symbol.Interfaces.Select(i => Create(Context, i))) + foreach (var t in base.Symbol.Interfaces.Select(i => Create(Context, i))) { trapFile.implement(this, t.TypeRef); baseTypes.Add(t); @@ -100,17 +100,17 @@ namespace Semmle.Extraction.CSharp.Entities } var containingType = ContainingType; - if (containingType != null && symbol.Kind != SymbolKind.TypeParameter) + if (containingType != null && Symbol.Kind != SymbolKind.TypeParameter) { - var originalDefinition = symbol.TypeKind == TypeKind.Error ? this : Create(Context, symbol.OriginalDefinition); + var originalDefinition = Symbol.TypeKind == TypeKind.Error ? this : Create(Context, Symbol.OriginalDefinition); trapFile.nested_types(this, containingType, originalDefinition); } - else if (symbol.ContainingNamespace != null) + else if (Symbol.ContainingNamespace != null) { - trapFile.parent_namespace(this, Namespace.Create(Context, symbol.ContainingNamespace)); + trapFile.parent_namespace(this, Namespace.Create(Context, Symbol.ContainingNamespace)); } - if (symbol is IArrayTypeSymbol array) + if (Symbol is IArrayTypeSymbol array) { // They are in the namespace of the original object var elementType = array.ElementType; @@ -119,7 +119,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.parent_namespace(this, Namespace.Create(Context, ns)); } - if (symbol is IPointerTypeSymbol pointer) + if (Symbol is IPointerTypeSymbol pointer) { var elementType = pointer.PointedAtType; var ns = elementType.TypeKind == TypeKind.TypeParameter ? Context.Compilation.GlobalNamespace : elementType.ContainingNamespace; @@ -128,26 +128,26 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.parent_namespace(this, Namespace.Create(Context, ns)); } - if (symbol.BaseType != null && symbol.BaseType.SpecialType == SpecialType.System_MulticastDelegate) + if (Symbol.BaseType != null && Symbol.BaseType.SpecialType == SpecialType.System_MulticastDelegate) { // This is a delegate. // The method "Invoke" has the return type. - var invokeMethod = ((INamedTypeSymbol)symbol).DelegateInvokeMethod; + var invokeMethod = ((INamedTypeSymbol)Symbol).DelegateInvokeMethod; ExtractParametersForDelegateLikeType(trapFile, invokeMethod, t => trapFile.delegate_return_type(this, t)); } - if (symbol is IFunctionPointerTypeSymbol functionPointer) + if (Symbol is IFunctionPointerTypeSymbol functionPointer) { ExtractParametersForDelegateLikeType(trapFile, functionPointer.Signature, t => trapFile.function_pointer_return_type(this, t)); } - Modifier.ExtractModifiers(Context, trapFile, this, symbol); + Modifier.ExtractModifiers(Context, trapFile, this, Symbol); - if (IsSourceDeclaration && symbol.FromSource()) + if (IsSourceDeclaration && Symbol.FromSource()) { - var declSyntaxReferences = symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).ToArray(); + var declSyntaxReferences = Symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).ToArray(); var baseLists = declSyntaxReferences.OfType().Select(c => c.BaseList); baseLists = baseLists.Concat(declSyntaxReferences.OfType().Select(c => c.BaseList)); @@ -157,7 +157,7 @@ namespace Semmle.Extraction.CSharp.Entities .Where(bl => bl != null) .SelectMany(bl => bl.Types) .Zip( - baseTypes.Where(bt => bt.symbol.SpecialType != SpecialType.System_Object), + baseTypes.Where(bt => bt.Symbol.SpecialType != SpecialType.System_Object), (s, t) => TypeMention.Create(Context, s.Type, this, t)) .Enumerate(); } @@ -171,7 +171,7 @@ namespace Semmle.Extraction.CSharp.Entities var originalParam = invokeMethod.OriginalDefinition.Parameters[i]; var originalParamEntity = SymbolEqualityComparer.Default.Equals(param, originalParam) ? null - : DelegateTypeParameter.Create(Context, originalParam, Create(Context, ((INamedTypeSymbol)symbol).OriginalDefinition)); + : DelegateTypeParameter.Create(Context, originalParam, Create(Context, ((INamedTypeSymbol)Symbol).OriginalDefinition)); DelegateTypeParameter.Create(Context, param, this, originalParamEntity); } @@ -187,12 +187,12 @@ namespace Semmle.Extraction.CSharp.Entities /// public void ExtractRecursive() { - foreach (var l in symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax().GetLocation())) + foreach (var l in Symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax().GetLocation())) { Context.BindComments(this, l); } - foreach (var member in symbol.GetMembers()) + foreach (var member in Symbol.GetMembers()) { switch (member.Kind) { @@ -211,21 +211,21 @@ namespace Semmle.Extraction.CSharp.Entities /// public void PopulateGenerics() { - if (symbol == null || !NeedsPopulation || !Context.ExtractGenerics(this)) + if (Symbol == null || !NeedsPopulation || !Context.ExtractGenerics(this)) return; var members = new List(); - foreach (var member in symbol.GetMembers()) + foreach (var member in Symbol.GetMembers()) members.Add(member); - foreach (var member in symbol.GetTypeMembers()) + foreach (var member in Symbol.GetTypeMembers()) members.Add(member); // Mono extractor puts all BASE interface members as members of the current interface. - if (symbol.TypeKind == TypeKind.Interface) + if (Symbol.TypeKind == TypeKind.Interface) { - foreach (var baseInterface in symbol.Interfaces) + foreach (var baseInterface in Symbol.Interfaces) { foreach (var member in baseInterface.GetMembers()) members.Add(member); @@ -239,10 +239,10 @@ namespace Semmle.Extraction.CSharp.Entities Context.CreateEntity(member); } - if (symbol.BaseType != null) - Create(Context, symbol.BaseType).PopulateGenerics(); + if (Symbol.BaseType != null) + Create(Context, Symbol.BaseType).PopulateGenerics(); - foreach (var i in symbol.Interfaces) + foreach (var i in Symbol.Interfaces) { Create(Context, i).PopulateGenerics(); } @@ -250,7 +250,7 @@ namespace Semmle.Extraction.CSharp.Entities public void ExtractRecursive(TextWriter trapFile, IEntity parent) { - if (symbol.ContainingSymbol.Kind == SymbolKind.Namespace && !symbol.ContainingNamespace.IsGlobalNamespace) + if (Symbol.ContainingSymbol.Kind == SymbolKind.Namespace && !Symbol.ContainingNamespace.IsGlobalNamespace) { trapFile.parent_namespace_declaration(this, (NamespaceDeclaration)parent); } @@ -315,10 +315,10 @@ namespace Semmle.Extraction.CSharp.Entities public override bool Equals(object obj) { var other = obj as Type; - return other?.GetType() == GetType() && SymbolEqualityComparer.Default.Equals(other.symbol, symbol); + return other?.GetType() == GetType() && SymbolEqualityComparer.Default.Equals(other.Symbol, Symbol); } - public override int GetHashCode() => SymbolEqualityComparer.Default.GetHashCode(symbol); + public override int GetHashCode() => SymbolEqualityComparer.Default.GetHashCode(Symbol); } internal abstract class Type : Type where T : ITypeSymbol @@ -326,6 +326,7 @@ namespace Semmle.Extraction.CSharp.Entities protected Type(Context cx, T init) : base(cx, init) { } - public new T symbol => (T)base.symbol; + // todo: change this with .net 5 to be an override + public new T Symbol => (T)base.Symbol; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs index b4d35f7b506..fc8ac7e39d8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs @@ -24,22 +24,22 @@ namespace Semmle.Extraction.CSharp.Entities var constraints = new TypeParameterConstraints(Context); trapFile.type_parameter_constraints(constraints, this); - if (symbol.HasReferenceTypeConstraint) + if (Symbol.HasReferenceTypeConstraint) trapFile.general_type_parameter_constraints(constraints, 1); - if (symbol.HasValueTypeConstraint) + if (Symbol.HasValueTypeConstraint) trapFile.general_type_parameter_constraints(constraints, 2); - if (symbol.HasConstructorConstraint) + if (Symbol.HasConstructorConstraint) trapFile.general_type_parameter_constraints(constraints, 3); - if (symbol.HasUnmanagedTypeConstraint) + if (Symbol.HasUnmanagedTypeConstraint) trapFile.general_type_parameter_constraints(constraints, 4); - if (symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated) + if (Symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated) trapFile.general_type_parameter_constraints(constraints, 5); - foreach (var abase in symbol.GetAnnotatedTypeConstraints()) + foreach (var abase in Symbol.GetAnnotatedTypeConstraints()) { var t = Create(Context, abase.Symbol); trapFile.specific_type_parameter_constraints(constraints, t.TypeRef); @@ -47,19 +47,19 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.specific_type_parameter_nullability(constraints, t.TypeRef, NullabilityEntity.Create(Context, Nullability.Create(abase))); } - trapFile.types(this, Kinds.TypeKind.TYPE_PARAMETER, symbol.Name); + trapFile.types(this, Kinds.TypeKind.TYPE_PARAMETER, Symbol.Name); - var parentNs = Namespace.Create(Context, symbol.TypeParameterKind == TypeParameterKind.Method ? Context.Compilation.GlobalNamespace : symbol.ContainingNamespace); + var parentNs = Namespace.Create(Context, Symbol.TypeParameterKind == TypeParameterKind.Method ? Context.Compilation.GlobalNamespace : Symbol.ContainingNamespace); trapFile.parent_namespace(this, parentNs); - foreach (var l in symbol.Locations) + foreach (var l in Symbol.Locations) { - trapFile.type_location(this, Context.Create(l)); + trapFile.type_location(this, Context.CreateLocation(l)); } if (IsSourceDeclaration) { - var declSyntaxReferences = symbol.DeclaringSyntaxReferences + var declSyntaxReferences = Symbol.DeclaringSyntaxReferences .Select(d => d.GetSyntax()) .Select(s => s.Parent) .Where(p => p != null) @@ -69,7 +69,7 @@ namespace Semmle.Extraction.CSharp.Entities clauses = clauses.Concat(declSyntaxReferences.OfType().SelectMany(c => c.ConstraintClauses)); clauses = clauses.Concat(declSyntaxReferences.OfType().SelectMany(c => c.ConstraintClauses)); clauses = clauses.Concat(declSyntaxReferences.OfType().SelectMany(c => c.ConstraintClauses)); - foreach (var clause in clauses.Where(c => c.Name.Identifier.Text == symbol.Name)) + foreach (var clause in clauses.Where(c => c.Name.Identifier.Text == Symbol.Name)) { TypeMention.Create(Context, clause.Name, this, this); foreach (var constraint in clause.Constraints.OfType()) @@ -92,13 +92,13 @@ namespace Semmle.Extraction.CSharp.Entities { get { - switch (symbol.Variance) + switch (Symbol.Variance) { case VarianceKind.None: return Variance.None; case VarianceKind.Out: return Variance.Out; case VarianceKind.In: return Variance.In; default: - throw new InternalError($"Unexpected VarianceKind {symbol.Variance}"); + throw new InternalError($"Unexpected VarianceKind {Symbol.Variance}"); } } } @@ -107,22 +107,22 @@ namespace Semmle.Extraction.CSharp.Entities { string kind; IEntity containingEntity; - switch (symbol.TypeParameterKind) + switch (Symbol.TypeParameterKind) { case TypeParameterKind.Method: kind = "methodtypeparameter"; - containingEntity = Method.Create(Context, (IMethodSymbol)symbol.ContainingSymbol); + containingEntity = Method.Create(Context, (IMethodSymbol)Symbol.ContainingSymbol); break; case TypeParameterKind.Type: kind = "typeparameter"; - containingEntity = Create(Context, symbol.ContainingType); + containingEntity = Create(Context, Symbol.ContainingType); break; default: - throw new InternalError(symbol, $"Unhandled type parameter kind {symbol.TypeParameterKind}"); + throw new InternalError(Symbol, $"Unhandled type parameter kind {Symbol.TypeParameterKind}"); } trapFile.WriteSubId(containingEntity); trapFile.Write('_'); - trapFile.Write(symbol.Ordinal); + trapFile.Write(Symbol.Ordinal); trapFile.Write(';'); trapFile.Write(kind); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index d4c6fa457c1..2643363773b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -15,10 +15,10 @@ namespace Semmle.Extraction.CSharp.Entities PopulateMethod(trapFile); PopulateModifiers(trapFile); - var returnType = Type.Create(Context, symbol.ReturnType); + var returnType = Type.Create(Context, Symbol.ReturnType); trapFile.operators(this, - symbol.Name, - OperatorSymbol(Context, symbol.Name), + Symbol.Name, + OperatorSymbol(Context, Symbol.Name), ContainingType, returnType.TypeRef, (UserOperator)OriginalDefinition); @@ -28,7 +28,7 @@ namespace Semmle.Extraction.CSharp.Entities if (IsSourceDeclaration) { - var declSyntaxReferences = symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax()).ToArray(); + var declSyntaxReferences = Symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax()).ToArray(); foreach (var declaration in declSyntaxReferences.OfType()) TypeMention.Create(Context, declaration.ReturnType, this, returnType); foreach (var declaration in declSyntaxReferences.OfType()) @@ -38,7 +38,7 @@ namespace Semmle.Extraction.CSharp.Entities ContainingType.PopulateGenerics(); } - public override bool NeedsPopulation => Context.Defines(symbol) || IsImplicitOperator(out _); + public override bool NeedsPopulation => Context.Defines(Symbol) || IsImplicitOperator(out _); public override Type ContainingType { @@ -57,22 +57,22 @@ namespace Semmle.Extraction.CSharp.Entities /// private bool IsImplicitOperator(out ITypeSymbol containingType) { - containingType = symbol.ContainingType; + containingType = Symbol.ContainingType; if (containingType != null) { var containingNamedType = containingType as INamedTypeSymbol; return containingNamedType == null || - !containingNamedType.GetMembers(symbol.Name).Contains(symbol); + !containingNamedType.GetMembers(Symbol.Name).Contains(Symbol); } - var pointerType = symbol.Parameters.Select(p => p.Type).OfType().FirstOrDefault(); + var pointerType = Symbol.Parameters.Select(p => p.Type).OfType().FirstOrDefault(); if (pointerType != null) { containingType = pointerType; return true; } - Context.ModelError(symbol, "Unexpected implicit operator"); + Context.ModelError(Symbol, "Unexpected implicit operator"); return true; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs index caa12ab0082..96ce5f339cf 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs @@ -21,30 +21,30 @@ namespace Semmle.Extraction.CSharp.Entities protected override void Populate(TextWriter trapFile) { - var info = cx.GetModel(node).GetSymbolInfo(node.Name); + var info = Context.GetModel(node).GetSymbolInfo(node.Name); if (node.StaticKeyword.Kind() == SyntaxKind.None) { // A normal using if (info.Symbol is INamespaceSymbol namespaceSymbol) { - var ns = Namespace.Create(cx, namespaceSymbol); + var ns = Namespace.Create(Context, namespaceSymbol); trapFile.using_namespace_directives(this, ns); - trapFile.using_directive_location(this, cx.Create(ReportingLocation)); + trapFile.using_directive_location(this, Context.CreateLocation(ReportingLocation)); } else { - cx.Extractor.MissingNamespace(node.Name.ToFullString(), cx.FromSource); - cx.ModelError(node, "Namespace not found"); + Context.Extractor.MissingNamespace(node.Name.ToFullString(), Context.FromSource); + Context.ModelError(node, "Namespace not found"); return; } } else { // A "using static" - var m = Type.Create(cx, (ITypeSymbol)info.Symbol); + var m = Type.Create(Context, (ITypeSymbol)info.Symbol); trapFile.using_static_directives(this, m.TypeRef); - trapFile.using_directive_location(this, cx.Create(ReportingLocation)); + trapFile.using_directive_location(this, Context.CreateLocation(ReportingLocation)); } if (parent != null) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs index cf991e0930a..2f979863dd0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs @@ -68,7 +68,10 @@ namespace Semmle.Extraction.CSharp { var stopwatch = new Stopwatch(); stopwatch.Start(); - var commandLineArguments = Options.CreateWithEnvironment(args); + + Entities.Compilation.Settings = (Directory.GetCurrentDirectory(), args); + + var commandLineArguments = Options.CreateWithEnvironment(Entities.Compilation.Settings.Args); var fileLogger = new FileLogger(commandLineArguments.Verbosity, GetCSharpLogPath()); using var logger = commandLineArguments.Console ? new CombinedLogger(new ConsoleLogger(commandLineArguments.Verbosity), fileLogger) @@ -95,10 +98,9 @@ namespace Semmle.Extraction.CSharp return ExitCode.Ok; } - var cwd = Directory.GetCurrentDirectory(); var compilerArguments = CSharpCommandLineParser.Default.Parse( compilerVersion.ArgsWithResponse, - cwd, + Entities.Compilation.Settings.Cwd, compilerVersion.FrameworkPath, compilerVersion.AdditionalReferenceDirectories ); @@ -106,7 +108,7 @@ namespace Semmle.Extraction.CSharp if (compilerArguments == null) { var sb = new StringBuilder(); - sb.Append(" Failed to parse command line: ").AppendList(" ", args); + sb.Append(" Failed to parse command line: ").AppendList(" ", Entities.Compilation.Settings.Args); logger.Log(Severity.Error, sb.ToString()); ++analyser.CompilationErrors; return ExitCode.Failed; @@ -159,7 +161,7 @@ namespace Semmle.Extraction.CSharp ); analyser.EndInitialize(compilerArguments, commandLineArguments, compilation); - analyser.AnalyseCompilation(cwd, args); + analyser.AnalyseCompilation(); analyser.AnalyseReferences(); foreach (var tree in compilation.SyntaxTrees) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs index ee1185da30d..292e8c47d98 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs @@ -124,5 +124,7 @@ namespace Semmle.Extraction.Kinds AND_PATTERN = 127, OR_PATTERN = 128, FUNCTION_POINTER_INVOCATION = 129, + + DEFINE_SYMBOL = 999 } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs deleted file mode 100644 index 866d436bda1..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Entities; - -namespace Semmle.Extraction.CSharp.Populators -{ - internal class Ast : CSharpSyntaxVisitor - { - private readonly Context cx; - private readonly IExpressionParentEntity parent; - private readonly int child; - - public Ast(Context cx, IExpressionParentEntity parent, int child) - { - this.cx = cx; - this.parent = parent; - this.child = child; - } - - public override void DefaultVisit(SyntaxNode node) - { - cx.ModelError(node, $"Unhandled syntax node {node.Kind()}"); - } - - public override void VisitArgumentList(ArgumentListSyntax node) - { - var c = 0; - foreach (var m in node.Arguments) - { - cx.Extract(m, parent, c++); - } - } - - public override void VisitArgument(ArgumentSyntax node) - { - Expression.Create(cx, node.Expression, parent, child); - } - } - - public static class AstExtensions - { - public static void Extract(this Context cx, CSharpSyntaxNode node, IExpressionParentEntity parent, int child) - { - using (cx.StackGuard) - { - try - { - node.Accept(new Ast(cx, parent, child)); - } - catch (System.Exception ex) // lgtm[cs/catch-of-all-exceptions] - { - cx.ModelError(node, $"Exception processing syntax node of type {node.Kind()}: {ex.Message}"); - } - } - } - - public static void Extract(this Context cx, SyntaxNode node, IEntity parent, int child) - { - cx.Extract(((CSharpSyntaxNode)node), parent, child); - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/AstLineCounter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/AstLineCounter.cs new file mode 100644 index 00000000000..a185675ee27 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/AstLineCounter.cs @@ -0,0 +1,48 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Util; + +namespace Semmle.Extraction.CSharp.Populators +{ + internal class AstLineCounter : CSharpSyntaxVisitor + { + public override LineCounts DefaultVisit(SyntaxNode node) + { + var text = node.SyntaxTree.GetText().GetSubText(node.GetLocation().SourceSpan).ToString(); + return LineCounter.ComputeLineCounts(text); + } + + public override LineCounts VisitMethodDeclaration(MethodDeclarationSyntax method) + { + return Visit(method.Identifier, method.Body ?? (SyntaxNode)method.ExpressionBody); + } + + public static LineCounts Visit(SyntaxToken identifier, SyntaxNode body) + { + var start = identifier.GetLocation().SourceSpan.Start; + var end = body.GetLocation().SourceSpan.End - 1; + + var textSpan = new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start); + + var text = body.SyntaxTree.GetText().GetSubText(textSpan) + "\r\n"; + return LineCounter.ComputeLineCounts(text); + } + + public override LineCounts VisitConstructorDeclaration(ConstructorDeclarationSyntax method) + { + return Visit(method.Identifier, (SyntaxNode)method.Body ?? method.ExpressionBody); + } + + public override LineCounts VisitDestructorDeclaration(DestructorDeclarationSyntax method) + { + return Visit(method.Identifier, (SyntaxNode)method.Body ?? method.ExpressionBody); + } + + public override LineCounts VisitOperatorDeclaration(OperatorDeclarationSyntax node) + { + return Visit(node.OperatorToken, node.Body ?? (SyntaxNode)node.ExpressionBody); + } + } + +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CommentPopulator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CommentPopulator.cs new file mode 100644 index 00000000000..325746274ff --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CommentPopulator.cs @@ -0,0 +1,123 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Semmle.Extraction.CommentProcessing; +using Semmle.Extraction.CSharp.Entities; +using System; + +namespace Semmle.Extraction.CSharp.Populators +{ + /// + /// Populators for comments. + /// + public static class CommentPopulator + { + public static void ExtractCommentBlocks(Context cx, ICommentGenerator gen) + { + cx.Try(null, null, () => + { + gen.GenerateBindings((entity, duplicationGuardKey, block, binding) => + { + var commentBlock = Entities.CommentBlock.Create(cx, block); + Action a = () => + { + commentBlock.BindTo(entity, binding); + }; + // When the duplication guard key exists, it means that the entity is guarded against + // trap duplication (). + // We must therefore also guard comment construction. + if (duplicationGuardKey != null) + cx.WithDuplicationGuard(duplicationGuardKey, a); + else + a(); + }); + }); + } + + public static void ExtractComment(Context cx, SyntaxTrivia trivia) + { + switch (trivia.Kind()) + { + case SyntaxKind.SingleLineDocumentationCommentTrivia: + /* + This is actually a multi-line comment consisting of /// lines. + So split it up. + */ + + var text = trivia.ToFullString(); + + var split = text.Split('\n'); + var currentLocation = trivia.GetLocation().SourceSpan.Start - 3; + + for (var line = 0; line < split.Length - 1; ++line) + { + var fullLine = split[line]; + var nextLineLocation = currentLocation + fullLine.Length + 1; + fullLine = fullLine.TrimEnd('\r'); + var trimmedLine = fullLine; + + var leadingSpaces = trimmedLine.IndexOf('/'); + if (leadingSpaces != -1) + { + fullLine = fullLine.Substring(leadingSpaces); + currentLocation += leadingSpaces; + trimmedLine = trimmedLine.Substring(leadingSpaces + 3); // Remove leading spaces and the "///" + trimmedLine = trimmedLine.Trim(); + + var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(currentLocation, currentLocation + fullLine.Length); + var location = Microsoft.CodeAnalysis.Location.Create(trivia.SyntaxTree, span); + var commentType = CommentLineType.XmlDoc; + cx.CommentGenerator.AddComment(CommentLine.Create(cx, location, commentType, trimmedLine, fullLine)); + } + else + { + cx.ModelError("Unexpected comment format"); + } + currentLocation = nextLineLocation; + } + break; + + case SyntaxKind.SingleLineCommentTrivia: + { + var contents = trivia.ToString().Substring(2); + var commentType = CommentLineType.Singleline; + if (contents.Length > 0 && contents[0] == '/') + { + commentType = CommentLineType.XmlDoc; + contents = contents.Substring(1); // An XML comment. + } + cx.CommentGenerator.AddComment(CommentLine.Create(cx, trivia.GetLocation(), commentType, contents.Trim(), trivia.ToFullString())); + } + break; + case SyntaxKind.MultiLineDocumentationCommentTrivia: + case SyntaxKind.MultiLineCommentTrivia: + /* We receive a single SyntaxTrivia for a multiline block spanning several lines. + So we split it into separate lines + */ + text = trivia.ToFullString(); + + split = text.Split('\n'); + currentLocation = trivia.GetLocation().SourceSpan.Start; + + for (var line = 0; line < split.Length; ++line) + { + var fullLine = split[line]; + var nextLineLocation = currentLocation + fullLine.Length + 1; + fullLine = fullLine.TrimEnd('\r'); + var trimmedLine = fullLine; + if (line == 0) + trimmedLine = trimmedLine.Substring(2); + if (line == split.Length - 1) + trimmedLine = trimmedLine.Substring(0, trimmedLine.Length - 2); + trimmedLine = trimmedLine.Trim(); + + var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(currentLocation, currentLocation + fullLine.Length); + var location = Microsoft.CodeAnalysis.Location.Create(trivia.SyntaxTree, span); + var commentType = line == 0 ? CommentLineType.Multiline : CommentLineType.MultilineContinuation; + cx.CommentGenerator.AddComment(CommentLine.Create(cx, location, commentType, trimmedLine, fullLine)); + currentLocation = nextLineLocation; + } + break; + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Comments.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Comments.cs deleted file mode 100644 index 8f6bb6f5206..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Comments.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Semmle.Extraction.CommentProcessing; -using System; - -namespace Semmle.Extraction.CSharp.Populators -{ - /// - /// Populators for comments. - /// - public static class Comments - { - public static void ExtractComments(this Context cx, ICommentGenerator gen) - { - cx.Try(null, null, () => - { - gen.GenerateBindings((entity, duplicationGuardKey, block, binding) => - { - var commentBlock = Entities.CommentBlock.Create(cx, block); - Action a = () => - { - commentBlock.BindTo(entity, binding); - }; - // When the duplication guard key exists, it means that the entity is guarded against - // trap duplication (). - // We must therefore also guard comment construction. - if (duplicationGuardKey != null) - cx.WithDuplicationGuard(duplicationGuardKey, a); - else - a(); - }); - }); - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnit.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnit.cs deleted file mode 100644 index 69814bf197a..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnit.cs +++ /dev/null @@ -1,150 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Entities; -using Semmle.Extraction.Entities; -using Semmle.Util; -using Semmle.Util.Logging; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace Semmle.Extraction.CSharp.Populators -{ - public class TypeContainerVisitor : CSharpSyntaxVisitor - { - protected Context cx { get; } - protected IEntity parent { get; } - protected TextWriter trapFile { get; } - private readonly Lazy> attributeLookup; - - public TypeContainerVisitor(Context cx, TextWriter trapFile, IEntity parent) - { - this.cx = cx; - this.parent = parent; - this.trapFile = trapFile; - attributeLookup = new Lazy>(() => - { - var dict = new Dictionary(); - foreach (var attributeData in cx.Compilation.Assembly.GetAttributes().Concat(cx.Compilation.Assembly.Modules.SelectMany(m => m.GetAttributes()))) - { - if (attributeData.ApplicationSyntaxReference?.GetSyntax() is SyntaxNode syntax) - dict.Add(syntax, attributeData); - } - return dict.GetValueOrDefault; - }); - } - - public override void DefaultVisit(SyntaxNode node) - { - throw new InternalError(node, "Unhandled top-level syntax node"); - } - - public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) - { - Entities.NamedType.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); - } - - public override void VisitClassDeclaration(ClassDeclarationSyntax classDecl) - { - Entities.Type.Create(cx, cx.GetModel(classDecl).GetDeclaredSymbol(classDecl)).ExtractRecursive(trapFile, parent); - } - - public override void VisitStructDeclaration(StructDeclarationSyntax node) - { - Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); - } - - public override void VisitEnumDeclaration(EnumDeclarationSyntax node) - { - Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); - } - - public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) - { - Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); - } - - public override void VisitAttributeList(AttributeListSyntax node) - { - if (cx.Extractor.Standalone) - return; - - var outputAssembly = Assembly.CreateOutputAssembly(cx); - foreach (var attribute in node.Attributes) - { - if (attributeLookup.Value(attribute) is AttributeData attributeData) - { - var ae = Semmle.Extraction.CSharp.Entities.Attribute.Create(cx, attributeData, outputAssembly); - cx.BindComments(ae, attribute.GetLocation()); - } - } - } - } - - internal class TypeOrNamespaceVisitor : TypeContainerVisitor - { - public TypeOrNamespaceVisitor(Context cx, TextWriter trapFile, IEntity parent) - : base(cx, trapFile, parent) { } - - public override void VisitUsingDirective(UsingDirectiveSyntax usingDirective) - { - // Only deal with "using namespace" not "using X = Y" - if (usingDirective.Alias == null) - new UsingDirective(cx, usingDirective, (NamespaceDeclaration)parent); - } - - public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) - { - NamespaceDeclaration.Create(cx, node, (NamespaceDeclaration)parent); - } - } - - internal class CompilationUnitVisitor : TypeOrNamespaceVisitor - { - public CompilationUnitVisitor(Context cx) - : base(cx, cx.TrapWriter.Writer, null) { } - - public override void VisitExternAliasDirective(ExternAliasDirectiveSyntax node) - { - // This information is not yet extracted. - cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), Extraction.Entities.Location.Create(cx, node.GetLocation()), "", Severity.Info); - } - - public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit) - { - foreach (var m in compilationUnit.ChildNodes()) - { - cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this)); - } - - // Gather comments: - foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span)) - { - CommentLine.Extract(cx, trivia); - } - - foreach (var trivia in compilationUnit.GetLeadingTrivia()) - { - CommentLine.Extract(cx, trivia); - } - - foreach (var trivia in compilationUnit.GetTrailingTrivia()) - { - CommentLine.Extract(cx, trivia); - } - } - } - - public class CompilationUnit - { - public static void Extract(Context cx, SyntaxNode unit) - { - // Ensure that the file itself is populated in case the source file is totally empty - Semmle.Extraction.Entities.File.Create(cx, unit.SyntaxTree.FilePath); - - ((CSharpSyntaxNode)unit).Accept(new CompilationUnitVisitor(cx)); - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs new file mode 100644 index 00000000000..58e5404ccd7 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs @@ -0,0 +1,73 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Util.Logging; +using Semmle.Extraction.CSharp.Entities; +using Semmle.Extraction.CSharp.Entities.Statements; +using System.Linq; + +namespace Semmle.Extraction.CSharp.Populators +{ + internal class CompilationUnitVisitor : TypeOrNamespaceVisitor + { + public CompilationUnitVisitor(Context cx) + : base(cx, cx.TrapWriter.Writer, null) { } + + public override void VisitExternAliasDirective(ExternAliasDirectiveSyntax node) + { + // This information is not yet extracted. + Cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), Cx.CreateLocation(node.GetLocation()), "", Severity.Info); + } + + public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit) + { + foreach (var m in compilationUnit.ChildNodes()) + { + Cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this)); + } + + ExtractGlobalStatements(compilationUnit); + + // Gather comments: + foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span, descendIntoTrivia: true)) + { + CommentPopulator.ExtractComment(Cx, trivia); + } + + foreach (var trivia in compilationUnit.GetLeadingTrivia()) + { + CommentPopulator.ExtractComment(Cx, trivia); + } + + foreach (var trivia in compilationUnit.GetTrailingTrivia()) + { + CommentPopulator.ExtractComment(Cx, trivia); + } + } + + private void ExtractGlobalStatements(CompilationUnitSyntax compilationUnit) + { + var globalStatements = compilationUnit + .ChildNodes() + .OfType() + .ToList(); + + if (!globalStatements.Any()) + { + return; + } + + var entryPoint = Cx.Compilation.GetEntryPoint(System.Threading.CancellationToken.None); + var entryMethod = Method.Create(Cx, entryPoint); + var block = GlobalStatementsBlock.Create(Cx, entryMethod); + + for (var i = 0; i < globalStatements.Count; i++) + { + if (globalStatements[i].Statement is object) + { + Statement.Create(Cx, globalStatements[i].Statement, block, i); + } + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs new file mode 100644 index 00000000000..0c400728554 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Semmle.Extraction.CSharp.Populators +{ + internal class DirectiveVisitor : CSharpSyntaxWalker + { + private readonly Context cx; + + public DirectiveVisitor(Context cx) : base(SyntaxWalkerDepth.StructuredTrivia) + { + this.cx = cx; + } + + public override void VisitPragmaWarningDirectiveTrivia(PragmaWarningDirectiveTriviaSyntax node) + { + new Entities.PragmaWarningDirective(cx, node); + } + + public override void VisitPragmaChecksumDirectiveTrivia(PragmaChecksumDirectiveTriviaSyntax node) + { + new Entities.PragmaChecksumDirective(cx, node); + } + + public override void VisitDefineDirectiveTrivia(DefineDirectiveTriviaSyntax node) + { + new Entities.DefineDirective(cx, node); + } + + public override void VisitUndefDirectiveTrivia(UndefDirectiveTriviaSyntax node) + { + new Entities.UndefineDirective(cx, node); + } + + public override void VisitWarningDirectiveTrivia(WarningDirectiveTriviaSyntax node) + { + new Entities.WarningDirective(cx, node); + } + + public override void VisitErrorDirectiveTrivia(ErrorDirectiveTriviaSyntax node) + { + new Entities.ErrorDirective(cx, node); + } + + public override void VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node) + { + new Entities.NullableDirective(cx, node); + } + + public override void VisitLineDirectiveTrivia(LineDirectiveTriviaSyntax node) + { + new Entities.LineDirective(cx, node); + } + + private readonly Stack regionStarts = new Stack(); + + public override void VisitRegionDirectiveTrivia(RegionDirectiveTriviaSyntax node) + { + var region = new Entities.RegionDirective(cx, node); + regionStarts.Push(region); + } + + public override void VisitEndRegionDirectiveTrivia(EndRegionDirectiveTriviaSyntax node) + { + if (regionStarts.Count == 0) + { + cx.ExtractionError("Couldn't find start region", null, + cx.CreateLocation(node.GetLocation()), null, Util.Logging.Severity.Warning); + return; + } + + var start = regionStarts.Pop(); + new Entities.EndRegionDirective(cx, node, start); + } + + private class IfDirectiveStackElement + { + public Entities.IfDirective Entity { get; } + public int SiblingCount { get; set; } + + + public IfDirectiveStackElement(Entities.IfDirective entity) + { + Entity = entity; + } + } + + private readonly Stack ifStarts = new Stack(); + + public override void VisitIfDirectiveTrivia(IfDirectiveTriviaSyntax node) + { + var ifStart = new Entities.IfDirective(cx, node); + ifStarts.Push(new IfDirectiveStackElement(ifStart)); + } + + public override void VisitEndIfDirectiveTrivia(EndIfDirectiveTriviaSyntax node) + { + if (ifStarts.Count == 0) + { + cx.ExtractionError("Couldn't find start if", null, + cx.CreateLocation(node.GetLocation()), null, Util.Logging.Severity.Warning); + return; + } + + var start = ifStarts.Pop(); + new Entities.EndIfDirective(cx, node, start.Entity); + } + + public override void VisitElifDirectiveTrivia(ElifDirectiveTriviaSyntax node) + { + if (ifStarts.Count == 0) + { + cx.ExtractionError("Couldn't find start if", null, + cx.CreateLocation(node.GetLocation()), null, Util.Logging.Severity.Warning); + return; + } + + var start = ifStarts.Peek(); + new Entities.ElifDirective(cx, node, start.Entity, start.SiblingCount++); + } + + public override void VisitElseDirectiveTrivia(ElseDirectiveTriviaSyntax node) + { + if (ifStarts.Count == 0) + { + cx.ExtractionError("Couldn't find start if", null, + cx.CreateLocation(node.GetLocation()), null, Util.Logging.Severity.Warning); + return; + } + + var start = ifStarts.Peek(); + new Entities.ElseDirective(cx, node, start.Entity, start.SiblingCount++); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs deleted file mode 100644 index 148160b8815..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Util; -using System.IO; - -namespace Semmle.Extraction.CSharp.Populators -{ - public static class MethodExtensions - { - private class AstLineCounter : CSharpSyntaxVisitor - { - public override LineCounts DefaultVisit(SyntaxNode node) - { - var text = node.SyntaxTree.GetText().GetSubText(node.GetLocation().SourceSpan).ToString(); - return Semmle.Util.LineCounter.ComputeLineCounts(text); - } - - public override LineCounts VisitMethodDeclaration(MethodDeclarationSyntax method) - { - return Visit(method.Identifier, method.Body ?? (SyntaxNode)method.ExpressionBody); - } - - public static LineCounts Visit(SyntaxToken identifier, SyntaxNode body) - { - var start = identifier.GetLocation().SourceSpan.Start; - var end = body.GetLocation().SourceSpan.End - 1; - - var textSpan = new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start); - - var text = body.SyntaxTree.GetText().GetSubText(textSpan) + "\r\n"; - return Semmle.Util.LineCounter.ComputeLineCounts(text); - } - - public override LineCounts VisitConstructorDeclaration(ConstructorDeclarationSyntax method) - { - return Visit(method.Identifier, (SyntaxNode)method.Body ?? method.ExpressionBody); - } - - public override LineCounts VisitDestructorDeclaration(DestructorDeclarationSyntax method) - { - return Visit(method.Identifier, (SyntaxNode)method.Body ?? method.ExpressionBody); - } - - public override LineCounts VisitOperatorDeclaration(OperatorDeclarationSyntax node) - { - return Visit(node.OperatorToken, node.Body ?? (SyntaxNode)node.ExpressionBody); - } - } - - public static void NumberOfLines(this Context cx, TextWriter trapFile, ISymbol symbol, IEntity callable) - { - foreach (var decl in symbol.DeclaringSyntaxReferences) - { - cx.NumberOfLines(trapFile, (CSharpSyntaxNode)decl.GetSyntax(), callable); - } - } - - public static void NumberOfLines(this Context cx, TextWriter trapFile, CSharpSyntaxNode node, IEntity callable) - { - var lineCounts = node.Accept(new AstLineCounter()); - trapFile.numlines(callable, lineCounts); - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs new file mode 100644 index 00000000000..ededf2978b9 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs @@ -0,0 +1,99 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.Entities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Semmle.Extraction.CSharp.Populators +{ + public class TypeContainerVisitor : CSharpSyntaxVisitor + { + protected Context Cx { get; } + protected IEntity Parent { get; } + protected TextWriter TrapFile { get; } + private readonly Lazy> attributeLookup; + + public TypeContainerVisitor(Context cx, TextWriter trapFile, IEntity parent) + { + Cx = cx; + Parent = parent; + TrapFile = trapFile; + + attributeLookup = new Lazy>(() => + { + var dict = new Dictionary(); + foreach (var attributeData in cx.Compilation.Assembly.GetAttributes().Concat(cx.Compilation.Assembly.Modules.SelectMany(m => m.GetAttributes()))) + { + if (attributeData.ApplicationSyntaxReference?.GetSyntax() is SyntaxNode syntax) + dict.Add(syntax, attributeData); + } + return dict.GetValueOrDefault; + }); + } + + public override void DefaultVisit(SyntaxNode node) + { + throw new InternalError(node, "Unhandled top-level syntax node"); + } + + public override void VisitGlobalStatement(GlobalStatementSyntax node) + { + // Intentionally left empty. + // Global statements are handled in CompilationUnitVisitor + } + + public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) + { + Entities.NamedType.Create(Cx, Cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(TrapFile, Parent); + } + + public override void VisitRecordDeclaration(RecordDeclarationSyntax node) + { + ExtractTypeDeclaration(node); + } + + public override void VisitClassDeclaration(ClassDeclarationSyntax node) + { + ExtractTypeDeclaration(node); + } + + public override void VisitStructDeclaration(StructDeclarationSyntax node) + { + ExtractTypeDeclaration(node); + } + + public override void VisitEnumDeclaration(EnumDeclarationSyntax node) + { + ExtractTypeDeclaration(node); + } + + public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) + { + ExtractTypeDeclaration(node); + } + + private void ExtractTypeDeclaration(BaseTypeDeclarationSyntax node) + { + Entities.Type.Create(Cx, Cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(TrapFile, Parent); + } + + public override void VisitAttributeList(AttributeListSyntax node) + { + if (Cx.Extractor.Standalone) + return; + + var outputAssembly = Assembly.CreateOutputAssembly(Cx); + foreach (var attribute in node.Attributes) + { + if (attributeLookup.Value(attribute) is AttributeData attributeData) + { + var ae = Entities.Attribute.Create(Cx, attributeData, outputAssembly); + Cx.BindComments(ae, attribute.GetLocation()); + } + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs new file mode 100644 index 00000000000..a3daae08a60 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs @@ -0,0 +1,24 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.CSharp.Entities; +using System.IO; + +namespace Semmle.Extraction.CSharp.Populators +{ + internal class TypeOrNamespaceVisitor : TypeContainerVisitor + { + public TypeOrNamespaceVisitor(Context cx, TextWriter trapFile, IEntity parent) + : base(cx, trapFile, parent) { } + + public override void VisitUsingDirective(UsingDirectiveSyntax usingDirective) + { + // Only deal with "using namespace" not "using X = Y" + if (usingDirective.Alias == null) + new UsingDirective(Cx, usingDirective, (NamespaceDeclaration)Parent); + } + + public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) + { + NamespaceDeclaration.Create(Cx, node, (NamespaceDeclaration)Parent); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 630c2848e3d..df39d6a836c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -1,5 +1,7 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CommentProcessing; using Semmle.Extraction.CSharp.Entities; +using Semmle.Extraction.CSharp.Entities.Expressions; using Semmle.Extraction.Entities; using Semmle.Extraction.Kinds; using Semmle.Util; @@ -51,6 +53,17 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("catch_type", @catch, type, explicityCaught ? 1 : 2); } + internal static void foreach_stmt_info(this TextWriter trapFile, Entities.Statements.ForEach @foreach, bool isAsync) + { + trapFile.WriteTuple("foreach_stmt_info", @foreach, isAsync ? 2 : 1); + } + + internal static void foreach_stmt_desugar(this TextWriter trapFile, Entities.Statements.ForEach @foreach, IEntity entity, + Entities.Statements.ForEach.ForeachSymbolType type) + { + trapFile.WriteTuple("foreach_stmt_desugar", @foreach, entity, (int)type); + } + internal static void commentblock(this TextWriter trapFile, CommentBlock k) { trapFile.WriteTuple("commentblock", k); @@ -590,5 +603,123 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("using_static_directives", @using, type); } + + internal static void preprocessor_directive_location(this TextWriter trapFile, + PreprocessorDirective directive, Location location) + where TDirective : DirectiveTriviaSyntax + { + trapFile.WriteTuple("preprocessor_directive_location", directive, location); + } + + internal static void preprocessor_directive_compilation(this TextWriter trapFile, + PreprocessorDirective directive, Compilation compilation) + where TDirective : DirectiveTriviaSyntax + { + trapFile.WriteTuple("preprocessor_directive_compilation", directive, compilation); + } + + internal static void preprocessor_directive_active(this TextWriter trapFile, + PreprocessorDirective directive, bool isActive) + where TDirective : DirectiveTriviaSyntax + { + trapFile.WriteTuple("preprocessor_directive_active", directive, isActive ? 1 : 0); + } + + internal static void pragma_warnings(this TextWriter trapFile, PragmaWarningDirective pragma, int kind) + { + trapFile.WriteTuple("pragma_warnings", pragma, kind); + } + + internal static void pragma_warning_error_codes(this TextWriter trapFile, PragmaWarningDirective pragma, string errorCode, int child) + { + trapFile.WriteTuple("pragma_warning_error_codes", pragma, errorCode, child); + } + + internal static void pragma_checksums(this TextWriter trapFile, PragmaChecksumDirective pragma, Extraction.Entities.File file, string guid, string bytes) + { + trapFile.WriteTuple("pragma_checksums", pragma, file, guid, bytes); + } + + internal static void directive_defines(this TextWriter trapFile, DefineDirective directive, string name) + { + trapFile.WriteTuple("directive_defines", directive, name); + } + + internal static void directive_undefines(this TextWriter trapFile, UndefineDirective directive, string name) + { + trapFile.WriteTuple("directive_undefines", directive, name); + } + + internal static void directive_warnings(this TextWriter trapFile, WarningDirective directive, string message) + { + trapFile.WriteTuple("directive_warnings", directive, message); + } + + internal static void directive_errors(this TextWriter trapFile, ErrorDirective directive, string message) + { + trapFile.WriteTuple("directive_errors", directive, message); + } + + internal static void directive_nullables(this TextWriter trapFile, NullableDirective directive, int setting, int target) + { + trapFile.WriteTuple("directive_nullables", directive, setting, target); + } + + internal static void directive_lines(this TextWriter trapFile, LineDirective directive, int kind) + { + trapFile.WriteTuple("directive_lines", directive, kind); + } + + internal static void directive_line_value(this TextWriter trapFile, LineDirective directive, int line) + { + trapFile.WriteTuple("directive_line_value", directive, line); + } + + internal static void directive_line_file(this TextWriter trapFile, LineDirective directive, Extraction.Entities.File file) + { + trapFile.WriteTuple("directive_line_file", directive, file); + } + + internal static void directive_regions(this TextWriter trapFile, RegionDirective directive, string name) + { + trapFile.WriteTuple("directive_regions", directive, name); + } + + internal static void directive_endregions(this TextWriter trapFile, EndRegionDirective directive, RegionDirective start) + { + trapFile.WriteTuple("directive_endregions", directive, start); + } + + internal static void regions(this TextWriter trapFile, RegionDirective start, EndRegionDirective end) + { + trapFile.WriteTuple("regions", start, end); + } + + internal static void directive_ifs(this TextWriter trapFile, IfDirective directive, bool branchTaken, bool conditionValue) + { + trapFile.WriteTuple("directive_ifs", directive, branchTaken ? 1 : 0, conditionValue ? 1 : 0); + } + + internal static void directive_elifs(this TextWriter trapFile, ElifDirective directive, bool branchTaken, bool conditionValue, + IfDirective start, int index) + { + trapFile.WriteTuple("directive_elifs", directive, branchTaken ? 1 : 0, conditionValue ? 1 : 0, start, index); + } + + internal static void directive_elses(this TextWriter trapFile, ElseDirective directive, bool branchTaken, + IfDirective start, int index) + { + trapFile.WriteTuple("directive_elses", directive, branchTaken ? 1 : 0, start, index); + } + + internal static void directive_endifs(this TextWriter trapFile, EndIfDirective directive, IfDirective start) + { + trapFile.WriteTuple("directive_endifs", directive, start); + } + + internal static void directive_define_symbols(this TextWriter trapFile, DefineSymbol symb, string name) + { + trapFile.WriteTuple("directive_define_symbols", symb, name); + } } } diff --git a/csharp/extractor/Semmle.Extraction/AssemblyScope.cs b/csharp/extractor/Semmle.Extraction/AssemblyScope.cs index 84c117d17c4..27c9377bb30 100644 --- a/csharp/extractor/Semmle.Extraction/AssemblyScope.cs +++ b/csharp/extractor/Semmle.Extraction/AssemblyScope.cs @@ -21,7 +21,5 @@ namespace Semmle.Extraction public bool InScope(ISymbol symbol) => SymbolEqualityComparer.Default.Equals(symbol.ContainingAssembly, assembly) || SymbolEqualityComparer.Default.Equals(symbol, assembly); - - public bool FromSource => false; } } diff --git a/csharp/extractor/Semmle.Extraction/CommentProcessing.cs b/csharp/extractor/Semmle.Extraction/CommentProcessing.cs index f407f5703fe..201ac705136 100644 --- a/csharp/extractor/Semmle.Extraction/CommentProcessing.cs +++ b/csharp/extractor/Semmle.Extraction/CommentProcessing.cs @@ -53,7 +53,7 @@ namespace Semmle.Extraction.CommentProcessing if (l2 == null) return 1; - var diff = l1.SourceTree == l2.SourceTree ? 0 : l1.SourceTree.FilePath.CompareTo(l2.SourceTree.FilePath); + var diff = l1.SourceTree == l2.SourceTree ? 0 : l1.SourceTree!.FilePath.CompareTo(l2.SourceTree!.FilePath); if (diff != 0) return diff; diff = l1.SourceSpan.Start - l2.SourceSpan.Start; @@ -384,9 +384,12 @@ namespace Semmle.Extraction.CommentProcessing /// The line to add. public void AddCommentLine(ICommentLine line) { - Location = !lines.Any() ? - line.Location : - Location.Create(line.Location.SourceTree, new TextSpan(Location.SourceSpan.Start, line.Location.SourceSpan.End - Location.SourceSpan.Start)); + Location = !lines.Any() + ? line.Location + : Location.Create( + line.Location.SourceTree!, + new TextSpan(Location.SourceSpan.Start, line.Location.SourceSpan.End - Location.SourceSpan.Start)); + lines.Add(line); } } diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index cbb68e1a936..a4b84d5d047 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction /// /// Access various extraction functions, e.g. logger, trap writer. /// - public IExtractor Extractor { get; } + public Extractor Extractor { get; } /// /// The program database provided by Roslyn. @@ -51,7 +51,7 @@ namespace Semmle.Extraction // A recursion guard against writing to the trap file whilst writing an id to the trap file. private bool writingLabel = false; - public void DefineLabel(IEntity entity, TextWriter trapFile, IExtractor extractor) + public void DefineLabel(IEntity entity, TextWriter trapFile, Extractor extractor) { if (writingLabel) { @@ -73,11 +73,11 @@ namespace Semmle.Extraction } #if DEBUG_LABELS - private void CheckEntityHasUniqueLabel(string id, ICachedEntity entity) + private void CheckEntityHasUniqueLabel(string id, CachedEntity entity) { if (idLabelCache.ContainsKey(id)) { - this.Extractor.Message(new Message("Label collision for " + id, entity.Label.ToString(), Entities.Location.Create(this, entity.ReportingLocation), "", Severity.Warning)); + this.Extractor.Message(new Message("Label collision for " + id, entity.Label.ToString(), CreateLocation(entity.ReportingLocation), "", Severity.Warning)); } else { @@ -89,12 +89,12 @@ namespace Semmle.Extraction public Label GetNewLabel() => new Label(GetNewId()); public TEntity CreateEntity(ICachedEntityFactory factory, object cacheKey, TInit init) - where TEntity : ICachedEntity => + where TEntity : CachedEntity => cacheKey is ISymbol s ? CreateEntity(factory, s, init, symbolEntityCache) : CreateEntity(factory, cacheKey, init, objectEntityCache); public TEntity CreateEntityFromSymbol(ICachedEntityFactory factory, TSymbol init) where TSymbol : ISymbol - where TEntity : ICachedEntity => CreateEntity(factory, init, init, symbolEntityCache); + where TEntity : CachedEntity => CreateEntity(factory, init, init, symbolEntityCache); /// /// Creates and populates a new entity, or returns the existing one from the cache. @@ -104,9 +104,9 @@ namespace Semmle.Extraction /// The initializer for the entity. /// The dictionary to use for caching. /// The new/existing entity. - private TEntity CreateEntity(ICachedEntityFactory factory, TCacheKey cacheKey, TInit init, IDictionary dictionary) + private TEntity CreateEntity(ICachedEntityFactory factory, TCacheKey cacheKey, TInit init, IDictionary dictionary) where TCacheKey : notnull - where TEntity : ICachedEntity + where TEntity : CachedEntity { if (dictionary.TryGetValue(cacheKey, out var cached)) return (TEntity)cached; @@ -143,7 +143,7 @@ namespace Semmle.Extraction /// /// The entity to extract. /// True only on the first call for a particular entity. - public bool ExtractGenerics(ICachedEntity entity) + public bool ExtractGenerics(CachedEntity entity) { if (extractedGenerics.Contains(entity.Label)) { @@ -158,18 +158,18 @@ namespace Semmle.Extraction /// Creates a fresh label with ID "*", and set it on the /// supplied object. /// - public void AddFreshLabel(IEntity entity) + public void AddFreshLabel(Entity entity) { entity.Label = GetNewLabel(); entity.DefineFreshLabel(TrapWriter.Writer); } #if DEBUG_LABELS - private readonly Dictionary idLabelCache = new Dictionary(); + private readonly Dictionary idLabelCache = new Dictionary(); #endif - private readonly IDictionary objectEntityCache = new Dictionary(); - private readonly IDictionary symbolEntityCache = new Dictionary(10000, SymbolEqualityComparer.Default); + private readonly IDictionary objectEntityCache = new Dictionary(); + private readonly IDictionary symbolEntityCache = new Dictionary(10000, SymbolEqualityComparer.Default); private readonly HashSet