diff --git a/.gitignore b/.gitignore index b14dab0a6b1..0951496d45c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ # Byte-compiled python files *.pyc +# python virtual environment folder +.venv/ + # It's useful (though not required) to be able to unpack codeql in the ql checkout itself /codeql/ diff --git a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql index de786d22f30..5ed84f45250 100644 --- a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql +++ b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql @@ -27,6 +27,10 @@ class Configuration extends TaintTrackingConfiguration { override predicate isSink(Element tainted) { exists(SQLLikeFunction runSql | runSql.outermostWrapperFunctionCall(tainted, _)) } + + override predicate isBarrier(Expr e) { + super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType + } } from diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.c b/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.c new file mode 100644 index 00000000000..14dd07a573e --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.c @@ -0,0 +1,35 @@ +// BAD: the memset call will probably be removed. +void getPassword(void) { + char pwd[64]; + if (GetPassword(pwd, sizeof(pwd))) { + /* Checking of password, secure operations, etc. */ + } + memset(pwd, 0, sizeof(pwd)); +} +// GOOD: in this case the memset will not be removed. +void getPassword(void) { + char pwd[64]; + + if (retrievePassword(pwd, sizeof(pwd))) { + /* Checking of password, secure operations, etc. */ + } + memset_s(pwd, 0, sizeof(pwd)); +} +// GOOD: in this case the memset will not be removed. +void getPassword(void) { + char pwd[64]; + if (retrievePassword(pwd, sizeof(pwd))) { + /* Checking of password, secure operations, etc. */ + } + SecureZeroMemory(pwd, sizeof(pwd)); +} +// GOOD: in this case the memset will not be removed. +void getPassword(void) { + char pwd[64]; + if (retrievePassword(pwd, sizeof(pwd))) { + /* Checking of password, secure operations, etc. */ + } +#pragma optimize("", off) + memset(pwd, 0, sizeof(pwd)); +#pragma optimize("", on) +} diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.qhelp new file mode 100644 index 00000000000..df0ed151d8f --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.qhelp @@ -0,0 +1,31 @@ + + + +

Compiler optimization will exclude the cleaning of private information. +Using the memset function to clear private data in a variable that has no subsequent use is potentially dangerous, since the compiler can remove the call. +For some compilers, optimization is also possible when using calls to free memory after the memset function.

+ +

It is possible to miss detection of vulnerabilities if used to clear fields of structures or parts of a buffer.

+ +
+ + +

We recommend to use the RtlSecureZeroMemory or memset_s functions, or compilation flags that exclude optimization of memset calls (e.g. -fno-builtin-memset).

+ +
+ +

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

+ + +
+ + +
  • + CERT C Coding Standard: + MSC06-C. Beware of compiler optimizations. +
  • + +
    +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql b/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql new file mode 100644 index 00000000000..db09de9430d --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql @@ -0,0 +1,127 @@ +/** + * @name Compiler Removal Of Code To Clear Buffers + * @description Using memset the function to clear private data in a variable that has no subsequent use + * is potentially dangerous because the compiler can remove the call. + * @kind problem + * @id cpp/compiler-removal-of-code-to-clear-buffers + * @problem.severity warning + * @precision medium + * @tags security + * external/cwe/cwe-14 + */ + +import cpp +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.StackAddress + +/** + * A call to `memset` of the form `memset(ptr, value, num)`, for some local variable `ptr`. + */ +class CompilerRemovaMemset extends FunctionCall { + CompilerRemovaMemset() { + this.getTarget().hasGlobalOrStdName("memset") and + exists(DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, Expr exp | + DataFlow::localFlow(source, sink) and + this.getArgument(0) = isv.getAnAccess() and + ( + source.asExpr() = exp + or + // handle the case where exp is defined by an address being passed into some function. + source.asDefiningArgument() = exp + ) and + exp.getLocation().getEndLine() < this.getArgument(0).getLocation().getStartLine() and + sink.asExpr() = this.getArgument(0) + ) + } + + predicate isExistsAllocForThisVariable() { + exists(AllocationExpr alloc, Variable v | + alloc = v.getAnAssignedValue() and + this.getArgument(0) = v.getAnAccess() and + alloc.getASuccessor+() = this + ) + or + not stackPointerFlowsToUse(this.getArgument(0), _, _, _) + } + + predicate isExistsFreeForThisVariable() { + exists(DeallocationExpr free, Variable v | + this.getArgument(0) = v.getAnAccess() and + free.getFreedExpr() = v.getAnAccess() and + this.getASuccessor+() = free + ) + } + + predicate isExistsCallWithThisVariableExcludingDeallocationCalls() { + exists(FunctionCall fc, Variable v | + not fc instanceof DeallocationExpr and + this.getArgument(0) = v.getAnAccess() and + fc.getAnArgument() = v.getAnAccess() and + this.getASuccessor+() = fc + ) + } + + predicate isVariableUseAfterMemsetExcludingCalls() { + exists(DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, Expr exp | + DataFlow::localFlow(source, sink) and + this.getArgument(0) = isv.getAnAccess() and + source.asExpr() = isv.getAnAccess() and + exp.getLocation().getStartLine() > this.getArgument(2).getLocation().getEndLine() and + not exp.getParent() instanceof FunctionCall and + sink.asExpr() = exp + ) + } + + predicate isVariableUseBoundWithArgumentFunction() { + exists(DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, Parameter p, Expr exp | + DataFlow::localFlow(source, sink) and + this.getArgument(0) = isv.getAnAccess() and + this.getEnclosingFunction().getAParameter() = p and + exp.getAChild*() = p.getAnAccess() and + source.asExpr() = exp and + sink.asExpr() = isv.getAnAccess() + ) + } + + predicate isVariableUseBoundWithGlobalVariable() { + exists( + DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, GlobalVariable gv, Expr exp + | + DataFlow::localFlow(source, sink) and + this.getArgument(0) = isv.getAnAccess() and + exp.getAChild*() = gv.getAnAccess() and + source.asExpr() = exp and + sink.asExpr() = isv.getAnAccess() + ) + } + + predicate isExistsCompilationFlagsBlockingRemoval() { + exists(Compilation c | + c.getAFileCompiled() = this.getFile() and + c.getAnArgument() = "-fno-builtin-memset" + ) + } + + predicate isUseVCCompilation() { + exists(Compilation c | + c.getAFileCompiled() = this.getFile() and + ( + c.getArgument(2).matches("%gcc%") or + c.getArgument(2).matches("%g++%") or + c.getArgument(2).matches("%clang%") or + c.getArgument(2) = "--force-recompute" + ) + ) + } +} + +from CompilerRemovaMemset fc +where + not (fc.isExistsAllocForThisVariable() and not fc.isExistsFreeForThisVariable()) and + not (fc.isExistsFreeForThisVariable() and not fc.isUseVCCompilation()) and + not fc.isVariableUseAfterMemsetExcludingCalls() and + not fc.isExistsCallWithThisVariableExcludingDeallocationCalls() and + not fc.isVariableUseBoundWithArgumentFunction() and + not fc.isVariableUseBoundWithGlobalVariable() and + not fc.isExistsCompilationFlagsBlockingRemoval() +select fc.getArgument(0), "This variable will not be cleared." diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql b/cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql index 60b13525aff..205f17c06c9 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql @@ -16,6 +16,6 @@ import DataFlow::PathGraph from WriteConfig b, DataFlow::PathNode source, DataFlow::PathNode sink where b.hasFlowPath(source, sink) -select sink.getNode(), - "This write into the external location '" + sink + "' may contain unencrypted data from $@", - source, "this source." +select sink.getNode(), source, sink, + "This write into the external location '" + sink.getNode() + + "' may contain unencrypted data from $@", source, "this source." diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-401/MemoryLeakOnFailedCallToRealloc.ql b/cpp/ql/src/experimental/Security/CWE/CWE-401/MemoryLeakOnFailedCallToRealloc.ql index da54d9a49bf..1578bff1407 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-401/MemoryLeakOnFailedCallToRealloc.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-401/MemoryLeakOnFailedCallToRealloc.ql @@ -12,6 +12,20 @@ */ import cpp +import semmle.code.cpp.controlflow.Guards + +/** + * A function call that potentially does not return (such as `exit`). + */ +class CallMayNotReturn extends FunctionCall { + CallMayNotReturn() { + // call that is known to not return + not exists(this.(ControlFlowNode).getASuccessor()) + or + // call to another function that may not return + exists(CallMayNotReturn exit | getTarget() = exit.getEnclosingFunction()) + } +} /** * A call to `realloc` of the form `v = realloc(v, size)`, for some variable `v`. @@ -30,40 +44,19 @@ class ReallocCallLeak extends FunctionCall { ) } - predicate isExistsIfWithExitCall() { - exists(IfStmt ifc | - this.getArgument(0) = v.getAnAccess() and - ifc.getCondition().getAChild*() = v.getAnAccess() and - ifc.getEnclosingFunction() = this.getEnclosingFunction() and - ifc.getLocation().getStartLine() >= this.getArgument(0).getLocation().getStartLine() and - exists(FunctionCall fc | - fc.getTarget().hasName("exit") and - fc.getEnclosingFunction() = this.getEnclosingFunction() and - (ifc.getThen().getAChild*() = fc or ifc.getElse().getAChild*() = fc) - ) - or - exists(FunctionCall fc, FunctionCall ftmp1, FunctionCall ftmp2 | - ftmp1.getTarget().hasName("exit") and - ftmp2.(ControlFlowNode).getASuccessor*() = ftmp1 and - fc = ftmp2.getEnclosingFunction().getACallToThisFunction() and - fc.getEnclosingFunction() = this.getEnclosingFunction() and - (ifc.getThen().getAChild*() = fc or ifc.getElse().getAChild*() = fc) - ) - ) - } - - predicate isExistsAssertWithArgumentCall() { - exists(FunctionCall fc | - fc.getTarget().hasName("__assert_fail") and - this.getEnclosingFunction() = fc.getEnclosingFunction() and - fc.getLocation().getStartLine() > this.getArgument(0).getLocation().getEndLine() and - fc.getArgument(0).toString().matches("%" + this.getArgument(0).toString() + "%") + /** + * Holds if failure of this allocation may be handled by termination, for + * example a call to `exit()`. + */ + predicate mayHandleByTermination() { + exists(GuardCondition guard, CallMayNotReturn exit | + this.(ControlFlowNode).getASuccessor*() = guard and + guard.getAChild*() = v.getAnAccess() and + guard.controls(exit.getBasicBlock(), _) ) } } from ReallocCallLeak rcl -where - not rcl.isExistsIfWithExitCall() and - not rcl.isExistsAssertWithArgumentCall() +where not rcl.mayHandleByTermination() select rcl, "possible loss of original pointer on unsuccessful call realloc" diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.c b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.c new file mode 100644 index 00000000000..060a22b5c18 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.c @@ -0,0 +1,4 @@ + +strncat(dest, source, sizeof(dest) - strlen(dest)); // BAD: writes a zero byte past the `dest` buffer. + +strncat(dest, source, sizeof(dest) - strlen(dest) -1); // GOOD: Reserves space for the zero byte. diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.qhelp new file mode 100644 index 00000000000..5c2154097ec --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.qhelp @@ -0,0 +1,32 @@ + + + +

    The standard library function strncat(dest, source, count) appends the source string to the dest string. count specifies the maximum number of characters to append and must be less than the remaining space in the target buffer. Calls of the form strncat (dest, source, sizeof (dest) - strlen (dest)) set the third argument to one more than possible. So when the dest is full, the expression sizeof (dest) - strlen (dest) will be equal to one, and not zero as the programmer might think. Making a call of this type may result in a zero byte being written just outside the dest buffer.

    + + +
    + + +

    We recommend subtracting one from the third argument. For example, replace strncat(dest, source, sizeof(dest)-strlen(dest)) with strncat(dest, source, sizeof(dest)-strlen(dest)-1).

    + +
    + +

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

    + + +
    + + +
  • + CERT C Coding Standard: +STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator. +
  • +
  • + CERT C Coding Standard: + ARR30-C. Do not form or use out-of-bounds pointers or array subscripts. +
  • + +
    +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.ql b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.ql new file mode 100644 index 00000000000..5311ffe2708 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.ql @@ -0,0 +1,64 @@ +/** + * @name Access Of Memory Location After The End Of A Buffer Using Strncat + * @description Calls of the form `strncat(dest, source, sizeof (dest) - strlen (dest))` set the third argument to one more than possible. So when `dest` is full, the expression `sizeof(dest) - strlen (dest)` will be equal to one, and not zero as the programmer might think. Making a call of this type may result in a zero byte being written just outside the `dest` buffer. + * @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 + +/** + * A call to `strncat` of the form `strncat(buff, str, someExpr - strlen(buf))`, for some expression `someExpr` equal to `sizeof(buff)`. + */ +class WrongCallStrncat extends FunctionCall { + Expr leftsomeExpr; + + WrongCallStrncat() { + this.getTarget().hasGlobalOrStdName("strncat") and + // the expression of the first argument in `strncat` and `strnlen` is identical + globalValueNumber(this.getArgument(0)) = + globalValueNumber(this.getArgument(2).(SubExpr).getRightOperand().(StrlenCall).getStringExpr()) and + // using a string constant often speaks of manually calculating the length of the required buffer. + ( + not this.getArgument(1) instanceof StringLiteral and + not this.getArgument(1) instanceof CharLiteral + ) and + // for use in predicates + leftsomeExpr = this.getArgument(2).(SubExpr).getLeftOperand() + } + + /** + * Holds if the left side of the expression `someExpr` equal to `sizeof(buf)`. + */ + predicate isExpressionEqualSizeof() { + // the left side of the expression `someExpr` is `sizeof(buf)`. + globalValueNumber(this.getArgument(0)) = + globalValueNumber(leftsomeExpr.(SizeofExprOperator).getExprOperand()) + or + // value of the left side of the expression `someExpr` equal `sizeof(buf)` value, and `buf` is array. + leftsomeExpr.getValue().toInt() = this.getArgument(0).getType().getSize() + } + + /** + * Holds if the left side of the expression `someExpr` equal to variable containing the length of the memory allocated for the buffer. + */ + predicate isVariableEqualValueSizegBuffer() { + // the left side of expression `someExpr` is the variable that was used in the function of allocating memory for the buffer`. + exists(AllocationExpr alc | + leftsomeExpr.(VariableAccess).getTarget() = + alc.(FunctionCall).getArgument(0).(VariableAccess).getTarget() + ) + } +} + +from WrongCallStrncat sc +where + sc.isExpressionEqualSizeof() or + sc.isVariableEqualValueSizegBuffer() +select sc, "if the used buffer is full, writing out of the buffer is possible" diff --git a/cpp/ql/src/semmle/code/cpp/Comments.qll b/cpp/ql/src/semmle/code/cpp/Comments.qll index 65e2af5fd22..7574f0ff32c 100644 --- a/cpp/ql/src/semmle/code/cpp/Comments.qll +++ b/cpp/ql/src/semmle/code/cpp/Comments.qll @@ -50,5 +50,5 @@ class CStyleComment extends Comment { * ``` */ class CppStyleComment extends Comment { - CppStyleComment() { this.getContents().prefix(2) = "//" } + CppStyleComment() { this.getContents().matches("//%") } } diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 560ddfbd4c8..4ddf852f49f 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -334,6 +334,18 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { ) } + /** + * Gets the class of which this function, called `memberName`, is a member. + * + * Prefer to use `getDeclaringType()` or `getName()` directly if you do not + * need to reason about both. + */ + pragma[nomagic] + Class getClassAndName(string memberName) { + this.hasName(memberName) and + this.getDeclaringType() = result + } + /** * Implements `ControlFlowNode.getControlFlowScope`. The `Function` is * used to represent the exit node of the control flow graph, so it is diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index 81b28cca4c9..a0d8c42df32 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -274,7 +274,7 @@ class Type extends Locatable, @type { /** * Gets this type with any typedefs resolved. For example, given - * `typedef C T`, this would resolve `const T&` to `const C&`. + * `typedef C T`, this would resolve `const T&` to `const C&`. * Note that this will only work if the resolved type actually appears * on its own elsewhere in the program. */ @@ -1544,9 +1544,9 @@ class FunctionPointerIshType extends DerivedType { /** * A C++ pointer to data member. See 15.5. * ``` - * class C { int m; }; + * class C { public: int m; }; * int C::* p = &C::m; // pointer to data member m of class C - * class C *; + * class C c; * int val = c.*p; // access data member * ``` */ diff --git a/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll b/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll index c7641385393..92955ae3580 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll @@ -87,7 +87,7 @@ abstract class MutexType extends Type { private Function mustlockCandidate() { exists(string name | name = result.getName() | name = "lock" or - name.suffix(name.length() - 10) = "mutex_lock" + name.matches("%mutex\\_lock") ) } @@ -97,7 +97,7 @@ private Function mustlockCandidate() { private Function trylockCandidate() { exists(string name | name = result.getName() | name = "try_lock" or - name.suffix(name.length() - 13) = "mutex_trylock" + name.matches("%mutex\\_trylock") ) } @@ -107,7 +107,7 @@ private Function trylockCandidate() { private Function unlockCandidate() { exists(string name | name = result.getName() | name = "unlock" or - name.suffix(name.length() - 12) = "mutex_unlock" + name.matches("%mutex\\_unlock") ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index 5154f5c3239..7ca03067d0a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -545,6 +545,9 @@ module TaintedWithPath { /** Override this to specify which elements are sinks in this configuration. */ abstract predicate isSink(Element e); + /** Override this to specify which expressions are barriers in this configuration. */ + predicate isBarrier(Expr e) { nodeIsBarrier(getNodeForExpr(e)) } + /** * Override this predicate to `any()` to allow taint to flow through global * variables. @@ -578,7 +581,9 @@ module TaintedWithPath { ) } - override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) } + override predicate isBarrier(DataFlow::Node node) { + exists(TaintTrackingConfiguration cfg, Expr e | cfg.isBarrier(e) and node = getNodeForExpr(e)) + } override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) } } 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 762ce8d47b4..68b31a732f4 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,6 +2,7 @@ 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 @@ -209,6 +210,13 @@ 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 { @@ -221,69 +229,101 @@ private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array content" } } -private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) { - exists(StoreInstruction store, Class c | - store = node2.asInstruction() and +/** + * 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 store.getSourceValueOperand() = node1.asOperand() and - getWrittenField(store, f.(FieldContent).getAField(), c) and - f.hasOffset(c, _, _) + f.getADirectField() = pd.getPreUpdateNode().getField() ) } -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 +/** + * 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 - 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, _, _) + 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() ) ) } -private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) { +/** + * 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) { a = TArrayContent() and - exists(ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store | + exists( + ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store, PartialDefinition pd + | + pd = node2.getPartialDefinition() and 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. - 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 - ) + 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 ) } @@ -293,82 +333,10 @@ private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode n * value of `node1`. */ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { - fieldStoreStepNoChi(node1, f, node2) or - fieldStoreStepChi(node1, f, node2) or + instrToFieldNodeStoreStepNoChi(node1, f, node2) or + instrToFieldNodeStoreStepChi(node1, f, node2) or arrayStoreStepChi(node1, f, node2) or - 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, _, _) - ) + callableWithoutDefinitionStoreStep(node1, f, node2) } private class ArrayToPointerConvertInstruction extends ConvertInstruction { @@ -378,34 +346,96 @@ private class ArrayToPointerConvertInstruction extends ConvertInstruction { } } -private Instruction skipOneCopyValueInstructionRec(CopyValueInstruction copy) { - copy.getUnary() = result and not result instanceof CopyValueInstruction - or - result = skipOneCopyValueInstructionRec(copy.getUnary()) +private class InexactLoadOperand extends LoadOperand { + InexactLoadOperand() { this.isDefinitionInexact() } } -private Instruction skipCopyValueInstructions(Operand op) { - not result instanceof CopyValueInstruction and result = op.getDef() +/** 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) or - result = skipOneCopyValueInstructionRec(op.getDef()) + // Some instructions produce a glvalue. Recurse past those to get the actual `PointerType`. + result = getPointerType(i.(PointerOffsetInstruction).getLeft()) +} + +pragma[noinline] +private predicate deconstructLoad( + LoadInstruction load, InexactLoadOperand loadOperand, Instruction addressInstr +) { + load.getSourceAddress() = addressInstr and + load.getSourceValueOperand() = loadOperand } 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(LoadOperand operand, Instruction address | - operand.isDefinitionInexact() and - node1.asInstruction() = operand.getAnyDef() and - operand = node2.asOperand() and - address = skipCopyValueInstructions(operand.getAddressOperand()) and - ( - address instanceof LoadInstruction or - address instanceof ArrayToPointerConvertInstruction or - address instanceof PointerOffsetInstruction - ) + 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 + 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)) + ) +} + +/** 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 @@ -417,21 +447,25 @@ private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { * f(&x); * use(x); * ``` - * 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. + * 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. */ -private predicate exactReadStep(Node node1, ArrayContent a, Node node2) { +private predicate innerReadStep(Node node1, Content a, Node node2) { a = TArrayContent() and - exists(WriteSideEffectInstruction write, ChiInstruction chi | - not chi.isResultConflated() and - chi.getPartial() = write and + exists(WriteSideEffectInstruction write, CallInstruction call, CopyValueInstruction copyValue | + write.getPrimaryInstruction() = call and node1.asInstruction() = write and - 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) + ( + 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() ) } @@ -441,10 +475,10 @@ private predicate exactReadStep(Node node1, ArrayContent a, Node node2) { * `node2`. */ predicate readStep(Node node1, Content f, Node node2) { - fieldReadStep(node1, f, node2) or + aliasedReadStep(node1, f, node2) or arrayReadStep(node1, f, node2) or - exactReadStep(node1, f, node2) or - suppressArrayRead(node1, f, node2) + instrToFieldNodeReadStep(node1, f, node2) or + innerReadStep(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 15fc2fa1d9a..7580bfc9012 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,7 +15,11 @@ cached private newtype TIRDataFlowNode = TInstructionNode(Instruction i) or TOperandNode(Operand op) or - TVariableNode(Variable var) + 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) /** * A node in a data flow graph. @@ -28,7 +32,22 @@ class Node extends TIRDataFlowNode { /** * INTERNAL: Do not use. */ - Declaration getEnclosingCallable() { none() } // overridden in subclasses + 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() + } /** Gets the function to which this node belongs, if any. */ Function getFunction() { none() } // overridden in subclasses @@ -133,8 +152,6 @@ 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() } @@ -159,8 +176,6 @@ 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() } @@ -170,6 +185,139 @@ 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. */ @@ -307,11 +455,26 @@ 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 InstructionNode { +abstract class PostUpdateNode extends Node { /** * 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(); } /** @@ -327,112 +490,40 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode { - abstract Expr getDefinedExpr(); -} +class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode { + PartialDefinition pd; -private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { - override ChiInstruction instr; - StoreInstruction store; + PartialDefinitionNode() { this = TPartialDefinitionNode(pd) } - ExplicitFieldStoreQualifierNode() { - not instr.isResultConflated() and - instr.getPartial() = store and - ( - instr.getUpdatedInterval(_, _) or - store.getDestinationAddress() instanceof FieldAddressInstruction - ) - } + /** Gets the expression that is partially defined by this node, if any. */ + Expr getDefinedExpr() { result = pd.getDefinedExpr() } - // 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() } + override Node getPreUpdateNode() { result = pd.getPreUpdateNode() } - override Expr getDefinedExpr() { - result = - store - .getDestinationAddress() - .(FieldAddressInstruction) - .getObjectAddress() - .getUnconvertedResultExpression() - } -} + /** Gets the `PartialDefinition` associated with this node. */ + PartialDefinition getPartialDefinition() { result = pd } -/** - * 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() - } + override string toString() { result = getPreUpdateNode().toString() + " [post update]" } } /** * 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 PartialDefinitionNode { - override ChiInstruction instr; +private class ArrayStoreNode extends InstructionNode, PartialDefinition { + ChiInstruction chi; PointerAddInstruction add; ArrayStoreNode() { - not instr.isResultConflated() and + chi = this.getInstruction() and + not chi.isResultConflated() and exists(StoreInstruction store | - instr.getPartial() = store and + chi.getPartial() = store and add = store.getDestinationAddress() ) } - override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } + override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() } override Expr getDefinedExpr() { result = add.getLeft().getUnconvertedResultExpression() } } @@ -441,18 +532,24 @@ private class ArrayStoreNode extends PartialDefinitionNode { * 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 PostUpdateNode { - override ChiInstruction instr; +private class PointerStoreNode extends InstructionNode, PartialDefinition { + ChiInstruction chi; + LoadInstruction load; PointerStoreNode() { - not instr.isResultConflated() and + chi = this.getInstruction() and + not chi.isResultConflated() and exists(StoreInstruction store | - instr.getPartial() = store and - store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction + chi.getPartial() = store and + load = store.getDestinationAddress().(CopyValueInstruction).getUnary() ) } - override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } + override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() } + + override Expr getDefinedExpr() { + result = load.getSourceAddress().getUnconvertedResultExpression() + } } /** @@ -465,7 +562,7 @@ private class PointerStoreNode extends PostUpdateNode { * returned. This node will have its `getArgument()` equal to `&x` and its * `getVariableAccess()` equal to `x`. */ -class DefinitionByReferenceNode extends InstructionNode { +class DefinitionByReferenceNode extends InstructionNode, PostUpdateNode { override WriteSideEffectInstruction instr; /** Gets the unconverted argument corresponding to this node. */ @@ -493,6 +590,22 @@ class DefinitionByReferenceNode extends InstructionNode { 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() + ) + } } /** @@ -510,15 +623,6 @@ 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() } @@ -585,6 +689,69 @@ 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. * @@ -598,6 +765,10 @@ 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] @@ -749,6 +920,27 @@ 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/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index 3bf3bf2e276..e0bccafae6b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -341,7 +341,7 @@ module IRTypeConsistency { query predicate multipleIRTypes(Language::LanguageType type, string message) { strictcount(type.getIRType()) > 1 and message = - "`LanguageType` " + type.getAQlClass() + " has multiple `IRType`s: " + + "`LanguageType` " + type + " has multiple `IRType`s: " + concat(type.getIRType().toString(), ", ") } 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 813c2834586..df6c27b2187 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll @@ -6,6 +6,7 @@ import semmle.code.cpp.Function import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow +import semmle.code.cpp.models.interfaces.Alias import semmle.code.cpp.models.interfaces.SideEffect import semmle.code.cpp.models.interfaces.Taint @@ -13,27 +14,29 @@ import semmle.code.cpp.models.interfaces.Taint * The standard functions `memcpy`, `memmove` and `bcopy`; and the gcc variant * `__builtin___memcpy_chk`. */ -private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction { +private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction, + AliasFunction { MemcpyFunction() { // memcpy(dest, src, num) // memmove(dest, src, num) // memmove(dest, src, num, remaining) - this.hasName(["memcpy", "memmove", "__builtin___memcpy_chk"]) + this.hasGlobalOrStdName(["memcpy", "memmove"]) or // bcopy(src, dest, num) - this.hasGlobalOrStdName("bcopy") + // mempcpy(dest, src, num) + this.hasGlobalName(["bcopy", mempcpy(), "__builtin___memcpy_chk"]) } /** * Gets the index of the parameter that is the source buffer for the copy. */ - int getParamSrc() { if this.hasGlobalOrStdName("bcopy") then result = 0 else result = 1 } + int getParamSrc() { if this.hasGlobalName("bcopy") then result = 0 else result = 1 } /** * Gets the index of the parameter that is the destination buffer for the * copy. */ - int getParamDest() { if this.hasGlobalOrStdName("bcopy") then result = 1 else result = 0 } + int getParamDest() { if this.hasGlobalName("bcopy") then result = 1 else result = 0 } /** * Gets the index of the parameter that is the size of the copy (in bytes). @@ -82,4 +85,21 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect i = getParamSrc() ) } + + override predicate parameterNeverEscapes(int index) { + index = getParamSrc() + or + this.hasGlobalName("bcopy") and index = getParamDest() + } + + override predicate parameterEscapesOnlyViaReturn(int index) { + not this.hasGlobalName("bcopy") and index = getParamDest() + } + + override predicate parameterIsAlwaysReturned(int index) { + not this.hasGlobalName(["bcopy", mempcpy()]) and + index = getParamDest() + } } + +private string mempcpy() { result = ["mempcpy", "wmempcpy"] } 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 c53a0476715..8fd2f79cfdd 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -9,9 +9,9 @@ import semmle.code.cpp.models.interfaces.Iterator import semmle.code.cpp.models.interfaces.DataFlow /** - * The `std::basic_string` template class. + * The `std::basic_string` template class instantiations. */ -private class StdBasicString extends TemplateClass { +private class StdBasicString extends ClassTemplateInstantiation { StdBasicString() { this.hasQualifiedName("std", "basic_string") } } @@ -24,7 +24,7 @@ private class StdBasicString extends TemplateClass { * ``` */ private class StdStringConstructor extends Constructor, TaintFunction { - StdStringConstructor() { this.getDeclaringType().hasQualifiedName("std", "basic_string") } + StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString } /** * Gets the index of a parameter to this function that is a string (or @@ -69,7 +69,7 @@ private class StdStringConstructor extends Constructor, TaintFunction { * The `std::string` function `c_str`. */ private class StdStringCStr extends TaintFunction { - StdStringCStr() { this.hasQualifiedName("std", "basic_string", "c_str") } + StdStringCStr() { this.getClassAndName("c_str") instanceof StdBasicString } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string itself (qualifier) to return value @@ -82,7 +82,7 @@ private class StdStringCStr extends TaintFunction { * The `std::string` function `data`. */ private class StdStringData extends TaintFunction { - StdStringData() { this.hasQualifiedName("std", "basic_string", "data") } + StdStringData() { this.getClassAndName("data") instanceof StdBasicString } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string itself (qualifier) to return value @@ -100,7 +100,7 @@ private class StdStringData extends TaintFunction { * The `std::string` function `push_back`. */ private class StdStringPush extends TaintFunction { - StdStringPush() { this.hasQualifiedName("std", "basic_string", "push_back") } + StdStringPush() { this.getClassAndName("push_back") instanceof StdBasicString } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from parameter to qualifier @@ -113,7 +113,7 @@ private class StdStringPush extends TaintFunction { * The `std::string` functions `front` and `back`. */ private class StdStringFrontBack extends TaintFunction { - StdStringFrontBack() { this.hasQualifiedName("std", "basic_string", ["front", "back"]) } + StdStringFrontBack() { this.getClassAndName(["front", "back"]) instanceof StdBasicString } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from object to returned reference @@ -123,12 +123,12 @@ private class StdStringFrontBack extends TaintFunction { } /** - * The `std::string` function `operator+`. + * The (non-member) `std::string` function `operator+`. */ private class StdStringPlus extends TaintFunction { StdStringPlus() { this.hasQualifiedName("std", "operator+") and - this.getUnspecifiedType() = any(StdBasicString s).getAnInstantiation() + this.getUnspecifiedType() instanceof StdBasicString } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -148,7 +148,7 @@ private class StdStringPlus extends TaintFunction { */ private class StdStringAppend extends TaintFunction { StdStringAppend() { - this.hasQualifiedName("std", "basic_string", ["operator+=", "append", "insert", "replace"]) + this.getClassAndName(["operator+=", "append", "insert", "replace"]) instanceof StdBasicString } /** @@ -190,7 +190,7 @@ private class StdStringAppend extends TaintFunction { * The standard function `std::string.assign`. */ private class StdStringAssign extends TaintFunction { - StdStringAssign() { this.hasQualifiedName("std", "basic_string", "assign") } + StdStringAssign() { this.getClassAndName("assign") instanceof StdBasicString } /** * Gets the index of a parameter to this function that is a string (or @@ -230,7 +230,7 @@ private class StdStringAssign extends TaintFunction { * The standard function `std::string.copy`. */ private class StdStringCopy extends TaintFunction { - StdStringCopy() { this.hasQualifiedName("std", "basic_string", "copy") } + StdStringCopy() { this.getClassAndName("copy") instanceof StdBasicString } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // copy(dest, num, pos) @@ -243,7 +243,7 @@ private class StdStringCopy extends TaintFunction { * The standard function `std::string.substr`. */ private class StdStringSubstr extends TaintFunction { - StdStringSubstr() { this.hasQualifiedName("std", "basic_string", "substr") } + StdStringSubstr() { this.getClassAndName("substr") instanceof StdBasicString } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // substr(pos, num) @@ -252,11 +252,18 @@ 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[]`. */ private class StdStringAt extends TaintFunction { - StdStringAt() { this.hasQualifiedName("std", "basic_string", ["at", "operator[]"]) } + StdStringAt() { this.getClassAndName(["at", "operator[]"]) instanceof StdBasicString } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to referenced return value @@ -270,9 +277,9 @@ private class StdStringAt extends TaintFunction { } /** - * The `std::basic_istream` template class. + * The `std::basic_istream` template class instantiations. */ -private class StdBasicIStream extends TemplateClass { +private class StdBasicIStream extends ClassTemplateInstantiation { StdBasicIStream() { this.hasQualifiedName("std", "basic_istream") } } @@ -280,7 +287,7 @@ private class StdBasicIStream extends TemplateClass { * The `std::istream` function `operator>>` (defined as a member function). */ private class StdIStreamIn extends DataFlowFunction, TaintFunction { - StdIStreamIn() { this.hasQualifiedName("std", "basic_istream", "operator>>") } + StdIStreamIn() { this.getClassAndName("operator>>") instanceof StdBasicIStream } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -305,8 +312,7 @@ private class StdIStreamIn extends DataFlowFunction, TaintFunction { private class StdIStreamInNonMember extends DataFlowFunction, TaintFunction { StdIStreamInNonMember() { this.hasQualifiedName("std", "operator>>") and - this.getUnspecifiedType().(ReferenceType).getBaseType() = - any(StdBasicIStream s).getAnInstantiation() + this.getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdBasicIStream } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { @@ -331,7 +337,7 @@ private class StdIStreamInNonMember extends DataFlowFunction, TaintFunction { */ private class StdIStreamGet extends TaintFunction { StdIStreamGet() { - this.hasQualifiedName("std", "basic_istream", ["get", "peek"]) and + this.getClassAndName(["get", "peek"]) instanceof StdBasicIStream and this.getNumberOfParameters() = 0 } @@ -347,7 +353,7 @@ private class StdIStreamGet extends TaintFunction { */ private class StdIStreamRead extends DataFlowFunction, TaintFunction { StdIStreamRead() { - this.hasQualifiedName("std", "basic_istream", ["get", "read"]) and + this.getClassAndName(["get", "read"]) instanceof StdBasicIStream and this.getNumberOfParameters() > 0 } @@ -372,7 +378,7 @@ private class StdIStreamRead extends DataFlowFunction, TaintFunction { * The `std::istream` function `readsome`. */ private class StdIStreamReadSome extends TaintFunction { - StdIStreamReadSome() { this.hasQualifiedName("std", "basic_istream", "readsome") } + StdIStreamReadSome() { this.getClassAndName("readsome") instanceof StdBasicIStream } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to first parameter @@ -385,7 +391,7 @@ private class StdIStreamReadSome extends TaintFunction { * The `std::istream` function `putback`. */ private class StdIStreamPutBack extends DataFlowFunction, TaintFunction { - StdIStreamPutBack() { this.hasQualifiedName("std", "basic_istream", "putback") } + StdIStreamPutBack() { this.getClassAndName("putback") instanceof StdBasicIStream } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -418,7 +424,7 @@ private class StdIStreamPutBack extends DataFlowFunction, TaintFunction { * The `std::istream` function `getline`. */ private class StdIStreamGetLine extends DataFlowFunction, TaintFunction { - StdIStreamGetLine() { this.hasQualifiedName("std", "basic_istream", "getline") } + StdIStreamGetLine() { this.getClassAndName("getline") instanceof StdBasicIStream } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -461,9 +467,9 @@ private class StdGetLine extends DataFlowFunction, TaintFunction { } /** - * The `std::basic_ostream` template class. + * The `std::basic_ostream` template class instantiations. */ -private class StdBasicOStream extends TemplateClass { +private class StdBasicOStream extends ClassTemplateInstantiation { StdBasicOStream() { this.hasQualifiedName("std", "basic_ostream") } } @@ -472,7 +478,9 @@ private class StdBasicOStream extends TemplateClass { * `put` and `write`. */ private class StdOStreamOut extends DataFlowFunction, TaintFunction { - StdOStreamOut() { this.hasQualifiedName("std", "basic_ostream", ["operator<<", "put", "write"]) } + StdOStreamOut() { + this.getClassAndName(["operator<<", "put", "write"]) instanceof StdBasicOStream + } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // returns reference to `*this` @@ -507,8 +515,7 @@ private class StdOStreamOut extends DataFlowFunction, TaintFunction { private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { StdOStreamOutNonMember() { this.hasQualifiedName("std", "operator<<") and - this.getUnspecifiedType().(ReferenceType).getBaseType() = - any(StdBasicOStream s).getAnInstantiation() + this.getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdBasicOStream } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { @@ -537,9 +544,7 @@ private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { * input parameter. */ private class StdStringStreamConstructor extends Constructor, TaintFunction { - StdStringStreamConstructor() { - this.getDeclaringType().hasQualifiedName("std", "basic_stringstream") - } + StdStringStreamConstructor() { this.getDeclaringType() instanceof StdBasicStringStream } /** * Gets the index of a parameter to this function that is a string. @@ -563,7 +568,7 @@ private class StdStringStreamConstructor extends Constructor, TaintFunction { * The `std::stringstream` function `str`. */ private class StdStringStreamStr extends TaintFunction { - StdStringStreamStr() { this.hasQualifiedName("std", "basic_stringstream", "str") } + StdStringStreamStr() { this.getClassAndName("str") instanceof StdBasicStringStream } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to return value (if any) @@ -576,15 +581,24 @@ private class StdStringStreamStr extends TaintFunction { } } +/** + * The `std::basic_ios` template class instantiations. + */ +private class StdBasicIOS extends ClassTemplateInstantiation { + StdBasicIOS() { this.hasQualifiedName("std", "basic_ios") } +} + /** * A `std::` stream function that does not require a model, except that it * returns a reference to `*this` and thus could be used in a chain. */ private class StdStreamFunction extends DataFlowFunction, TaintFunction { StdStreamFunction() { - this.hasQualifiedName("std", "basic_istream", ["ignore", "unget", "seekg"]) or - this.hasQualifiedName("std", "basic_ostream", ["seekp", "flush"]) or - this.hasQualifiedName("std", "basic_ios", "copyfmt") + this.getClassAndName(["ignore", "unget", "seekg"]) instanceof StdBasicIStream + or + this.getClassAndName(["seekp", "flush"]) instanceof StdBasicOStream + or + this.getClassAndName("copyfmt") instanceof StdBasicIOS } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { 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 061209d65b7..c4332c3ef5c 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll @@ -40,9 +40,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid /** * Holds if this is one of the `strcpy_s` variants. */ - private predicate isSVariant() { - exists(string name | name = getName() | name.suffix(name.length() - 2) = "_s") - } + private predicate isSVariant() { getName().matches("%\\_s") } /** * Gets the index of the parameter that is the maximum size of the copy (in characters). diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll index c1b65d62706..b30861254dc 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll @@ -24,5 +24,6 @@ abstract class DataFlowFunction extends Function { * represented by `input` to the return value or buffer represented by * `output` */ + pragma[nomagic] abstract predicate hasDataFlow(FunctionInput input, FunctionOutput output); } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll index 195cbcb63b5..4ab55ee5b3f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll @@ -108,6 +108,16 @@ class FunctionInput extends TFunctionInput { */ predicate isQualifierAddress() { none() } + /** + * Holds if `i >= 0` and `isParameter(i)` holds for this value, or + * if `i = -1` and `isQualifierAddress()` holds for this value. + */ + final predicate isParameterOrQualifierAddress(ParameterIndex i) { + i >= 0 and this.isParameter(i) + or + i = -1 and this.isQualifierAddress() + } + /** * Holds if this is the input value pointed to by the return value of a * function, if the function returns a pointer, or the input value referred @@ -134,7 +144,7 @@ class FunctionInput extends TFunctionInput { predicate isReturnValueDeref() { none() } /** - * Holds if `i >= 0` and `isParameterDeref(i)` holds for this is value, or + * Holds if `i >= 0` and `isParameterDeref(i)` holds for this value, or * if `i = -1` and `isQualifierObject()` holds for this value. */ final predicate isParameterDerefOrQualifierObject(ParameterIndex i) { diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll index fe617533f59..05a5d9f1c28 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll @@ -28,5 +28,6 @@ abstract class TaintFunction extends Function { * Holds if data passed into the argument, qualifier, or buffer represented by * `input` influences the return value or buffer represented by `output` */ + pragma[nomagic] abstract predicate hasTaintFlow(FunctionInput input, FunctionOutput output); } diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.expected new file mode 100644 index 00000000000..8d98d94ff46 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.expected @@ -0,0 +1,3 @@ +| test.c:13:9:13:13 | buff1 | This variable will not be cleared. | +| test.c:35:9:35:13 | buff1 | This variable will not be cleared. | +| test.c:43:9:43:13 | buff1 | This variable will not be cleared. | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.qlref new file mode 100644 index 00000000000..61d2a29b126 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/test.c b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/test.c new file mode 100644 index 00000000000..221072330c3 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/test.c @@ -0,0 +1,201 @@ +struct buffers +{ + unsigned char buff1[50]; + unsigned char *buff2; +} globalBuff1,*globalBuff2; + +unsigned char * globalBuff; +void badFunc0_0(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); +} +void nobadFunc0_0(){ + unsigned char buff1[12]; + memset(buff1,12,12); +} +void nobadFunc0_1(){ + unsigned char buff1[12]; + int i; + memset(buff1,12,12); + for(i=0;i<12;i++) + buff1[i]=13; + free(buff1); +} +void nobadFunc1_0(){ + unsigned char * buff1; + buff1 = (unsigned char *) malloc(12); + memset(buff1,12,12); +} +void badFunc1_0(){ + unsigned char * buff1; + buff1 = (unsigned char *) malloc(12); + memset(buff1,12,12); + free(buff1); +} +void badFunc1_1(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + free(buff1); +} +void nobadFunc2_0_0(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + printf(buff1); +} + +void nobadFunc2_0_1(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + printf(buff1+3); +} + +void nobadFunc2_0_2(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + printf(*buff1); +} + +void nobadFunc2_0_3(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + printf(*(buff1+3)); +} +unsigned char * nobadFunc2_0_4(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + return buff1; +} + +unsigned char * nobadFunc2_0_5(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + return buff1+3; +} +unsigned char nobadFunc2_0_6(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + return *buff1; +} + +unsigned char nobadFunc2_0_7(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + return *(buff1+3); +} +void nobadFunc2_1_0(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + if(*buff1==0) + printf("123123"); +} +void nobadFunc2_1_1(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + if(*(buff1+3)==0) + printf("123123"); +} +void nobadFunc2_1_2(){ + unsigned char buff1[12]; + int i; + for(i=0;i<12;i++) + buff1[i]=13; + memset(buff1,12,12); + buff1[2]=5; +} +void nobadFunc3_0(unsigned char * buffAll){ + unsigned char * buff1 = buffAll; + memset(buff1,12,12); +} +void nobadFunc3_1(unsigned char * buffAll){ + unsigned char * buff1 = buffAll+3; + memset(buff1,12,12); +} +void nobadFunc3_2(struct buffers buffAll){ + unsigned char * buff1 = buffAll.buff1; + memset(buff1,12,12); +} +void nobadFunc3_3(struct buffers buffAll){ + unsigned char * buff1 = buffAll.buff2; + memset(buff1,12,12); +} +void nobadFunc3_4(struct buffers buffAll){ + unsigned char * buff1 = buffAll.buff2+3; + memset(buff1,12,12); +} +void nobadFunc3_5(struct buffers * buffAll){ + unsigned char * buff1 = buffAll->buff1; + memset(buff1,12,12); +} +void nobadFunc3_6(struct buffers *buffAll){ + unsigned char * buff1 = buffAll->buff2; + memset(buff1,12,12); +} +void nobadFunc4(){ + unsigned char * buff1 = globalBuff; + memset(buff1,12,12); +} +void nobadFunc4_0(){ + unsigned char * buff1 = globalBuff; + memset(buff1,12,12); +} +void nobadFunc4_1(){ + unsigned char * buff1 = globalBuff+3; + memset(buff1,12,12); +} +void nobadFunc4_2(){ + unsigned char * buff1 = globalBuff1.buff1; + memset(buff1,12,12); +} +void nobadFunc4_3(){ + unsigned char * buff1 = globalBuff1.buff2; + memset(buff1,12,12); +} +void nobadFunc4_4(){ + unsigned char * buff1 = globalBuff1.buff2+3; + memset(buff1,12,12); +} +void nobadFunc4_5(){ + unsigned char * buff1 = globalBuff2->buff1; + memset(buff1,12,12); +} +void nobadFunc4_6(){ + unsigned char * buff1 = globalBuff2->buff2; + memset(buff1,12,12); +} + diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.expected index c263d7e6dfd..887547f2c2e 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.expected @@ -13,9 +13,9 @@ nodes | test.cpp:96:37:96:46 | theZipcode | semmle.label | theZipcode | | test.cpp:99:42:99:51 | theZipcode | semmle.label | theZipcode | #select -| test.cpp:57:9:57:18 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:57:9:57:18 | theZipcode | this source. | -| test.cpp:74:24:74:30 | medical | This write into the external location 'medical' may contain unencrypted data from $@ | test.cpp:74:24:74:30 | medical | this source. | -| test.cpp:78:24:78:27 | temp | This write into the external location 'temp' may contain unencrypted data from $@ | test.cpp:77:16:77:22 | medical | this source. | -| test.cpp:82:24:82:28 | buff5 | This write into the external location 'buff5' may contain unencrypted data from $@ | test.cpp:81:22:81:28 | medical | this source. | -| test.cpp:96:37:96:46 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:96:37:96:46 | theZipcode | this source. | -| test.cpp:99:42:99:51 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:99:42:99:51 | theZipcode | this source. | +| test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:57:9:57:18 | theZipcode | this source. | +| test.cpp:74:24:74:30 | medical | test.cpp:74:24:74:30 | medical | test.cpp:74:24:74:30 | medical | This write into the external location 'medical' may contain unencrypted data from $@ | test.cpp:74:24:74:30 | medical | this source. | +| test.cpp:78:24:78:27 | temp | test.cpp:77:16:77:22 | medical | test.cpp:78:24:78:27 | temp | This write into the external location 'temp' may contain unencrypted data from $@ | test.cpp:77:16:77:22 | medical | this source. | +| test.cpp:82:24:82:28 | buff5 | test.cpp:81:22:81:28 | medical | test.cpp:82:24:82:28 | buff5 | This write into the external location 'buff5' may contain unencrypted data from $@ | test.cpp:81:22:81:28 | medical | this source. | +| test.cpp:96:37:96:46 | theZipcode | test.cpp:96:37:96:46 | theZipcode | test.cpp:96:37:96:46 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:96:37:96:46 | theZipcode | this source. | +| test.cpp:99:42:99:51 | theZipcode | test.cpp:99:42:99:51 | theZipcode | test.cpp:99:42:99:51 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:99:42:99:51 | theZipcode | this source. | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-401/semmle/tests/MemoryLeakOnFailedCallToRealloc.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-401/semmle/tests/MemoryLeakOnFailedCallToRealloc.expected index c9b574fe315..b40e19c7559 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-401/semmle/tests/MemoryLeakOnFailedCallToRealloc.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-401/semmle/tests/MemoryLeakOnFailedCallToRealloc.expected @@ -2,3 +2,7 @@ | test.c:63:29:63:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc | | test.c:139:29:139:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc | | test.c:186:29:186:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc | +| test.c:282:29:282:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc | +| test.c:299:26:299:32 | call to realloc | possible loss of original pointer on unsuccessful call realloc | +| test.c:328:29:328:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc | +| test.c:342:29:342:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-401/semmle/tests/test.c b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-401/semmle/tests/test.c index fcf60467ba9..df33fc19ef6 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-401/semmle/tests/test.c +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-401/semmle/tests/test.c @@ -2,7 +2,7 @@ #define NULL ((void*)0) #define assert(x) if (!(x)) __assert_fail(#x,__FILE__,__LINE__) -void __assert_fail(const char *assertion, const char *file, int line) { } +void __assert_fail(const char *assertion, const char *file, int line); void aFakeFailed_1(int file, int line) { @@ -272,3 +272,75 @@ unsigned char * noBadResize_2_7(unsigned char * buffer,size_t currentSize,size_t myASSERT_2(buffer); return buffer; } + +unsigned char *goodResize_3_1(unsigned char *buffer, size_t currentSize, size_t newSize) +{ + // GOOD: this way we will exclude possible memory leak [FALSE POSITIVE] + unsigned char *tmp = buffer; + if (currentSize < newSize) + { + buffer = (unsigned char *)realloc(buffer, newSize); + if (buffer == NULL) + { + free(tmp); + return NULL; + } + } + + return buffer; +} + +unsigned char *goodResize_3_2(unsigned char *buffer, size_t currentSize, size_t newSize) +{ + // GOOD: this way we will exclude possible memory leak [FALSE POSITIVE] + unsigned char *tmp = buffer; + if (currentSize < newSize) + { + tmp = (unsigned char *)realloc(tmp, newSize); + if (tmp != 0) + { + buffer = tmp; + } + } + + return buffer; +} + +void abort(void); + +unsigned char *noBadResize_4_1(unsigned char *buffer, size_t currentSize, size_t newSize) +{ + // GOOD: program to end + if (currentSize < newSize) + { + if (buffer = (unsigned char *)realloc(buffer, newSize)) + abort(); + } + + return buffer; +} + +unsigned char * badResize_5_2(unsigned char *buffer, size_t currentSize, size_t newSize, int cond) +{ + // BAD: on unsuccessful call to realloc, we will lose a pointer to a valid memory block + if (currentSize < newSize) + { + buffer = (unsigned char *)realloc(buffer, newSize); + } + if (cond) + { + abort(); // irrelevant + } + return buffer; +} + +unsigned char * badResize_5_1(unsigned char *buffer, size_t currentSize, size_t newSize, int cond) +{ + // BAD: on unsuccessful call to realloc, we will lose a pointer to a valid memory block + if (currentSize < newSize) + { + buffer = (unsigned char *)realloc(buffer, newSize); + assert(cond); // irrelevant + } + return buffer; +} diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.expected new file mode 100644 index 00000000000..af52dac0144 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.expected @@ -0,0 +1,3 @@ +| test.c:4:3:4:9 | call to strncat | if the used buffer is full, writing out of the buffer is possible | +| test.c:11:3:11:9 | call to strncat | if the used buffer is full, writing out of the buffer is possible | +| test.c:19:3:19:9 | call to strncat | if the used buffer is full, writing out of the buffer is possible | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.qlref new file mode 100644 index 00000000000..8fd8b1b3217 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrncat.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 new file mode 100644 index 00000000000..c3347e1fd65 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c @@ -0,0 +1,28 @@ +void workFunction_0(char *s) { + char buf[80]; + strncat(buf, s, sizeof(buf)-strlen(buf)-1); // GOOD + strncat(buf, s, sizeof(buf)-strlen(buf)); // BAD + strncat(buf, "fix", sizeof(buf)-strlen(buf)); // BAD [NOT DETECTED] +} +void workFunction_1(char *s) { +#define MAX_SIZE 80 + char buf[MAX_SIZE]; + strncat(buf, s, MAX_SIZE-strlen(buf)-1); // GOOD + strncat(buf, s, MAX_SIZE-strlen(buf)); // BAD + strncat(buf, "fix", MAX_SIZE-strlen(buf)); // BAD [NOT DETECTED] +} +void workFunction_2_0(char *s) { + char * buf; + int len=80; + buf = (char *) malloc(len); + strncat(buf, s, len-strlen(buf)-1); // GOOD + strncat(buf, s, len-strlen(buf)); // BAD + strncat(buf, "fix", len-strlen(buf)); // BAD [NOT DETECTED] +} +void workFunction_2_1(char *s) { + char * buf; + int len=80; + buf = (char *) malloc(len+1); + strncat(buf, s, len-strlen(buf)-1); // GOOD + strncat(buf, s, len-strlen(buf)); // GOOD +} 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 fc6c97aa2a6..b9f6f717c80 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,60 +26,21 @@ 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 -| 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. | +| 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. | 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 f59552aa2dd..774ecddeab2 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 MISSING: ir + sink(field); // $ ast,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 500bbed53a9..833e85600a6 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp @@ -204,4 +204,32 @@ 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 8e84d39be3b..46abcd62c07 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(void *o); void sink(const char *o); void *user_input(void); struct S { @@ -135,3 +135,13 @@ 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 c6528723d22..500faa38eb1 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -89,6 +89,10 @@ 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. | @@ -119,6 +123,9 @@ 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. | @@ -152,5 +159,6 @@ 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 63d3b2c0f48..0a03ccef569 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,145 +20,71 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| 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. | +| 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. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| 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. | +| 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. | 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 c8b70a74b3a..0f25daa307d 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,50 +4,62 @@ 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: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: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: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 | 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: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:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Chi [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:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Chi [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:150:12:150:18 | new | A.cpp:151:12:151:24 | D output argument [b] | -| 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] | +| 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 | | 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: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: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: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: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 | +| 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 | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Chi [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:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [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: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: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: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: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: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: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: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: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] | @@ -58,7 +70,19 @@ 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:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | Chi [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: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 | * ... | @@ -71,16 +95,37 @@ 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 | 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 | +| 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 | | 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 | * ... | @@ -96,65 +141,126 @@ 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:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Chi [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:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp: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:92:3:92:20 | Chi [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | | by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | -| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | Chi [array content] | +| by_reference.cpp: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:96:3:96:19 | Chi [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | | by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | -| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | Chi [array content] | -| by_reference.cpp: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 | +| 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 | | 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: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: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 | a output argument [b_] | complex.cpp:43:18:43:18 | call to b | -| complex.cpp:53:12:53:12 | Chi [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| 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 | 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 | Chi [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:19:53:28 | call to user_input | complex.cpp:53:12:53:12 | setA output argument [a_] | -| complex.cpp:54:12:54:12 | Chi [b_] | complex.cpp:40:17:40:17 | *b [b_] | +| 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 | 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 | Chi [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:19:54:28 | call to user_input | complex.cpp:54:12:54:12 | setB output argument [b_] | -| 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: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 | 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 | 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:55:12:55:12 | f [post update] [f, 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: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: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 | 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 | Chi [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 [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 | Chi [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: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_] | @@ -182,21 +288,25 @@ 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: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] | +| 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] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | 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: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 | 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 *)... | @@ -206,66 +316,75 @@ 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:5:100:13 | Chi [a] | semmle.label | Chi [a] | +| A.cpp:100:9:100:9 | a [post update] [a] | semmle.label | a [post update] [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:12:22:21 | Chi [s1] | semmle.label | Chi [s1] | +| C.cpp:22:9:22:22 | s1 [post update] [s1] | semmle.label | s1 [post update] [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:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:60:6:60:7 | m1 [post update] [m1] | semmle.label | m1 [post update] [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:3:98:21 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | semmle.label | m1 [post update] [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] | @@ -285,19 +404,42 @@ 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 | 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 | semmle.label | taint_a_ptr output argument | | 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:187:15:187:22 | Chi | semmle.label | Chi | -| aliasing.cpp:187:15:187:22 | Chi [m1] | semmle.label | Chi [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 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| aliasing.cpp:188:13:188:14 | Store [m1] | semmle.label | Store [m1] | +| 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:189:15:189:16 | m1 | semmle.label | m1 | -| aliasing.cpp:200:15:200:24 | Chi | semmle.label | Chi | -| aliasing.cpp:200:15:200:24 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp: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 | 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 | * ... | @@ -319,60 +461,111 @@ 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:104:15:104:22 | Chi | semmle.label | Chi | -| by_reference.cpp:104:15:104:22 | Chi [a] | semmle.label | Chi [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 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:104:22:104:22 | a [post update] [a] | semmle.label | a [post update] [a] | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:108:15:108:24 | Chi | semmle.label | Chi | -| by_reference.cpp:108:15:108:24 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp: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 | 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:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:116:16:116:16 | a [a] | semmle.label | a [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:124:15:124:21 | Chi | semmle.label | Chi | -| by_reference.cpp:124:15:124:21 | Chi [a] | semmle.label | Chi [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 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] | -| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:124:21:124:21 | a [post update] [a] | semmle.label | a [post update] [a] | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:128:15:128:23 | Chi | semmle.label | Chi | -| by_reference.cpp:128:15:128:23 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp: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 | 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:42:16:42:16 | Chi [b_] | semmle.label | Chi [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 | 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:12:53:12 | Chi [a_] | semmle.label | Chi [a_] | +| 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 | 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:12:54:12 | Chi [b_] | semmle.label | Chi [b_] | +| 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 | 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:12:55:12 | Chi [a_] | semmle.label | Chi [a_] | +| 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 | 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:12:56:12 | Chi [a_] | semmle.label | Chi [a_] | -| complex.cpp:56:12:56:12 | Chi [b_] | semmle.label | Chi [b_] | +| 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 | 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_] | @@ -401,25 +594,29 @@ 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:5:65:22 | Store [i] | semmle.label | Store [i] | +| simple.cpp:65:7:65:7 | i [post update] [i] | semmle.label | i [post update] [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:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | +| 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: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:5:92:22 | Store [i] | semmle.label | Store [i] | +| simple.cpp:92:7:92:7 | i [post update] [i] | semmle.label | i [post update] [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:20:20:20:29 | Chi [a] | semmle.label | Chi [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 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | -| struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [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 | 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 | @@ -449,6 +646,8 @@ 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 | @@ -466,6 +665,9 @@ 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 996836a65b4..d7939750db6 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,15 +14,11 @@ | 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 | @@ -34,85 +30,61 @@ | 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:169:12:169:12 | l | AST only | +| A.cpp:167:47:167:50 | l | IR 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 | @@ -120,26 +92,14 @@ | 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 | @@ -147,79 +107,92 @@ | 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:92:3:92:3 | w | AST only | +| aliasing.cpp:87:10:87:10 | w | IR only | +| aliasing.cpp:87:12:87:13 | s | IR 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:158:15:158:15 | s | AST only | +| aliasing.cpp:148:13:148:14 | access to array | IR only | | aliasing.cpp:158:17:158:20 | data | AST only | -| aliasing.cpp:164:15:164:15 | s | AST only | +| aliasing.cpp:159:11:159:14 | s | IR 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:175:16:175:17 | s2 | AST only | +| aliasing.cpp:176:11:176:11 | s2 | IR only | +| aliasing.cpp:176:13:176:14 | s | IR only | | aliasing.cpp:181:15:181:22 | & ... | AST only | -| aliasing.cpp:181:16:181:17 | s2 | AST only | +| aliasing.cpp:182:11:182:11 | s2 | IR only | +| aliasing.cpp:182:13:182:14 | s | IR only | | aliasing.cpp:187:15:187:22 | & ... | AST only | -| aliasing.cpp:187:16:187:17 | s2 | AST only | +| aliasing.cpp:189:13:189:13 | s2_2 | IR only | +| aliasing.cpp:189:15:189:16 | s | IR only | | aliasing.cpp:194:15:194:22 | & ... | AST only | -| aliasing.cpp:194:16:194:17 | s2 | AST only | +| aliasing.cpp:196:13:196:13 | s2_2 | IR only | +| aliasing.cpp:196:15:196:16 | s | IR only | | aliasing.cpp:200:15:200:24 | & ... | AST only | -| aliasing.cpp:200:16:200:18 | ps2 | AST only | +| aliasing.cpp:201:13:201:13 | ps2 | IR only | +| aliasing.cpp:201:15:201:16 | s | IR only | | aliasing.cpp:205:15:205:24 | & ... | AST only | -| aliasing.cpp:205:16:205:18 | ps2 | 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 | | 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 | @@ -227,6 +200,8 @@ | 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 | @@ -244,87 +219,63 @@ | 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:10:4:10:5 | ra | AST only | +| conflated.cpp:11:12:11:12 | ra | IR 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:36:3:36:4 | pa | AST only | +| conflated.cpp:30:12:30:12 | pa | IR 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 | @@ -336,68 +287,55 @@ | 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: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: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: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 | @@ -411,31 +349,24 @@ | 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:83:9:83:10 | this | 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:12:83:13 | f1 | AST only | | simple.cpp:84:14:84:20 | this | AST only | | simple.cpp:92:7:92:7 | i | AST only | -| struct_init.c:15:8:15:9 | ab | 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: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 294c46a5694..437a36cc2ba 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,72 +1,338 @@ | 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 9b03e4f8039..9821d527b87 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -220,6 +220,18 @@ | 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 | @@ -340,6 +352,8 @@ | 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_ | @@ -484,6 +498,9 @@ | 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 6604dde87d4..6ea374d0ddf 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -160,6 +160,7 @@ 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] | @@ -187,6 +188,20 @@ 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 | * ... | @@ -308,6 +323,9 @@ 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_] | @@ -449,6 +467,12 @@ 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] | @@ -689,6 +713,22 @@ 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 | @@ -818,6 +858,10 @@ 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_] | @@ -980,6 +1024,13 @@ 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 | @@ -1045,6 +1096,8 @@ 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 | @@ -1071,6 +1124,7 @@ 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 | @@ -1098,6 +1152,7 @@ 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 e4d4f70edb0..829974a1b67 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -94,4 +94,16 @@ 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/constructor_delegation.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/constructor_delegation.cpp new file mode 100644 index 00000000000..d1acc67f81f --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/constructor_delegation.cpp @@ -0,0 +1,47 @@ + +int source(); +void sink(...); + +class MyValue +{ +public: + MyValue(int _x) : x(_x) {}; // taint flows from parameter `_x` to member variable `x` + MyValue(int _x, bool ex) : MyValue(_x) {}; // taint flows from parameter `_x` to member variable `x` + MyValue(int _x, int _y) : MyValue(_x + _y) {}; // taint flows from parameters `_x` and `_y` to member variable `x` + MyValue(int _x, bool ex1, bool ex2) : MyValue(0) {}; // taint doesn't flow from parameter `_x` + + int x; +}; + +class MyDerivedValue : public MyValue +{ +public: + MyDerivedValue(bool ex, int _x) : MyValue(_x) {}; // taint flows from parameter `_x` to member variable `x` +}; + +void test_inits() +{ + MyValue v1(0); + MyValue v2(source()); + MyValue v3(0, true); + MyValue v4(source(), true); + MyValue v5(0, 1); + MyValue v6(source(), 1); + MyValue v7(0, source()); + MyValue v8(0, true, true); + MyValue v9(source(), true, true); + MyDerivedValue v10(true, 0); + MyDerivedValue v11(true, source()); + + sink(v1.x); + sink(v2.x); // $ ast,ir + sink(v3.x); + sink(v4.x); // $ ir MISSING: ast + sink(v5.x); + sink(v6.x); // $ ir MISSING: ast + sink(v7.x); // $ ir MISSING: ast + sink(v8.x); + sink(v9.x); + sink(v10.x); + sink(v11.x); // $ ir MISSING: ast +} 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 6edd97d0069..7b8d59fe3e7 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -135,6 +135,28 @@ | arrayassignment.cpp:145:12:145:12 | 5 | arrayassignment.cpp:145:7:145:13 | access to array | TAINT | | arrayassignment.cpp:146:7:146:10 | arr3 | arrayassignment.cpp:146:7:146:13 | access to array | | | arrayassignment.cpp:146:12:146:12 | 5 | arrayassignment.cpp:146:7:146:13 | access to array | TAINT | +| constructor_delegation.cpp:8:2:8:8 | this | constructor_delegation.cpp:8:20:8:24 | constructor init of field x [pre-this] | | +| constructor_delegation.cpp:8:14:8:15 | _x | constructor_delegation.cpp:8:22:8:23 | _x | | +| constructor_delegation.cpp:8:22:8:23 | _x | constructor_delegation.cpp:8:20:8:24 | constructor init of field x | TAINT | +| constructor_delegation.cpp:9:37:9:38 | _x | constructor_delegation.cpp:9:29:9:39 | call to MyValue | TAINT | +| constructor_delegation.cpp:10:36:10:37 | _x | constructor_delegation.cpp:10:36:10:42 | ... + ... | TAINT | +| constructor_delegation.cpp:10:36:10:42 | ... + ... | constructor_delegation.cpp:10:28:10:43 | call to MyValue | TAINT | +| constructor_delegation.cpp:10:41:10:42 | _y | constructor_delegation.cpp:10:36:10:42 | ... + ... | TAINT | +| constructor_delegation.cpp:11:48:11:48 | 0 | constructor_delegation.cpp:11:40:11:49 | call to MyValue | TAINT | +| constructor_delegation.cpp:19:44:19:45 | _x | constructor_delegation.cpp:19:36:19:46 | call to MyValue | TAINT | +| constructor_delegation.cpp:24:13:24:13 | 0 | constructor_delegation.cpp:24:13:24:14 | call to MyValue | TAINT | +| constructor_delegation.cpp:24:13:24:14 | call to MyValue | constructor_delegation.cpp:36:7:36:8 | v1 | | +| constructor_delegation.cpp:25:13:25:18 | call to source | constructor_delegation.cpp:25:13:25:21 | call to MyValue | TAINT | +| constructor_delegation.cpp:25:13:25:21 | call to MyValue | constructor_delegation.cpp:37:7:37:8 | v2 | | +| constructor_delegation.cpp:26:13:26:20 | call to MyValue | constructor_delegation.cpp:38:7:38:8 | v3 | | +| constructor_delegation.cpp:27:13:27:27 | call to MyValue | constructor_delegation.cpp:39:7:39:8 | v4 | | +| constructor_delegation.cpp:28:13:28:17 | call to MyValue | constructor_delegation.cpp:40:7:40:8 | v5 | | +| constructor_delegation.cpp:29:13:29:24 | call to MyValue | constructor_delegation.cpp:41:7:41:8 | v6 | | +| constructor_delegation.cpp:30:13:30:24 | call to MyValue | constructor_delegation.cpp:42:7:42:8 | v7 | | +| constructor_delegation.cpp:31:13:31:26 | call to MyValue | constructor_delegation.cpp:43:7:43:8 | v8 | | +| constructor_delegation.cpp:32:13:32:33 | call to MyValue | constructor_delegation.cpp:44:7:44:8 | v9 | | +| constructor_delegation.cpp:33:21:33:28 | call to MyDerivedValue | constructor_delegation.cpp:45:7:45:9 | v10 | | +| constructor_delegation.cpp:34:21:34:35 | call to MyDerivedValue | constructor_delegation.cpp:46:7:46:9 | v11 | | | copyableclass.cpp:8:2:8:16 | this | copyableclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | | | copyableclass.cpp:8:22:8:23 | _v | copyableclass.cpp:8:30:8:31 | _v | | | copyableclass.cpp:8:30:8:31 | _v | copyableclass.cpp:8:28:8:32 | constructor init of field v | 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 709ba8e7af4..3fb8c738305 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 @@ -38,13 +38,13 @@ public: void test_typedefs(int_iterator_by_typedefs source1) { sink(*source1); // $ ast,ir - sink(*(source1++)); // $ ast MISSING: ir + sink(*(source1++)); // $ ast,ir sink(*(++source1)); // $ ast MISSING: ir } void test_trait(int_iterator_by_trait source1) { sink(*source1); // $ ast,ir - sink(*(source1++)); // $ ast MISSING: ir + sink(*(source1++)); // $ ast,ir sink(*(++source1)); // $ ast MISSING: ir } diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp index 3741c54285b..9169113c1d9 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp @@ -415,10 +415,10 @@ void test_string_iterators() { sink(*i9); // $ ast,ir i10 = i2; - sink(*(i10++)); // $ ast MISSING: ir + sink(*(i10++)); // $ ast,ir sink(i10); // $ ast,ir i11 = i2; - sink(*(i11--)); // $ ast MISSING: ir + sink(*(i11--)); // $ ast,ir sink(i11); // $ ast,ir } } diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp index 794df6704da..7b7712f0c01 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stringstream.cpp @@ -75,7 +75,7 @@ void test_stringstream_int(int source) sink(ss1 << 1234); sink(ss2 << source); // $ ast MISSING: ir sink(ss1 >> v1); - sink(ss2 >> v2); // $ ast MISSING: ir + sink(ss2 >> v2); // $ ast,ir sink(ss1); sink(ss2); // $ ast,ir @@ -143,27 +143,27 @@ void test_stringstream_in() sink(ss2 << source()); // $ ast,ir sink(ss1 >> s1); - sink(ss2 >> s2); // $ ast MISSING: ir - sink(ss2 >> s3 >> s4); // $ ast MISSING: ir + sink(ss2 >> s2); // $ ast,ir + sink(ss2 >> s3 >> s4); // $ ast,ir sink(s1); sink(s2); // $ ast,ir sink(s3); // $ ast,ir - sink(s4); // $ ast MISSING: ir + sink(s4); // $ ast,ir sink(ss1 >> b1); - sink(ss2 >> b2); // $ ast MISSING: ir - sink(ss2 >> b3 >> b4); // $ ast MISSING: ir + sink(ss2 >> b2); // $ ast,ir + sink(ss2 >> b3 >> b4); // $ ast,ir sink(b1); sink(b2); // $ ast,ir sink(b3); // $ ast,ir - sink(b4); // $ ast MISSING: ir + sink(b4); // $ ast,ir sink(ss1.read(b5, 100)); - sink(ss2.read(b6, 100)); // $ ast MISSING: ir + sink(ss2.read(b6, 100)); // $ ast,ir sink(ss1.readsome(b7, 100)); sink(ss2.readsome(b8, 100)); // (returns a length, not significantly tainted) sink(ss1.get(b9, 100)); - sink(ss2.get(b10, 100)); // $ ast MISSING: ir + sink(ss2.get(b10, 100)); // $ ast,ir sink(b5); sink(b6); // $ ast,ir sink(b7); @@ -176,7 +176,7 @@ void test_stringstream_in() sink(c3 = ss1.peek()); sink(c4 = ss2.peek()); // $ ast,ir sink(ss1.get(c5)); - sink(ss2.get(c6)); // $ ast MISSING: ir + sink(ss2.get(c6)); // $ ast,ir sink(c1); sink(c2); // $ ast,ir sink(c3); @@ -212,44 +212,44 @@ void test_getline() std::string s1, s2, s3, s4, s5, s6, s7, s8; sink(ss1.getline(b1, 1000)); - sink(ss2.getline(b2, 1000)); // $ ast MISSING: ir - sink(ss2.getline(b3, 1000)); // $ ast MISSING: ir + sink(ss2.getline(b2, 1000)); // $ ast,ir + sink(ss2.getline(b3, 1000)); // $ ast,ir sink(ss1.getline(b3, 1000)); sink(b1); sink(b2); // $ ast,ir sink(b3); // $ SPURIOUS: ast,ir sink(ss1.getline(b4, 1000, ' ')); - sink(ss2.getline(b5, 1000, ' ')); // $ ast MISSING: ir - sink(ss2.getline(b6, 1000, ' ')); // $ ast MISSING: ir + sink(ss2.getline(b5, 1000, ' ')); // $ ast,ir + sink(ss2.getline(b6, 1000, ' ')); // $ ast,ir sink(ss1.getline(b6, 1000, ' ')); sink(b4); sink(b5); // $ ast,ir sink(b6); // $ SPURIOUS: ast,ir - sink(ss2.getline(b7, 1000).getline(b8, 1000)); // $ ast MISSING: ir + sink(ss2.getline(b7, 1000).getline(b8, 1000)); // $ ast,ir sink(b7); // $ ast,ir sink(b8); // $ ast MISSING: ir sink(getline(ss1, s1)); - sink(getline(ss2, s2)); // $ ast MISSING: ir - sink(getline(ss2, s3)); // $ ast MISSING: ir + sink(getline(ss2, s2)); // $ ast,ir + sink(getline(ss2, s3)); // $ ast,ir sink(getline(ss1, s3)); sink(s1); sink(s2); // $ ast,ir sink(s3); // $ SPURIOUS: ast,ir sink(getline(ss1, s4, ' ')); - sink(getline(ss2, s5, ' ')); // $ ast MISSING: ir - sink(getline(ss2, s6, ' ')); // $ ast MISSING: ir + sink(getline(ss2, s5, ' ')); // $ ast,ir + sink(getline(ss2, s6, ' ')); // $ ast,ir sink(getline(ss1, s6, ' ')); sink(s4); sink(s5); // $ ast,ir sink(s6); // $ SPURIOUS: ast,ir - sink(getline(getline(ss2, s7), s8)); // $ ast MISSING: ir + sink(getline(getline(ss2, s7), s8)); // $ ast,ir sink(s7); // $ ast,ir - sink(s8); // $ ast MISSING: ir + sink(s8); // $ ast,ir } void test_chaining() @@ -259,7 +259,7 @@ void test_chaining() char b1[1000] = {0}; char b2[1000] = {0}; - sink(ss1.get(b1, 100).unget().get(b2, 100)); // $ ast MISSING: ir + sink(ss1.get(b1, 100).unget().get(b2, 100)); // $ ast,ir sink(b1); // $ ast,ir sink(b2); // $ ast MISSING: ir diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index f241c851109..c4019a38251 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -889,10 +889,8 @@ ssa.cpp: # 207| m207_4(unknown) = Chi : total:m207_2, partial:m207_3 # 207| r207_5(glval) = VariableAddress[x] : # 207| m207_6(int) = InitializeParameter[x] : &:r207_5 -# 207| m207_7(unknown) = Chi : total:m207_4, partial:m207_6 # 208| r208_1(glval) = VariableAddress[y] : # 208| m208_2(int) = Uninitialized[y] : &:r208_1 -# 208| m208_3(unknown) = Chi : total:m207_7, partial:m208_2 # 209| r209_1(glval) = FunctionAddress[memcpy] : # 209| r209_2(glval) = VariableAddress[y] : # 209| r209_3(int *) = CopyValue : r209_2 @@ -904,15 +902,15 @@ ssa.cpp: # 209| r209_9(void *) = Call[memcpy] : func:r209_1, 0:r209_4, 1:r209_7, 2:r209_8 # 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m207_6 # 209| m209_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r209_4, r209_8 -# 209| m209_12(unknown) = Chi : total:m208_3, partial:m209_11 +# 209| m209_12(int) = Chi : total:m208_2, partial:m209_11 # 210| r210_1(glval) = VariableAddress[#return] : # 210| r210_2(glval) = VariableAddress[y] : -# 210| r210_3(int) = Load[y] : &:r210_2, ~m209_12 +# 210| r210_3(int) = Load[y] : &:r210_2, m209_12 # 210| m210_4(int) = Store[#return] : &:r210_1, r210_3 -# 207| r207_8(glval) = VariableAddress[#return] : -# 207| v207_9(void) = ReturnValue : &:r207_8, m210_4 -# 207| v207_10(void) = AliasedUse : m207_3 -# 207| v207_11(void) = ExitFunction : +# 207| r207_7(glval) = VariableAddress[#return] : +# 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 +# 207| v207_9(void) = AliasedUse : m207_3 +# 207| v207_10(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 @@ -1104,51 +1102,49 @@ ssa.cpp: # 247| m247_6(char *) = InitializeParameter[src] : &:r247_5 # 247| r247_7(char *) = Load[src] : &:r247_5, m247_6 # 247| m247_8(unknown) = InitializeIndirection[src] : &:r247_7 -# 247| m247_9(unknown) = Chi : total:m247_4, partial:m247_8 -# 247| r247_10(glval) = VariableAddress[size] : -# 247| m247_11(int) = InitializeParameter[size] : &:r247_10 +# 247| r247_9(glval) = VariableAddress[size] : +# 247| m247_10(int) = InitializeParameter[size] : &:r247_9 # 248| r248_1(glval) = VariableAddress[dst] : # 248| r248_2(glval) = FunctionAddress[operator new[]] : # 248| r248_3(glval) = VariableAddress[size] : -# 248| r248_4(int) = Load[size] : &:r248_3, m247_11 +# 248| r248_4(int) = Load[size] : &:r248_3, m247_10 # 248| r248_5(unsigned long) = Convert : r248_4 # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 # 248| r248_8(void *) = Call[operator new[]] : func:r248_2, 0:r248_7 -# 248| m248_9(unknown) = ^CallSideEffect : ~m247_9 -# 248| m248_10(unknown) = Chi : total:m247_9, partial:m248_9 +# 248| m248_9(unknown) = ^CallSideEffect : ~m247_4 +# 248| m248_10(unknown) = Chi : total:m247_4, partial:m248_9 # 248| m248_11(unknown) = ^InitializeDynamicAllocation : &:r248_8 -# 248| m248_12(unknown) = Chi : total:m248_10, partial:m248_11 -# 248| r248_13(char *) = Convert : r248_8 -# 248| m248_14(char *) = Store[dst] : &:r248_1, r248_13 +# 248| r248_12(char *) = Convert : r248_8 +# 248| m248_13(char *) = Store[dst] : &:r248_1, r248_12 # 249| r249_1(char) = Constant[97] : # 249| r249_2(glval) = VariableAddress[src] : # 249| r249_3(char *) = Load[src] : &:r249_2, m247_6 # 249| r249_4(glval) = CopyValue : r249_3 # 249| m249_5(char) = Store[?] : &:r249_4, r249_1 -# 249| m249_6(unknown) = Chi : total:m248_12, partial:m249_5 +# 249| m249_6(unknown) = Chi : total:m247_8, partial:m249_5 # 250| r250_1(glval) = FunctionAddress[memcpy] : # 250| r250_2(glval) = VariableAddress[dst] : -# 250| r250_3(char *) = Load[dst] : &:r250_2, m248_14 +# 250| r250_3(char *) = Load[dst] : &:r250_2, m248_13 # 250| r250_4(void *) = Convert : r250_3 # 250| r250_5(glval) = VariableAddress[src] : # 250| r250_6(char *) = Load[src] : &:r250_5, m247_6 # 250| r250_7(void *) = Convert : r250_6 # 250| r250_8(glval) = VariableAddress[size] : -# 250| r250_9(int) = Load[size] : &:r250_8, m247_11 +# 250| r250_9(int) = Load[size] : &:r250_8, m247_10 # 250| r250_10(void *) = Call[memcpy] : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 # 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m249_6 # 250| m250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 -# 250| m250_13(unknown) = Chi : total:m249_6, partial:m250_12 +# 250| m250_13(unknown) = Chi : total:m248_11, partial:m250_12 # 251| r251_1(glval) = VariableAddress[#return] : # 251| r251_2(glval) = VariableAddress[dst] : -# 251| r251_3(char *) = Load[dst] : &:r251_2, m248_14 +# 251| r251_3(char *) = Load[dst] : &:r251_2, m248_13 # 251| m251_4(char *) = Store[#return] : &:r251_1, r251_3 -# 247| v247_12(void) = ReturnIndirection[src] : &:r247_7, ~m250_13 -# 247| r247_13(glval) = VariableAddress[#return] : -# 247| v247_14(void) = ReturnValue : &:r247_13, m251_4 -# 247| v247_15(void) = AliasedUse : ~m250_13 -# 247| v247_16(void) = ExitFunction : +# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, m249_6 +# 247| r247_12(glval) = VariableAddress[#return] : +# 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 +# 247| v247_14(void) = AliasedUse : ~m248_10 +# 247| v247_15(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 @@ -1206,39 +1202,37 @@ ssa.cpp: # 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 # 268| r268_7(void *) = Load[s] : &:r268_5, m268_6 # 268| m268_8(unknown) = InitializeIndirection[s] : &:r268_7 -# 268| m268_9(unknown) = Chi : total:m268_4, partial:m268_8 -# 268| r268_10(glval) = VariableAddress[size] : -# 268| m268_11(int) = InitializeParameter[size] : &:r268_10 +# 268| r268_9(glval) = VariableAddress[size] : +# 268| m268_10(int) = InitializeParameter[size] : &:r268_9 # 269| r269_1(glval) = VariableAddress[buf] : # 269| r269_2(glval) = FunctionAddress[malloc] : # 269| r269_3(glval) = VariableAddress[size] : -# 269| r269_4(int) = Load[size] : &:r269_3, m268_11 +# 269| r269_4(int) = Load[size] : &:r269_3, m268_10 # 269| r269_5(void *) = Call[malloc] : func:r269_2, 0:r269_4 -# 269| m269_6(unknown) = ^CallSideEffect : ~m268_9 -# 269| m269_7(unknown) = Chi : total:m268_9, partial:m269_6 +# 269| m269_6(unknown) = ^CallSideEffect : ~m268_4 +# 269| m269_7(unknown) = Chi : total:m268_4, partial:m269_6 # 269| m269_8(unknown) = ^InitializeDynamicAllocation : &:r269_5 -# 269| m269_9(unknown) = Chi : total:m269_7, partial:m269_8 -# 269| m269_10(void *) = Store[buf] : &:r269_1, r269_5 +# 269| m269_9(void *) = Store[buf] : &:r269_1, r269_5 # 270| r270_1(glval) = FunctionAddress[memcpy] : # 270| r270_2(glval) = VariableAddress[buf] : -# 270| r270_3(void *) = Load[buf] : &:r270_2, m269_10 +# 270| r270_3(void *) = Load[buf] : &:r270_2, m269_9 # 270| r270_4(glval) = VariableAddress[s] : # 270| r270_5(void *) = Load[s] : &:r270_4, m268_6 # 270| r270_6(glval) = VariableAddress[size] : -# 270| r270_7(int) = Load[size] : &:r270_6, m268_11 +# 270| r270_7(int) = Load[size] : &:r270_6, m268_10 # 270| r270_8(void *) = Call[memcpy] : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 -# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m269_7 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m268_8 # 270| m270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 -# 270| m270_11(unknown) = Chi : total:m269_9, partial:m270_10 +# 270| m270_11(unknown) = Chi : total:m269_8, partial:m270_10 # 271| r271_1(glval) = VariableAddress[#return] : # 271| r271_2(glval) = VariableAddress[buf] : -# 271| r271_3(void *) = Load[buf] : &:r271_2, m269_10 +# 271| r271_3(void *) = Load[buf] : &:r271_2, m269_9 # 271| m271_4(void *) = Store[#return] : &:r271_1, r271_3 -# 268| v268_12(void) = ReturnIndirection[s] : &:r268_7, ~m270_11 -# 268| r268_13(glval) = VariableAddress[#return] : -# 268| v268_14(void) = ReturnValue : &:r268_13, m271_4 -# 268| v268_15(void) = AliasedUse : ~m270_11 -# 268| v268_16(void) = ExitFunction : +# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, m268_8 +# 268| r268_12(glval) = VariableAddress[#return] : +# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 +# 268| v268_14(void) = AliasedUse : ~m269_7 +# 268| v268_15(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 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 6aeadb2f174..4f709d960cc 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,117 +1464,93 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| 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. | +| 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. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| 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. | +| 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. | diff --git a/cpp/ql/test/qlpack.yml b/cpp/ql/test/qlpack.yml index 008af57baef..89f684e9e3e 100644 --- a/cpp/ql/test/qlpack.yml +++ b/cpp/ql/test/qlpack.yml @@ -2,3 +2,4 @@ name: codeql-cpp-tests version: 0.0.0 libraryPathDependencies: codeql-cpp extractor: cpp +tests: . diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected new file mode 100644 index 00000000000..af50f184740 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected @@ -0,0 +1,13 @@ +edges +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | (const char *)... | +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | (const char *)... | +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | +| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | +nodes +| test.c:15:20:15:23 | argv | semmle.label | argv | +| test.c:15:20:15:23 | argv | semmle.label | argv | +| test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... | +| test.c:21:18:21:23 | (const char *)... | semmle.label | (const char *)... | +| test.c:21:18:21:23 | query1 | semmle.label | query1 | +#select +| test.c:21:18:21:23 | query1 | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg) | test.c:15:20:15:23 | argv | user input (argv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.qlref new file mode 100644 index 00000000000..21a12e5eadd --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-089/SqlTainted.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c new file mode 100644 index 00000000000..45304f13872 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.c @@ -0,0 +1,34 @@ +// Semmle test case for rule SprintfToSqlQuery.ql (Uncontrolled sprintf for SQL query) +// Associated with CWE-089: SQL injection. http://cwe.mitre.org/data/definitions/89.html + +///// Library routines ///// + +typedef unsigned long size_t; +int snprintf(char *s, size_t n, const char *format, ...); +void sanitizeString(char *stringOut, size_t len, const char *strIn); +int mysql_query(int arg1, const char *sqlArg); +int atoi(const char *nptr); + +///// Test code ///// + +int main(int argc, char** argv) { + char *userName = argv[2]; + int userNumber = atoi(argv[3]); + + // a string from the user is injected directly into an SQL query. + char query1[1000] = {0}; + snprintf(query1, 1000, "SELECT UID FROM USERS where name = \"%s\"", userName); + mysql_query(0, query1); // BAD + + // the user string is encoded by a library routine. + char userNameSanitized[1000] = {0}; + sanitizeString(userNameSanitized, 1000, userName); + char query2[1000] = {0}; + snprintf(query2, 1000, "SELECT UID FROM USERS where name = \"%s\"", userNameSanitized); + mysql_query(0, query2); // GOOD + + // an integer from the user is injected into an SQL query. + char query3[1000] = {0}; + snprintf(query3, 1000, "SELECT UID FROM USERS where number = \"%i\"", userNumber); + mysql_query(0, query3); // GOOD +} 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 9876b9695ad..0299afff063 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,18 +59,21 @@ 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: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: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: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 | 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: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: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 | ... * ... | @@ -144,6 +147,7 @@ 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 | @@ -151,12 +155,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 | Chi | semmle.label | Chi | +| test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | | 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 | Chi | semmle.label | Chi | +| test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | | 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 ca8dd38fc3b..c684f1da6ce 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,19 +43,23 @@ 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: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: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:18:2:18:14 | Chi [array content] | test.cpp:36:13:36:13 | get_rand3 output argument [array content] | -| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [array content] | -| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [array content] | +| test.cpp: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: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 | 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 | +| 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 | 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 | @@ -110,22 +114,24 @@ 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 | Chi | semmle.label | Chi | +| test.cpp:30:13:30:14 | get_rand2 output argument | semmle.label | get_rand2 output argument | | 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 | Chi | semmle.label | Chi | +| test.cpp:36:13:36:13 | get_rand3 output argument | semmle.label | get_rand3 output argument | | 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/csharp/change-notes/2021-01-14-Unary-pattern.md b/csharp/change-notes/2021-01-14-Unary-pattern.md new file mode 100644 index 00000000000..0afd5f0c7c1 --- /dev/null +++ b/csharp/change-notes/2021-01-14-Unary-pattern.md @@ -0,0 +1,3 @@ +lgtm,codescanning +* The `UnaryPatternExpr` and `NotPatternExpr` classes have been added to support +C# 9 unary `not` pattern. diff --git a/csharp/change-notes/2021-01-15-Relational-pattern.md b/csharp/change-notes/2021-01-15-Relational-pattern.md new file mode 100644 index 00000000000..77179884d12 --- /dev/null +++ b/csharp/change-notes/2021-01-15-Relational-pattern.md @@ -0,0 +1,3 @@ +lgtm,codescanning +* The `RelationalPatternExpr` and its 4 sub class have been added to support C# 9 +relational `<`, `>`, `<=`, and `>=` patterns. diff --git a/csharp/change-notes/2021-01-19-Function-pointer.md b/csharp/change-notes/2021-01-19-Function-pointer.md new file mode 100644 index 00000000000..b48855d2f89 --- /dev/null +++ b/csharp/change-notes/2021-01-19-Function-pointer.md @@ -0,0 +1,3 @@ +lgtm,codescanning +* Function pointer types (`FunctionPointerType`) and call to function pointers +(`FunctionPointerCall`) are extracted. diff --git a/csharp/change-notes/2021-01-25-Function-pointer-cil.md b/csharp/change-notes/2021-01-25-Function-pointer-cil.md new file mode 100644 index 00000000000..097df002d0f --- /dev/null +++ b/csharp/change-notes/2021-01-25-Function-pointer-cil.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Function pointer types (`FunctionPointerType`) are extracted from IL. Also, `pinned` and `by-reference` (`cil_type_annotation`) type extraction is fixed. diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/ByRefType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/ByRefType.cs new file mode 100644 index 00000000000..2a527419249 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/ByRefType.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Semmle.Extraction.CIL.Entities +{ + /// + /// Types that are passed by reference are not written directly to trap files. Instead, the annotation is stored on + /// the entity. + /// + internal sealed class ByRefType : Type + { + public ByRefType(Context cx, Type elementType) : base(cx) + { + ElementType = elementType; + } + + public override CilTypeKind Kind => throw new NotImplementedException(); + + public override Namespace? ContainingNamespace => throw new NotImplementedException(); + + public override Type? ContainingType => throw new NotImplementedException(); + + public override int ThisTypeParameterCount => throw new NotImplementedException(); + + public override IEnumerable TypeParameters => throw new NotImplementedException(); + + public override Type Construct(IEnumerable typeArguments) => throw new NotImplementedException(); + + public override string Name => $"{ElementType.Name}&"; + + public Type ElementType { get; } + + public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException(); + + public override void WriteId(TextWriter trapFile, bool inContext) + { + ElementType.WriteId(trapFile, inContext); + trapFile.Write('&'); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/CilTypeKind.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/CilTypeKind.cs index f5ccf5057f7..e95fe0e28c0 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/CilTypeKind.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/CilTypeKind.cs @@ -8,6 +8,7 @@ namespace Semmle.Extraction.CIL.Entities ValueOrRefType, TypeParameter, Array, - Pointer + Pointer, + FunctionPointer } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/CustomAttributeDecoder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/CustomAttributeDecoder.cs index caf6a3287de..94d6cc0ab6d 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/CustomAttributeDecoder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/CustomAttributeDecoder.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Reflection.Metadata; namespace Semmle.Extraction.CIL.Entities @@ -36,12 +37,26 @@ namespace Semmle.Extraction.CIL.Entities } var name = type.GetQualifiedName(); + + if (wellKnownEnums.TryGetValue(name, out var code)) + { + cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Debug, $"Using hard coded underlying enum type for {name}"); + return code; + } + cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Info, $"Couldn't get underlying enum type for {name}"); // We can't fall back to Int32, because the type returned here defines how many bytes are read from the // stream and how those bytes are interpreted. throw new NotImplementedException(); } + public bool IsSystemType(Type type) => type.GetQualifiedName() == "System.Type"; + + private static readonly Dictionary wellKnownEnums = new Dictionary + { + { "System.AttributeTargets", PrimitiveTypeCode.Int32 }, + { "System.ComponentModel.EditorBrowsableState", PrimitiveTypeCode.Int32 } + }; } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs index 353015bb9ad..175da806597 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs @@ -121,8 +121,19 @@ namespace Semmle.Extraction.CIL.Entities for (var l = 0; l < this.locals.Length; ++l) { - this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, localVariableTypes[l])); - yield return this.locals[l]; + var t = localVariableTypes[l]; + if (t is ByRefType brt) + { + t = brt.ElementType; + this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, t)); + yield return this.locals[l]; + yield return Tuples.cil_type_annotation(this.locals[l], TypeAnnotation.Ref); + } + else + { + this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, t)); + yield return this.locals[l]; + } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/FunctionPointerType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/FunctionPointerType.cs new file mode 100644 index 00000000000..e92dd957cb5 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/FunctionPointerType.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection.Metadata; + +namespace Semmle.Extraction.CIL.Entities +{ + internal sealed class FunctionPointerType : Type, IParameterizable, ICustomModifierReceiver + { + private readonly MethodSignature signature; + + public FunctionPointerType(Context cx, MethodSignature signature) : base(cx) + { + this.signature = signature; + } + + public override CilTypeKind Kind => CilTypeKind.FunctionPointer; + + public override string Name + { + get + { + using var id = new StringWriter(); + WriteName( + id.Write, + t => id.Write(t.Name), + signature + ); + return id.ToString(); + } + } + + public override Namespace? ContainingNamespace => Cx.GlobalNamespace; + + public override Type? ContainingType => null; + + public override int ThisTypeParameterCount => throw new System.NotImplementedException(); + + public override IEnumerable TypeParameters => throw new System.NotImplementedException(); + + public override Type Construct(IEnumerable typeArguments) => throw new System.NotImplementedException(); + + public override void WriteAssemblyPrefix(TextWriter trapFile) { } + + public override void WriteId(TextWriter trapFile, bool inContext) + { + WriteName( + trapFile.Write, + t => t.WriteId(trapFile, inContext), + signature + ); + } + + internal static void WriteName(Action write, Action writeType, MethodSignature signature) + { + write("delegate* "); + write(GetCallingConvention(signature.Header.CallingConvention)); + write("<"); + foreach (var pt in signature.ParameterTypes) + { + writeType(pt); + write(","); + } + writeType(signature.ReturnType); + write(">"); + } + + internal static string GetCallingConvention(SignatureCallingConvention callingConvention) + { + if (callingConvention == SignatureCallingConvention.Default) + { + return "managed"; + } + + if (callingConvention == SignatureCallingConvention.Unmanaged) + { + return "unmanaged"; + } + + return $"unmanaged[{callingConvention}]"; + } + + public override IEnumerable Contents + { + get + { + foreach (var c in base.Contents) + { + yield return c; + } + + var retType = signature.ReturnType; + if (retType is ModifiedType mt) + { + retType = mt.Unmodified; + yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired); + } + if (retType is ByRefType byRefType) + { + retType = byRefType.ElementType; + yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref); + } + yield return Tuples.cil_function_pointer_return_type(this, retType); + + yield return Tuples.cil_function_pointer_calling_conventions(this, signature.Header.CallingConvention); + + foreach (var p in Method.GetParameterExtractionProducts(signature.ParameterTypes, this, this, Cx, 0)) + { + yield return p; + } + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/IParameterizable.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/IParameterizable.cs new file mode 100644 index 00000000000..ad9347848e4 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/IParameterizable.cs @@ -0,0 +1,7 @@ +namespace Semmle.Extraction.CIL.Entities +{ + internal interface IParameterizable : IEntity + { + + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs index 119dc2fd287..30e94c8e16a 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs @@ -9,7 +9,7 @@ namespace Semmle.Extraction.CIL.Entities /// /// A method entity. /// - internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver + internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver, IParameterizable { protected MethodTypeParameter[]? genericParams; protected GenericContext gc; @@ -86,15 +86,34 @@ namespace Semmle.Extraction.CIL.Entities yield return Cx.Populate(new Parameter(Cx, this, i++, DeclaringType)); } + foreach (var p in GetParameterExtractionProducts(parameterTypes, this, this, Cx, i)) + { + yield return p; + } + } + + internal static IEnumerable GetParameterExtractionProducts(IEnumerable parameterTypes, IParameterizable parameterizable, ICustomModifierReceiver receiver, Context cx, int firstChildIndex) + { + var i = firstChildIndex; foreach (var p in parameterTypes) { var t = p; if (t is ModifiedType mt) { t = mt.Unmodified; - yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired); + yield return Tuples.cil_custom_modifiers(receiver, mt.Modifier, mt.IsRequired); + } + if (t is ByRefType brt) + { + t = brt.ElementType; + var parameter = cx.Populate(new Parameter(cx, parameterizable, i++, t)); + yield return parameter; + yield return Tuples.cil_type_annotation(parameter, TypeAnnotation.Ref); + } + else + { + yield return cx.Populate(new Parameter(cx, parameterizable, i++, t)); } - yield return Cx.Populate(new Parameter(Cx, this, i++, t)); } } @@ -106,6 +125,11 @@ namespace Semmle.Extraction.CIL.Entities t = mt.Unmodified; yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired); } + if (t is ByRefType brt) + { + t = brt.ElementType; + yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref); + } yield return Tuples.cil_method(this, name, declaringType, t); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/ModifiedType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/ModifiedType.cs index c794ed812a5..f160c6869de 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/ModifiedType.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/ModifiedType.cs @@ -37,6 +37,13 @@ namespace Semmle.Extraction.CIL.Entities public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException(); - public override void WriteId(TextWriter trapFile, bool inContext) => throw new NotImplementedException(); + public override void WriteId(TextWriter trapFile, bool inContext) + { + Unmodified.WriteId(trapFile, inContext); + trapFile.Write(IsRequired ? " modreq" : " modopt"); + trapFile.Write("("); + Modifier.WriteId(trapFile, inContext); + trapFile.Write(")"); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs index 54d2403e1e1..fde969d12b9 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using Semmle.Util; namespace Semmle.Extraction.CIL.Entities { @@ -21,6 +20,7 @@ namespace Semmle.Extraction.CIL.Entities private readonly Type[]? thisTypeArguments; private readonly Type unboundGenericType; private readonly Type? containingType; + private readonly Namespace? containingNamespace; private readonly NamedTypeIdWriter idWriter; @@ -53,13 +53,20 @@ namespace Semmle.Extraction.CIL.Entities ? null : new NoMetadataHandleType(Cx, containerName); + containingNamespace = isContainerNamespace + ? containerName == Cx.GlobalNamespace.Name + ? Cx.GlobalNamespace + : containerName == Cx.SystemNamespace.Name + ? Cx.SystemNamespace + : new Namespace(Cx, containerName) + : null; + Populate(); } private void Populate() { - if (isContainerNamespace && - !ContainingNamespace!.IsGlobalNamespace) + if (isContainerNamespace) { Cx.Populate(ContainingNamespace); } @@ -100,11 +107,7 @@ namespace Semmle.Extraction.CIL.Entities public override string Name => GenericsHelper.GetNonGenericName(name); - public override Namespace? ContainingNamespace => isContainerNamespace - ? containerName == Cx.GlobalNamespace.Name - ? Cx.GlobalNamespace - : new Namespace(Cx, containerName) - : null; + public override Namespace? ContainingNamespace => containingNamespace; public override Type? ContainingType => containingType; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs index dea5f2db30b..90452fe9265 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs @@ -8,11 +8,11 @@ namespace Semmle.Extraction.CIL.Entities /// internal sealed class Parameter : LabelledEntity { - private readonly Method method; + private readonly IParameterizable method; private readonly int index; private readonly Type type; - public Parameter(Context cx, Method m, int i, Type t) : base(cx) + public Parameter(Context cx, IParameterizable m, int i, Type t) : base(cx) { method = m; index = i; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs index 3a15bf795fe..5fb22b40409 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs @@ -62,6 +62,11 @@ namespace Semmle.Extraction.CIL.Entities t = mt.Unmodified; yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired); } + if (t is ByRefType brt) + { + t = brt.ElementType; + yield return Tuples.cil_type_annotation(this, TypeAnnotation.Ref); + } yield return Tuples.cil_property(this, type, name, t); var accessors = pd.GetAccessors(); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs index 15920051143..a80f456df72 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs @@ -41,17 +41,27 @@ namespace Semmle.Extraction.CIL.Entities public void WriteId(TextWriter trapFile, GenericContext gc) { - trapFile.Write("ref "); elementType.WriteId(trapFile, gc); + trapFile.Write('&'); } } private struct FnPtr : ITypeSignature { + private readonly MethodSignature signature; + + public FnPtr(MethodSignature signature) + { + this.signature = signature; + } public void WriteId(TextWriter trapFile, GenericContext gc) { - trapFile.Write(""); + FunctionPointerType.WriteName( + trapFile.Write, + t => t.WriteId(trapFile, gc), + signature + ); } } @@ -62,7 +72,7 @@ namespace Semmle.Extraction.CIL.Entities new ByRef(elementType); ITypeSignature ISignatureTypeProvider.GetFunctionPointerType(MethodSignature signature) => - new FnPtr(); + new FnPtr(signature); private class Instantiation : ITypeSignature { @@ -163,25 +173,9 @@ namespace Semmle.Extraction.CIL.Entities return new Modified(unmodifiedType, modifier, isRequired); } - private class Pinned : ITypeSignature - { - private readonly ITypeSignature elementType; - - public Pinned(ITypeSignature elementType) - { - this.elementType = elementType; - } - - public void WriteId(TextWriter trapFile, GenericContext gc) - { - trapFile.Write("pinned "); - elementType.WriteId(trapFile, gc); - } - } - ITypeSignature ISignatureTypeProvider.GetPinnedType(ITypeSignature elementType) { - return new Pinned(elementType); + return elementType; } private class PointerType : ITypeSignature diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeAnnotation.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeAnnotation.cs new file mode 100644 index 00000000000..fe005326b95 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeAnnotation.cs @@ -0,0 +1,11 @@ +using System; + +namespace Semmle.Extraction.CIL.Entities +{ + [Flags] + public enum TypeAnnotation + { + None = 0, + Ref = 32 + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs index cf04f4fbdaf..dcb986f1526 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs @@ -20,10 +20,10 @@ namespace Semmle.Extraction.CIL.Entities cx.Populate(new ArrayType(cx, elementType, shape.Rank)); Type IConstructedTypeProvider.GetByReferenceType(Type elementType) => - elementType; // ?? + new ByRefType(cx, elementType); Type ISignatureTypeProvider.GetFunctionPointerType(MethodSignature signature) => - cx.ErrorType; // Don't know what to do !! + cx.Populate(new FunctionPointerType(cx, signature)); Type IConstructedTypeProvider.GetGenericInstantiation(Type genericType, ImmutableArray typeArguments) => genericType.Construct(typeArguments); @@ -37,8 +37,7 @@ namespace Semmle.Extraction.CIL.Entities Type ISignatureTypeProvider.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) => new ModifiedType(cx, unmodifiedType, modifier, isRequired); - Type ISignatureTypeProvider.GetPinnedType(Type elementType) => - cx.Populate(new PointerType(cx, elementType)); + Type ISignatureTypeProvider.GetPinnedType(Type elementType) => elementType; Type IConstructedTypeProvider.GetPointerType(Type elementType) => cx.Populate(new PointerType(cx, elementType)); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs b/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs index 9568537f71f..0ae92386c3e 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs @@ -86,6 +86,12 @@ namespace Semmle.Extraction.CIL internal static Tuple cil_method(Method method, string name, Type declType, Type returnType) => new Tuple("cil_method", method, name, declType, returnType); + internal static Tuple cil_function_pointer_return_type(FunctionPointerType fnptr, Type returnType) => + new Tuple("cil_function_pointer_return_type", fnptr, returnType); + + internal static Tuple cil_function_pointer_calling_conventions(FunctionPointerType fnptr, System.Reflection.Metadata.SignatureCallingConvention callingConvention) => + new Tuple("cil_function_pointer_calling_conventions", fnptr, (int)callingConvention); + internal static Tuple cil_method_implementation(MethodImplementation impl, Method method, Assembly assembly) => new Tuple("cil_method_implementation", impl, method, assembly); @@ -101,7 +107,7 @@ namespace Semmle.Extraction.CIL internal static Tuple cil_newslot(Method method) => new Tuple("cil_newslot", method); - internal static Tuple cil_parameter(Parameter p, Method m, int i, Type t) => + internal static Tuple cil_parameter(Parameter p, IParameterizable m, int i, Type t) => new Tuple("cil_parameter", p, m, i, t); internal static Tuple cil_parameter_in(Parameter p) => @@ -191,6 +197,9 @@ 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) => + new Tuple("cil_type_annotation", receiver, (int)annotation); + internal static Tuple containerparent(Folder parent, IFileOrFolder child) => new Tuple("containerparent", parent, child); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index b5a4c79d8f2..1222403515f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -232,7 +232,7 @@ 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, true), AddAssemblyTrapPrefix); + var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); compilationEntity = new Entities.Compilation(cx, cwd, args); } @@ -287,7 +287,7 @@ namespace Semmle.Extraction.CSharp if (c.GetAssemblyOrModuleSymbol(r) is IAssemblySymbol assembly) { - var cx = extractor.CreateContext(c, trapWriter, new AssemblyScope(assembly, assemblyPath, false), AddAssemblyTrapPrefix); + var cx = extractor.CreateContext(c, trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); foreach (var module in assembly.Modules) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs index 67a4325ce35..d4f0da99a28 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs @@ -21,9 +21,10 @@ namespace Semmle.Extraction.CSharp.Entities protected override void Populate(TextWriter trapFile) { - Extraction.Entities.Assembly.CreateOutputAssembly(cx); + var assembly = Extraction.Entities.Assembly.CreateOutputAssembly(cx); trapFile.compilations(this, FileUtils.ConvertToUnix(cwd)); + trapFile.compilation_assembly(this, assembly); // Arguments var index = 0; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs index 35b3f2eb808..499e6ec418a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -42,16 +42,16 @@ namespace Semmle.Extraction.CSharp.Entities if (initializer == null) return; - Type initializerType; + ITypeSymbol initializerType; var symbolInfo = Context.GetSymbolInfo(initializer); switch (initializer.Kind()) { case SyntaxKind.BaseConstructorInitializer: - initializerType = Type.Create(Context, symbol.ContainingType.BaseType); + initializerType = symbol.ContainingType.BaseType; break; case SyntaxKind.ThisConstructorInitializer: - initializerType = ContainingType; + initializerType = symbol.ContainingType; break; default: Context.ModelError(initializer, "Unknown initializer"); @@ -59,7 +59,7 @@ namespace Semmle.Extraction.CSharp.Entities } var initInfo = new ExpressionInfo(Context, - new AnnotatedType(initializerType, NullableAnnotation.None), + AnnotatedTypeSymbol.CreateNotAnnotated(initializerType), Context.Create(initializer.ThisOrBaseKeyword.GetLocation()), Kinds.ExprKind.CONSTRUCTOR_INIT, this, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index 0c0fbca6489..9d701d242a3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities internal class Expression : FreshEntity, IExpressionParentEntity { private readonly IExpressionInfo info; - public AnnotatedType Type { get; } + public AnnotatedTypeSymbol? Type { get; } public Extraction.Entities.Location Location { get; } public ExprKind Kind { get; } @@ -33,25 +33,23 @@ namespace Semmle.Extraction.CSharp.Entities Location = info.Location; Kind = info.Kind; Type = info.Type; - if (Type.Type is null) - Type = NullType.Create(cx); TryPopulate(); } protected sealed override void Populate(TextWriter trapFile) { - trapFile.expressions(this, Kind, Type.Type.TypeRef); + var type = Type.HasValue ? Entities.Type.Create(cx, Type.Value) : NullType.Create(cx); + trapFile.expressions(this, Kind, type.TypeRef); if (info.Parent.IsTopLevelParent) trapFile.expr_parent_top_level(this, info.Child, info.Parent); else trapFile.expr_parent(this, info.Child, info.Parent); trapFile.expr_location(this, Location); - var annotatedType = Type.Symbol; - if (!annotatedType.HasObliviousNullability()) + if (Type.HasValue && !Type.Value.HasObliviousNullability()) { - var n = NullabilityEntity.Create(cx, Nullability.Create(annotatedType)); + var n = NullabilityEntity.Create(cx, Nullability.Create(Type.Value)); trapFile.type_nullability(this, n); } @@ -66,7 +64,7 @@ namespace Semmle.Extraction.CSharp.Entities if (info.ExprValue is string value) trapFile.expr_value(this, value); - Type.Type.PopulateGenerics(); + type.PopulateGenerics(); } public override Microsoft.CodeAnalysis.Location ReportingLocation => Location.symbol; @@ -318,6 +316,11 @@ namespace Semmle.Extraction.CSharp.Entities /// public static ExprKind AdjustKind(this Expression.CallType ct, ExprKind k) { + if (k == ExprKind.ADDRESS_OF) + { + return k; + } + switch (ct) { case Expression.CallType.Dynamic: @@ -367,7 +370,7 @@ namespace Semmle.Extraction.CSharp.Entities /// /// The type of the expression. /// - AnnotatedType Type { get; } + AnnotatedTypeSymbol? Type { get; } /// /// The location of the expression. @@ -411,7 +414,7 @@ namespace Semmle.Extraction.CSharp.Entities internal class ExpressionInfo : IExpressionInfo { public Context Context { get; } - public AnnotatedType Type { get; } + public AnnotatedTypeSymbol? Type { get; } public Extraction.Entities.Location Location { get; } public ExprKind Kind { get; } public IExpressionParentEntity Parent { get; } @@ -419,7 +422,7 @@ namespace Semmle.Extraction.CSharp.Entities public bool IsCompilerGenerated { get; } public string ExprValue { get; } - public ExpressionInfo(Context cx, AnnotatedType type, Extraction.Entities.Location location, ExprKind kind, + public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Extraction.Entities.Location location, ExprKind kind, IExpressionParentEntity parent, int child, bool isCompilerGenerated, string value) { Context = cx; @@ -466,10 +469,15 @@ namespace Semmle.Extraction.CSharp.Entities public AnnotatedTypeSymbol ResolvedType => new AnnotatedTypeSymbol(TypeInfo.Type.DisambiguateType(), TypeInfo.Nullability.Annotation); public AnnotatedTypeSymbol ConvertedType => new AnnotatedTypeSymbol(TypeInfo.ConvertedType.DisambiguateType(), TypeInfo.ConvertedNullability.Annotation); - public AnnotatedTypeSymbol ExpressionType + private AnnotatedTypeSymbol? cachedType; + private bool cachedTypeSet; + public AnnotatedTypeSymbol? Type { get { + if (cachedTypeSet) + return cachedType; + var type = ResolvedType; if (type.Symbol == null) @@ -491,6 +499,9 @@ namespace Semmle.Extraction.CSharp.Entities Context.ModelError(Node, "Failed to determine type"); } + cachedType = type; + cachedTypeSet = true; + return type; } } @@ -522,22 +533,6 @@ namespace Semmle.Extraction.CSharp.Entities } } - private AnnotatedType cachedType; - - public AnnotatedType Type - { - get - { - if (cachedType.Type == null) - cachedType = Entities.Type.Create(Context, ExpressionType); - return cachedType; - } - set - { - cachedType = value; - } - } - private Extraction.Entities.Location cachedLocation; public Extraction.Entities.Location Location @@ -572,9 +567,10 @@ namespace Semmle.Extraction.CSharp.Entities return this; } - public ExpressionNodeInfo SetType(AnnotatedType type) + public ExpressionNodeInfo SetType(AnnotatedTypeSymbol? type) { - Type = type; + cachedType = type; + cachedTypeSet = true; 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 e91b81a3d77..d4d4c86c507 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs @@ -52,7 +52,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (implicitThis && !symbol.IsStatic) { - This.CreateImplicit(cx, Entities.Type.Create(cx, symbol.ContainingType), Location, this, -1); + This.CreateImplicit(cx, 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 d8d12229f62..ea818862d80 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs @@ -90,7 +90,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var info = new ExpressionInfo( cx, - new AnnotatedType(Entities.Type.Create(cx, type), NullableAnnotation.None), + AnnotatedTypeSymbol.CreateNotAnnotated(type), location, ExprKind.ARRAY_CREATION, parent, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs index 8048d4da2cd..6f2551ec904 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs @@ -36,7 +36,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var info = new ExpressionInfo( cx, - new AnnotatedType(Entities.Type.Create(cx, type), Microsoft.CodeAnalysis.NullableAnnotation.None), + AnnotatedTypeSymbol.CreateNotAnnotated(type), location, ExprKind.CAST, parent, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs index 194261c4614..ef35f901b92 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, Entities.Type.Create(cx, cx.GetType(syntax)), cx.Create(syntax.GetLocation()), ExprKind.DISCARD, parent, child, false, null)) + base(new ExpressionInfo(cx, cx.GetType(syntax), cx.Create(syntax.GetLocation()), ExprKind.DISCARD, parent, child, false, null)) { } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs index a9884a5df5d..eccead4a4de 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs @@ -12,13 +12,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions } public ImplicitCast(ExpressionNodeInfo info) - : base(new ExpressionInfo(info.Context, Entities.Type.Create(info.Context, info.ConvertedType), info.Location, ExprKind.CAST, info.Parent, info.Child, true, info.ExprValue)) + : 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)); } public ImplicitCast(ExpressionNodeInfo info, IMethodSymbol method) - : base(new ExpressionInfo(info.Context, Entities.Type.Create(info.Context, info.ConvertedType), info.Location, ExprKind.OPERATOR_INVOCATION, info.Parent, info.Child, true, info.ExprValue)) + : base(new ExpressionInfo(info.Context, info.ConvertedType, info.Location, ExprKind.OPERATOR_INVOCATION, info.Parent, info.Child, true, info.ExprValue)) { Expr = Factory.Create(info.SetParent(this, 0)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs index 7a7dd1b9170..d96a44527d8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class ArrayInitializer : Expression { - private ArrayInitializer(ExpressionNodeInfo info) : base(info.SetType(NullType.Create(info.Context)).SetKind(ExprKind.ARRAY_INIT)) { } + private ArrayInitializer(ExpressionNodeInfo info) : base(info.SetType(null).SetKind(ExprKind.ARRAY_INIT)) { } public static Expression Create(ExpressionNodeInfo info) => new ArrayInitializer(info).TryPopulate(); @@ -40,7 +40,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var info = new ExpressionInfo( cx, - NullType.Create(cx), + null, location, ExprKind.ARRAY_INIT, parent, @@ -135,7 +135,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var collectionInfo = cx.GetModel(Syntax).GetCollectionInitializerSymbolInfo(i); var addMethod = Method.Create(cx, collectionInfo.Symbol as IMethodSymbol); - var voidType = Entities.Type.Create(cx, new AnnotatedTypeSymbol(cx.Compilation.GetSpecialType(SpecialType.System_Void), NullableAnnotation.None)); + var voidType = AnnotatedTypeSymbol.CreateNotAnnotated(cx.Compilation.GetSpecialType(SpecialType.System_Void)); var invocation = new Expression(new ExpressionInfo(cx, voidType, cx.Create(i.GetLocation()), ExprKind.METHOD_INVOCATION, this, child++, false, null)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs index 7a0e2fcc683..638822f3d27 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs @@ -4,6 +4,7 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp; using Semmle.Extraction.Kinds; using System.IO; +using System; namespace Semmle.Extraction.CSharp.Entities.Expressions { @@ -55,7 +56,7 @@ 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, Entities.Type.Create(cx, callingMethod.ContainingType), Location, this, child++); + This.CreateImplicit(cx, callingMethod.ContainingType, Location, this, child++); else cx.ModelError(Syntax, "Couldn't determine implicit this type"); } @@ -66,7 +67,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions } break; default: - // Delegate call; `d()` + // Delegate or function pointer call; `d()` Create(cx, Syntax.Expression, this, child++); break; } @@ -84,7 +85,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (target == null) { - if (!isDynamicCall && !IsDelegateCall(info)) + if (!isDynamicCall && !IsDelegateLikeCall(info)) cx.ModelError(Syntax, "Unable to resolve target for call. (Compilation error?)"); return; } @@ -98,7 +99,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions // Either the qualifier (Expression) is dynamic, // or one of the arguments is dynamic. var node = (InvocationExpressionSyntax)info.Node; - return !IsDelegateCall(info) && + return !IsDelegateLikeCall(info) && (IsDynamic(info.Context, node.Expression) || node.ArgumentList.Arguments.Any(arg => IsDynamic(info.Context, arg.Expression))); } @@ -133,12 +134,22 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions } } - private static bool IsDelegateCall(ExpressionNodeInfo info) + private static bool IsDelegateLikeCall(ExpressionNodeInfo info) + { + return IsDelegateLikeCall(info, symbol => IsFunctionPointer(symbol) || IsDelegateInvoke(symbol)); + } + + private static bool IsDelegateInvokeCall(ExpressionNodeInfo info) + { + return IsDelegateLikeCall(info, IsDelegateInvoke); + } + + private static bool IsDelegateLikeCall(ExpressionNodeInfo info, Func check) { var si = info.SymbolInfo; if (si.CandidateReason == CandidateReason.OverloadResolutionFailure && - si.CandidateSymbols.OfType().All(s => s.MethodKind == MethodKind.DelegateInvoke)) + si.CandidateSymbols.All(check)) { return true; } @@ -153,9 +164,20 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return true; } - return si.Symbol != null && - si.Symbol.Kind == SymbolKind.Method && - ((IMethodSymbol)si.Symbol).MethodKind == MethodKind.DelegateInvoke; + return check(si.Symbol); + } + + private static bool IsFunctionPointer(ISymbol symbol) + { + return symbol != null && + symbol.Kind == SymbolKind.FunctionPointerType; + } + + private static bool IsDelegateInvoke(ISymbol symbol) + { + return symbol != null && + symbol.Kind == SymbolKind.Method && + ((IMethodSymbol)symbol).MethodKind == MethodKind.DelegateInvoke; } private static bool IsLocalFunctionInvocation(ExpressionNodeInfo info) @@ -168,8 +190,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { return IsNameof((InvocationExpressionSyntax)info.Node) ? ExprKind.NAMEOF - : IsDelegateCall(info) - ? ExprKind.DELEGATE_INVOCATION + : IsDelegateLikeCall(info) + ? IsDelegateInvokeCall(info) + ? ExprKind.DELEGATE_INVOCATION + : ExprKind.FUNCTION_POINTER_INVOCATION : IsLocalFunctionInvocation(info) ? ExprKind.LOCAL_FUNCTION_INVOCATION : ExprKind.METHOD_INVOCATION; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs index d31a75b33d4..ad63cc26ac6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs @@ -21,11 +21,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case SyntaxKind.DefaultLiteralExpression: return ExprKind.DEFAULT; case SyntaxKind.NullLiteralExpression: - info.Type = Entities.NullType.Create(info.Context); // Don't use converted type. + info.SetType(null); // Don't use converted type. return ExprKind.NULL_LITERAL; } - var type = info.Type.Type.symbol; + var type = info.Type?.Symbol; return GetExprKind(type, info.Node, info.Context); } @@ -82,7 +82,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var info = new ExpressionInfo( cx, - new AnnotatedType(Entities.Type.Create(cx, type), NullableAnnotation.None), + AnnotatedTypeSymbol.CreateNotAnnotated(type), location, GetExprKind(type, null, cx), parent, @@ -97,7 +97,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var info = new ExpressionInfo( cx, - NullType.Create(cx), + null, location, ExprKind.NULL_LITERAL, parent, 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 718217bb720..5703c3101a2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs @@ -35,7 +35,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions // Create an "assignment" var property = cx.GetModel(init).GetDeclaredSymbol(init); var propEntity = Property.Create(cx, property); - var type = Entities.Type.Create(cx, property.GetAnnotatedType()); + var type = property.GetAnnotatedType(); var loc = cx.Create(init.GetLocation()); var assignment = new Expression(new ExpressionInfo(cx, type, loc, ExprKind.SIMPLE_ASSIGN, objectInitializer, child++, false, null)); 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 82b9899598d..10f4df8bf7f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/BaseObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/BaseObjectCreation.cs @@ -46,10 +46,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions switch (Syntax.Initializer.Kind()) { case SyntaxKind.CollectionInitializerExpression: - CollectionInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1) { Type = Type }); + CollectionInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1).SetType(Type)); break; case SyntaxKind.ObjectInitializerExpression: - ObjectInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1) { Type = Type }); + ObjectInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1).SetType(Type)); break; default: cx.ModelError("Unhandled initializer in object creation"); 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 7fe552ec8e9..a1555805640 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs @@ -20,6 +20,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case TypePatternSyntax typePattern: return Expressions.TypeAccess.Create(cx, typePattern.Type, parent, child); + case UnaryPatternSyntax unaryPattern: + return new UnaryPattern(cx, unaryPattern, parent, child); + case DeclarationPatternSyntax declPattern: // Creates a single local variable declaration. { @@ -27,7 +30,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { if (cx.GetModel(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol) { - var type = Type.Create(cx, symbol.GetAnnotatedType()); + var type = symbol.GetAnnotatedType(); return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.Create(syntax.GetLocation()), false, parent, child); } if (designation is DiscardDesignationSyntax) @@ -42,6 +45,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case RecursivePatternSyntax recPattern: return new RecursivePattern(cx, recPattern, parent, child); + case RelationalPatternSyntax relPattern: + return new RelationalPattern(cx, relPattern, parent, child); + case VarPatternSyntax varPattern: switch (varPattern.Designation) { @@ -50,7 +56,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case SingleVariableDesignationSyntax varDesignation: if (cx.GetModel(syntax).GetDeclaredSymbol(varDesignation) is ILocalSymbol symbol) { - var type = Type.Create(cx, symbol.GetAnnotatedType()); + var type = symbol.GetAnnotatedType(); return VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), true, parent, child); } 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 b65b9020743..0f3c2bf8800 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, Entities.NullType.Create(cx), cx.Create(posPc.GetLocation()), ExprKind.POSITIONAL_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.Create(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 147ac595c77..ed947990045 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, Entities.NullType.Create(cx), cx.Create(pp.GetLocation()), ExprKind.PROPERTY_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.Create(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 997c622c818..02246311648 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs @@ -15,9 +15,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions /// The syntax node of the recursive pattern. /// The parent pattern/expression. /// The child index of this pattern. - /// If this pattern is in the top level of a case/is. In that case, the variable and type access are populated elsewhere. public RecursivePattern(Context cx, RecursivePatternSyntax syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, Entities.NullType.Create(cx), cx.Create(syntax.GetLocation()), ExprKind.RECURSIVE_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), ExprKind.RECURSIVE_PATTERN, parent, child, false, null)) { // Extract the type access if (syntax.Type is TypeSyntax t) @@ -26,7 +25,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions // Extract the local variable declaration if (syntax.Designation is VariableDesignationSyntax designation && cx.GetModel(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol) { - var type = Entities.Type.Create(cx, symbol.GetAnnotatedType()); + var type = symbol.GetAnnotatedType(); VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), false, this, 0); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs new file mode 100644 index 00000000000..77efd5668c4 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs @@ -0,0 +1,29 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp; +using Semmle.Extraction.Kinds; +using Semmle.Extraction.Entities; + +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)) + { + Expression.Create(cx, syntax.Expression, this, 0); + } + + private static ExprKind GetKind(SyntaxToken operatorToken) + { + return operatorToken.Kind() switch + { + SyntaxKind.LessThanEqualsToken => ExprKind.LE_PATTERN, + SyntaxKind.GreaterThanEqualsToken => ExprKind.GE_PATTERN, + SyntaxKind.LessThanToken => ExprKind.LT_PATTERN, + SyntaxKind.GreaterThanToken => ExprKind.GT_PATTERN, + _ => throw new InternalError(operatorToken.Parent, $"Relation pattern with operator token '{operatorToken.Kind()}' is not supported."), + }; + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs new file mode 100644 index 00000000000..d80c390efff --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs @@ -0,0 +1,15 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.Entities; +using Semmle.Extraction.Kinds; + +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)) + { + Pattern.Create(cx, syntax.Pattern, this, 0); + } + } +} \ No newline at end of file diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs index 83c4a25d3a4..1db6c39fef2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs @@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private class QueryCall : Expression { public QueryCall(Context cx, IMethodSymbol method, SyntaxNode clause, IExpressionParentEntity parent, int child) - : base(new ExpressionInfo(cx, method is null ? NullType.Create(cx) : Entities.Type.Create(cx, method.GetAnnotatedReturnType()), + : base(new ExpressionInfo(cx, method?.GetAnnotatedReturnType(), cx.Create(clause.GetLocation()), ExprKind.METHOD_INVOCATION, parent, child, false, null)) { @@ -63,21 +63,21 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected Expression DeclareRangeVariable(Context cx, IExpressionParentEntity parent, int child, bool getElement, ISymbol variableSymbol, SyntaxToken name) { - var type = Type.Create(cx, cx.GetType(Expr)); + var type = cx.GetType(Expr); - AnnotatedType declType; + AnnotatedTypeSymbol? declType; TypeSyntax declTypeSyntax = null; if (getElement) { if (node is FromClauseSyntax from && from.Type != null) { declTypeSyntax = from.Type; - declType = Type.Create(cx, cx.GetType(from.Type)); + declType = cx.GetType(from.Type); } else { declTypeSyntax = null; - declType = type.Type.ElementType; + declType = GetElementType(cx, type.Symbol); } } else @@ -104,6 +104,36 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return decl; } + private static AnnotatedTypeSymbol? GetEnumerableType(Context cx, INamedTypeSymbol type) + { + return type.SpecialType == SpecialType.System_Collections_IEnumerable + ? cx.Compilation.ObjectType.WithAnnotation(NullableAnnotation.NotAnnotated) + : type.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T + ? type.GetAnnotatedTypeArguments().First() + : (AnnotatedTypeSymbol?)null; + } + + private static AnnotatedTypeSymbol? GetEnumerableElementType(Context cx, INamedTypeSymbol type) + { + var et = GetEnumerableType(cx, type); + if (et != null) + return et; + + return type.AllInterfaces + .Where(i => i.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T) + .Concat(type.AllInterfaces.Where(i => i.SpecialType == SpecialType.System_Collections_IEnumerable)) + .Select(i => GetEnumerableType(cx, i)) + .FirstOrDefault(); + } + + private static AnnotatedTypeSymbol? GetElementType(Context cx, ITypeSymbol symbol) => + symbol switch + { + IArrayTypeSymbol a => a.GetAnnotatedElementType(), + INamedTypeSymbol n => GetEnumerableElementType(cx, n), + _ => null + }; + protected void PopulateArguments(Context cx, QueryCall callExpr, int child) { foreach (var e in arguments) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs index 3585996c7db..5fdc08c66d3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs @@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { internal SwitchCase(Context cx, SwitchExpressionArmSyntax arm, Switch parent, int child) : base(new ExpressionInfo( - cx, Entities.Type.Create(cx, cx.GetType(arm.Expression)), cx.Create(arm.GetLocation()), + cx, cx.GetType(arm.Expression), cx.Create(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/This.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs index 838e494ff00..a13c2cb95bc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/This.cs @@ -7,8 +7,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { private This(IExpressionInfo info) : base(info) { } - public static This CreateImplicit(Context cx, Type @class, Extraction.Entities.Location loc, IExpressionParentEntity parent, int child) => - new This(new ExpressionInfo(cx, new AnnotatedType(@class, NullableAnnotation.None), loc, Kinds.ExprKind.THIS_ACCESS, parent, child, true, null)); + public static This CreateImplicit(Context cx, ITypeSymbol @class, Extraction.Entities.Location loc, IExpressionParentEntity parent, int child) => + new This(new ExpressionInfo(cx, AnnotatedTypeSymbol.CreateNotAnnotated(@class), loc, Kinds.ExprKind.THIS_ACCESS, parent, child, true, null)); public static This CreateExplicit(ExpressionNodeInfo info) => new This(info.SetKind(ExprKind.THIS_ACCESS)); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs index 334ae764d26..e5c0fd3ac66 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs @@ -15,7 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { case SyntaxKind.SimpleMemberAccessExpression: var maes = (MemberAccessExpressionSyntax)Syntax; - if (Type.Type.ContainingType == null) + if (Type?.Symbol.ContainingType is null) { // namespace qualifier TypeMention.Create(cx, maes.Name, this, Type, Syntax.GetLocation()); @@ -39,7 +39,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var typeAccessInfo = new ExpressionInfo( cx, - new AnnotatedType(Entities.Type.Create(cx, type), Microsoft.CodeAnalysis.NullableAnnotation.None), + AnnotatedTypeSymbol.CreateNotAnnotated(type), location, ExprKind.TYPE_ACCESS, parent, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs index e99b7d8b324..686e4156528 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs @@ -21,7 +21,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var info = new ExpressionInfo( cx, - new AnnotatedType(Entities.Type.Create(cx, type), Microsoft.CodeAnalysis.NullableAnnotation.None), + AnnotatedTypeSymbol.CreateNotAnnotated(type), location, ExprKind.TYPEOF, parent, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs index 84b61956ae6..349236e893a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs @@ -11,7 +11,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { private VariableDeclaration(IExpressionInfo info) : base(info) { } - public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedType type, TypeSyntax optionalSyntax, Extraction.Entities.Location exprLocation, bool isVar, IExpressionParentEntity parent, int child) + public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedTypeSymbol? type, TypeSyntax optionalSyntax, Extraction.Entities.Location exprLocation, bool isVar, IExpressionParentEntity parent, int child) { var ret = new VariableDeclaration(new ExpressionInfo(cx, type, exprLocation, ExprKind.LOCAL_VAR_DECL, parent, child, false, null)); cx.Try(null, null, () => @@ -30,10 +30,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (variableSymbol == null) { cx.ModelError(node, "Failed to determine local variable"); - return Create(cx, node, NullType.Create(cx), parent, child); + return Create(cx, node, (AnnotatedTypeSymbol?)null, parent, child); } - var type = Entities.Type.Create(cx, variableSymbol.GetAnnotatedType()); + var type = variableSymbol.GetAnnotatedType(); var ret = Create(cx, designation, type, parent, child); cx.Try(null, null, () => { @@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions /// public static Expression CreateParenthesized(Context cx, DeclarationExpressionSyntax node, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child) { - var type = Entities.NullType.Create(cx); // Should ideally be a corresponding tuple type + 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)); cx.Try(null, null, () => @@ -64,7 +64,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPattern, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child) { - var type = NullType.Create(cx); // Should ideally be a corresponding tuple type + 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)); cx.Try(null, null, () => @@ -80,7 +80,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case SingleVariableDesignationSyntax single: if (cx.GetModel(variable).GetDeclaredSymbol(single) is ILocalSymbol local) { - var decl = Create(cx, variable, Entities.Type.Create(cx, local.GetAnnotatedType()), tuple, child0++); + var decl = Create(cx, variable, local.GetAnnotatedType(), tuple, child0++); var l = LocalVariable.Create(cx, local); l.PopulateManual(decl, true); } @@ -111,25 +111,24 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case ParenthesizedVariableDesignationSyntax paren: return CreateParenthesized(cx, node, paren, parent, child); case DiscardDesignationSyntax discard: - var ti = cx.GetType(discard); - var type = Entities.Type.Create(cx, ti); + var type = cx.GetType(discard); return Create(cx, node, type, parent, child); default: cx.ModelError(node, "Failed to determine designation type"); - return Create(cx, node, NullType.Create(cx), parent, child); + return Create(cx, node, null, parent, child); } } public static Expression Create(Context cx, DeclarationExpressionSyntax node, IExpressionParentEntity parent, int child) => Create(cx, node, node.Designation, parent, child); - public static VariableDeclaration Create(Context cx, CSharpSyntaxNode c, AnnotatedType type, IExpressionParentEntity parent, int 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)); public static VariableDeclaration Create(Context cx, CatchDeclarationSyntax d, bool isVar, IExpressionParentEntity parent, int child) { var symbol = cx.GetModel(d).GetDeclaredSymbol(d); - var type = Entities.Type.Create(cx, symbol.GetAnnotatedType()); + var type = symbol.GetAnnotatedType(); var ret = Create(cx, d, type, parent, child); cx.Try(d, null, () => { @@ -141,7 +140,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return ret; } - public static VariableDeclaration CreateDeclarator(Context cx, VariableDeclaratorSyntax d, AnnotatedType type, bool isVar, IExpressionParentEntity parent, int child) + public static VariableDeclaration CreateDeclarator(Context cx, VariableDeclaratorSyntax d, AnnotatedTypeSymbol type, bool isVar, IExpressionParentEntity parent, int child) { var ret = Create(cx, d, type, parent, child); cx.Try(d, null, () => @@ -170,7 +169,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { public static void Populate(Context cx, VariableDeclarationSyntax decl, IExpressionParentEntity parent, int child, int childIncrement = 1) { - var type = Type.Create(cx, cx.GetType(decl.Type)); + var type = cx.GetType(decl.Type); foreach (var v in decl.Variables) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs index 2990332648d..aadd9d2fbab 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.GetAnnotatedType())); + type = new Lazy(() => Entities.Type.Create(cx, symbol.Type)); } public static Field Create(Context cx, IFieldSymbol field) => FieldFactory.Instance.CreateEntityFromSymbol(cx, field); @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulateNullability(trapFile, symbol.GetAnnotatedType()); var unboundFieldKey = Field.Create(Context, symbol.OriginalDefinition); - trapFile.fields(this, (symbol.IsConst ? 2 : 1), symbol.Name, ContainingType, Type.Type.TypeRef, unboundFieldKey); + trapFile.fields(this, (symbol.IsConst ? 2 : 1), symbol.Name, ContainingType, Type.TypeRef, unboundFieldKey); PopulateModifiers(trapFile); @@ -71,7 +71,7 @@ namespace Semmle.Extraction.CSharp.Entities if (!symbol.IsStatic) { - This.CreateImplicit(Context, Entities.Type.Create(Context, symbol.ContainingType), Location, fieldAccess, -1); + This.CreateImplicit(Context, symbol.ContainingType, Location, fieldAccess, -1); } }); } @@ -107,19 +107,20 @@ namespace Semmle.Extraction.CSharp.Entities private Expression AddInitializerAssignment(TextWriter trapFile, ExpressionSyntax initializer, Extraction.Entities.Location loc, string constValue, ref int child) { - var simpleAssignExpr = new Expression(new ExpressionInfo(Context, Type, loc, ExprKind.SIMPLE_ASSIGN, this, child++, false, constValue)); + 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)); + var access = new Expression(new ExpressionInfo(Context, type, Location, ExprKind.FIELD_ACCESS, simpleAssignExpr, 1, false, constValue)); trapFile.expr_access(access, this); return access; } - private readonly Lazy type; - public AnnotatedType Type => type.Value; + private readonly Lazy type; + public Type Type => type.Value; public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(Type.Type); + trapFile.WriteSubId(Type); trapFile.Write(" "); trapFile.WriteSubId(ContainingType); trapFile.Write('.'); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs index 5873d3e19f4..70b15a6fe16 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Indexer.cs @@ -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) { Type = Type.Create(Context, symbol.GetAnnotatedType()) })); + Context.PopulateLater(() => Expression.CreateFromNode(new ExpressionNodeInfo(Context, expressionBody, this, 0).SetType(symbol.GetAnnotatedType()))); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs index 309feabfe3d..921036250d1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs @@ -39,7 +39,7 @@ namespace Semmle.Extraction.CSharp.Entities 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); + 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 de44b16d69f..e988ec2c815 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalVariable.cs @@ -24,9 +24,9 @@ namespace Semmle.Extraction.CSharp.Entities { var trapFile = Context.TrapWriter.Writer; var (kind, type) = symbol is ILocalSymbol l - ? (l.IsRef ? 3 : l.IsConst ? 2 : 1, Type.Create(Context, l.GetAnnotatedType())) + ? (l.IsRef ? 3 : l.IsConst ? 2 : 1, l.GetAnnotatedType()) : (1, parent.Type); - trapFile.localvars(this, kind, symbol.Name, isVar ? 1 : 0, type.Type.TypeRef, parent); + trapFile.localvars(this, kind, symbol.Name, isVar ? 1 : 0, Type.Create(Context, type).TypeRef, parent); if (symbol is ILocalSymbol local) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 94e8c838e7b..6a52087e384 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -40,7 +40,9 @@ namespace Semmle.Extraction.CSharp.Entities foreach (var p in parameters.Zip(originalParameters, (paramSymbol, originalParam) => new { paramSymbol, originalParam })) { - var original = SymbolEqualityComparer.Default.Equals(p.paramSymbol, p.originalParam) ? null : Parameter.Create(Context, p.originalParam, originalMethod); + var original = SymbolEqualityComparer.Default.Equals(p.paramSymbol, p.originalParam) + ? null + : Parameter.Create(Context, p.originalParam, originalMethod); Parameter.Create(Context, p.paramSymbol, this, original); } @@ -110,7 +112,7 @@ namespace Semmle.Extraction.CSharp.Entities /// /// Factored out to share logic between `Method` and `UserOperator`. /// - protected static void BuildMethodId(Method m, TextWriter trapFile) + private static void BuildMethodId(Method m, TextWriter trapFile) { m.symbol.ReturnType.BuildOrWriteId(m.Context, trapFile, m.symbol); trapFile.Write(" "); @@ -324,12 +326,12 @@ namespace Semmle.Extraction.CSharp.Entities } } - protected void ExtractRefReturn(TextWriter trapFile) + public static void ExtractRefReturn(TextWriter trapFile, IMethodSymbol method, IEntity element) { - if (symbol.ReturnsByRef) - trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref); - if (symbol.ReturnsByRefReadonly) - trapFile.type_annotation(this, Kinds.TypeAnnotation.ReadonlyRef); + if (method.ReturnsByRef) + trapFile.type_annotation(element, Kinds.TypeAnnotation.Ref); + if (method.ReturnsByRefReadonly) + trapFile.type_annotation(element, Kinds.TypeAnnotation.ReadonlyRef); } protected void PopulateMethod(TextWriter trapFile) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs index dbeab838b25..d81fc25f72b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs @@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulateGenerics(trapFile); Overrides(trapFile); - ExtractRefReturn(trapFile); + ExtractRefReturn(trapFile, symbol, this); ExtractCompilerGenerated(trapFile); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index 739708138ad..08d5ae47c5e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -85,14 +85,14 @@ namespace Semmle.Extraction.CSharp.Entities Context.PopulateLater(() => { var loc = Context.Create(initializer.GetLocation()); - var annotatedType = new AnnotatedType(type, NullableAnnotation.None); + 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) { - This.CreateImplicit(Context, Type.Create(Context, symbol.ContainingType), Location, access, -1); + This.CreateImplicit(Context, symbol.ContainingType, Location, access, -1); } }); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs index 13cc39f7fea..db1a0d413c1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs @@ -20,11 +20,11 @@ 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, decl.Type.Type.TypeRef, true); + trapFile.catch_type(this, Type.Create(cx, 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)).Type.TypeRef, true); + trapFile.catch_type(this, Type.Create(cx, cx.GetType(Stmt.Declaration.Type)).TypeRef, true); } else // A catch clause of the form 'catch { ... }' { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs index 653ed384e7b..262b3f0e328 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements Expression.Create(cx, Stmt.Expression, this, 1); var typeSymbol = cx.GetModel(Stmt).GetDeclaredSymbol(Stmt); - var type = Type.Create(cx, typeSymbol.GetAnnotatedType()); + var type = typeSymbol.GetAnnotatedType(); var location = cx.Create(Stmt.Identifier.GetLocation()); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs index 4f1e166b8dc..8d6074f3e8d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs @@ -47,7 +47,7 @@ namespace Semmle.Extraction.CSharp.Entities switch (type) { case ArrayType at: - return GetArrayElementType(at.ElementType.Type); + return GetArrayElementType(at.ElementType); case NamedType nt when nt.symbol.IsBoundSpan() || nt.symbol.IsBoundReadOnlySpan(): return nt.TypeArguments.Single(); @@ -128,8 +128,8 @@ namespace Semmle.Extraction.CSharp.Entities return ret; } - public static TypeMention Create(Context cx, TypeSyntax syntax, IEntity parent, AnnotatedType type, Microsoft.CodeAnalysis.Location loc = null) => - Create(cx, syntax, parent, type.Type, loc); + public static TypeMention Create(Context cx, TypeSyntax syntax, IEntity parent, AnnotatedTypeSymbol? type, Microsoft.CodeAnalysis.Location loc = null) => + Create(cx, syntax, parent, Type.Create(cx, type?.Symbol), loc); public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs index 2c617158219..4ec1db558e5 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using Microsoft.CodeAnalysis; @@ -8,16 +9,16 @@ namespace Semmle.Extraction.CSharp.Entities private ArrayType(Context cx, IArrayTypeSymbol init) : base(cx, init) { - element = Create(cx, symbol.GetAnnotatedElementType()); + elementLazy = new Lazy(() => Create(cx, symbol.ElementType)); } - private readonly AnnotatedType element; + private readonly Lazy elementLazy; public int Rank => symbol.Rank; - public override AnnotatedType ElementType => element; + public Type ElementType => elementLazy.Value; - public override int Dimension => 1 + element.Type.Dimension; + public override int Dimension => 1 + ElementType.Dimension; // All array types are extracted because they won't // be extracted in their defining assembly. @@ -25,18 +26,19 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate(TextWriter trapFile) { - trapFile.array_element_type(this, Dimension, Rank, element.Type.TypeRef); + trapFile.array_element_type(this, Dimension, Rank, ElementType.TypeRef); PopulateType(trapFile); } public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(element.Type); + trapFile.WriteSubId(ElementType); symbol.BuildArraySuffix(trapFile); trapFile.Write(";type"); } - public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol); + public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => + ArrayTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol); private class ArrayTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/FunctionPointerType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/FunctionPointerType.cs new file mode 100644 index 00000000000..1bf68a4c3c2 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/FunctionPointerType.cs @@ -0,0 +1,42 @@ +using System.IO; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class FunctionPointerType : Type + { + private FunctionPointerType(Context cx, IFunctionPointerTypeSymbol init) + : base(cx, init) + { + } + + public override void WriteId(TextWriter trapFile) + { + symbol.BuildTypeId(Context, trapFile, symbol); + trapFile.Write(";functionpointertype"); + } + + public override bool NeedsPopulation => true; + + 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.has_unmanaged_calling_conventions(this, i, conv.TypeRef); + } + + PopulateType(trapFile); + } + + public static FunctionPointerType Create(Context cx, IFunctionPointerTypeSymbol symbol) => FunctionPointerTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol); + + private class FunctionPointerTypeFactory : ICachedEntityFactory + { + public static FunctionPointerTypeFactory Instance { get; } = new FunctionPointerTypeFactory(); + + public FunctionPointerType Create(Context cx, IFunctionPointerTypeSymbol init) => new FunctionPointerType(cx, init); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index bc48b30091c..bded5f60c57 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -149,36 +149,6 @@ namespace Semmle.Extraction.CSharp.Entities base.WriteQuotedId(trapFile); } - /// - /// Returns the element type in an Enumerable/IEnumerable - /// - /// Extraction context. - /// The enumerable type. - /// The element type, or null. - private static AnnotatedTypeSymbol GetElementType(Context cx, INamedTypeSymbol type) - { - var et = GetEnumerableType(cx, type); - if (et.Symbol != null) - return et; - - return type.AllInterfaces - .Where(i => i.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T) - .Concat(type.AllInterfaces.Where(i => i.SpecialType == SpecialType.System_Collections_IEnumerable)) - .Select(i => GetEnumerableType(cx, i)) - .FirstOrDefault(); - } - - private static AnnotatedTypeSymbol GetEnumerableType(Context cx, INamedTypeSymbol type) - { - return type.SpecialType == SpecialType.System_Collections_IEnumerable - ? cx.Compilation.ObjectType.WithAnnotation(NullableAnnotation.NotAnnotated) - : type.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T - ? type.GetAnnotatedTypeArguments().First() - : default(AnnotatedTypeSymbol); - } - - public override AnnotatedType ElementType => Type.Create(Context, GetElementType(Context, symbol)); - private class NamedTypeFactory : ICachedEntityFactory { public static NamedTypeFactory Instance { get; } = new NamedTypeFactory(); @@ -235,5 +205,5 @@ namespace Semmle.Extraction.CSharp.Entities { trapFile.typerefs(this, symbol.Name); } - }; + } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs index 2822e346384..33f7c44d21f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs @@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities return obj != null && obj.GetType() == typeof(NullType); } - public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateEntity(cx, typeof(NullType), null), NullableAnnotation.None); + public static Type Create(Context cx) => NullTypeFactory.Instance.CreateEntity(cx, typeof(NullType), null); private class NullTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index af9c4bf4fa6..4ddc258f5c7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -59,6 +59,6 @@ namespace Semmle.Extraction.CSharp.Entities private readonly Lazy tupleElementsLazy; public Field[] TupleElements => tupleElementsLazy.Value; - public override IEnumerable TypeMentions => TupleElements.Select(e => e.Type.Type); + public override IEnumerable TypeMentions => TupleElements.Select(e => e.Type); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 1b1d205b3d7..8c96a334565 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -1,42 +1,18 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Util; +using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace Semmle.Extraction.CSharp.Entities { - /// - /// Represents an annotated type consisting of a type entity and nullability information. - /// - public struct AnnotatedType - { - public AnnotatedType(Type t, NullableAnnotation n) - { - Type = t; - annotation = n; - } - - /// - /// The underlying type. - /// - public Type Type { get; private set; } - - private readonly NullableAnnotation annotation; - - /// - /// Gets the annotated type symbol of this annotated type. - /// - public AnnotatedTypeSymbol Symbol => new AnnotatedTypeSymbol(Type.symbol, annotation); - } - public abstract class Type : CachedSymbol { protected Type(Context cx, ITypeSymbol init) : base(cx, init) { } - public virtual AnnotatedType ElementType => default(AnnotatedType); public override bool NeedsPopulation => base.NeedsPopulation || symbol.TypeKind == TypeKind.Dynamic || symbol.TypeKind == TypeKind.TypeParameter; @@ -82,6 +58,7 @@ namespace Semmle.Extraction.CSharp.Entities case TypeKind.Enum: return Kinds.TypeKind.ENUM; case TypeKind.Delegate: return Kinds.TypeKind.DELEGATE; case TypeKind.Pointer: return Kinds.TypeKind.POINTER; + case TypeKind.FunctionPointer: return Kinds.TypeKind.FUNCTION_POINTER; case TypeKind.Error: return Kinds.TypeKind.UNKNOWN; default: cx.ModelError(t, $"Unhandled type kind '{t.TypeKind}'"); @@ -156,23 +133,14 @@ namespace Semmle.Extraction.CSharp.Entities // This is a delegate. // The method "Invoke" has the return type. var invokeMethod = ((INamedTypeSymbol)symbol).DelegateInvokeMethod; + ExtractParametersForDelegateLikeType(trapFile, invokeMethod, + t => trapFile.delegate_return_type(this, t)); + } - // Copy the parameters from the "Invoke" method to the delegate type - for (var i = 0; i < invokeMethod.Parameters.Length; ++i) - { - var param = invokeMethod.Parameters[i]; - 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, param, this, originalParamEntity); - } - - var returnKey = Create(Context, invokeMethod.ReturnType); - trapFile.delegate_return_type(this, returnKey.TypeRef); - if (invokeMethod.ReturnsByRef) - trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref); - if (invokeMethod.ReturnsByRefReadonly) - trapFile.type_annotation(this, Kinds.TypeAnnotation.ReadonlyRef); + if (symbol is IFunctionPointerTypeSymbol functionPointer) + { + ExtractParametersForDelegateLikeType(trapFile, functionPointer.Signature, + t => trapFile.function_pointer_return_type(this, t)); } Modifier.ExtractModifiers(Context, trapFile, this, symbol); @@ -195,6 +163,23 @@ namespace Semmle.Extraction.CSharp.Entities } } + private void ExtractParametersForDelegateLikeType(TextWriter trapFile, IMethodSymbol invokeMethod, Action storeReturnType) + { + for (var i = 0; i < invokeMethod.Parameters.Length; ++i) + { + var param = invokeMethod.Parameters[i]; + 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, param, this, originalParamEntity); + } + + var returnKey = Create(Context, invokeMethod.ReturnType); + storeReturnType(returnKey.TypeRef); + Method.ExtractRefReturn(trapFile, invokeMethod, this); + } + /// /// Called to extract all members and nested types. /// This is called on each member of a namespace, @@ -277,12 +262,12 @@ namespace Semmle.Extraction.CSharp.Entities { type = type.DisambiguateType(); return type == null - ? NullType.Create(cx).Type + ? NullType.Create(cx) : (Type)cx.CreateEntity(type); } - public static AnnotatedType Create(Context cx, AnnotatedTypeSymbol type) => - new AnnotatedType(Create(cx, type.Symbol), type.Nullability); + public static Type Create(Context cx, AnnotatedTypeSymbol? type) => + Create(cx, type?.Symbol); public virtual int Dimension => 0; @@ -290,8 +275,7 @@ namespace Semmle.Extraction.CSharp.Entities symbol != null && symbol.TypeKind == TypeKind.Delegate; /// - /// A copy of a delegate "Invoke" method parameter used for the delgate - /// type. + /// A copy of a delegate "Invoke" method or function pointer parameter. /// private class DelegateTypeParameter : Parameter { @@ -331,10 +315,10 @@ namespace Semmle.Extraction.CSharp.Entities public override bool Equals(object obj) { var other = obj as Type; - return other?.GetType() == GetType() && SymbolEqualityComparer.IncludeNullability.Equals(other.symbol, symbol); + return other?.GetType() == GetType() && SymbolEqualityComparer.Default.Equals(other.symbol, symbol); } - public override int GetHashCode() => SymbolEqualityComparer.IncludeNullability.GetHashCode(symbol); + public override int GetHashCode() => SymbolEqualityComparer.Default.GetHashCode(symbol); } internal abstract class Type : Type where T : ITypeSymbol diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs index f46ed47ff5f..4dce36430d3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs @@ -115,6 +115,12 @@ namespace Semmle.Extraction.Kinds SWITCH_CASE = 118, ASSIGN_COALESCE = 119, SUPPRESS_NULLABLE_WARNING = 120, - NAMESPACE_ACCESS = 121 + NAMESPACE_ACCESS = 121, + LT_PATTERN = 122, + GT_PATTERN = 123, + LE_PATTERN = 124, + GE_PATTERN = 125, + NOT_PATTERN = 126, + FUNCTION_POINTER_INVOCATION = 129, } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/TypeKind.cs b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/TypeKind.cs index fb205a6646e..01fad60e003 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/TypeKind.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/TypeKind.cs @@ -34,6 +34,7 @@ namespace Semmle.Extraction.Kinds // lgtm[cs/similar-file] DYNAMIC = 29, ARGLIST = 30, UNKNOWN = 31, - TUPLE = 32 + TUPLE = 32, + FUNCTION_POINTER = 33 } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Symbols.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Symbols.cs index ddf64257cbe..a4a06fd6ba2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Symbols.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Symbols.cs @@ -38,6 +38,8 @@ namespace Semmle.Extraction.CSharp.Populators public override IEntity VisitPointerType(IPointerTypeSymbol symbol) => PointerType.Create(cx, symbol); + public override IEntity VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol) => FunctionPointerType.Create(cx, symbol); + public override IEntity VisitDynamicType(IDynamicTypeSymbol symbol) => DynamicType.Create(cx, symbol); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index 530a30d8a51..77e27a00be5 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -23,6 +23,9 @@ namespace Semmle.Extraction.CSharp Symbol = symbol; Nullability = nullability; } + + public static AnnotatedTypeSymbol? CreateNotAnnotated(ITypeSymbol symbol) => + symbol is null ? (AnnotatedTypeSymbol?)null : new AnnotatedTypeSymbol(symbol, NullableAnnotation.None); } internal static class SymbolExtensions @@ -131,6 +134,13 @@ namespace Semmle.Extraction.CSharp return tp.ContainingSymbol is ITypeSymbol cont ? IdDependsOnImpl(cont) : SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, symbol); + case TypeKind.FunctionPointer: + var funptr = (IFunctionPointerTypeSymbol)type; + if (funptr.Signature.Parameters.Any(p => IdDependsOnImpl(p.Type))) + { + return true; + } + return IdDependsOnImpl(funptr.Signature.ReturnType); default: return false; } @@ -187,6 +197,10 @@ namespace Semmle.Extraction.CSharp case TypeKind.Dynamic: trapFile.Write("dynamic"); return; + case TypeKind.FunctionPointer: + var funptr = (IFunctionPointerTypeSymbol)type; + funptr.BuildFunctionPointerTypeId(cx, trapFile, symbolBeingDefined); + return; default: throw new InternalError(type, $"Unhandled type kind '{type.TypeKind}'"); } @@ -262,6 +276,11 @@ namespace Semmle.Extraction.CSharp trapFile.Write("::"); } + private static void BuildFunctionPointerTypeId(this IFunctionPointerTypeSymbol funptr, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined) + { + BuildFunctionPointerSignature(funptr, trapFile, (s, tw) => s.BuildOrWriteId(cx, tw, symbolBeingDefined)); + } + private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType) { if (!constructUnderlyingTupleType && named.IsTupleType) @@ -391,6 +410,10 @@ namespace Semmle.Extraction.CSharp ptr.PointedAtType.BuildDisplayName(cx, trapFile); trapFile.Write('*'); return; + case TypeKind.FunctionPointer: + var funptr = (IFunctionPointerTypeSymbol)type; + funptr.BuildFunctionPointerTypeDisplayName(cx, trapFile); + return; case TypeKind.TypeParameter: trapFile.Write(type.Name); return; @@ -403,31 +426,93 @@ namespace Semmle.Extraction.CSharp } } - public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, TextWriter trapFile, bool constructUnderlyingTupleType) + public static void BuildFunctionPointerSignature(IFunctionPointerTypeSymbol funptr, TextWriter trapFile, + Action buildNested) + { + trapFile.Write("delegate* "); + trapFile.Write(funptr.Signature.CallingConvention.ToString().ToLowerInvariant()); + + if (funptr.Signature.UnmanagedCallingConventionTypes.Any()) + { + trapFile.Write('['); + trapFile.BuildList(",", funptr.Signature.UnmanagedCallingConventionTypes, buildNested); + trapFile.Write("]"); + } + + trapFile.Write('<'); + trapFile.BuildList(",", funptr.Signature.Parameters, + (p, trap) => + { + buildNested(p.Type, trap); + switch (p.RefKind) + { + case RefKind.Out: + trap.Write(" out"); + break; + case RefKind.In: + trap.Write(" in"); + break; + case RefKind.Ref: + trap.Write(" ref"); + break; + } + }); + + if (funptr.Signature.Parameters.Any()) + { + trapFile.Write(","); + } + + buildNested(funptr.Signature.ReturnType, trapFile); + + if (funptr.Signature.ReturnsByRef) + trapFile.Write(" ref"); + if (funptr.Signature.ReturnsByRefReadonly) + trapFile.Write(" ref readonly"); + + trapFile.Write('>'); + } + + private static void BuildFunctionPointerTypeDisplayName(this IFunctionPointerTypeSymbol funptr, Context cx, TextWriter trapFile) + { + BuildFunctionPointerSignature(funptr, trapFile, (s, tw) => s.BuildDisplayName(cx, tw)); + } + + private static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, TextWriter trapFile, bool constructUnderlyingTupleType) { if (!constructUnderlyingTupleType && namedType.IsTupleType) { trapFile.Write('('); - trapFile.BuildList(",", namedType.TupleElements.Select(f => f.Type), - (t, tb0) => t.BuildDisplayName(cx, tb0) - ); - + trapFile.BuildList( + ",", + namedType.TupleElements.Select(f => f.Type), + (t, tb0) => t.BuildDisplayName(cx, tb0)); trapFile.Write(")"); return; } if (namedType.IsAnonymousType) + { namedType.BuildAnonymousName(cx, trapFile); + } else + { trapFile.Write(namedType.Name); + } + if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any()) { trapFile.Write('<'); - trapFile.BuildList(",", namedType.TypeArguments, (p, tb0) => - { - if (IsReallyBound(namedType)) - p.BuildDisplayName(cx, tb0); - }); + trapFile.BuildList( + ",", + namedType.TypeArguments, + (p, tb0) => + { + if (IsReallyBound(namedType)) + { + p.BuildDisplayName(cx, tb0); + } + }); trapFile.Write('>'); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 254aa367570..630c2848e3d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -111,6 +111,11 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("compilations", compilation, cwd); } + internal static void compilation_assembly(this TextWriter trapFile, Compilation compilation, Assembly assembly) + { + trapFile.WriteTuple("compilation_assembly", compilation, assembly); + } + internal static void compiler_generated(this TextWriter trapFile, IEntity entity) { trapFile.WriteTuple("compiler_generated", entity); @@ -146,6 +151,11 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("delegate_return_type", delegateKey, returnType); } + internal static void function_pointer_return_type(this TextWriter trapFile, Type functionPointer, Type returnType) + { + trapFile.WriteTuple("function_pointer_return_type", functionPointer, returnType); + } + internal static void destructor_location(this TextWriter trapFile, Destructor destructor, Location location) { trapFile.WriteTuple("destructor_location", destructor, location); @@ -471,6 +481,16 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("specific_type_parameter_nullability", constraints, baseType, nullability); } + internal static void function_pointer_calling_conventions(this TextWriter trapFile, FunctionPointerType type, int kind) + { + trapFile.WriteTuple("function_pointer_calling_conventions", type, kind); + } + + internal static void has_unmanaged_calling_conventions(this TextWriter trapFile, FunctionPointerType type, int index, Type convention) + { + trapFile.WriteTuple("has_unmanaged_calling_conventions", type, index, convention); + } + internal static void stackalloc_array_creation(this TextWriter trapFile, Expression array) { trapFile.WriteTuple("stackalloc_array_creation", array); diff --git a/csharp/extractor/Semmle.Extraction/AssemblyScope.cs b/csharp/extractor/Semmle.Extraction/AssemblyScope.cs index b2c947dea83..84c117d17c4 100644 --- a/csharp/extractor/Semmle.Extraction/AssemblyScope.cs +++ b/csharp/extractor/Semmle.Extraction/AssemblyScope.cs @@ -10,15 +10,12 @@ namespace Semmle.Extraction private readonly IAssemblySymbol assembly; private readonly string filepath; - public AssemblyScope(IAssemblySymbol symbol, string path, bool isOutput) + public AssemblyScope(IAssemblySymbol symbol, string path) { assembly = symbol; filepath = path; - IsGlobalScope = isOutput; } - public bool IsGlobalScope { get; } - public bool InFileScope(string path) => path == filepath; public bool InScope(ISymbol symbol) => diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index af254c817a3..cbb68e1a936 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -169,7 +169,7 @@ namespace Semmle.Extraction #endif private readonly IDictionary objectEntityCache = new Dictionary(); - private readonly IDictionary symbolEntityCache = new Dictionary(10000, SymbolEqualityComparer.IncludeNullability); + private readonly IDictionary symbolEntityCache = new Dictionary(10000, SymbolEqualityComparer.Default); private readonly HashSet