From 83e618d49e6f121be67ec24de407cc6caa98a0ba Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Fri, 7 Jun 2019 21:15:58 -0700 Subject: [PATCH 0001/1227] C++: Make cpp/comparison-with-wider-type visible The results from this query look good on real-world projects, so let's make it visible by default. --- change-notes/1.22/analysis-cpp.md | 1 + cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/change-notes/1.22/analysis-cpp.md b/change-notes/1.22/analysis-cpp.md index 19bb2898ec0..73c6a9e4060 100644 --- a/change-notes/1.22/analysis-cpp.md +++ b/change-notes/1.22/analysis-cpp.md @@ -15,6 +15,7 @@ | No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | False positives involving strings that are not null-terminated have been excluded. | | Suspicious pointer scaling (`cpp/suspicious-pointer-scaling`) | Lower precision | The precision of this query has been reduced to "medium". This coding pattern is used intentionally and safely in a number of real-world projects. Results are no longer displayed on LGTM unless you choose to display them. | | Non-constant format string (`cpp/non-constant-format`) | Fewer false positive results | Rewritten using the taint-tracking library. | +| Comparison of narrow type with wide type in loop condition (`cpp/comparison-with-wider-type`) | Higher precision | The precision of this query has been increased to "high" as the alerts from this query have proved to be valuable on real-world projects. With this precision, results are now displayed by default on LGTM. | ## Changes to QL libraries diff --git a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql index af343fc991f..5be8058ee7a 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql @@ -5,14 +5,13 @@ * @id cpp/comparison-with-wider-type * @kind problem * @problem.severity warning - * @precision medium + * @precision high * @tags reliability * security * external/cwe/cwe-190 * external/cwe/cwe-197 * external/cwe/cwe-835 - * -*/ + */ import cpp import semmle.code.cpp.controlflow.Dominance From 2ea0d5449004ccc3412355533ff3f0ae9729690b Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 10 Jul 2019 11:36:30 +0200 Subject: [PATCH 0002/1227] C++: wording: "in LGTM", not "on" Co-Authored-By: semmledocs-ac <42443977+semmledocs-ac@users.noreply.github.com> --- change-notes/1.22/analysis-cpp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.22/analysis-cpp.md b/change-notes/1.22/analysis-cpp.md index 73c6a9e4060..d7dafc65786 100644 --- a/change-notes/1.22/analysis-cpp.md +++ b/change-notes/1.22/analysis-cpp.md @@ -15,7 +15,7 @@ | No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | False positives involving strings that are not null-terminated have been excluded. | | Suspicious pointer scaling (`cpp/suspicious-pointer-scaling`) | Lower precision | The precision of this query has been reduced to "medium". This coding pattern is used intentionally and safely in a number of real-world projects. Results are no longer displayed on LGTM unless you choose to display them. | | Non-constant format string (`cpp/non-constant-format`) | Fewer false positive results | Rewritten using the taint-tracking library. | -| Comparison of narrow type with wide type in loop condition (`cpp/comparison-with-wider-type`) | Higher precision | The precision of this query has been increased to "high" as the alerts from this query have proved to be valuable on real-world projects. With this precision, results are now displayed by default on LGTM. | +| Comparison of narrow type with wide type in loop condition (`cpp/comparison-with-wider-type`) | Higher precision | The precision of this query has been increased to "high" as the alerts from this query have proved to be valuable on real-world projects. With this precision, results are now displayed by default in LGTM. | ## Changes to QL libraries From e8f867204d46bce3e0957ca1a149d28b36a66d5b Mon Sep 17 00:00:00 2001 From: james Date: Mon, 9 Sep 2019 10:53:56 +0100 Subject: [PATCH 0003/1227] docs: fix broken links in js topics --- docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst | 2 +- docs/language/learn-ql/javascript/introduce-libraries-js.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst index 17f3c0ee318..5159c26bf19 100644 --- a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst +++ b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst @@ -31,7 +31,7 @@ Use the following template to create a taint tracking path query: This query reports flow paths which: - Begin at a node matched by `isSource `__. -- Step through variables, function calls, properties, strings, arrays, promises, exceptions, and steps added by `isAdditionalTaintStep `__. +- Step through variables, function calls, properties, strings, arrays, promises, exceptions, and steps added by `isAdditionalTaintStep `__. - End at a node matched by `isSink `__. See also: `Global data flow `__ and :doc:`Constructing path queries <../writing-queries/path-queries>`. diff --git a/docs/language/learn-ql/javascript/introduce-libraries-js.rst b/docs/language/learn-ql/javascript/introduce-libraries-js.rst index 9c864400444..6137fdaa297 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-js.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-js.rst @@ -357,7 +357,7 @@ JavaScript provides several ways of defining functions: in ECMAScript 5, there a - ``Function.getId()`` returns the `Identifier `__ naming the function, which may not be defined for function expressions. - ``Function.getParameter(i)`` and ``Function.getAParameter()`` access the ``i``\ th parameter or any parameter, respectively; parameters are modeled by the class `Parameter `__, which is a subclass of `BindingPattern `__ (see below). -- ``Function.getBody()`` returns the body of the function, which is usually a `Stmt `__, but may be an `Expr `__ for arrow function expressions and legacy `expression closures `__. +- ``Function.getBody()`` returns the body of the function, which is usually a `Stmt `__, but may be an `Expr `__ for arrow function expressions and legacy `expression closures `__. As an example, here is a query that finds all expression closures: @@ -472,7 +472,7 @@ As an example of a query involving properties, consider the following query that Modules ^^^^^^^ -The JavaScript library has support for working with ECMAScript 2015 modules, as well as legacy CommonJS modules (still commonly employed by Node.js code bases) and AMD-style modules. The QL classes `ES2015Module `__, `NodeModule `__ and `AMDModule `__ represent these three types of modules, and all three extend the common superclass `Module `__. +The JavaScript library has support for working with ECMAScript 2015 modules, as well as legacy CommonJS modules (still commonly employed by Node.js code bases) and AMD-style modules. The QL classes `ES2015Module `__, `NodeModule `__, and `AMDModule `__ represent these three types of modules, and all three extend the common superclass `Module `__. The most important member predicates defined by `Module `__ are: From 0528d8ef397a9f17e39f140ff3123fae773cb14f Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Tue, 3 Sep 2019 15:35:56 +0100 Subject: [PATCH 0004/1227] C# IR: Object creation refactoring The way object creation was translated has been changed: now creations are treated as expressions. The main motivation for this was the inability to have creation expressions as arguments to function calls (a test case has been added to showcase this). All code that dealt with creation expressions has been moved from `TranslatedInitialization.qll` to `TranslatedExpr.qll`. Some light refactoring has also been done, mainly removing code that was useless after the changes mentioned above. --- .../raw/internal/TranslatedElement.qll | 19 +- .../raw/internal/TranslatedExpr.qll | 94 ++++++++- .../raw/internal/TranslatedInitialization.qll | 185 +++--------------- .../test/library-tests/ir/ir/obj_creation.cs | 6 + .../test/library-tests/ir/ir/raw_ir.expected | 116 ++++++----- 5 files changed, 197 insertions(+), 223 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll index 84f6b98df34..3814f939d28 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll @@ -169,6 +169,10 @@ newtype TTranslatedElement = not isNativeCondition(expr) and not isFlexibleCondition(expr) } or + // A creation expression + TTranslatedCreationExpr(Expr expr) { + not ignoreExpr(expr) + } or // A separate element to handle the lvalue-to-rvalue conversion step of an // expression. TTranslatedLoad(Expr expr) { @@ -219,32 +223,21 @@ newtype TTranslatedElement = // we deal with all the types of initialization separately. // First only simple local variable initialization (ie. `int x = 0`) exists(LocalVariableDeclAndInitExpr lvInit | - lvInit.getInitializer() = expr and - not expr instanceof ArrayCreation and - not expr instanceof ObjectCreation and - not expr instanceof DelegateCreation + lvInit.getInitializer() = expr ) or // Then treat more complex ones - expr instanceof ObjectCreation - or - expr instanceof DelegateCreation - or expr instanceof ArrayInitializer or expr instanceof ObjectInitializer or - expr = any(ThrowExpr throw).getExpr() + expr = any(ThrowStmt throwStmt).getExpr() or expr = any(CollectionInitializer colInit).getAnElementInitializer() or expr = any(ReturnStmt returnStmt).getExpr() or expr = any(ArrayInitializer arrInit).getAnElement() - or - expr = any(LambdaExpr lambda).getSourceDeclaration() - or - expr = any(AnonymousMethodExpr anonMethExpr).getSourceDeclaration() ) } or // The initialization of an array element via a member of an initializer list. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 4aa4c6fc29c..0543f4d1811 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -24,7 +24,11 @@ private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language */ TranslatedExpr getTranslatedExpr(Expr expr) { result.getExpr() = expr and - result.producesExprResult() + result.producesExprResult() and + // When a constructor call is needed, we fetch it manually. + // This is because of how we translate object creations: the translated expression + // and the translated constructor call are attached to the same element. + (expr instanceof ObjectCreation implies not result instanceof TranslatedConstructorCall) } /** @@ -1918,3 +1922,91 @@ class TranslatedDelegateCall extends TranslatedNonConstantExpr { result = DelegateElements::getInvoke(expr) } } + +/** + * Represents the IR translation of creation expression. Can be the translation of an + * `ObjectCreation` or a `DelegateCreation`. + * The `NewObj` instruction denotes the fact that during initialization a new + * object is allocated, which is then initialized by the constructor. + */ +abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreationExpr, + ConstructorCallContext { + TranslatedCreation() { this = TTranslatedCreationExpr(expr) } + + override TranslatedElement getChild(int id) { + id = 0 and result = this.getConstructorCall() + or + id = 1 and result = this.getInitializerExpr() + } + + override predicate hasInstruction( + Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + ) { + // Instruction that allocated space for a new object, + // and returns its address + tag = NewObjTag() and + opcode instanceof Opcode::NewObj and + resultType = expr.getType() and + isLValue = false + } + + final override Instruction getFirstInstruction() { result = this.getInstruction(NewObjTag()) } + + override Instruction getResult() { result = getInstruction(NewObjTag()) } + + override Instruction getReceiver() { result = getInstruction(NewObjTag()) } + + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { + kind instanceof GotoEdge and + tag = NewObjTag() and + result = this.getConstructorCall().getFirstInstruction() + } + + override Instruction getChildSuccessor(TranslatedElement child) { + ( + child = this.getConstructorCall() and + if exists(this.getInitializerExpr()) + then result = this.getInitializerExpr().getFirstInstruction() + else result = this.getParent().getChildSuccessor(this) + ) + or + child = this.getInitializerExpr() and + result = this.getParent().getChildSuccessor(this) + } + + abstract TranslatedElement getConstructorCall(); + + abstract TranslatedExpr getInitializerExpr(); +} + +/** + * Represents the IR translation of an `ObjectCreation`. + */ +class TranslatedObjectCreation extends TranslatedCreation { + override ObjectCreation expr; + + override TranslatedExpr getInitializerExpr() { result = getTranslatedExpr(expr.getInitializer()) } + + override TranslatedExpr getConstructorCall() { + // Since calls are also expressions, we can't + // use the predicate getTranslatedExpr (since that would + // also return `this`). + exists(TranslatedConstructorCall cc | + cc.getAST() = this.getAST() and + result = cc + ) + } +} + +/** + * Represents the IR translation of a `DelegateCreation`. + */ +class TranslatedDelegateCreation extends TranslatedCreation { + override DelegateCreation expr; + + override TranslatedExpr getInitializerExpr() { none() } + + override TranslatedElement getConstructorCall() { + result = DelegateElements::getConstructor(expr) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll index 777d000ebe4..89be95151e6 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -123,13 +123,9 @@ class TranslatedArrayListInitialization extends TranslatedListInitialization { */ class TranslatedDirectInitialization extends TranslatedInitialization { TranslatedDirectInitialization() { - // TODO: Make sure this is complete and correct not expr instanceof ArrayInitializer and not expr instanceof ObjectInitializer and - not expr instanceof DelegateCreation and - not expr instanceof CollectionInitializer and - not expr instanceof ObjectCreation and - not expr instanceof StringLiteral + not expr instanceof CollectionInitializer } override TranslatedElement getChild(int id) { id = 0 and result = this.getInitializer() } @@ -145,64 +141,6 @@ class TranslatedDirectInitialization extends TranslatedInitialization { opcode instanceof Opcode::Store and resultType = this.getContext().getTargetType() and isLValue = false - } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = InitializerStoreTag() and - result = this.getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = this.getInitializer() and result = this.getInstruction(InitializerStoreTag()) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = InitializerStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getContext().getTargetAddress() - or - operandTag instanceof StoreValueOperandTag and - result = this.getInitializer().getResult() - ) - } - - TranslatedExpr getInitializer() { result = getTranslatedExpr(expr) } -} - -/** - * Represents the IR translation of an initialization from a constructor. - * The `NewObj` instruction denotes the fact that during initialization a new - * object of type `expr.getType()` is allocated, which is then initialized by the - * constructor. - */ -class TranslatedObjectInitialization extends TranslatedInitialization, ConstructorCallContext { - override ObjectCreation expr; - - override TranslatedElement getChild(int id) { - id = 0 and result = this.getConstructorCall() - or - id = 1 and result = this.getInitializerExpr() - } - - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue - ) { - // Instruction that allocated space for a new object, - // and returns its address - tag = NewObjTag() and - opcode instanceof Opcode::NewObj and - resultType = expr.getType() and - isLValue = false - or - // Store op used to assign the variable that - // is initialized the address of the newly allocated - // object - tag = InitializerStoreTag() and - opcode instanceof Opcode::Store and - resultType = expr.getType() and - isLValue = false or needsConversion() and tag = AssignmentConvertRightTag() and @@ -214,39 +152,22 @@ class TranslatedObjectInitialization extends TranslatedInitialization, Construct isLValue = false } - final override Instruction getFirstInstruction() { result = this.getInstruction(NewObjTag()) } - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - kind instanceof GotoEdge and - ( - tag = NewObjTag() and - result = this.getConstructorCall().getFirstInstruction() - or - tag = InitializerStoreTag() and - result = this.getParent().getChildSuccessor(this) - or - tag = AssignmentConvertRightTag() and - result = this.getInstruction(InitializerStoreTag()) - ) + tag = InitializerStoreTag() and + result = this.getParent().getChildSuccessor(this) and + kind instanceof GotoEdge + or + needsConversion() and + tag = AssignmentConvertRightTag() and + result = getInstruction(InitializerStoreTag()) and + kind instanceof GotoEdge } override Instruction getChildSuccessor(TranslatedElement child) { - ( - child = this.getConstructorCall() and - if exists(this.getInitializerExpr()) - then result = this.getInitializerExpr().getFirstInstruction() - else - if this.needsConversion() - then result = this.getInstruction(AssignmentConvertRightTag()) - else result = this.getInstruction(InitializerStoreTag()) - ) - or - ( - child = this.getInitializerExpr() and - if this.needsConversion() - then result = this.getInstruction(AssignmentConvertRightTag()) - else result = this.getInstruction(InitializerStoreTag()) - ) + child = this.getInitializer() and + if this.needsConversion() + then result = this.getInstruction(AssignmentConvertRightTag()) + else result = this.getInstruction(InitializerStoreTag()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -256,33 +177,28 @@ class TranslatedObjectInitialization extends TranslatedInitialization, Construct result = this.getParent().(InitializationContext).getTargetAddress() or ( + operandTag instanceof AddressOperandTag and + result = this.getContext().getTargetAddress() + or operandTag instanceof StoreValueOperandTag and - if needsConversion() - then result = this.getInstruction(AssignmentConvertRightTag()) - else result = this.getInstruction(NewObjTag()) + result = this.getInitializer().getResult() ) ) or tag = AssignmentConvertRightTag() and operandTag instanceof UnaryOperandTag and + result = this.getInitializer().getResult() + or + tag = AssignmentConvertRightTag() and + operandTag instanceof UnaryOperandTag and result = this.getInstruction(NewObjTag()) } - private TranslatedExpr getConstructorCall() { result = getTranslatedExpr(expr) } - - private TranslatedExpr getInitializerExpr() { result = getTranslatedExpr(expr.getInitializer()) } - - override Instruction getReceiver() { - // The newly allocated object will be the target of the constructor call - result = this.getInstruction(NewObjTag()) - } + TranslatedExpr getInitializer() { result = getTranslatedExpr(expr) } private predicate needsConversion() { expr.getType() != this.getContext().getTargetType() } } -//private string getZeroValue(Type type) { -// if type instanceof FloatingPointType then result = "0.0" else result = "0" -//} /** * Represents the IR translation of the initialization of an array element from * an element of an initializer list. @@ -424,7 +340,7 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons TTranslatedConstructorInitializer { TranslatedConstructorInitializer() { this = TTranslatedConstructorInitializer(call) } - override string toString() { result = "constuructor init: " + call.toString() } + override string toString() { result = "constructor init: " + call.toString() } override Instruction getFirstInstruction() { if needsConversion() @@ -472,58 +388,3 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons derivedClass = this.getFunction().getDeclaringType() } } - -/** - * Represents the IR translation of a delegate creation. - */ -class TranslatedDelegateCreation extends TranslatedInitialization, ConstructorCallContext { - override DelegateCreation expr; - - override TranslatedElement getChild(int id) { id = 0 and result = getConstructorCall() } - - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue - ) { - tag = NewObjTag() and - opcode instanceof Opcode::NewObj and - resultType = expr.getType() and - isLValue = false - or - tag = InitializerStoreTag() and - opcode instanceof Opcode::Store and - resultType = expr.getType() and - isLValue = false - } - - final override Instruction getFirstInstruction() { result = getInstruction(NewObjTag()) } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = NewObjTag() and - result = getConstructorCall().getFirstInstruction() and - kind instanceof GotoEdge - or - tag = InitializerStoreTag() and - result = getParent().getChildSuccessor(this) and - kind instanceof GotoEdge - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = getConstructorCall() and - result = getInstruction(InitializerStoreTag()) - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = InitializerStoreTag() and - ( - operandTag instanceof AddressOperandTag and - result = getParent().(InitializationContext).getTargetAddress() - or - operandTag instanceof StoreValueOperandTag and - result = getInstruction(NewObjTag()) - ) - } - - private TranslatedElement getConstructorCall() { result = DelegateElements::getConstructor(expr) } - - override Instruction getReceiver() { result = getInstruction(NewObjTag()) } -} diff --git a/csharp/ql/test/library-tests/ir/ir/obj_creation.cs b/csharp/ql/test/library-tests/ir/ir/obj_creation.cs index 3be78a0a5b5..d045f44ed88 100644 --- a/csharp/ql/test/library-tests/ir/ir/obj_creation.cs +++ b/csharp/ql/test/library-tests/ir/ir/obj_creation.cs @@ -13,11 +13,17 @@ public class ObjCreation x = _x; } } + + public static void SomeFun(MyClass x) + { + } public static void Main() { MyClass obj = new MyClass(100); MyClass obj_initlist = new MyClass { x = 101 }; int a = obj.x; + + SomeFun(new MyClass(100)); } } diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index 387e09f1a0b..5d85352add6 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -534,7 +534,7 @@ inheritance_polymorphism.cs: # 33| v0_28(Void) = Call : func:r0_27, this:r0_26 # 33| mu0_29(null) = ^CallSideEffect : ~mu0_2 # 33| r0_30(A) = Convert : r0_26 -# 33| mu0_31(C) = Store : &:r0_25, r0_30 +# 33| mu0_31(A) = Store : &:r0_25, r0_26 # 34| r0_32(glval) = VariableAddress[objC] : # 34| r0_33(A) = Load : &:r0_32, ~mu0_2 # 34| r0_34(glval) = FunctionAddress[function] : @@ -547,21 +547,23 @@ inheritance_polymorphism.cs: isexpr.cs: # 8| System.Void IsExpr.Main() # 8| Block 0 -# 8| v0_0(Void) = EnterFunction : -# 8| mu0_1(null) = AliasedDefinition : -# 8| mu0_2(null) = UnmodeledDefinition : -# 10| r0_3(glval) = VariableAddress[obj] : -# 10| r0_4(null) = Constant[null] : -# 10| mu0_5(Is_A) = Store : &:r0_3, r0_4 -# 12| r0_6(glval) = VariableAddress[o] : -# 12| r0_7(glval) = VariableAddress[obj] : -# 12| mu0_8(Object) = Store : &:r0_6, r0_7 -# 13| r0_9(glval) = VariableAddress[o] : -# 13| r0_10(Object) = Load : &:r0_9, ~mu0_2 -# 13| r0_11(Is_A) = CheckedConvertOrNull : r0_10 -# 13| r0_12(Is_A) = Constant[0] : -# 13| r0_13(Boolean) = CompareNE : r0_11, r0_12 -# 13| r0_14(Boolean) = ConditionalBranch : r0_13 +# 8| v0_0(Void) = EnterFunction : +# 8| mu0_1(null) = AliasedDefinition : +# 8| mu0_2(null) = UnmodeledDefinition : +# 10| r0_3(glval) = VariableAddress[obj] : +# 10| r0_4(null) = Constant[null] : +# 10| r0_5(Is_A) = Convert : r0_4 +# 10| mu0_6(Is_A) = Store : &:r0_3, r0_4 +# 12| r0_7(glval) = VariableAddress[o] : +# 12| r0_8(glval) = VariableAddress[obj] : +# 12| r0_9(Object) = Convert : r0_8 +# 12| mu0_10(Object) = Store : &:r0_7, r0_8 +# 13| r0_11(glval) = VariableAddress[o] : +# 13| r0_12(Object) = Load : &:r0_11, ~mu0_2 +# 13| r0_13(Is_A) = CheckedConvertOrNull : r0_12 +# 13| r0_14(Is_A) = Constant[0] : +# 13| r0_15(Boolean) = CompareNE : r0_13, r0_14 +# 13| r0_16(Boolean) = ConditionalBranch : r0_15 #-----| False -> Block 2 #-----| True -> Block 3 @@ -571,13 +573,13 @@ isexpr.cs: # 8| v1_2(Void) = ExitFunction : # 13| Block 2 -# 13| v2_0(Void) = ConditionalBranch : r0_13 +# 13| v2_0(Void) = ConditionalBranch : r0_15 #-----| False -> Block 5 #-----| True -> Block 4 # 13| Block 3 # 13| r3_0(glval) = VariableAddress[tmp] : -# 13| mu3_1(Is_A) = Store : &:r3_0, r0_11 +# 13| mu3_1(Is_A) = Store : &:r3_0, r0_13 #-----| Goto -> Block 2 # 15| Block 4 @@ -684,36 +686,56 @@ obj_creation.cs: # 11| v0_12(Void) = UnmodeledUse : mu* # 11| v0_13(Void) = ExitFunction : -# 17| System.Void ObjCreation.Main() +# 17| System.Void ObjCreation.SomeFun(ObjCreation.MyClass) # 17| Block 0 -# 17| v0_0(Void) = EnterFunction : -# 17| mu0_1(null) = AliasedDefinition : -# 17| mu0_2(null) = UnmodeledDefinition : -# 19| r0_3(glval) = VariableAddress[obj] : -# 19| r0_4(MyClass) = NewObj : -# 19| r0_5(glval) = FunctionAddress[MyClass] : -# 19| r0_6(Int32) = Constant[100] : -# 19| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6 -# 19| mu0_8(null) = ^CallSideEffect : ~mu0_2 -# 19| mu0_9(MyClass) = Store : &:r0_3, r0_4 -# 20| r0_10(glval) = VariableAddress[obj_initlist] : -# 20| r0_11(MyClass) = NewObj : -# 20| r0_12(glval) = FunctionAddress[MyClass] : -# 20| v0_13(Void) = Call : func:r0_12, this:r0_11 -# 20| mu0_14(null) = ^CallSideEffect : ~mu0_2 -# 20| r0_15(Int32) = Constant[101] : -# 20| r0_16(glval) = FieldAddress[x] : r0_11 -# 20| mu0_17(Int32) = Store : &:r0_16, r0_15 -# 20| mu0_18(MyClass) = Store : &:r0_10, r0_11 -# 21| r0_19(glval) = VariableAddress[a] : -# 21| r0_20(glval) = VariableAddress[obj] : -# 21| r0_21(MyClass) = Load : &:r0_20, ~mu0_2 -# 21| r0_22(glval) = FieldAddress[x] : r0_21 -# 21| r0_23(Int32) = Load : &:r0_22, ~mu0_2 -# 21| mu0_24(Int32) = Store : &:r0_19, r0_23 -# 17| v0_25(Void) = ReturnVoid : -# 17| v0_26(Void) = UnmodeledUse : mu* -# 17| v0_27(Void) = ExitFunction : +# 17| v0_0(Void) = EnterFunction : +# 17| mu0_1(null) = AliasedDefinition : +# 17| mu0_2(null) = UnmodeledDefinition : +# 17| r0_3(glval) = VariableAddress[x] : +# 17| mu0_4(MyClass) = InitializeParameter[x] : &:r0_3 +# 18| v0_5(Void) = NoOp : +# 17| v0_6(Void) = ReturnVoid : +# 17| v0_7(Void) = UnmodeledUse : mu* +# 17| v0_8(Void) = ExitFunction : + +# 21| System.Void ObjCreation.Main() +# 21| Block 0 +# 21| v0_0(Void) = EnterFunction : +# 21| mu0_1(null) = AliasedDefinition : +# 21| mu0_2(null) = UnmodeledDefinition : +# 23| r0_3(glval) = VariableAddress[obj] : +# 23| r0_4(MyClass) = NewObj : +# 23| r0_5(glval) = FunctionAddress[MyClass] : +# 23| r0_6(Int32) = Constant[100] : +# 23| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6 +# 23| mu0_8(null) = ^CallSideEffect : ~mu0_2 +# 23| mu0_9(MyClass) = Store : &:r0_3, r0_4 +# 24| r0_10(glval) = VariableAddress[obj_initlist] : +# 24| r0_11(MyClass) = NewObj : +# 24| r0_12(glval) = FunctionAddress[MyClass] : +# 24| v0_13(Void) = Call : func:r0_12, this:r0_11 +# 24| mu0_14(null) = ^CallSideEffect : ~mu0_2 +# 24| r0_15(Int32) = Constant[101] : +# 24| r0_16(glval) = FieldAddress[x] : r0_11 +# 24| mu0_17(Int32) = Store : &:r0_16, r0_15 +# 24| mu0_18(MyClass) = Store : &:r0_10, r0_11 +# 25| r0_19(glval) = VariableAddress[a] : +# 25| r0_20(glval) = VariableAddress[obj] : +# 25| r0_21(MyClass) = Load : &:r0_20, ~mu0_2 +# 25| r0_22(glval) = FieldAddress[x] : r0_21 +# 25| r0_23(Int32) = Load : &:r0_22, ~mu0_2 +# 25| mu0_24(Int32) = Store : &:r0_19, r0_23 +# 27| r0_25(glval) = FunctionAddress[SomeFun] : +# 27| r0_26(MyClass) = NewObj : +# 27| r0_27(glval) = FunctionAddress[MyClass] : +# 27| r0_28(Int32) = Constant[100] : +# 27| v0_29(Void) = Call : func:r0_27, this:r0_26, 0:r0_28 +# 27| mu0_30(null) = ^CallSideEffect : ~mu0_2 +# 27| v0_31(Void) = Call : func:r0_25, 0:r0_26 +# 27| mu0_32(null) = ^CallSideEffect : ~mu0_2 +# 21| v0_33(Void) = ReturnVoid : +# 21| v0_34(Void) = UnmodeledUse : mu* +# 21| v0_35(Void) = ExitFunction : prop.cs: # 7| System.Int32 PropClass.get_Prop() From 241a40c145758ca10f5868be586ba95ff86a9f5a Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Tue, 3 Sep 2019 16:26:39 +0100 Subject: [PATCH 0005/1227] C# IR: Initializers Add support for collection initializers. Instead of using `AssignExpr` for the translation of object initializers, `MemberInitializer` is now used. --- .../raw/internal/TranslatedCall.qll | 9 ++- .../raw/internal/TranslatedExpr.qll | 55 ++++++++++++++++--- .../test/library-tests/ir/ir/collections.cs | 19 +++++++ .../test/library-tests/ir/ir/raw_ir.expected | 44 +++++++++++++++ 4 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 csharp/ql/test/library-tests/ir/ir/collections.cs diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll index 580a4a7e5fa..c278fddbe20 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll @@ -4,6 +4,7 @@ private import semmle.code.csharp.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedElement private import TranslatedExpr +private import TranslatedInitialization private import semmle.code.csharp.ir.Util private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language @@ -50,7 +51,13 @@ class TranslatedFunctionCall extends TranslatedNonConstantExpr, TranslatedCall { result = getTranslatedExpr(expr.(QualifiableExpr).getQualifier()) } - override Instruction getQualifierResult() { result = this.getQualifier().getResult() } + override Instruction getQualifierResult() { + // since `ElementInitializer`s do not have a qualifier, the qualifier's result is retrieved + // from the enclosing initialization context + if expr.getParent() instanceof CollectionInitializer + then result = getTranslatedExpr(expr.getParent()).(InitializationContext).getTargetAddress() + else result = this.getQualifier().getResult() + } override Type getCallResultType() { result = expr.getTarget().getReturnType() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 0543f4d1811..9bf368dbb6a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -485,11 +485,7 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial } override TranslatedElement getChild(int id) { - exists(AssignExpr assign | - result = getTranslatedExpr(expr.getChild(id)) and - expr.getAChild() = assign and - assign.getIndex() = id - ) + result = getTranslatedExpr(expr.getMemberInitializer(id)) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } @@ -503,9 +499,54 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial ) } - override Instruction getTargetAddress() { result = this.getParent().getInstruction(NewObjTag()) } + override Instruction getTargetAddress() { + // The target address is the address of the newly allocated object, + // which can be retrieved from the parent `TranslatedObjectCreation`. + result = this.getParent().getInstruction(NewObjTag()) + } - override Type getTargetType() { none() } + override Type getTargetType() { + result = this.getParent().getInstruction(NewObjTag()).getResultType() + } +} + +class TranslatedCollectionInitializer extends TranslatedNonConstantExpr, InitializationContext { + override CollectionInitializer expr; + + override Instruction getResult() { none() } + + override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() } + + override predicate hasInstruction( + Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + ) { + none() + } + + override TranslatedElement getChild(int id) { + result = getTranslatedExpr(expr.getElementInitializer(id)) + } + + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } + + override Instruction getChildSuccessor(TranslatedElement child) { + exists(int index | + child = this.getChild(index) and + if exists(this.getChild(index + 1)) + then result = this.getChild(index + 1).getFirstInstruction() + else result = this.getParent().getChildSuccessor(this) + ) + } + + override Instruction getTargetAddress() { + // The target address is the address of the newly allocated object, + // which can be retrieved from the parent `TranslatedObjectCreation`. + result = this.getParent().getInstruction(NewObjTag()) + } + + override Type getTargetType() { + result = this.getParent().getInstruction(NewObjTag()).getResultType() + } } /** diff --git a/csharp/ql/test/library-tests/ir/ir/collections.cs b/csharp/ql/test/library-tests/ir/ir/collections.cs new file mode 100644 index 00000000000..b8f6c56dd50 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/ir/collections.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +public class Collections +{ + class MyClass + { + public string a; + public string b; + } + + public static void Main() + { + var dict = new Dictionary() + { + { 0, new MyClass { a="Hello", b="World" } }, + { 1, new MyClass { a="Foo", b="Bar" } } + }; + } +} diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index 5d85352add6..32844b09dc6 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -161,6 +161,50 @@ casts.cs: # 11| v0_20(Void) = UnmodeledUse : mu* # 11| v0_21(Void) = ExitFunction : +collections.cs: +# 11| System.Void Collections.Main() +# 11| Block 0 +# 11| v0_0(Void) = EnterFunction : +# 11| mu0_1(null) = AliasedDefinition : +# 11| mu0_2(null) = UnmodeledDefinition : +# 13| r0_3(glval>) = VariableAddress[dict] : +# 13| r0_4(Dictionary) = NewObj : +# 13| r0_5(glval) = FunctionAddress[Dictionary] : +# 13| v0_6(Void) = Call : func:r0_5, this:r0_4 +# 13| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 15| r0_8(glval) = FunctionAddress[Add] : +# 15| r0_9(Int32) = Constant[0] : +# 15| r0_10(MyClass) = NewObj : +# 15| r0_11(glval) = FunctionAddress[MyClass] : +# 15| v0_12(Void) = Call : func:r0_11, this:r0_10 +# 15| mu0_13(null) = ^CallSideEffect : ~mu0_2 +# 15| r0_14(String) = StringConstant["Hello"] : +# 15| r0_15(glval) = FieldAddress[a] : r0_10 +# 15| mu0_16(String) = Store : &:r0_15, r0_14 +# 15| r0_17(String) = StringConstant["World"] : +# 15| r0_18(glval) = FieldAddress[b] : r0_10 +# 15| mu0_19(String) = Store : &:r0_18, r0_17 +# 15| v0_20(Void) = Call : func:r0_8, this:r0_4, 0:r0_9, 1:r0_10 +# 15| mu0_21(null) = ^CallSideEffect : ~mu0_2 +# 16| r0_22(glval) = FunctionAddress[Add] : +# 16| r0_23(Int32) = Constant[1] : +# 16| r0_24(MyClass) = NewObj : +# 16| r0_25(glval) = FunctionAddress[MyClass] : +# 16| v0_26(Void) = Call : func:r0_25, this:r0_24 +# 16| mu0_27(null) = ^CallSideEffect : ~mu0_2 +# 16| r0_28(String) = StringConstant["Foo"] : +# 16| r0_29(glval) = FieldAddress[a] : r0_24 +# 16| mu0_30(String) = Store : &:r0_29, r0_28 +# 16| r0_31(String) = StringConstant["Bar"] : +# 16| r0_32(glval) = FieldAddress[b] : r0_24 +# 16| mu0_33(String) = Store : &:r0_32, r0_31 +# 16| v0_34(Void) = Call : func:r0_22, this:r0_4, 0:r0_23, 1:r0_24 +# 16| mu0_35(null) = ^CallSideEffect : ~mu0_2 +# 13| mu0_36(Dictionary) = Store : &:r0_3, r0_4 +# 11| v0_37(Void) = ReturnVoid : +# 11| v0_38(Void) = UnmodeledUse : mu* +# 11| v0_39(Void) = ExitFunction : + constructor_init.cs: # 5| System.Void BaseClass..ctor() # 5| Block 0 From 97fc10e669973f0534c4dff3405f0c889f50b596 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 10 Sep 2019 14:02:05 +0100 Subject: [PATCH 0006/1227] Add query for detecting potential DOS form a tainted .length property --- .../src/Security/CWE-834/TaintedLength.qhelp | 67 +++++ .../ql/src/Security/CWE-834/TaintedLength.ql | 22 ++ .../CWE-834/examples/TaintedLength.js | 22 ++ .../CWE-834/examples/TaintedLength_fixed.js | 24 ++ .../security/dataflow/TaintedLength.qll | 43 +++ .../dataflow/TaintedLengthCustomizations.qll | 256 ++++++++++++++++++ .../Security/CWE-834/TaintedLength.expected | 57 ++++ .../Security/CWE-834/TaintedLength.qlref | 1 + .../Security/CWE-834/TaintedLengthBad.js | 59 ++++ .../Security/CWE-834/TaintedLengthExitBad.js | 70 +++++ .../Security/CWE-834/TaintedLengthExitGood.js | 57 ++++ .../Security/CWE-834/TaintedLengthGood.js | 73 +++++ .../Security/CWE-834/TaintedLengthLodash.js | 17 ++ .../Security/CWE-834/TaintedLengthNested.js | 13 + .../TaintedLengthObviousLengthCheck.js | 22 ++ .../TaintedLengthObviousNullPointer.js | 58 ++++ ...dLengthObviousNullPointerInPreviousLoop.js | 24 ++ 17 files changed, 885 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-834/TaintedLength.qhelp create mode 100644 javascript/ql/src/Security/CWE-834/TaintedLength.ql create mode 100644 javascript/ql/src/Security/CWE-834/examples/TaintedLength.js create mode 100644 javascript/ql/src/Security/CWE-834/examples/TaintedLength_fixed.js create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/TaintedLength.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/TaintedLengthCustomizations.qll create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLength.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLength.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthBad.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthExitBad.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthExitGood.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthGood.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthLodash.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthNested.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousLengthCheck.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousNullPointer.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousNullPointerInPreviousLoop.js diff --git a/javascript/ql/src/Security/CWE-834/TaintedLength.qhelp b/javascript/ql/src/Security/CWE-834/TaintedLength.qhelp new file mode 100644 index 00000000000..05ee11e8c9b --- /dev/null +++ b/javascript/ql/src/Security/CWE-834/TaintedLength.qhelp @@ -0,0 +1,67 @@ + + + + +

+ Iterating the elements of an untrusted object using the + .length property can lead to a server looping + indefinitely or crashing. Thereby creating a + denial-of-service or DOS. + This happens when an attacker creates a JSON object with an + absurdly large number in the .length property that the server then + loops through. +
+ The problem can also happen when using utility methods from Lodash or + Underscore that operate on array-like values. + As a simple example of how a DOS can happen, this code will crash most + servers with an out-of-memory exception + _.map({length:999999999}). +

+
+ + +

+ The attack is easy to prevent and there are multiple ways of doing so. + Forcing the user controlled object to be an array or preventing the + .length property from being too large can limit the + impact of the attack. +
+ Alternatively the loop can exit early if the currently iterated element + is seen to be undefined, as the attacker cannot create an + array-like object with non-undefined values for an + unlimited amount of array elements. +
+ Accessing a property of the currently iterated element will also + prevent the attack, as a null-pointer exception will occur in the first + iteration where the element is undefined. +

+
+ + +

+ In the example below, a server iterates over a user controlled object + obj using the obj.length property in order + to copy the elements from obj to an array. +

+ + + +

+ This is not secure since an attacker can control the value of + obj.length, and thereby cause the loop to loop + indefinitely. + Here the potential DOS is fixed by enforcing that the user controlled + object is an array. +

+ + +
+ + +
  • CWE entry: + CWE-834 +
  • +
    +
    diff --git a/javascript/ql/src/Security/CWE-834/TaintedLength.ql b/javascript/ql/src/Security/CWE-834/TaintedLength.ql new file mode 100644 index 00000000000..3ac3ade2d24 --- /dev/null +++ b/javascript/ql/src/Security/CWE-834/TaintedLength.ql @@ -0,0 +1,22 @@ +/** + * @name Tainted .length looping + * @description If server-side code iterates over a user-controlled object with + * an arbitary .length value, then an attacker can trick the server + * to loop infinitely. + * @kind path-problem + * @problem.severity warning + * @id js/tainted-length-looping + * @tags security + * @precision low + */ + +import javascript + +import semmle.javascript.security.dataflow.TaintedLength::TaintedLength + +from + Configuration dataflow, DataFlow::PathNode source, DataFlow::PathNode sink +where dataflow.hasFlowPath(source, sink) +select sink, source, sink, + "Iterating over user controlled object with an unbounded .length property $@.", + source, "here" diff --git a/javascript/ql/src/Security/CWE-834/examples/TaintedLength.js b/javascript/ql/src/Security/CWE-834/examples/TaintedLength.js new file mode 100644 index 00000000000..6e621d6b9be --- /dev/null +++ b/javascript/ql/src/Security/CWE-834/examples/TaintedLength.js @@ -0,0 +1,22 @@ +'use strict'; + +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +rootRoute.post(function(req, res) { + var obj = req.body; + + calcStuff(obj); +}); + +function calcStuff(obj) { + var ret = []; + + // potential DOS if obj.length is large. + for (var i = 0; i < obj.length; i++) { + ret.push(obj[i]); + } + + return ret; +} \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-834/examples/TaintedLength_fixed.js b/javascript/ql/src/Security/CWE-834/examples/TaintedLength_fixed.js new file mode 100644 index 00000000000..fce7ae9bde2 --- /dev/null +++ b/javascript/ql/src/Security/CWE-834/examples/TaintedLength_fixed.js @@ -0,0 +1,24 @@ +'use strict'; + +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +rootRoute.post(function(req, res) { + var obj = req.body; + + calcStuff(obj); +}); + +function calcStuff(obj) { + if (!(obj instanceof Array)) { // prevents DOS + return []; + } + + var ret = []; + for (var i = 0; i < obj.length; i++) { + ret.push(obj[i]); + } + + return ret; +} \ No newline at end of file diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedLength.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedLength.qll new file mode 100644 index 00000000000..657610b9049 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedLength.qll @@ -0,0 +1,43 @@ +/** + * Provides a taint tracking configuration for reasoning about DOS attacks + * using a user controlled object with an unbounded .length property. + * + * Note, for performance reasons: only import this file if + * `TaintedLength::Configuration` is needed, otherwise + * `TaintedLengthCustomizations` should be imported instead. + */ + +import javascript +import semmle.javascript.security.TaintedObject + +module TaintedLength { + import TaintedLengthCustomizations::TaintedLength + + /** + * A taint-tracking configuration for reasoning about looping on tainted objects with unbounded length. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "LabeledLoopTaintedObject" } + + override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { + source instanceof Source and label = TaintedObject::label() + } + + override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { + sink instanceof Sink and label = TaintedObject::label() + } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof TaintedObject::SanitizerGuard or + guard instanceof IsArraySanitizerGuard or + guard instanceof InstanceofArraySanitizerGuard or + guard instanceof LengthCheckSanitizerGuard + } + + override predicate isAdditionalFlowStep( + DataFlow::Node src, DataFlow::Node trg, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl + ) { + TaintedObject::step(src, trg, inlbl, outlbl) + } + } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedLengthCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedLengthCustomizations.qll new file mode 100644 index 00000000000..dacc9adfe92 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedLengthCustomizations.qll @@ -0,0 +1,256 @@ +/** + * Provides default sources, sinks and sanitisers for reasoning about + * DOS attacks using objects with unbounded length object. + * As well as extension points for adding your own. + */ + +import javascript + +module TaintedLength { + import semmle.javascript.security.dataflow.RemoteFlowSources + import semmle.javascript.security.TaintedObject + import DataFlow::PathGraph + + // Heavily inspired by Expr::inNullSensitiveContext + predicate isCrashingWithNullValues(Expr e) { + exists(ExprOrStmt ctx | + e = ctx.(PropAccess).getBase() + or + e = ctx.(InvokeExpr).getCallee() + or + e = ctx.(AssignExpr).getRhs() and + ctx.(AssignExpr).getLhs() instanceof DestructuringPattern + or + e = ctx.(SpreadElement).getOperand() + or + e = ctx.(ForOfStmt).getIterationDomain() + ) + } + + // Inspired by LoopIterationSkippedDueToShifting::ArrayIterationLoop + // Added some Dataflow to the .length access. + // Added support for while/dowhile loops. + class ArrayIterationLoop extends LoopStmt { + LocalVariable indexVariable; + + ArrayIterationLoop() { + exists(RelationalComparison compare, DataFlow::PropRead lengthRead | + compare = this.getTest() and + compare.getLesserOperand() = indexVariable.getAnAccess() and + lengthRead.accesses(_, "length") and + lengthRead.flowsToExpr(compare.getGreaterOperand()) + ) and + ( + this.(ForStmt).getUpdate().(IncExpr).getOperand() = indexVariable.getAnAccess() or + this.getBody().getAChild*().(IncExpr).getOperand() = indexVariable.getAnAccess() + ) + } + + override Stmt getBody() { + result = this.(ForStmt).getBody() or + result = this.(WhileStmt).getBody() or + result = this.(DoWhileStmt).getBody() + } + + override Expr getTest() { + result = this.(ForStmt).getTest() or + result = this.(WhileStmt).getTest() or + result = this.(DoWhileStmt).getTest() + } + + /** + * Gets the variable holding the loop variable and current array index. + */ + LocalVariable getIndexVariable() { result = indexVariable } + } + + abstract class Sink extends DataFlow::Node { } + + // for (..; .. sink.length; ...) ... + private class LoopSink extends Sink { + LoopSink() { + exists(ArrayIterationLoop loop, Expr lengthAccess, DataFlow::PropRead lengthRead | + loop.getTest().getAChild*() = lengthAccess and + lengthRead.flowsToExpr(lengthAccess) and + lengthRead.accesses(this, "length") and + // In the DOS we are looking for arrayRead will evaluate to undefined. + // If an obvious nullpointer happens on this undefined, then the DOS cannot happen. + not exists(DataFlow::PropRead arrayRead, Expr throws | + // It doesn't only happen inside the for-loop, outside is also a sink (assuming it happens before). + loop.getBody().getAChild*() = arrayRead.asExpr() and + loop.getBody().getAChild*() = throws and + arrayRead.getPropertyNameExpr() = loop.getIndexVariable().getAnAccess() and + arrayRead.flowsToExpr(throws) and + isCrashingWithNullValues(throws) + ) and + // The existance of some kind of early-exit usually indicates that the loop will stop early and no DOS happens. + not exists(BreakStmt br | br.getTarget() = loop) and + not exists(ReturnStmt ret | + loop.getBody().getAChild*() = ret and + ret.getContainer() = loop.getContainer() + ) and + not exists(ThrowStmt throw | + loop.getBody().getAChild*() = throw and + not loop.getBody().getAChild*() = throw.getTarget() + ) + ) + } + } + + predicate loopableLodashMethod(string name) { + name = "chunk" or + name = "compact" or + name = "difference" or + name = "differenceBy" or + name = "differenceWith" or + name = "drop" or + name = "dropRight" or + name = "dropRightWhile" or + name = "dropWhile" or + name = "fill" or + name = "findIndex" or + name = "findLastIndex" or + name = "flatten" or + name = "flattenDeep" or + name = "flattenDepth" or + name = "initial" or + name = "intersection" or + name = "intersectionBy" or + name = "intersectionWith" or + name = "join" or + name = "remove" or + name = "reverse" or + name = "slice" or + name = "sortedUniq" or + name = "sortedUniqBy" or + name = "tail" or + name = "union" or + name = "unionBy" or + name = "unionWith" or + name = "uniqBy" or + name = "unzip" or + name = "unzipWith" or + name = "without" or + name = "zip" or + name = "zipObject" or + name = "zipObjectDeep" or + name = "zipWith" or + name = "countBy" or + name = "each" or + name = "forEach" or + name = "eachRight" or + name = "forEachRight" or + name = "filter" or + name = "find" or + name = "findLast" or + name = "flatMap" or + name = "flatMapDeep" or + name = "flatMapDepth" or + name = "forEach" or + name = "forEachRight" or + name = "groupBy" or + name = "invokeMap" or + name = "keyBy" or + name = "map" or + name = "orderBy" or + name = "partition" or + name = "reduce" or + name = "reduceRight" or + name = "reject" or + name = "sortBy" + } + + // _.each(sink); + private class LodashIterationSink extends Sink { + DataFlow::CallNode call; + + LodashIterationSink() { + exists(string name | + loopableLodashMethod(name) and + call = any(LodashUnderscore::member(name)).getACall() and + call.getArgument(0) = this and + + // Here it is just assumed that the array elements is the first parameter in the callback function. + not exists(DataFlow::FunctionNode func, DataFlow::ParameterNode e | + func.flowsTo(call.getAnArgument()) and + e = func.getParameter(0) and + ( + // Looking for obvious null-pointers happening on the array elements in the iteration. + // Similar to what is done in the loop iteration sink. + exists(Expr throws | + throws = func.asExpr().(Function).getBody().getAChild*() and + e.flowsToExpr(throws) and + isCrashingWithNullValues(throws) + ) + or + // similar to the loop sink - the existance of an early-exit usually means that no DOS can happen. + exists(ThrowStmt throw | + throw = func.asExpr().(Function).getBody().getAChild*() and + throw.getTarget() = func.asExpr() + ) + ) + ) + ) + } + } + + abstract class Source extends DataFlow::Node { } + + /** + * A source of remote user input objects. + */ + class TaintedObjectSource extends Source { + TaintedObjectSource() { this instanceof TaintedObject::Source } + } + + + class IsArraySanitizerGuard extends TaintTracking::LabeledSanitizerGuardNode, + DataFlow::ValueNode { + override CallExpr astNode; + + IsArraySanitizerGuard() { astNode.getCalleeName() = "isArray" } + + override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { + true = outcome and + e = astNode.getAnArgument() and + label = TaintedObject::label() + } + } + + class InstanceofArraySanitizerGuard extends TaintTracking::LabeledSanitizerGuardNode, + DataFlow::ValueNode { + override BinaryExpr astNode; + + InstanceofArraySanitizerGuard() { + astNode.getOperator() = "instanceof" and + astNode.getRightOperand().(Identifier).getName() = "Array" + } + + override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { + true = outcome and + e = astNode.getLeftOperand() and + label = TaintedObject::label() + } + } + + // Does two things: + // 1) Detects any length-check that limits the size of the .length property. + // 2) Makes sure that only the first loop that is DOS-prone is selected by the query. (due to the .length test having outcome=false when exiting the loop). + class LengthCheckSanitizerGuard extends TaintTracking::LabeledSanitizerGuardNode, + DataFlow::ValueNode { + override RelationalComparison astNode; + + PropAccess propAccess; + + LengthCheckSanitizerGuard() { + propAccess = astNode.getGreaterOperand().getAChild*() and + propAccess.getPropertyName() = "length" + } + + override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { + false = outcome and + astNode.getAChild*() = e and + label = TaintedObject::label() + } + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLength.expected b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLength.expected new file mode 100644 index 00000000000..393aa04b9e1 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLength.expected @@ -0,0 +1,57 @@ +nodes +| TaintedLengthBad.js:8:10:8:17 | req.body | +| TaintedLengthBad.js:10:12:10:19 | req.body | +| TaintedLengthBad.js:12:22:12:29 | req.body | +| TaintedLengthBad.js:14:16:14:23 | req.body | +| TaintedLengthBad.js:17:18:17:20 | val | +| TaintedLengthBad.js:21:22:21:24 | val | +| TaintedLengthBad.js:26:20:26:22 | val | +| TaintedLengthBad.js:30:13:30:15 | val | +| TaintedLengthBad.js:37:30:37:32 | val | +| TaintedLengthBad.js:40:12:40:14 | val | +| TaintedLengthBad.js:49:24:49:26 | val | +| TaintedLengthBad.js:54:22:54:24 | val | +| TaintedLengthExitBad.js:8:9:8:16 | req.body | +| TaintedLengthExitBad.js:10:9:10:16 | req.body | +| TaintedLengthExitBad.js:12:10:12:17 | req.body | +| TaintedLengthExitBad.js:14:14:14:21 | req.body | +| TaintedLengthExitBad.js:17:17:17:19 | val | +| TaintedLengthExitBad.js:20:22:20:24 | val | +| TaintedLengthExitBad.js:30:17:30:19 | val | +| TaintedLengthExitBad.js:33:22:33:24 | val | +| TaintedLengthExitBad.js:46:18:46:20 | val | +| TaintedLengthExitBad.js:49:22:49:24 | val | +| TaintedLengthExitBad.js:59:22:59:24 | val | +| TaintedLengthExitBad.js:60:8:60:10 | val | +| TaintedLengthLodash.js:9:10:9:17 | req.body | +| TaintedLengthLodash.js:14:18:14:20 | val | +| TaintedLengthLodash.js:15:10:15:12 | val | +edges +| TaintedLengthBad.js:8:10:8:17 | req.body | TaintedLengthBad.js:17:18:17:20 | val | +| TaintedLengthBad.js:10:12:10:19 | req.body | TaintedLengthBad.js:26:20:26:22 | val | +| TaintedLengthBad.js:12:22:12:29 | req.body | TaintedLengthBad.js:37:30:37:32 | val | +| TaintedLengthBad.js:14:16:14:23 | req.body | TaintedLengthBad.js:49:24:49:26 | val | +| TaintedLengthBad.js:17:18:17:20 | val | TaintedLengthBad.js:21:22:21:24 | val | +| TaintedLengthBad.js:26:20:26:22 | val | TaintedLengthBad.js:30:13:30:15 | val | +| TaintedLengthBad.js:37:30:37:32 | val | TaintedLengthBad.js:40:12:40:14 | val | +| TaintedLengthBad.js:49:24:49:26 | val | TaintedLengthBad.js:54:22:54:24 | val | +| TaintedLengthExitBad.js:8:9:8:16 | req.body | TaintedLengthExitBad.js:17:17:17:19 | val | +| TaintedLengthExitBad.js:10:9:10:16 | req.body | TaintedLengthExitBad.js:30:17:30:19 | val | +| TaintedLengthExitBad.js:12:10:12:17 | req.body | TaintedLengthExitBad.js:46:18:46:20 | val | +| TaintedLengthExitBad.js:14:14:14:21 | req.body | TaintedLengthExitBad.js:59:22:59:24 | val | +| TaintedLengthExitBad.js:17:17:17:19 | val | TaintedLengthExitBad.js:20:22:20:24 | val | +| TaintedLengthExitBad.js:30:17:30:19 | val | TaintedLengthExitBad.js:33:22:33:24 | val | +| TaintedLengthExitBad.js:46:18:46:20 | val | TaintedLengthExitBad.js:49:22:49:24 | val | +| TaintedLengthExitBad.js:59:22:59:24 | val | TaintedLengthExitBad.js:60:8:60:10 | val | +| TaintedLengthLodash.js:9:10:9:17 | req.body | TaintedLengthLodash.js:14:18:14:20 | val | +| TaintedLengthLodash.js:14:18:14:20 | val | TaintedLengthLodash.js:15:10:15:12 | val | +#select +| TaintedLengthBad.js:21:22:21:24 | val | TaintedLengthBad.js:8:10:8:17 | req.body | TaintedLengthBad.js:21:22:21:24 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthBad.js:8:10:8:17 | req.body | here | +| TaintedLengthBad.js:30:13:30:15 | val | TaintedLengthBad.js:10:12:10:19 | req.body | TaintedLengthBad.js:30:13:30:15 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthBad.js:10:12:10:19 | req.body | here | +| TaintedLengthBad.js:40:12:40:14 | val | TaintedLengthBad.js:12:22:12:29 | req.body | TaintedLengthBad.js:40:12:40:14 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthBad.js:12:22:12:29 | req.body | here | +| TaintedLengthBad.js:54:22:54:24 | val | TaintedLengthBad.js:14:16:14:23 | req.body | TaintedLengthBad.js:54:22:54:24 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthBad.js:14:16:14:23 | req.body | here | +| TaintedLengthExitBad.js:20:22:20:24 | val | TaintedLengthExitBad.js:8:9:8:16 | req.body | TaintedLengthExitBad.js:20:22:20:24 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthExitBad.js:8:9:8:16 | req.body | here | +| TaintedLengthExitBad.js:33:22:33:24 | val | TaintedLengthExitBad.js:10:9:10:16 | req.body | TaintedLengthExitBad.js:33:22:33:24 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthExitBad.js:10:9:10:16 | req.body | here | +| TaintedLengthExitBad.js:49:22:49:24 | val | TaintedLengthExitBad.js:12:10:12:17 | req.body | TaintedLengthExitBad.js:49:22:49:24 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthExitBad.js:12:10:12:17 | req.body | here | +| TaintedLengthExitBad.js:60:8:60:10 | val | TaintedLengthExitBad.js:14:14:14:21 | req.body | TaintedLengthExitBad.js:60:8:60:10 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthExitBad.js:14:14:14:21 | req.body | here | +| TaintedLengthLodash.js:15:10:15:12 | val | TaintedLengthLodash.js:9:10:9:17 | req.body | TaintedLengthLodash.js:15:10:15:12 | val | Iterating over user controlled object with an unbounded .length property $@. | TaintedLengthLodash.js:9:10:9:17 | req.body | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLength.qlref b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLength.qlref new file mode 100644 index 00000000000..88fa98656c8 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLength.qlref @@ -0,0 +1 @@ +Security/CWE-834/TaintedLength.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthBad.js b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthBad.js new file mode 100644 index 00000000000..dacbb2d1f43 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthBad.js @@ -0,0 +1,59 @@ +'use strict'; + +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +rootRoute.post(function(req, res) { + problem(req.body); + + whileLoop(req.body); + + useLengthIndirectly(req.body); + + noNullPointer(req.body); +}); + +function problem(val) { + var ret = []; + + // Potential DOS! .length property could have been set to an arbitrary + // value! + for (var i = 0; i < val.length; i++) { + ret.push(val[i]); + } +} + +function whileLoop(val) { + var ret = []; + var i = 0; + // Potential DOS! .length property could have been set to an arbitrary + // value! + while (i < val.length) { + ret.push(val[i]); + i++; + } +} + +function useLengthIndirectly(val) { + var ret = []; + + var len = val.length; + + // Same as above, but the .length access happens outside the loop. + for (var i = 0; i < len; i++) { + ret.push(val[i]); + } +} + +// the obvious null-pointer detection should not hit this one. +function noNullPointer(val) { + var ret = []; + + const c = 0; + + for (var i = 0; i < val.length; i++) { + ret.push(val[c].foo); // constantly accessing element 0, therefore not + // guaranteed null-pointer. + } +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthExitBad.js b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthExitBad.js new file mode 100644 index 00000000000..d18554278a2 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthExitBad.js @@ -0,0 +1,70 @@ +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +var _ = require("lodash"); + +rootRoute.post(function (req, res) { + breaks(req.body); + + throws(req.body); + + returns(req.body); + + lodashThrow(req.body); +}); + +function breaks(val) { + var ret = []; + + for (var i = 0; i < val.length; i++) { + for (var k = 0; k < 2; k++) { + if (k == 3) { + // Does not prevent DOS, because this is inside an inner loop. + break; + } + } + ret.push(val[i]); + } +} + +function throws(val) { + var ret = []; + + for (var i = 0; i < val.length; i++) { + if (val[i] == null) { + try { + throw 2; // Is catched, and therefore the DOS is not prevented. + } catch(e) { + // ignored + } + } + ret.push(val[i]); + } +} + +// the obvious null-pointer detection should not hit this one. +function returns(val) { + var ret = []; + + for (var i = 0; i < val.length; i++) { + if (val[i] == null) { + (function (i) { + return i+2; // Does not prevent DOS. + })(i); + } + ret.push(val[i]); + } +} + +function lodashThrow(val) { + _.map(val, function (e) { + if (!e) { + try { + throw new Error(); // Does not prevent DOS + } catch(e) { + // ignored. + } + } + }) +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthExitGood.js b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthExitGood.js new file mode 100644 index 00000000000..a2141e5ffb4 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthExitGood.js @@ -0,0 +1,57 @@ +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +var _ = require("lodash"); + +rootRoute.post(function (req, res) { + breaks(req.body); + + throws(req.body); + + returns(req.body); + + lodashThrow(req.body); +}); + +function breaks(val) { + var ret = []; + + for (var i = 0; i < val.length; i++) { + if (val[i] == null) { + break; // prevents DOS. + } + ret.push(val[i]); + } +} + +function throws(val) { + var ret = []; + + for (var i = 0; i < val.length; i++) { + if (val[i] == null) { + throw 2; // prevents DOS. + } + ret.push(val[i]); + } +} + +// the obvious null-pointer detection should not hit this one. +function returns(val) { + var ret = []; + + for (var i = 0; i < val.length; i++) { + if (val[i] == null) { + return 2; // prevents DOS. + } + ret.push(val[i]); + } +} + +function lodashThrow(val) { + _.map(val, function (e) { + if (!e) { + throw new Error(); // prevents DOS. + } + }) +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthGood.js b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthGood.js new file mode 100644 index 00000000000..8d1f0d543c8 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthGood.js @@ -0,0 +1,73 @@ +'use strict'; + +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +rootRoute.post(function(req, res) { + sanitized(req.body); + + sanitized2(req.body); + + sanitized3(req.body); + + sanitized4(req.body); +}); + +function sanitized(val) { + var ret = []; + + if (!Array.isArray(val)) { + return []; + } + // At this point we know that val must be an Array, and an attacked is + // therefore not able to send a cheap request that spends a lot of time + // inside the loop. + for (var i = 0; i < val.length; i++) { + ret.push(val[i] + 42); + } +} + +function sanitized2(val) { + var ret = []; + + if (typeof val === "object") { + return []; + } + // Val can only be a primitive. Therefore no issue! + for (var i = 0; i < val.length; i++) { + ret.push(val[i] + 42); + } +} + +function isArray(foo) { + return foo instanceof Array; +} + +function sanitized3(val) { + var ret = []; + + if (!isArray(val)) { + return []; + } + // At this point we know that val must be an Array, and an attacked is + // therefore not able to send a cheap request that spends a lot of time + // inside the loop. + for (var i = 0; i < val.length; i++) { + ret.push(val[i] + 42); + } +} + +function sanitized4(val) { + var ret = []; + + if (!(val instanceof Array)) { + return []; + } + // At this point we know that val must be an Array, and an attacked is + // therefore not able to send a cheap request that spends a lot of time + // inside the loop. + for (var i = 0; i < val.length; i++) { + ret.push(val[i] + 42); + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthLodash.js b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthLodash.js new file mode 100644 index 00000000000..755bd9cf48e --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthLodash.js @@ -0,0 +1,17 @@ +'use strict'; + +var _ = require('lodash'); +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +rootRoute.post(function(req, res) { + problem(req.body); + + useLengthIndirectly(req.body); +}); + +function problem(val) { + // can take an arbitrary amount of time with a tainted .length property + _.chunk(val, 2); +} diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthNested.js b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthNested.js new file mode 100644 index 00000000000..a562469f898 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthNested.js @@ -0,0 +1,13 @@ +'use strict'; + +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +var global; + +rootRoute.post(function(req, res) { + for (i = 0; i < req.body.personas.length; i++) { + req.body.personas[i].parentesco.id; + } +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousLengthCheck.js b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousLengthCheck.js new file mode 100644 index 00000000000..6ee6cf5f336 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousLengthCheck.js @@ -0,0 +1,22 @@ +'use strict'; + +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +rootRoute.post(function(req, res) { + problem(req.body); +}); + +function problem(val) { + var ret = []; + + // Prevents DOS + if (val.length > 100) { + return []; + } + + for (var i = 0; i < val.length; i++) { + ret.push(val[i]); + } +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousNullPointer.js b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousNullPointer.js new file mode 100644 index 00000000000..bd3aed633ff --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousNullPointer.js @@ -0,0 +1,58 @@ +'use strict'; + +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +var _ = require("lodash"); + +rootRoute.post(function(req, res) { + nullPointer(req.body); + + nullPointer2(req.body); + + nullPointer3(req.body); + + lodashPointer(req.body); + + lodashArrowFunc(req.body); +}); + +function nullPointer(val) { + var ret = []; + + for (var i = 0; i < val.length; i++) { + ret.push(val[i].foo + 42); + } +} + + +function nullPointer2(val) { + var ret = []; + + for (var i = 0; i < val.length; i++) { + var element = val[i]; + ret.push(element.foo + 42); + } +} + +function nullPointer3(val) { + let arr = val.messaging + for (let i = 0; i < arr.length; i++) { + let event = val.messaging[i] + let sender = event.sender.id + } +} + + +function lodashPointer(val) { + return _.map(val, function(e) { + return e.foo; + }) +} + +function lodashArrowFunc(val) { + return _.map(val, (e) => { + return e.foo; + }); +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousNullPointerInPreviousLoop.js b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousNullPointerInPreviousLoop.js new file mode 100644 index 00000000000..ac456fbdbd9 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-834/TaintedLengthObviousNullPointerInPreviousLoop.js @@ -0,0 +1,24 @@ +'use strict'; + +var express = require('express'); +var router = new express.Router(); +var rootRoute = router.route('foobar'); + +var _ = require("lodash"); + +rootRoute.post(function(req, res) { + nullPointer(req.body); +}); + +function nullPointer(val) { + var ret = []; + + // Has obvious null-pointer. And guards the next loop. + for (var i = 0; i < val.length; i++) { + ret.push(val[i].foo); + } + + for (var i = 0; i < val.length; i++) { + ret.push(val[i]); + } +} From bd59029e2b8fca02b3db1a708e5a2db6d758daa9 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 10 Sep 2019 16:23:23 +0200 Subject: [PATCH 0007/1227] C++: Add pointer-to-member test to syntax-zoo This test was inspired by problems observed in a MySQL snapshot. The results show there are problems with both the QL CFG and the IR. --- .../syntax-zoo/aliased_ssa_sanity.expected | 1 + .../syntax-zoo/drawDifferent.expected | 129 +++++++++++------- .../syntax-zoo/pointer_to_member.cpp | 6 + .../syntax-zoo/raw_sanity.expected | 3 + .../syntax-zoo/tellDifferent.expected | 5 + .../syntax-zoo/unaliased_ssa_sanity.expected | 1 + 6 files changed, 92 insertions(+), 53 deletions(-) diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index 550bce00c2b..5e76fb042be 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -20,6 +20,7 @@ instructionWithoutSuccessor | ms_try_mix.cpp:11:12:11:15 | Chi: call to C | | ms_try_mix.cpp:28:12:28:15 | Chi: call to C | | ms_try_mix.cpp:48:10:48:13 | Chi: call to C | +| pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} | | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | | vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | diff --git a/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected b/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected index a0326f41b6a..d1839e8a79a 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected @@ -1,53 +1,76 @@ -| staticlocals__staticlocals_f2_extractor | false | 31268 | 31268 | f2 | -| staticlocals__staticlocals_f2_extractor | false | 31274 | 31274 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 31277 | 31277 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 31280 | 31280 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 31283 | 31283 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 31286 | 31286 | return ... | -| staticlocals__staticlocals_f2_extractor | false | 31289 | 31289 | { ... } | -| staticlocals__staticlocals_f2_extractor | false | 31292 | 31292 | call to C | -| staticlocals__staticlocals_f2_extractor | false | 31295 | 31295 | initializer for c | -| staticlocals__staticlocals_f2_extractor | false | 31298 | 31298 | call to addOne | -| staticlocals__staticlocals_f2_extractor | false | 31304 | 31304 | 2 | -| staticlocals__staticlocals_f2_extractor | false | 31309 | 31309 | initializer for j | -| staticlocals__staticlocals_f2_extractor | false | 31311 | 31311 | call to addOne | -| staticlocals__staticlocals_f2_extractor | false | 31319 | 31319 | 2 | -| staticlocals__staticlocals_f2_extractor | false | 31321 | 31321 | initializer for two | -| staticlocals__staticlocals_f2_extractor | false | 31325 | 31325 | two | -| staticlocals__staticlocals_f2_extractor | false | 31333 | 31333 | initializer for i | -| staticlocals__staticlocals_f2_extractor | true | 31274 | 31321 | | -| staticlocals__staticlocals_f2_extractor | true | 31277 | 31280 | | -| staticlocals__staticlocals_f2_extractor | true | 31280 | 31283 | | -| staticlocals__staticlocals_f2_extractor | true | 31283 | 31286 | | -| staticlocals__staticlocals_f2_extractor | true | 31286 | 31268 | | -| staticlocals__staticlocals_f2_extractor | true | 31289 | 31274 | | -| staticlocals__staticlocals_f2_extractor | true | 31319 | 31277 | | -| staticlocals__staticlocals_f2_extractor | true | 31321 | 31319 | | -| staticlocals__staticlocals_f2_ql | false | 31268 | 31268 | f2 | -| staticlocals__staticlocals_f2_ql | false | 31274 | 31274 | declaration | -| staticlocals__staticlocals_f2_ql | false | 31277 | 31277 | declaration | -| staticlocals__staticlocals_f2_ql | false | 31280 | 31280 | declaration | -| staticlocals__staticlocals_f2_ql | false | 31283 | 31283 | declaration | -| staticlocals__staticlocals_f2_ql | false | 31286 | 31286 | return ... | -| staticlocals__staticlocals_f2_ql | false | 31289 | 31289 | { ... } | -| staticlocals__staticlocals_f2_ql | false | 31292 | 31292 | call to C | -| staticlocals__staticlocals_f2_ql | false | 31295 | 31295 | initializer for c | -| staticlocals__staticlocals_f2_ql | false | 31298 | 31298 | call to addOne | -| staticlocals__staticlocals_f2_ql | false | 31304 | 31304 | 2 | -| staticlocals__staticlocals_f2_ql | false | 31309 | 31309 | initializer for j | -| staticlocals__staticlocals_f2_ql | false | 31311 | 31311 | call to addOne | -| staticlocals__staticlocals_f2_ql | false | 31319 | 31319 | 2 | -| staticlocals__staticlocals_f2_ql | false | 31321 | 31321 | initializer for two | -| staticlocals__staticlocals_f2_ql | false | 31325 | 31325 | two | -| staticlocals__staticlocals_f2_ql | false | 31333 | 31333 | initializer for i | -| staticlocals__staticlocals_f2_ql | true | 31274 | 31321 | | -| staticlocals__staticlocals_f2_ql | true | 31277 | 31280 | | -| staticlocals__staticlocals_f2_ql | true | 31280 | 31283 | | -| staticlocals__staticlocals_f2_ql | true | 31283 | 31286 | | -| staticlocals__staticlocals_f2_ql | true | 31283 | 31295 | | -| staticlocals__staticlocals_f2_ql | true | 31286 | 31268 | | -| staticlocals__staticlocals_f2_ql | true | 31289 | 31274 | | -| staticlocals__staticlocals_f2_ql | true | 31292 | 31286 | | -| staticlocals__staticlocals_f2_ql | true | 31295 | 31292 | | -| staticlocals__staticlocals_f2_ql | true | 31319 | 31277 | | -| staticlocals__staticlocals_f2_ql | true | 31321 | 31319 | | +| pointer_to_member__pmIsConst_extractor | false | 15698 | 15698 | pmIsConst | +| pointer_to_member__pmIsConst_extractor | false | 15724 | 15724 | declaration | +| pointer_to_member__pmIsConst_extractor | false | 15726 | 15726 | return ... | +| pointer_to_member__pmIsConst_extractor | false | 15728 | 15728 | { ... } | +| pointer_to_member__pmIsConst_extractor | false | 15731 | 15731 | {...} | +| pointer_to_member__pmIsConst_extractor | false | 15734 | 15734 | x1 | +| pointer_to_member__pmIsConst_extractor | false | 15735 | 15735 | initializer for pms | +| pointer_to_member__pmIsConst_extractor | true | 15724 | 15726 | | +| pointer_to_member__pmIsConst_extractor | true | 15726 | 15698 | | +| pointer_to_member__pmIsConst_extractor | true | 15728 | 15724 | | +| pointer_to_member__pmIsConst_ql | false | 15698 | 15698 | pmIsConst | +| pointer_to_member__pmIsConst_ql | false | 15724 | 15724 | declaration | +| pointer_to_member__pmIsConst_ql | false | 15726 | 15726 | return ... | +| pointer_to_member__pmIsConst_ql | false | 15728 | 15728 | { ... } | +| pointer_to_member__pmIsConst_ql | false | 15731 | 15731 | {...} | +| pointer_to_member__pmIsConst_ql | false | 15734 | 15734 | x1 | +| pointer_to_member__pmIsConst_ql | false | 15735 | 15735 | initializer for pms | +| pointer_to_member__pmIsConst_ql | true | 15724 | 15735 | | +| pointer_to_member__pmIsConst_ql | true | 15726 | 15698 | | +| pointer_to_member__pmIsConst_ql | true | 15728 | 15724 | | +| pointer_to_member__pmIsConst_ql | true | 15731 | 15726 | | +| pointer_to_member__pmIsConst_ql | true | 15734 | 15731 | | +| pointer_to_member__pmIsConst_ql | true | 15735 | 15734 | | +| staticlocals__staticlocals_f2_extractor | false | 22465 | 22465 | f2 | +| staticlocals__staticlocals_f2_extractor | false | 22470 | 22470 | declaration | +| staticlocals__staticlocals_f2_extractor | false | 22472 | 22472 | declaration | +| staticlocals__staticlocals_f2_extractor | false | 22474 | 22474 | declaration | +| staticlocals__staticlocals_f2_extractor | false | 22476 | 22476 | declaration | +| staticlocals__staticlocals_f2_extractor | false | 22478 | 22478 | return ... | +| staticlocals__staticlocals_f2_extractor | false | 22480 | 22480 | { ... } | +| staticlocals__staticlocals_f2_extractor | false | 22482 | 22482 | call to C | +| staticlocals__staticlocals_f2_extractor | false | 22484 | 22484 | initializer for c | +| staticlocals__staticlocals_f2_extractor | false | 22486 | 22486 | call to addOne | +| staticlocals__staticlocals_f2_extractor | false | 22490 | 22490 | 2 | +| staticlocals__staticlocals_f2_extractor | false | 22493 | 22493 | initializer for j | +| staticlocals__staticlocals_f2_extractor | false | 22494 | 22494 | call to addOne | +| staticlocals__staticlocals_f2_extractor | false | 22499 | 22499 | 2 | +| staticlocals__staticlocals_f2_extractor | false | 22500 | 22500 | initializer for two | +| staticlocals__staticlocals_f2_extractor | false | 22503 | 22503 | two | +| staticlocals__staticlocals_f2_extractor | false | 22508 | 22508 | initializer for i | +| staticlocals__staticlocals_f2_extractor | true | 22470 | 22500 | | +| staticlocals__staticlocals_f2_extractor | true | 22472 | 22474 | | +| staticlocals__staticlocals_f2_extractor | true | 22474 | 22476 | | +| staticlocals__staticlocals_f2_extractor | true | 22476 | 22478 | | +| staticlocals__staticlocals_f2_extractor | true | 22478 | 22465 | | +| staticlocals__staticlocals_f2_extractor | true | 22480 | 22470 | | +| staticlocals__staticlocals_f2_extractor | true | 22499 | 22472 | | +| staticlocals__staticlocals_f2_extractor | true | 22500 | 22499 | | +| staticlocals__staticlocals_f2_ql | false | 22465 | 22465 | f2 | +| staticlocals__staticlocals_f2_ql | false | 22470 | 22470 | declaration | +| staticlocals__staticlocals_f2_ql | false | 22472 | 22472 | declaration | +| staticlocals__staticlocals_f2_ql | false | 22474 | 22474 | declaration | +| staticlocals__staticlocals_f2_ql | false | 22476 | 22476 | declaration | +| staticlocals__staticlocals_f2_ql | false | 22478 | 22478 | return ... | +| staticlocals__staticlocals_f2_ql | false | 22480 | 22480 | { ... } | +| staticlocals__staticlocals_f2_ql | false | 22482 | 22482 | call to C | +| staticlocals__staticlocals_f2_ql | false | 22484 | 22484 | initializer for c | +| staticlocals__staticlocals_f2_ql | false | 22486 | 22486 | call to addOne | +| staticlocals__staticlocals_f2_ql | false | 22490 | 22490 | 2 | +| staticlocals__staticlocals_f2_ql | false | 22493 | 22493 | initializer for j | +| staticlocals__staticlocals_f2_ql | false | 22494 | 22494 | call to addOne | +| staticlocals__staticlocals_f2_ql | false | 22499 | 22499 | 2 | +| staticlocals__staticlocals_f2_ql | false | 22500 | 22500 | initializer for two | +| staticlocals__staticlocals_f2_ql | false | 22503 | 22503 | two | +| staticlocals__staticlocals_f2_ql | false | 22508 | 22508 | initializer for i | +| staticlocals__staticlocals_f2_ql | true | 22470 | 22500 | | +| staticlocals__staticlocals_f2_ql | true | 22472 | 22474 | | +| staticlocals__staticlocals_f2_ql | true | 22474 | 22476 | | +| staticlocals__staticlocals_f2_ql | true | 22476 | 22478 | | +| staticlocals__staticlocals_f2_ql | true | 22476 | 22484 | | +| staticlocals__staticlocals_f2_ql | true | 22478 | 22465 | | +| staticlocals__staticlocals_f2_ql | true | 22480 | 22470 | | +| staticlocals__staticlocals_f2_ql | true | 22482 | 22478 | | +| staticlocals__staticlocals_f2_ql | true | 22484 | 22482 | | +| staticlocals__staticlocals_f2_ql | true | 22499 | 22472 | | +| staticlocals__staticlocals_f2_ql | true | 22500 | 22499 | | diff --git a/cpp/ql/test/library-tests/syntax-zoo/pointer_to_member.cpp b/cpp/ql/test/library-tests/syntax-zoo/pointer_to_member.cpp index db5d4f6ac4f..d429e4c6acc 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/pointer_to_member.cpp +++ b/cpp/ql/test/library-tests/syntax-zoo/pointer_to_member.cpp @@ -28,3 +28,9 @@ int usePM(int PM::* pm) { return acc; } + +void pmIsConst() { + static const struct { + int PM::* pm1; + } pms = { &PM::x1 }; +} diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index 88a95f2acb0..b9c4bd7eba5 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -7,6 +7,7 @@ missingOperand | misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | +| pointer_to_member.cpp:35:13:35:19 | FieldAddress: x1 | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() | | range_analysis.c:368:10:368:21 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) | | range_analysis.c:369:10:369:36 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) | | range_analysis.c:370:10:370:38 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) | @@ -65,6 +66,7 @@ instructionWithoutSuccessor | ms_try_mix.cpp:48:10:48:13 | CallSideEffect: call to C | | ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... | | ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } | +| pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} | | static_init_templates.cpp:80:27:80:36 | Convert: (void *)... | | static_init_templates.cpp:80:27:80:36 | Convert: (void *)... | | static_init_templates.cpp:89:27:89:36 | Convert: (void *)... | @@ -671,6 +673,7 @@ useNotDominatedByDefinition | ms_try_mix.cpp:38:16:38:19 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | ms_try_mix.cpp:27:6:27:19 | IR: ms_finally_mix | void ms_finally_mix(int) | | ms_try_mix.cpp:41:12:41:15 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | ms_try_mix.cpp:27:6:27:19 | IR: ms_finally_mix | void ms_finally_mix(int) | | ms_try_mix.cpp:51:5:51:11 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | ms_try_mix.cpp:47:6:47:28 | IR: ms_empty_finally_at_end | void ms_empty_finally_at_end() | +| pointer_to_member.cpp:35:13:35:19 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() | | stmt_expr.cpp:30:20:30:21 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | stmt_expr.cpp:21:6:21:6 | IR: g | void stmtexpr::g(int) | | stmt_expr.cpp:31:16:31:18 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | stmt_expr.cpp:21:6:21:6 | IR: g | void stmtexpr::g(int) | | try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) | diff --git a/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected b/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected index ffb4863ef4c..c940eaaa466 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected @@ -1,3 +1,8 @@ +| pointer_to_member__pmIsConst | pointer_to_member.cpp:33:3:35:22 | declaration | pointer_to_member.cpp:35:11:35:21 | initializer for pms | Standard edge, only from QL | +| pointer_to_member__pmIsConst | pointer_to_member.cpp:33:3:35:22 | declaration | pointer_to_member.cpp:36:1:36:1 | return ... | Standard edge, only from extractor | +| pointer_to_member__pmIsConst | pointer_to_member.cpp:35:11:35:21 | initializer for pms | pointer_to_member.cpp:35:13:35:19 | x1 | Standard edge, only from QL | +| pointer_to_member__pmIsConst | pointer_to_member.cpp:35:11:35:21 | {...} | pointer_to_member.cpp:36:1:36:1 | return ... | Standard edge, only from QL | +| pointer_to_member__pmIsConst | pointer_to_member.cpp:35:13:35:19 | x1 | pointer_to_member.cpp:35:11:35:21 | {...} | Standard edge, only from QL | | staticlocals__staticlocals_f2 | file://:0:0:0:0 | call to C | staticlocals.cpp:30:1:30:1 | return ... | Standard edge, only from QL | | staticlocals__staticlocals_f2 | file://:0:0:0:0 | initializer for c | file://:0:0:0:0 | call to C | Standard edge, only from QL | | staticlocals__staticlocals_f2 | staticlocals.cpp:29:5:29:17 | declaration | file://:0:0:0:0 | initializer for c | Standard edge, only from QL | diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index e2d62d73e1b..ab5362cb06c 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -29,6 +29,7 @@ instructionWithoutSuccessor | ms_try_mix.cpp:11:12:11:15 | CallSideEffect: call to C | | ms_try_mix.cpp:28:12:28:15 | CallSideEffect: call to C | | ms_try_mix.cpp:48:10:48:13 | CallSideEffect: call to C | +| pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} | | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | | vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | From ff64aedc0ad48f74894e38d5ae0343ca0f38a2a3 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 27 Aug 2019 14:15:27 +0100 Subject: [PATCH 0008/1227] Python docs: Replace remaining references to old 'Object' API are replaced by new 'Value' API. (cherry picked from commit 6edf9efe1b4a4818186066c240d1bf7208630b5c) --- .../python/introduce-libraries-python.rst | 16 ++++++++-------- docs/language/learn-ql/python/taint-tracking.rst | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/language/learn-ql/python/introduce-libraries-python.rst b/docs/language/learn-ql/python/introduce-libraries-python.rst index b1a6e464a22..f9d134aeb59 100644 --- a/docs/language/learn-ql/python/introduce-libraries-python.rst +++ b/docs/language/learn-ql/python/introduce-libraries-python.rst @@ -297,28 +297,28 @@ The ``SsaVariable`` class represents `static single assignment form `__ This query returns a list of classes for the projects analyzed. If you want to include the results for `builtin classes `__, which do not have any Python source code, show the non-source results. +➤ `See this in the query console `__ This query returns a list of classes for the projects analyzed. If you want to include the results for `builtin classes `__, which do not have any Python source code, show the non-source results. Summary ~~~~~~~ -- `Object `__ +- `Value `__ - - ``ClassObject`` - - ``FunctionObject`` - - ``ModuleObject`` + - ``ClassValue`` + - ``CallableValue`` + - ``ModuleValue`` These classes are explained in more detail in :doc:`Tutorial: Points-to analysis and type inference `. diff --git a/docs/language/learn-ql/python/taint-tracking.rst b/docs/language/learn-ql/python/taint-tracking.rst index 5c6e6965e40..ff177c70f6a 100644 --- a/docs/language/learn-ql/python/taint-tracking.rst +++ b/docs/language/learn-ql/python/taint-tracking.rst @@ -96,7 +96,7 @@ The sink is defined by using a custom ``TaintTracking::Sink`` class. class UnsafeSink extends TaintTracking::Sink { UnsafeSink() { - exists(FunctionObject unsafe | + exists(FunctionValue unsafe | unsafe.getName() = "unsafe" and unsafe.getACall().(CallNode).getAnArg() = this ) @@ -172,7 +172,7 @@ Thus, our example query becomes: class UnsafeSink extends TaintTracking::Sink { UnsafeSink() { - exists(FunctionObject unsafe | + exists(FunctionValue unsafe | unsafe.getName() = "unsafe" and unsafe.getACall().(CallNode).getAnArg() = this ) @@ -255,4 +255,4 @@ What next? ---------- - Experiment with the worked examples in the QL for Python tutorial topics: :doc:`Control flow `, and :doc:`Points-to analysis and type inference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. \ No newline at end of file +- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. From 1fe5d0cb9722da78bb28466f23272f7df3db663a Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 27 Aug 2019 14:20:00 +0100 Subject: [PATCH 0009/1227] Python docs: Remove all references to ClassExpr and FunctionExpr; we want to remove them eventually. (cherry picked from commit 562f4ef60467afc89335b489a44e349dcc8faf41) --- .../learn-ql/python/statements-expressions.rst | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/docs/language/learn-ql/python/statements-expressions.rst b/docs/language/learn-ql/python/statements-expressions.rst index daeb9067a52..2d45abde73a 100644 --- a/docs/language/learn-ql/python/statements-expressions.rst +++ b/docs/language/learn-ql/python/statements-expressions.rst @@ -101,12 +101,10 @@ Each kind of Python expression has its own class. Here is the full class hierarc - ``BoolExpr`` – Short circuit logical operations, ``x and y``, ``x or y`` - ``Bytes`` – A bytes literal, ``b"x"`` or (in Python 2) ``"x"`` - ``Call`` – A function call, ``f(arg)`` - - ``ClassExpr`` – An artificial expression representing the right hand side a ``ClassDef`` assignment - ``Compare`` – A comparison operation, ``0 < x < 10`` - ``Dict`` – A dictionary literal, ``{'a': 2}`` - ``DictComp`` – A dictionary comprehension, ``{k: v for ...}`` - ``Ellipsis`` – An ellipsis expression, ``...`` - - ``FunctionExpr`` – An artificial expression representing the right hand side a ``FunctionDef`` assignment - ``GeneratorExp`` – A generator expression - ``IfExp`` – A conditional expression, ``x if cond else y`` - ``ImportExpr`` – An artificial expression representing the module imported @@ -255,9 +253,9 @@ checks that the value of the attribute (the expression to the left of the dot in Class and function definitions ------------------------------ -As Python is a dynamically typed language, class, and function definitions are executable statements. This means that a class statement is both a statement and a scope containing statements. To represent this cleanly the class definition is broken into a number of parts. At runtime, when a class definition is executed a class object is created and then assigned to a variable of the same name in the scope enclosing the class. This class is created from a code-object representing the source code for the body of the class. To represent this the ``ClassDef`` class (which represents a ``class`` statement) subclasses ``Assign``. The right hand side of the ``ClassDef`` is a ``ClassExpr`` representing the creation of the class. The ``Class`` class, which represents the body of the class, can be accessed via the ``ClassExpr.getInnerScope()`` +As Python is a dynamically typed language, class, and function definitions are executable statements. This means that a class statement is both a statement and a scope containing statements. To represent this cleanly the class definition is broken into a number of parts. At runtime, when a class definition is executed a class object is created and then assigned to a variable of the same name in the scope enclosing the class. This class is created from a code-object representing the source code for the body of the class. To represent this the ``ClassDef`` class (which represents a ``class`` statement) subclasses ``Assign``. The ``Class`` class, which represents the body of the class, can be accessed via the ``ClassDef.getDefinedClass()`` -``FunctionDef``, ``FunctionExpr`` and ``Function`` are handled similarly. +``FunctionDef``, ``Function`` are handled similarly. Here is the relevant part of the class hierarchy: @@ -268,12 +266,6 @@ Here is the relevant part of the class hierarchy: - ``ClassDef`` - ``FunctionDef`` -- ``Expr`` - - - ``ClassExp`` - - - ``FunctionExpr`` - - ``Scope`` - ``Class`` @@ -283,4 +275,4 @@ What next? ---------- - Experiment with the worked examples in the QL for Python tutorial topics: :doc:`Control flow `, :doc:`Points-to analysis and type inference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. \ No newline at end of file +- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. From 63a391a654948e20176b5e003f0756b863b99752 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 27 Aug 2019 14:45:33 +0100 Subject: [PATCH 0010/1227] Python docs: remove confusing reference to SSA as 'dataflow' and add a reference to the taint-tracking library from the library overview page. (cherry picked from commit dafed6b93eae50708d83f3592eed50f1c5d34c60) --- .../python/introduce-libraries-python.rst | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/docs/language/learn-ql/python/introduce-libraries-python.rst b/docs/language/learn-ql/python/introduce-libraries-python.rst index f9d134aeb59..593f6daf037 100644 --- a/docs/language/learn-ql/python/introduce-libraries-python.rst +++ b/docs/language/learn-ql/python/introduce-libraries-python.rst @@ -20,8 +20,8 @@ The QL Python library incorporates a large number of classes, each class corresp - **Syntactic** - classes that represent entities in the Python source code. - **Control flow** - classes that represent entities from the control flow graphs. -- **Data flow** - classes that assist in performing data flow analyses on Python source code. -- **Type inference** - classes that represent the inferred types of entities in the Python source code. +- **Type inference** - classes that represent the inferred values and types of entities in the Python source code. +- **Taint tracking** - classes that represent the source, sinks and kinds of taint used to implement taint-tracking queries. Syntactic classes ~~~~~~~~~~~~~~~~~ @@ -289,10 +289,6 @@ The classes in the control-flow part of the library are: - `ControlFlowNode `__ – A control-flow node. There is a one-to-many relation between AST nodes and control-flow nodes. - `BasicBlock `__ – A non branching list of control-flow nodes. -Data flow -~~~~~~~~~ - -The ``SsaVariable`` class represents `static single assignment form `__ variables (SSA variables). There is a one-to-many relation between variables and SSA variables. The ``SsaVariable`` class provides an accurate and fast means of tracking data flow from definition to use; the ``SsaVariable`` class is an important element for building data flow analyses, including type inference. Type-inference classes ---------------------- @@ -322,8 +318,23 @@ Summary These classes are explained in more detail in :doc:`Tutorial: Points-to analysis and type inference `. +Taint-tracking classes +---------------------- + +The QL library for Python also supplies classes to specify taint-tracking analyses. The ``Configuration`` class can be overrridden to specify a taint-tracking analysis, by specifying source, sinks, sanitizers adn additional flwo steps. For those analyses that require additional types of taint to be tracked the ``TaintKind`` class can be overridden. + + +Summary +~~~~~~~ + +- `TaintKind `__ +- `Configuration `__ + +These classes are explained in more detail in :doc:`Tutorial: Taint tracking and data flow analysis in Python `. + + What next? ---------- -- Experiment with the worked examples in the QL for Python tutorial topics: :doc:`Functions `, :doc:`Statements and expressions `, :doc:`Control flow ` and :doc:`Points-to analysis and type inference `. +- Experiment with the worked examples in the QL for Python tutorial topics: :doc:`Functions `, :doc:`Statements and expressions `, :doc:`Control flow `, :doc:`Points-to analysis and type inference ` and :doc:`Taint tracking and data flow analysis in Python `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. From 6b9566a6e4c35efbd2e73e36afb80788beba2f64 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 12 Aug 2019 15:42:26 +0100 Subject: [PATCH 0011/1227] docs: add rst versions of java slide decks and improve a few c++ slides (cherry picked from commit 7fa7f2dd65dd5a0fe68444e8f8d794c7a1feb7d1) --- .../java-data-flow-code-example.svg | 1 + .../_static-training/java-expression-ast.svg | 1 + .../mismatched-calls-and-returns.svg | 1 + .../static/theme/css/default.css | 48 +++- .../ql-training-rst/cpp/data-flow-cpp.rst | 2 +- .../cpp/global-data-flow-cpp.rst | 84 +----- docs/language/ql-training-rst/index.rst | 15 +- .../java/apache-struts-java.rst | 136 ++++++++++ .../ql-training-rst/java/data-flow-java.rst | 249 +++++++++++++++++ .../java/global-data-flow-java.rst | 251 ++++++++++++++++++ .../ql-training-rst/java/intro-ql-java.rst | 4 +- .../java/program-representation-java.rst | 167 ++++++++++++ .../java/query-injection-java.rst | 144 ++++++++++ .../query-examples/java/data-flow-java-1.ql | 11 + .../query-examples/java/data-flow-java-2.ql | 8 + .../java/global-data-flow-java-1.ql | 14 + .../java/query-injection-java-1.ql | 7 + .../java/query-injection-java-2.ql | 8 + .../java/query-injection-java-3.ql | 12 + .../global-data-flow-extra-slides.rst | 67 +++++ 20 files changed, 1118 insertions(+), 112 deletions(-) create mode 100644 docs/language/ql-training-rst/_static-training/java-data-flow-code-example.svg create mode 100644 docs/language/ql-training-rst/_static-training/java-expression-ast.svg create mode 100644 docs/language/ql-training-rst/_static-training/mismatched-calls-and-returns.svg create mode 100644 docs/language/ql-training-rst/java/apache-struts-java.rst create mode 100644 docs/language/ql-training-rst/java/data-flow-java.rst create mode 100644 docs/language/ql-training-rst/java/global-data-flow-java.rst create mode 100644 docs/language/ql-training-rst/java/program-representation-java.rst create mode 100644 docs/language/ql-training-rst/java/query-injection-java.rst create mode 100644 docs/language/ql-training-rst/query-examples/java/data-flow-java-1.ql create mode 100644 docs/language/ql-training-rst/query-examples/java/data-flow-java-2.ql create mode 100644 docs/language/ql-training-rst/query-examples/java/global-data-flow-java-1.ql create mode 100644 docs/language/ql-training-rst/query-examples/java/query-injection-java-1.ql create mode 100644 docs/language/ql-training-rst/query-examples/java/query-injection-java-2.ql create mode 100644 docs/language/ql-training-rst/query-examples/java/query-injection-java-3.ql create mode 100644 docs/language/ql-training-rst/slide-snippets/global-data-flow-extra-slides.rst diff --git a/docs/language/ql-training-rst/_static-training/java-data-flow-code-example.svg b/docs/language/ql-training-rst/_static-training/java-data-flow-code-example.svg new file mode 100644 index 00000000000..bc854199540 --- /dev/null +++ b/docs/language/ql-training-rst/_static-training/java-data-flow-code-example.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/language/ql-training-rst/_static-training/java-expression-ast.svg b/docs/language/ql-training-rst/_static-training/java-expression-ast.svg new file mode 100644 index 00000000000..5ce46354ad7 --- /dev/null +++ b/docs/language/ql-training-rst/_static-training/java-expression-ast.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/language/ql-training-rst/_static-training/mismatched-calls-and-returns.svg b/docs/language/ql-training-rst/_static-training/mismatched-calls-and-returns.svg new file mode 100644 index 00000000000..083531cac2d --- /dev/null +++ b/docs/language/ql-training-rst/_static-training/mismatched-calls-and-returns.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/language/ql-training-rst/_static-training/slides-semmle-2/static/theme/css/default.css b/docs/language/ql-training-rst/_static-training/slides-semmle-2/static/theme/css/default.css index f73097df55a..3af950d3554 100644 --- a/docs/language/ql-training-rst/_static-training/slides-semmle-2/static/theme/css/default.css +++ b/docs/language/ql-training-rst/_static-training/slides-semmle-2/static/theme/css/default.css @@ -744,11 +744,7 @@ table tr:nth-child(odd) { table th { color: white; font-size: 1em; - background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSI0MCUiIHN0b3AtY29sb3I9IiM0Mzg3ZmQiLz48c3RvcCBvZmZzZXQ9IjgwJSIgc3RvcC1jb2xvcj0iIzJhN2NkZiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==') no-repeat; - background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(40%, #4387fd), color-stop(80%, #2a7cdf)) no-repeat; - background: -moz-linear-gradient(top, #4387fd 40%, #2a7cdf 80%) no-repeat; - background: -webkit-linear-gradient(top, #4387fd 40%, #2a7cdf 80%) no-repeat; - background: linear-gradient(to bottom, #4387fd 40%, #2a7cdf 80%) no-repeat; + background: grey; } /* line 494, ../scss/default.scss */ table td, table th { @@ -758,17 +754,16 @@ table td, table th { /* line 499, ../scss/default.scss */ table td.highlight { color: #515151; - background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSI0MCUiIHN0b3AtY29sb3I9IiNmZmQxNGQiLz48c3RvcCBvZmZzZXQ9IjgwJSIgc3RvcC1jb2xvcj0iI2Y2YzAwMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==') no-repeat; - background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(40%, #ffd14d), color-stop(80%, #f6c000)) no-repeat; - background: -moz-linear-gradient(top, #ffd14d 40%, #f6c000 80%) no-repeat; - background: -webkit-linear-gradient(top, #ffd14d 40%, #f6c000 80%) no-repeat; - background: linear-gradient(to bottom, #ffd14d 40%, #f6c000 80%) no-repeat; + background: grey; } /* line 504, ../scss/default.scss */ table.rows { border-bottom: none; border-right: 1px solid #797979; } +table td { + background: white; +} /* line 510, ../scss/default.scss */ q { @@ -1469,6 +1464,15 @@ hgroup .pre { color: white; } +.subheading { + position: absolute; + top: 62.5%; +} + +.subheading p { + position: relative; +} + /* purple background slides (new section)*/ .background2 { @@ -1593,7 +1597,7 @@ p.first.admonition-title { width: inherit; } -/* images */ +/********* images ************/ /* general styles to scale and centre images*/ .image-box { @@ -1606,7 +1610,7 @@ img { margin: auto; } -/* deck-specific styles for individual images*/ +/********* deck-specific styles for individual images *********/ /* intro to ql */ img.analysis { width: 90%; @@ -1619,6 +1623,26 @@ img.analysis { right: -10%; } +.java-expression-ast { + background-image: url("../../java-expression-ast.svg"); + background-size: cover; +} + +/* java data flow code example */ + +.java-data-flow-code-example { + background-image: url("../../java-data-flow-code-example.svg"); + background-size: cover; +} + +/* extra global data flow slies*/ + +.mismatched-calls-and-returns { + background-image: url("../../mismatched-calls-and-returns.svg"); + background-size: cover; +} + +/******* Other custom styles *******/ /* custom styles for lists*/ ol { diff --git a/docs/language/ql-training-rst/cpp/data-flow-cpp.rst b/docs/language/ql-training-rst/cpp/data-flow-cpp.rst index ffcbff11d02..cac3db9e170 100644 --- a/docs/language/ql-training-rst/cpp/data-flow-cpp.rst +++ b/docs/language/ql-training-rst/cpp/data-flow-cpp.rst @@ -343,4 +343,4 @@ Beyond local data flow - Results are still underwhelming. - Dealing with parameter passing becomes cumbersome. - Instead, let’s turn the problem around and find user-controlled data that flows into a ``printf`` format argument, potentially through calls. -- This needs :doc:`global data flow `. \ No newline at end of file +- This needs :doc:`global data flow `. diff --git a/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst b/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst index 330d56830aa..ce0b34d4b1e 100644 --- a/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst +++ b/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst @@ -252,86 +252,4 @@ Data flow models Extra slides ============ -Exercise: How not to do global data flow -======================================== - -Implement a ``flowStep`` predicate extending ``localFlowStep`` with steps through function calls and returns. Why might we not want to use this? - -.. code-block:: ql - - predicate stepIn(Call c, DataFlow::Node arg, DataFlow::ParameterNode parm) { - exists(int i | arg.asExpr() = c.getArgument(i) | - parm.asParameter() = c.getTarget().getParameter(i)) - } - - predicate stepOut(Call c, DataFlow::Node ret, DataFlow::Node res) { - exists(ReturnStmt retStmt | retStmt.getEnclosingFunction() = c.getTarget() | - ret.asExpr() = retStmt.getExpr() and res.asExpr() = c) - } - - predicate flowStep(DataFlow::Node pred, DataFlow::Node succ) { - DataFlow::localFlowStep(pred, succ) or - stepIn(_, pred, succ) or - stepOut(_, pred, succ) - } - -Mismatched calls and returns -============================ - -.. container:: column-left - - .. code-block:: ql - - char *logFormat(char *fmt) { - log("Observed format string %s.", fmt); - return fmt; - } - - ... - char *dangerousFmt = unvalidatedUserData(); - printf(logFormat(dangerousFmt), args); - ... - char *safeFmt = "Hello %s!"; - printf(logFormat(safeFmt), name); - -.. container:: column-right - - Infeasible path due to mismatched call/return pair! - -Balancing calls and returns -=========================== - -- If we simply take ``flowStep*``, we might mismatch calls and returns, causing imprecision, which in turn may cause false positives. - -- Instead, make sure that matching ``stepIn``/``stepOut`` pairs talk about the same call site: - - .. code-block:: ql - - predicate balancedPath(DataFlow::Node src, DataFlow::Node snk) { - src = snk or DataFlow::localFlowStep(src, snk) or - exists(DataFlow::Node m | balancedPath(src, m) | balancedPath(m, snk)) or - exists(Call c, DataFlow::Node parm, DataFlow::Node ret | - stepIn(c, src, parm) and - balancedPath(parm, ret) and - stepOut(c, ret, snk) - ) - } - -Summary-based global data flow -============================== - -- To avoid traversing the same paths many times, we compute *function summaries* that record if a function parameter flows into a return value: - - .. code-block:: ql - - predicate returnsParameter(Function f, int i) { - exists (Parameter p, ReturnStmt retStmt, Expr ret | - p = f.getParameter(i) and - retStmt.getEnclosingFunction() = f and - ret = retStmt.getExpr() and - balancedPath(DataFlow::parameterNode(p), DataFlow::exprNode(ret)) - ) - } - -- Use this predicate in balancedPath instead of ``stepIn``/``stepOut`` pairs. - +.. include:: ../slide-snippets/global-data-flow-extra-slides.rst diff --git a/docs/language/ql-training-rst/index.rst b/docs/language/ql-training-rst/index.rst index a7af5b375aa..293e9833e1a 100644 --- a/docs/language/ql-training-rst/index.rst +++ b/docs/language/ql-training-rst/index.rst @@ -10,17 +10,4 @@ QL training and variant analysis examples :maxdepth: 1 :hidden: - ./cpp/intro-ql-cpp - ./cpp/bad-overflow-guard - ./cpp/program-representation-cpp - ./cpp/data-flow-cpp - ./cpp/snprintf - ./cpp/global-data-flow-cpp - ./cpp/control-flow-cpp - -.. toctree:: - :glob: - :maxdepth: 1 - :hidden: - - ./java/intro-ql-java \ No newline at end of file + ./**/* \ No newline at end of file diff --git a/docs/language/ql-training-rst/java/apache-struts-java.rst b/docs/language/ql-training-rst/java/apache-struts-java.rst new file mode 100644 index 00000000000..b4f31214b5c --- /dev/null +++ b/docs/language/ql-training-rst/java/apache-struts-java.rst @@ -0,0 +1,136 @@ +======================= +Exercise: Apache Struts +======================= + +.. container:: subheading + + Unsafe deserialization leading to an RCE + + CVE-2017-9805 + +.. container:: semmle-logo + + Semmle :sup:`TM` + +.. rst-class:: setup + +Setup +===== + +For this example you should download: + +- `QL for Eclipse `__ +- `Apache Struts snapshot `__ + +.. note:: + + For this example, we will be analyzing `Apache Struts `__. + + You can also query the project in `the query console `__ on LGTM.com. + + Note that results generated in the query console are likely to differ to those generated in the QL plugin as LGTM.com analyzes the most recent revisions of each project that has been added–the snapshot available to download above is based on an historical version of the code base. + +Unsafe deserialization in Struts +================================ + +Apache Struts provides a ContentTypeHandler interface, which can be implemented for specific content types. It defines the following interface method: + +.. code-block:: java + + void toObject(Reader in, Object target); + + +which is intended to populate the “target” object with data from the reader, usually through deserialization. However, the in parameter should be considered untrusted, and should not be deserialized without sanitization. + +RCE in Apache Struts +==================== + +- Vulnerable code looked like this (`original `__): + +.. code-block:: java + + public void toObject(Reader in, Object target) { + XStream xstream = createXStream(); + xstream.fromXML(in, target); + } + +- Xstream allows deserialization of **dynamic proxies**, which permit remote code execution. + +- Disclosed as `CVE-2017-9805 `__ + +- Blog post: https://lgtm.com/blog/apache_struts_CVE-2017-9805 + +Finding the RCE yourself +======================== + +#. Create a QL class to find the interface ``org.apache.struts2.rest.handler.ContentTypeHandler`` + + **Hint**: Use predicate ``hasQualifiedName(...)`` + +#. Identify methods called ``toObject``, which are defined on direct subtypes of ``ContentTypeHandler`` + + **Hint**: Use ``Method.getDeclaringType()`` and ``Type.getASupertype()`` + +#. Implement a ``DataFlow::Configuration``, defining the source as the first parameter of a ``toObject`` method, and the sink as an instance of ``UnsafeDeserializationSink``. + + **Hint**: Use ``Node::asParameter()`` + +#. Construct the query as a path-problem query, and verify you find one result. + +Model answer, step 1 +==================== + +.. code-block:: ql + + import java + + /** The interface `org.apache.struts2.rest.handler.ContentTypeHandler`. */ + class ContentTypeHandler extends RefType { + ContentTypeHandler() { + this.hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler") + } + } + +Model answer, step 2 +==================== + +.. code-block:: ql + + /** A `toObject` method on a subtype of `org.apache.struts2.rest.handler.ContentTypeHandler`. */ + class ContentTypeHandlerDeserialization extends Method { + ContentTypeHandlerDeserialization() { + this.getDeclaringType().getASupertype() instanceof ContentTypeHandler and + this.hasName("toObject") + +Model answer, step 3 +==================== + +.. code-block:: ql + + import UnsafeDeserialization + import semmle.code.java.dataflow.DataFlow::DataFlow + /** + * Configuration that tracks the flow of taint from the first parameter of + * `ContentTypeHandler.toObject` to an instance of unsafe deserialization. + */ + class StrutsUnsafeDeserializationConfig extends Configuration { + StrutsUnsafeDeserializationConfig() { this = "StrutsUnsafeDeserializationConfig" } + override predicate isSource(Node source) { + source.asParameter() = any(ContentTypeHandlerDeserialization des).getParameter(0) + } + override predicate isSink(Node sink) { sink instanceof UnsafeDeserializationSink } + } + +Model answer, step 4 +==================== + +.. code-block:: ql + + import PathGraph + ... + from PathNode source, PathNode sink, StrutsUnsafeDeserializationConfig conf + where conf.hasFlowPath(source, sink) + and sink.getNode() instanceof UnsafeDeserializationSink + select sink.getNode().(UnsafeDeserializationSink).getMethodAccess(), source, sink, "Unsafe deserialization of $@.", source, "user input" + +More full-featured version: https://github.com/Semmle/demos/tree/master/ql_demos/java/Apache_Struts_CVE-2017-9805 \ No newline at end of file diff --git a/docs/language/ql-training-rst/java/data-flow-java.rst b/docs/language/ql-training-rst/java/data-flow-java.rst new file mode 100644 index 00000000000..d2cee2580b6 --- /dev/null +++ b/docs/language/ql-training-rst/java/data-flow-java.rst @@ -0,0 +1,249 @@ +========================= +Introduction to data flow +========================= + +.. container:: semmle-logo + + Semmle :sup:`TM` + +Finding SPARQL injection vulnerabilities in Java + +.. rst-class:: setup + +Setup +===== + +For this example you should download: + +- `QL for Eclipse `__ +- `VIVO Vitro snapshot `__ + +.. note:: + + For this example, we will be analyzing `VIVO Vitro `__. + + You can also query the project in `the query console `__ on LGTM.com. + + Note that results generated in the query console are likely to differ to those generated in the QL plugin as LGTM.com analyzes the most recent revisions of each project that has been added–the snapshot available to download above is based on an historical version of the code base. + +.. rst-class:: agenda + +Agenda +====== + +- SPARQL injection +- Data flow +- Modules and libraries +- Local data flow +- Local taint tracking + +Motivation +========== + +`SPARQL `__ is a language for querying key-value databases in RDF format, which can suffer from SQL injection-like vulnerabilities: + +.. code-block:: none + + sparqlAskQuery("ASK { <" + individualURI + "> ?p ?o }") + +``individualURI`` is provided by a user, allowing an attacker to prematurely close the ``>``, and provide additional content. + +**Goal**: Find query strings that are created by concatenation. + +.. note:: + + If you have completed the “Example: Query injection” slide deck which was part of the previous course, this example will look familiar to you. + + To understand the scope of this vulnerability, consider what would happen if a malicious user could provide the following as the content of the individualURI variable: + + ``“http://vivoweb.org/ontology/core#FacultyMember> ?p ?o . FILTER regex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!", "(.*a){50}") } #`` + + +Example: SPARQL injection +========================= + +We can write a simple query that finds string concatenations that occur in calls SPARQL query APIs. + +.. rst-class:: build + +.. literalinclude:: ../query-examples/java/data-flow-java-1.ql + :language: ql + +.. note:: + + This is similar, but not identical, to the formulation we had in the previous training deck. It has been rewritten to make it easier for the next step. + +Success! But also missing results... +==================================== + +Query finds a CVE reported by Semmle (CVE-2019-6986), plus one other result, but misses other opportunities where: + + - String concatenation occurs on a different line in the same method. + - String concatenation occurs in a different method. + - String concatenation occurs through StringBuilders or similar. + - Entirety of user input is provided as the query. + +We want to improve our query to catch more of these cases. + +.. note:: + + For more details of the CVE, see: https://github.com/Semmle/SecurityExploits/tree/master/vivo-project/CVE-2019-6986 + + As an example, consider this SPARQL query call: + + .. code-block:: none + + String queryString = "ASK { <" + individualURI + "> ?p ?o }"; + sparqlAskQuery(queryString); + + Here the concatenation occurs before the call, so the existing query would miss this - the string concatenation does not occur *directly* as the first argument of the call. + +Data flow analysis +================== + +- Models flow of data through the program. +- Implemented in the module ``semmle.code.java.dataflow.DataFlow``. +- Class ``DataFlow::Node`` represents program elements that have a value, such as expressions and function parameters. + + - Nodes of the data flow graph. + +- Various predicated represent flow between these nodes. + + - Edges of the data flow graph. + +.. note:: + + The solution here is to use *data flow*. Data flow is, as the name suggests, about tracking the flow of data through the program. It helps answers questions like: *does this expression ever hold a value that originates from a particular other place in the program*? + + We can visualize the data flow problem as one of finding paths through a directed graph, where the nodes of the graph are elements in program, and the edges represent the flow of data between those elements. If a path exists, then the data flows between those two edges. + +Local vs global data flow +========================= + +- Local (“intra-procedural”) data flow models flow within one function; feasible to compute for all functions in a snapshot +- Global (“inter-procedural”) data flow models flow across function calls; not feasible to compute for all functions in a snapshot +- Different APIs, so discussed separately +- This slide deck focuses on the former. + +.. note:: + + For further information, see: + + - `Introduction to data flow analysis in QL `__ + - `Analyzing data flow in Java `__ + +.. rst-class:: background2 + +Local data flow +=============== + +Importing data flow +=================== + +To use the data flow library, add the following import: + +.. code-block:: ql + + import semmle.code.java.dataflow.DataFlow + +**Note**: this library contains an explicit “module” declaration: + +.. code-block:: ql + + module DataFlow { + class Node extends ... { ... } + predicate localFlow(Node source, Node sink) { + localFlowStep*(source, sink) + } + ... + } + +So all references will need to be qualified (that is, ``DataFlow::Node``) + +.. note:: + + A **query library** is file with the extension ``.qll``. Query libraries do not contain a query clause, but may contain modules, classes, and predicates. For example, the `Java data flow library `__ is contained in the ``semmle/code/java/dataflow/DataFlow.qll`` QLL file, and can be imported as shown above. + + A **module** is a way of organizing QL code by grouping together related predicates, classes, and (sub-)modules. They can be either explicitly declared or implicit. A query library implicitly declares a module with the same name as the QLL file. + + For further information on libraries and modules in QL, see the chapter on `Modules `__ in the QL language handbook. + + For further information on importing QL libraries and modules, see the chapter on `Name resolution `__ in the QL language handbook. + +Data flow graph +=============== + +- Class ``DataFlow::Node`` represents data flow graph nodes +- Predicate ``DataFlow::localFlowStep`` represents local data flow graph edges, ``DataFlow::localFlow`` is its transitive closure +- Data flow graph nodes are *not* AST nodes, but they correspond to AST nodes, and there are predicates for mapping between them: + + - ``Expr Node.asExpr()`` + - ``Parameter Node.asParameter()`` + - ``DataFlow::Node DataFlow::exprNode(Expr e)`` + - ``DataFlow::Node DataFlow::parameterNode(Parameter p)`` + - ``etc.`` + +.. note:: + + The ``DataFlow::Node`` class is shared between both the local and global data flow graphs–the primary difference is the edges, which in the “global” case can link different functions. + + ``localFlowStep`` is the “single step” flow relation–that is, it describes single edges in the local data flow graph. ``localFlow`` represents the `transitive `__ closure of this relation–in other words, it contains every pair of nodes where the second node is reachable from the first in the data flow graph. + + The data flow graph is separate from the `AST `__, to allow for flexibility in how data flow is modeled. There are a small number of data flow node types–expression nodes, parameter nodes, uninitialized variable nodes, and definition by reference nodes. Each node provides mapping functions to and from the relevant AST (for example ``Expr``, ``Parameter`` etc.) or symbol table (for example ``Variable``) classes. + +Taint tracking +============== + +- Usually, we want to generalise slightly by not only considering plain data flow, but also “taint” propagation, that is, whether a value is influenced by or derived from another. + +- Examples: + + .. code-block:: java + + sink = source; // source -> sink: data and taint + strcat(sink, source); // source -> sink: taint, not data + +- Library ``semmle.code.java.dataflow.TaintTracking`` provides predicates for tracking taint; ``TaintTracking::localTaintStep`` represents one (local) taint step, ``TaintTracking::localTaint`` is its transitive closure. + +.. note:: + + Taint tracking can be thought of as another type of data flow graph. It usually extends the standard data flow graph for a problem by adding edges between nodes where one one node influences or *taints* another. + + The `API `__ is almost identical to that of the local data flow. All we need to do to switch to taint tracking is ``import semmle.code.java.dataflow.TaintTracking`` instead of ``semmle.code.java.dataflow.DataFlow``, and instead of using ``localFlow``, we use ``localTaint``. + +Exercise: revisiting SPARQL injection +===================================== + +Refine the query to find string concatenation that occurs in the same method, but a different line. + +**Hint**: Use ``DataFlow::localFlow`` to assert that the result flows to the SPARQL call argument, using ``DataFlow::exprNode`` to get the data flow nodes for the relevant expression nodes. + +.. rst-class:: build + +.. literalinclude:: ../query-examples/java/data-flow-java-2.ql + :language: ql + +Refinements (take home exercise) +================================ + +In Java, strings are often created using ``StringBuilder`` and ``StringBuffer`` classes. For example: + + .. code-block:: java + + StringBuilder queryBuilder = new StringBuilder(); + queryBuilder.add("ASK { <"); + queryBuilder.add(individualURI); + queryBuilder.add("> ?p ?o }"); + sparqlAskQuery(queryBuilder); + +**Exercise**: Refine the query to consider strings created from ``StringBuilder`` and ``StringBuffer`` classes as sources of concatenation. + +Beyond local data flow +====================== + +- We are still missing possible results. + + - Concatenation that occurs outside the enclosing method. + +- Instead, let’s turn the problem around and find user-controlled data that flows into a ``printf`` format argument, potentially through calls. +- This needs :doc:`global data flow `. \ No newline at end of file diff --git a/docs/language/ql-training-rst/java/global-data-flow-java.rst b/docs/language/ql-training-rst/java/global-data-flow-java.rst new file mode 100644 index 00000000000..eca3aa7fe3a --- /dev/null +++ b/docs/language/ql-training-rst/java/global-data-flow-java.rst @@ -0,0 +1,251 @@ +================================ +Introduction to global data flow +================================ + +QL for Java + +.. container:: semmle-logo + + Semmle :sup:`TM` + +.. rst-class:: setup + +Setup +===== + +For this example you should download: + +- `QL for Eclipse `__ +- `Apache Struts snapshot `__ + +.. note:: + + For this example, we will be analyzing `Apache Struts `__. + + You can also query the project in `the query console `__ on LGTM.com. + + Note that results generated in the query console are likely to differ to those generated in the QL plugin as LGTM.com analyzes the most recent revisions of each project that has been added–the snapshot available to download above is based on an historical version of the code base. + +.. rst-class:: agenda + +Agenda +====== + +- Global taint tracking +- Sanitizers +- Path queries +- Data flow models + +Information flow +================ + +- Many security problems can be phrased as an information flow problem: + + Given a (problem-specific) set of sources and sinks, is there a path in the data flow graph from some source to some sink? + +- Some examples: + + - SQL injection: sources are user-input, sinks are SQL queries + - Reflected XSS: sources are HTTP requests, sinks are HTTP responses + +- We can solve such problems using the data flow and taint tracking libraries. + +Global data flow and taint tracking +=================================== + +- Recap: + + - Local (“intra-procedural”) data flow models flow within one function; feasible to compute for all functions in a snapshot + - Global (“inter-procedural”) data flow models flow across function calls; not feasible to compute for all functions in a snapshot + +- For global data flow (and taint tracking), we must therefore provided restrictions to ensure the problem is tractable. +- Typically, this involves specifying the *source* and *sink*. + +.. note:: + + As we mentioned in the previous slide deck, while local data flow is feasible to compute for all functions in a snapshot, global data flow is not. This is because the number of paths becomes exponentially larger for global data flow. + + The global data flow (and taint tracking) avoids this problem by requiring that the query author specifies which ``sources`` and ``sinks`` are applicable. This allows the implementation to compute paths between the restricted set of nodes, rather than the full graph. + +Global taint-tracking library +============================= + +The ``semmle.code.java.dataflow.TaintTracking`` library provides a framework for implementing solvers for global taint tracking problems: + + #. Subclass ``TaintTracking::Configuration`` following this template: + + .. code-block:: ql + + class Config extends TaintTracking::Configuration { + Config() { this = "" } + override predicate isSource(DataFlow::Node nd) { ... } + override predicate isSink(DataFlow::Node nd) { ... } + } + + #. Use ``Config.hasFlow(source, sink)`` to find inter-procedural paths. + +.. note:: + + In addition to the taint tracking configuration described here, there is also an equivalent *data flow* configuration in ``semmle.code.java.dataflow.DataFlow``, ``DataFlow::Configuration``. Data flow configurations are used to track whether the exact value produced by a source is used by a sink, whereas taint tracking configurations are used to determine whether the source may influence the value used at the sink. Whether you use taint tracking or data flow depends on the analysis problem you are trying to solve. + +Code injection in Apache Struts +=============================== + +- In April 2018, Man Yue Mo, a security researcher at Semmle, reported 5 remote code execution (RCE) vulnerabilities (CVE-2018-11776) in Apache Struts. + +- These vulnerabilities were caused by untrusted, unsanitized data being evaluated as an OGNL (Object Graph Navigation Library) expression, allowing malicious users to perform remote code execution. + +- Conceptually, this is a global taint tracking problem - does untrusted remote input flow to a method call which evaluates OGNL? + +.. note:: + + More details on the CVE can be found here: https://lgtm.com/blog/apache_struts_CVE-2018-11776 and + https://github.com/Semmle/demos/tree/master/ql_demos/java/Apache_Struts_CVE-2018-11776 + + More details on OGNL can be found here: https://commons.apache.org/proper/commons-ognl/ + +.. rst-class:: java-data-flow-code-example + +Code example +============ + +Finding RCEs (outline) +====================== + +.. literalinclude:: ../query-examples/java/global-data-flow-java-1.ql + :language: ql + +Defining sources +================ + +We want to look for method calls where the method name is ``getNamespace()``, and the declaring type of the method is a class called ``ActionProxy``. + +.. code-block:: ql + + import semmle.code.java.security.Security + + class TaintedOGNLConfig extends TaintTracking::Configuration { + override predicate isSource(DataFlow::Node source) { + exists(Method m | + m.getName() = "getNamespace" and + m.getDeclaringType().getName() = "ActionProxy" and + source.asExpr() = m.getAReference() + ) + } + ... + } + +.. note:: + + We first define what it means to be a *source* of tainted data for this particular problem. In this case, we are interested in the value returned by calls to ``getNamespace()``. + + +Exercise: Defining sinks +======================== + +Fill in the definition of ``isSink``. + +**Hint**: We want to find the first argument of calls to the method compileAndExecute. + +.. code-block:: ql + + import semmle.code.java.security.Security + + class TaintedOGNLConfig extends TaintTracking::Configuration { + override predicate isSink(DataFlow::Node sink) { + /* Fill me in */ + } + ... + } + +.. note:: + + The second part is to define what it means to be a sink for this particular problem. The queries from the previous slide deck will be useful for this exercise. + +Solution: Defining sinks +======================== + +Find a method access to ``compileAndExecute``, and mark the first argument. + +.. code-block:: ql + + import semmle.code.java.security.Security + + class TaintedOGNLConfig extends TaintTracking::Configuration { + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess ma | + ma.getMethod().getName() = "compileAndExecute" and + ma.getArgument(0) = sink.asExpr() + ) + } + ... + } + +Path queries +============ + +Path queries provide information about the identified paths from sources to sinks. Paths can be examined in Path Explorer view. + +Use this template: + +.. code-block:: ql + + /** + * ... + * @kind path-problem + */ + + import semmle.code.java.dataflow.TaintTracking + import DataFlow::PathGraph + ... + from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink + where cfg.hasFlowPath(source, sink) + select sink, source, sink, "" + +.. note:: + + To see the paths between the source and the sinks, we can convert the query to a path problem query. There are a few minor changes that need to be made for this to work - we need an additional import, to specify ``PathNode`` rather than ``Node``, and to add the source/sink to the query output (so that we can automatically determine the paths). + +Defining sanitizers +=================== + +A sanitizer allows us to *prevent* flow through a particular node in the graph. For example, flows that go via ``ValueStackShadowMap`` are not particularly interesting, because it is a class that is rarely used in practice. We can exclude them like so: + +.. code-block:: ql + + class TaintedOGNLConfig extends TaintTracking::Configuration { + override predicate isSanitizer(DataFlow::Node nd) { + nd.getEnclosingCallable() + .getDeclaringType() + .getName() = "ValueStackShadowMap" + } + ... + } + +Defining additional taint steps +=============================== + +Add an additional taint step that (heuristically) taints a local variable if it is a pointer, and it is passed to a function in a parameter position that taints it. + +.. code-block:: ql + + class TaintedOGNLConfig extends TaintTracking::Configuration { + override predicate isAdditionalTaintStep(DataFlow::Node pred, + DataFlow::Node succ) { + exists(Field f, RefType t | + node1.asExpr() = f.getAnAssignedValue() and + node2.asExpr() = f.getAnAccess() and + node1.asExpr().getEnclosingCallable().getDeclaringType() = t and + node2.asExpr().getEnclosingCallable().getDeclaringType() = t + ) + } + ... + } + + +.. rst-class:: end-slide + +Extra slides +============ + +.. include:: ../slide-snippets/global-data-flow-extra-slides.rst diff --git a/docs/language/ql-training-rst/java/intro-ql-java.rst b/docs/language/ql-training-rst/java/intro-ql-java.rst index 1db5878d928..68a403641d9 100644 --- a/docs/language/ql-training-rst/java/intro-ql-java.rst +++ b/docs/language/ql-training-rst/java/intro-ql-java.rst @@ -47,7 +47,7 @@ Oops } - The return statement has been commented out (during debugging?) -- The if statement is now dead code +- The ``if`` statement is now dead code - No explicit bounds checking, will throw ``ArrayIndexOutOfbounds`` .. note:: @@ -182,7 +182,7 @@ Iterative query refinement - **Common workflow**: Start with a simple query, inspect a few results, refine, repeat. -- For example, empty then branches are not a problem if there is an else. +- For example, empty ``then`` branches are not a problem if there is an ``else``. - **Exercise**: How can we refine the query to take this into account? diff --git a/docs/language/ql-training-rst/java/program-representation-java.rst b/docs/language/ql-training-rst/java/program-representation-java.rst new file mode 100644 index 00000000000..3c90b33bc88 --- /dev/null +++ b/docs/language/ql-training-rst/java/program-representation-java.rst @@ -0,0 +1,167 @@ +====================== +Program representation +====================== + +QL for Java + +.. container:: semmle-logo + + Semmle :sup:`TM` + +.. rst-class:: agenda + +Agenda +====== + +- Abstract syntax trees +- Database representation +- Program elements +- AST classes + +Abstract syntax trees +===================== + +The basic representation of an analyzed program is an *abstract syntax tree (AST)*. + +.. container:: column-left + + .. code-block:: java + + try { + ... + } catch (AnException e) { + } + +.. container:: ast-graph + + .. graphviz:: + + digraph { + graph [ dpi = 1000 ] + node [shape=polygon,sides=4,color=blue4,style="filled,rounded", fontname=consolas,fontcolor=white] + a [label=] + b [label=] + c [label=<...>,color=white,fontcolor=black] + d [label=DeclExpr>] + e [label=<...>,color=white,fontcolor=black] + f [label=<...>,color=white,fontcolor=black] + g [label=<...>,color=white,fontcolor=black] + + a -> {b, c} + b -> {d, e} + d -> {f, g} + } + + + +.. note:: + + When writing queries in QL it is important to have in mind the underlying representation of the program which is stored in the database. Typically queries make use of the “AST” representation of the program - a tree structure where program elements are nested within other program elements. + + The “Introducing the Java libraries” help topic contains a more complete overview of important AST classes and the rest of the Java QL libraries: https://help.semmle.com/QL/learn-ql/ql/java/introduce-libraries-java.html + +Database representations of ASTs +================================ + +AST nodes and other program elements are encoded in the database as *entity values*. Entities are implemented as integers, but in QL they are opaque - all one can do with them is to check their equality. + +Each entity belongs to an entity type. Entity types have names starting with “@” and are defined in the database schema (not in QL). + +Properties of AST nodes and their relationships to each other are encoded by database relations, which are predicates defined in the database (not in QL). + +Entity types are rarely used directly, the usual pattern is to define a QL class that extends the type and exposes properties of its entities through member predicates. + +.. note:: + + ASTs are a typical example of the kind of data representation one finds in object-oriented programming, with data-carrying nodes that reference each other. At first glance, QL, which can only work with atomic values, does not seem to be well suited for working with this kind of data. However, ultimately all that we require of the nodes in an AST is that they have an identity. The relationships among nodes, usually implemented by reference-valued object fields in other languages, can just as well (and arguably more naturally) be represented as relations over nodes. Attaching data (such as strings or numbers) to nodes can also be represented with relations over nodes and primitive values. All we need is a way for relations to reference nodes. This is achieved in QL (as in other database languages) by means of *entity values* (or entities, for short), which are opaque atomic values, implemented as integers under the hood. + + It is the job of the extractor to create entity values for all AST nodes and populate database relations that encode the relationship between AST nodes and any values associated with them. These relations are *extensional*, that is, explicitly stored in the database, unlike the relations described by QL predicates, which we also refer to as *intensional* relations. Entity values belong to *entity types*, whose name starts with “@” to set them apart from primitive types and classes. + + The interface between entity types and extensional relations on the one hand and QL predicates and classes on the other hand is provided by the *database schema*, which defines the available entity types and the schema of each extensional relation, that is, how many columns the relation has, and which entity type or primitive type the values in each column come from. QL programs can refer to entity types and extensional relations just as they would refer to QL classes and predicates, with the restriction that entity types cannot be directly selected in a “select” clause, since they do not have a well-defined string representation. + + For example, the database schema for Java snapshot databases is here: https://github.com/Semmle/ql/blob/master/java/ql/src/config/semmlecode.dbscheme + + +Program elements +================ + +- The QL class ``Element`` represents program elements with a name. +- This includes: packages (``Package``), compilation units (``CompilationUnit``), types (``Type``), methods (``Method``), constructors (``Constructor``), and variables (``Variable``). +- It is often convenient to refer to an element that might either be a method or a constructor; the class ``Callable``, which is a common superclass of ``Method`` and ``Constructor``, can be used for this purpose. + +.. note:: + + The “Introducing the Java libraries” help topic contains a more complete overview of important AST classes and the rest of the Java QL libraries: https://help.semmle.com/QL/learn-ql/ql/java/introduce-libraries-java.html + +AST +=== + +There are two primary AST classes, used within ``Callables``: + + - ``Expr``: expressions such as assignments, variable references, function calls, ... + - ``Stmt``: statements such as conditionals, loops, try statements, ... + +Operations are provided for exploring the AST: + + - ``Expr.getAChildExpr`` returns a sub-expression of a given expression. + - ``Stmt.getAChild`` returns a statement or expression that is nested directly inside a given statement. + - ``Expr.getParent`` and ``Stmt.getParent`` return the parent node of an AST node. + +.. note:: + + The “Introducing the Java libraries” help topic contains a more complete overview of important AST classes and the rest of the Java QL libraries: https://help.semmle.com/QL/learn-ql/ql/java/introduce-libraries-java.html + +Types +===== + +The database also includes information about the types used in a program: + +- ``PrimitiveType`` represents a `primitive type `__, that is, one of ``boolean``, ``byte``, ``char``, ``double``, ``float``, ``int``, ``long``, ``short``. QL also classifies ``void`` and ```` (the type of the ``null`` literal) as primitive types. +- ``RefType`` represents a reference type; it has several subclasses: + + - ``Class`` represents a Java class. + - ``Interface`` represents a Java interface. + - ``EnumType`` represents a Java enum type. + - ``Array`` represents a Java array type. + +.. note:: + + The “Introducing the Java libraries” help topic contains a more complete overview of important AST classes and the rest of the Java QL libraries: https://help.semmle.com/QL/learn-ql/ql/java/introduce-libraries-java.html + +Working with variables +====================== + +``Variable`` represents program variables, including locally scoped variables (``LocalScopeVariable``), fields (``Fields``), and parameters (``Parameters``): + +- ``string Variable.getName()`` +- ``Type Variable.getType()`` + +``Access`` represents references to declared entities such as methods (``MethodAccess``) and variables (``VariableAccess``), including fields (``FieldAccess``). + +- ``Declaration Access.getTarget()`` + +``VariableDeclarationEntry`` represents declarations or definitions of a variable. + +- ``Variable VariableDeclarationEntry.getVariable()`` + +Working with callables +====================== + +Callables are represented by the ``Callable`` QL class. + +Calls to callables are modeled by the QL class ``Call`` and its subclasses: + +- ``Call.getCallee()`` gets the declared target of the call +- ``Call.getAReference()`` gets a call to this function + +Typically, callables are identified by name: + +- ``string Callable.getName()`` +- ``string Callable.getQualifiedName()`` + +.. rst-class:: java-expression-ast + +Example: Java expression AST +============================ + +.. diagram copied from google slides \ No newline at end of file diff --git a/docs/language/ql-training-rst/java/query-injection-java.rst b/docs/language/ql-training-rst/java/query-injection-java.rst new file mode 100644 index 00000000000..ea536b64467 --- /dev/null +++ b/docs/language/ql-training-rst/java/query-injection-java.rst @@ -0,0 +1,144 @@ +======================== +Example: Query injection +======================== + +QL for Java + +.. container:: semmle-logo + + Semmle :sup:`TM` + +.. rst-class:: setup + +Setup +===== + +For this example you should download: + +- `QL for Eclipse `__ +- `VIVO Vitro snapshot `__ + +.. note:: + + For this example, we will be analyzing `VIVO Vitro `__. + + You can also query the project in `the query console `__ on LGTM.com. + + Note that results generated in the query console are likely to differ to those generated in the QL plugin as LGTM.com analyzes the most recent revisions of each project that has been added–the snapshot available to download above is based on an historical version of the code base. + +SQL injection +============= + +- Occurs when user input is used to construct an SQL query without any sanitization or escaping. + +- Classic example involves constructing a query using string concatenation: + + .. code-block:: sql + + runQuery("SELECT * FROM users WHERE id='" + userId + "'"); + + +- If the ``userId`` can be provided by a user, and is not sanitized, then a malicious user can provide input that manipulates the intended query. + +- For example, providing the input ``"' OR '1'='1"`` would allow the attacker to return all records in the users table. + +.. note:: + + `SQL `__ is a database query language, which is often used from within other programming languages to interact with a database. The typical case is that a query is to be executed to find some data, based on some input provided by the user - for example, the user’s ID. However, the interface between the host programming language and SQL is typically implemented by passing a string containing the query to some API. + +SPARQL injection +================ + +- `SPARQL `__ is a language for querying key-value databases in RDF format. + +- The same type of vulnerability can occur for SPARQL as for SQL: if the SPARQL query is constructed through string concatenation, a malicious user can subvert the query: + + .. code-block:: sql + + sparqlAskQuery("ASK { <" + individualURI + "> ?p ?o }"); + +- SPARQL is used by many projects, but we will be looking at `VIVO Vitro `__. + +.. rst-class:: background2 + +Developing a QL query +====================== + +Finding a query concatenation + +QL query: find SPARQL methods +============================= + +Let’s start by looking for calls to methods with names of the form ``sparql*Query``, using the classes ``Method`` and ``MethodAccess`` from the Java library. + +.. rst-class:: build + +.. literalinclude:: ../query-examples/java/query-injection-java-1.ql + +.. note:: + + - When performing `variant analysis `__, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong. + - In this case, we start by looking for all the method calls which appear to run, before trying to refine the query to find cases which are vulnerable to query injection. + - The ``select`` clause defines what this query is looking for: + + - a ``MethodAccess``: the call to a SPARQL query method + - a ``Method``: the SPARQL query method. + + - The ``where`` part of the query ties these three QL variables together using `predicates `__ defined in the `standard QL for Java library `__. + +QL query: find string concatenation +=================================== + +We now need to define what would make these API calls unsafe. + +A simple heuristic would be to look for string concatenation used in the query argument. We may want to reuse this logic, so let us create a separate predicate. + +Looking at autocomplete suggestions, we see that we can get the type of an expression using the getType() method. + +.. rst-class:: build + +.. code-block:: ql + + predicate isStringConcat(AddExpr ae) { + ae.getType() instanceof TypeString + } + +.. note:: + + - An important part of the query is to determine whether a given expression is string concatenation. + - We therefore write a helper predicate for finding string concatenation. + - This predicate effectively represents the set of all add expressions in the database where the type of the expression is ``TypeString`` - that is, the addition produces a ``String`` value. + +QL query: SPARQL injection +========================== + +We can now combine our predicate with the existing query. +Note that we do not need to specify that the argument of the method access is an ``AddExpr`` - this is implied by the ``isStringConcat`` requirement. + +Now our query becomes: + +.. rst-class:: build + +.. literalinclude:: ../query-examples/java/query-injection-java-2.ql + :language: ql + +The final query +=============== + +.. literalinclude:: ../query-examples/java/query-injection-java-3.ql + :language: ql + +There are two results, one of which was assigned **CVE-2019-6986**. + +.. note:: + + Full write up and exploit can be found here: https://github.com/Semmle/SecurityExploits/tree/master/vivo-project/CVE-2019-6986 + +Follow up +========= + +- Our query successfully finds cases where the concatenation occurs in the argument to the SPARQL API. + +- However, in general, the concatenation could occur before the method call. + +- For this, we would need to use :doc:`local data flow `, which is the topic of the next set of training slides. diff --git a/docs/language/ql-training-rst/query-examples/java/data-flow-java-1.ql b/docs/language/ql-training-rst/query-examples/java/data-flow-java-1.ql new file mode 100644 index 00000000000..efc8793b794 --- /dev/null +++ b/docs/language/ql-training-rst/query-examples/java/data-flow-java-1.ql @@ -0,0 +1,11 @@ +import java + +class StringConcat extends AddExpr { + StringConcat() { getType() instanceof TypeString } +} + +from MethodAccess ma +where + ma.getMethod().getName().matches("sparql%Query") and + ma.getArgument(0) instanceof StringConcat +select ma, "SPARQL query vulnerable to injection." \ No newline at end of file diff --git a/docs/language/ql-training-rst/query-examples/java/data-flow-java-2.ql b/docs/language/ql-training-rst/query-examples/java/data-flow-java-2.ql new file mode 100644 index 00000000000..14020c1dc22 --- /dev/null +++ b/docs/language/ql-training-rst/query-examples/java/data-flow-java-2.ql @@ -0,0 +1,8 @@ +import java +import semmle.code.java.dataflow.DataFlow::DataFlow + +from MethodAccess ma, StringConcat stringConcat +where + ma.getMethod().getName().matches("sparql%Query") and + localFlow(exprNode(stringConcat), exprNode(ma.getArgument(0))) +select ma, "SPARQL query vulnerable to injection." \ No newline at end of file diff --git a/docs/language/ql-training-rst/query-examples/java/global-data-flow-java-1.ql b/docs/language/ql-training-rst/query-examples/java/global-data-flow-java-1.ql new file mode 100644 index 00000000000..f30e4c20d68 --- /dev/null +++ b/docs/language/ql-training-rst/query-examples/java/global-data-flow-java-1.ql @@ -0,0 +1,14 @@ +import java +import semmle.code.java.dataflow.TaintTracking + +class TaintedOGNLConfig extends TaintTracking::Configuration { + TaintedOGNLConfig() { this = "TaintedOGNLConfig" } + override predicate isSource(DataFlow::Node source) { /* TBD */ } + override predicate isSink(DataFlow::Node sink) { /* TBD */ } +} + +from TaintedOGNLConfig cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) +select source, + "This untrusted input is evaluated as an OGNL expression $@.", + sink, "here" \ No newline at end of file diff --git a/docs/language/ql-training-rst/query-examples/java/query-injection-java-1.ql b/docs/language/ql-training-rst/query-examples/java/query-injection-java-1.ql new file mode 100644 index 00000000000..af007406057 --- /dev/null +++ b/docs/language/ql-training-rst/query-examples/java/query-injection-java-1.ql @@ -0,0 +1,7 @@ +import java + +from Method m, MethodAccess ma +where + m.getName().matches("sparql%Query") and + ma.getMethod() = m +select ma, m \ No newline at end of file diff --git a/docs/language/ql-training-rst/query-examples/java/query-injection-java-2.ql b/docs/language/ql-training-rst/query-examples/java/query-injection-java-2.ql new file mode 100644 index 00000000000..84f8fde6363 --- /dev/null +++ b/docs/language/ql-training-rst/query-examples/java/query-injection-java-2.ql @@ -0,0 +1,8 @@ +import java + +from Method m, MethodAccess ma +where + m.getName().matches("sparql%Query") and + ma.getMethod() = m and + isStringConcat(ma.getArgument(0)) +select ma, m \ No newline at end of file diff --git a/docs/language/ql-training-rst/query-examples/java/query-injection-java-3.ql b/docs/language/ql-training-rst/query-examples/java/query-injection-java-3.ql new file mode 100644 index 00000000000..923c65294f1 --- /dev/null +++ b/docs/language/ql-training-rst/query-examples/java/query-injection-java-3.ql @@ -0,0 +1,12 @@ +import java + +predicate isStringConcat(AddExpr ae) { + ae.getType() instanceof TypeString +} + +from Method m, MethodAccess ma +where + m.getName().matches("sparql%Query") and + ma.getMethod() = m and + isStringConcat(ma.getArgument(0)) +select ma, "SPARQL query vulnerable to injection." \ No newline at end of file diff --git a/docs/language/ql-training-rst/slide-snippets/global-data-flow-extra-slides.rst b/docs/language/ql-training-rst/slide-snippets/global-data-flow-extra-slides.rst new file mode 100644 index 00000000000..93b64f02dba --- /dev/null +++ b/docs/language/ql-training-rst/slide-snippets/global-data-flow-extra-slides.rst @@ -0,0 +1,67 @@ +Exercise: How not to do global data flow +======================================== + +Implement a flowStep predicate extending localFlowStep with steps through function calls and returns. Why might we not want to use this? + +.. code-block:: ql + + predicate stepIn(Call c, DataFlow::Node arg, DataFlow::ParameterNode parm) { + exists(int i | arg.asExpr() = c.getArgument(i) | + parm.asParameter() = c.getTarget().getParameter(i)) + } + + predicate stepOut(Call c, DataFlow::Node ret, DataFlow::Node res) { + exists(ReturnStmt retStmt | retStmt.getEnclosingFunction() = c.getTarget() | + ret.asExpr() = retStmt.getExpr() and res.asExpr() = c) + } + + predicate flowStep(DataFlow::Node pred, DataFlow::Node succ) { + DataFlow::localFlowStep(pred, succ) or + stepIn(_, pred, succ) or + stepOut(_, pred, succ) + } + +.. rst-class:: mismatched-calls-and-returns + +Mismatched calls and returns +============================ + +.. diagram copied from google slides + +Balancing calls and returns +=========================== + +- If we simply take ``flowStep*``, we might mismatch calls and returns, causing imprecision, which in turn may cause false positives. + +- Instead, make sure that matching ``stepIn``/``stepOut`` pairs talk about the same call site: + +.. code-block:: ql + + predicate balancedPath(DataFlow::Node src, DataFlow::Node snk) { + src = snk or DataFlow::localFlowStep(src, snk) or + exists(DataFlow::Node m | balancedPath(src, m) | balancedPath(m, snk)) or + exists(Call c, DataFlow::Node parm, DataFlow::Node ret | + stepIn(c, src, parm) and + balancedPath(parm, ret) and + stepOut(c, ret, snk) + ) + } + +Summary-based global data flow +============================== + +- To avoid traversing the same paths many times, we compute function summaries that record if a function parameter flows into a return value: + + .. code-block:: ql + + predicate returnsParameter(Function f, int i) { + exists (Parameter p, ReturnStmt retStmt, Expr ret | + p = f.getParameter(i) and + retStmt.getEnclosingFunction() = f and + ret = retStmt.getExpr() and + balancedPath(DataFlow::parameterNode(p), DataFlow::exprNode(ret)) + ) + } + +- Use this predicate in ``balancedPath`` instead of ``stepIn``/``stepOut`` pairs. + From dfeab086dbe03c9857f016735db7907857e43fd9 Mon Sep 17 00:00:00 2001 From: james Date: Fri, 23 Aug 2019 16:04:16 +0100 Subject: [PATCH 0012/1227] docs: add template slide deck (cherry picked from commit ec9ca6852bb1433d65bccaac033db67178db7cee) --- docs/language/ql-training-rst/index.rst | 3 +- docs/language/ql-training-rst/template.rst | 172 +++++++++++++++++++++ 2 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 docs/language/ql-training-rst/template.rst diff --git a/docs/language/ql-training-rst/index.rst b/docs/language/ql-training-rst/index.rst index 293e9833e1a..55e4c0f7005 100644 --- a/docs/language/ql-training-rst/index.rst +++ b/docs/language/ql-training-rst/index.rst @@ -10,4 +10,5 @@ QL training and variant analysis examples :maxdepth: 1 :hidden: - ./**/* \ No newline at end of file + ./**/* + template \ No newline at end of file diff --git a/docs/language/ql-training-rst/template.rst b/docs/language/ql-training-rst/template.rst new file mode 100644 index 00000000000..ba4c111d9d0 --- /dev/null +++ b/docs/language/ql-training-rst/template.rst @@ -0,0 +1,172 @@ +.. Template for rst slide shows + + +.. Key points: + - Each heading marks the start of a new slide + - The default slide style is a plain white-ish background with minimal company branding + - Different slide designs have been preconfigured. To choose a different layout + use the appropriate .. rst-class:: directive. For examples of the different designs, + see the template below. + - Additional notes can be added to a slide using a .. note:: directive + - Press P to access the additional notes on the rendered slides. + - Press F is go into full screen mode when viewing the rendered slides. + + +.. Title slide. Includes the deck title, subtitles, and the company logo + +=================== +Template slide deck +=================== + +.. container:: subheading + + First subheading + + Second subheading + +.. container:: semmle-logo + + Semmle :sup:`TM` + +.. Set up slide. Include link to QL4E snapshots required for examples + +.. rst-class:: setup + +Setup +===== + +For this example you should download: + +- `QL for Eclipse `__ +- A snapshot + +.. note:: + + Some notes about the project, perhaps a link to the project page on LGTM. + +.. Agenda slide. Explaining what is to be covered in the presentation + +.. rst-class:: Agenda + +Agenda +====== + +- Item 1 +- Item 2 +- Item 3 +- Item 4 +- Item 5 + + +Text +==== + +If you don't specify an rst-class, you default to the 'basic' slide design. + +You can fit about this much text on a slide: + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor +incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis +nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore +eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, +sunt in culpa qui officia deserunt mollit anim id est laborum. + +Code sample +=========== + +Use a ``.. code-block::`` directive to include a code snippet. +Specify the language after the directive to add syntax highlighting. + +.. code-block:: ql + + import cpp + + from AddExpr a, Variable v, RelationalOperation cmp + where + a.getAnOperand() = v.getAnAccess() and + cmp.getAnOperand() = a and + cmp.getAnOperand() = v.getAnAccess() + select cmp, "Overflow check." + +Columns and graphs +================== + +.. container:: column-left + + ``.. container:: column-left`` sets up a column on the left of the slide. + + ``.. container:: column-right`` sets up a column on the right of the slide. + + Code can be included in columns: + + .. code-block:: ql + + import cpp + + from IfStmt ifstmt, Block block + where + block = ifstmt.getThen() and + block.isEmpty() + select ifstmt, "This if-statement is redundant." + + +.. container:: column-right + + Graphs can be built from text using a ``.. graphviz directive``. + See the source file for details. + + .. graphviz:: + + digraph { + graph [ dpi = 1000 ] + node [shape=polygon,sides=4,color=blue4,style="filled,rounded", fontname=consolas,fontcolor=white] + a [label=ParameterNode>] + b [label=ExprNode>] + c [label=ExprNode>] + d [label=ExprNode>] + a -> b + b -> {c, d} + } + +.. You can indicate a new concept by using a purple slide background + +.. rst-class:: background2 + +Purple background +================= + +Subheading on purple slide + +Including snippets +================== + +rst snippets can be included using: + +.. code-block:: none + + .. include:: path/to/file.rst + +Code snippets can be included using: + +.. code-block:: none + + .. literalinclude:: path/to/file.ql + :language: ql + :emphasize-lines: 3-6 + +Specify the language to apply syntax highlighting and the lines of the fragment that you want to emphasize. + +Further details +=============== + +- For more information on writing in reStructuredText, see http://docutils.sourceforge.net/rst.html. + +- For more information on Sphinx, see https://www.sphinx-doc.org. + +- For more information about hieroglpyh, the Sphinx extension used to generate these slides, see https://github.com/nyergler/hieroglyph. + +- For more information about creating graphs, see https://build-me-the-docs-please.readthedocs.io/en/latest/Using_Sphinx/UsingGraphicsAndDiagramsInSphinx.html. + + +.. The final slide with the company details is generated automatically. \ No newline at end of file From 6dcf9997e9f738d675d67207d3c1c5306eb69f90 Mon Sep 17 00:00:00 2001 From: james Date: Thu, 29 Aug 2019 11:01:50 +0100 Subject: [PATCH 0013/1227] docs: make use of includes for local and global data flow slides (cherry picked from commit b89f0161aa6cd211ae3857993e76208a2893d359) --- .../ql-training-rst/cpp/data-flow-cpp.rst | 159 +---------------- .../cpp/global-data-flow-cpp.rst | 76 +-------- .../java/global-data-flow-java.rst | 79 +-------- .../slide-snippets/global-data-flow.rst | 51 ++++++ .../slide-snippets/local-data-flow.rst | 160 ++++++++++++++++++ .../slide-snippets/path-queries.rst | 24 +++ 6 files changed, 252 insertions(+), 297 deletions(-) create mode 100644 docs/language/ql-training-rst/slide-snippets/global-data-flow.rst create mode 100644 docs/language/ql-training-rst/slide-snippets/local-data-flow.rst create mode 100644 docs/language/ql-training-rst/slide-snippets/path-queries.rst diff --git a/docs/language/ql-training-rst/cpp/data-flow-cpp.rst b/docs/language/ql-training-rst/cpp/data-flow-cpp.rst index cac3db9e170..969f791bcb5 100644 --- a/docs/language/ql-training-rst/cpp/data-flow-cpp.rst +++ b/docs/language/ql-training-rst/cpp/data-flow-cpp.rst @@ -112,164 +112,13 @@ We need something better. Here, ``DMLOut`` and ``ExtOut`` are macros that expand to formatting calls. The format specifier is not constant, in the sense that the format argument is not a string literal. However, it is clearly one of two possible constants, both with the same number of format specifiers. - What we need is a way to determine whether the format argument is ever set to something that is not constant. + What we need is a way to determine whether the format argument is ever set to something that is, not constant. -Data flow analysis -================== +.. include general data flow slides -- Models flow of data through the program. -- Implemented in the module ``semmle.code.cpp.dataflow.DataFlow``. -- Class ``DataFlow::Node`` represents program elements that have a value, such as expressions and function parameters. +.. include:: ../slide-snippets/local-data-flow.rst - - Nodes of the data flow graph. - -- Various predicated represent flow between these nodes. - - - Edges of the data flow graph. - -.. note:: - - The solution here is to use *data flow*. Data flow is, as the name suggests, about tracking the flow of data through the program. It helps answers questions like: *does this expression ever hold a value that originates from a particular other place in the program*? - - We can visualize the data flow problem as one of finding paths through a directed graph, where the nodes of the graph are elements in the program, and the edges represent the flow of data between those elements. If a path exists, then the data flows between those two edges. - -Data flow graphs -================ - -.. container:: column-left - - Example: - - .. code-block:: cpp - - int func(int, tainted) { - int x = tainted; - if (someCondition) { - int y = x; - callFoo(y); - } else { - return x; - } - return -1; - } - -.. container:: column-right - - Data flow graph: - - .. graphviz:: - - digraph { - graph [ dpi = 1000 ] - node [shape=polygon,sides=4,color=blue4,style="filled,rounded", fontname=consolas,fontcolor=white] - a [label=ParameterNode>] - b [label=ExprNode>] - c [label=ExprNode>] - d [label=ExprNode>] - e [label=ExprNode>] - - a -> b - b -> {c, d} - c -> e - - } - -Local vs global data flow -========================= - -- Local (“intra-procedural”) data flow models flow within one function; feasible to compute for all functions in a snapshot -- Global (“inter-procedural”) data flow models flow across function calls; not feasible to compute for all functions in a snapshot -- Different APIs, so discussed separately -- This slide deck focuses on the former. - -.. note:: - - For further information, see: - - - `Introduction to data flow analysis in QL `__ - - `Analyzing data flow in C/C++ `__ - -.. rst-class:: background2 - -Local data flow -=============== - -Importing data flow -=================== - -To use the data flow library, add the following import: - -.. code-block:: ql - - import semmle.code.cpp.dataflow.DataFlow - -**Note**: this library contains an explicit “module” declaration: - -.. code-block:: ql - - module DataFlow { - class Node extends ... { ... } - predicate localFlow(Node source, Node sink) { - localFlowStep*(source, sink) - } - ... - } - -So all references will need to be qualified (that is, ``DataFlow::Node``) - -.. note:: - - A **query library** is file with the extension ``.qll``. Query libraries do not contain a query clause, but may contain modules, classes, and predicates. For example, the `C/C++ data flow library `__ is contained in the ``semmle/code/cpp/dataflow/DataFlow.qll`` QLL file, and can be imported as shown above. - - A **module** is a way of organizing QL code by grouping together related predicates, classes, and (sub-)modules. They can be either explicitly declared or implicit. A query library implicitly declares a module with the same name as the QLL file. - - For further information on libraries and modules in QL, see the chapter on `Modules `__ in the QL language handbook. - - For further information on importing QL libraries and modules, see the chapter on `Name resolution `__ in the QL language handbook. - -Data flow graph -=============== - -- Class ``DataFlow::Node`` represents data flow graph nodes -- Predicate ``DataFlow::localFlowStep`` represents local data flow graph edges, ``DataFlow::localFlow`` is its transitive closure -- Data flow graph nodes are *not* AST nodes, but they correspond to AST nodes, and there are predicates for mapping between them: - - - ``Expr Node.asExpr()`` - - ``Parameter Node.asParameter()`` - - ``DataFlow::Node DataFlow::exprNode(Expr e)`` - - ``DataFlow::Node DataFlow::parameterNode(Parameter p)`` - - ``etc.`` - -.. note:: - - The ``DataFlow::Node`` class is shared between both the local and global data flow graphs–the primary difference is the edges, which in the “global” case can link different functions. - - ``localFlowStep`` is the “single step” flow relation–that is, it describes single edges in the local data flow graph. ``localFlow`` represents the `transitive `__ closure of this relation–in other words, it contains every pair of nodes where the second node is reachable from the first in the data flow graph. - - The data flow graph is separate from the `AST `__, to allow for flexibility in how data flow is modeled. There are a small number of data flow node types–expression nodes, parameter nodes, uninitialized variable nodes, and definition by reference nodes. Each node provides mapping functions to and from the relevant AST (for example ``Expr``, ``Parameter`` etc.) or symbol table (for example ``Variable``) classes. - -Taint tracking -============== - -- Usually, we want to generalise slightly by not only considering plain data flow, but also “taint” propagation, that is, whether a value is influenced by or derived from another. - -- Examples: - - .. code-block:: cpp - - sink = source; // source -> sink: data and taint - strcat(sink, source); // source -> sink: taint, not data - -- Library ``semmle.code.cpp.dataflow.TaintTracking`` provides predicates for tracking taint: - - - ``TaintTracking::localTaintStep`` represents one (local) taint step - - ``TaintTracking::localTaint`` is its transitive closure. - -.. note:: - - Taint tracking can be thought of as another type of data flow graph. It usually extends the standard data flow graph for a problem by adding edges between nodes where one one node influences or *taints* another. - - The `API `__ is almost identical to that of the local data flow. All we need to do to switch to taint tracking is ``import semmle.code.cpp.dataflow.TaintTracking`` instead of ``semmle.code.cpp.dataflow.DataFlow``, and instead of using ``localFlow``, we use ``localTaint``. +.. resume language-specific slides Exercise: source nodes ====================== diff --git a/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst b/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst index ce0b34d4b1e..ac01498e339 100644 --- a/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst +++ b/docs/language/ql-training-rst/cpp/global-data-flow-cpp.rst @@ -36,57 +36,12 @@ Agenda - Path queries - Data flow models -Information flow -================ +.. insert common global data flow slides -- Many security problems can be phrased as an information flow problem: +.. include:: ../slide-snippets/global-data-flow.rst - Given a (problem-specific) set of sources and sinks, is there a path in the data flow graph from some source to some sink? +.. resume language-specific global data flow slides -- Some examples: - - - SQL injection: sources are user-input, sinks are SQL queries - - Reflected XSS: sources are HTTP requests, sinks are HTTP responses - -- We can solve such problems using the data flow and taint tracking libraries. - -Global data flow and taint tracking -=================================== - -- Recap: - - - Local (“intra-procedural”) data flow models flow within one function; feasible to compute for all functions in a snapshot - - Global (“inter-procedural”) data flow models flow across function calls; not feasible to compute for all functions in a snapshot - -- For global data flow (and taint tracking), we must therefore provide restrictions to ensure the problem is tractable. -- Typically, this involves specifying the *source* and *sink*. - -.. note:: - - As we mentioned in the previous slide deck, while local data flow is feasible to compute for all functions in a snapshot, global data flow is not. This is because the number of paths becomes exponentially larger for global data flow. - - The global data flow (and taint tracking) avoids this problem by requiring that the query author specifies which ``sources`` and ``sinks`` are applicable. This allows the implementation to compute paths between the restricted set of nodes, rather than the full graph. - -Global taint tracking library -============================= - -The ``semmle.code.cpp.dataflow.TaintTracking`` library provides a framework for implementing solvers for global taint tracking problems: - - #. Subclass ``TaintTracking::Configuration`` following this template: - - .. code-block:: ql - - class Config extends TaintTracking::Configuration { - Config() { this = "" } - override predicate isSource(DataFlow::Node nd) { ... } - override predicate isSink(DataFlow::Node nd) { ... } - } - - #. Use ``Config.hasFlow(source, sink)`` to find inter-procedural paths. - -.. note:: - - In addition to the taint tracking configuration described here, there is also an equivalent *data flow* configuration in ``semmle.code.cpp.dataflow.DataFlow``, ``DataFlow::Configuration``. Data flow configurations are used to track whether the exact value produced by a source is used by a sink, whereas taint tracking configurations are used to determine whether the source may influence the value used at the sink. Whether you use taint tracking or data flow depends on the analysis problem you are trying to solve. Finding tainted format strings (outline) ======================================== @@ -164,30 +119,11 @@ Use the ``FormattingFunction`` class, we can write the sink as: When we run this query, we should find a single result. However, it is tricky to determine whether this result is a true positive (a “real” result) because our query only reports the source and the sink, and not the path through the graph between the two. -Path queries -============ +.. insert path queries slides -Path queries provide information about the identified paths from sources to sinks. Paths can be examined in Path Explorer view. +.. include:: ../slide-snippets/path-queries.rst -Use this template: - -.. code-block:: ql - - /** - * ... - * @kind path-problem - */ - - import semmle.code.cpp.dataflow.TaintTracking - import DataFlow::PathGraph - ... - from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink - where cfg.hasFlowPath(source, sink) - select sink, source, sink, "" - -.. note:: - - To see the paths between the source and the sinks, we can convert the query to a path problem query. There are a few minor changes that need to be made for this to work–we need an additional import, to specify ``PathNode`` rather than ``Node``, and to add the source/sink to the query output (so that we can automatically determine the paths). +.. resume language-specific global data flow slides Defining additional taint steps =============================== diff --git a/docs/language/ql-training-rst/java/global-data-flow-java.rst b/docs/language/ql-training-rst/java/global-data-flow-java.rst index eca3aa7fe3a..59bf7324d68 100644 --- a/docs/language/ql-training-rst/java/global-data-flow-java.rst +++ b/docs/language/ql-training-rst/java/global-data-flow-java.rst @@ -36,59 +36,13 @@ Agenda - Path queries - Data flow models -Information flow -================ +.. insert common global data flow slides -- Many security problems can be phrased as an information flow problem: +.. include:: ../slide-snippets/global-data-flow.rst - Given a (problem-specific) set of sources and sinks, is there a path in the data flow graph from some source to some sink? +.. resume language-specific global data flow slides -- Some examples: - - - SQL injection: sources are user-input, sinks are SQL queries - - Reflected XSS: sources are HTTP requests, sinks are HTTP responses - -- We can solve such problems using the data flow and taint tracking libraries. - -Global data flow and taint tracking -=================================== - -- Recap: - - - Local (“intra-procedural”) data flow models flow within one function; feasible to compute for all functions in a snapshot - - Global (“inter-procedural”) data flow models flow across function calls; not feasible to compute for all functions in a snapshot - -- For global data flow (and taint tracking), we must therefore provided restrictions to ensure the problem is tractable. -- Typically, this involves specifying the *source* and *sink*. - -.. note:: - - As we mentioned in the previous slide deck, while local data flow is feasible to compute for all functions in a snapshot, global data flow is not. This is because the number of paths becomes exponentially larger for global data flow. - - The global data flow (and taint tracking) avoids this problem by requiring that the query author specifies which ``sources`` and ``sinks`` are applicable. This allows the implementation to compute paths between the restricted set of nodes, rather than the full graph. - -Global taint-tracking library -============================= - -The ``semmle.code.java.dataflow.TaintTracking`` library provides a framework for implementing solvers for global taint tracking problems: - - #. Subclass ``TaintTracking::Configuration`` following this template: - - .. code-block:: ql - - class Config extends TaintTracking::Configuration { - Config() { this = "" } - override predicate isSource(DataFlow::Node nd) { ... } - override predicate isSink(DataFlow::Node nd) { ... } - } - - #. Use ``Config.hasFlow(source, sink)`` to find inter-procedural paths. - -.. note:: - - In addition to the taint tracking configuration described here, there is also an equivalent *data flow* configuration in ``semmle.code.java.dataflow.DataFlow``, ``DataFlow::Configuration``. Data flow configurations are used to track whether the exact value produced by a source is used by a sink, whereas taint tracking configurations are used to determine whether the source may influence the value used at the sink. Whether you use taint tracking or data flow depends on the analysis problem you are trying to solve. - -Code injection in Apache Struts +Code injection in Apache struts =============================== - In April 2018, Man Yue Mo, a security researcher at Semmle, reported 5 remote code execution (RCE) vulnerabilities (CVE-2018-11776) in Apache Struts. @@ -181,30 +135,11 @@ Find a method access to ``compileAndExecute``, and mark the first argument. ... } -Path queries -============ +.. insert path queries slides -Path queries provide information about the identified paths from sources to sinks. Paths can be examined in Path Explorer view. +.. include:: ../slide-snippets/path-queries.rst -Use this template: - -.. code-block:: ql - - /** - * ... - * @kind path-problem - */ - - import semmle.code.java.dataflow.TaintTracking - import DataFlow::PathGraph - ... - from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink - where cfg.hasFlowPath(source, sink) - select sink, source, sink, "" - -.. note:: - - To see the paths between the source and the sinks, we can convert the query to a path problem query. There are a few minor changes that need to be made for this to work - we need an additional import, to specify ``PathNode`` rather than ``Node``, and to add the source/sink to the query output (so that we can automatically determine the paths). +.. resume language-specific global data flow slides Defining sanitizers =================== diff --git a/docs/language/ql-training-rst/slide-snippets/global-data-flow.rst b/docs/language/ql-training-rst/slide-snippets/global-data-flow.rst new file mode 100644 index 00000000000..f18dc22d178 --- /dev/null +++ b/docs/language/ql-training-rst/slide-snippets/global-data-flow.rst @@ -0,0 +1,51 @@ +Information flow +================ + +- Many security problems can be phrased as an information flow problem: + + Given a (problem-specific) set of sources and sinks, is there a path in the data flow graph from some source to some sink? + +- Some examples: + + - SQL injection: sources are user-input, sinks are SQL queries + - Reflected XSS: sources are HTTP requests, sinks are HTTP responses + +- We can solve such problems using the data flow and taint tracking libraries. + +Global data flow and taint tracking +=================================== + +- Recap: + + - Local (“intra-procedural”) data flow models flow within one function; feasible to compute for all functions in a snapshot + - Global (“inter-procedural”) data flow models flow across function calls; not feasible to compute for all functions in a snapshot + +- For global data flow (and taint tracking), we must therefore provide restrictions to ensure the problem is tractable. +- Typically, this involves specifying the *source* and *sink*. + +.. note:: + + As we mentioned in the previous slide deck, while local data flow is feasible to compute for all functions in a snapshot, global data flow is not. This is because the number of paths becomes exponentially larger for global data flow. + + The global data flow (and taint tracking) avoids this problem by requiring that the query author specifies which ``sources`` and ``sinks`` are applicable. This allows the implementation to compute paths between the restricted set of nodes, rather than the full graph. + +Global taint tracking library +============================= + +The ``semmle.code..dataflow.TaintTracking`` library provides a framework for implementing solvers for global taint tracking problems: + + #. Subclass ``TaintTracking::Configuration`` following this template: + + .. code-block:: ql + + class Config extends TaintTracking::Configuration { + Config() { this = "" } + override predicate isSource(DataFlow::Node nd) { ... } + override predicate isSink(DataFlow::Node nd) { ... } + } + + #. Use ``Config.hasFlow(source, sink)`` to find inter-procedural paths. + +.. note:: + + In addition to the taint tracking configuration described here, there is also an equivalent *data flow* configuration in ``semmle.code..dataflow.DataFlow``, ``DataFlow::Configuration``. Data flow configurations are used to track whether the exact value produced by a source is used by a sink, whereas taint tracking configurations are used to determine whether the source may influence the value used at the sink. Whether you use taint tracking or data flow depends on the analysis problem you are trying to solve. diff --git a/docs/language/ql-training-rst/slide-snippets/local-data-flow.rst b/docs/language/ql-training-rst/slide-snippets/local-data-flow.rst new file mode 100644 index 00000000000..110e3040aab --- /dev/null +++ b/docs/language/ql-training-rst/slide-snippets/local-data-flow.rst @@ -0,0 +1,160 @@ +Data flow analysis +================== + +- Models flow of data through the program. +- Implemented in the module ``semmle.code..dataflow.DataFlow``. +- Class ``DataFlow::Node`` represents program elements that have a value, such as expressions and function parameters. + + - Nodes of the data flow graph. + +- Various predicated represent flow between these nodes. + + - Edges of the data flow graph. + +.. note:: + + The solution here is to use *data flow*. Data flow is, as the name suggests, about tracking the flow of data through the program. It helps answers questions like: *does this expression ever hold a value that originates from a particular other place in the program*? + + We can visualize the data flow problem as one of finding paths through a directed graph, where the nodes of the graph are elements in program, and the edges represent the flow of data between those elements. If a path exists, then the data flows between those two edges. + +Data flow graphs +================ + +.. container:: column-left + + Example: + + .. code-block:: cpp + + int func(int, tainted) { + int x = tainted; + if (someCondition) { + int y = x; + callFoo(y); + } else { + return x; + } + return -1; + } + +.. container:: column-right + + Data flow graph: + + .. graphviz:: + + digraph { + graph [ dpi = 1000 ] + node [shape=polygon,sides=4,color=blue4,style="filled,rounded", fontname=consolas,fontcolor=white] + a [label=ParameterNode>] + b [label=ExprNode>] + c [label=ExprNode>] + d [label=ExprNode>] + e [label=ExprNode>] + + a -> b + b -> {c, d} + c -> e + + } + +Local vs global data flow +========================= + +- Local (“intra-procedural”) data flow models flow within one function; feasible to compute for all functions in a snapshot +- Global (“inter-procedural”) data flow models flow across function calls; not feasible to compute for all functions in a snapshot +- Different APIs, so discussed separately +- This slide deck focuses on the former. + +.. note:: + + For further information, see: + + - `Introduction to data flow analysis in QL `__ + +.. rst-class:: background2 + +Local data flow +=============== + +Importing data flow +=================== + +To use the data flow library, add the following import: + +.. code-block:: ql + + import semmle.code..dataflow.DataFlow + +**Note**: this library contains an explicit “module” declaration: + +.. code-block:: ql + + module DataFlow { + class Node extends ... { ... } + predicate localFlow(Node source, Node sink) { + localFlowStep*(source, sink) + } + ... + } + +So all references will need to be qualified (that is, ``DataFlow::Node``) + +.. note:: + + A **query library** is file with the extension ``.qll``. Query libraries do not contain a query clause, but may contain modules, classes, and predicates. + For further information on the data flow libraries, see the following links: + + - `Java data flow library `__ + - `C/C++ data flow library `__ + - `C# data flow library `__ + + A **module** is a way of organizing QL code by grouping together related predicates, classes, and (sub-)modules. They can be either explicitly declared or implicit. A query library implicitly declares a module with the same name as the QLL file. + + For further information on libraries and modules in QL, see the chapter on `Modules `__ in the QL language handbook. + For further information on importing QL libraries and modules, see the chapter on `Name resolution `__ in the QL language handbook. + +Data flow graph +=============== + +- Class ``DataFlow::Node`` represents data flow graph nodes +- Predicate ``DataFlow::localFlowStep`` represents local data flow graph edges, ``DataFlow::localFlow`` is its transitive closure +- Data flow graph nodes are *not* AST nodes, but they correspond to AST nodes, and there are predicates for mapping between them: + + - ``Expr Node.asExpr()`` + - ``Parameter Node.asParameter()`` + - ``DataFlow::Node DataFlow::exprNode(Expr e)`` + - ``DataFlow::Node DataFlow::parameterNode(Parameter p)`` + - ``etc.`` + +.. note:: + + The ``DataFlow::Node`` class is shared between both the local and global data flow graphs–the primary difference is the edges, which in the “global” case can link different functions. + + ``localFlowStep`` is the “single step” flow relation–that is, it describes single edges in the local data flow graph. ``localFlow`` represents the `transitive `__ closure of this relation–in other words, it contains every pair of nodes where the second node is reachable from the first in the data flow graph. + + The data flow graph is separate from the `AST `__, to allow for flexibility in how data flow is modeled. There are a small number of data flow node types–expression nodes, parameter nodes, uninitialized variable nodes, and definition by reference nodes. Each node provides mapping functions to and from the relevant AST (for example ``Expr``, ``Parameter`` etc.) or symbol table (for example ``Variable``) classes. + +Taint tracking +============== + +- Usually, we want to generalise slightly by not only considering plain data flow, but also “taint” propagation, that is, whether a value is influenced by or derived from another. + +- Examples: + + .. code-block:: java + + sink = source; // source -> sink: data and taint + strcat(sink, source); // source -> sink: taint, not data + +- Library ``semmle.code..dataflow.TaintTracking`` provides predicates for tracking taint; ``TaintTracking::localTaintStep`` represents one (local) taint step, ``TaintTracking::localTaint`` is its transitive closure. + +.. note:: + + Taint tracking can be thought of as another type of data flow graph. It usually extends the standard data flow graph for a problem by adding edges between nodes where one one node influences or *taints* another. + + The taint-tracking API is almost identical to that of the local data flow. All we need to do to switch to taint tracking is ``import semmle.code..dataflow.TaintTracking`` instead of ``semmle.code..dataflow.DataFlow``, and instead of using ``localFlow``, we use ``localTaint``. + + - `Java taint-tracking library `__ + - `C/C++ taint-tracking library `__ + - `C# taint-tracking library `__ \ No newline at end of file diff --git a/docs/language/ql-training-rst/slide-snippets/path-queries.rst b/docs/language/ql-training-rst/slide-snippets/path-queries.rst new file mode 100644 index 00000000000..c7d9212e644 --- /dev/null +++ b/docs/language/ql-training-rst/slide-snippets/path-queries.rst @@ -0,0 +1,24 @@ +Path queries +============ + +Path queries provide information about the identified paths from sources to sinks. Paths can be examined in Path Explorer view. + +Use this template: + +.. code-block:: ql + + /** + * ... + * @kind path-problem + */ + + import semmle.code..dataflow.TaintTracking + import DataFlow::PathGraph + ... + from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink + where cfg.hasFlowPath(source, sink) + select sink, source, sink, "" + +.. note:: + + To see the paths between the source and the sinks, we can convert the query to a path problem query. There are a few minor changes that need to be made for this to work–we need an additional import, to specify ``PathNode`` rather than ``Node``, and to add the source/sink to the query output (so that we can automatically determine the paths). \ No newline at end of file From 9eefeb770a03a5c907818d5a273cd26da1aa8bdd Mon Sep 17 00:00:00 2001 From: james Date: Thu, 29 Aug 2019 11:53:19 +0100 Subject: [PATCH 0014/1227] docs: fix include in data flow slides (cherry picked from commit 387147ede2ec0548415e0c8d99ba0f43cd15a9b4) --- .../java/apache-struts-java.rst | 12 +- .../ql-training-rst/java/data-flow-java.rst | 113 +----------------- 2 files changed, 9 insertions(+), 116 deletions(-) diff --git a/docs/language/ql-training-rst/java/apache-struts-java.rst b/docs/language/ql-training-rst/java/apache-struts-java.rst index b4f31214b5c..90d6050d738 100644 --- a/docs/language/ql-training-rst/java/apache-struts-java.rst +++ b/docs/language/ql-training-rst/java/apache-struts-java.rst @@ -47,12 +47,12 @@ RCE in Apache Struts - Vulnerable code looked like this (`original `__): -.. code-block:: java - - public void toObject(Reader in, Object target) { - XStream xstream = createXStream(); - xstream.fromXML(in, target); - } + .. code-block:: java + + public void toObject(Reader in, Object target) { + XStream xstream = createXStream(); + xstream.fromXML(in, target); + } - Xstream allows deserialization of **dynamic proxies**, which permit remote code execution. diff --git a/docs/language/ql-training-rst/java/data-flow-java.rst b/docs/language/ql-training-rst/java/data-flow-java.rst index d2cee2580b6..17077d88b59 100644 --- a/docs/language/ql-training-rst/java/data-flow-java.rst +++ b/docs/language/ql-training-rst/java/data-flow-java.rst @@ -98,118 +98,11 @@ We want to improve our query to catch more of these cases. Here the concatenation occurs before the call, so the existing query would miss this - the string concatenation does not occur *directly* as the first argument of the call. -Data flow analysis -================== +.. include general data flow slides -- Models flow of data through the program. -- Implemented in the module ``semmle.code.java.dataflow.DataFlow``. -- Class ``DataFlow::Node`` represents program elements that have a value, such as expressions and function parameters. +.. include:: ../slide-snippets/local-data-flow.rst - - Nodes of the data flow graph. - -- Various predicated represent flow between these nodes. - - - Edges of the data flow graph. - -.. note:: - - The solution here is to use *data flow*. Data flow is, as the name suggests, about tracking the flow of data through the program. It helps answers questions like: *does this expression ever hold a value that originates from a particular other place in the program*? - - We can visualize the data flow problem as one of finding paths through a directed graph, where the nodes of the graph are elements in program, and the edges represent the flow of data between those elements. If a path exists, then the data flows between those two edges. - -Local vs global data flow -========================= - -- Local (“intra-procedural”) data flow models flow within one function; feasible to compute for all functions in a snapshot -- Global (“inter-procedural”) data flow models flow across function calls; not feasible to compute for all functions in a snapshot -- Different APIs, so discussed separately -- This slide deck focuses on the former. - -.. note:: - - For further information, see: - - - `Introduction to data flow analysis in QL `__ - - `Analyzing data flow in Java `__ - -.. rst-class:: background2 - -Local data flow -=============== - -Importing data flow -=================== - -To use the data flow library, add the following import: - -.. code-block:: ql - - import semmle.code.java.dataflow.DataFlow - -**Note**: this library contains an explicit “module” declaration: - -.. code-block:: ql - - module DataFlow { - class Node extends ... { ... } - predicate localFlow(Node source, Node sink) { - localFlowStep*(source, sink) - } - ... - } - -So all references will need to be qualified (that is, ``DataFlow::Node``) - -.. note:: - - A **query library** is file with the extension ``.qll``. Query libraries do not contain a query clause, but may contain modules, classes, and predicates. For example, the `Java data flow library `__ is contained in the ``semmle/code/java/dataflow/DataFlow.qll`` QLL file, and can be imported as shown above. - - A **module** is a way of organizing QL code by grouping together related predicates, classes, and (sub-)modules. They can be either explicitly declared or implicit. A query library implicitly declares a module with the same name as the QLL file. - - For further information on libraries and modules in QL, see the chapter on `Modules `__ in the QL language handbook. - - For further information on importing QL libraries and modules, see the chapter on `Name resolution `__ in the QL language handbook. - -Data flow graph -=============== - -- Class ``DataFlow::Node`` represents data flow graph nodes -- Predicate ``DataFlow::localFlowStep`` represents local data flow graph edges, ``DataFlow::localFlow`` is its transitive closure -- Data flow graph nodes are *not* AST nodes, but they correspond to AST nodes, and there are predicates for mapping between them: - - - ``Expr Node.asExpr()`` - - ``Parameter Node.asParameter()`` - - ``DataFlow::Node DataFlow::exprNode(Expr e)`` - - ``DataFlow::Node DataFlow::parameterNode(Parameter p)`` - - ``etc.`` - -.. note:: - - The ``DataFlow::Node`` class is shared between both the local and global data flow graphs–the primary difference is the edges, which in the “global” case can link different functions. - - ``localFlowStep`` is the “single step” flow relation–that is, it describes single edges in the local data flow graph. ``localFlow`` represents the `transitive `__ closure of this relation–in other words, it contains every pair of nodes where the second node is reachable from the first in the data flow graph. - - The data flow graph is separate from the `AST `__, to allow for flexibility in how data flow is modeled. There are a small number of data flow node types–expression nodes, parameter nodes, uninitialized variable nodes, and definition by reference nodes. Each node provides mapping functions to and from the relevant AST (for example ``Expr``, ``Parameter`` etc.) or symbol table (for example ``Variable``) classes. - -Taint tracking -============== - -- Usually, we want to generalise slightly by not only considering plain data flow, but also “taint” propagation, that is, whether a value is influenced by or derived from another. - -- Examples: - - .. code-block:: java - - sink = source; // source -> sink: data and taint - strcat(sink, source); // source -> sink: taint, not data - -- Library ``semmle.code.java.dataflow.TaintTracking`` provides predicates for tracking taint; ``TaintTracking::localTaintStep`` represents one (local) taint step, ``TaintTracking::localTaint`` is its transitive closure. - -.. note:: - - Taint tracking can be thought of as another type of data flow graph. It usually extends the standard data flow graph for a problem by adding edges between nodes where one one node influences or *taints* another. - - The `API `__ is almost identical to that of the local data flow. All we need to do to switch to taint tracking is ``import semmle.code.java.dataflow.TaintTracking`` instead of ``semmle.code.java.dataflow.DataFlow``, and instead of using ``localFlow``, we use ``localTaint``. +.. resume language-specific slides Exercise: revisiting SPARQL injection ===================================== From d592af1c226adb9770401d1f992a9b894392a09e Mon Sep 17 00:00:00 2001 From: james Date: Thu, 29 Aug 2019 14:42:17 +0100 Subject: [PATCH 0015/1227] docs: fix speaker note bug (cherry picked from commit 0b31ca46b164e5bb64ec6967dbe92df841b86568) --- .../slides-semmle-2/layout.html | 4 ++-- .../static/theme/css/default.css | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/language/ql-training-rst/_static-training/slides-semmle-2/layout.html b/docs/language/ql-training-rst/_static-training/slides-semmle-2/layout.html index 4c2ef333cb2..f0101ddfbc6 100644 --- a/docs/language/ql-training-rst/_static-training/slides-semmle-2/layout.html +++ b/docs/language/ql-training-rst/_static-training/slides-semmle-2/layout.html @@ -134,7 +134,7 @@ URL: https://code.google.com/p/io-2012-slides {% endblock %} -
    + @@ -146,7 +146,7 @@ URL: https://code.google.com/p/io-2012-slides -
    + +{% endblock %} From bbf7e56e4794b7290805f731e37801da03a3d2ac Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 19 Sep 2019 11:48:53 +0200 Subject: [PATCH 0149/1227] remove unused import in query --- .../security/dataflow/LoopBoundInjectionCustomizations.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/LoopBoundInjectionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/LoopBoundInjectionCustomizations.qll index e44d7baec3c..db167a0b233 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/LoopBoundInjectionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/LoopBoundInjectionCustomizations.qll @@ -7,7 +7,6 @@ import javascript module LoopBoundInjection { - import semmle.javascript.security.dataflow.RemoteFlowSources import semmle.javascript.security.TaintedObject import DataFlow::PathGraph From 3c33e863ad08ba9514298e00687d165ccebc7510 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 19 Sep 2019 11:44:14 +0200 Subject: [PATCH 0150/1227] Python: split tests for Functions into more files Makes it easier to see what the testcases are relevant for what queries. --- .../general/DeprecatedSliceMethod.expected | 6 +- .../general/ExplicitReturnInInit.expected | 2 +- .../general/InitIsGenerator.expected | 2 +- ...odificationOfParameterWithDefault.expected | 20 +-- .../Functions/general/NonCls.expected | 4 +- .../Functions/general/NonSelf.expected | 4 +- .../Functions/general/argument_names.py | 68 +++++++++ .../general/explicit_return_in_init.py | 39 +++++ .../Functions/general/functions_test.py | 133 ++---------------- 9 files changed, 140 insertions(+), 138 deletions(-) create mode 100644 python/ql/test/query-tests/Functions/general/argument_names.py create mode 100644 python/ql/test/query-tests/Functions/general/explicit_return_in_init.py diff --git a/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.expected b/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.expected index 8d89bff1f23..b5eca463705 100644 --- a/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.expected +++ b/python/ql/test/query-tests/Functions/general/DeprecatedSliceMethod.expected @@ -1,3 +1,3 @@ -| functions_test.py:200:5:200:40 | Function __getslice__ | __getslice__ method has been deprecated since Python 2.0 | -| functions_test.py:203:5:203:47 | Function __setslice__ | __setslice__ method has been deprecated since Python 2.0 | -| functions_test.py:206:5:206:40 | Function __delslice__ | __delslice__ method has been deprecated since Python 2.0 | +| functions_test.py:99:5:99:40 | Function __getslice__ | __getslice__ method has been deprecated since Python 2.0 | +| functions_test.py:102:5:102:47 | Function __setslice__ | __setslice__ method has been deprecated since Python 2.0 | +| functions_test.py:105:5:105:40 | Function __delslice__ | __delslice__ method has been deprecated since Python 2.0 | diff --git a/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected b/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected index e695c7d0030..38252a5cca2 100644 --- a/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected +++ b/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected @@ -1 +1 @@ -| functions_test.py:45:9:45:19 | Return | Explicit return in __init__ method. | +| explicit_return_in_init.py:4:9:4:19 | Return | Explicit return in __init__ method. | diff --git a/python/ql/test/query-tests/Functions/general/InitIsGenerator.expected b/python/ql/test/query-tests/Functions/general/InitIsGenerator.expected index ec18b839c48..b8216f44b8b 100644 --- a/python/ql/test/query-tests/Functions/general/InitIsGenerator.expected +++ b/python/ql/test/query-tests/Functions/general/InitIsGenerator.expected @@ -1 +1 @@ -| functions_test.py:73:5:73:23 | Function __init__ | __init__ method is a generator. | +| explicit_return_in_init.py:32:5:32:23 | Function __init__ | __init__ method is a generator. | diff --git a/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected b/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected index 1cde44c6893..bc4b1153499 100644 --- a/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected +++ b/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected @@ -1,14 +1,14 @@ edges | functions_test.py:39:9:39:9 | empty mutable value | functions_test.py:40:5:40:5 | empty mutable value | -| functions_test.py:238:15:238:15 | empty mutable value | functions_test.py:239:5:239:5 | empty mutable value | -| functions_test.py:290:25:290:25 | empty mutable value | functions_test.py:291:5:291:5 | empty mutable value | -| functions_test.py:293:21:293:21 | empty mutable value | functions_test.py:294:5:294:5 | empty mutable value | -| functions_test.py:296:27:296:27 | empty mutable value | functions_test.py:297:25:297:25 | empty mutable value | -| functions_test.py:296:27:296:27 | empty mutable value | functions_test.py:298:21:298:21 | empty mutable value | -| functions_test.py:297:25:297:25 | empty mutable value | functions_test.py:290:25:290:25 | empty mutable value | -| functions_test.py:298:21:298:21 | empty mutable value | functions_test.py:293:21:293:21 | empty mutable value | +| functions_test.py:133:15:133:15 | empty mutable value | functions_test.py:134:5:134:5 | empty mutable value | +| functions_test.py:185:25:185:25 | empty mutable value | functions_test.py:186:5:186:5 | empty mutable value | +| functions_test.py:188:21:188:21 | empty mutable value | functions_test.py:189:5:189:5 | empty mutable value | +| functions_test.py:191:27:191:27 | empty mutable value | functions_test.py:192:25:192:25 | empty mutable value | +| functions_test.py:191:27:191:27 | empty mutable value | functions_test.py:193:21:193:21 | empty mutable value | +| functions_test.py:192:25:192:25 | empty mutable value | functions_test.py:185:25:185:25 | empty mutable value | +| functions_test.py:193:21:193:21 | empty mutable value | functions_test.py:188:21:188:21 | empty mutable value | #select | functions_test.py:40:5:40:5 | x | functions_test.py:39:9:39:9 | empty mutable value | functions_test.py:40:5:40:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:39:9:39:9 | x | Default value | -| functions_test.py:239:5:239:5 | x | functions_test.py:238:15:238:15 | empty mutable value | functions_test.py:239:5:239:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:238:15:238:15 | x | Default value | -| functions_test.py:291:5:291:5 | x | functions_test.py:296:27:296:27 | empty mutable value | functions_test.py:291:5:291:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:296:27:296:27 | y | Default value | -| functions_test.py:294:5:294:5 | x | functions_test.py:296:27:296:27 | empty mutable value | functions_test.py:294:5:294:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:296:27:296:27 | y | Default value | +| functions_test.py:134:5:134:5 | x | functions_test.py:133:15:133:15 | empty mutable value | functions_test.py:134:5:134:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:133:15:133:15 | x | Default value | +| functions_test.py:186:5:186:5 | x | functions_test.py:191:27:191:27 | empty mutable value | functions_test.py:186:5:186:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:191:27:191:27 | y | Default value | +| functions_test.py:189:5:189:5 | x | functions_test.py:191:27:191:27 | empty mutable value | functions_test.py:189:5:189:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:191:27:191:27 | y | Default value | diff --git a/python/ql/test/query-tests/Functions/general/NonCls.expected b/python/ql/test/query-tests/Functions/general/NonCls.expected index da955e6f353..59e2d12ceda 100644 --- a/python/ql/test/query-tests/Functions/general/NonCls.expected +++ b/python/ql/test/query-tests/Functions/general/NonCls.expected @@ -1,2 +1,2 @@ -| functions_test.py:100:5:100:24 | Function n_cmethod | Class methods or methods of a type deriving from type should have 'cls', rather than 'self', as their first argument. | -| functions_test.py:114:5:114:20 | Function c_method | Class methods or methods of a type deriving from type should have 'cls', rather than 'y', as their first argument. | +| argument_names.py:17:5:17:24 | Function n_cmethod | Class methods or methods of a type deriving from type should have 'cls', rather than 'self', as their first argument. | +| argument_names.py:32:5:32:20 | Function c_method | Class methods or methods of a type deriving from type should have 'cls', rather than 'y', as their first argument. | diff --git a/python/ql/test/query-tests/Functions/general/NonSelf.expected b/python/ql/test/query-tests/Functions/general/NonSelf.expected index 1bb0993593d..d35e282cb55 100644 --- a/python/ql/test/query-tests/Functions/general/NonSelf.expected +++ b/python/ql/test/query-tests/Functions/general/NonSelf.expected @@ -1,3 +1,3 @@ -| functions_test.py:130:5:130:20 | Function __init__ | Normal methods should have 'self', rather than 'x', as their first parameter. | -| functions_test.py:133:5:133:20 | Function s_method | Normal methods should have 'self', rather than 'y', as their first parameter. | +| argument_names.py:45:5:45:20 | Function __init__ | Normal methods should have 'self', rather than 'x', as their first parameter. | +| argument_names.py:48:5:48:20 | Function s_method | Normal methods should have 'self', rather than 'y', as their first parameter. | | om_test.py:71:5:71:19 | Function __repr__ | Normal methods should have at least one parameter (the first of which should be 'self'). | diff --git a/python/ql/test/query-tests/Functions/general/argument_names.py b/python/ql/test/query-tests/Functions/general/argument_names.py new file mode 100644 index 00000000000..f245bdf3d74 --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/argument_names.py @@ -0,0 +1,68 @@ +# Using name other than 'self' for first argument in methods. +# This shouldn't apply to classmethods (first argument should be 'cls' or similar) +# or static methods (first argument can be anything) + + +class Normal(object): + + def n_ok(self): + pass + + @staticmethod + def n_smethod(ok): + pass + + # not ok + @classmethod + def n_cmethod(self): + pass + + # this is allowed because it has a decorator other than @classmethod + @classmethod + @id + def n_suppress(any_name): + pass + + +class Class(type): + + def __init__(cls): + pass + + def c_method(y): + pass + + def c_ok(cls): + pass + + @id + def c_suppress(any_name): + pass + + +class NonSelf(object): + + def __init__(x): + pass + + def s_method(y): + pass + + def s_ok(self): + pass + + @staticmethod + def s_smethod(ok): + pass + + @classmethod + def s_cmethod(cls): + pass + + def s_smethod2(ok): + pass + s_smethod2 = staticmethod(s_smethod2) + + def s_cmethod2(cls): + pass + s_cmethod2 = classmethod(s_cmethod2) diff --git a/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py b/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py new file mode 100644 index 00000000000..f73a55c2faf --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py @@ -0,0 +1,39 @@ +class ExplicitReturnInInit(object): + + def __init__(self): + return self + +#These are OK +class ExplicitReturnNoneInInit(object): + + def __init__(self): + return None + +class PlainReturnInInit(object): + + def __init__(self): + return + +def error(): + raise Exception() + +class InitCallsError(object): + + def __init__(self): + return error() + +class InitCallsInit(InitCallsError): + + def __init__(self): + return InitCallsError.__init__(self) + +class InitIsGenerator(object): + + def __init__(self): + yield self + +#OK as it returns result of a call to super().__init__() +class InitCallsInit(InitCallsError): + + def __init__(self): + return super(InitCallsInit, self).__init__() diff --git a/python/ql/test/query-tests/Functions/general/functions_test.py b/python/ql/test/query-tests/Functions/general/functions_test.py index 810c484bfe6..104371d2ac4 100644 --- a/python/ql/test/query-tests/Functions/general/functions_test.py +++ b/python/ql/test/query-tests/Functions/general/functions_test.py @@ -24,7 +24,7 @@ def cr2(x): return 4 else: return - + def ok3(x): try: return @@ -39,39 +39,6 @@ def ok4(x = []): def mpd(x = []): x.append("x") -class ExplicitReturnInInit(object): - - def __init__(self): - return self - -#These are OK -class ExplicitReturnNoneInInit(object): - - def __init__(self): - return None - -class PlainReturnInInit(object): - - def __init__(self): - return - -def error(): - raise Exception() - -class InitCallsError(object): - - def __init__(self): - return error() - -class InitCallsInit(InitCallsError): - - def __init__(self): - return InitCallsError.__init__(self) - -class InitIsGenerator(object): - - def __init__(self): - yield self def use_implicit_return_value(arg): x = do_nothing() @@ -83,74 +50,6 @@ y = lambda x : do_nothing() def do_nothing(): pass -#Using name other than 'cls' for first parameter in methods. -# This shouldn't apply to classmethods (first parameter should be 'cls' or similar) -# or static methods (first parameter can be anything) - -class Normal(object): - - def n_ok(self): - pass - - @staticmethod - def n_smethod(ok): - pass - - @classmethod - def n_cmethod(self): - pass - - # this is allowed because it has a decorator other than @classmethod - @classmethod - @id - def n_suppress(any_name): - pass - -class Class(type): - - def __init__(cls): - pass - - def c_method(y): - pass - - def c_ok(cls): - pass - - @id - def c_suppress(any_name): - pass - -#Using name other than 'self' for first parameter in methods. -# This shouldn't apply to classmethods (first parameter should be 'cls' or similar) -# or static methods (first parameter can be anything) - -class NonSelf(object): - - def __init__(x): - pass - - def s_method(y): - pass - - def s_ok(self): - pass - - @staticmethod - def s_smethod(ok): - pass - - @classmethod - def s_cmethod(cls): - pass - - def s_smethod2(ok): - pass - s_smethod2 = staticmethod(s_smethod2) - - def s_cmethod2(cls): - pass - s_cmethod2 = classmethod(s_cmethod2) def returns_self(self): return self @@ -159,9 +58,9 @@ def return_value_ignored(): ok2() ok4() sorted([1,2]) - + d = {} - + def use_return_values(): x = ok2() x = ok2() @@ -194,15 +93,15 @@ def ok_to_ignore(): returns_self() ok3() y() - + class DeprecatedSliceMethods(object): - + def __getslice__(self, start, stop): pass - + def __setslice__(self, start, stop, value): pass - + def __delslice__(self, start, stop): pass @@ -217,36 +116,32 @@ def nested_call_implicit_return_func_ok(arg): -#OK as it returns result of a call to super().__init__() -class InitCallsInit(InitCallsError): - def __init__(self): - return super(InitCallsInit, self).__init__() - + #Harmless, so we allow it. def use_implicit_return_value_ok(arg): return do_nothing() - + def mutli_return(arg): if arg: return do_something() else: return do_nothing() - + #Modification of parameter with default def augassign(x = []): x += ["x"] - - + + #Possible FPs for non-self. ODASA-2439 class C(object): def _func(f): return f - + _func(x) - + #or @_func def meth(self): From 7671b6759b81ea3747c97c6cedeac6600f777921 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 19 Sep 2019 11:59:45 +0200 Subject: [PATCH 0151/1227] import DataFlow::PathGraph from the ql file instead of the qll file --- javascript/ql/src/Security/CWE-834/LoopBoundInjection.ql | 1 + .../security/dataflow/LoopBoundInjectionCustomizations.qll | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-834/LoopBoundInjection.ql b/javascript/ql/src/Security/CWE-834/LoopBoundInjection.ql index e06dea4d080..72de22117cd 100644 --- a/javascript/ql/src/Security/CWE-834/LoopBoundInjection.ql +++ b/javascript/ql/src/Security/CWE-834/LoopBoundInjection.ql @@ -12,6 +12,7 @@ import javascript import semmle.javascript.security.dataflow.LoopBoundInjection::LoopBoundInjection +import DataFlow::PathGraph from Configuration dataflow, DataFlow::PathNode source, DataFlow::PathNode sink where dataflow.hasFlowPath(source, sink) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/LoopBoundInjectionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/LoopBoundInjectionCustomizations.qll index db167a0b233..c595fc0d2cd 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/LoopBoundInjectionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/LoopBoundInjectionCustomizations.qll @@ -8,7 +8,6 @@ import javascript module LoopBoundInjection { import semmle.javascript.security.TaintedObject - import DataFlow::PathGraph /** * Holds if an exception will be thrown whenever `e` evaluates to `undefined` or `null`. From 0a710f2770627d0013317539b3b3cf4b5ec4d6cd Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Thu, 19 Sep 2019 11:54:50 +0100 Subject: [PATCH 0152/1227] Sphinx: Make clickable section more obvious --- docs/language/global-sphinx-files/_static/custom.css_t | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/language/global-sphinx-files/_static/custom.css_t b/docs/language/global-sphinx-files/_static/custom.css_t index a8643fee503..7f17a6683e2 100644 --- a/docs/language/global-sphinx-files/_static/custom.css_t +++ b/docs/language/global-sphinx-files/_static/custom.css_t @@ -455,6 +455,10 @@ blockquote.pull-quote > :last-child { clear: both; } +.toggle .name:hover { + text-decoration: underline; +} + .toggle .name:after { content: " ▶"; } From 30d1c327cfd2e868ac096423fb1bfc1188f942fc Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 19 Sep 2019 13:04:16 +0200 Subject: [PATCH 0153/1227] C++: Implement predictableInstruction without Expr This is one step toward implementing the taint-tracking wrapper in terms of `Instruction` rather than `Expr`. This leads to a few duplicate results in `TaintedAllocationSize.ql` because the library now considers `sizeof(int)` to be just as predictable as `4`, whereas the `security.TaintTracking` library does not consider `sizeof` to be predictable. I think it's simpler to accept the duplicate results since they are ultimately a quirk of the query, not the library. The following is the diff between (a) replacing `TaintTracking.qll` with a link to `DefaultTaintTracking.qll` and (b) additionally applying this commit. diff --git a b --- 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 @@ -1,5 +1,8 @@ | test.cpp:42:31:42:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | +| test.cpp:43:31:43:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | +| test.cpp:45:31:45:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:48:25:48:30 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:49:17:49:30 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | +| test.cpp:52:21:52:27 | call to realloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | --- a/semmlecode-cpp-tests/DO_NOT_DISTRIBUTE/security-tests/CWE-190/CERT/INT04-C/int04.expected +++ b/semmlecode-cpp-tests/DO_NOT_DISTRIBUTE/security-tests/CWE-190/CERT/INT04-C/int04.expected @@ -1 +1,2 @@ | int04c.c:21:29:21:51 | ... * ... | This allocation size is derived from $@ and might overflow | int04c.c:14:30:14:35 | call to getenv | user input (getenv) | +| int04c.c:22:33:22:38 | call to malloc | This allocation size is derived from $@ and might overflow | int04c.c:14:30:14:35 | call to getenv | user input (getenv) | --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) 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 9a4f144df49..7560ffad278 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -4,25 +4,17 @@ private import semmle.code.cpp.ir.dataflow.DataFlow private import semmle.code.cpp.ir.IR /** - * A predictable expression is one where an external user can predict + * A predictable instruction is one where an external user can predict * the value. For example, a literal in the source code is considered * predictable. */ -// TODO: Change to use Instruction instead of Expr. Naive attempt breaks -// TaintedAllocationSize qltest. -private predicate predictable(Expr expr) { - expr instanceof Literal - or - exists(BinaryOperation binop | binop = expr | - predictable(binop.getLeftOperand()) and predictable(binop.getRightOperand()) - ) - or - exists(UnaryOperation unop | unop = expr | predictable(unop.getOperand())) -} - -// TODO: remove when `predictable` has an `Instruction` parameter instead of `Expr`. private predicate predictableInstruction(Instruction instr) { - predictable(DataFlow::instructionNode(instr).asExpr()) + instr instanceof ConstantInstruction + or + instr instanceof StringConstantInstruction + or + // This could be a conversion on a string literal + predictableInstruction(instr.(UnaryInstruction).getUnary()) } private class DefaultTaintTrackingCfg extends DataFlow::Configuration { From 61bd9f2f17a92b069a7e0832eeab51cf3e292906 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 19 Sep 2019 09:54:15 +0200 Subject: [PATCH 0154/1227] C#: Address review comments --- csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs | 2 +- csharp/extractor/Semmle.Util/CommandLineExtensions.cs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index 60e6b5f1ef3..58a9beebb68 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -456,7 +456,7 @@ namespace Semmle.Extraction.CSharp bool argsWritten; using (var streamWriter = new StreamWriter(new FileStream(tempFile, FileMode.Append, FileAccess.Write))) { - streamWriter.WriteLine($"# Arguments to Roslyn: {string.Join(' ', roslynArgs)}"); + streamWriter.WriteLine($"# Arguments to Roslyn: {string.Join(' ', roslynArgs.Where(arg => !arg.StartsWith('@')))}"); argsWritten = roslynArgs.WriteCommandLine(streamWriter); } diff --git a/csharp/extractor/Semmle.Util/CommandLineExtensions.cs b/csharp/extractor/Semmle.Util/CommandLineExtensions.cs index a5d47c8dd3f..b7c5166f2f0 100644 --- a/csharp/extractor/Semmle.Util/CommandLineExtensions.cs +++ b/csharp/extractor/Semmle.Util/CommandLineExtensions.cs @@ -15,15 +15,16 @@ namespace Semmle.Util /// True iff the file was written. public static bool WriteCommandLine(this IEnumerable commandLineArguments, TextWriter textWriter) { - foreach (var arg in commandLineArguments.Where(arg => arg[0] == '@').Select(arg => arg.Substring(1))) + var found = false; + foreach (var arg in commandLineArguments.Where(arg => arg.StartsWith('@')).Select(arg => arg.Substring(1))) { string line; using (StreamReader file = new StreamReader(arg)) while ((line = file.ReadLine()) != null) textWriter.WriteLine(line); - return true; + found = true; } - return false; + return found; } } } From 0ed0951d439d2db69e7cb0a412bc3b638397c921 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 19 Sep 2019 14:19:34 +0200 Subject: [PATCH 0155/1227] C++: Demonstrate AmbiguouslySignedBitField FP --- .../AmbiguouslySignedBitField.expected | 1 + .../Likely Bugs/AmbiguouslySignedBitField/test.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/AmbiguouslySignedBitField.expected b/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/AmbiguouslySignedBitField.expected index 152f5c04692..3cb464e0b2f 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/AmbiguouslySignedBitField.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/AmbiguouslySignedBitField.expected @@ -3,3 +3,4 @@ | test.cpp:20:8:20:18 | nosignshort | Bit field nosignshort of type short should have explicitly unsigned integral, explicitly signed integral, or enumeration type. | | test.cpp:21:18:21:30 | nosigntypedef | Bit field nosigntypedef of type int should have explicitly unsigned integral, explicitly signed integral, or enumeration type. | | test.cpp:23:15:23:25 | nosignconst | Bit field nosignconst of type const int should have explicitly unsigned integral, explicitly signed integral, or enumeration type. | +| test.cpp:31:5:31:16 | templatesign | Bit field templatesign of type T should have explicitly unsigned integral, explicitly signed integral, or enumeration type. | diff --git a/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/test.cpp index f83bc985a11..74893a6ca5b 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/test.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/test.cpp @@ -25,3 +25,10 @@ struct { myEnum nosignenum : 2; const myEnum constnosignenum : 2; }; + +template +struct TemplateWithBitfield { + T templatesign : 2; // GOOD [FALSE POSITIVE] +}; + +TemplateWithBitfield twb; From 34a5368101505c4d8aa4eb545528d8261b1d1154 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 19 Sep 2019 14:21:53 +0200 Subject: [PATCH 0156/1227] C++: Ignore templates in AmbiguouslySignedBitField If it's possible that the type is not fully resolved, it's better to avoid giving an alert. This fixes a FP in https://github.com/heremaps/flatdata. --- cpp/ql/src/Likely Bugs/AmbiguouslySignedBitField.ql | 3 ++- .../AmbiguouslySignedBitField.expected | 1 - .../query-tests/Likely Bugs/AmbiguouslySignedBitField/test.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/AmbiguouslySignedBitField.ql b/cpp/ql/src/Likely Bugs/AmbiguouslySignedBitField.ql index a2f3ec1d119..7a7f328bd4e 100644 --- a/cpp/ql/src/Likely Bugs/AmbiguouslySignedBitField.ql +++ b/cpp/ql/src/Likely Bugs/AmbiguouslySignedBitField.ql @@ -28,7 +28,8 @@ where not bf.getType().hasName("BOOL") and // If this is true, then there cannot be unsigned sign extension or overflow. not bf.getDeclaredNumBits() = bf.getType().getSize() * 8 and - not bf.isAnonymous() + not bf.isAnonymous() and + not bf.isFromUninstantiatedTemplate(_) select bf, "Bit field " + bf.getName() + " of type " + bf.getUnderlyingType().getName() + " should have explicitly unsigned integral, explicitly signed integral, or enumeration type." diff --git a/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/AmbiguouslySignedBitField.expected b/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/AmbiguouslySignedBitField.expected index 3cb464e0b2f..152f5c04692 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/AmbiguouslySignedBitField.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/AmbiguouslySignedBitField.expected @@ -3,4 +3,3 @@ | test.cpp:20:8:20:18 | nosignshort | Bit field nosignshort of type short should have explicitly unsigned integral, explicitly signed integral, or enumeration type. | | test.cpp:21:18:21:30 | nosigntypedef | Bit field nosigntypedef of type int should have explicitly unsigned integral, explicitly signed integral, or enumeration type. | | test.cpp:23:15:23:25 | nosignconst | Bit field nosignconst of type const int should have explicitly unsigned integral, explicitly signed integral, or enumeration type. | -| test.cpp:31:5:31:16 | templatesign | Bit field templatesign of type T should have explicitly unsigned integral, explicitly signed integral, or enumeration type. | diff --git a/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/test.cpp index 74893a6ca5b..19aa4ef2e64 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/test.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/AmbiguouslySignedBitField/test.cpp @@ -28,7 +28,7 @@ struct { template struct TemplateWithBitfield { - T templatesign : 2; // GOOD [FALSE POSITIVE] + T templatesign : 2; // GOOD }; TemplateWithBitfield twb; From 29c93488bcad7aed5f2377a8bdec16d9f3d2a425 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 19 Sep 2019 14:14:33 +0200 Subject: [PATCH 0157/1227] C++: DefaultTaintTracking flow from a to a[i] Switching `security.TaintTracking` to use `DefaultTaintTracking` causes us to lose a result from `UnboundedWrite.ql`, while this commit restores it: diff --git a/semmlecode-cpp-tests/DO_NOT_DISTRIBUTE/security-tests/CWE-120/CERT/STR35-C/UnboundedWrite.expected b/semmlecode-cpp-tests/DO_NOT_DISTRIBUTE/security-tests/CWE-120/CERT/STR35-C/UnboundedWrite.expected index 1eba0e52f0e..d947b33b9d9 100644 --- a/semmlecode-cpp-tests/DO_NOT_DISTRIBUTE/security-tests/CWE-120/CERT/STR35-C/UnboundedWrite.expected +++ b/semmlecode-cpp-tests/DO_NOT_DISTRIBUTE/security-tests/CWE-120/CERT/STR35-C/UnboundedWrite.expected @@ -1,2 +1,3 @@ +| main.c:54:7:54:12 | call to strcat | This 'call to strcat' with input from $@ may overflow the destination. | main.c:93:15:93:18 | argv | argv | | main.c:99:9:99:12 | call to gets | This 'call to gets' with input from $@ may overflow the destination. | main.c:99:9:99:12 | call to gets | call to gets | | main.c:213:17:213:19 | buf | This 'scanf string argument' with input from $@ may overflow the destination. | main.c:213:17:213:19 | buf | buf | --- .../semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 9a4f144df49..5d422b1e10d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -90,10 +90,10 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) { predictableInstruction(i2.getAnOperand().getDef()) and i1 = i2.getAnOperand().getDef() ) - // TODO: Check that we have flow from `a` to `a[i]`. It may work for constant - // `i` because there is flow through `predictable` `BinaryInstruction` and - // through `LoadInstruction`. - // + or + // This is part of the translation of `a[i]`, where we want taint to flow + // from `a`. + i2.(PointerAddInstruction).getLeft() = i1 // TODO: Flow from argument to return of known functions: Port missing parts // of `returnArgument` to the `interfaces.Taint` and `interfaces.DataFlow` // libraries. From 2956cb781be25be33d8b1548f9f75176be925a88 Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Thu, 19 Sep 2019 15:07:18 +0100 Subject: [PATCH 0158/1227] Sphinx: Change to pointer --- docs/language/global-sphinx-files/_static/custom.css_t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/global-sphinx-files/_static/custom.css_t b/docs/language/global-sphinx-files/_static/custom.css_t index 7f17a6683e2..edd269cd7cd 100644 --- a/docs/language/global-sphinx-files/_static/custom.css_t +++ b/docs/language/global-sphinx-files/_static/custom.css_t @@ -456,7 +456,7 @@ blockquote.pull-quote > :last-child { } .toggle .name:hover { - text-decoration: underline; + cursor: pointer; } .toggle .name:after { From 56f4f86921b7139bb713930c608952aab825d10d Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Thu, 19 Sep 2019 21:18:47 +0100 Subject: [PATCH 0159/1227] C++: ignore uninstantiated templates in WrongTypeFormatArguments.ql --- .../Format/WrongTypeFormatArguments.ql | 3 ++- .../WrongTypeFormatArguments.expected | 1 + .../Linux_signed_chars/linux.cpp | 20 +++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql index 75c5bc73029..6f44f3d4d08 100644 --- a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql +++ b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql @@ -157,7 +157,8 @@ where formatOtherArgType(ffc, n, expected, arg, actual) and not actual.getUnspecifiedType().(IntegralType).getSize() = sizeof_IntType() ) and - not arg.isAffectedByMacro() + not arg.isAffectedByMacro() and + not arg.isFromUninstantiatedTemplate(_) select arg, "This argument should be of type '" + expected.getName() + "' but is of type '" + actual.getUnspecifiedType().getName() + "'" diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected index c609cad22e9..65f4f546976 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected @@ -1,6 +1,7 @@ | format.h:16:59:16:61 | str | This argument should be of type 'int' but is of type 'char *' | | format.h:16:64:16:64 | i | This argument should be of type 'double' but is of type 'int' | | format.h:16:67:16:67 | d | This argument should be of type 'char *' but is of type 'double' | +| linux.cpp:15:24:15:41 | call to get_template_value | This argument should be of type 'int' but is of type 'long' | | linux_c.c:11:15:11:18 | str3 | This argument should be of type 'char *' but is of type 'short *' | | pri_macros.h:15:35:15:40 | my_u64 | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | | printf1.h:12:27:12:27 | i | This argument should be of type 'double' but is of type 'int' | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/linux.cpp b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/linux.cpp index 2380c5e7cdb..9b26de4f54e 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/linux.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/linux.cpp @@ -2,3 +2,23 @@ typedef unsigned long size_t; typedef long ssize_t; #include "common.h" + +template +struct S { + int get_int(); + T get_template_value(); +}; + +template +void template_func_calling_printf(S &obj) { + ::printf("%d\n", obj.get_int()); + ::printf("%d\n", obj.get_template_value()); +} + +void instantiate() { + S s_int; + S s_long; + + template_func_calling_printf(s_int); // ok + template_func_calling_printf(s_long); // not ok (long -> int) +} From cb7db8f4c0dfceda540d6427eb02210777ef025a Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 19 Sep 2019 21:31:09 +0200 Subject: [PATCH 0160/1227] C#: Add more nullness tests --- csharp/ql/test/query-tests/Nullness/E.cs | 20 +++++++++++++++++++ .../Nullness/EqualityCheck.expected | 2 ++ .../Nullness/Implications.expected | 20 +++++++++++++++++++ .../query-tests/Nullness/NullCheck.expected | 6 ++++++ .../query-tests/Nullness/NullMaybe.expected | 12 +++++++++++ 5 files changed, 60 insertions(+) diff --git a/csharp/ql/test/query-tests/Nullness/E.cs b/csharp/ql/test/query-tests/Nullness/E.cs index 569d1b66640..8a1f0f4d1cf 100644 --- a/csharp/ql/test/query-tests/Nullness/E.cs +++ b/csharp/ql/test/query-tests/Nullness/E.cs @@ -342,6 +342,26 @@ public class E var x = s ?? o as string; x.ToString(); // BAD (maybe) } + + static void Ex31(string s, object o) + { + dynamic x = s ?? o as string; + x.ToString(); // BAD (maybe) + } + + static void Ex32(string s, object o) + { + dynamic x = s ?? o as string; + if (x != null) + x.ToString(); // GOOD (FALSE POSITIVE) + } + + static void Ex33(string s, object o) + { + var x = s ?? o as string; + if (x != (string)null) + x.ToString(); // GOOD (FALSE POSITIVE) + } } public static class Extensions diff --git a/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected b/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected index 198480b47e9..2fe927a8621 100644 --- a/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected +++ b/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected @@ -216,6 +216,8 @@ | E.cs:293:13:293:24 | ... == ... | true | E.cs:293:15:293:19 | call to method M2 | E.cs:293:24:293:24 | (...) ... | | E.cs:293:13:293:24 | ... == ... | true | E.cs:293:24:293:24 | (...) ... | E.cs:293:15:293:19 | call to method M2 | | E.cs:321:13:321:30 | ... is ... | true | E.cs:321:14:321:21 | ... ?? ... | E.cs:321:27:321:30 | null | +| E.cs:362:13:362:29 | ... != ... | false | E.cs:362:13:362:13 | access to local variable x | E.cs:362:18:362:29 | (...) ... | +| E.cs:362:13:362:29 | ... != ... | false | E.cs:362:18:362:29 | (...) ... | E.cs:362:13:362:13 | access to local variable x | | Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:13:59:13 | access to parameter o | Forwarding.cs:59:18:59:21 | null | | Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:18:59:21 | null | Forwarding.cs:59:13:59:13 | access to parameter o | | Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | true | Forwarding.cs:78:32:78:32 | access to parameter o | Forwarding.cs:78:35:78:38 | null | diff --git a/csharp/ql/test/query-tests/Nullness/Implications.expected b/csharp/ql/test/query-tests/Nullness/Implications.expected index f5e5acca322..7d5ce701b58 100644 --- a/csharp/ql/test/query-tests/Nullness/Implications.expected +++ b/csharp/ql/test/query-tests/Nullness/Implications.expected @@ -1171,6 +1171,26 @@ | E.cs:343:9:343:9 | access to local variable x | non-empty | E.cs:342:17:342:32 | ... ?? ... | non-empty | | E.cs:343:9:343:9 | access to local variable x | non-null | E.cs:342:17:342:32 | ... ?? ... | non-null | | E.cs:343:9:343:9 | access to local variable x | null | E.cs:342:17:342:32 | ... ?? ... | null | +| E.cs:348:21:348:36 | ... ?? ... | null | E.cs:348:21:348:21 | access to parameter s | null | +| E.cs:348:21:348:36 | ... ?? ... | null | E.cs:348:26:348:36 | ... as ... | null | +| E.cs:349:9:349:9 | access to local variable x | non-null | E.cs:348:21:348:36 | ... ?? ... | non-null | +| E.cs:349:9:349:9 | access to local variable x | null | E.cs:348:21:348:36 | ... ?? ... | null | +| E.cs:354:21:354:36 | ... ?? ... | null | E.cs:354:21:354:21 | access to parameter s | null | +| E.cs:354:21:354:36 | ... ?? ... | null | E.cs:354:26:354:36 | ... as ... | null | +| E.cs:355:13:355:13 | access to local variable x | non-null | E.cs:354:21:354:36 | ... ?? ... | non-null | +| E.cs:355:13:355:13 | access to local variable x | null | E.cs:354:21:354:36 | ... ?? ... | null | +| E.cs:356:13:356:13 | access to local variable x | non-null | E.cs:354:21:354:36 | ... ?? ... | non-null | +| E.cs:356:13:356:13 | access to local variable x | null | E.cs:354:21:354:36 | ... ?? ... | null | +| E.cs:361:17:361:32 | ... ?? ... | null | E.cs:361:17:361:17 | access to parameter s | null | +| E.cs:361:17:361:32 | ... ?? ... | null | E.cs:361:22:361:32 | ... as ... | null | +| E.cs:362:13:362:13 | access to local variable x | empty | E.cs:361:17:361:32 | ... ?? ... | empty | +| E.cs:362:13:362:13 | access to local variable x | non-empty | E.cs:361:17:361:32 | ... ?? ... | non-empty | +| E.cs:362:13:362:13 | access to local variable x | non-null | E.cs:361:17:361:32 | ... ?? ... | non-null | +| E.cs:362:13:362:13 | access to local variable x | null | E.cs:361:17:361:32 | ... ?? ... | null | +| E.cs:362:18:362:29 | (...) ... | non-null | E.cs:362:26:362:29 | null | non-null | +| E.cs:362:18:362:29 | (...) ... | null | E.cs:362:26:362:29 | null | null | +| E.cs:363:13:363:13 | access to local variable x | non-null | E.cs:361:17:361:32 | ... ?? ... | non-null | +| E.cs:363:13:363:13 | access to local variable x | null | E.cs:361:17:361:32 | ... ?? ... | null | | Forwarding.cs:9:13:9:30 | !... | false | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | true | | Forwarding.cs:9:13:9:30 | !... | true | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | false | | Forwarding.cs:9:14:9:14 | access to local variable s | empty | Forwarding.cs:7:20:7:23 | null | empty | diff --git a/csharp/ql/test/query-tests/Nullness/NullCheck.expected b/csharp/ql/test/query-tests/Nullness/NullCheck.expected index 2af39f8b296..9b45eae33bb 100644 --- a/csharp/ql/test/query-tests/Nullness/NullCheck.expected +++ b/csharp/ql/test/query-tests/Nullness/NullCheck.expected @@ -217,6 +217,12 @@ | E.cs:336:17:336:17 | access to parameter s | E.cs:336:17:336:17 | access to parameter s | null | true | | E.cs:342:17:342:17 | access to parameter s | E.cs:342:17:342:17 | access to parameter s | non-null | false | | E.cs:342:17:342:17 | access to parameter s | E.cs:342:17:342:17 | access to parameter s | null | true | +| E.cs:348:21:348:21 | access to parameter s | E.cs:348:21:348:21 | access to parameter s | non-null | false | +| E.cs:348:21:348:21 | access to parameter s | E.cs:348:21:348:21 | access to parameter s | null | true | +| E.cs:354:21:354:21 | access to parameter s | E.cs:354:21:354:21 | access to parameter s | non-null | false | +| E.cs:354:21:354:21 | access to parameter s | E.cs:354:21:354:21 | access to parameter s | null | true | +| E.cs:361:17:361:17 | access to parameter s | E.cs:361:17:361:17 | access to parameter s | non-null | false | +| E.cs:361:17:361:17 | access to parameter s | E.cs:361:17:361:17 | access to parameter s | null | true | | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | Forwarding.cs:9:14:9:14 | access to local variable s | false | false | | Forwarding.cs:14:13:14:32 | call to method IsNotNullOrEmpty | Forwarding.cs:14:13:14:13 | access to local variable s | true | false | | Forwarding.cs:19:14:19:23 | call to method IsNull | Forwarding.cs:19:14:19:14 | access to local variable s | false | false | diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected index 2248bfb3dff..8134f22fca7 100644 --- a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected @@ -349,6 +349,12 @@ nodes | E.cs:331:9:331:9 | access to local variable x | | E.cs:342:13:342:32 | SSA def(x) | | E.cs:343:9:343:9 | access to local variable x | +| E.cs:348:17:348:36 | SSA def(x) | +| E.cs:349:9:349:9 | access to local variable x | +| E.cs:354:17:354:36 | SSA def(x) | +| E.cs:356:13:356:13 | access to local variable x | +| E.cs:361:13:361:32 | SSA def(x) | +| E.cs:363:13:363:13 | access to local variable x | | Forwarding.cs:7:16:7:23 | SSA def(s) | | Forwarding.cs:14:9:17:9 | if (...) ... | | Forwarding.cs:19:9:22:9 | if (...) ... | @@ -679,6 +685,9 @@ edges | E.cs:321:27:321:30 | null | E.cs:323:13:323:14 | access to parameter s1 | | E.cs:330:13:330:36 | SSA def(x) | E.cs:331:9:331:9 | access to local variable x | | E.cs:342:13:342:32 | SSA def(x) | E.cs:343:9:343:9 | access to local variable x | +| E.cs:348:17:348:36 | SSA def(x) | E.cs:349:9:349:9 | access to local variable x | +| E.cs:354:17:354:36 | SSA def(x) | E.cs:356:13:356:13 | access to local variable x | +| E.cs:361:13:361:32 | SSA def(x) | E.cs:363:13:363:13 | access to local variable x | | Forwarding.cs:7:16:7:23 | SSA def(s) | Forwarding.cs:14:9:17:9 | if (...) ... | | Forwarding.cs:14:9:17:9 | if (...) ... | Forwarding.cs:19:9:22:9 | if (...) ... | | Forwarding.cs:19:9:22:9 | if (...) ... | Forwarding.cs:24:9:27:9 | if (...) ... | @@ -778,6 +787,9 @@ edges | E.cs:285:9:285:9 | access to local variable o | E.cs:283:13:283:22 | [b (line 279): true] SSA def(o) | E.cs:285:9:285:9 | access to local variable o | Variable $@ may be null here as suggested by $@ null check. | E.cs:283:13:283:13 | o | o | E.cs:284:9:284:9 | access to local variable o | this | | E.cs:302:9:302:9 | access to local variable s | E.cs:301:13:301:27 | SSA def(s) | E.cs:302:9:302:9 | access to local variable s | Variable $@ may be null here because of $@ assignment. | E.cs:301:13:301:13 | s | s | E.cs:301:13:301:27 | String s = ... | this | | E.cs:343:9:343:9 | access to local variable x | E.cs:342:13:342:32 | SSA def(x) | E.cs:343:9:343:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:342:13:342:13 | x | x | E.cs:342:13:342:32 | String x = ... | this | +| E.cs:349:9:349:9 | access to local variable x | E.cs:348:17:348:36 | SSA def(x) | E.cs:349:9:349:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:348:17:348:17 | x | x | E.cs:348:17:348:36 | dynamic x = ... | this | +| E.cs:356:13:356:13 | access to local variable x | E.cs:354:17:354:36 | SSA def(x) | E.cs:356:13:356:13 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:354:17:354:17 | x | x | E.cs:354:17:354:36 | dynamic x = ... | this | +| E.cs:363:13:363:13 | access to local variable x | E.cs:361:13:361:32 | SSA def(x) | E.cs:363:13:363:13 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:361:13:361:13 | x | x | E.cs:361:13:361:32 | String x = ... | this | | GuardedString.cs:35:31:35:31 | access to local variable s | GuardedString.cs:7:16:7:32 | SSA def(s) | GuardedString.cs:35:31:35:31 | access to local variable s | Variable $@ may be null here because of $@ assignment. | GuardedString.cs:7:16:7:16 | s | s | GuardedString.cs:7:16:7:32 | String s = ... | this | | NullMaybeBad.cs:7:27:7:27 | access to parameter o | NullMaybeBad.cs:13:17:13:20 | null | NullMaybeBad.cs:7:27:7:27 | access to parameter o | Variable $@ may be null here because of $@ null argument. | NullMaybeBad.cs:5:25:5:25 | o | o | NullMaybeBad.cs:13:17:13:20 | null | this | | StringConcatenation.cs:16:17:16:17 | access to local variable s | StringConcatenation.cs:14:16:14:23 | SSA def(s) | StringConcatenation.cs:16:17:16:17 | access to local variable s | Variable $@ may be null here because of $@ assignment. | StringConcatenation.cs:14:16:14:16 | s | s | StringConcatenation.cs:14:16:14:23 | String s = ... | this | From c923cc6378e620edad4c7fc7d83e8fbd55a9232f Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 20 Sep 2019 09:03:45 +0200 Subject: [PATCH 0161/1227] C#: Add tests for dynamic comparisons --- .../commons/ComparisonTest/ComparisonTest.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/csharp/ql/test/library-tests/commons/ComparisonTest/ComparisonTest.cs b/csharp/ql/test/library-tests/commons/ComparisonTest/ComparisonTest.cs index 62ee168f2c3..7a8cfae5254 100644 --- a/csharp/ql/test/library-tests/commons/ComparisonTest/ComparisonTest.cs +++ b/csharp/ql/test/library-tests/commons/ComparisonTest/ComparisonTest.cs @@ -106,4 +106,16 @@ class ComparisonTest b = x.CompareTo(y).CompareTo(0).CompareTo(1) == 0; } } + + void DynamicComparisons(object o1, object o2) + { + dynamic d1 = o1; + dynamic d2 = o2; + var b = d1 == d2; + b = d1 != d2; + b = d1 > d2; + b = d1 < d2; + b = d1 >= d2; + b = d1 <= d2; + } } From 40fafc5fda0cad4bada029a490fe8a76fabd2b1b Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 20 Sep 2019 09:04:09 +0200 Subject: [PATCH 0162/1227] C#: Teach comparison library about dynamic comparison operations --- csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll | 5 ++++- .../commons/ComparisonTest/comparisonTest.expected | 6 ++++++ csharp/ql/test/query-tests/Nullness/E.cs | 2 +- csharp/ql/test/query-tests/Nullness/EqualityCheck.expected | 2 ++ csharp/ql/test/query-tests/Nullness/Implications.expected | 2 ++ csharp/ql/test/query-tests/Nullness/NullCheck.expected | 2 ++ csharp/ql/test/query-tests/Nullness/NullMaybe.expected | 4 ---- 7 files changed, 17 insertions(+), 6 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll b/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll index 2247e522e9b..cc783c7e5cc 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll @@ -121,7 +121,10 @@ private newtype TComparisonTest = ) } or TComparisonOperatorCall(OperatorCall oc, ComparisonKind kind, Expr first, Expr second) { - exists(Operator o | o = oc.getTarget() | + exists(Operator o | + o = oc.getTarget() or + o.getName() = oc.(DynamicOperatorCall).getLateBoundTargetName() + | o instanceof EQOperator and kind.isEquality() and first = oc.getArgument(0) and diff --git a/csharp/ql/test/library-tests/commons/ComparisonTest/comparisonTest.expected b/csharp/ql/test/library-tests/commons/ComparisonTest/comparisonTest.expected index b8400ed579e..4d3bc1ebab1 100644 --- a/csharp/ql/test/library-tests/commons/ComparisonTest/comparisonTest.expected +++ b/csharp/ql/test/library-tests/commons/ComparisonTest/comparisonTest.expected @@ -62,3 +62,9 @@ | ComparisonTest.cs:106:17:106:61 | ... == ... | < | ComparisonTest.cs:106:42:106:42 | 0 | ComparisonTest.cs:106:17:106:30 | call to method CompareTo | | ComparisonTest.cs:106:17:106:61 | ... == ... | = | ComparisonTest.cs:106:17:106:43 | call to method CompareTo | ComparisonTest.cs:106:55:106:55 | 1 | | ComparisonTest.cs:106:17:106:61 | ... == ... | = | ComparisonTest.cs:106:17:106:56 | call to method CompareTo | ComparisonTest.cs:106:61:106:61 | 0 | +| ComparisonTest.cs:114:17:114:24 | dynamic call to operator == | = | ComparisonTest.cs:114:17:114:18 | access to local variable d1 | ComparisonTest.cs:114:23:114:24 | access to local variable d2 | +| ComparisonTest.cs:115:13:115:20 | dynamic call to operator != | != | ComparisonTest.cs:115:13:115:14 | access to local variable d1 | ComparisonTest.cs:115:19:115:20 | access to local variable d2 | +| ComparisonTest.cs:116:13:116:19 | dynamic call to operator > | < | ComparisonTest.cs:116:18:116:19 | access to local variable d2 | ComparisonTest.cs:116:13:116:14 | access to local variable d1 | +| ComparisonTest.cs:117:13:117:19 | dynamic call to operator < | < | ComparisonTest.cs:117:13:117:14 | access to local variable d1 | ComparisonTest.cs:117:18:117:19 | access to local variable d2 | +| ComparisonTest.cs:118:13:118:20 | dynamic call to operator >= | <= | ComparisonTest.cs:118:19:118:20 | access to local variable d2 | ComparisonTest.cs:118:13:118:14 | access to local variable d1 | +| ComparisonTest.cs:119:13:119:20 | dynamic call to operator <= | <= | ComparisonTest.cs:119:13:119:14 | access to local variable d1 | ComparisonTest.cs:119:19:119:20 | access to local variable d2 | diff --git a/csharp/ql/test/query-tests/Nullness/E.cs b/csharp/ql/test/query-tests/Nullness/E.cs index 8a1f0f4d1cf..711e11fe65a 100644 --- a/csharp/ql/test/query-tests/Nullness/E.cs +++ b/csharp/ql/test/query-tests/Nullness/E.cs @@ -353,7 +353,7 @@ public class E { dynamic x = s ?? o as string; if (x != null) - x.ToString(); // GOOD (FALSE POSITIVE) + x.ToString(); // GOOD } static void Ex33(string s, object o) diff --git a/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected b/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected index 2fe927a8621..2aa5b3f4f5e 100644 --- a/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected +++ b/csharp/ql/test/query-tests/Nullness/EqualityCheck.expected @@ -216,6 +216,8 @@ | E.cs:293:13:293:24 | ... == ... | true | E.cs:293:15:293:19 | call to method M2 | E.cs:293:24:293:24 | (...) ... | | E.cs:293:13:293:24 | ... == ... | true | E.cs:293:24:293:24 | (...) ... | E.cs:293:15:293:19 | call to method M2 | | E.cs:321:13:321:30 | ... is ... | true | E.cs:321:14:321:21 | ... ?? ... | E.cs:321:27:321:30 | null | +| E.cs:355:13:355:21 | dynamic call to operator != | false | E.cs:355:13:355:13 | access to local variable x | E.cs:355:18:355:21 | null | +| E.cs:355:13:355:21 | dynamic call to operator != | false | E.cs:355:18:355:21 | null | E.cs:355:13:355:13 | access to local variable x | | E.cs:362:13:362:29 | ... != ... | false | E.cs:362:13:362:13 | access to local variable x | E.cs:362:18:362:29 | (...) ... | | E.cs:362:13:362:29 | ... != ... | false | E.cs:362:18:362:29 | (...) ... | E.cs:362:13:362:13 | access to local variable x | | Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:13:59:13 | access to parameter o | Forwarding.cs:59:18:59:21 | null | diff --git a/csharp/ql/test/query-tests/Nullness/Implications.expected b/csharp/ql/test/query-tests/Nullness/Implications.expected index 7d5ce701b58..e54cdf14245 100644 --- a/csharp/ql/test/query-tests/Nullness/Implications.expected +++ b/csharp/ql/test/query-tests/Nullness/Implications.expected @@ -1179,6 +1179,8 @@ | E.cs:354:21:354:36 | ... ?? ... | null | E.cs:354:26:354:36 | ... as ... | null | | E.cs:355:13:355:13 | access to local variable x | non-null | E.cs:354:21:354:36 | ... ?? ... | non-null | | E.cs:355:13:355:13 | access to local variable x | null | E.cs:354:21:354:36 | ... ?? ... | null | +| E.cs:355:13:355:21 | dynamic call to operator != | false | E.cs:355:13:355:13 | access to local variable x | null | +| E.cs:355:13:355:21 | dynamic call to operator != | true | E.cs:355:13:355:13 | access to local variable x | non-null | | E.cs:356:13:356:13 | access to local variable x | non-null | E.cs:354:21:354:36 | ... ?? ... | non-null | | E.cs:356:13:356:13 | access to local variable x | null | E.cs:354:21:354:36 | ... ?? ... | null | | E.cs:361:17:361:32 | ... ?? ... | null | E.cs:361:17:361:17 | access to parameter s | null | diff --git a/csharp/ql/test/query-tests/Nullness/NullCheck.expected b/csharp/ql/test/query-tests/Nullness/NullCheck.expected index 9b45eae33bb..59fc2775290 100644 --- a/csharp/ql/test/query-tests/Nullness/NullCheck.expected +++ b/csharp/ql/test/query-tests/Nullness/NullCheck.expected @@ -221,6 +221,8 @@ | E.cs:348:21:348:21 | access to parameter s | E.cs:348:21:348:21 | access to parameter s | null | true | | E.cs:354:21:354:21 | access to parameter s | E.cs:354:21:354:21 | access to parameter s | non-null | false | | E.cs:354:21:354:21 | access to parameter s | E.cs:354:21:354:21 | access to parameter s | null | true | +| E.cs:355:13:355:21 | dynamic call to operator != | E.cs:355:13:355:13 | access to local variable x | false | true | +| E.cs:355:13:355:21 | dynamic call to operator != | E.cs:355:13:355:13 | access to local variable x | true | false | | E.cs:361:17:361:17 | access to parameter s | E.cs:361:17:361:17 | access to parameter s | non-null | false | | E.cs:361:17:361:17 | access to parameter s | E.cs:361:17:361:17 | access to parameter s | null | true | | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | Forwarding.cs:9:14:9:14 | access to local variable s | false | false | diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected index 8134f22fca7..369ffac4cf1 100644 --- a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected @@ -351,8 +351,6 @@ nodes | E.cs:343:9:343:9 | access to local variable x | | E.cs:348:17:348:36 | SSA def(x) | | E.cs:349:9:349:9 | access to local variable x | -| E.cs:354:17:354:36 | SSA def(x) | -| E.cs:356:13:356:13 | access to local variable x | | E.cs:361:13:361:32 | SSA def(x) | | E.cs:363:13:363:13 | access to local variable x | | Forwarding.cs:7:16:7:23 | SSA def(s) | @@ -686,7 +684,6 @@ edges | E.cs:330:13:330:36 | SSA def(x) | E.cs:331:9:331:9 | access to local variable x | | E.cs:342:13:342:32 | SSA def(x) | E.cs:343:9:343:9 | access to local variable x | | E.cs:348:17:348:36 | SSA def(x) | E.cs:349:9:349:9 | access to local variable x | -| E.cs:354:17:354:36 | SSA def(x) | E.cs:356:13:356:13 | access to local variable x | | E.cs:361:13:361:32 | SSA def(x) | E.cs:363:13:363:13 | access to local variable x | | Forwarding.cs:7:16:7:23 | SSA def(s) | Forwarding.cs:14:9:17:9 | if (...) ... | | Forwarding.cs:14:9:17:9 | if (...) ... | Forwarding.cs:19:9:22:9 | if (...) ... | @@ -788,7 +785,6 @@ edges | E.cs:302:9:302:9 | access to local variable s | E.cs:301:13:301:27 | SSA def(s) | E.cs:302:9:302:9 | access to local variable s | Variable $@ may be null here because of $@ assignment. | E.cs:301:13:301:13 | s | s | E.cs:301:13:301:27 | String s = ... | this | | E.cs:343:9:343:9 | access to local variable x | E.cs:342:13:342:32 | SSA def(x) | E.cs:343:9:343:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:342:13:342:13 | x | x | E.cs:342:13:342:32 | String x = ... | this | | E.cs:349:9:349:9 | access to local variable x | E.cs:348:17:348:36 | SSA def(x) | E.cs:349:9:349:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:348:17:348:17 | x | x | E.cs:348:17:348:36 | dynamic x = ... | this | -| E.cs:356:13:356:13 | access to local variable x | E.cs:354:17:354:36 | SSA def(x) | E.cs:356:13:356:13 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:354:17:354:17 | x | x | E.cs:354:17:354:36 | dynamic x = ... | this | | E.cs:363:13:363:13 | access to local variable x | E.cs:361:13:361:32 | SSA def(x) | E.cs:363:13:363:13 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:361:13:361:13 | x | x | E.cs:361:13:361:32 | String x = ... | this | | GuardedString.cs:35:31:35:31 | access to local variable s | GuardedString.cs:7:16:7:32 | SSA def(s) | GuardedString.cs:35:31:35:31 | access to local variable s | Variable $@ may be null here because of $@ assignment. | GuardedString.cs:7:16:7:16 | s | s | GuardedString.cs:7:16:7:32 | String s = ... | this | | NullMaybeBad.cs:7:27:7:27 | access to parameter o | NullMaybeBad.cs:13:17:13:20 | null | NullMaybeBad.cs:7:27:7:27 | access to parameter o | Variable $@ may be null here because of $@ null argument. | NullMaybeBad.cs:5:25:5:25 | o | o | NullMaybeBad.cs:13:17:13:20 | null | this | From aa0c78cd85fc70c5736e13235896ee3cf9454159 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 20 Sep 2019 09:05:10 +0200 Subject: [PATCH 0163/1227] C#: Teach guards library about more `null` guards --- .../semmle/code/csharp/controlflow/Guards.qll | 7 ++-- csharp/ql/test/query-tests/Nullness/E.cs | 2 +- .../Nullness/Implications.expected | 38 +++++++++++++++++++ .../query-tests/Nullness/NullCheck.expected | 38 +++++++++++++++++++ .../query-tests/Nullness/NullMaybe.expected | 4 -- 5 files changed, 81 insertions(+), 8 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index b14281b3e42..00841dbe3ce 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -277,11 +277,12 @@ class DereferenceableExpr extends Expr { private Expr getABooleanNullCheck(BooleanValue v, boolean isNull) { exists(boolean branch | branch = v.getValue() | // Comparison with `null`, for example `x != null` - exists(ComparisonTest ct, ComparisonKind ck, NullLiteral nl | + exists(ComparisonTest ct, ComparisonKind ck, Expr e | ct.getExpr() = result and ct.getAnArgument() = this and - ct.getAnArgument() = nl and - this != nl and + ct.getAnArgument() = e and + e = any(NullValue nv | nv.isNull()).getAnExpr() and + this != e and ck = ct.getComparisonKind() | ck.isEquality() and isNull = branch diff --git a/csharp/ql/test/query-tests/Nullness/E.cs b/csharp/ql/test/query-tests/Nullness/E.cs index 711e11fe65a..a0338c57565 100644 --- a/csharp/ql/test/query-tests/Nullness/E.cs +++ b/csharp/ql/test/query-tests/Nullness/E.cs @@ -360,7 +360,7 @@ public class E { var x = s ?? o as string; if (x != (string)null) - x.ToString(); // GOOD (FALSE POSITIVE) + x.ToString(); // GOOD } } diff --git a/csharp/ql/test/query-tests/Nullness/Implications.expected b/csharp/ql/test/query-tests/Nullness/Implications.expected index e54cdf14245..7857874a8ec 100644 --- a/csharp/ql/test/query-tests/Nullness/Implications.expected +++ b/csharp/ql/test/query-tests/Nullness/Implications.expected @@ -203,25 +203,33 @@ | B.cs:12:13:12:24 | access to local variable eqCallAlways | non-null | B.cs:7:26:7:29 | null | non-null | | B.cs:12:13:12:24 | access to local variable eqCallAlways | null | B.cs:7:26:7:29 | null | null | | B.cs:12:13:12:32 | call to operator == | false | B.cs:12:13:12:24 | access to local variable eqCallAlways | non-null | +| B.cs:12:13:12:32 | call to operator == | false | B.cs:12:29:12:32 | null | non-null | | B.cs:12:13:12:32 | call to operator == | true | B.cs:12:13:12:24 | access to local variable eqCallAlways | null | +| B.cs:12:13:12:32 | call to operator == | true | B.cs:12:29:12:32 | null | null | | B.cs:13:13:13:24 | access to local variable eqCallAlways | non-null | B.cs:7:26:7:29 | null | non-null | | B.cs:13:13:13:24 | access to local variable eqCallAlways | null | B.cs:7:26:7:29 | null | null | | B.cs:15:13:15:14 | access to local variable b2 | non-null | B.cs:8:16:8:19 | null | non-null | | B.cs:15:13:15:14 | access to local variable b2 | null | B.cs:8:16:8:19 | null | null | | B.cs:15:13:15:22 | call to operator != | false | B.cs:15:13:15:14 | access to local variable b2 | null | +| B.cs:15:13:15:22 | call to operator != | false | B.cs:15:19:15:22 | null | null | | B.cs:15:13:15:22 | call to operator != | true | B.cs:15:13:15:14 | access to local variable b2 | non-null | +| B.cs:15:13:15:22 | call to operator != | true | B.cs:15:19:15:22 | null | non-null | | B.cs:16:13:16:14 | access to local variable b2 | non-null | B.cs:8:16:8:19 | null | non-null | | B.cs:16:13:16:14 | access to local variable b2 | null | B.cs:8:16:8:19 | null | null | | B.cs:18:13:18:14 | access to local variable b3 | non-null | B.cs:9:16:9:19 | null | non-null | | B.cs:18:13:18:14 | access to local variable b3 | null | B.cs:9:16:9:19 | null | null | | B.cs:18:13:18:22 | call to operator == | false | B.cs:18:13:18:14 | access to local variable b3 | non-null | +| B.cs:18:13:18:22 | call to operator == | false | B.cs:18:19:18:22 | null | non-null | | B.cs:18:13:18:22 | call to operator == | true | B.cs:18:13:18:14 | access to local variable b3 | null | +| B.cs:18:13:18:22 | call to operator == | true | B.cs:18:19:18:22 | null | null | | B.cs:20:13:20:14 | access to local variable b3 | non-null | B.cs:9:16:9:19 | null | non-null | | B.cs:20:13:20:14 | access to local variable b3 | null | B.cs:9:16:9:19 | null | null | | B.cs:22:13:22:25 | access to local variable neqCallAlways | non-null | B.cs:10:27:10:30 | null | non-null | | B.cs:22:13:22:25 | access to local variable neqCallAlways | null | B.cs:10:27:10:30 | null | null | | B.cs:22:13:22:33 | call to operator != | false | B.cs:22:13:22:25 | access to local variable neqCallAlways | null | +| B.cs:22:13:22:33 | call to operator != | false | B.cs:22:30:22:33 | null | null | | B.cs:22:13:22:33 | call to operator != | true | B.cs:22:13:22:25 | access to local variable neqCallAlways | non-null | +| B.cs:22:13:22:33 | call to operator != | true | B.cs:22:30:22:33 | null | non-null | | B.cs:24:13:24:25 | access to local variable neqCallAlways | non-null | B.cs:10:27:10:30 | null | non-null | | B.cs:24:13:24:25 | access to local variable neqCallAlways | null | B.cs:10:27:10:30 | null | null | | B.cs:34:16:34:26 | !... | false | B.cs:34:18:34:25 | call to operator == | true | @@ -229,11 +237,17 @@ | B.cs:53:17:53:25 | (...) ... | non-null | B.cs:53:25:53:25 | access to local variable o | non-null | | B.cs:53:17:53:25 | (...) ... | null | B.cs:53:25:53:25 | access to local variable o | null | | B.cs:53:17:53:33 | ... != ... | false | B.cs:53:17:53:25 | (...) ... | null | +| B.cs:53:17:53:33 | ... != ... | false | B.cs:53:30:53:33 | null | null | | B.cs:53:17:53:33 | ... != ... | true | B.cs:53:17:53:25 | (...) ... | non-null | +| B.cs:53:17:53:33 | ... != ... | true | B.cs:53:30:53:33 | null | non-null | | B.cs:53:25:53:25 | access to local variable o | non-null | B.cs:52:24:52:27 | null | non-null | | B.cs:53:25:53:25 | access to local variable o | null | B.cs:52:24:52:27 | null | null | | B.cs:55:26:55:26 | access to local variable o | non-null | B.cs:52:24:52:27 | null | non-null | | B.cs:55:26:55:26 | access to local variable o | null | B.cs:52:24:52:27 | null | null | +| B.cs:55:26:55:36 | call to method Equals | false | B.cs:55:26:55:26 | access to local variable o | non-null | +| B.cs:55:26:55:36 | call to method Equals | false | B.cs:55:35:55:35 | access to local variable o | non-null | +| B.cs:55:26:55:36 | call to method Equals | true | B.cs:55:26:55:26 | access to local variable o | null | +| B.cs:55:26:55:36 | call to method Equals | true | B.cs:55:35:55:35 | access to local variable o | null | | B.cs:55:35:55:35 | access to local variable o | non-null | B.cs:52:24:52:27 | null | non-null | | B.cs:55:35:55:35 | access to local variable o | null | B.cs:52:24:52:27 | null | null | | C.cs:11:13:11:30 | !... | false | C.cs:11:15:11:29 | !... | true | @@ -245,7 +259,9 @@ | C.cs:11:19:11:19 | access to local variable o | non-null | C.cs:10:20:10:23 | null | non-null | | C.cs:11:19:11:19 | access to local variable o | null | C.cs:10:20:10:23 | null | null | | C.cs:11:19:11:27 | ... == ... | false | C.cs:11:19:11:19 | access to local variable o | non-null | +| C.cs:11:19:11:27 | ... == ... | false | C.cs:11:24:11:27 | null | non-null | | C.cs:11:19:11:27 | ... == ... | true | C.cs:11:19:11:19 | access to local variable o | null | +| C.cs:11:19:11:27 | ... == ... | true | C.cs:11:24:11:27 | null | null | | C.cs:13:13:13:13 | access to local variable o | non-null | C.cs:10:20:10:23 | null | non-null | | C.cs:13:13:13:13 | access to local variable o | null | C.cs:10:20:10:23 | null | null | | C.cs:16:13:16:24 | !... | false | C.cs:16:15:16:23 | ... != ... | true | @@ -253,7 +269,9 @@ | C.cs:16:15:16:15 | access to local variable o | non-null | C.cs:10:20:10:23 | null | non-null | | C.cs:16:15:16:15 | access to local variable o | null | C.cs:10:20:10:23 | null | null | | C.cs:16:15:16:23 | ... != ... | false | C.cs:16:15:16:15 | access to local variable o | null | +| C.cs:16:15:16:23 | ... != ... | false | C.cs:16:20:16:23 | null | null | | C.cs:16:15:16:23 | ... != ... | true | C.cs:16:15:16:15 | access to local variable o | non-null | +| C.cs:16:15:16:23 | ... != ... | true | C.cs:16:20:16:23 | null | non-null | | C.cs:18:13:18:13 | access to local variable o | non-null | C.cs:10:20:10:23 | null | non-null | | C.cs:18:13:18:13 | access to local variable o | null | C.cs:10:20:10:23 | null | null | | C.cs:24:13:24:21 | ... != ... | false | C.cs:24:13:24:13 | access to parameter o | null | @@ -362,7 +380,9 @@ | C.cs:114:22:114:28 | access to local variable colours | non-null | C.cs:113:26:113:29 | null | non-null | | C.cs:114:22:114:28 | access to local variable colours | null | C.cs:113:26:113:29 | null | null | | C.cs:114:22:114:36 | ... == ... | false | C.cs:114:22:114:28 | access to local variable colours | non-null | +| C.cs:114:22:114:36 | ... == ... | false | C.cs:114:33:114:36 | null | non-null | | C.cs:114:22:114:36 | ... == ... | true | C.cs:114:22:114:28 | access to local variable colours | null | +| C.cs:114:22:114:36 | ... == ... | true | C.cs:114:33:114:36 | null | null | | C.cs:114:22:114:59 | ... \|\| ... | false | C.cs:114:22:114:36 | ... == ... | false | | C.cs:114:22:114:59 | ... \|\| ... | false | C.cs:114:41:114:59 | ... == ... | false | | C.cs:114:22:114:90 | ... ? ... : ... | null | C.cs:114:22:114:59 | ... \|\| ... | false | @@ -376,10 +396,14 @@ | C.cs:121:13:121:20 | access to local variable children | non-null | C.cs:119:29:119:32 | null | non-null | | C.cs:121:13:121:20 | access to local variable children | null | C.cs:119:29:119:32 | null | null | | C.cs:121:13:121:28 | ... == ... | false | C.cs:121:13:121:20 | access to local variable children | non-null | +| C.cs:121:13:121:28 | ... == ... | false | C.cs:121:25:121:28 | null | non-null | | C.cs:121:13:121:28 | ... == ... | true | C.cs:121:13:121:20 | access to local variable children | null | +| C.cs:121:13:121:28 | ... == ... | true | C.cs:121:25:121:28 | null | null | | C.cs:123:13:123:31 | ... > ... | true | C.cs:123:13:123:20 | access to local variable children | non-empty | | C.cs:130:13:130:38 | ... == ... | false | C.cs:130:14:130:29 | ... = ... | non-null | +| C.cs:130:13:130:38 | ... == ... | false | C.cs:130:35:130:38 | null | non-null | | C.cs:130:13:130:38 | ... == ... | true | C.cs:130:14:130:29 | ... = ... | null | +| C.cs:130:13:130:38 | ... == ... | true | C.cs:130:35:130:38 | null | null | | C.cs:130:13:130:55 | ... \|\| ... | false | C.cs:130:13:130:38 | ... == ... | false | | C.cs:130:13:130:55 | ... \|\| ... | false | C.cs:130:43:130:55 | ... > ... | false | | C.cs:130:14:130:29 | ... = ... | empty | C.cs:130:14:130:15 | access to local variable ok | empty | @@ -417,7 +441,9 @@ | C.cs:138:35:138:37 | access to local variable ok2 | non-null | C.cs:138:23:138:29 | "hello" | non-null | | C.cs:138:35:138:37 | access to local variable ok2 | null | C.cs:138:23:138:29 | "hello" | null | | C.cs:146:13:146:39 | ... != ... | false | C.cs:146:14:146:30 | ... = ... | null | +| C.cs:146:13:146:39 | ... != ... | false | C.cs:146:36:146:39 | null | null | | C.cs:146:13:146:39 | ... != ... | true | C.cs:146:14:146:30 | ... = ... | non-null | +| C.cs:146:13:146:39 | ... != ... | true | C.cs:146:36:146:39 | null | non-null | | C.cs:146:13:146:57 | ... && ... | true | C.cs:146:13:146:39 | ... != ... | true | | C.cs:146:13:146:57 | ... && ... | true | C.cs:146:44:146:57 | ... > ... | true | | C.cs:146:14:146:30 | ... = ... | empty | C.cs:146:14:146:15 | access to local variable xx | empty | @@ -445,19 +471,25 @@ | C.cs:158:16:158:16 | access to local variable s | non-null | C.cs:156:17:156:20 | null | non-null | | C.cs:158:16:158:16 | access to local variable s | null | C.cs:156:17:156:20 | null | null | | C.cs:158:16:158:24 | ... != ... | false | C.cs:158:16:158:16 | access to local variable s | null | +| C.cs:158:16:158:24 | ... != ... | false | C.cs:158:21:158:24 | null | null | | C.cs:158:16:158:24 | ... != ... | true | C.cs:158:16:158:16 | access to local variable s | non-null | +| C.cs:158:16:158:24 | ... != ... | true | C.cs:158:21:158:24 | null | non-null | | C.cs:166:16:166:16 | access to local variable s | empty | C.cs:164:17:164:20 | null | empty | | C.cs:166:16:166:16 | access to local variable s | non-empty | C.cs:164:17:164:20 | null | non-empty | | C.cs:166:16:166:16 | access to local variable s | non-null | C.cs:164:17:164:20 | null | non-null | | C.cs:166:16:166:16 | access to local variable s | null | C.cs:164:17:164:20 | null | null | | C.cs:166:16:166:24 | ... != ... | false | C.cs:166:16:166:16 | access to local variable s | null | +| C.cs:166:16:166:24 | ... != ... | false | C.cs:166:21:166:24 | null | null | | C.cs:166:16:166:24 | ... != ... | true | C.cs:166:16:166:16 | access to local variable s | non-null | +| C.cs:166:16:166:24 | ... != ... | true | C.cs:166:21:166:24 | null | non-null | | C.cs:171:13:171:13 | access to local variable s | non-null | C.cs:168:13:168:16 | null | non-null | | C.cs:171:13:171:13 | access to local variable s | null | C.cs:168:13:168:16 | null | null | | C.cs:173:16:173:16 | access to local variable s | non-null | C.cs:168:13:168:16 | null | non-null | | C.cs:173:16:173:16 | access to local variable s | null | C.cs:168:13:168:16 | null | null | | C.cs:173:16:173:24 | ... != ... | false | C.cs:173:16:173:16 | access to local variable s | null | +| C.cs:173:16:173:24 | ... != ... | false | C.cs:173:21:173:24 | null | null | | C.cs:173:16:173:24 | ... != ... | true | C.cs:173:16:173:16 | access to local variable s | non-null | +| C.cs:173:16:173:24 | ... != ... | true | C.cs:173:21:173:24 | null | non-null | | C.cs:187:16:187:24 | ... != ... | false | C.cs:187:16:187:16 | access to local variable s | null | | C.cs:187:16:187:24 | ... != ... | true | C.cs:187:16:187:16 | access to local variable s | non-null | | C.cs:211:17:211:35 | ... ? ... : ... | non-null | C.cs:211:17:211:23 | call to method Maybe | false | @@ -515,7 +547,9 @@ | C.cs:236:14:236:21 | ... = ... | null | C.cs:236:14:236:14 | access to local variable s | null | | C.cs:236:14:236:21 | ... = ... | null | C.cs:236:18:236:21 | null | null | | C.cs:236:24:236:32 | ... == ... | false | C.cs:236:24:236:24 | access to local variable s | non-null | +| C.cs:236:24:236:32 | ... == ... | false | C.cs:236:29:236:32 | null | non-null | | C.cs:236:24:236:32 | ... == ... | true | C.cs:236:24:236:24 | access to local variable s | null | +| C.cs:236:24:236:32 | ... == ... | true | C.cs:236:29:236:32 | null | null | | C.cs:236:35:236:42 | ... = ... | empty | C.cs:236:35:236:35 | access to local variable s | empty | | C.cs:236:35:236:42 | ... = ... | empty | C.cs:236:39:236:42 | null | empty | | C.cs:236:35:236:42 | ... = ... | non-empty | C.cs:236:35:236:35 | access to local variable s | non-empty | @@ -794,7 +828,9 @@ | D.cs:212:18:212:18 | access to local variable n | non-null | D.cs:211:20:211:23 | null | non-null | | D.cs:212:18:212:18 | access to local variable n | null | D.cs:211:20:211:23 | null | null | | D.cs:212:18:212:26 | ... == ... | false | D.cs:212:18:212:18 | access to local variable n | non-null | +| D.cs:212:18:212:26 | ... == ... | false | D.cs:212:23:212:26 | null | non-null | | D.cs:212:18:212:26 | ... == ... | true | D.cs:212:18:212:18 | access to local variable n | null | +| D.cs:212:18:212:26 | ... == ... | true | D.cs:212:23:212:26 | null | null | | D.cs:212:18:212:45 | ... ? ... : ... | non-null | D.cs:212:18:212:26 | ... == ... | true | | D.cs:212:18:212:45 | ... ? ... : ... | non-null | D.cs:212:30:212:41 | object creation of type Object | non-null | | D.cs:212:18:212:45 | ... ? ... : ... | null | D.cs:212:18:212:26 | ... == ... | false | @@ -1189,6 +1225,8 @@ | E.cs:362:13:362:13 | access to local variable x | non-empty | E.cs:361:17:361:32 | ... ?? ... | non-empty | | E.cs:362:13:362:13 | access to local variable x | non-null | E.cs:361:17:361:32 | ... ?? ... | non-null | | E.cs:362:13:362:13 | access to local variable x | null | E.cs:361:17:361:32 | ... ?? ... | null | +| E.cs:362:13:362:29 | ... != ... | false | E.cs:362:13:362:13 | access to local variable x | null | +| E.cs:362:13:362:29 | ... != ... | true | E.cs:362:13:362:13 | access to local variable x | non-null | | E.cs:362:18:362:29 | (...) ... | non-null | E.cs:362:26:362:29 | null | non-null | | E.cs:362:18:362:29 | (...) ... | null | E.cs:362:26:362:29 | null | null | | E.cs:363:13:363:13 | access to local variable x | non-null | E.cs:361:17:361:32 | ... ?? ... | non-null | diff --git a/csharp/ql/test/query-tests/Nullness/NullCheck.expected b/csharp/ql/test/query-tests/Nullness/NullCheck.expected index 59fc2775290..ef3986119d4 100644 --- a/csharp/ql/test/query-tests/Nullness/NullCheck.expected +++ b/csharp/ql/test/query-tests/Nullness/NullCheck.expected @@ -18,18 +18,36 @@ | Assert.cs:50:24:50:32 | ... != ... | Assert.cs:50:24:50:24 | access to local variable s | true | false | | B.cs:12:13:12:32 | call to operator == | B.cs:12:13:12:24 | access to local variable eqCallAlways | false | false | | B.cs:12:13:12:32 | call to operator == | B.cs:12:13:12:24 | access to local variable eqCallAlways | true | true | +| B.cs:12:13:12:32 | call to operator == | B.cs:12:29:12:32 | null | false | false | +| B.cs:12:13:12:32 | call to operator == | B.cs:12:29:12:32 | null | true | true | | B.cs:15:13:15:22 | call to operator != | B.cs:15:13:15:14 | access to local variable b2 | false | true | | B.cs:15:13:15:22 | call to operator != | B.cs:15:13:15:14 | access to local variable b2 | true | false | +| B.cs:15:13:15:22 | call to operator != | B.cs:15:19:15:22 | null | false | true | +| B.cs:15:13:15:22 | call to operator != | B.cs:15:19:15:22 | null | true | false | | B.cs:18:13:18:22 | call to operator == | B.cs:18:13:18:14 | access to local variable b3 | false | false | | B.cs:18:13:18:22 | call to operator == | B.cs:18:13:18:14 | access to local variable b3 | true | true | +| B.cs:18:13:18:22 | call to operator == | B.cs:18:19:18:22 | null | false | false | +| B.cs:18:13:18:22 | call to operator == | B.cs:18:19:18:22 | null | true | true | | B.cs:22:13:22:33 | call to operator != | B.cs:22:13:22:25 | access to local variable neqCallAlways | false | true | | B.cs:22:13:22:33 | call to operator != | B.cs:22:13:22:25 | access to local variable neqCallAlways | true | false | +| B.cs:22:13:22:33 | call to operator != | B.cs:22:30:22:33 | null | false | true | +| B.cs:22:13:22:33 | call to operator != | B.cs:22:30:22:33 | null | true | false | | B.cs:53:17:53:33 | ... != ... | B.cs:53:17:53:25 | (...) ... | false | true | | B.cs:53:17:53:33 | ... != ... | B.cs:53:17:53:25 | (...) ... | true | false | +| B.cs:53:17:53:33 | ... != ... | B.cs:53:30:53:33 | null | false | true | +| B.cs:53:17:53:33 | ... != ... | B.cs:53:30:53:33 | null | true | false | +| B.cs:55:26:55:36 | call to method Equals | B.cs:55:26:55:26 | access to local variable o | false | false | +| B.cs:55:26:55:36 | call to method Equals | B.cs:55:26:55:26 | access to local variable o | true | true | +| B.cs:55:26:55:36 | call to method Equals | B.cs:55:35:55:35 | access to local variable o | false | false | +| B.cs:55:26:55:36 | call to method Equals | B.cs:55:35:55:35 | access to local variable o | true | true | | C.cs:11:19:11:27 | ... == ... | C.cs:11:19:11:19 | access to local variable o | false | false | | C.cs:11:19:11:27 | ... == ... | C.cs:11:19:11:19 | access to local variable o | true | true | +| C.cs:11:19:11:27 | ... == ... | C.cs:11:24:11:27 | null | false | false | +| C.cs:11:19:11:27 | ... == ... | C.cs:11:24:11:27 | null | true | true | | C.cs:16:15:16:23 | ... != ... | C.cs:16:15:16:15 | access to local variable o | false | true | | C.cs:16:15:16:23 | ... != ... | C.cs:16:15:16:15 | access to local variable o | true | false | +| C.cs:16:15:16:23 | ... != ... | C.cs:16:20:16:23 | null | false | true | +| C.cs:16:15:16:23 | ... != ... | C.cs:16:20:16:23 | null | true | false | | C.cs:24:13:24:21 | ... != ... | C.cs:24:13:24:13 | access to parameter o | false | true | | C.cs:24:13:24:21 | ... != ... | C.cs:24:13:24:13 | access to parameter o | true | false | | C.cs:28:37:28:45 | ... == ... | C.cs:28:37:28:37 | access to parameter o | false | false | @@ -49,18 +67,32 @@ | C.cs:89:13:89:23 | ... is ... | C.cs:89:13:89:13 | access to local variable o | true | false | | C.cs:114:22:114:36 | ... == ... | C.cs:114:22:114:28 | access to local variable colours | false | false | | C.cs:114:22:114:36 | ... == ... | C.cs:114:22:114:28 | access to local variable colours | true | true | +| C.cs:114:22:114:36 | ... == ... | C.cs:114:33:114:36 | null | false | false | +| C.cs:114:22:114:36 | ... == ... | C.cs:114:33:114:36 | null | true | true | | C.cs:121:13:121:28 | ... == ... | C.cs:121:13:121:20 | access to local variable children | false | false | | C.cs:121:13:121:28 | ... == ... | C.cs:121:13:121:20 | access to local variable children | true | true | +| C.cs:121:13:121:28 | ... == ... | C.cs:121:25:121:28 | null | false | false | +| C.cs:121:13:121:28 | ... == ... | C.cs:121:25:121:28 | null | true | true | | C.cs:130:13:130:38 | ... == ... | C.cs:130:14:130:29 | ... = ... | false | false | | C.cs:130:13:130:38 | ... == ... | C.cs:130:14:130:29 | ... = ... | true | true | +| C.cs:130:13:130:38 | ... == ... | C.cs:130:35:130:38 | null | false | false | +| C.cs:130:13:130:38 | ... == ... | C.cs:130:35:130:38 | null | true | true | | C.cs:146:13:146:39 | ... != ... | C.cs:146:14:146:30 | ... = ... | false | true | | C.cs:146:13:146:39 | ... != ... | C.cs:146:14:146:30 | ... = ... | true | false | +| C.cs:146:13:146:39 | ... != ... | C.cs:146:36:146:39 | null | false | true | +| C.cs:146:13:146:39 | ... != ... | C.cs:146:36:146:39 | null | true | false | | C.cs:158:16:158:24 | ... != ... | C.cs:158:16:158:16 | access to local variable s | false | true | | C.cs:158:16:158:24 | ... != ... | C.cs:158:16:158:16 | access to local variable s | true | false | +| C.cs:158:16:158:24 | ... != ... | C.cs:158:21:158:24 | null | false | true | +| C.cs:158:16:158:24 | ... != ... | C.cs:158:21:158:24 | null | true | false | | C.cs:166:16:166:24 | ... != ... | C.cs:166:16:166:16 | access to local variable s | false | true | | C.cs:166:16:166:24 | ... != ... | C.cs:166:16:166:16 | access to local variable s | true | false | +| C.cs:166:16:166:24 | ... != ... | C.cs:166:21:166:24 | null | false | true | +| C.cs:166:16:166:24 | ... != ... | C.cs:166:21:166:24 | null | true | false | | C.cs:173:16:173:24 | ... != ... | C.cs:173:16:173:16 | access to local variable s | false | true | | C.cs:173:16:173:24 | ... != ... | C.cs:173:16:173:16 | access to local variable s | true | false | +| C.cs:173:16:173:24 | ... != ... | C.cs:173:21:173:24 | null | false | true | +| C.cs:173:16:173:24 | ... != ... | C.cs:173:21:173:24 | null | true | false | | C.cs:187:16:187:24 | ... != ... | C.cs:187:16:187:16 | access to local variable s | false | true | | C.cs:187:16:187:24 | ... != ... | C.cs:187:16:187:16 | access to local variable s | true | false | | C.cs:212:13:212:21 | ... != ... | C.cs:212:13:212:13 | access to local variable s | false | true | @@ -74,6 +106,8 @@ | C.cs:230:22:230:30 | ... != ... | C.cs:230:22:230:22 | access to local variable s | true | false | | C.cs:236:24:236:32 | ... == ... | C.cs:236:24:236:24 | access to local variable s | false | false | | C.cs:236:24:236:32 | ... == ... | C.cs:236:24:236:24 | access to local variable s | true | true | +| C.cs:236:24:236:32 | ... == ... | C.cs:236:29:236:32 | null | false | false | +| C.cs:236:24:236:32 | ... == ... | C.cs:236:29:236:32 | null | true | true | | D.cs:28:13:28:25 | ... != ... | D.cs:28:13:28:17 | access to parameter param | false | true | | D.cs:28:13:28:25 | ... != ... | D.cs:28:13:28:17 | access to parameter param | true | false | | D.cs:37:13:37:23 | ... is ... | D.cs:37:13:37:13 | access to parameter x | true | false | @@ -122,6 +156,8 @@ | D.cs:206:17:206:25 | ... == ... | D.cs:206:17:206:17 | access to local variable e | true | true | | D.cs:212:18:212:26 | ... == ... | D.cs:212:18:212:18 | access to local variable n | false | false | | D.cs:212:18:212:26 | ... == ... | D.cs:212:18:212:18 | access to local variable n | true | true | +| D.cs:212:18:212:26 | ... == ... | D.cs:212:23:212:26 | null | false | false | +| D.cs:212:18:212:26 | ... == ... | D.cs:212:23:212:26 | null | true | true | | D.cs:216:13:216:22 | ... == ... | D.cs:216:13:216:14 | access to local variable o3 | false | false | | D.cs:216:13:216:22 | ... == ... | D.cs:216:13:216:14 | access to local variable o3 | true | true | | D.cs:216:13:216:22 | ... == ... | D.cs:216:19:216:22 | null | true | false | @@ -225,6 +261,8 @@ | E.cs:355:13:355:21 | dynamic call to operator != | E.cs:355:13:355:13 | access to local variable x | true | false | | E.cs:361:17:361:17 | access to parameter s | E.cs:361:17:361:17 | access to parameter s | non-null | false | | E.cs:361:17:361:17 | access to parameter s | E.cs:361:17:361:17 | access to parameter s | null | true | +| E.cs:362:13:362:29 | ... != ... | E.cs:362:13:362:13 | access to local variable x | false | true | +| E.cs:362:13:362:29 | ... != ... | E.cs:362:13:362:13 | access to local variable x | true | false | | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | Forwarding.cs:9:14:9:14 | access to local variable s | false | false | | Forwarding.cs:14:13:14:32 | call to method IsNotNullOrEmpty | Forwarding.cs:14:13:14:13 | access to local variable s | true | false | | Forwarding.cs:19:14:19:23 | call to method IsNull | Forwarding.cs:19:14:19:14 | access to local variable s | false | false | diff --git a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected index 369ffac4cf1..25349d10cc0 100644 --- a/csharp/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/csharp/ql/test/query-tests/Nullness/NullMaybe.expected @@ -351,8 +351,6 @@ nodes | E.cs:343:9:343:9 | access to local variable x | | E.cs:348:17:348:36 | SSA def(x) | | E.cs:349:9:349:9 | access to local variable x | -| E.cs:361:13:361:32 | SSA def(x) | -| E.cs:363:13:363:13 | access to local variable x | | Forwarding.cs:7:16:7:23 | SSA def(s) | | Forwarding.cs:14:9:17:9 | if (...) ... | | Forwarding.cs:19:9:22:9 | if (...) ... | @@ -684,7 +682,6 @@ edges | E.cs:330:13:330:36 | SSA def(x) | E.cs:331:9:331:9 | access to local variable x | | E.cs:342:13:342:32 | SSA def(x) | E.cs:343:9:343:9 | access to local variable x | | E.cs:348:17:348:36 | SSA def(x) | E.cs:349:9:349:9 | access to local variable x | -| E.cs:361:13:361:32 | SSA def(x) | E.cs:363:13:363:13 | access to local variable x | | Forwarding.cs:7:16:7:23 | SSA def(s) | Forwarding.cs:14:9:17:9 | if (...) ... | | Forwarding.cs:14:9:17:9 | if (...) ... | Forwarding.cs:19:9:22:9 | if (...) ... | | Forwarding.cs:19:9:22:9 | if (...) ... | Forwarding.cs:24:9:27:9 | if (...) ... | @@ -785,7 +782,6 @@ edges | E.cs:302:9:302:9 | access to local variable s | E.cs:301:13:301:27 | SSA def(s) | E.cs:302:9:302:9 | access to local variable s | Variable $@ may be null here because of $@ assignment. | E.cs:301:13:301:13 | s | s | E.cs:301:13:301:27 | String s = ... | this | | E.cs:343:9:343:9 | access to local variable x | E.cs:342:13:342:32 | SSA def(x) | E.cs:343:9:343:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:342:13:342:13 | x | x | E.cs:342:13:342:32 | String x = ... | this | | E.cs:349:9:349:9 | access to local variable x | E.cs:348:17:348:36 | SSA def(x) | E.cs:349:9:349:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:348:17:348:17 | x | x | E.cs:348:17:348:36 | dynamic x = ... | this | -| E.cs:363:13:363:13 | access to local variable x | E.cs:361:13:361:32 | SSA def(x) | E.cs:363:13:363:13 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:361:13:361:13 | x | x | E.cs:361:13:361:32 | String x = ... | this | | GuardedString.cs:35:31:35:31 | access to local variable s | GuardedString.cs:7:16:7:32 | SSA def(s) | GuardedString.cs:35:31:35:31 | access to local variable s | Variable $@ may be null here because of $@ assignment. | GuardedString.cs:7:16:7:16 | s | s | GuardedString.cs:7:16:7:32 | String s = ... | this | | NullMaybeBad.cs:7:27:7:27 | access to parameter o | NullMaybeBad.cs:13:17:13:20 | null | NullMaybeBad.cs:7:27:7:27 | access to parameter o | Variable $@ may be null here because of $@ null argument. | NullMaybeBad.cs:5:25:5:25 | o | o | NullMaybeBad.cs:13:17:13:20 | null | this | | StringConcatenation.cs:16:17:16:17 | access to local variable s | StringConcatenation.cs:14:16:14:23 | SSA def(s) | StringConcatenation.cs:16:17:16:17 | access to local variable s | Variable $@ may be null here because of $@ assignment. | StringConcatenation.cs:14:16:14:16 | s | s | StringConcatenation.cs:14:16:14:23 | String s = ... | this | From fb68d839a9d43e3952a00610450a5e639027634d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 20 Sep 2019 10:40:20 +0200 Subject: [PATCH 0164/1227] C#: Add change note --- change-notes/1.23/analysis-csharp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.23/analysis-csharp.md b/change-notes/1.23/analysis-csharp.md index d22f7ea567a..243a1efec8a 100644 --- a/change-notes/1.23/analysis-csharp.md +++ b/change-notes/1.23/analysis-csharp.md @@ -15,6 +15,7 @@ The following changes in version 1.23 affect C# analysis in all applications. | **Query** | **Expected impact** | **Change** | |------------------------------|------------------------|-----------------------------------| +| Dereferenced variable may be null (`cs/dereferenced-value-may-be-null`) | Fewer false positive results | More `null` checks are now taken into account, including `null` checks for `dynamic` expressions and `null` checks such as `object alwaysNull = null; if (x != alwaysNull) ...`. | ## Removal of old queries From cb6e1536a389c39f73c1abd0000a9a808a86a0d4 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 20 Sep 2019 11:40:18 +0200 Subject: [PATCH 0165/1227] C#: Fix broken unit test on Windows --- csharp/extractor/Semmle.Extraction.Tests/Options.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.Tests/Options.cs b/csharp/extractor/Semmle.Extraction.Tests/Options.cs index 356228a0ce8..ce240ce146d 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Options.cs +++ b/csharp/extractor/Semmle.Extraction.Tests/Options.cs @@ -3,6 +3,7 @@ using Semmle.Util.Logging; using System; using System.IO; using Semmle.Util; +using System.Text.RegularExpressions; namespace Semmle.Extraction.Tests { @@ -197,7 +198,7 @@ namespace Semmle.Extraction.Tests { File.AppendAllText(file, "Test"); new string[] { "/noconfig", "@" + file }.WriteCommandLine(sw); - Assert.Equal("Test\n", sw.ToString()); + Assert.Equal("Test", Regex.Replace(sw.ToString(), @"\t|\n|\r", "")); } finally { From 06b391ef9ba35fdcee626e40a42d229884243f52 Mon Sep 17 00:00:00 2001 From: james Date: Fri, 20 Sep 2019 11:14:16 +0100 Subject: [PATCH 0166/1227] docs: fix links --- docs/language/learn-ql/java/introduce-libraries-java.rst | 2 +- docs/language/learn-ql/javascript/introduce-libraries-ts.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index 4757085cfe1..32863b099e0 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -369,7 +369,7 @@ Conversely, ``Callable.getAReference`` returns a ``Call`` that refers to it. So where not exists(c.getAReference()) select c -➤ `See this in the query console `__. The LGTM.com demo projects all appear to have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see `Navigating the call graph `__. +➤ `See this in the query console `__. The LGTM.com demo projects all appear to have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see :doc:`Navigating the call graph `. For more information about callables and calls, see the :doc:`call graph tutorial `. diff --git a/docs/language/learn-ql/javascript/introduce-libraries-ts.rst b/docs/language/learn-ql/javascript/introduce-libraries-ts.rst index a31bf9ffad6..539d81fb016 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-ts.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-ts.rst @@ -134,7 +134,7 @@ The QL class `ClassOrInterface `__. -Also see the documentation for classes in the `Introduction to the QL libraries for JavaScript `__. +Also see the documentation for classes in the `Introduction to the QL libraries for JavaScript `__. To select the type references to a class or an interface, use ``getTypeName()``. @@ -443,6 +443,6 @@ A `LocalNamespaceName `. +- Learn about the QL standard libraries used to write queries for JavaScript in :doc:`Introducing the JavaScript libraries `. - Find out more about QL in the `QL language handbook `__ and `QL language specification `__. - Learn more about the query console in `Using the query console `__. \ No newline at end of file From 1c971d3f8857fa56b044374e4b72d913cae57b3f Mon Sep 17 00:00:00 2001 From: Pavel Avgustinov Date: Thu, 19 Sep 2019 18:17:47 +0100 Subject: [PATCH 0167/1227] HashCons: Further performance improvements The key insight here is that `HC_FieldCons` and `HC_Array` are functionally determined by the things that arise in another recursive call. Lifting them to their own predicate, therefore, reduces nonlinearity and constrains the join order in a way that cannot be asymptotically bad -- and, indeed, makes quite a big difference in practice. --- .../code/cpp/valuenumbering/HashCons.qll | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/valuenumbering/HashCons.qll b/cpp/ql/src/semmle/code/cpp/valuenumbering/HashCons.qll index 5a5ab9e819a..1077a01c946 100644 --- a/cpp/ql/src/semmle/code/cpp/valuenumbering/HashCons.qll +++ b/cpp/ql/src/semmle/code/cpp/valuenumbering/HashCons.qll @@ -729,6 +729,18 @@ private predicate mk_AlignofExpr(HashCons child, AlignofExprOperator e) { child = hashCons(e.getAChild()) } +/** + * Gets the hash cons of field initializer expressions [0..i), where i > 0, for + * the class aggregate literal `cal` of type `c`, where `head` is the hash cons + * of the i'th initializer expression. + */ +HC_Fields aggInitExprsUpTo(ClassAggregateLiteral cal, Class c, int i) { + exists(Field f, HashCons head, HC_Fields tail | + result = HC_FieldCons(c, i - 1, f, head, tail) and + mk_FieldCons(c, i - 1, f, head, tail, cal) + ) +} + private predicate mk_FieldCons( Class c, int i, Field f, HashCons hc, HC_Fields hcf, ClassAggregateLiteral cal ) { @@ -738,12 +750,8 @@ private predicate mk_FieldCons( e = cal.getFieldExpr(f).getFullyConverted() and f.getInitializationOrder() = i and ( - exists(HashCons head, Field f2, HC_Fields tail | - hc = hashCons(e) and - hcf = HC_FieldCons(c, i - 1, f2, head, tail) and - f2.getInitializationOrder() = i - 1 and - mk_FieldCons(c, i - 1, f2, head, tail, cal) - ) + hc = hashCons(e) and + hcf = aggInitExprsUpTo(cal, c, i) or hc = hashCons(e) and i = 0 and @@ -766,14 +774,7 @@ private predicate mk_ClassAggregateLiteral(Class c, HC_Fields hcf, ClassAggregat analyzableClassAggregateLiteral(cal) and c = cal.getUnspecifiedType() and ( - exists(HC_Fields tail, Expr e, Field f, int numChildren, HashCons eCons | - f.getInitializationOrder() = cal.getNumChild() - 1 and - e = cal.getFieldExpr(f).getFullyConverted() and - eCons = hashCons(e) and - numChildren = cal.getNumChild() and - hcf = HC_FieldCons(c, numChildren - 1, f, eCons, tail) and - mk_FieldCons(c, numChildren - 1, f, eCons, tail, cal) - ) + hcf = aggInitExprsUpTo(cal, c, cal.getNumChild()) or cal.getNumChild() = 0 and hcf = HC_EmptyFields(c) @@ -785,15 +786,23 @@ private predicate analyzableArrayAggregateLiteral(ArrayAggregateLiteral aal) { strictcount(aal.getUnspecifiedType()) = 1 } +/** + * Gets the hash cons of array elements in [0..i), where i > 0, for + * the array aggregate literal `aal` of type `t`. + */ +private HC_Array arrayElemsUpTo(ArrayAggregateLiteral aal, Type t, int i) { + exists(HC_Array tail, HashCons head | + result = HC_ArrayCons(t, i - 1, head, tail) and + mk_ArrayCons(t, i - 1, head, tail, aal) + ) +} + private predicate mk_ArrayCons(Type t, int i, HashCons hc, HC_Array hca, ArrayAggregateLiteral aal) { analyzableArrayAggregateLiteral(aal) and t = aal.getUnspecifiedType() and hc = hashCons(aal.getChild(i)) and ( - exists(HC_Array tail, HashCons head | - hca = HC_ArrayCons(t, i - 1, head, tail) and - mk_ArrayCons(t, i - 1, head, tail, aal) - ) + hca = arrayElemsUpTo(aal, t, i) or i = 0 and hca = HC_EmptyArray(t) From 81110dca0a357770a3b992b2972338bc33bc9db3 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 20 Sep 2019 10:32:26 +0100 Subject: [PATCH 0168/1227] C#: Add new test for switch statements. --- .../controlflow/graph/BasicBlock.expected | 5 ++ .../controlflow/graph/Condition.expected | 2 + .../controlflow/graph/Dominance.expected | 54 +++++++++++++++++++ .../graph/EnclosingCallable.expected | 27 ++++++++++ .../controlflow/graph/EntryElement.expected | 30 +++++++++++ .../controlflow/graph/ExitElement.expected | 50 +++++++++++++++++ .../controlflow/graph/NodeGraph.expected | 21 ++++++++ .../controlflow/graph/Nodes.expected | 2 + .../library-tests/controlflow/graph/Switch.cs | 20 +++++++ 9 files changed, 211 insertions(+) diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index baac84950ea..d0f9ee7f2ea 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -555,6 +555,11 @@ | Switch.cs:131:40:131:40 | access to local variable s | Switch.cs:131:40:131:40 | access to local variable s | 1 | | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:131:48:131:51 | null | 3 | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:56:131:66 | call to method ToString | 1 | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:134:9:134:11 | exit M13 | 9 | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:148:18:148:18 | 1 | 6 | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | exit M14 | 1 | +| Switch.cs:148:28:148:28 | 1 | Switch.cs:148:21:148:29 | return ...; | 2 | +| Switch.cs:149:13:149:20 | default: | Switch.cs:149:22:149:31 | return ...; | 4 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:7:13:7:22 | ... is ... | 14 | | TypeAccesses.cs:7:25:7:25 | ; | TypeAccesses.cs:7:25:7:25 | ; | 1 | | TypeAccesses.cs:8:9:8:28 | ... ...; | TypeAccesses.cs:3:10:3:10 | exit M | 4 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected index bda0851440e..9641f753a47 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected @@ -603,6 +603,8 @@ conditionBlock | Switch.cs:129:12:129:14 | enter M12 | Switch.cs:131:43:131:51 | ... => ... | false | | Switch.cs:129:12:129:14 | enter M12 | Switch.cs:131:56:131:66 | call to method ToString | true | | Switch.cs:131:40:131:40 | access to local variable s | Switch.cs:131:56:131:66 | call to method ToString | false | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:148:28:148:28 | 1 | true | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:149:13:149:20 | default: | false | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:7:25:7:25 | ; | true | | VarDecls.cs:19:7:19:8 | enter M3 | VarDecls.cs:25:24:25:24 | access to local variable x | true | | VarDecls.cs:19:7:19:8 | enter M3 | VarDecls.cs:25:28:25:28 | access to local variable y | false | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index b510a7df2f4..c2ee4e899c8 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -2249,6 +2249,25 @@ dominance | Switch.cs:131:40:131:40 | access to local variable s | Switch.cs:131:56:131:66 | call to method ToString | | Switch.cs:131:43:131:43 | _ | Switch.cs:131:48:131:51 | null | | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:131:43:131:43 | _ | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:135:5:142:5 | {...} | +| Switch.cs:135:5:142:5 | {...} | Switch.cs:136:9:141:9 | switch (...) {...} | +| Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:136:17:136:17 | access to parameter i | +| Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:138:13:138:20 | default: | +| Switch.cs:138:13:138:20 | default: | Switch.cs:138:30:138:30 | 1 | +| Switch.cs:138:22:138:31 | return ...; | Switch.cs:134:9:134:11 | exit M13 | +| Switch.cs:138:29:138:30 | -... | Switch.cs:138:22:138:31 | return ...; | +| Switch.cs:138:30:138:30 | 1 | Switch.cs:138:29:138:30 | -... | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:145:5:152:5 | {...} | +| Switch.cs:145:5:152:5 | {...} | Switch.cs:146:9:151:9 | switch (...) {...} | +| Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:146:17:146:17 | access to parameter i | +| Switch.cs:146:17:146:17 | access to parameter i | Switch.cs:148:13:148:19 | case ...: | +| Switch.cs:148:13:148:19 | case ...: | Switch.cs:148:18:148:18 | 1 | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:148:28:148:28 | 1 | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:149:13:149:20 | default: | +| Switch.cs:148:28:148:28 | 1 | Switch.cs:148:21:148:29 | return ...; | +| Switch.cs:149:13:149:20 | default: | Switch.cs:149:30:149:30 | 1 | +| Switch.cs:149:29:149:30 | -... | Switch.cs:149:22:149:31 | return ...; | +| Switch.cs:149:30:149:30 | 1 | Switch.cs:149:29:149:30 | -... | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:4:5:9:5 | {...} | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:5:9:5:26 | ... ...; | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:5:25:5:25 | access to parameter o | @@ -5092,6 +5111,25 @@ postDominance | Switch.cs:131:28:131:40 | ... => ... | Switch.cs:131:17:131:17 | access to parameter o | | Switch.cs:131:43:131:43 | _ | Switch.cs:131:43:131:51 | ... => ... | | Switch.cs:131:48:131:51 | null | Switch.cs:131:43:131:43 | _ | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:138:22:138:31 | return ...; | +| Switch.cs:135:5:142:5 | {...} | Switch.cs:134:9:134:11 | enter M13 | +| Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:135:5:142:5 | {...} | +| Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:136:9:141:9 | switch (...) {...} | +| Switch.cs:138:13:138:20 | default: | Switch.cs:136:17:136:17 | access to parameter i | +| Switch.cs:138:22:138:31 | return ...; | Switch.cs:138:29:138:30 | -... | +| Switch.cs:138:29:138:30 | -... | Switch.cs:138:30:138:30 | 1 | +| Switch.cs:138:30:138:30 | 1 | Switch.cs:138:13:138:20 | default: | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:148:21:148:29 | return ...; | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:149:22:149:31 | return ...; | +| Switch.cs:145:5:152:5 | {...} | Switch.cs:144:9:144:11 | enter M14 | +| Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:145:5:152:5 | {...} | +| Switch.cs:146:17:146:17 | access to parameter i | Switch.cs:146:9:151:9 | switch (...) {...} | +| Switch.cs:148:13:148:19 | case ...: | Switch.cs:146:17:146:17 | access to parameter i | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:148:13:148:19 | case ...: | +| Switch.cs:148:21:148:29 | return ...; | Switch.cs:148:28:148:28 | 1 | +| Switch.cs:149:22:149:31 | return ...; | Switch.cs:149:29:149:30 | -... | +| Switch.cs:149:29:149:30 | -... | Switch.cs:149:30:149:30 | 1 | +| Switch.cs:149:30:149:30 | 1 | Switch.cs:149:13:149:20 | default: | | TypeAccesses.cs:3:10:3:10 | exit M | TypeAccesses.cs:8:13:8:27 | Type t = ... | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:3:10:3:10 | enter M | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:4:5:9:5 | {...} | @@ -7350,6 +7388,14 @@ blockDominance | Switch.cs:131:40:131:40 | access to local variable s | Switch.cs:131:56:131:66 | call to method ToString | | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:131:43:131:51 | ... => ... | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:56:131:66 | call to method ToString | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:134:9:134:11 | enter M13 | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:144:9:144:11 | enter M14 | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:144:9:144:11 | exit M14 | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:148:28:148:28 | 1 | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:149:13:149:20 | default: | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | exit M14 | +| Switch.cs:148:28:148:28 | 1 | Switch.cs:148:28:148:28 | 1 | +| Switch.cs:149:13:149:20 | default: | Switch.cs:149:13:149:20 | default: | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | enter M | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:7:25:7:25 | ; | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:8:9:8:28 | ... ...; | @@ -9031,6 +9077,14 @@ postBlockDominance | Switch.cs:131:40:131:40 | access to local variable s | Switch.cs:131:40:131:40 | access to local variable s | | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:131:43:131:51 | ... => ... | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:56:131:66 | call to method ToString | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:134:9:134:11 | enter M13 | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:144:9:144:11 | enter M14 | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | enter M14 | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | exit M14 | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:148:28:148:28 | 1 | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:149:13:149:20 | default: | +| Switch.cs:148:28:148:28 | 1 | Switch.cs:148:28:148:28 | 1 | +| Switch.cs:149:13:149:20 | default: | Switch.cs:149:13:149:20 | default: | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | enter M | | TypeAccesses.cs:7:25:7:25 | ; | TypeAccesses.cs:7:25:7:25 | ; | | TypeAccesses.cs:8:9:8:28 | ... ...; | TypeAccesses.cs:3:10:3:10 | enter M | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index 824f5fc2f3b..4a740712076 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -2432,6 +2432,28 @@ nodeEnclosing | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:129:12:129:14 | M12 | | Switch.cs:131:48:131:51 | null | Switch.cs:129:12:129:14 | M12 | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:129:12:129:14 | M12 | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:135:5:142:5 | {...} | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:138:13:138:20 | default: | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:138:22:138:31 | return ...; | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:138:29:138:30 | -... | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:138:30:138:30 | 1 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:145:5:152:5 | {...} | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:146:17:146:17 | access to parameter i | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:148:13:148:19 | case ...: | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:148:21:148:29 | return ...; | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:148:28:148:28 | 1 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:149:13:149:20 | default: | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:149:22:149:31 | return ...; | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:149:29:149:30 | -... | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:149:30:149:30 | 1 | Switch.cs:144:9:144:11 | M14 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:3:10:3:10 | exit M | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:3:10:3:10 | M | @@ -3698,6 +3720,11 @@ blockEnclosing | Switch.cs:131:40:131:40 | access to local variable s | Switch.cs:129:12:129:14 | M12 | | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:129:12:129:14 | M12 | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:129:12:129:14 | M12 | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:148:28:148:28 | 1 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:149:13:149:20 | default: | Switch.cs:144:9:144:11 | M14 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:7:25:7:25 | ; | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:8:9:8:28 | ... ...; | TypeAccesses.cs:3:10:3:10 | M | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index 9aac94b8388..29ef1c6475b 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -1756,6 +1756,36 @@ | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:131:43:131:51 | ... => ... | | Switch.cs:131:48:131:51 | null | Switch.cs:131:48:131:51 | null | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:17:131:53 | ... switch { ... } | +| Switch.cs:135:5:142:5 | {...} | Switch.cs:135:5:142:5 | {...} | +| Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:136:9:141:9 | switch (...) {...} | +| Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:136:17:136:17 | access to parameter i | +| Switch.cs:138:13:138:20 | default: | Switch.cs:138:13:138:20 | default: | +| Switch.cs:138:22:138:31 | return ...; | Switch.cs:138:30:138:30 | 1 | +| Switch.cs:138:29:138:30 | -... | Switch.cs:138:30:138:30 | 1 | +| Switch.cs:138:30:138:30 | 1 | Switch.cs:138:30:138:30 | 1 | +| Switch.cs:139:13:139:19 | case ...: | Switch.cs:139:13:139:19 | case ...: | +| Switch.cs:139:18:139:18 | 1 | Switch.cs:139:18:139:18 | 1 | +| Switch.cs:139:21:139:29 | return ...; | Switch.cs:139:28:139:28 | 1 | +| Switch.cs:139:28:139:28 | 1 | Switch.cs:139:28:139:28 | 1 | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:13:140:19 | case ...: | +| Switch.cs:140:18:140:18 | 2 | Switch.cs:140:18:140:18 | 2 | +| Switch.cs:140:21:140:29 | return ...; | Switch.cs:140:28:140:28 | 2 | +| Switch.cs:140:28:140:28 | 2 | Switch.cs:140:28:140:28 | 2 | +| Switch.cs:145:5:152:5 | {...} | Switch.cs:145:5:152:5 | {...} | +| Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:146:9:151:9 | switch (...) {...} | +| Switch.cs:146:17:146:17 | access to parameter i | Switch.cs:146:17:146:17 | access to parameter i | +| Switch.cs:148:13:148:19 | case ...: | Switch.cs:148:13:148:19 | case ...: | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:148:18:148:18 | 1 | +| Switch.cs:148:21:148:29 | return ...; | Switch.cs:148:28:148:28 | 1 | +| Switch.cs:148:28:148:28 | 1 | Switch.cs:148:28:148:28 | 1 | +| Switch.cs:149:13:149:20 | default: | Switch.cs:149:13:149:20 | default: | +| Switch.cs:149:22:149:31 | return ...; | Switch.cs:149:30:149:30 | 1 | +| Switch.cs:149:29:149:30 | -... | Switch.cs:149:30:149:30 | 1 | +| Switch.cs:149:30:149:30 | 1 | Switch.cs:149:30:149:30 | 1 | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:13:150:19 | case ...: | +| Switch.cs:150:18:150:18 | 2 | Switch.cs:150:18:150:18 | 2 | +| Switch.cs:150:21:150:29 | return ...; | Switch.cs:150:28:150:28 | 2 | +| Switch.cs:150:28:150:28 | 2 | Switch.cs:150:28:150:28 | 2 | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:4:5:9:5 | {...} | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:5:9:5:26 | ... ...; | | TypeAccesses.cs:5:13:5:25 | String s = ... | TypeAccesses.cs:5:25:5:25 | access to parameter o | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index f868113cd51..e0fb985f1b6 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -2433,6 +2433,56 @@ | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:40:131:40 | access to local variable s | null | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:48:131:51 | null | null | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:56:131:66 | call to method ToString | normal | +| Switch.cs:135:5:142:5 | {...} | Switch.cs:138:22:138:31 | return ...; | return | +| Switch.cs:135:5:142:5 | {...} | Switch.cs:139:21:139:29 | return ...; | return | +| Switch.cs:135:5:142:5 | {...} | Switch.cs:140:18:140:18 | 2 | no-match | +| Switch.cs:135:5:142:5 | {...} | Switch.cs:140:21:140:29 | return ...; | return | +| Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:138:22:138:31 | return ...; | return | +| Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:139:21:139:29 | return ...; | return | +| Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:140:18:140:18 | 2 | no-match | +| Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:140:21:140:29 | return ...; | return | +| Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:136:17:136:17 | access to parameter i | normal | +| Switch.cs:138:13:138:20 | default: | Switch.cs:138:22:138:31 | return ...; | return | +| Switch.cs:138:22:138:31 | return ...; | Switch.cs:138:22:138:31 | return ...; | return | +| Switch.cs:138:29:138:30 | -... | Switch.cs:138:29:138:30 | -... | normal | +| Switch.cs:138:30:138:30 | 1 | Switch.cs:138:30:138:30 | 1 | normal | +| Switch.cs:139:13:139:19 | case ...: | Switch.cs:139:18:139:18 | 1 | no-match | +| Switch.cs:139:13:139:19 | case ...: | Switch.cs:139:21:139:29 | return ...; | return | +| Switch.cs:139:18:139:18 | 1 | Switch.cs:139:18:139:18 | 1 | match | +| Switch.cs:139:18:139:18 | 1 | Switch.cs:139:18:139:18 | 1 | no-match | +| Switch.cs:139:21:139:29 | return ...; | Switch.cs:139:21:139:29 | return ...; | return | +| Switch.cs:139:28:139:28 | 1 | Switch.cs:139:28:139:28 | 1 | normal | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:18:140:18 | 2 | no-match | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:21:140:29 | return ...; | return | +| Switch.cs:140:18:140:18 | 2 | Switch.cs:140:18:140:18 | 2 | match | +| Switch.cs:140:18:140:18 | 2 | Switch.cs:140:18:140:18 | 2 | no-match | +| Switch.cs:140:21:140:29 | return ...; | Switch.cs:140:21:140:29 | return ...; | return | +| Switch.cs:140:28:140:28 | 2 | Switch.cs:140:28:140:28 | 2 | normal | +| Switch.cs:145:5:152:5 | {...} | Switch.cs:148:21:148:29 | return ...; | return | +| Switch.cs:145:5:152:5 | {...} | Switch.cs:149:22:149:31 | return ...; | return | +| Switch.cs:145:5:152:5 | {...} | Switch.cs:150:18:150:18 | 2 | no-match | +| Switch.cs:145:5:152:5 | {...} | Switch.cs:150:21:150:29 | return ...; | return | +| Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:148:21:148:29 | return ...; | return | +| Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:149:22:149:31 | return ...; | return | +| Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:150:18:150:18 | 2 | no-match | +| Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:150:21:150:29 | return ...; | return | +| Switch.cs:146:17:146:17 | access to parameter i | Switch.cs:146:17:146:17 | access to parameter i | normal | +| Switch.cs:148:13:148:19 | case ...: | Switch.cs:148:18:148:18 | 1 | no-match | +| Switch.cs:148:13:148:19 | case ...: | Switch.cs:148:21:148:29 | return ...; | return | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:148:18:148:18 | 1 | match | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:148:18:148:18 | 1 | no-match | +| Switch.cs:148:21:148:29 | return ...; | Switch.cs:148:21:148:29 | return ...; | return | +| Switch.cs:148:28:148:28 | 1 | Switch.cs:148:28:148:28 | 1 | normal | +| Switch.cs:149:13:149:20 | default: | Switch.cs:149:22:149:31 | return ...; | return | +| Switch.cs:149:22:149:31 | return ...; | Switch.cs:149:22:149:31 | return ...; | return | +| Switch.cs:149:29:149:30 | -... | Switch.cs:149:29:149:30 | -... | normal | +| Switch.cs:149:30:149:30 | 1 | Switch.cs:149:30:149:30 | 1 | normal | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:18:150:18 | 2 | no-match | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:21:150:29 | return ...; | return | +| Switch.cs:150:18:150:18 | 2 | Switch.cs:150:18:150:18 | 2 | match | +| Switch.cs:150:18:150:18 | 2 | Switch.cs:150:18:150:18 | 2 | no-match | +| Switch.cs:150:21:150:29 | return ...; | Switch.cs:150:21:150:29 | return ...; | return | +| Switch.cs:150:28:150:28 | 2 | Switch.cs:150:28:150:28 | 2 | normal | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:8:13:8:27 | Type t = ... | normal | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:5:13:5:25 | String s = ... | normal | | TypeAccesses.cs:5:13:5:25 | String s = ... | TypeAccesses.cs:5:13:5:25 | String s = ... | normal | diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index 168cfe358fe..d45b359ad67 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -2536,6 +2536,27 @@ | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:131:43:131:43 | _ | semmle.label | successor | | Switch.cs:131:48:131:51 | null | Switch.cs:131:9:131:67 | return ...; | semmle.label | null | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:9:131:67 | return ...; | semmle.label | successor | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:135:5:142:5 | {...} | semmle.label | successor | +| Switch.cs:135:5:142:5 | {...} | Switch.cs:136:9:141:9 | switch (...) {...} | semmle.label | successor | +| Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:136:17:136:17 | access to parameter i | semmle.label | successor | +| Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:138:13:138:20 | default: | semmle.label | successor | +| Switch.cs:138:13:138:20 | default: | Switch.cs:138:30:138:30 | 1 | semmle.label | successor | +| Switch.cs:138:22:138:31 | return ...; | Switch.cs:134:9:134:11 | exit M13 | semmle.label | return | +| Switch.cs:138:29:138:30 | -... | Switch.cs:138:22:138:31 | return ...; | semmle.label | successor | +| Switch.cs:138:30:138:30 | 1 | Switch.cs:138:29:138:30 | -... | semmle.label | successor | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:145:5:152:5 | {...} | semmle.label | successor | +| Switch.cs:145:5:152:5 | {...} | Switch.cs:146:9:151:9 | switch (...) {...} | semmle.label | successor | +| Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:146:17:146:17 | access to parameter i | semmle.label | successor | +| Switch.cs:146:17:146:17 | access to parameter i | Switch.cs:148:13:148:19 | case ...: | semmle.label | successor | +| Switch.cs:148:13:148:19 | case ...: | Switch.cs:148:18:148:18 | 1 | semmle.label | successor | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:148:28:148:28 | 1 | semmle.label | match | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:149:13:149:20 | default: | semmle.label | no-match | +| Switch.cs:148:21:148:29 | return ...; | Switch.cs:144:9:144:11 | exit M14 | semmle.label | return | +| Switch.cs:148:28:148:28 | 1 | Switch.cs:148:21:148:29 | return ...; | semmle.label | successor | +| Switch.cs:149:13:149:20 | default: | Switch.cs:149:30:149:30 | 1 | semmle.label | successor | +| Switch.cs:149:22:149:31 | return ...; | Switch.cs:144:9:144:11 | exit M14 | semmle.label | return | +| Switch.cs:149:29:149:30 | -... | Switch.cs:149:22:149:31 | return ...; | semmle.label | successor | +| Switch.cs:149:30:149:30 | 1 | Switch.cs:149:29:149:30 | -... | semmle.label | successor | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:4:5:9:5 | {...} | semmle.label | successor | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:5:9:5:26 | ... ...; | semmle.label | successor | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:5:25:5:25 | access to parameter o | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected index 2816bccb0fb..0a7201f1280 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected @@ -754,6 +754,8 @@ entryPoint | Switch.cs:113:9:113:11 | M10 | Switch.cs:114:5:121:5 | {...} | | Switch.cs:123:10:123:12 | M11 | Switch.cs:124:5:127:5 | {...} | | Switch.cs:129:12:129:14 | M12 | Switch.cs:130:5:132:5 | {...} | +| Switch.cs:134:9:134:11 | M13 | Switch.cs:135:5:142:5 | {...} | +| Switch.cs:144:9:144:11 | M14 | Switch.cs:145:5:152:5 | {...} | | TypeAccesses.cs:3:10:3:10 | M | TypeAccesses.cs:4:5:9:5 | {...} | | VarDecls.cs:5:18:5:19 | M1 | VarDecls.cs:6:5:11:5 | {...} | | VarDecls.cs:13:12:13:13 | M2 | VarDecls.cs:14:5:17:5 | {...} | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Switch.cs b/csharp/ql/test/library-tests/controlflow/graph/Switch.cs index 258afb5a123..6b670908224 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Switch.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/Switch.cs @@ -130,4 +130,24 @@ class Switch { return (o switch { string s => s, _ => null })?.ToString(); } + + int M13(int i) + { + switch (i) + { + default: return -1; + case 1: return 1; + case 2: return 2; + } + } + + int M14(int i) + { + switch (i) + { + case 1: return 1; + default: return -1; + case 2: return 2; + } + } } From d696235668046b764c231c88b1b2ead2f4091d48 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 20 Sep 2019 11:07:04 +0100 Subject: [PATCH 0169/1227] C#: Updated CFG for switch statements - note that the last() predicate is incorrect. --- csharp/ql/src/semmle/code/csharp/Stmt.qll | 11 +++- .../controlflow/graph/BasicBlock.expected | 9 ++- .../controlflow/graph/Condition.expected | 10 +++ .../controlflow/graph/Dominance.expected | 62 +++++++++++++++++-- .../graph/EnclosingCallable.expected | 19 ++++++ .../controlflow/graph/NodeGraph.expected | 21 ++++++- 6 files changed, 123 insertions(+), 9 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index dc8587a5bb8..6dd438bff40 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -215,9 +215,16 @@ private module SwithStmtInternal { cached CaseStmt getCase(SwitchStmt ss, int i) { exists(int index, int rankIndex | - result = ss.getChildStmt(index) and + caseIndex(ss, result, index) and rankIndex = i + 1 and - index = rank[rankIndex](int j, CaseStmt cs | cs = ss.getChildStmt(j) | j) + index = rank[rankIndex](int j, CaseStmt cs | caseIndex(ss, cs, j) | j) + ) + } + + /** Implicitly reorder case statements to put the default case last if needed. */ + private predicate caseIndex(SwitchStmt ss, CaseStmt case, int index) { + exists(int i | case = ss.getChildStmt(i) | + if case instanceof DefaultCase then index = 1000000 else index = i ) } diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index d0f9ee7f2ea..f0a19c633d7 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -555,11 +555,18 @@ | Switch.cs:131:40:131:40 | access to local variable s | Switch.cs:131:40:131:40 | access to local variable s | 1 | | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:131:48:131:51 | null | 3 | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:56:131:66 | call to method ToString | 1 | -| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:134:9:134:11 | exit M13 | 9 | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:139:18:139:18 | 1 | 6 | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:134:9:134:11 | exit M13 | 1 | +| Switch.cs:138:13:138:20 | default: | Switch.cs:138:22:138:31 | return ...; | 4 | +| Switch.cs:139:28:139:28 | 1 | Switch.cs:139:21:139:29 | return ...; | 2 | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:18:140:18 | 2 | 2 | +| Switch.cs:140:28:140:28 | 2 | Switch.cs:140:21:140:29 | return ...; | 2 | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:148:18:148:18 | 1 | 6 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | exit M14 | 1 | | Switch.cs:148:28:148:28 | 1 | Switch.cs:148:21:148:29 | return ...; | 2 | | Switch.cs:149:13:149:20 | default: | Switch.cs:149:22:149:31 | return ...; | 4 | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:18:150:18 | 2 | 2 | +| Switch.cs:150:28:150:28 | 2 | Switch.cs:150:21:150:29 | return ...; | 2 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:7:13:7:22 | ... is ... | 14 | | TypeAccesses.cs:7:25:7:25 | ; | TypeAccesses.cs:7:25:7:25 | ; | 1 | | TypeAccesses.cs:8:9:8:28 | ... ...; | TypeAccesses.cs:3:10:3:10 | exit M | 4 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected index 9641f753a47..4937b513ac9 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected @@ -603,8 +603,18 @@ conditionBlock | Switch.cs:129:12:129:14 | enter M12 | Switch.cs:131:43:131:51 | ... => ... | false | | Switch.cs:129:12:129:14 | enter M12 | Switch.cs:131:56:131:66 | call to method ToString | true | | Switch.cs:131:40:131:40 | access to local variable s | Switch.cs:131:56:131:66 | call to method ToString | false | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:138:13:138:20 | default: | false | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:139:28:139:28 | 1 | true | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:140:13:140:19 | case ...: | false | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:140:28:140:28 | 2 | false | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:138:13:138:20 | default: | false | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:28:140:28 | 2 | true | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:148:28:148:28 | 1 | true | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:149:13:149:20 | default: | false | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:150:13:150:19 | case ...: | false | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:150:28:150:28 | 2 | false | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:149:13:149:20 | default: | false | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:28:150:28 | 2 | true | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:7:25:7:25 | ; | true | | VarDecls.cs:19:7:19:8 | enter M3 | VarDecls.cs:25:24:25:24 | access to local variable x | true | | VarDecls.cs:19:7:19:8 | enter M3 | VarDecls.cs:25:28:25:28 | access to local variable y | false | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index c2ee4e899c8..a34522f0325 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -2252,22 +2252,33 @@ dominance | Switch.cs:134:9:134:11 | enter M13 | Switch.cs:135:5:142:5 | {...} | | Switch.cs:135:5:142:5 | {...} | Switch.cs:136:9:141:9 | switch (...) {...} | | Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:136:17:136:17 | access to parameter i | -| Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:138:13:138:20 | default: | +| Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:139:13:139:19 | case ...: | | Switch.cs:138:13:138:20 | default: | Switch.cs:138:30:138:30 | 1 | -| Switch.cs:138:22:138:31 | return ...; | Switch.cs:134:9:134:11 | exit M13 | | Switch.cs:138:29:138:30 | -... | Switch.cs:138:22:138:31 | return ...; | | Switch.cs:138:30:138:30 | 1 | Switch.cs:138:29:138:30 | -... | +| Switch.cs:139:13:139:19 | case ...: | Switch.cs:139:18:139:18 | 1 | +| Switch.cs:139:18:139:18 | 1 | Switch.cs:139:28:139:28 | 1 | +| Switch.cs:139:18:139:18 | 1 | Switch.cs:140:13:140:19 | case ...: | +| Switch.cs:139:28:139:28 | 1 | Switch.cs:139:21:139:29 | return ...; | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:18:140:18 | 2 | +| Switch.cs:140:18:140:18 | 2 | Switch.cs:138:13:138:20 | default: | +| Switch.cs:140:18:140:18 | 2 | Switch.cs:140:28:140:28 | 2 | +| Switch.cs:140:28:140:28 | 2 | Switch.cs:140:21:140:29 | return ...; | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:145:5:152:5 | {...} | | Switch.cs:145:5:152:5 | {...} | Switch.cs:146:9:151:9 | switch (...) {...} | | Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:146:17:146:17 | access to parameter i | | Switch.cs:146:17:146:17 | access to parameter i | Switch.cs:148:13:148:19 | case ...: | | Switch.cs:148:13:148:19 | case ...: | Switch.cs:148:18:148:18 | 1 | | Switch.cs:148:18:148:18 | 1 | Switch.cs:148:28:148:28 | 1 | -| Switch.cs:148:18:148:18 | 1 | Switch.cs:149:13:149:20 | default: | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:150:13:150:19 | case ...: | | Switch.cs:148:28:148:28 | 1 | Switch.cs:148:21:148:29 | return ...; | | Switch.cs:149:13:149:20 | default: | Switch.cs:149:30:149:30 | 1 | | Switch.cs:149:29:149:30 | -... | Switch.cs:149:22:149:31 | return ...; | | Switch.cs:149:30:149:30 | 1 | Switch.cs:149:29:149:30 | -... | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:18:150:18 | 2 | +| Switch.cs:150:18:150:18 | 2 | Switch.cs:149:13:149:20 | default: | +| Switch.cs:150:18:150:18 | 2 | Switch.cs:150:28:150:28 | 2 | +| Switch.cs:150:28:150:28 | 2 | Switch.cs:150:21:150:29 | return ...; | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:4:5:9:5 | {...} | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:5:9:5:26 | ... ...; | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:5:25:5:25 | access to parameter o | @@ -5112,15 +5123,24 @@ postDominance | Switch.cs:131:43:131:43 | _ | Switch.cs:131:43:131:51 | ... => ... | | Switch.cs:131:48:131:51 | null | Switch.cs:131:43:131:43 | _ | | Switch.cs:134:9:134:11 | exit M13 | Switch.cs:138:22:138:31 | return ...; | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:139:21:139:29 | return ...; | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:140:18:140:18 | 2 | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:140:21:140:29 | return ...; | | Switch.cs:135:5:142:5 | {...} | Switch.cs:134:9:134:11 | enter M13 | | Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:135:5:142:5 | {...} | | Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:136:9:141:9 | switch (...) {...} | -| Switch.cs:138:13:138:20 | default: | Switch.cs:136:17:136:17 | access to parameter i | | Switch.cs:138:22:138:31 | return ...; | Switch.cs:138:29:138:30 | -... | | Switch.cs:138:29:138:30 | -... | Switch.cs:138:30:138:30 | 1 | | Switch.cs:138:30:138:30 | 1 | Switch.cs:138:13:138:20 | default: | +| Switch.cs:139:13:139:19 | case ...: | Switch.cs:136:17:136:17 | access to parameter i | +| Switch.cs:139:18:139:18 | 1 | Switch.cs:139:13:139:19 | case ...: | +| Switch.cs:139:21:139:29 | return ...; | Switch.cs:139:28:139:28 | 1 | +| Switch.cs:140:18:140:18 | 2 | Switch.cs:140:13:140:19 | case ...: | +| Switch.cs:140:21:140:29 | return ...; | Switch.cs:140:28:140:28 | 2 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:148:21:148:29 | return ...; | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:149:22:149:31 | return ...; | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:150:18:150:18 | 2 | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:150:21:150:29 | return ...; | | Switch.cs:145:5:152:5 | {...} | Switch.cs:144:9:144:11 | enter M14 | | Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:145:5:152:5 | {...} | | Switch.cs:146:17:146:17 | access to parameter i | Switch.cs:146:9:151:9 | switch (...) {...} | @@ -5130,6 +5150,8 @@ postDominance | Switch.cs:149:22:149:31 | return ...; | Switch.cs:149:29:149:30 | -... | | Switch.cs:149:29:149:30 | -... | Switch.cs:149:30:149:30 | 1 | | Switch.cs:149:30:149:30 | 1 | Switch.cs:149:13:149:20 | default: | +| Switch.cs:150:18:150:18 | 2 | Switch.cs:150:13:150:19 | case ...: | +| Switch.cs:150:21:150:29 | return ...; | Switch.cs:150:28:150:28 | 2 | | TypeAccesses.cs:3:10:3:10 | exit M | TypeAccesses.cs:8:13:8:27 | Type t = ... | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:3:10:3:10 | enter M | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:4:5:9:5 | {...} | @@ -7389,13 +7411,31 @@ blockDominance | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:131:43:131:51 | ... => ... | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:56:131:66 | call to method ToString | | Switch.cs:134:9:134:11 | enter M13 | Switch.cs:134:9:134:11 | enter M13 | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:134:9:134:11 | exit M13 | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:138:13:138:20 | default: | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:139:28:139:28 | 1 | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:140:13:140:19 | case ...: | +| Switch.cs:134:9:134:11 | enter M13 | Switch.cs:140:28:140:28 | 2 | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:134:9:134:11 | exit M13 | +| Switch.cs:138:13:138:20 | default: | Switch.cs:138:13:138:20 | default: | +| Switch.cs:139:28:139:28 | 1 | Switch.cs:139:28:139:28 | 1 | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:138:13:138:20 | default: | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:13:140:19 | case ...: | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:28:140:28 | 2 | +| Switch.cs:140:28:140:28 | 2 | Switch.cs:140:28:140:28 | 2 | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:144:9:144:11 | enter M14 | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:144:9:144:11 | exit M14 | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:148:28:148:28 | 1 | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:149:13:149:20 | default: | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:150:13:150:19 | case ...: | +| Switch.cs:144:9:144:11 | enter M14 | Switch.cs:150:28:150:28 | 2 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | exit M14 | | Switch.cs:148:28:148:28 | 1 | Switch.cs:148:28:148:28 | 1 | | Switch.cs:149:13:149:20 | default: | Switch.cs:149:13:149:20 | default: | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:149:13:149:20 | default: | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:13:150:19 | case ...: | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:28:150:28 | 2 | +| Switch.cs:150:28:150:28 | 2 | Switch.cs:150:28:150:28 | 2 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | enter M | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:7:25:7:25 | ; | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:8:9:8:28 | ... ...; | @@ -9078,13 +9118,27 @@ postBlockDominance | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:131:43:131:51 | ... => ... | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:56:131:66 | call to method ToString | | Switch.cs:134:9:134:11 | enter M13 | Switch.cs:134:9:134:11 | enter M13 | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:134:9:134:11 | enter M13 | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:134:9:134:11 | exit M13 | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:138:13:138:20 | default: | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:139:28:139:28 | 1 | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:140:13:140:19 | case ...: | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:140:28:140:28 | 2 | +| Switch.cs:138:13:138:20 | default: | Switch.cs:138:13:138:20 | default: | +| Switch.cs:139:28:139:28 | 1 | Switch.cs:139:28:139:28 | 1 | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:13:140:19 | case ...: | +| Switch.cs:140:28:140:28 | 2 | Switch.cs:140:28:140:28 | 2 | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:144:9:144:11 | enter M14 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | enter M14 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | exit M14 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:148:28:148:28 | 1 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:149:13:149:20 | default: | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:150:13:150:19 | case ...: | +| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:150:28:150:28 | 2 | | Switch.cs:148:28:148:28 | 1 | Switch.cs:148:28:148:28 | 1 | | Switch.cs:149:13:149:20 | default: | Switch.cs:149:13:149:20 | default: | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:13:150:19 | case ...: | +| Switch.cs:150:28:150:28 | 2 | Switch.cs:150:28:150:28 | 2 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | enter M | | TypeAccesses.cs:7:25:7:25 | ; | TypeAccesses.cs:7:25:7:25 | ; | | TypeAccesses.cs:8:9:8:28 | ... ...; | TypeAccesses.cs:3:10:3:10 | enter M | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index 4a740712076..d6c78dda8ae 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -2441,6 +2441,14 @@ nodeEnclosing | Switch.cs:138:22:138:31 | return ...; | Switch.cs:134:9:134:11 | M13 | | Switch.cs:138:29:138:30 | -... | Switch.cs:134:9:134:11 | M13 | | Switch.cs:138:30:138:30 | 1 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:139:13:139:19 | case ...: | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:139:18:139:18 | 1 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:139:21:139:29 | return ...; | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:139:28:139:28 | 1 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:140:18:140:18 | 2 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:140:21:140:29 | return ...; | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:140:28:140:28 | 2 | Switch.cs:134:9:134:11 | M13 | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:144:9:144:11 | M14 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | M14 | | Switch.cs:145:5:152:5 | {...} | Switch.cs:144:9:144:11 | M14 | @@ -2454,6 +2462,10 @@ nodeEnclosing | Switch.cs:149:22:149:31 | return ...; | Switch.cs:144:9:144:11 | M14 | | Switch.cs:149:29:149:30 | -... | Switch.cs:144:9:144:11 | M14 | | Switch.cs:149:30:149:30 | 1 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:150:18:150:18 | 2 | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:150:21:150:29 | return ...; | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:150:28:150:28 | 2 | Switch.cs:144:9:144:11 | M14 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:3:10:3:10 | exit M | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:3:10:3:10 | M | @@ -3721,10 +3733,17 @@ blockEnclosing | Switch.cs:131:43:131:51 | ... => ... | Switch.cs:129:12:129:14 | M12 | | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:129:12:129:14 | M12 | | Switch.cs:134:9:134:11 | enter M13 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:138:13:138:20 | default: | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:139:28:139:28 | 1 | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:134:9:134:11 | M13 | +| Switch.cs:140:28:140:28 | 2 | Switch.cs:134:9:134:11 | M13 | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:144:9:144:11 | M14 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:144:9:144:11 | M14 | | Switch.cs:148:28:148:28 | 1 | Switch.cs:144:9:144:11 | M14 | | Switch.cs:149:13:149:20 | default: | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:144:9:144:11 | M14 | +| Switch.cs:150:28:150:28 | 2 | Switch.cs:144:9:144:11 | M14 | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:7:25:7:25 | ; | TypeAccesses.cs:3:10:3:10 | M | | TypeAccesses.cs:8:9:8:28 | ... ...; | TypeAccesses.cs:3:10:3:10 | M | diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index d45b359ad67..e65017c4412 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -2539,24 +2539,41 @@ | Switch.cs:134:9:134:11 | enter M13 | Switch.cs:135:5:142:5 | {...} | semmle.label | successor | | Switch.cs:135:5:142:5 | {...} | Switch.cs:136:9:141:9 | switch (...) {...} | semmle.label | successor | | Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:136:17:136:17 | access to parameter i | semmle.label | successor | -| Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:138:13:138:20 | default: | semmle.label | successor | +| Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:139:13:139:19 | case ...: | semmle.label | successor | | Switch.cs:138:13:138:20 | default: | Switch.cs:138:30:138:30 | 1 | semmle.label | successor | | Switch.cs:138:22:138:31 | return ...; | Switch.cs:134:9:134:11 | exit M13 | semmle.label | return | | Switch.cs:138:29:138:30 | -... | Switch.cs:138:22:138:31 | return ...; | semmle.label | successor | | Switch.cs:138:30:138:30 | 1 | Switch.cs:138:29:138:30 | -... | semmle.label | successor | +| Switch.cs:139:13:139:19 | case ...: | Switch.cs:139:18:139:18 | 1 | semmle.label | successor | +| Switch.cs:139:18:139:18 | 1 | Switch.cs:139:28:139:28 | 1 | semmle.label | match | +| Switch.cs:139:18:139:18 | 1 | Switch.cs:140:13:140:19 | case ...: | semmle.label | no-match | +| Switch.cs:139:21:139:29 | return ...; | Switch.cs:134:9:134:11 | exit M13 | semmle.label | return | +| Switch.cs:139:28:139:28 | 1 | Switch.cs:139:21:139:29 | return ...; | semmle.label | successor | +| Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:18:140:18 | 2 | semmle.label | successor | +| Switch.cs:140:18:140:18 | 2 | Switch.cs:134:9:134:11 | exit M13 | semmle.label | no-match | +| Switch.cs:140:18:140:18 | 2 | Switch.cs:138:13:138:20 | default: | semmle.label | no-match | +| Switch.cs:140:18:140:18 | 2 | Switch.cs:140:28:140:28 | 2 | semmle.label | match | +| Switch.cs:140:21:140:29 | return ...; | Switch.cs:134:9:134:11 | exit M13 | semmle.label | return | +| Switch.cs:140:28:140:28 | 2 | Switch.cs:140:21:140:29 | return ...; | semmle.label | successor | | Switch.cs:144:9:144:11 | enter M14 | Switch.cs:145:5:152:5 | {...} | semmle.label | successor | | Switch.cs:145:5:152:5 | {...} | Switch.cs:146:9:151:9 | switch (...) {...} | semmle.label | successor | | Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:146:17:146:17 | access to parameter i | semmle.label | successor | | Switch.cs:146:17:146:17 | access to parameter i | Switch.cs:148:13:148:19 | case ...: | semmle.label | successor | | Switch.cs:148:13:148:19 | case ...: | Switch.cs:148:18:148:18 | 1 | semmle.label | successor | | Switch.cs:148:18:148:18 | 1 | Switch.cs:148:28:148:28 | 1 | semmle.label | match | -| Switch.cs:148:18:148:18 | 1 | Switch.cs:149:13:149:20 | default: | semmle.label | no-match | +| Switch.cs:148:18:148:18 | 1 | Switch.cs:150:13:150:19 | case ...: | semmle.label | no-match | | Switch.cs:148:21:148:29 | return ...; | Switch.cs:144:9:144:11 | exit M14 | semmle.label | return | | Switch.cs:148:28:148:28 | 1 | Switch.cs:148:21:148:29 | return ...; | semmle.label | successor | | Switch.cs:149:13:149:20 | default: | Switch.cs:149:30:149:30 | 1 | semmle.label | successor | | Switch.cs:149:22:149:31 | return ...; | Switch.cs:144:9:144:11 | exit M14 | semmle.label | return | | Switch.cs:149:29:149:30 | -... | Switch.cs:149:22:149:31 | return ...; | semmle.label | successor | | Switch.cs:149:30:149:30 | 1 | Switch.cs:149:29:149:30 | -... | semmle.label | successor | +| Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:18:150:18 | 2 | semmle.label | successor | +| Switch.cs:150:18:150:18 | 2 | Switch.cs:144:9:144:11 | exit M14 | semmle.label | no-match | +| Switch.cs:150:18:150:18 | 2 | Switch.cs:149:13:149:20 | default: | semmle.label | no-match | +| Switch.cs:150:18:150:18 | 2 | Switch.cs:150:28:150:28 | 2 | semmle.label | match | +| Switch.cs:150:21:150:29 | return ...; | Switch.cs:144:9:144:11 | exit M14 | semmle.label | return | +| Switch.cs:150:28:150:28 | 2 | Switch.cs:150:21:150:29 | return ...; | semmle.label | successor | | TypeAccesses.cs:3:10:3:10 | enter M | TypeAccesses.cs:4:5:9:5 | {...} | semmle.label | successor | | TypeAccesses.cs:4:5:9:5 | {...} | TypeAccesses.cs:5:9:5:26 | ... ...; | semmle.label | successor | | TypeAccesses.cs:5:9:5:26 | ... ...; | TypeAccesses.cs:5:25:5:25 | access to parameter o | semmle.label | successor | From fdc8abce4d5d96a072b95207ae8852de454c7528 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 20 Sep 2019 14:11:42 +0100 Subject: [PATCH 0170/1227] C#: Fix CFG by removing unnecessary edge. --- .../semmle/code/csharp/controlflow/ControlFlowGraph.qll | 6 ------ .../library-tests/controlflow/graph/Consistency.expected | 1 + .../ql/test/library-tests/controlflow/graph/Consistency.ql | 7 +++++++ .../library-tests/controlflow/graph/Dominance.expected | 2 -- .../library-tests/controlflow/graph/ExitElement.expected | 4 ---- .../library-tests/controlflow/graph/NodeGraph.expected | 2 -- 6 files changed, 8 insertions(+), 14 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index c3fca2bbef4..3afce0b1994 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -947,12 +947,6 @@ module ControlFlow { result = cs.getCondition() and c = specificBoolean(false) ) - or - // Last statement exits with any non-break completion - exists(int last | last = max(int i | exists(ss.getStmt(i))) | - result = ss.getStmt(last) and - c = TRec(TLastRecNonBreakCompletion()) - ) ) or cfe = any(SwitchExpr se | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected b/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected index b15e0193c1b..bccab8e85a4 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected @@ -4,3 +4,4 @@ breakInvariant2 breakInvariant3 breakInvariant4 breakInvariant5 +multipleSuccessors diff --git a/csharp/ql/test/library-tests/controlflow/graph/Consistency.ql b/csharp/ql/test/library-tests/controlflow/graph/Consistency.ql index f9b78f5e8b8..983ecebc6c6 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Consistency.ql +++ b/csharp/ql/test/library-tests/controlflow/graph/Consistency.ql @@ -94,3 +94,10 @@ query predicate breakInvariant5( not (split.hasSuccessor(pred, succ, c) and split = predSplits.getASplit()) and not (split.hasEntry(pred, succ, c) and not split = predSplits.getASplit()) } + +query predicate multipleSuccessors( + ControlFlow::Node node, SuccessorType t, ControlFlow::Node successor +) { + strictcount(node.getASuccessorByType(t)) > 1 and + successor = node.getASuccessorByType(t) +} diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index a34522f0325..5db89e6d2ca 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -5124,7 +5124,6 @@ postDominance | Switch.cs:131:48:131:51 | null | Switch.cs:131:43:131:43 | _ | | Switch.cs:134:9:134:11 | exit M13 | Switch.cs:138:22:138:31 | return ...; | | Switch.cs:134:9:134:11 | exit M13 | Switch.cs:139:21:139:29 | return ...; | -| Switch.cs:134:9:134:11 | exit M13 | Switch.cs:140:18:140:18 | 2 | | Switch.cs:134:9:134:11 | exit M13 | Switch.cs:140:21:140:29 | return ...; | | Switch.cs:135:5:142:5 | {...} | Switch.cs:134:9:134:11 | enter M13 | | Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:135:5:142:5 | {...} | @@ -5139,7 +5138,6 @@ postDominance | Switch.cs:140:21:140:29 | return ...; | Switch.cs:140:28:140:28 | 2 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:148:21:148:29 | return ...; | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:149:22:149:31 | return ...; | -| Switch.cs:144:9:144:11 | exit M14 | Switch.cs:150:18:150:18 | 2 | | Switch.cs:144:9:144:11 | exit M14 | Switch.cs:150:21:150:29 | return ...; | | Switch.cs:145:5:152:5 | {...} | Switch.cs:144:9:144:11 | enter M14 | | Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:145:5:152:5 | {...} | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index e0fb985f1b6..622637f5c9d 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -2435,11 +2435,9 @@ | Switch.cs:131:56:131:66 | call to method ToString | Switch.cs:131:56:131:66 | call to method ToString | normal | | Switch.cs:135:5:142:5 | {...} | Switch.cs:138:22:138:31 | return ...; | return | | Switch.cs:135:5:142:5 | {...} | Switch.cs:139:21:139:29 | return ...; | return | -| Switch.cs:135:5:142:5 | {...} | Switch.cs:140:18:140:18 | 2 | no-match | | Switch.cs:135:5:142:5 | {...} | Switch.cs:140:21:140:29 | return ...; | return | | Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:138:22:138:31 | return ...; | return | | Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:139:21:139:29 | return ...; | return | -| Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:140:18:140:18 | 2 | no-match | | Switch.cs:136:9:141:9 | switch (...) {...} | Switch.cs:140:21:140:29 | return ...; | return | | Switch.cs:136:17:136:17 | access to parameter i | Switch.cs:136:17:136:17 | access to parameter i | normal | | Switch.cs:138:13:138:20 | default: | Switch.cs:138:22:138:31 | return ...; | return | @@ -2460,11 +2458,9 @@ | Switch.cs:140:28:140:28 | 2 | Switch.cs:140:28:140:28 | 2 | normal | | Switch.cs:145:5:152:5 | {...} | Switch.cs:148:21:148:29 | return ...; | return | | Switch.cs:145:5:152:5 | {...} | Switch.cs:149:22:149:31 | return ...; | return | -| Switch.cs:145:5:152:5 | {...} | Switch.cs:150:18:150:18 | 2 | no-match | | Switch.cs:145:5:152:5 | {...} | Switch.cs:150:21:150:29 | return ...; | return | | Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:148:21:148:29 | return ...; | return | | Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:149:22:149:31 | return ...; | return | -| Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:150:18:150:18 | 2 | no-match | | Switch.cs:146:9:151:9 | switch (...) {...} | Switch.cs:150:21:150:29 | return ...; | return | | Switch.cs:146:17:146:17 | access to parameter i | Switch.cs:146:17:146:17 | access to parameter i | normal | | Switch.cs:148:13:148:19 | case ...: | Switch.cs:148:18:148:18 | 1 | no-match | diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index e65017c4412..4756e86100b 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -2550,7 +2550,6 @@ | Switch.cs:139:21:139:29 | return ...; | Switch.cs:134:9:134:11 | exit M13 | semmle.label | return | | Switch.cs:139:28:139:28 | 1 | Switch.cs:139:21:139:29 | return ...; | semmle.label | successor | | Switch.cs:140:13:140:19 | case ...: | Switch.cs:140:18:140:18 | 2 | semmle.label | successor | -| Switch.cs:140:18:140:18 | 2 | Switch.cs:134:9:134:11 | exit M13 | semmle.label | no-match | | Switch.cs:140:18:140:18 | 2 | Switch.cs:138:13:138:20 | default: | semmle.label | no-match | | Switch.cs:140:18:140:18 | 2 | Switch.cs:140:28:140:28 | 2 | semmle.label | match | | Switch.cs:140:21:140:29 | return ...; | Switch.cs:134:9:134:11 | exit M13 | semmle.label | return | @@ -2569,7 +2568,6 @@ | Switch.cs:149:29:149:30 | -... | Switch.cs:149:22:149:31 | return ...; | semmle.label | successor | | Switch.cs:149:30:149:30 | 1 | Switch.cs:149:29:149:30 | -... | semmle.label | successor | | Switch.cs:150:13:150:19 | case ...: | Switch.cs:150:18:150:18 | 2 | semmle.label | successor | -| Switch.cs:150:18:150:18 | 2 | Switch.cs:144:9:144:11 | exit M14 | semmle.label | no-match | | Switch.cs:150:18:150:18 | 2 | Switch.cs:149:13:149:20 | default: | semmle.label | no-match | | Switch.cs:150:18:150:18 | 2 | Switch.cs:150:28:150:28 | 2 | semmle.label | match | | Switch.cs:150:21:150:29 | return ...; | Switch.cs:144:9:144:11 | exit M14 | semmle.label | return | From 56bc8cb035252a5dafc3d57c802a905a1086fecd Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Fri, 20 Sep 2019 14:23:47 +0100 Subject: [PATCH 0171/1227] QL etudes: Add river crossing puzzle WIP --- .../learn-ql/ql-etudes/river-crossing-1.ql | 98 +++++++ .../learn-ql/ql-etudes/river-crossing.ql | 114 ++++++++ .../learn-ql/ql-etudes/river-crossing.rst | 243 ++++++++++++++++++ 3 files changed, 455 insertions(+) create mode 100644 docs/language/learn-ql/ql-etudes/river-crossing-1.ql create mode 100644 docs/language/learn-ql/ql-etudes/river-crossing.ql create mode 100644 docs/language/learn-ql/ql-etudes/river-crossing.rst diff --git a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql new file mode 100644 index 00000000000..58b923306cd --- /dev/null +++ b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql @@ -0,0 +1,98 @@ +/** + * @name River crossing puzzle (version 1) + * @description An "elementary" version of the solution to + * the river crossing problem. + * + * Note: Parts of this QL file are included in the corresponding .rst file. + * Make sure to update the line numbers if you change anything here! + */ + +/** A possible cargo item. */ +class Cargo extends string { + Cargo() { + this = "Nothing" or + this = "Goat" or + this = "Cabbage" or + this = "Wolf" + } +} + +/** One of two shores. */ +class Shore extends string { + Shore() { this = "Left" or this = "Right" } + + /** Returns "the other shore". */ + Shore flip() { + this = "Left" and result = "Right" + or + this = "Right" and result = "Left" + } +} + +/** A record of where everything is. */ +class State extends string { + Shore man; + + Shore goat; + + Shore cabbage; + + Shore wolf; + + State() { this = man + "," + goat + "," + cabbage + "," + wolf } + + State ferry(Cargo cargo) { + cargo = "Nothing" and result = man.flip() + "," + goat + "," + cabbage + "," + wolf + or + cargo = "Goat" and result = man.flip() + "," + goat.flip() + "," + cabbage + "," + wolf + or + cargo = "Cabbage" and result = man.flip() + "," + goat + "," + cabbage.flip() + "," + wolf + or + cargo = "Wolf" and result = man.flip() + "," + goat + "," + cabbage + "," + wolf.flip() + } + + /** + * Holds if predator and prey are on the same shore and the man + * is on the other shore. + */ + predicate eats(Shore predator, Shore prey) { predator = prey and man = predator.flip() } + + /** Holds if nothing gets eaten in this state. */ + predicate isSafe() { not (eats(goat, cabbage) or eats(wolf, goat)) } + + /** Returns the state that is reached after safely ferrying a cargo item. */ + State safeFerry(Cargo cargo) { result = this.ferry(cargo) and result.isSafe() } + + /** + * Returns all states that are reachable via safe ferrying. + * `path` keeps track of how it is achieved and `steps` keeps track of the number of steps it takes. + */ + State reachesVia(string path, int steps) { + // Trivial case: a state is always reachable from itself + steps = 0 and this = result and path = "" + or + // A state is reachable using pathSoFar and then safely ferrying cargo. + exists(int stepsSoFar, string pathSoFar, Cargo cargo | + result = this.reachesVia(pathSoFar, stepsSoFar).safeFerry(cargo) and + steps = stepsSoFar + 1 and + // We expect a solution in 7 steps, but you can choose any value here. + steps <= 7 and + path = pathSoFar + "\n Ferry " + cargo + ) + } +} + +/** The initial state, where everything is on the left shore. */ +class InitialState extends State { + InitialState() { this = "Left" + "," + "Left" + "," + "Left" + "," + "Left" } +} + +/** The goal state, where everything is on the right shore. */ +class GoalState extends State { + GoalState() { this = "Right" + "," + "Right" + "," + "Right" + "," + "Right" } +} + +from string path +where any(InitialState is).reachesVia(path, _) = any(GoalState gs) +select path + diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.ql b/docs/language/learn-ql/ql-etudes/river-crossing.ql new file mode 100644 index 00000000000..d7687602ad2 --- /dev/null +++ b/docs/language/learn-ql/ql-etudes/river-crossing.ql @@ -0,0 +1,114 @@ +/** + * @name River crossing puzzle + * @description This implements the classical puzzle where a man is trying to + * ferry a goat, a cabbage, and a wolf across a river. + * His boat can only take himself and at most one item as cargo. + * His problem is that if the goat is left alone with the cabbage, + * it will eat it. + * And if the wolf is left alone with the goat, it will eat it. + * How does he get everything across the river? + * + * Note: Parts of this QL file are included in the corresponding .rst file. + * Make sure to update the line numbers if you change anything here! + */ + +/** A possible cargo item. */ +class Cargo extends string { + Cargo() { + this = "Nothing" or + this = "Goat" or + this = "Cabbage" or + this = "Wolf" + } +} + +/** One of two shores. */ +class Shore extends string { + Shore() { + this = "Left" or + this = "Right" + } + + /** Returns "the other shore". */ + Shore flip() { + this = "Left" and result = "Right" + or + this = "Right" and result = "Left" + } +} + +/** Renders the state as a string. */ +string renderState(Shore man, Shore goat, Shore cabbage, Shore wolf) { + result = man + "," + goat + "," + cabbage + "," + wolf +} + +/** A record of where everything is. */ +class State extends string { + Shore man; + + Shore goat; + + Shore cabbage; + + Shore wolf; + + State() { this = renderState(man, goat, cabbage, wolf) } + + /** Returns the state that is reached after ferrying a particular cargo item. */ + State ferry(Cargo cargo) { + cargo = "Nothing" and result = renderState(man.flip(), goat, cabbage, wolf) + or + cargo = "Goat" and result = renderState(man.flip(), goat.flip(), cabbage, wolf) + or + cargo = "Cabbage" and result = renderState(man.flip(), goat, cabbage.flip(), wolf) + or + cargo = "Wolf" and result = renderState(man.flip(), goat, cabbage, wolf.flip()) + } + + /** + * Holds if predator and prey are on the same shore and the man + * is on the other shore. + */ + predicate eats(Shore predator, Shore prey) { predator = prey and man = predator.flip() } + + /** Holds if nothing gets eaten in this state. */ + predicate isSafe() { not (eats(goat, cabbage) or eats(wolf, goat)) } + + /** Returns the state that is reached after safely ferrying a cargo item. */ + State safeFerry(Cargo cargo) { result = this.ferry(cargo) and result.isSafe() } + + /** + * Returns all states that are reachable via safe ferrying. + * `path` keeps track of how it is achieved. + * `visitedStates` keeps track of previously visited states and is used to avoid loops. + */ + State reachesVia(string path, string visitedStates) { + // Trivial case: a state is always reachable from itself. + this = result and + visitedStates = "" and + path = "" + or + // A state is reachable using pathSoFar and then safely ferrying cargo. + exists(string pathSoFar, string visitedStatesSoFar, Cargo cargo | + result = this.reachesVia(pathSoFar, visitedStatesSoFar).safeFerry(cargo) and + // The resulting state has not yet been visited. + not exists(int i | i = visitedStatesSoFar.indexOf(result)) and + visitedStates = visitedStatesSoFar + "/" + result and + path = pathSoFar + "\n Ferry " + cargo + ) + } +} + +/** The initial state, where everything is on the left shore. */ +class InitialState extends State { + InitialState() { this = renderState("Left", "Left", "Left", "Left") } +} + +/** The goal state, where everything is on the right shore. */ +class GoalState extends State { + GoalState() { this = renderState("Right", "Right", "Right", "Right") } +} + +from string path +where any(InitialState is).reachesVia(path, _) = any(GoalState gs) +select path diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.rst b/docs/language/learn-ql/ql-etudes/river-crossing.rst new file mode 100644 index 00000000000..5c7ad8100a7 --- /dev/null +++ b/docs/language/learn-ql/ql-etudes/river-crossing.rst @@ -0,0 +1,243 @@ +River crossing puzzle +##################### + +The aim of this tutorial is to write a QL query that finds a solution to the following classical logic puzzle: + +.. pull-quote:: + + River crossing puzzle + + A man is trying to ferry a goat, a cabbage, and a wolf across a river. + His boat can only take himself and at most one item as cargo. + His problem is that if the goat is left alone with the cabbage, it will eat it. + And if the wolf is left alone with the goat, it will eat it. + How does he get everything across the river? + +A solution should be a set of instructions for how to ferry the items, such as "First ferry the goat +across the river, and come back with nothing. Then ferry the cabbage across, and come back with ..." + +There are lots of ways to approach this problem and implement it in QL. Before you start, make +sure that you are familiar with how to define `classes `__ +and `predicates `__ in QL. +The following walkthrough is just one of many possible implementations, so have a go at writing your +own query too! To find more example queries, see the list :ref:`below `. + +Walkthrough +----------- + +Model the elements of the puzzle +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The basic components of the puzzle are the cargo items and the shores on either side of the river. +Start by modeling these as classes. + +First, define a class ``Cargo`` containing the different cargo items. +Note that the man can also travel on his own, so it helps to explicitly include ``"Nothing"`` as +a piece of cargo. + +.. container:: toggle + + .. container:: name + + *Show/hide code* + + .. literalinclude:: river-crossing.ql + :lines: 15-22 + +Second, any item can be on one of two shores. Let's call these the "left shore" and the "right shore". +Define a class ``Shore`` containing ``"Left"`` and ``"Right"``. + +It would be helpful to express "the other shore". You can do this by defining a member predicate +``flip`` in the class ``Shore`` such that ``"Left".flip()`` returns ``"Right"`` and vice versa. + +.. container:: toggle + + .. container:: name + + *Show/hide code* + + .. literalinclude:: river-crossing.ql + :lines: 25-38 + +We also want a way to keep track of where the man, the goat, the cabbage, and the wolf are—call this combined +information the "state". Define a class ``State`` that encodes this information. +For example, if the man is on the left shore, the goat on the right shore, and the cabbage and wolf on the left +shore, the state should be ``Left, Right, Left, Left``. + +You may find it helpful to introduce some variables that refer to the shore on which the man and the cargo items are. These +temporary variables in the body of a class are called `fields `__. + +.. container:: toggle + + .. container:: name + + *Show/hide code* + + .. literalinclude:: river-crossing-1.ql + :lines: 32-42,83 + +We are interested in two particular states, namely the initial state and the goal state. +Assuming that all items start on the left shore and end up on the right shore, define +``InitialState`` and ``GoalState`` as subclasses of ``State``. + +.. container:: toggle + + .. container:: name + + *Show/hide code* + + .. literalinclude:: river-crossing-1.ql + :lines: 85-93 + +.. pull-quote:: + + Note + + To avoid typing out the lengthy string concatenations, you could introduce a helper predicate + ``renderState`` that renders the state in the required form. + +Using the above note, the QL code so far looks like this: + +.. container:: toggle + + .. container:: name + + *Show/hide code* + + .. literalinclude:: river-crossing.ql + :lines: 14-55,100-110 + +Model the action of "ferrying" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The basic act of ferrying moves the man and a cargo item to the other shore, +resulting in a new state. + +Write a member predicate (of ``State``) called ``ferry``, that specifies what happens to the state +after ferrying a particular cargo. (Hint: Use the predicate ``flip``.) + +.. container:: toggle + + .. container:: name + + *Show/hide code* + + .. literalinclude:: river-crossing.ql + :lines: 57-66 + +Of course, not all ferrying actions are possible. Add some extra conditions to describe when a ferrying +action is "safe", that is, it doesn't lead to a state where the goat or the cabbage get eaten. +For example, follow these steps: + + #. Define a predicate ``eats`` that encodes the conditions for when something gets eaten. + #. Define a predicate ``isSafe`` that holds when nothing gets eaten. + #. Define a predicate ``safeFerry`` that restricts ``ferry`` to only include safe ferrying actions. + +.. container:: toggle + + .. container:: name + + *Show/hide code* + + .. literalinclude:: river-crossing.ql + :lines: 68-78 + +Find paths from one state to another +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The main aim of this query is to find a path, that is, a list of successive ferrying actions, to get +from one state to another. + +When finding the path, you should be careful to avoid "infinite" solutions. For example, the man +could ferry the goat back and forth any number of times without ever reaching an unsafe state. + +One way to restrict to finite solutions is to define a `member predicate `__ +``State reachesVia(string path, int steps)``. +The result of this predicate is any state that is reachable from the current state (``this``) via +the given path in a specified finite number of steps. + +You can write this as a `recursive predicate `__, +with the following base case and recursion step: + + - If ``this`` *is* the result state, then it (trivially) reaches the result state via an + empty path in zero steps. + - Any other state is reachable if ``this`` can reach an intermediate state (for some value of + ``path`` and ``steps``), and there is a ``safeFerry`` action from that intermediate + state to the result state. + +To ensure that the predicate is finite, you should restrict ``steps`` to a particular value, +for example ``steps <= 7``. + +.. container:: toggle + + .. container:: name + + *Show/hide code* + + .. literalinclude:: river-crossing-1.ql + :lines: 66-82 + +However, although this ensures that the solution is finite, it can still contain loops if the upper bound +for ``steps`` is large. + +Instead of picking an arbitrary upper bound for the number of steps, you can avoid +counting steps altogether. If you keep track of states that have already been visited and ensure +that each ferrying action leads to a new state, the solution certainly won't contain any loops. + +To do this, change the member predicate to ``State reachesVia(string path, string visitedStates)``. +The result of this predicate is any state that is reachable from the current state (``this``) via +the given path without revisiting any previously visited states. + + - As before, if ``this`` *is* the result state, then it (trivially) reaches the result state via an + empty path and an empty string of visited states. + - Any other state is reachable if ``this`` can reach an intermediate state via some path, without + revisiting any previous states, and there is a ``safeFerry`` action from the intermediate state to + the result state. + (Hint: To check whether a state has previously been visited, you could check if + there is an `index of `__ + ``visitedStates`` at which the state occurs.) + +.. container:: toggle + + .. container:: name + + *Show/hide code* + + .. literalinclude:: river-crossing.ql + :lines: 80-99 + +Display the results +~~~~~~~~~~~~~~~~~~~ + +Once you've defined all the necessary classes and predicates, write a `select clause `__ +that returns the resulting path. + +.. container:: toggle + + .. container:: name + + *Show/hide code* + + .. literalinclude:: river-crossing.ql + :lines: 112-114 + +For now, the path defined in the above predicate ``reachesVia`` just lists the order of cargo items to ferry. +You could tweak the predicates and the select clause to make the solution clearer. Here are some suggestions: + + - Display more information, such as the direction in which the cargo is ferried, for example + ``"Goat to the left shore"``. + - Fully describe the state at every step, for example ``"Goat: Left, Man: Left, Cabbage: Right, Wolf: Right"``. + - Display the path in a more "visual" way, for example by using arrows to display the transitions between states. + +.. _alternatives: + +Alternative solutions +--------------------- + +Here are some more example QL queries that solve the river crossing puzzle: + + - Solutions described in more detail: https://lgtm.com/query/4550752404102766320/ + - Solutions displayed in a more visual way: https://lgtm.com/query/5824364611285694673/ + +.. TODO: Add more examples + From 8408e90b5f7238316150b5b307f2cdce92e5faca Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 20 Sep 2019 14:32:54 +0100 Subject: [PATCH 0172/1227] C#: Change note & docs. --- change-notes/1.23/analysis-csharp.md | 1 + csharp/ql/src/semmle/code/csharp/Stmt.qll | 1 + 2 files changed, 2 insertions(+) diff --git a/change-notes/1.23/analysis-csharp.md b/change-notes/1.23/analysis-csharp.md index d22f7ea567a..7a44dd303fc 100644 --- a/change-notes/1.23/analysis-csharp.md +++ b/change-notes/1.23/analysis-csharp.md @@ -37,5 +37,6 @@ The following changes in version 1.23 affect C# analysis in all applications. disabled by default and can be enabled for individual configurations by overriding `int explorationLimit()`. * `foreach` statements where the body is guaranteed to be executed at least once, such as `foreach (var x in new string[]{ "a", "b", "c" }) { ... }`, are now recognized by all analyses based on the control flow graph (such as SSA, data flow and taint tracking). +* Fixed the control flow graph for `switch` statements where the `default` case was not the last case. This had caused the remaining cases to be unreachable. `SwitchStmt.getCase(int i)` now puts the `default` case last. ## Changes to autobuilder diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 6dd438bff40..dc11e83f065 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -165,6 +165,7 @@ class SwitchStmt extends SelectionStmt, Switch, @switch_stmt { * return 3; * } * ``` + * Note that this reorders the `default` case to always be at the end. */ override CaseStmt getCase(int i) { result = SwithStmtInternal::getCase(this, i) } From 9a407eb43cba0a8e97ce6778d83f3a83c98a9eb4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 20 Sep 2019 11:07:22 +0100 Subject: [PATCH 0173/1227] CPP: Test format args with mismatching declarations. --- .../TooManyFormatArguments.expected | 6 ++++++ .../WrongNumberOfFormatArguments.expected | 6 ++++++ .../Format/WrongNumberOfFormatArguments/a.c | 18 ++++++++++++++++++ .../Format/WrongNumberOfFormatArguments/b.c | 15 +++++++++++++++ .../Format/WrongNumberOfFormatArguments/c.c | 11 +++++++++++ 5 files changed, 56 insertions(+) create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected index 0d9d84285f1..1da77d08161 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected @@ -1,3 +1,9 @@ +| a.c:14:3:14:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | +| a.c:17:3:17:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 2 | +| b.c:11:3:11:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | +| b.c:14:3:14:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 2 | +| c.c:7:3:7:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | +| c.c:10:3:10:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 2 | | custom_printf.cpp:31:5:31:12 | call to myPrintf | Format expects 2 arguments but given 3 | | macros.cpp:12:2:12:31 | call to printf | Format expects 2 arguments but given 3 | | macros.cpp:16:2:16:30 | call to printf | Format expects 2 arguments but given 3 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected index db4318a4b96..93e0f5d51a0 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected @@ -1,3 +1,9 @@ +| a.c:12:3:12:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | +| a.c:15:3:15:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 0 | +| b.c:9:3:9:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | +| b.c:12:3:12:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 0 | +| c.c:5:3:5:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | +| c.c:8:3:8:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 0 | | custom_printf.cpp:29:5:29:12 | call to myPrintf | Format expects 2 arguments but given 1 | | macros.cpp:14:2:14:37 | call to printf | Format expects 4 arguments but given 3 | | macros.cpp:21:2:21:36 | call to printf | Format expects 4 arguments but given 3 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c new file mode 100644 index 00000000000..9971f8f2aec --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c @@ -0,0 +1,18 @@ + +__attribute__((format(printf, 1, 3))) +void myMultiplyDefinedPrintf(const char *format, int extraArg, ...) +{ + // ... +} +__attribute__((format(printf, 1, 3))) +void myMultiplyDefinedPrintf2(const char *format, int extraArg, ...); + +void test_custom_printf1() +{ + myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments) + myMultiplyDefinedPrintf("%i", 0, 1); // GOOD + myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments) + myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] + myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c new file mode 100644 index 00000000000..f4405c95c99 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c @@ -0,0 +1,15 @@ + +__attribute__((format(printf, 1, 2))) +void myMultiplyDefinedPrintf(const char *format, ...); // this declaration does not match the definition +__attribute__((format(printf, 1, 2))) +void myMultiplyDefinedPrintf2(const char *format, ...); + +void test_custom_printf2() +{ + myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments) + myMultiplyDefinedPrintf("%i", 0, 1); // GOOD + myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments) + myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] + myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] +} \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c new file mode 100644 index 00000000000..15dae5e535f --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c @@ -0,0 +1,11 @@ + +void test_custom_printf2() +{ + // (implicitly defined) + myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments) + myMultiplyDefinedPrintf("%i", 0, 1); // GOOD + myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments) + myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] + myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] +} From f7607313e7366eed95fb117532e294be4ab10ce6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 20 Sep 2019 15:12:55 +0100 Subject: [PATCH 0174/1227] CPP: Fix FPs. --- cpp/ql/src/semmle/code/cpp/commons/Printf.qll | 7 ++++++- .../cpp/models/interfaces/FormattingFunction.qll | 15 ++++++++++++++- .../TooManyFormatArguments.expected | 3 --- .../WrongNumberOfFormatArguments.expected | 3 --- .../Format/WrongNumberOfFormatArguments/a.c | 4 ++-- .../Format/WrongNumberOfFormatArguments/b.c | 4 ++-- .../Format/WrongNumberOfFormatArguments/c.c | 4 ++-- 7 files changed, 26 insertions(+), 14 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll index a7ab7c25b86..61b937bfb38 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll @@ -169,7 +169,12 @@ class FormattingFunctionCall extends Expr { * Gets the number of arguments to this call that are parameters to the * format string. */ - int getNumFormatArgument() { result = count(this.getFormatArgument(_)) } + int getNumFormatArgument() { + result = count(this.getFormatArgument(_)) and + + // format arguments must be known + exists(getTarget().(FormattingFunction).getFirstFormatArgumentIndex()) + } } /** diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll index 56cce6d01b0..35ab2c2d511 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll @@ -115,7 +115,20 @@ abstract class FormattingFunction extends Function { * Gets the position of the first format argument, corresponding with * the first format specifier in the format string. */ - int getFirstFormatArgumentIndex() { result = getNumberOfParameters() } + int getFirstFormatArgumentIndex() { + result = getNumberOfParameters() + and + // the formatting function either has a definition in the snapshot, or all + // `DeclarationEntry`s agree on the number of parameters (otherwise we don't + // really know the correct number) + ( + hasDefinition() or + forall(FunctionDeclarationEntry fde | + fde = getADeclarationEntry() | + result = fde.getNumberOfParameters() + ) + ) + } /** * Gets the position of the buffer size argument, if any. diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected index 1da77d08161..387b1291745 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected @@ -1,9 +1,6 @@ | a.c:14:3:14:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | -| a.c:17:3:17:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 2 | | b.c:11:3:11:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | -| b.c:14:3:14:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 2 | | c.c:7:3:7:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | -| c.c:10:3:10:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 2 | | custom_printf.cpp:31:5:31:12 | call to myPrintf | Format expects 2 arguments but given 3 | | macros.cpp:12:2:12:31 | call to printf | Format expects 2 arguments but given 3 | | macros.cpp:16:2:16:30 | call to printf | Format expects 2 arguments but given 3 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected index 93e0f5d51a0..fd10c8368e7 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected @@ -1,9 +1,6 @@ | a.c:12:3:12:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | -| a.c:15:3:15:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 0 | | b.c:9:3:9:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | -| b.c:12:3:12:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 0 | | c.c:5:3:5:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | -| c.c:8:3:8:26 | call to myMultiplyDefinedPrintf2 | Format expects 1 arguments but given 0 | | custom_printf.cpp:29:5:29:12 | call to myPrintf | Format expects 2 arguments but given 1 | | macros.cpp:14:2:14:37 | call to printf | Format expects 4 arguments but given 3 | | macros.cpp:21:2:21:36 | call to printf | Format expects 4 arguments but given 3 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c index 9971f8f2aec..0ff140a14f7 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c @@ -12,7 +12,7 @@ void test_custom_printf1() myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments) myMultiplyDefinedPrintf("%i", 0, 1); // GOOD myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments) - myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] + myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) - myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] + myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) } diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c index f4405c95c99..d1c44c80219 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c @@ -9,7 +9,7 @@ void test_custom_printf2() myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments) myMultiplyDefinedPrintf("%i", 0, 1); // GOOD myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments) - myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] + myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) - myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] + myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) } \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c index 15dae5e535f..961a4bcc721 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c @@ -5,7 +5,7 @@ void test_custom_printf2() myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments) myMultiplyDefinedPrintf("%i", 0, 1); // GOOD myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments) - myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] + myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) - myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) [FALSE POSITIVE] + myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) } From 648335d46db4349badab1e41382fb1b4c21e8b52 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 20 Sep 2019 16:12:56 +0200 Subject: [PATCH 0175/1227] Java: Remove two unnecessary unbinds. --- .../src/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index d0be8824f98..d0760463efa 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1175,12 +1175,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } From d9aa46d3b0fe4321692cb735c987780bfd553cad Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 20 Sep 2019 16:13:48 +0200 Subject: [PATCH 0176/1227] Java: Add missing field pruning. --- java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index d0760463efa..c7690946dad 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or From accb8246d40dba2f9b5a823585784ba9637bcbac Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 20 Sep 2019 15:15:35 +0100 Subject: [PATCH 0177/1227] CPP: Change note. --- change-notes/1.23/analysis-cpp.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.23/analysis-cpp.md b/change-notes/1.23/analysis-cpp.md index ce317236f93..cc8cde276f3 100644 --- a/change-notes/1.23/analysis-cpp.md +++ b/change-notes/1.23/analysis-cpp.md @@ -18,6 +18,8 @@ The following changes in version 1.23 affect C/C++ analysis in all applications. | Hard-coded Japanese era start date in call (`cpp/japanese-era/constructor-or-method-with-exact-era-date`) | Deprecated | This query has been deprecated. Use the new combined query Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) instead. | | Hard-coded Japanese era start date in struct (`cpp/japanese-era/struct-with-exact-era-date`) | Deprecated | This query has been deprecated. Use the new combined query Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) instead. | | Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | More correct results | This query now checks for the beginning date of the Reiwa era (1st May 2019). | +| Too few arguments to formatting function (`cpp/wrong-number-format-arguments`) | Fewer false positive results | Fixed false positives resulting from mistmatching declarations of a formatting function. | +| Too many arguments to formatting function (`cpp/too-many-format-arguments`) | Fewer false positive results | Fixed false positives resulting from mistmatching declarations of a formatting function. | ## Changes to QL libraries From 42a970b905d150eff45a59363297bc78ff217138 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 20 Sep 2019 16:21:03 +0200 Subject: [PATCH 0178/1227] Java: Update qldoc. --- .../src/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index c7690946dad..6fa04737e33 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1222,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. From 9100ab93608fa809e5caf497a3be594a28557666 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 20 Sep 2019 15:30:59 +0100 Subject: [PATCH 0179/1227] CPP: Autoformat. --- cpp/ql/src/semmle/code/cpp/commons/Printf.qll | 9 ++++----- .../code/cpp/models/interfaces/FormattingFunction.qll | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll index 61b937bfb38..bd179fe27cc 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll @@ -170,11 +170,10 @@ class FormattingFunctionCall extends Expr { * format string. */ int getNumFormatArgument() { - result = count(this.getFormatArgument(_)) and - - // format arguments must be known - exists(getTarget().(FormattingFunction).getFirstFormatArgumentIndex()) - } + result = count(this.getFormatArgument(_)) and + // format arguments must be known + exists(getTarget().(FormattingFunction).getFirstFormatArgumentIndex()) + } } /** diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll index 35ab2c2d511..130c067f70c 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll @@ -116,15 +116,14 @@ abstract class FormattingFunction extends Function { * the first format specifier in the format string. */ int getFirstFormatArgumentIndex() { - result = getNumberOfParameters() - and + result = getNumberOfParameters() and // the formatting function either has a definition in the snapshot, or all // `DeclarationEntry`s agree on the number of parameters (otherwise we don't // really know the correct number) ( - hasDefinition() or - forall(FunctionDeclarationEntry fde | - fde = getADeclarationEntry() | + hasDefinition() + or + forall(FunctionDeclarationEntry fde | fde = getADeclarationEntry() | result = fde.getNumberOfParameters() ) ) From 1ce0a48996ee7b275f7d7816a707ada5e106cb05 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 20 Sep 2019 15:41:36 +0100 Subject: [PATCH 0180/1227] JS: Update tests --- .../library-tests/frameworks/Electron/BrowserObject.expected | 2 ++ .../test/library-tests/frameworks/Electron/WebContents.expected | 2 ++ .../Security/CWE-020/IncompleteHostnameRegExp.expected | 1 + .../Security/CWE-020/tst-IncompleteHostnameRegExp.js | 2 +- 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/frameworks/Electron/BrowserObject.expected b/javascript/ql/test/library-tests/frameworks/Electron/BrowserObject.expected index fca1b6a91a3..579c5817840 100644 --- a/javascript/ql/test/library-tests/frameworks/Electron/BrowserObject.expected +++ b/javascript/ql/test/library-tests/frameworks/Electron/BrowserObject.expected @@ -6,7 +6,9 @@ | electron.js:4:10:4:46 | new Bro ... s: {}}) | | electron.js:35:14:35:14 | x | | electron.js:36:12:36:12 | x | +| electron.js:39:1:39:7 | foo(bw) | | electron.js:39:5:39:6 | bw | +| electron.js:40:1:40:7 | foo(bv) | | electron.js:40:5:40:6 | bv | | electron.ts:3:12:3:13 | bw | | electron.ts:3:40:3:41 | bv | diff --git a/javascript/ql/test/library-tests/frameworks/Electron/WebContents.expected b/javascript/ql/test/library-tests/frameworks/Electron/WebContents.expected index a55d4a16e4d..4ae6c7e5d95 100644 --- a/javascript/ql/test/library-tests/frameworks/Electron/WebContents.expected +++ b/javascript/ql/test/library-tests/frameworks/Electron/WebContents.expected @@ -1,2 +1,4 @@ +| electron.js:39:1:39:19 | foo(bw).webContents | +| electron.js:40:1:40:19 | foo(bv).webContents | | electron.ts:4:3:4:16 | bw.webContents | | electron.ts:5:3:5:16 | bv.webContents | diff --git a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected index c128823024e..180319c4017 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected +++ b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected @@ -3,6 +3,7 @@ | tst-IncompleteHostnameRegExp.js:6:2:6:43 | /^http: ... b).com/ | This regular expression has an unescaped '.' before '(example-a\|example-b).com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:6:2:6:43 | /^http: ... b).com/ | here | | tst-IncompleteHostnameRegExp.js:11:13:11:38 | "^http: ... le.com" | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:11:13:11:38 | "^http: ... le.com" | here | | tst-IncompleteHostnameRegExp.js:12:10:12:35 | "^http: ... le.com" | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:12:10:12:35 | "^http: ... le.com" | here | +| tst-IncompleteHostnameRegExp.js:15:22:15:47 | "^http: ... le.com" | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:15:13:15:50 | id(id(i ... com"))) | here | | tst-IncompleteHostnameRegExp.js:17:13:17:31 | `test.example.com$` | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:17:13:17:31 | `test.example.com$` | here | | tst-IncompleteHostnameRegExp.js:17:14:17:30 | test.example.com$ | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:17:13:17:31 | `test.example.com$` | here | | tst-IncompleteHostnameRegExp.js:19:17:19:35 | '^test.example.com' | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:20:13:20:26 | `${hostname}$` | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-020/tst-IncompleteHostnameRegExp.js b/javascript/ql/test/query-tests/Security/CWE-020/tst-IncompleteHostnameRegExp.js index 47b85447abc..c86c5ad3d0d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/tst-IncompleteHostnameRegExp.js +++ b/javascript/ql/test/query-tests/Security/CWE-020/tst-IncompleteHostnameRegExp.js @@ -12,7 +12,7 @@ s.match("^http://test.example.com"); // NOT OK function id(e) { return e; } - new RegExp(id(id(id("^http://test.example.com")))); // NOT OK, but not supported by type tracking + new RegExp(id(id(id("^http://test.example.com")))); // NOT OK new RegExp(`test.example.com$`); // NOT OK From 69a88c4fcd640bfac4914159d9231003011b1c41 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 20 Sep 2019 15:43:08 +0100 Subject: [PATCH 0181/1227] JS: Fix typo and add metadata to DomValueRefs --- .../ql/src/meta/analysis-quality/DomValueRefs.ql | 14 ++++++++++++++ .../ql/src/meta/analysis-quality/DomValuesRefs.ql | 4 ---- 2 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 javascript/ql/src/meta/analysis-quality/DomValueRefs.ql delete mode 100644 javascript/ql/src/meta/analysis-quality/DomValuesRefs.ql diff --git a/javascript/ql/src/meta/analysis-quality/DomValueRefs.ql b/javascript/ql/src/meta/analysis-quality/DomValueRefs.ql new file mode 100644 index 00000000000..b61091d38f0 --- /dev/null +++ b/javascript/ql/src/meta/analysis-quality/DomValueRefs.ql @@ -0,0 +1,14 @@ +/** + * @name DOM value references + * @description The number of references to a DOM value. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id js/meta/dom-value-refs + */ + +import javascript +import CallGraphQuality + +select projectRoot(), count(DOM::domValueRef()) diff --git a/javascript/ql/src/meta/analysis-quality/DomValuesRefs.ql b/javascript/ql/src/meta/analysis-quality/DomValuesRefs.ql deleted file mode 100644 index 1ec0b3f82b2..00000000000 --- a/javascript/ql/src/meta/analysis-quality/DomValuesRefs.ql +++ /dev/null @@ -1,4 +0,0 @@ -import javascript -import CallGraphQuality - -select projectRoot(), count(DOM::domValueRef()) From 814c5537be9d406ecd969478d49afa056e331984 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 20 Sep 2019 22:56:08 +0200 Subject: [PATCH 0182/1227] update name of loop bound injection in change-notes --- change-notes/1.23/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md index 851e444adb2..7fb1226c007 100644 --- a/change-notes/1.23/analysis-javascript.md +++ b/change-notes/1.23/analysis-javascript.md @@ -14,7 +14,7 @@ | **Query** | **Tags** | **Purpose** | |---------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Unused index variable (`js/unused-index-variable`) | correctness | Highlights loops that iterate over an array, but do not use the index variable to access array elements, indicating a possible typo or logic error. Results are shown on LGTM by default. | -| Tainted .length in loop condition (`js/loop-bound-injection`) | security, external/cwe/cwe-834 | Highlights loops where a user-controlled object with an arbitrary .length value can trick the server to loop indefinitely. Results are not shown on LGTM by default. | +| Loop bound injection (`js/loop-bound-injection`) | security, external/cwe/cwe-834 | Highlights loops where a user-controlled object with an arbitrary .length value can trick the server to loop indefinitely. Results are not shown on LGTM by default. | ## Changes to existing queries From e4d17a9b0449cf437e4c95d1b4028fa91fa0f2f4 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 18 Sep 2019 16:41:31 +0200 Subject: [PATCH 0183/1227] C#: Refactor `getAnOutNode()` predicate --- csharp/ql/src/semmle/code/csharp/Caching.qll | 2 +- .../dataflow/internal/DataFlowDispatch.qll | 48 +++---------- .../dataflow/internal/DataFlowPrivate.qll | 68 +++++++++++++++---- .../dataflow/global/GetAnOutNode.expected | 6 -- 4 files changed, 66 insertions(+), 58 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Caching.qll b/csharp/ql/src/semmle/code/csharp/Caching.qll index ec239e93f41..2ee25bf065d 100644 --- a/csharp/ql/src/semmle/code/csharp/Caching.qll +++ b/csharp/ql/src/semmle/code/csharp/Caching.qll @@ -72,7 +72,7 @@ module Stages { or exists(any(DataFlow::Node n).toString()) or - exists(any(OutNode n).getCall()) + exists(any(OutNode n).getCall(_)) or exists(CallContext cc) or diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index cd94661301b..77dfc82a3a6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -187,49 +187,16 @@ private module Cached { ) } } - - /** - * Gets a node that can read the value returned from `call` with return kind - * `kind`. - */ - cached - OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { - // normal `return` - result = call.getNode() and - kind instanceof NormalReturnKind and - not call.getExpr().getType() instanceof VoidType - or - // `yield return` - result = call.getNode() and - kind instanceof YieldReturnKind and - call.getExpr().getType() instanceof YieldReturnType - or - // `out`/`ref` parameter - exists(Parameter p, AssignableDefinitions::OutRefDefinition def | - p.getSourceDeclaration().getPosition() = kind.(OutRefReturnKind).getPosition() - | - def = result.(SsaDefinitionNode).getDefinition().(Ssa::ExplicitDefinition).getADefinition() and - def.getTargetAccess() = call.getExpr().(Call).getArgumentForParameter(p) - ) - or - // implicit captured variable return - exists(Ssa::ExplicitDefinition def, Ssa::ImplicitCallDefinition cdef, LocalScopeVariable v | - kind.(ImplicitCapturedReturnKind).getVariable() = v and - def.isCapturedVariableDefinitionFlowOut(cdef, _) and - cdef = result.(SsaDefinitionNode).getDefinition() and - v = def.getSourceVariable().getAssignable() - | - call.getControlFlowNode() = cdef.getControlFlowNode() - or - exists(DataFlowCall outer | call.(ImplicitDelegateDataFlowCall).isArgumentOf(outer, _) | - outer.getControlFlowNode() = cdef.getControlFlowNode() - ) - ) - } } import Cached +/** + * Gets a node that can read the value returned from `call` with return kind + * `kind`. + */ +OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) } + predicate viableCallable = viableImpl/1; /** @@ -394,6 +361,9 @@ class ImplicitDelegateDataFlowCall extends DelegateDataFlowCall, TImplicitDelega /** Gets the number of parameters of the supplied delegate. */ int getNumberOfDelegateParameters() { result = arg.getDelegateType().getNumberOfParameters() } + /** Gets the return type of the supplied delegate. */ + Type getDelegateReturnType() { result = arg.getDelegateType().getReturnType() } + override DotNet::Callable getARuntimeTarget(CallContext::CallContext cc) { result = cfn.getElement().(DelegateArgumentToLibraryCallable).getARuntimeTarget(cc) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 477688191a0..da34fc5f2d3 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -944,17 +944,35 @@ import ReturnNodes /** A data flow node that represents the output of a call. */ abstract class OutNode extends Node { - /** Gets the underlying call. */ + /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ cached - abstract DataFlowCall getCall(); + abstract DataFlowCall getCall(ReturnKind kind); } private module OutNodes { + private import semmle.code.csharp.frameworks.system.Collections + private import semmle.code.csharp.frameworks.system.collections.Generic + private DataFlowCall csharpCall(Expr e, ControlFlow::Node cfn) { e = any(DispatchCall dc | result = TNonDelegateCall(cfn, dc)).getCall() or result = TExplicitDelegateCall(cfn, e) } + /** A valid return type for a method that uses `yield return`. */ + private class YieldReturnType extends Type { + YieldReturnType() { + exists(Type t | t = this.getSourceDeclaration() | + t instanceof SystemCollectionsIEnumerableInterface + or + t instanceof SystemCollectionsIEnumeratorInterface + or + t instanceof SystemCollectionsGenericIEnumerableTInterface + or + t instanceof SystemCollectionsGenericIEnumeratorInterface + ) + } + } + /** * A data flow node that reads a value returned directly by a callable, * either via a C# call or a CIL call. @@ -969,8 +987,16 @@ private module OutNodes { ) } - override DataFlowCall getCall() { - Stages::DataFlowStage::forceCachingInSameStage() and result = call + override DataFlowCall getCall(ReturnKind kind) { + Stages::DataFlowStage::forceCachingInSameStage() and + result = call and + ( + kind instanceof NormalReturnKind and + not call.getExpr().getType() instanceof VoidType + or + kind instanceof YieldReturnKind and + call.getExpr().getType() instanceof YieldReturnType + ) } } @@ -995,7 +1021,13 @@ private module OutNodes { ) } - override DataFlowCall getCall() { result = call } + override DataFlowCall getCall(ReturnKind kind) { + result = call and + kind.(ImplicitCapturedReturnKind).getVariable() = this + .getDefinition() + .getSourceVariable() + .getAssignable() + } } /** @@ -1003,13 +1035,16 @@ private module OutNodes { * `out` or `ref` parameter. */ class ParamOutNode extends OutNode, SsaDefinitionNode { - ParamOutNode() { - this.getDefinition().(Ssa::ExplicitDefinition).getADefinition() instanceof - AssignableDefinitions::OutRefDefinition - } + private AssignableDefinitions::OutRefDefinition outRefDef; - override DataFlowCall getCall() { - result = csharpCall(_, this.getDefinition().getControlFlowNode()) + ParamOutNode() { outRefDef = this.getDefinition().(Ssa::ExplicitDefinition).getADefinition() } + + override DataFlowCall getCall(ReturnKind kind) { + result = csharpCall(_, this.getDefinition().getControlFlowNode()) and + exists(Parameter p | + p.getSourceDeclaration().getPosition() = kind.(OutRefReturnKind).getPosition() and + outRefDef.getTargetAccess() = result.getExpr().(Call).getArgumentForParameter(p) + ) } } @@ -1036,7 +1071,16 @@ private module OutNodes { override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } - override ImplicitDelegateDataFlowCall getCall() { result.getNode() = this } + override ImplicitDelegateDataFlowCall getCall(ReturnKind kind) { + result.getNode() = this and + ( + kind instanceof NormalReturnKind and + not result.getDelegateReturnType() instanceof VoidType + or + kind instanceof YieldReturnKind and + result.getDelegateReturnType() instanceof YieldReturnType + ) + } override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index ad7c1dbb90a..34b473e5659 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -4,7 +4,6 @@ | Capture.cs:33:30:33:39 | [implicit call] access to local variable captureIn3 | return | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 | | Capture.cs:71:9:71:21 | call to local function CaptureOut1 | captured sink30 | Capture.cs:71:9:71:21 | SSA call def(sink30) | | Capture.cs:83:9:83:21 | [transitive] call to local function CaptureOut2 | captured sink31 | Capture.cs:83:9:83:21 | SSA call def(sink31) | -| Capture.cs:83:9:83:21 | call to local function CaptureOut2 | captured sink31 | Capture.cs:83:9:83:21 | SSA call def(sink31) | | Capture.cs:92:9:92:41 | call to method Select | captured sink32 | Capture.cs:92:9:92:41 | SSA call def(sink32) | | Capture.cs:92:9:92:41 | call to method Select | return | Capture.cs:92:9:92:41 | call to method Select | | Capture.cs:92:9:92:41 | call to method Select | yield return | Capture.cs:92:9:92:41 | call to method Select | @@ -12,14 +11,9 @@ | Capture.cs:92:30:92:40 | [implicit call] access to local variable captureOut3 | captured sink32 | Capture.cs:92:9:92:41 | SSA call def(sink32) | | Capture.cs:92:30:92:40 | [implicit call] access to local variable captureOut3 | return | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 | | Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured nonSink0 | Capture.cs:121:9:121:35 | SSA call def(nonSink0) | -| Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured nonSink0 | Capture.cs:121:9:121:35 | SSA call def(nonSink0) | | Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured sink40 | Capture.cs:121:9:121:35 | SSA call def(sink40) | -| Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured sink40 | Capture.cs:121:9:121:35 | SSA call def(sink40) | -| Capture.cs:121:9:121:35 | call to local function CaptureOutMultipleLambdas | captured nonSink0 | Capture.cs:121:9:121:35 | SSA call def(nonSink0) | -| Capture.cs:121:9:121:35 | call to local function CaptureOutMultipleLambdas | captured sink40 | Capture.cs:121:9:121:35 | SSA call def(sink40) | | Capture.cs:132:9:132:25 | call to local function CaptureThrough1 | captured sink33 | Capture.cs:132:9:132:25 | SSA call def(sink33) | | Capture.cs:144:9:144:25 | [transitive] call to local function CaptureThrough2 | captured sink34 | Capture.cs:144:9:144:25 | SSA call def(sink34) | -| Capture.cs:144:9:144:25 | call to local function CaptureThrough2 | captured sink34 | Capture.cs:144:9:144:25 | SSA call def(sink34) | | Capture.cs:153:9:153:45 | call to method Select | captured sink35 | Capture.cs:153:9:153:45 | SSA call def(sink35) | | Capture.cs:153:9:153:45 | call to method Select | return | Capture.cs:153:9:153:45 | call to method Select | | Capture.cs:153:9:153:45 | call to method Select | yield return | Capture.cs:153:9:153:45 | call to method Select | From 149ae5d7abd7fc98c8896cbf4b1e40352d495016 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Sun, 22 Sep 2019 16:04:05 +0100 Subject: [PATCH 0184/1227] JavaScript: Fix IllegalInvocation. This fixes false positives that arise when a call such as `f.apply` can either be interpreted as a reflective invocation of `f`, or a normal call to method `apply` of `f`. --- change-notes/1.23/analysis-javascript.md | 1 + javascript/ql/src/LanguageFeatures/IllegalInvocation.ql | 3 ++- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 7 +++++++ javascript/ql/src/semmle/javascript/dataflow/Nodes.qll | 3 +++ .../query-tests/LanguageFeatures/IllegalInvocation/tst.js | 8 ++++++++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md index ea1dcb58ee9..ae043ade607 100644 --- a/change-notes/1.23/analysis-javascript.md +++ b/change-notes/1.23/analysis-javascript.md @@ -25,6 +25,7 @@ | Client-side cross-site scripting (`js/xss`) | More results | More potential vulnerabilities involving functions that manipulate DOM attributes are now recognized. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving functions that manipulate DOM event handler attributes are now recognized. | | Hard-coded credentials (`js/hardcoded-credentials`) | Fewer false-positive results | This rule now flags fewer password examples. | +| Illegal invocation (`js/illegal-invocation`) | Fewer false-positive results | This rule now correctly handles methods named `call` and `apply`. | | Incorrect suffix check (`js/incorrect-suffix-check`) | Fewer false-positive results | The query recognizes valid checks in more cases. | Network data written to file (`js/http-to-file-access`) | Fewer false-positive results | This query has been renamed to better match its intended purpose, and now only considers network data untrusted. | | Password in configuration file (`js/password-in-configuration-file`) | Fewer false-positive results | This rule now flags fewer password examples. | diff --git a/javascript/ql/src/LanguageFeatures/IllegalInvocation.ql b/javascript/ql/src/LanguageFeatures/IllegalInvocation.ql index 3593666e3ea..f9cf0a458a6 100644 --- a/javascript/ql/src/LanguageFeatures/IllegalInvocation.ql +++ b/javascript/ql/src/LanguageFeatures/IllegalInvocation.ql @@ -58,7 +58,8 @@ where // filter out some easy cases not isCallToFunction(cs) and // conservatively only flag call sites where _all_ callees are illegal - forex(Function otherCallee | otherCallee = cs.getACallee() | + forex(DataFlow::InvokeNode cs2, Function otherCallee | + cs2.getInvokeExpr() = cs.getInvokeExpr() and otherCallee = cs2.getACallee() | illegalInvocation(cs, otherCallee, _, _) ) select cs, "Illegal invocation of $@ " + how + ".", callee, calleeDesc diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index c88ef86eb84..88f42d810c4 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -935,6 +935,9 @@ module DataFlow { * and either with or without `new`. */ abstract class InvokeNodeDef extends DataFlow::Node { + /** Gets the syntactic invoke expression underlying this function invocation. */ + abstract InvokeExpr getInvokeExpr(); + /** Gets the name of the function or method being invoked, if it can be determined. */ abstract string getCalleeName(); @@ -985,6 +988,8 @@ module DataFlow { class ExplicitInvokeNode extends InvokeNodeDef, DataFlow::ValueNode { override InvokeExpr astNode; + override InvokeExpr getInvokeExpr() { result = astNode } + override string getCalleeName() { result = astNode.getCalleeName() } override DataFlow::Node getCalleeNode() { result = DataFlow::valueNode(astNode.getCallee()) } @@ -1046,6 +1051,8 @@ module DataFlow { ReflectiveCallNodeDef() { this = TReflectiveCallNode(originalCall.asExpr(), kind) } + override InvokeExpr getInvokeExpr() { result = originalCall.getInvokeExpr() } + override string getCalleeName() { result = originalCall.getReceiver().asExpr().(PropAccess).getPropertyName() } diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index a2674b46286..1b52e8b20e0 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -34,6 +34,9 @@ class InvokeNode extends DataFlow::SourceNode { InvokeNode() { this = impl } + /** Gets the syntactic invoke expression underlying this function invocation. */ + InvokeExpr getInvokeExpr() { result = impl.getInvokeExpr() } + /** Gets the name of the function or method being invoked, if it can be determined. */ string getCalleeName() { result = impl.getCalleeName() } diff --git a/javascript/ql/test/query-tests/LanguageFeatures/IllegalInvocation/tst.js b/javascript/ql/test/query-tests/LanguageFeatures/IllegalInvocation/tst.js index 9366c3976d2..ecd10bb47ff 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/IllegalInvocation/tst.js +++ b/javascript/ql/test/query-tests/LanguageFeatures/IllegalInvocation/tst.js @@ -45,4 +45,12 @@ new h() // NOT OK C.call(); // NOT OK C.apply(); // NOT OK +class E { + static call() {} + static apply() {} +} + +E.call(); // OK +E.apply(); // OK + //semmle-extractor-options: --experimental From f94b01cb404155523551310e236aecf871705aaa Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Mon, 23 Sep 2019 09:52:43 +0100 Subject: [PATCH 0185/1227] QL etudes: Address comments + fix sphinx warning --- docs/language/learn-ql/index.rst | 1 + .../learn-ql/ql-etudes/river-crossing-1.ql | 21 ++++++++++--------- .../learn-ql/ql-etudes/river-crossing.ql | 18 ++++++++-------- .../learn-ql/ql-etudes/river-crossing.rst | 13 ++++++------ 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/docs/language/learn-ql/index.rst b/docs/language/learn-ql/index.rst index 108dab99683..7b529fb6806 100644 --- a/docs/language/learn-ql/index.rst +++ b/docs/language/learn-ql/index.rst @@ -23,6 +23,7 @@ If you are new to QL, start by looking at the following topics: introduction-to-ql about-ql beginner/ql-tutorials + ql-etudes/river-crossing QL training and variant analysis examples ****************************************** diff --git a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql index 58b923306cd..9ffd820bb1b 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql +++ b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql @@ -1,7 +1,8 @@ /** * @name River crossing puzzle (version 1) * @description An "elementary" version of the solution to - * the river crossing problem. + * the river crossing problem. It introduces more explicit and intuitive + * definitions, before tidying them up in the "full" version. * * Note: Parts of this QL file are included in the corresponding .rst file. * Make sure to update the line numbers if you change anything here! @@ -21,8 +22,8 @@ class Cargo extends string { class Shore extends string { Shore() { this = "Left" or this = "Right" } - /** Returns "the other shore". */ - Shore flip() { + /** Returns the other shore. */ + Shore other() { this = "Left" and result = "Right" or this = "Right" and result = "Left" @@ -42,20 +43,20 @@ class State extends string { State() { this = man + "," + goat + "," + cabbage + "," + wolf } State ferry(Cargo cargo) { - cargo = "Nothing" and result = man.flip() + "," + goat + "," + cabbage + "," + wolf + cargo = "Nothing" and result = man.other() + "," + goat + "," + cabbage + "," + wolf or - cargo = "Goat" and result = man.flip() + "," + goat.flip() + "," + cabbage + "," + wolf + cargo = "Goat" and result = man.other() + "," + goat.other() + "," + cabbage + "," + wolf or - cargo = "Cabbage" and result = man.flip() + "," + goat + "," + cabbage.flip() + "," + wolf + cargo = "Cabbage" and result = man.other() + "," + goat + "," + cabbage.other() + "," + wolf or - cargo = "Wolf" and result = man.flip() + "," + goat + "," + cabbage + "," + wolf.flip() + cargo = "Wolf" and result = man.other() + "," + goat + "," + cabbage + "," + wolf.other() } /** * Holds if predator and prey are on the same shore and the man - * is on the other shore. + * is not present. */ - predicate eats(Shore predator, Shore prey) { predator = prey and man = predator.flip() } + predicate eats(Shore predator, Shore prey) { predator = prey and man = predator.other() } /** Holds if nothing gets eaten in this state. */ predicate isSafe() { not (eats(goat, cabbage) or eats(wolf, goat)) } @@ -93,6 +94,6 @@ class GoalState extends State { } from string path -where any(InitialState is).reachesVia(path, _) = any(GoalState gs) +where any(InitialState i).reachesVia(path, _) = any(GoalState g) select path diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.ql b/docs/language/learn-ql/ql-etudes/river-crossing.ql index d7687602ad2..d6c56309722 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.ql +++ b/docs/language/learn-ql/ql-etudes/river-crossing.ql @@ -29,8 +29,8 @@ class Shore extends string { this = "Right" } - /** Returns "the other shore". */ - Shore flip() { + /** Returns the other shore. */ + Shore other() { this = "Left" and result = "Right" or this = "Right" and result = "Left" @@ -56,20 +56,20 @@ class State extends string { /** Returns the state that is reached after ferrying a particular cargo item. */ State ferry(Cargo cargo) { - cargo = "Nothing" and result = renderState(man.flip(), goat, cabbage, wolf) + cargo = "Nothing" and result = renderState(man.other(), goat, cabbage, wolf) or - cargo = "Goat" and result = renderState(man.flip(), goat.flip(), cabbage, wolf) + cargo = "Goat" and result = renderState(man.other(), goat.other(), cabbage, wolf) or - cargo = "Cabbage" and result = renderState(man.flip(), goat, cabbage.flip(), wolf) + cargo = "Cabbage" and result = renderState(man.other(), goat, cabbage.other(), wolf) or - cargo = "Wolf" and result = renderState(man.flip(), goat, cabbage, wolf.flip()) + cargo = "Wolf" and result = renderState(man.other(), goat, cabbage, wolf.other()) } /** * Holds if predator and prey are on the same shore and the man - * is on the other shore. + * is not present. */ - predicate eats(Shore predator, Shore prey) { predator = prey and man = predator.flip() } + predicate eats(Shore predator, Shore prey) { predator = prey and man = predator.other() } /** Holds if nothing gets eaten in this state. */ predicate isSafe() { not (eats(goat, cabbage) or eats(wolf, goat)) } @@ -110,5 +110,5 @@ class GoalState extends State { } from string path -where any(InitialState is).reachesVia(path, _) = any(GoalState gs) +where any(InitialState i).reachesVia(path, _) = any(GoalState g) select path diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.rst b/docs/language/learn-ql/ql-etudes/river-crossing.rst index 5c7ad8100a7..e5fce99b98e 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.rst +++ b/docs/language/learn-ql/ql-etudes/river-crossing.rst @@ -48,7 +48,7 @@ Second, any item can be on one of two shores. Let's call these the "left shore" Define a class ``Shore`` containing ``"Left"`` and ``"Right"``. It would be helpful to express "the other shore". You can do this by defining a member predicate -``flip`` in the class ``Shore`` such that ``"Left".flip()`` returns ``"Right"`` and vice versa. +``other`` in the class ``Shore`` such that ``"Left".other()`` returns ``"Right"`` and vice versa. .. container:: toggle @@ -74,7 +74,7 @@ temporary variables in the body of a class are called `fields Date: Mon, 23 Sep 2019 11:07:10 +0200 Subject: [PATCH 0186/1227] Java: Minor additional type pruning. --- .../semmle/code/java/dataflow/internal/DataFlowImplCommon.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 97052e80004..240913001d5 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -332,7 +332,8 @@ private module ImplCommon { exists(Node mid1, Node mid2, Content f | store(node1, f, mid1) and localValueStep*(mid1, mid2) and - read(mid2, f, node2) + read(mid2, f, node2) and + compatibleTypes(node1.getTypeBound(), node2.getTypeBound()) ) } From f88f7962e777d5820abf48e44745e12da57e3185 Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Mon, 23 Sep 2019 10:19:49 +0100 Subject: [PATCH 0187/1227] QL etudes: Update predicate --- docs/language/learn-ql/ql-etudes/river-crossing-1.ql | 2 +- docs/language/learn-ql/ql-etudes/river-crossing.ql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql index 9ffd820bb1b..8ad670cc7a3 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql +++ b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql @@ -56,7 +56,7 @@ class State extends string { * Holds if predator and prey are on the same shore and the man * is not present. */ - predicate eats(Shore predator, Shore prey) { predator = prey and man = predator.other() } + predicate eats(Shore predator, Shore prey) { predator = prey and man != predator } /** Holds if nothing gets eaten in this state. */ predicate isSafe() { not (eats(goat, cabbage) or eats(wolf, goat)) } diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.ql b/docs/language/learn-ql/ql-etudes/river-crossing.ql index d6c56309722..5a21adc90ee 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.ql +++ b/docs/language/learn-ql/ql-etudes/river-crossing.ql @@ -69,7 +69,7 @@ class State extends string { * Holds if predator and prey are on the same shore and the man * is not present. */ - predicate eats(Shore predator, Shore prey) { predator = prey and man = predator.other() } + predicate eats(Shore predator, Shore prey) { predator = prey and man != predator } /** Holds if nothing gets eaten in this state. */ predicate isSafe() { not (eats(goat, cabbage) or eats(wolf, goat)) } From f0479687d88172bd0a68017344ea830b8bc70c13 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 18 Sep 2019 17:15:18 +0200 Subject: [PATCH 0188/1227] Python: Fix documentation for Function.isInitMethod --- python/ql/src/semmle/python/Function.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/Function.qll b/python/ql/src/semmle/python/Function.qll index 4c8949f34e6..3ec8dcd5460 100644 --- a/python/ql/src/semmle/python/Function.qll +++ b/python/ql/src/semmle/python/Function.qll @@ -41,7 +41,7 @@ class Function extends Function_, Scope, AstNode { exists(YieldFrom y | y.getScope() = this) } - /** Whether this function is declared in a class and is named "__init__" */ + /** Whether this function is declared in a class and is named `__init__` */ predicate isInitMethod() { this.isMethod() and this.getName() = "__init__" } From 6e50a0ef84ee42a30182c5047f0ab75195cb56fa Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 18 Sep 2019 17:19:22 +0200 Subject: [PATCH 0189/1227] Python: Modernise the `py/explicit-return-in-init` query. Add explicit test case to show that we don't doulbe report this problem. --- python/ql/src/Functions/ExplicitReturnInInit.ql | 13 ++++++------- .../Functions/general/explicit_return_in_init.py | 6 ++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/python/ql/src/Functions/ExplicitReturnInInit.ql b/python/ql/src/Functions/ExplicitReturnInInit.ql index 0885e7cbdd7..34ce4460259 100644 --- a/python/ql/src/Functions/ExplicitReturnInInit.ql +++ b/python/ql/src/Functions/ExplicitReturnInInit.ql @@ -13,11 +13,10 @@ import python from Return r -where exists(Function init | init.isInitMethod() and -r.getScope() = init and exists(r.getValue())) and -not r.getValue() instanceof None and -not exists(FunctionObject f | f.getACall() = r.getValue().getAFlowNode() | - f.neverReturns() -) and -not exists(Attribute meth | meth = ((Call)r.getValue()).getFunc() | meth.getName() = "__init__") +where + exists(Function init | init.isInitMethod() and r.getScope() = init and exists(r.getValue())) and + not r.getValue() instanceof None and + not exists(FunctionValue f | f.getACall() = r.getValue().getAFlowNode() | f.neverReturns()) and + // to avoid double reporting, don't trigger if returning result from other __init__ function + not exists(Attribute meth | meth = r.getValue().(Call).getFunc() | meth.getName() = "__init__") select r, "Explicit return in __init__ method." diff --git a/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py b/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py index f73a55c2faf..c97f627243f 100644 --- a/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py +++ b/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py @@ -37,3 +37,9 @@ class InitCallsInit(InitCallsError): def __init__(self): return super(InitCallsInit, self).__init__() + +# This is not ok, but we will only report root cause (ExplicitReturnInInit) +class InitCallsBadInit(ExplicitReturnInInit): + + def __init__(self): + return ExplicitReturnInInit.__init__(self) From d2739740457a2385352567770c6e5b8e2b861f3c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 23 Sep 2019 11:09:32 +0200 Subject: [PATCH 0190/1227] Python: Don't flag `return procedure_call()` in __init__ as error This commit fixes the results for https://lgtm.com/projects/b/jjburton/cgmtools/snapshot/0d8a429b7ea17854a5e5341df98b1cbd54d7fe6c/files/mayaTools/cgm/lib/classes/AttrFactory.py?sort=name&dir=ASC&mode=heatmap#L90 ``` def __init__(...): if error_case: return guiFactory.warning(...) ``` that was wrongly reporting _Explicit return in __init__ method._ as an error. --- .../ql/src/Functions/ExplicitReturnInInit.ql | 11 ++-- .../general/ExplicitReturnInInit.expected | 1 + .../general/explicit_return_in_init.py | 61 ++++++++++++++++++- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/python/ql/src/Functions/ExplicitReturnInInit.ql b/python/ql/src/Functions/ExplicitReturnInInit.ql index 34ce4460259..b839c3bc9b7 100644 --- a/python/ql/src/Functions/ExplicitReturnInInit.ql +++ b/python/ql/src/Functions/ExplicitReturnInInit.ql @@ -12,11 +12,12 @@ import python -from Return r +from Return r, Expr rv where - exists(Function init | init.isInitMethod() and r.getScope() = init and exists(r.getValue())) and - not r.getValue() instanceof None and - not exists(FunctionValue f | f.getACall() = r.getValue().getAFlowNode() | f.neverReturns()) and + exists(Function init | init.isInitMethod() and r.getScope() = init) and + r.getValue() = rv and + not rv.pointsTo(Value::none_()) and + not exists(FunctionValue f | f.getACall() = rv.getAFlowNode() | f.neverReturns()) and // to avoid double reporting, don't trigger if returning result from other __init__ function - not exists(Attribute meth | meth = r.getValue().(Call).getFunc() | meth.getName() = "__init__") + not exists(Attribute meth | meth = rv.(Call).getFunc() | meth.getName() = "__init__") select r, "Explicit return in __init__ method." diff --git a/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected b/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected index 38252a5cca2..274a69864a7 100644 --- a/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected +++ b/python/ql/test/query-tests/Functions/general/ExplicitReturnInInit.expected @@ -1 +1,2 @@ | explicit_return_in_init.py:4:9:4:19 | Return | Explicit return in __init__ method. | +| explicit_return_in_init.py:102:9:102:18 | Return | Explicit return in __init__ method. | diff --git a/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py b/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py index c97f627243f..d847845d8a6 100644 --- a/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py +++ b/python/ql/test/query-tests/Functions/general/explicit_return_in_init.py @@ -3,7 +3,7 @@ class ExplicitReturnInInit(object): def __init__(self): return self -#These are OK +# These are OK class ExplicitReturnNoneInInit(object): def __init__(self): @@ -32,7 +32,7 @@ class InitIsGenerator(object): def __init__(self): yield self -#OK as it returns result of a call to super().__init__() +# OK as it returns result of a call to super().__init__() class InitCallsInit(InitCallsError): def __init__(self): @@ -43,3 +43,60 @@ class InitCallsBadInit(ExplicitReturnInInit): def __init__(self): return ExplicitReturnInInit.__init__(self) + +# OK as procedure implicitly returns None +# +# this was seen in the wild: https://lgtm.com/projects/b/jjburton/cgmtools/snapshot/0d8a429b7ea17854a5e5341df98b1cbd54d7fe6c/files/mayaTools/cgm/lib/classes/AttrFactory.py?sort=name&dir=ASC&mode=heatmap#L90 +# using a pattern of `return procedure_that_logs_error()` + +def procedure(): + pass + +def explicit_none(): + return None + +def explicit_none_nested(): + return explicit_none() + +class InitReturnsCallResult1(object): + + def __init__(self): + return procedure() + +class InitReturnsCallResult2(object): + + def __init__(self): + return explicit_none() + +class InitReturnsCallResult3(object): + + def __init__(self): + return explicit_none_nested() + +class InitReturnsCallResult4(object): + + def __init__(self, b): + if b: + p = procedure + else: + p = explicit_none + return p() + +class InitReturnsCallResult5(object): + + def __init__(self, b): + return procedure() if b else explicit_none() + +# Not OK + +def not_ok(): + return 42 + +class InitReturnsCallResult6(object): + + def __init__(self, b): + if b: + p = procedure_implicit_none() + else: + p = not_ok + return p() From d6a7b6f7f172a0196bd4c1aa3a35da1317cc3f4e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 23 Sep 2019 11:16:29 +0200 Subject: [PATCH 0191/1227] Python: Fix documentation markup for IdentityEqMethod --- python/ql/src/Classes/Equality.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Classes/Equality.qll b/python/ql/src/Classes/Equality.qll index 5f7648fafc4..7f546c42ecd 100644 --- a/python/ql/src/Classes/Equality.qll +++ b/python/ql/src/Classes/Equality.qll @@ -38,7 +38,7 @@ class GenericEqMethod extends Function { } } -/** An __eq__ method that just does self is other */ +/** An `__eq__` method that just does `self is other` */ class IdentityEqMethod extends Function { IdentityEqMethod() { From 040bd89163b3d4022eef766e9fbe6543506802f0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 23 Sep 2019 11:02:36 +0100 Subject: [PATCH 0192/1227] CPP: Correct expected results. --- .../Likely Bugs/Format/WrongNumberOfFormatArguments/a.c | 2 +- .../Likely Bugs/Format/WrongNumberOfFormatArguments/b.c | 2 +- .../Likely Bugs/Format/WrongNumberOfFormatArguments/c.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c index 0ff140a14f7..b85c0b9580c 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c @@ -14,5 +14,5 @@ void test_custom_printf1() myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments) myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) - myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf2("%i", 0, 1, 2); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED] } diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c index d1c44c80219..7783e2bd340 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c @@ -11,5 +11,5 @@ void test_custom_printf2() myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments) myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) - myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf2("%i", 0, 1, 2); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED] } \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c index 961a4bcc721..58edddae95b 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c @@ -7,5 +7,5 @@ void test_custom_printf2() myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments) myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) - myMultiplyDefinedPrintf2("%i", 0, 1, 2); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf2("%i", 0, 1, 2); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED] } From e1012d8d5a582f29014fa370f9ad359c3793e824 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 23 Sep 2019 12:24:32 +0200 Subject: [PATCH 0193/1227] Python: Add `__aiter__` as a recognised iterator method. --- .../src/semmle/python/objects/ObjectAPI.qll | 2 ++ .../iter/NonIteratorInForLoop.expected | 1 + .../Statements/iter/async_iterator.py | 27 +++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 python/ql/test/3/query-tests/Statements/iter/async_iterator.py diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 5181675b445..9dcd2bdd824 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -350,6 +350,8 @@ class ClassValue extends Value { predicate isIterable() { this.hasAttribute("__iter__") or + this.hasAttribute("__aiter__") + or this.hasAttribute("__getitem__") } diff --git a/python/ql/test/3/query-tests/Statements/iter/NonIteratorInForLoop.expected b/python/ql/test/3/query-tests/Statements/iter/NonIteratorInForLoop.expected index 134d31bcf06..4f6ed0fac55 100644 --- a/python/ql/test/3/query-tests/Statements/iter/NonIteratorInForLoop.expected +++ b/python/ql/test/3/query-tests/Statements/iter/NonIteratorInForLoop.expected @@ -1 +1,2 @@ +| async_iterator.py:26:11:26:34 | For | $@ of class '$@' may be used in for-loop. | async_iterator.py:26:20:26:33 | ControlFlowNode for MissingAiter() | Non-iterator | async_iterator.py:13:1:13:19 | class MissingAiter | MissingAiter | | statements_test.py:34:5:34:19 | For | $@ of class '$@' may be used in for-loop. | statements_test.py:34:18:34:18 | ControlFlowNode for IntegerLiteral | Non-iterator | file://:0:0:0:0 | builtin-class int | int | diff --git a/python/ql/test/3/query-tests/Statements/iter/async_iterator.py b/python/ql/test/3/query-tests/Statements/iter/async_iterator.py new file mode 100644 index 00000000000..fdde931eace --- /dev/null +++ b/python/ql/test/3/query-tests/Statements/iter/async_iterator.py @@ -0,0 +1,27 @@ + +class AsyncIterator: + def __init__(self): + pass + + def __aiter__(self): + return self + + async def __anext__(self): + await asyncio.sleep(5) + return 1 + +class MissingAiter: + def __init__(self, delay, to): + pass + + async def __anext__(self): + await asyncio.sleep(5) + return 1 + +async def good(): + async for x in AsyncIterator(): + yield x + +async def bad(): + async for x in MissingAiter(): + yield x From 2d8e4b3176f8bd53424f05581909eb4385bc0062 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 23 Sep 2019 11:28:50 +0100 Subject: [PATCH 0194/1227] CPP: Additional cases resembling the ticket. --- .../TooManyFormatArguments.expected | 4 ++-- .../WrongNumberOfFormatArguments.expected | 4 ++-- .../Likely Bugs/Format/WrongNumberOfFormatArguments/a.c | 7 +++++++ .../Likely Bugs/Format/WrongNumberOfFormatArguments/b.c | 9 ++++++++- .../Likely Bugs/Format/WrongNumberOfFormatArguments/c.c | 3 +++ 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected index 387b1291745..89a7719e741 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected @@ -1,5 +1,5 @@ -| a.c:14:3:14:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | -| b.c:11:3:11:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | +| a.c:18:3:18:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | +| b.c:15:3:15:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | | c.c:7:3:7:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 | | custom_printf.cpp:31:5:31:12 | call to myPrintf | Format expects 2 arguments but given 3 | | macros.cpp:12:2:12:31 | call to printf | Format expects 2 arguments but given 3 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected index fd10c8368e7..b255838183f 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected @@ -1,5 +1,5 @@ -| a.c:12:3:12:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | -| b.c:9:3:9:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | +| a.c:16:3:16:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | +| b.c:13:3:13:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | | c.c:5:3:5:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 | | custom_printf.cpp:29:5:29:12 | call to myPrintf | Format expects 2 arguments but given 1 | | macros.cpp:14:2:14:37 | call to printf | Format expects 4 arguments but given 3 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c index b85c0b9580c..d1567a5f185 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c @@ -4,9 +4,13 @@ void myMultiplyDefinedPrintf(const char *format, int extraArg, ...) { // ... } + __attribute__((format(printf, 1, 3))) void myMultiplyDefinedPrintf2(const char *format, int extraArg, ...); +__attribute__((format(printf, 2, 3))) +void myMultiplyDefinedPrintf3(int extraArg, const char *format, ...); + void test_custom_printf1() { myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments) @@ -15,4 +19,7 @@ void test_custom_printf1() myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1, 2); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED] + myMultiplyDefinedPrintf3("%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf3("%s", "%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf3("%s", "%s", "%s", "%s"); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED] } diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c index 7783e2bd340..da7f09123af 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/b.c @@ -1,9 +1,13 @@ __attribute__((format(printf, 1, 2))) void myMultiplyDefinedPrintf(const char *format, ...); // this declaration does not match the definition + __attribute__((format(printf, 1, 2))) void myMultiplyDefinedPrintf2(const char *format, ...); +__attribute__((format(printf, 1, 2))) +void myMultiplyDefinedPrintf3(const char *format, ...); + void test_custom_printf2() { myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments) @@ -12,4 +16,7 @@ void test_custom_printf2() myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1, 2); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED] -} \ No newline at end of file + myMultiplyDefinedPrintf3("%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf3("%s", "%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf3("%s", "%s", "%s", "%s"); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED] +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c index 58edddae95b..74183c2374f 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/c.c @@ -8,4 +8,7 @@ void test_custom_printf2() myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK) myMultiplyDefinedPrintf2("%i", 0, 1, 2); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED] + myMultiplyDefinedPrintf3("%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf3("%s", "%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK) + myMultiplyDefinedPrintf3("%s", "%s", "%s", "%s"); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED] } From b3df289a80188542a69cfb85a06fd6abfe52b690 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 23 Sep 2019 13:56:24 +0100 Subject: [PATCH 0195/1227] CPP: Fix test. --- .../Likely Bugs/Format/WrongNumberOfFormatArguments/a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c index d1567a5f185..ec28ef51144 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/a.c @@ -9,7 +9,7 @@ __attribute__((format(printf, 1, 3))) void myMultiplyDefinedPrintf2(const char *format, int extraArg, ...); __attribute__((format(printf, 2, 3))) -void myMultiplyDefinedPrintf3(int extraArg, const char *format, ...); +void myMultiplyDefinedPrintf3(const char *extraArg, const char *format, ...); void test_custom_printf1() { From 5468b8def75ab3faf5bc7a4b0243a8c943209e5e Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Thu, 22 Aug 2019 12:24:55 +0100 Subject: [PATCH 0196/1227] C++: Add support for C++ using aliases Previously these were identified as typedefs. --- cpp/ql/src/semmle/code/cpp/TypedefType.qll | 43 +++++++++++++++++++--- cpp/ql/src/semmlecode.cpp.dbscheme | 3 +- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/TypedefType.qll b/cpp/ql/src/semmle/code/cpp/TypedefType.qll index b7fd5f294fa..1616515bea1 100644 --- a/cpp/ql/src/semmle/code/cpp/TypedefType.qll +++ b/cpp/ql/src/semmle/code/cpp/TypedefType.qll @@ -3,11 +3,18 @@ private import semmle.code.cpp.internal.ResolveClass /** * A C/C++ typedef type. See 4.9.1. + * + * Represents either of the following typedef styles: + * + * * CTypedefType: typedef ; + * * UsingAliasTypedefType: using = ; */ class TypedefType extends UserType { - TypedefType() { usertypes(underlyingElement(this), _, 5) } - override string getCanonicalQLClass() { result = "TypedefType" } + TypedefType() { + usertypes(underlyingElement(this),_,5) or + usertypes(underlyingElement(this),_,14) + } /** * Gets the base type of this typedef type. @@ -26,10 +33,6 @@ class TypedefType extends UserType { result = this.getBaseType().getPointerIndirectionLevel() } - override string explain() { - result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" - } - override predicate isDeeplyConst() { this.getBaseType().isDeeplyConst() } // Just an alias override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConstBelow() } // Just an alias @@ -45,6 +48,34 @@ class TypedefType extends UserType { override Type stripType() { result = getBaseType().stripType() } } +/** + * A traditional C/C++ typedef type. See 4.9.1. + */ +class CTypedefType extends TypedefType { + + CTypedefType() { + usertypes(underlyingElement(this),_,5) + } + + override string getCanonicalQLClass() { result = "CTypedefType" } + + override string explain() { result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" } +} + +/** + * A using alias C++ typedef type. + */ +class UsingAliasTypedefType extends TypedefType { + + UsingAliasTypedefType() { + usertypes(underlyingElement(this),_,14) + } + + override string getCanonicalQLClass() { result = "UsingAliasTypedefType" } + + override string explain() { result = "using {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" } +} + /** * A C++ typedef type that is directly enclosed by a function. */ diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index c4c27a2661b..678a0f9164f 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -675,7 +675,7 @@ decltypes( | 2 = class | 3 = union | 4 = enum - | 5 = typedef + | 5 = typedef // classic C: typedef typedef type name | 6 = template | 7 = template_parameter | 8 = template_template_parameter @@ -684,6 +684,7 @@ decltypes( // ... 11 objc_protocol deprecated // ... 12 objc_category deprecated | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef ; */ usertypes( From 9ff38ebeeed8d2891d580ab28e09c03ed4582756 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Thu, 22 Aug 2019 12:26:35 +0100 Subject: [PATCH 0197/1227] C++: Update tests for new CTypedefType. --- .../examples/expressions/PrintAST.expected | 6 ++--- .../library-tests/ir/ir/PrintAST.expected | 22 +++++++++---------- .../library-tests/typedefs/Typedefs2.expected | 2 +- .../types/wchar_t_typedef/wchar_t.expected | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cpp/ql/test/examples/expressions/PrintAST.expected b/cpp/ql/test/examples/expressions/PrintAST.expected index da71c17f669..9a782825164 100644 --- a/cpp/ql/test/examples/expressions/PrintAST.expected +++ b/cpp/ql/test/examples/expressions/PrintAST.expected @@ -917,7 +917,7 @@ Varargs.c: # 8| body: [Block] { ... } # 9| 0: [DeclStmt] declaration # 9| 0: [VariableDeclarationEntry] definition of args -# 9| Type = [TypedefType] va_list +# 9| Type = [CTypedefType] va_list # 10| 1: [ExprStmt] ExprStmt # 10| 0: [BuiltInVarArgsStart] __builtin_va_start # 10| Type = [VoidType] void @@ -926,7 +926,7 @@ Varargs.c: # 10| Type = [PointerType] __va_list_tag * # 10| ValueCategory = prvalue # 10| expr: [VariableAccess] args -# 10| Type = [TypedefType] va_list +# 10| Type = [CTypedefType] va_list # 10| ValueCategory = lvalue # 10| 1: [VariableAccess] text # 10| Type = [PointerType] const char * @@ -939,7 +939,7 @@ Varargs.c: # 11| Type = [PointerType] __va_list_tag * # 11| ValueCategory = prvalue # 11| expr: [VariableAccess] args -# 11| Type = [TypedefType] va_list +# 11| Type = [CTypedefType] va_list # 11| ValueCategory = lvalue # 12| 3: [ReturnStmt] return ... macro_etc.c: diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index efea5c27210..d675fa95d21 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -3672,7 +3672,7 @@ ir.cpp: # 560| [TopLevelFunction] int EnumSwitch(E) # 560| params: # 560| 0: [Parameter] e -# 560| Type = [TypedefType] E +# 560| Type = [CTypedefType] E # 560| body: [Block] { ... } # 561| 0: [SwitchStmt] switch (...) ... # 561| 0: [CStyleCast] (int)... @@ -3680,7 +3680,7 @@ ir.cpp: # 561| Type = [IntType] int # 561| ValueCategory = prvalue # 561| expr: [VariableAccess] e -# 561| Type = [TypedefType] E +# 561| Type = [CTypedefType] E # 561| ValueCategory = prvalue(load) # 561| 1: [Block] { ... } # 562| 0: [SwitchCase] case ...: @@ -6191,19 +6191,19 @@ ir.cpp: # 915| [Operator,TopLevelFunction] void* operator new(size_t, float) # 915| params: # 915| 0: [Parameter] p#0 -# 915| Type = [Size_t,TypedefType] size_t +# 915| Type = [CTypedefType,Size_t] size_t # 915| 1: [Parameter] p#1 # 915| Type = [FloatType] float # 916| [Operator,TopLevelFunction] void* operator new[](size_t, float) # 916| params: # 916| 0: [Parameter] p#0 -# 916| Type = [Size_t,TypedefType] size_t +# 916| Type = [CTypedefType,Size_t] size_t # 916| 1: [Parameter] p#1 # 916| Type = [FloatType] float # 917| [Operator,TopLevelFunction] void* operator new(size_t, std::align_val_t, float) # 917| params: # 917| 0: [Parameter] p#0 -# 917| Type = [Size_t,TypedefType] size_t +# 917| Type = [CTypedefType,Size_t] size_t # 917| 1: [Parameter] p#1 # 917| Type = [ScopedEnum] align_val_t # 917| 2: [Parameter] p#2 @@ -6211,7 +6211,7 @@ ir.cpp: # 918| [Operator,TopLevelFunction] void* operator new[](size_t, std::align_val_t, float) # 918| params: # 918| 0: [Parameter] p#0 -# 918| Type = [Size_t,TypedefType] size_t +# 918| Type = [CTypedefType,Size_t] size_t # 918| 1: [Parameter] p#1 # 918| Type = [ScopedEnum] align_val_t # 918| 2: [Parameter] p#2 @@ -6255,23 +6255,23 @@ ir.cpp: # 926| [MemberFunction] void* SizedDealloc::operator new(size_t) # 926| params: # 926| 0: [Parameter] p#0 -# 926| Type = [Size_t,TypedefType] size_t +# 926| Type = [CTypedefType,Size_t] size_t # 927| [MemberFunction] void* SizedDealloc::operator new[](size_t) # 927| params: # 927| 0: [Parameter] p#0 -# 927| Type = [Size_t,TypedefType] size_t +# 927| Type = [CTypedefType,Size_t] size_t # 928| [MemberFunction] void SizedDealloc::operator delete(void*, size_t) # 928| params: # 928| 0: [Parameter] p#0 # 928| Type = [VoidPointerType] void * # 928| 1: [Parameter] p#1 -# 928| Type = [Size_t,TypedefType] size_t +# 928| Type = [CTypedefType,Size_t] size_t # 929| [MemberFunction] void SizedDealloc::operator delete[](void*, size_t) # 929| params: # 929| 0: [Parameter] p#0 # 929| Type = [VoidPointerType] void * # 929| 1: [Parameter] p#1 -# 929| Type = [Size_t,TypedefType] size_t +# 929| Type = [CTypedefType,Size_t] size_t # 932| [CopyAssignmentOperator] Overaligned& Overaligned::operator=(Overaligned const&) # 932| params: #-----| 0: [Parameter] p#0 @@ -7855,7 +7855,7 @@ ir.cpp: # 1118| Type = [IntType] int # 1119| 4: [DeclStmt] declaration # 1119| 0: [TypeDeclarationEntry] declaration of d -# 1119| Type = [LocalTypedefType] d +# 1119| Type = [CTypedefType,LocalTypedefType] d # 1120| 5: [ReturnStmt] return ... # 1117| [TopLevelFunction] int f(float) # 1117| params: diff --git a/cpp/ql/test/library-tests/typedefs/Typedefs2.expected b/cpp/ql/test/library-tests/typedefs/Typedefs2.expected index c8519c1fd80..8645ce97fcd 100644 --- a/cpp/ql/test/library-tests/typedefs/Typedefs2.expected +++ b/cpp/ql/test/library-tests/typedefs/Typedefs2.expected @@ -1,2 +1,2 @@ -| typedefs.cpp:6:6:6:7 | f1 | typedefs.cpp:8:15:8:18 | TYPE | LocalTypedefType | +| typedefs.cpp:6:6:6:7 | f1 | typedefs.cpp:8:15:8:18 | TYPE | CTypedefType, LocalTypedefType | | typedefs.cpp:6:6:6:7 | f1 | typedefs.cpp:9:9:9:9 | D | DirectAccessHolder, LocalClass, MetricClass, StructLikeClass | diff --git a/cpp/ql/test/library-tests/types/wchar_t_typedef/wchar_t.expected b/cpp/ql/test/library-tests/types/wchar_t_typedef/wchar_t.expected index 3e89d75be03..e0f36ebd68a 100644 --- a/cpp/ql/test/library-tests/types/wchar_t_typedef/wchar_t.expected +++ b/cpp/ql/test/library-tests/types/wchar_t_typedef/wchar_t.expected @@ -1,3 +1,3 @@ | file://:0:0:0:0 | wchar_t | Wchar_t, WideCharType | | -| file://:0:0:0:0 | wchar_t * | PointerType | TypedefType, Wchar_t | -| ms.c:2:24:2:30 | wchar_t | TypedefType, Wchar_t | | +| file://:0:0:0:0 | wchar_t * | PointerType | CTypedefType, Wchar_t | +| ms.c:2:24:2:30 | wchar_t | CTypedefType, Wchar_t | | From fc75a6af5a0d40dd208b0a922eb884c3f9de8579 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Thu, 22 Aug 2019 12:42:45 +0100 Subject: [PATCH 0198/1227] C++: Add tests for using aliases --- .../test/library-tests/using-aliases/using-alias.cpp | 10 ++++++++++ .../library-tests/using-aliases/using-alias.expected | 9 +++++++++ cpp/ql/test/library-tests/using-aliases/using-alias.ql | 4 ++++ 3 files changed, 23 insertions(+) create mode 100644 cpp/ql/test/library-tests/using-aliases/using-alias.cpp create mode 100644 cpp/ql/test/library-tests/using-aliases/using-alias.expected create mode 100644 cpp/ql/test/library-tests/using-aliases/using-alias.ql diff --git a/cpp/ql/test/library-tests/using-aliases/using-alias.cpp b/cpp/ql/test/library-tests/using-aliases/using-alias.cpp new file mode 100644 index 00000000000..9732978af18 --- /dev/null +++ b/cpp/ql/test/library-tests/using-aliases/using-alias.cpp @@ -0,0 +1,10 @@ + +typedef int type1; +using using1 = float; + +typedef using1 type2; +using using2 = type1; + +template struct S { using X = T*; }; + +using Y = S::X; diff --git a/cpp/ql/test/library-tests/using-aliases/using-alias.expected b/cpp/ql/test/library-tests/using-aliases/using-alias.expected new file mode 100644 index 00000000000..e528b93e279 --- /dev/null +++ b/cpp/ql/test/library-tests/using-aliases/using-alias.expected @@ -0,0 +1,9 @@ +| file://:0:0:0:0 | X | NestedTypedefType | file://:0:0:0:0 | int * | +| file://:0:0:0:0 | X | UsingAliasTypedefType | file://:0:0:0:0 | int * | +| using-alias.cpp:2:13:2:17 | type1 | CTypedefType | file://:0:0:0:0 | int | +| using-alias.cpp:3:7:3:12 | using1 | UsingAliasTypedefType | file://:0:0:0:0 | float | +| using-alias.cpp:5:16:5:20 | type2 | CTypedefType | file://:0:0:0:0 | float | +| using-alias.cpp:6:7:6:12 | using2 | UsingAliasTypedefType | file://:0:0:0:0 | int | +| using-alias.cpp:8:39:8:39 | X | NestedTypedefType | file://:0:0:0:0 | T * | +| using-alias.cpp:8:39:8:39 | X | UsingAliasTypedefType | file://:0:0:0:0 | T * | +| using-alias.cpp:10:7:10:7 | Y | UsingAliasTypedefType | file://:0:0:0:0 | int * | diff --git a/cpp/ql/test/library-tests/using-aliases/using-alias.ql b/cpp/ql/test/library-tests/using-aliases/using-alias.ql new file mode 100644 index 00000000000..79287777e4b --- /dev/null +++ b/cpp/ql/test/library-tests/using-aliases/using-alias.ql @@ -0,0 +1,4 @@ +import cpp + +from TypedefType t +select t, t.getCanonicalQLClass(), t.getUnderlyingType() From c8dfa46c63a06c6c18534d0ae9eec3c49cafdc6e Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Mon, 16 Sep 2019 15:37:02 +0100 Subject: [PATCH 0199/1227] C++: Add upgrade script for using aliases. --- .../old.dbscheme | 1909 ++++++++++++++++ .../semmlecode.cpp.dbscheme | 1910 +++++++++++++++++ .../upgrade.properties | 2 + 3 files changed, 3821 insertions(+) create mode 100644 cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/old.dbscheme create mode 100644 cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/semmlecode.cpp.dbscheme create mode 100644 cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/upgrade.properties diff --git a/cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/old.dbscheme b/cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/old.dbscheme new file mode 100644 index 00000000000..c4c27a2661b --- /dev/null +++ b/cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/old.dbscheme @@ -0,0 +1,1909 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +fun_decls( + unique int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +var_decls( + unique int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +membervariables( + unique int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +globalvariables( + unique int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + unique int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/semmlecode.cpp.dbscheme b/cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..678a0f9164f --- /dev/null +++ b/cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/semmlecode.cpp.dbscheme @@ -0,0 +1,1910 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +fun_decls( + unique int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +var_decls( + unique int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +membervariables( + unique int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +globalvariables( + unique int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + unique int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/upgrade.properties b/cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/upgrade.properties new file mode 100644 index 00000000000..894580c39fc --- /dev/null +++ b/cpp/upgrades/c4c27a2661b3baaf1cfd8e370320a106b7f41e2e/upgrade.properties @@ -0,0 +1,2 @@ +description: Add support for identifying using alias definitions. +compatibility: partial From af3b0d9e73d6e87d69b7b197bed42006f7b51ba0 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Tue, 17 Sep 2019 09:19:08 +0100 Subject: [PATCH 0200/1227] C++: Update stats. --- cpp/ql/src/semmlecode.cpp.dbscheme.stats | 1203 +++++++++++----------- 1 file changed, 594 insertions(+), 609 deletions(-) diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme.stats b/cpp/ql/src/semmlecode.cpp.dbscheme.stats index 85160eeeac5..e5b3ff92488 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/src/semmlecode.cpp.dbscheme.stats @@ -53,7 +53,7 @@ @function -3566289 +3566471 @fun_decl @@ -77,15 +77,15 @@ @static_assert -132361 +132358 @parameter -4781221 +4781331 @membervariable -329676 +329712 @globalvariable @@ -93,11 +93,11 @@ @localvariable -527113 +527101 @enumconstant -94489 +94487 @builtintype @@ -121,7 +121,7 @@ @type_mention -1699398 +1699359 @routinetype @@ -145,7 +145,7 @@ @declspec -58442 +58441 @msattribute @@ -193,7 +193,7 @@ @namequalifier -1125647 +1125621 @value @@ -201,23 +201,7 @@ @initialiser -1685056 - - -@preincrexpr -63965 - - -@predecrexpr -26590 - - -@assignexpr -551713 - - -@varaccess -5376523 +1685017 @literal @@ -296,6 +280,14 @@ 5401 +@preincrexpr +63965 + + +@predecrexpr +26590 + + @conditionalexpr 154429 @@ -369,7 +361,7 @@ @orexpr -145220 +145217 @xorexpr @@ -408,6 +400,10 @@ 1 +@assignexpr +551713 + + @assignaddexpr 68305 @@ -449,7 +445,7 @@ @assignpaddexpr -13215 +13214 @assignpsubexpr @@ -496,8 +492,12 @@ 30 +@varaccess +5376400 + + @thisaccess -1181367 +1181340 @new_expr @@ -653,7 +653,7 @@ @new_array_expr -5365 +5364 @foldexpr @@ -693,7 +693,7 @@ @reinterpret_cast -31208 +31207 @const_cast @@ -845,15 +845,7 @@ @stmt_expr -1284491 - - -@stmt_return -1197363 - - -@stmt_block -1398476 +1284462 @stmt_if @@ -872,12 +864,20 @@ 85508 +@stmt_return +1197363 + + +@stmt_block +1398476 + + @stmt_end_test_while 149900 @stmt_for -32388 +32387 @stmt_switch_case @@ -917,7 +917,7 @@ @stmt_empty -103683 +103681 @stmt_continue @@ -940,6 +940,14 @@ 3 +@ppd_plain_include +321760 + + +@ppd_define +350005 + + @ppd_if 171105 @@ -964,14 +972,6 @@ 329749 -@ppd_plain_include -321760 - - -@ppd_define -350005 - - @ppd_undef 21155 @@ -985,7 +985,7 @@ @ppd_pragma -37041 +37040 @ppd_objc_import @@ -1496,7 +1496,7 @@ seconds -12669 +12389 @@ -1540,19 +1540,14 @@ 12 -2 -3 -24 - - 3 4 -3027 +2942 4 5 -7513 +7623 @@ -1598,8 +1593,8 @@ 12 -1042 -1043 +1019 +1020 12 @@ -1651,18 +1646,18 @@ 12 -10 -11 +9 +10 12 -563 -564 +546 +547 12 -620 -621 +590 +591 12 @@ -1679,22 +1674,27 @@ 1 2 -8036 +7890 2 3 -2711 +2589 3 4 -996 +875 4 -597 -924 +14 +936 + + +15 +625 +97 @@ -1710,7 +1710,7 @@ 1 2 -12669 +12389 @@ -1726,17 +1726,12 @@ 1 2 -10796 +10784 2 3 -1835 - - -3 -4 -36 +1604 @@ -2115,11 +2110,11 @@ cpu_seconds -8450 +8425 elapsed_seconds -182 +170 @@ -2165,17 +2160,17 @@ 1 2 -7064 +7258 2 3 -984 +705 3 -9 -401 +10 +462 @@ -2191,12 +2186,12 @@ 1 2 -7951 +7963 2 3 -498 +462 @@ -2212,16 +2207,21 @@ 1 2 -36 +12 2 3 -24 +36 -4 -5 +5 +6 +12 + + +9 +10 12 @@ -2230,43 +2230,38 @@ 12 -12 -13 -12 - - 18 19 12 -23 -24 +27 +28 12 -57 -58 +49 +50 12 -127 -128 +121 +122 12 -131 -132 +128 +129 12 -237 -238 +246 +247 12 -245 -246 +251 +252 12 @@ -2283,16 +2278,21 @@ 1 2 -36 +12 2 3 -24 +36 -4 -5 +5 +6 +12 + + +9 +10 12 @@ -2301,43 +2301,38 @@ 12 -12 -13 +18 +19 12 -17 -18 +27 +28 12 -23 -24 +49 +50 12 -54 -55 +96 +97 12 -105 -106 +117 +118 12 -114 -115 +167 +168 12 -168 -169 -12 - - -222 -223 +226 +227 12 @@ -15439,11 +15434,11 @@ functions -3566289 +3566471 id -3566289 +3566471 name @@ -15465,7 +15460,7 @@ 1 2 -3566289 +3566471 @@ -15481,7 +15476,7 @@ 1 2 -3566289 +3566471 @@ -15516,7 +15511,7 @@ 13 -109481 +109484 17714 @@ -15572,8 +15567,8 @@ 12 -43770 -43771 +43779 +43780 12 @@ -15582,8 +15577,8 @@ 12 -131400 -131401 +131406 +131407 12 @@ -15644,7 +15639,7 @@ id -1065322 +1065395 entry_point @@ -15662,12 +15657,12 @@ 1 2 -1062307 +1062453 2 9 -3015 +2942 @@ -15693,15 +15688,15 @@ function_return_type -3577961 +3578144 id -3566253 +3566435 return_type -1030658 +1030695 @@ -15715,7 +15710,7 @@ 1 2 -3555042 +3555225 2 @@ -15736,7 +15731,7 @@ 1 2 -316545 +316581 2 @@ -15745,7 +15740,7 @@ 3 -81730 +81739 64488 @@ -15767,11 +15762,11 @@ function_deleted -51187 +51259 id -51187 +51259 @@ -15797,11 +15792,11 @@ function -3485630 +3485812 type_id -1023363 +1023400 name @@ -15887,12 +15882,12 @@ 1 2 -3344385 +3344750 2 9 -141244 +141062 @@ -15908,7 +15903,7 @@ 1 2 -3467246 +3467429 2 @@ -15929,7 +15924,7 @@ 1 2 -3485630 +3485812 @@ -15945,12 +15940,12 @@ 1 2 -3390527 +3390891 2 9 -95103 +94920 @@ -15966,12 +15961,12 @@ 1 2 -302538 +302611 2 3 -648142 +648105 3 @@ -15992,7 +15987,7 @@ 1 2 -315572 +315608 2 @@ -16001,7 +15996,7 @@ 3 -80906 +80915 63637 @@ -16018,7 +16013,7 @@ 1 2 -953671 +953708 2 @@ -16039,12 +16034,12 @@ 1 2 -917755 +917828 2 5 -82057 +82020 5 @@ -16130,7 +16125,7 @@ 26 -109465 +109468 8741 @@ -16156,7 +16151,7 @@ 5 -56195 +56198 12742 @@ -16951,11 +16946,11 @@ variable -5342029 +5342175 type_id -2038350 +2038459 name @@ -17041,12 +17036,12 @@ 1 2 -5147701 +5147993 2 9 -194328 +194182 @@ -17062,7 +17057,7 @@ 1 2 -5292362 +5292508 2 @@ -17083,7 +17078,7 @@ 1 2 -5323281 +5323427 2 @@ -17104,12 +17099,12 @@ 1 2 -5226682 +5226865 2 9 -115347 +115310 @@ -17125,7 +17120,7 @@ 1 2 -1580670 +1580816 2 @@ -17135,7 +17130,7 @@ 3 9 -154667 +154631 9 @@ -17156,12 +17151,12 @@ 1 2 -1607114 +1607187 2 3 -235059 +235095 3 @@ -17187,7 +17182,7 @@ 1 2 -1850964 +1851073 2 @@ -17213,12 +17208,12 @@ 1 2 -1771740 +1771886 2 4 -165196 +165160 4 @@ -17305,12 +17300,12 @@ 4 6 -11939 +11927 6 11 -11416 +11428 11 @@ -17319,7 +17314,7 @@ 28 -148417 +148426 9872 @@ -17360,7 +17355,7 @@ 28 -111442 +111448 4510 @@ -17463,7 +17458,7 @@ 6 -113868 +113877 78300 @@ -17489,7 +17484,7 @@ 3 -104373 +104379 99310 @@ -18373,15 +18368,15 @@ static_asserts -132361 +132358 id -132361 +132358 condition -132361 +132358 message @@ -18389,7 +18384,7 @@ location -16939 +16938 @@ -18403,7 +18398,7 @@ 1 2 -132361 +132358 @@ -18419,7 +18414,7 @@ 1 2 -132361 +132358 @@ -18435,7 +18430,7 @@ 1 2 -132361 +132358 @@ -18451,7 +18446,7 @@ 1 2 -132361 +132358 @@ -18467,7 +18462,7 @@ 1 2 -132361 +132358 @@ -18483,7 +18478,7 @@ 1 2 -132361 +132358 @@ -18499,7 +18494,7 @@ 1 2 -22396 +22395 2 @@ -18540,7 +18535,7 @@ 1 2 -22396 +22395 2 @@ -18581,7 +18576,7 @@ 1 2 -27913 +27912 2 @@ -18627,7 +18622,7 @@ 14 15 -2063 +2062 16 @@ -18683,7 +18678,7 @@ 14 15 -2063 +2062 16 @@ -18739,15 +18734,15 @@ params -4805368 +4805477 id -4781221 +4781331 function -3119223 +3119333 index @@ -18755,7 +18750,7 @@ type_id -1865919 +1866028 @@ -18769,7 +18764,7 @@ 1 2 -4780480 +4780589 2 @@ -18790,7 +18785,7 @@ 1 2 -4781221 +4781331 @@ -18806,7 +18801,7 @@ 1 2 -4759555 +4759664 2 @@ -18827,7 +18822,7 @@ 1 2 -2207948 +2208057 2 @@ -18858,7 +18853,7 @@ 1 2 -2207948 +2208057 2 @@ -18889,7 +18884,7 @@ 1 2 -2315246 +2315356 2 @@ -18968,8 +18963,8 @@ 24 -256377 -256378 +256386 +256387 12 @@ -19034,8 +19029,8 @@ 24 -256548 -256549 +256557 +256558 12 @@ -19100,8 +19095,8 @@ 24 -135721 -135722 +135727 +135728 12 @@ -19118,7 +19113,7 @@ 1 2 -1495062 +1495172 2 @@ -19149,7 +19144,7 @@ 1 2 -1517178 +1517288 2 @@ -19180,12 +19175,12 @@ 1 2 -1751155 +1751301 2 33 -114763 +114727 @@ -19195,11 +19190,11 @@ overrides -161131 +161127 new -126172 +126169 old @@ -19217,12 +19212,12 @@ 1 2 -91220 +91218 2 3 -34945 +34944 3 @@ -19283,11 +19278,11 @@ membervariables -329676 +329712 id -329676 +329712 type_id @@ -19309,7 +19304,7 @@ 1 2 -329676 +329712 @@ -19325,7 +19320,7 @@ 1 2 -329676 +329712 @@ -19341,12 +19336,12 @@ 1 2 -118447 +118411 2 3 -13362 +13398 3 @@ -19413,12 +19408,12 @@ 4 6 -4498 +4486 6 15 -4522 +4535 15 @@ -19640,19 +19635,19 @@ localvariables -527192 +527180 id -527113 +527101 type_id -48002 +48087 name -76218 +76217 @@ -19666,7 +19661,7 @@ 1 2 -527034 +527022 2 @@ -19687,7 +19682,7 @@ 1 2 -527113 +527101 @@ -19703,12 +19698,12 @@ 1 2 -26614 +26759 2 3 -6887 +6841 3 @@ -19718,7 +19713,7 @@ 4 6 -4132 +4119 6 @@ -19727,13 +19722,8 @@ 13 -3187 -3605 - - -4907 4908 -6 +3611 @@ -19749,17 +19739,17 @@ 1 2 -35934 +36072 2 3 -5009 +4969 3 5 -4336 +4323 5 @@ -19780,7 +19770,7 @@ 1 2 -43527 +43526 2 @@ -19790,7 +19780,7 @@ 3 4 -5141 +5140 4 @@ -19821,7 +19811,7 @@ 1 2 -64565 +64564 2 @@ -19909,15 +19899,15 @@ enumconstants -94489 +94487 id -94489 +94487 parent -7540 +7539 index @@ -19925,15 +19915,15 @@ type_id -7395 +7394 name -73852 +73851 location -76858 +76856 @@ -19947,7 +19937,7 @@ 1 2 -94489 +94487 @@ -19963,7 +19953,7 @@ 1 2 -94489 +94487 @@ -19979,7 +19969,7 @@ 1 2 -94489 +94487 @@ -19995,7 +19985,7 @@ 1 2 -94489 +94487 @@ -20011,7 +20001,7 @@ 1 2 -94489 +94487 @@ -20098,7 +20088,7 @@ 4 5 -580 +579 5 @@ -20175,7 +20165,7 @@ 4 5 -580 +579 5 @@ -20272,7 +20262,7 @@ 1 2 -2643 +2642 2 @@ -20287,7 +20277,7 @@ 4 7 -580 +579 7 @@ -20328,7 +20318,7 @@ 1 2 -2643 +2642 2 @@ -20343,7 +20333,7 @@ 4 7 -580 +579 7 @@ -20384,7 +20374,7 @@ 1 2 -2643 +2642 2 @@ -20399,7 +20389,7 @@ 4 7 -580 +579 7 @@ -20440,7 +20430,7 @@ 1 2 -2643 +2642 2 @@ -20455,7 +20445,7 @@ 4 7 -580 +579 7 @@ -20496,7 +20486,7 @@ 1 2 -2643 +2642 2 @@ -20511,7 +20501,7 @@ 4 7 -580 +579 7 @@ -20797,7 +20787,7 @@ 1 2 -66398 +66396 2 @@ -20823,7 +20813,7 @@ 1 2 -67050 +67049 2 @@ -20849,7 +20839,7 @@ 1 2 -68764 +68762 2 @@ -20870,7 +20860,7 @@ 1 2 -61942 +61941 2 @@ -20896,7 +20886,7 @@ 1 2 -71348 +71346 2 @@ -20917,7 +20907,7 @@ 1 2 -71532 +71531 2 @@ -20938,7 +20928,7 @@ 1 2 -71644 +71643 2 @@ -20959,7 +20949,7 @@ 1 2 -73213 +73211 2 @@ -20980,7 +20970,7 @@ 1 2 -66536 +66535 2 @@ -21006,7 +20996,7 @@ 1 2 -76686 +76685 2 @@ -21749,7 +21739,7 @@ type_id -2743126 +2743236 @@ -21897,8 +21887,8 @@ 12 -25096 -25097 +25102 +25103 12 @@ -21907,18 +21897,18 @@ 12 -53931 -53932 +53934 +53935 12 -97752 -97753 +97758 +97759 12 -154514 -154515 +154520 +154521 12 @@ -21999,8 +21989,8 @@ 12 -25096 -25097 +25102 +25103 12 @@ -22009,18 +21999,18 @@ 12 -53931 -53932 +53934 +53935 12 -97422 -97423 +97428 +97429 12 -154514 -154515 +154520 +154521 12 @@ -22037,12 +22027,12 @@ 1 2 -1661730 +1661767 2 3 -405544 +405581 3 @@ -22052,7 +22042,7 @@ 4 198 -60050 +60087 @@ -22068,12 +22058,12 @@ 1 2 -1663019 +1663092 2 3 -405398 +405435 3 @@ -22099,12 +22089,12 @@ 1 2 -1663408 +1663444 2 3 -406809 +406845 3 @@ -22114,7 +22104,7 @@ 4 7 -58324 +58360 @@ -22124,11 +22114,11 @@ pointerishsize -3358477 +3358659 id -3358477 +3358659 size @@ -22150,7 +22140,7 @@ 1 2 -3358477 +3358659 @@ -22166,7 +22156,7 @@ 1 2 -3358477 +3358659 @@ -22185,8 +22175,8 @@ 12 -276205 -276206 +276220 +276221 12 @@ -22217,8 +22207,8 @@ 12 -276226 -276227 +276241 +276242 12 @@ -23027,7 +23017,7 @@ kind -121 +133 @@ -23104,12 +23094,12 @@ 1 2 -842701 +842494 2 -9 -56877 +10 +57083 @@ -23148,8 +23138,13 @@ 12 -17519 -17520 +11651 +11652 +12 + + +17522 +17523 12 @@ -23168,8 +23163,8 @@ 12 -154981 -154982 +143330 +143331 12 @@ -23199,6 +23194,11 @@ 12 +548 +549 +12 + + 776 777 12 @@ -23209,8 +23209,8 @@ 12 -5034 -5035 +4545 +4546 12 @@ -23236,11 +23236,11 @@ usertypesize -1364882 +1364918 id -1364882 +1364918 size @@ -23262,7 +23262,7 @@ 1 2 -1364882 +1364918 @@ -23278,7 +23278,7 @@ 1 2 -1364882 +1364918 @@ -23409,8 +23409,8 @@ 12 -9653 -9654 +9656 +9657 12 @@ -23615,22 +23615,22 @@ is_standard_layout_class -1118989 +1119026 id -1118989 +1119026 is_complete -1346048 +1346085 id -1346048 +1346085 @@ -24025,19 +24025,19 @@ type_mentions -1699398 +1699359 id -1699398 +1699359 type_id -67393 +67392 location -1668493 +1668455 kind @@ -24055,7 +24055,7 @@ 1 2 -1699398 +1699359 @@ -24071,7 +24071,7 @@ 1 2 -1699398 +1699359 @@ -24087,7 +24087,7 @@ 1 2 -1699398 +1699359 @@ -24118,7 +24118,7 @@ 4 7 -6156 +6155 7 @@ -24164,7 +24164,7 @@ 4 7 -6156 +6155 7 @@ -24195,7 +24195,7 @@ 1 2 -66134 +66133 2 @@ -24216,7 +24216,7 @@ 1 2 -1637930 +1637892 2 @@ -24237,7 +24237,7 @@ 1 2 -1637930 +1637892 2 @@ -24258,7 +24258,7 @@ 1 2 -1668493 +1668455 @@ -24432,7 +24432,7 @@ arg_type -369871 +369908 @@ -24730,12 +24730,12 @@ 1 2 -249515 +249588 2 3 -48743 +48706 3 @@ -24766,12 +24766,12 @@ 1 2 -341214 +341287 2 5 -28171 +28134 5 @@ -25161,7 +25161,7 @@ type_id -209392 +209429 @@ -25384,12 +25384,12 @@ 1 2 -123639 +123712 2 3 -40913 +40876 3 @@ -25420,12 +25420,12 @@ 1 2 -156783 +156856 2 3 -41204 +41168 3 @@ -25644,11 +25644,11 @@ typespecifiers -1465031 +1465104 type_id -1460350 +1460423 spec_id @@ -25666,7 +25666,7 @@ 1 2 -1455669 +1455742 2 @@ -25715,8 +25715,8 @@ 12 -97284 -97285 +97290 +97291 12 @@ -25727,11 +25727,11 @@ funspecifiers -11371716 +11372263 func_id -3512354 +3512537 spec_id @@ -25759,7 +25759,7 @@ 3 4 -909123 +909305 4 @@ -25838,13 +25838,13 @@ 12 -33529 -33530 +33532 +33533 12 -122450 -122451 +122462 +122463 12 @@ -25853,13 +25853,13 @@ 12 -232286 -232287 +232301 +232302 12 -262991 -262992 +263006 +263007 12 @@ -25870,11 +25870,11 @@ varspecifiers -1123267 +1124177 var_id -934196 +935111 spec_id @@ -25892,17 +25892,17 @@ 1 2 -794360 +795278 2 3 -92281 +92279 3 5 -47554 +47553 @@ -25946,8 +25946,8 @@ 6 -11153 -11154 +11295 +11296 6 @@ -27400,15 +27400,15 @@ unspecifiedtype -9371008 +9371300 type_id -9371008 +9371300 unspecified_type_id -5062944 +5063090 @@ -27422,7 +27422,7 @@ 1 2 -9371008 +9371300 @@ -27438,17 +27438,17 @@ 1 2 -2734044 +2734080 2 3 -1949727 +1949800 3 7841 -379173 +379209 @@ -27458,11 +27458,11 @@ member -5112818 +5113037 parent -809898 +809934 index @@ -27470,7 +27470,7 @@ child -5068087 +5068306 @@ -27504,7 +27504,7 @@ 5 7 -65047 +65084 7 @@ -27560,7 +27560,7 @@ 5 7 -65740 +65777 7 @@ -27645,12 +27645,12 @@ 3427 -21553 +21556 231 -29159 -65990 +29162 +65993 48 @@ -27721,7 +27721,7 @@ 10213 -66835 +66838 121 @@ -27738,7 +27738,7 @@ 1 2 -5068087 +5068306 @@ -27754,7 +27754,7 @@ 1 2 -5043175 +5043394 2 @@ -27769,11 +27769,11 @@ enclosingfunction -131736 +131773 child -131736 +131773 parent @@ -27791,7 +27791,7 @@ 1 2 -131736 +131773 @@ -27807,12 +27807,12 @@ 1 2 -39283 +39247 2 3 -21897 +21933 3 @@ -29485,11 +29485,11 @@ compgenerated -6721088 +6721234 id -6721088 +6721234 @@ -29844,11 +29844,11 @@ exprparents -13615192 +13615303 expr_id -13615001 +13615112 child_index @@ -29856,7 +29856,7 @@ parent_id -9643112 +9644209 @@ -29870,7 +29870,7 @@ 1 2 -13614995 +13615105 2 @@ -29891,7 +29891,7 @@ 1 2 -13614817 +13614927 2 @@ -29941,7 +29941,7 @@ 6434 -1187663 +1187727 46 @@ -29987,7 +29987,7 @@ 6419 -1187540 +1187740 46 @@ -30004,17 +30004,17 @@ 1 2 -6839533 +6840662 2 3 -2212018 +2212086 3 1681 -591560 +591461 @@ -30030,17 +30030,17 @@ 1 2 -6839816 +6840682 2 3 -2211945 +2212066 3 480 -591349 +591461 @@ -30050,11 +30050,11 @@ expr_isload -5063230 +5063114 expr_id -5063230 +5063114 @@ -30303,23 +30303,23 @@ namequalifiers -1125647 +1125621 id -1125647 +1125621 qualifiableelement -1125647 +1125621 qualifyingelement -37002 +37001 location -509600 +509589 @@ -30333,7 +30333,7 @@ 1 2 -1125647 +1125621 @@ -30349,7 +30349,7 @@ 1 2 -1125647 +1125621 @@ -30365,7 +30365,7 @@ 1 2 -1125647 +1125621 @@ -30381,7 +30381,7 @@ 1 2 -1125647 +1125621 @@ -30397,7 +30397,7 @@ 1 2 -1125647 +1125621 @@ -30413,7 +30413,7 @@ 1 2 -1125647 +1125621 @@ -30429,7 +30429,7 @@ 1 2 -17110 +17109 2 @@ -30470,7 +30470,7 @@ 1 2 -17110 +17109 2 @@ -30516,12 +30516,12 @@ 2 3 -4818 +4817 3 4 -3803 +3802 4 @@ -30547,22 +30547,22 @@ 1 2 -387659 +387650 2 3 -57006 +57004 3 7 -39038 +39037 7 381 -25896 +25895 @@ -30578,22 +30578,22 @@ 1 2 -387659 +387650 2 3 -57006 +57004 3 7 -39038 +39037 7 381 -25896 +25895 @@ -30609,17 +30609,17 @@ 1 2 -452489 +452478 2 3 -44786 +44785 3 190 -12325 +12324 @@ -30629,15 +30629,15 @@ varbind -5497468 +5497554 expr -5497343 +5497428 var -1547527 +1549120 @@ -30651,7 +30651,7 @@ 1 2 -5497218 +5497303 2 @@ -30672,32 +30672,32 @@ 1 2 -685146 +685862 2 3 -310616 +311295 3 4 -235999 +236837 4 5 -94126 +93953 5 9 -135129 +134777 9 6150 -86507 +86393 @@ -30707,15 +30707,15 @@ funbind -2442817 +2442767 expr -2142581 +2142538 fun -438015 +438611 @@ -30729,12 +30729,12 @@ 1 2 -1842589 +1842553 2 3 -299814 +299807 3 @@ -30755,22 +30755,22 @@ 1 2 -254164 +255153 2 3 -76403 +76151 3 4 -31716 +31642 4 7 -33976 +33910 7 @@ -31436,11 +31436,11 @@ fieldoffsets -259546 +259582 id -259546 +259582 byteoffset @@ -31462,7 +31462,7 @@ 1 2 -259546 +259582 @@ -31478,7 +31478,7 @@ 1 2 -259546 +259582 @@ -31528,7 +31528,7 @@ 90 -12366 +12369 194 @@ -31584,8 +31584,8 @@ 12 -21335 -21336 +21338 +21339 12 @@ -31833,23 +31833,23 @@ initialisers -1685056 +1685017 init -1685056 +1685017 var -649693 +649678 expr -1685056 +1685017 location -321913 +321906 @@ -31863,7 +31863,7 @@ 1 2 -1685056 +1685017 @@ -31879,7 +31879,7 @@ 1 2 -1685056 +1685017 @@ -31895,7 +31895,7 @@ 1 2 -1685056 +1685017 @@ -31911,7 +31911,7 @@ 1 2 -561993 +561980 2 @@ -31921,7 +31921,7 @@ 16 17 -49689 +49688 17 @@ -31942,7 +31942,7 @@ 1 2 -561993 +561980 2 @@ -31952,7 +31952,7 @@ 16 17 -49689 +49688 17 @@ -31973,7 +31973,7 @@ 1 2 -649680 +649665 2 @@ -31994,7 +31994,7 @@ 1 2 -1685056 +1685017 @@ -32010,7 +32010,7 @@ 1 2 -1685056 +1685017 @@ -32026,7 +32026,7 @@ 1 2 -1685056 +1685017 @@ -32042,7 +32042,7 @@ 1 2 -248456 +248450 2 @@ -32057,7 +32057,7 @@ 7 65 -24347 +24346 67 @@ -32078,7 +32078,7 @@ 1 2 -271340 +271334 2 @@ -32088,7 +32088,7 @@ 3 24 -24156 +24155 24 @@ -32109,7 +32109,7 @@ 1 2 -248456 +248450 2 @@ -32124,7 +32124,7 @@ 7 65 -24347 +24346 67 @@ -32476,7 +32476,7 @@ typeid -1372748 +1372858 value_category @@ -32531,7 +32531,7 @@ 1 2 -530582 +530691 2 @@ -32546,12 +32546,12 @@ 4 5 -95346 +95382 5 8 -122885 +122848 8 @@ -32582,12 +32582,12 @@ 1 2 -1207211 +1207284 2 3 -157707 +157743 3 @@ -32637,13 +32637,13 @@ 12 -29722 -29723 +29728 +29729 12 -96102 -96103 +96108 +96109 12 @@ -32717,11 +32717,11 @@ new_array_allocated_type -5365 +5364 expr -5365 +5364 type_id @@ -32739,7 +32739,7 @@ 1 2 -5365 +5364 @@ -33769,7 +33769,7 @@ field -20794 +21730 captured_by_reference @@ -33781,7 +33781,7 @@ location -14052 +14051 @@ -34327,28 +34327,28 @@ 6 -138 -139 +140 +141 6 -215 -216 +220 +221 6 -399 -400 +412 +413 6 -741 -742 +773 +774 6 -1442 -1443 +1532 +1533 6 @@ -34503,12 +34503,7 @@ 1 2 -20142 - - -2 -11 -652 +21730 @@ -34524,12 +34519,7 @@ 1 2 -20142 - - -2 -11 -652 +21730 @@ -34545,7 +34535,7 @@ 1 2 -20794 +21730 @@ -34561,7 +34551,7 @@ 1 2 -20794 +21730 @@ -34577,7 +34567,7 @@ 1 2 -20794 +21730 @@ -34593,12 +34583,7 @@ 1 2 -20142 - - -2 -11 -652 +21730 @@ -34675,13 +34660,13 @@ 12 -1140 -1141 +1186 +1187 6 -2015 -2016 +2111 +2112 6 @@ -34796,13 +34781,13 @@ 12 -788 -789 +835 +836 6 -2367 -2368 +2462 +2463 6 @@ -34856,7 +34841,7 @@ 1 2 -12668 +12667 2 @@ -34882,7 +34867,7 @@ 1 2 -13116 +13115 2 @@ -34924,7 +34909,7 @@ 1 2 -12668 +12667 2 @@ -34971,7 +34956,7 @@ 1 2 -14052 +14051 @@ -36061,15 +36046,15 @@ for_initialization -29923 +29922 for_stmt -29923 +29922 init_id -29923 +29922 @@ -36083,7 +36068,7 @@ 1 2 -29923 +29922 @@ -36099,7 +36084,7 @@ 1 2 -29923 +29922 @@ -36109,15 +36094,15 @@ for_condition -31782 +31781 for_stmt -31782 +31781 condition_id -31782 +31781 @@ -36131,7 +36116,7 @@ 1 2 -31782 +31781 @@ -36147,7 +36132,7 @@ 1 2 -31782 +31781 @@ -36205,15 +36190,15 @@ for_body -32388 +32387 for_stmt -32388 +32387 body_id -32388 +32387 @@ -36227,7 +36212,7 @@ 1 2 -32388 +32387 @@ -36243,7 +36228,7 @@ 1 2 -32388 +32387 @@ -36253,11 +36238,11 @@ stmtparents -4168362 +4168478 id -4168362 +4168478 index @@ -36265,7 +36250,7 @@ parent -1761835 +1762006 @@ -36279,7 +36264,7 @@ 1 2 -4168362 +4168478 @@ -36295,7 +36280,7 @@ 1 2 -4168362 +4168478 @@ -36355,7 +36340,7 @@ 74 -191964 +191996 777 @@ -36416,7 +36401,7 @@ 74 -191964 +191996 777 @@ -36433,27 +36418,27 @@ 1 2 -1004226 +1004414 2 3 -386611 +386602 3 4 -109345 +109343 4 6 -115442 +115439 6 17 -133389 +133386 17 @@ -36474,27 +36459,27 @@ 1 2 -1004226 +1004414 2 3 -386611 +386602 3 4 -109345 +109343 4 6 -115442 +115439 6 17 -133389 +133386 17 @@ -36689,11 +36674,11 @@ stmt_decl_bind -538245 +538233 stmt -531291 +531279 num @@ -36701,7 +36686,7 @@ decl -538245 +538233 @@ -36715,7 +36700,7 @@ 1 2 -525788 +525776 2 @@ -36736,7 +36721,7 @@ 1 2 -525768 +525756 2 @@ -36859,7 +36844,7 @@ 1 2 -538245 +538233 @@ -36875,7 +36860,7 @@ 1 2 -538245 +538233 @@ -37064,7 +37049,7 @@ enclosing -1254386 +1254459 @@ -37094,12 +37079,12 @@ 1 2 -1171648 +1171794 2 509 -82738 +82665 @@ -37893,11 +37878,11 @@ link_parent -19146066 +19146504 element -5077012 +5077231 link_target @@ -37920,7 +37905,7 @@ 2 3 -1904753 +1904972 3 @@ -38014,8 +37999,8 @@ 48 -345632 -345633 +345650 +345651 12 From 4606587fe855ecbee9f7b6dacdf5193ac743a100 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Mon, 23 Sep 2019 11:35:51 +0100 Subject: [PATCH 0201/1227] C++: Apply style guide to TypedefType.qll --- cpp/ql/src/semmle/code/cpp/TypedefType.qll | 23 ++++++++++------------ 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/TypedefType.qll b/cpp/ql/src/semmle/code/cpp/TypedefType.qll index 1616515bea1..1dfbc1f3f82 100644 --- a/cpp/ql/src/semmle/code/cpp/TypedefType.qll +++ b/cpp/ql/src/semmle/code/cpp/TypedefType.qll @@ -10,10 +10,9 @@ private import semmle.code.cpp.internal.ResolveClass * * UsingAliasTypedefType: using = ; */ class TypedefType extends UserType { - TypedefType() { - usertypes(underlyingElement(this),_,5) or - usertypes(underlyingElement(this),_,14) + usertypes(underlyingElement(this), _, 5) or + usertypes(underlyingElement(this), _, 14) } /** @@ -52,28 +51,26 @@ class TypedefType extends UserType { * A traditional C/C++ typedef type. See 4.9.1. */ class CTypedefType extends TypedefType { - - CTypedefType() { - usertypes(underlyingElement(this),_,5) - } + CTypedefType() { usertypes(underlyingElement(this), _, 5) } override string getCanonicalQLClass() { result = "CTypedefType" } - override string explain() { result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" } + override string explain() { + result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" + } } /** * A using alias C++ typedef type. */ class UsingAliasTypedefType extends TypedefType { - - UsingAliasTypedefType() { - usertypes(underlyingElement(this),_,14) - } + UsingAliasTypedefType() { usertypes(underlyingElement(this), _, 14) } override string getCanonicalQLClass() { result = "UsingAliasTypedefType" } - override string explain() { result = "using {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" } + override string explain() { + result = "using {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" + } } /** From cd5f3b84a8a9b62100ef4f697fa9740b911083ab Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 23 Sep 2019 14:51:59 +0200 Subject: [PATCH 0202/1227] C++: Make sure there's a Instruction for each Expr This change ensures that all `Expr`s (except parentheses) have a `TranslatedExpr` with a `getResult` that's one of its own instructions, not an instruction from one of its operands. This means that when we translate back and forth between `Expr` and `Instruction`, like in `DataFlow::exprNode`, we will not conflate `e` with `&e` or `... = e`. --- .../raw/internal/InstructionTag.qll | 1 + .../raw/internal/TranslatedElement.qll | 10 + .../raw/internal/TranslatedExpr.qll | 94 +- .../ir/escape/points_to.expected | 58 + .../test/library-tests/ir/ir/raw_ir.expected | 3207 +++++++++-------- .../ir/ssa/aliased_ssa_ir.expected | 141 +- .../ir/ssa/unaliased_ssa_ir.expected | 131 +- 7 files changed, 2072 insertions(+), 1570 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll index ddac5692cdf..c18ff827992 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll @@ -44,6 +44,7 @@ newtype TInstructionTag = ConditionValueResultLoadTag() or BoolConversionConstantTag() or BoolConversionCompareTag() or + ResultCopyTag() or LoadTag() or // Implicit load due to lvalue-to-rvalue conversion CatchTag() or ThrowTag() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 23d3036ca15..b9a6d4c737d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -8,6 +8,7 @@ private import InstructionTag private import TranslatedCondition private import TranslatedFunction private import TranslatedStmt +private import TranslatedExpr private import IRConstruction /** @@ -235,6 +236,15 @@ newtype TTranslatedElement = expr.hasLValueToRValueConversion() and not ignoreLoad(expr) } or + TTranslatedResultCopy(Expr expr) { + not ignoreExpr(expr) and + exprNeedsCopyIfNotLoaded(expr) and + // Doesn't have a TTranslatedLoad + not ( + expr.hasLValueToRValueConversion() and + not ignoreLoad(expr) + ) + } or // An expression most naturally translated as control flow. TTranslatedNativeCondition(Expr expr) { not ignoreExpr(expr) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index fa8eeb36adb..e9e7cf59cb0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -85,11 +85,14 @@ abstract class TranslatedCoreExpr extends TranslatedExpr { final override predicate producesExprResult() { // If there's no load, then this is the only TranslatedExpr for this // expression. - not expr.hasLValueToRValueConversion() - or - // If we're supposed to ignore the load on this expression, then this - // is the only TranslatedExpr. - ignoreLoad(expr) + not hasLoad() and + // If there's a result copy, then this expression's result is the copy. + not exprNeedsCopyIfNotLoaded(expr) + } + + private predicate hasLoad() { + expr.hasLValueToRValueConversion() and + not ignoreLoad(expr) } /** @@ -106,7 +109,7 @@ abstract class TranslatedCoreExpr extends TranslatedExpr { or // If this TranslatedExpr doesn't produce the result, then it must represent // a glvalue that is then loaded by a TranslatedLoad. - not producesExprResult() + hasLoad() then result = true else result = false } @@ -302,6 +305,51 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad { private TranslatedCoreExpr getOperand() { result.getExpr() = expr } } +/** + * IR translation of an implicit lvalue-to-rvalue conversion on the result of + * an expression. + */ +class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy { + TranslatedResultCopy() { this = TTranslatedResultCopy(expr) } + + override string toString() { result = "Result of " + expr.toString() } + + override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() } + + override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } + + override predicate hasInstruction( + Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue + ) { + tag = ResultCopyTag() and + opcode instanceof Opcode::CopyValue and + resultType = getOperand().getResultType() and + isGLValue = getOperand().isResultGLValue() + } + + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { + tag = ResultCopyTag() and + result = getParent().getChildSuccessor(this) and + kind instanceof GotoEdge + } + + override Instruction getChildSuccessor(TranslatedElement child) { + child = getOperand() and result = getInstruction(ResultCopyTag()) + } + + override Instruction getResult() { result = getInstruction(ResultCopyTag()) } + + override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + tag = ResultCopyTag() and + operandTag instanceof UnaryOperandTag and + result = getOperand().getResult() + } + + final override predicate producesExprResult() { any() } + + private TranslatedCoreExpr getOperand() { result.getExpr() = expr } +} + class TranslatedCommaExpr extends TranslatedNonConstantExpr { override CommaExpr expr; @@ -2485,3 +2533,37 @@ class TranslatedErrorExpr extends TranslatedSingleInstructionExpr { final override Opcode getOpcode() { result instanceof Opcode::Error } } + +/** + * Holds if the translation of `expr` will not directly generate any + * `Instruction` for use as result. For such instructions we can synthesize a + * `CopyValue` instruction to ensure that there is a 1-to-1 mapping between + * expressions and result-bearing instructions. + */ +// This should ideally be a dispatch predicate on TranslatedNonConstantExpr, +// but it doesn't look monotonic to QL. +predicate exprNeedsCopyIfNotLoaded(Expr expr) { + expr instanceof AssignExpr + or + expr instanceof AssignOperation and + not expr.isPRValueCategory() // is C++ + or + expr instanceof PrefixCrementOperation and + not expr.isPRValueCategory() // is C++ + or + expr instanceof PointerDereferenceExpr + or + expr instanceof AddressOfExpr + or + expr instanceof BuiltInOperationBuiltInAddressOf + // No case for ParenthesisExpr to avoid getting too many instructions + or + expr instanceof ReferenceDereferenceExpr + or + expr instanceof ReferenceToExpr + or + expr instanceof CommaExpr + or + expr instanceof ConditionDeclExpr + // TODO: simplify TranslatedStmtExpr too +} diff --git a/cpp/ql/test/library-tests/ir/escape/points_to.expected b/cpp/ql/test/library-tests/ir/escape/points_to.expected index f40460f4d91..e6fefda7bb5 100644 --- a/cpp/ql/test/library-tests/ir/escape/points_to.expected +++ b/cpp/ql/test/library-tests/ir/escape/points_to.expected @@ -1,47 +1,105 @@ +| escape.cpp:108:5:108:11 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:109:5:109:13 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:110:5:110:19 | CopyValue | no_result+0:0 | no_result+0:0 | +| escape.cpp:111:5:111:21 | CopyValue | no_result+0:0 | no_result+0:0 | +| escape.cpp:111:18:111:21 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:114:5:114:8 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:115:5:115:29 | CopyValue | no_result+0:0 | no_result+0:0 | | escape.cpp:115:19:115:28 | PointerAdd[4] | no_+0:0 | no_+0:0 | +| escape.cpp:115:20:115:23 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:116:5:116:29 | CopyValue | no_result+0:0 | no_result+0:0 | | escape.cpp:116:19:116:28 | PointerSub[4] | no_+0:0 | no_+0:0 | +| escape.cpp:116:20:116:23 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:117:5:117:27 | CopyValue | no_result+0:0 | no_result+0:0 | | escape.cpp:117:19:117:26 | PointerAdd[4] | no_+0:0 | no_+0:0 | +| escape.cpp:117:23:117:26 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:118:9:118:12 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:120:12:120:15 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:123:14:123:17 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:124:9:124:12 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:124:15:124:18 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:124:21:124:24 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:127:9:127:12 | CopyValue | no_+0:0 | no_+0:0 | +| escape.cpp:129:12:129:15 | CopyValue | no_+0:0 | no_+0:0 | | escape.cpp:134:5:134:18 | Convert | no_Array+0:0 | no_Array+0:0 | | escape.cpp:134:11:134:18 | Convert | no_Array+0:0 | no_Array+0:0 | | escape.cpp:135:5:135:12 | Convert | no_Array+0:0 | no_Array+0:0 | | escape.cpp:135:5:135:15 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 | | escape.cpp:136:5:136:15 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 | | escape.cpp:136:7:136:14 | Convert | no_Array+0:0 | no_Array+0:0 | +| escape.cpp:137:5:137:27 | CopyValue | no_result+0:0 | no_result+0:0 | | escape.cpp:137:17:137:24 | Convert | no_Array+0:0 | no_Array+0:0 | | escape.cpp:137:17:137:27 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 | +| escape.cpp:138:5:138:27 | CopyValue | no_result+0:0 | no_result+0:0 | | escape.cpp:138:17:138:27 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 | | escape.cpp:138:19:138:26 | Convert | no_Array+0:0 | no_Array+0:0 | | escape.cpp:140:21:140:32 | FieldAddress[x] | no_Point+0:0 | no_Point+0:0 | | escape.cpp:140:21:140:32 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 | | escape.cpp:140:21:140:32 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 | | escape.cpp:141:27:141:27 | FieldAddress[x] | no_Point+0:0 | no_Point+0:0 | +| escape.cpp:142:5:142:21 | CopyValue | no_Point+4:0 | no_Point+4:0 | | escape.cpp:142:14:142:14 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 | +| escape.cpp:143:19:143:27 | CopyValue | no_Point+0:0 | no_Point+0:0 | | escape.cpp:143:31:143:31 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 | +| escape.cpp:144:5:144:25 | CopyValue | no_Point+4:0 | no_Point+4:0 | +| escape.cpp:144:6:144:14 | CopyValue | no_Point+0:0 | no_Point+0:0 | | escape.cpp:144:18:144:18 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 | +| escape.cpp:145:20:145:30 | CopyValue | no_Point+8:0 | no_Point+8:0 | | escape.cpp:145:30:145:30 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 | +| escape.cpp:146:5:146:18 | CopyValue | no_Point+8:0 | no_Point+8:0 | +| escape.cpp:146:5:146:25 | CopyValue | no_Point+8:0 | no_Point+8:0 | +| escape.cpp:146:7:146:17 | CopyValue | no_Point+8:0 | no_Point+8:0 | | escape.cpp:146:17:146:17 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 | | escape.cpp:149:5:149:14 | ConvertToBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 | | escape.cpp:149:5:149:14 | ConvertToBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 | +| escape.cpp:149:5:149:20 | CopyValue | no_Derived+0:0 | no_Derived+0:0 | | escape.cpp:149:16:149:16 | FieldAddress[b] | no_Derived+0:0 | no_Derived+0:0 | | escape.cpp:150:18:150:27 | ConvertToBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 | | escape.cpp:150:18:150:27 | ConvertToBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 | | escape.cpp:150:29:150:29 | FieldAddress[b] | no_Derived+0:0 | no_Derived+0:0 | | escape.cpp:151:5:151:14 | ConvertToBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 | +| escape.cpp:151:5:151:21 | CopyValue | no_Derived+16:0 | no_Derived+16:0 | | escape.cpp:151:16:151:17 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 | | escape.cpp:152:19:152:28 | ConvertToBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 | | escape.cpp:152:30:152:31 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 | +| escape.cpp:155:17:155:30 | CopyValue | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 | | escape.cpp:155:17:155:30 | Store | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 | +| escape.cpp:158:17:158:28 | CopyValue | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 | | escape.cpp:158:17:158:28 | Store | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 | | escape.cpp:161:19:161:42 | Convert | no_ssa_refToArrayElement+0:0 | no_ssa_refToArrayElement+0:0 | +| escape.cpp:161:19:161:45 | CopyValue | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 | | escape.cpp:161:19:161:45 | PointerAdd[4] | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 | | escape.cpp:161:19:161:45 | Store | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 | +| escape.cpp:164:24:164:40 | CopyValue | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 | | escape.cpp:164:24:164:40 | Store | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 | +| escape.cpp:167:19:167:28 | CopyValue | passByPtr+0:0 | passByPtr+0:0 | +| escape.cpp:170:21:170:29 | CopyValue | passByRef+0:0 | passByRef+0:0 | +| escape.cpp:173:22:173:38 | CopyValue | no_ssa_passByPtr+0:0 | no_ssa_passByPtr+0:0 | +| escape.cpp:176:24:176:39 | CopyValue | no_ssa_passByRef+0:0 | no_ssa_passByRef+0:0 | +| escape.cpp:179:22:179:42 | CopyValue | no_ssa_passByPtr_ret+0:0 | no_ssa_passByPtr_ret+0:0 | +| escape.cpp:182:24:182:43 | CopyValue | no_ssa_passByRef_ret+0:0 | no_ssa_passByRef_ret+0:0 | +| escape.cpp:185:30:185:40 | CopyValue | passByPtr2+0:0 | passByPtr2+0:0 | +| escape.cpp:188:32:188:41 | CopyValue | passByRef2+0:0 | passByRef2+0:0 | | escape.cpp:191:30:191:42 | Call | none | passByPtr3+0:0 | +| escape.cpp:191:44:191:54 | CopyValue | passByPtr3+0:0 | passByPtr3+0:0 | | escape.cpp:194:32:194:46 | Call | none | passByRef3+0:0 | +| escape.cpp:194:32:194:59 | CopyValue | none | passByRef3+0:0 | +| escape.cpp:194:48:194:57 | CopyValue | passByRef3+0:0 | passByRef3+0:0 | +| escape.cpp:199:17:199:34 | CopyValue | no_ssa_passByPtr4+0:0 | no_ssa_passByPtr4+0:0 | +| escape.cpp:199:37:199:54 | CopyValue | no_ssa_passByPtr5+0:0 | no_ssa_passByPtr5+0:0 | | escape.cpp:202:5:202:19 | Call | none | passByRef6+0:0 | +| escape.cpp:202:5:202:32 | CopyValue | none | passByRef6+0:0 | +| escape.cpp:202:21:202:30 | CopyValue | passByRef6+0:0 | passByRef6+0:0 | | escape.cpp:205:5:205:19 | Call | none | no_ssa_passByRef7+0:0 | +| escape.cpp:205:5:205:39 | CopyValue | none | no_ssa_passByRef7+0:0 | +| escape.cpp:205:21:205:37 | CopyValue | no_ssa_passByRef7+0:0 | no_ssa_passByRef7+0:0 | | escape.cpp:209:14:209:25 | Call | none | no_ssa_c+0:0 | +| escape.cpp:217:14:217:16 | CopyValue | c2+0:0 | c2+0:0 | | escape.cpp:221:8:221:19 | Call | none | c3+0:0 | | escape.cpp:225:17:225:28 | Call | none | c4+0:0 | +| escape.cpp:247:2:247:27 | CopyValue | no_condTemp+0:0 | no_condTemp+0:0 | | escape.cpp:247:2:247:27 | Store | condEscape1+0:0 | condEscape1+0:0 | +| escape.cpp:247:16:247:27 | CopyValue | condEscape1+0:0 | condEscape1+0:0 | +| escape.cpp:249:9:249:34 | CopyValue | no_condTemp+0:0 | no_condTemp+0:0 | | escape.cpp:249:9:249:34 | Store | condEscape2+0:0 | condEscape2+0:0 | +| escape.cpp:249:23:249:34 | CopyValue | condEscape2+0:0 | condEscape2+0:0 | diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 20f15e4f772..788e4a72663 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -40,13 +40,14 @@ bad_asts.cpp: # 27| r0_5(glval) = VariableAddress[b] : # 27| r0_6(glval) = VariableAddress[a] : # 27| r0_7(Point &) = Load : &:r0_6, ~mu0_2 -# 27| r0_8(glval) = Convert : r0_7 -# 27| r0_9(Point) = Load : &:r0_8, ~mu0_2 -# 27| mu0_10(Point) = Store : &:r0_5, r0_9 -# 28| v0_11(void) = NoOp : -# 26| v0_12(void) = ReturnVoid : -# 26| v0_13(void) = UnmodeledUse : mu* -# 26| v0_14(void) = ExitFunction : +# 27| r0_8(glval) = CopyValue : r0_7 +# 27| r0_9(glval) = Convert : r0_8 +# 27| r0_10(Point) = Load : &:r0_9, ~mu0_2 +# 27| mu0_11(Point) = Store : &:r0_5, r0_10 +# 28| v0_12(void) = NoOp : +# 26| v0_13(void) = ReturnVoid : +# 26| v0_14(void) = UnmodeledUse : mu* +# 26| v0_15(void) = ExitFunction : # 30| void Bad::errorExpr() # 30| Block 0 @@ -63,10 +64,11 @@ bad_asts.cpp: #-----| r0_10(error) = Load : &:r0_9, ~mu0_2 # 33| r0_11(glval) = VariableAddress[x] : # 33| mu0_12(int) = Store : &:r0_11, r0_10 -# 34| v0_13(void) = NoOp : -# 30| v0_14(void) = ReturnVoid : -# 30| v0_15(void) = UnmodeledUse : mu* -# 30| v0_16(void) = ExitFunction : +# 33| r0_13(glval) = CopyValue : r0_11 +# 34| v0_14(void) = NoOp : +# 30| v0_15(void) = ReturnVoid : +# 30| v0_16(void) = UnmodeledUse : mu* +# 30| v0_17(void) = ExitFunction : clang.cpp: # 5| int* globalIntAddress() @@ -76,11 +78,12 @@ clang.cpp: # 5| mu0_2(unknown) = UnmodeledDefinition : # 6| r0_3(glval) = VariableAddress[#return] : # 6| r0_4(glval) = VariableAddress[globalInt] : -# 6| mu0_5(int *) = Store : &:r0_3, r0_4 -# 5| r0_6(glval) = VariableAddress[#return] : -# 5| v0_7(void) = ReturnValue : &:r0_6, ~mu0_2 -# 5| v0_8(void) = UnmodeledUse : mu* -# 5| v0_9(void) = ExitFunction : +# 6| r0_5(int *) = CopyValue : r0_4 +# 6| mu0_6(int *) = Store : &:r0_3, r0_5 +# 5| r0_7(glval) = VariableAddress[#return] : +# 5| v0_8(void) = ReturnValue : &:r0_7, ~mu0_2 +# 5| v0_9(void) = UnmodeledUse : mu* +# 5| v0_10(void) = ExitFunction : ir.cpp: # 1| void Constants() @@ -197,18 +200,20 @@ ir.cpp: # 46| r0_15(short) = Convert : r0_14 # 46| r0_16(glval) = VariableAddress[y] : # 46| mu0_17(short) = Store : &:r0_16, r0_15 -# 47| r0_18(glval) = VariableAddress[x] : -# 47| r0_19(int) = Load : &:r0_18, ~mu0_2 -# 47| r0_20(glval) = VariableAddress[y] : -# 47| r0_21(short) = Load : &:r0_20, ~mu0_2 -# 47| r0_22(int) = Convert : r0_21 -# 47| r0_23(int) = Mul : r0_19, r0_22 -# 47| r0_24(glval) = VariableAddress[x] : -# 47| mu0_25(int) = Store : &:r0_24, r0_23 -# 48| v0_26(void) = NoOp : -# 43| v0_27(void) = ReturnVoid : -# 43| v0_28(void) = UnmodeledUse : mu* -# 43| v0_29(void) = ExitFunction : +# 46| r0_18(glval) = CopyValue : r0_16 +# 47| r0_19(glval) = VariableAddress[x] : +# 47| r0_20(int) = Load : &:r0_19, ~mu0_2 +# 47| r0_21(glval) = VariableAddress[y] : +# 47| r0_22(short) = Load : &:r0_21, ~mu0_2 +# 47| r0_23(int) = Convert : r0_22 +# 47| r0_24(int) = Mul : r0_20, r0_23 +# 47| r0_25(glval) = VariableAddress[x] : +# 47| mu0_26(int) = Store : &:r0_25, r0_24 +# 47| r0_27(glval) = CopyValue : r0_25 +# 48| v0_28(void) = NoOp : +# 43| v0_29(void) = ReturnVoid : +# 43| v0_30(void) = UnmodeledUse : mu* +# 43| v0_31(void) = ExitFunction : # 50| void IntegerOps(int, int) # 50| Block 0 @@ -228,160 +233,185 @@ ir.cpp: # 53| r0_13(int) = Add : r0_10, r0_12 # 53| r0_14(glval) = VariableAddress[z] : # 53| mu0_15(int) = Store : &:r0_14, r0_13 -# 54| r0_16(glval) = VariableAddress[x] : -# 54| r0_17(int) = Load : &:r0_16, ~mu0_2 -# 54| r0_18(glval) = VariableAddress[y] : -# 54| r0_19(int) = Load : &:r0_18, ~mu0_2 -# 54| r0_20(int) = Sub : r0_17, r0_19 -# 54| r0_21(glval) = VariableAddress[z] : -# 54| mu0_22(int) = Store : &:r0_21, r0_20 -# 55| r0_23(glval) = VariableAddress[x] : -# 55| r0_24(int) = Load : &:r0_23, ~mu0_2 -# 55| r0_25(glval) = VariableAddress[y] : +# 53| r0_16(glval) = CopyValue : r0_14 +# 54| r0_17(glval) = VariableAddress[x] : +# 54| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 54| r0_19(glval) = VariableAddress[y] : +# 54| r0_20(int) = Load : &:r0_19, ~mu0_2 +# 54| r0_21(int) = Sub : r0_18, r0_20 +# 54| r0_22(glval) = VariableAddress[z] : +# 54| mu0_23(int) = Store : &:r0_22, r0_21 +# 54| r0_24(glval) = CopyValue : r0_22 +# 55| r0_25(glval) = VariableAddress[x] : # 55| r0_26(int) = Load : &:r0_25, ~mu0_2 -# 55| r0_27(int) = Mul : r0_24, r0_26 -# 55| r0_28(glval) = VariableAddress[z] : -# 55| mu0_29(int) = Store : &:r0_28, r0_27 -# 56| r0_30(glval) = VariableAddress[x] : -# 56| r0_31(int) = Load : &:r0_30, ~mu0_2 -# 56| r0_32(glval) = VariableAddress[y] : -# 56| r0_33(int) = Load : &:r0_32, ~mu0_2 -# 56| r0_34(int) = Div : r0_31, r0_33 -# 56| r0_35(glval) = VariableAddress[z] : -# 56| mu0_36(int) = Store : &:r0_35, r0_34 -# 57| r0_37(glval) = VariableAddress[x] : -# 57| r0_38(int) = Load : &:r0_37, ~mu0_2 -# 57| r0_39(glval) = VariableAddress[y] : -# 57| r0_40(int) = Load : &:r0_39, ~mu0_2 -# 57| r0_41(int) = Rem : r0_38, r0_40 -# 57| r0_42(glval) = VariableAddress[z] : -# 57| mu0_43(int) = Store : &:r0_42, r0_41 -# 59| r0_44(glval) = VariableAddress[x] : -# 59| r0_45(int) = Load : &:r0_44, ~mu0_2 -# 59| r0_46(glval) = VariableAddress[y] : -# 59| r0_47(int) = Load : &:r0_46, ~mu0_2 -# 59| r0_48(int) = BitAnd : r0_45, r0_47 -# 59| r0_49(glval) = VariableAddress[z] : -# 59| mu0_50(int) = Store : &:r0_49, r0_48 -# 60| r0_51(glval) = VariableAddress[x] : -# 60| r0_52(int) = Load : &:r0_51, ~mu0_2 -# 60| r0_53(glval) = VariableAddress[y] : -# 60| r0_54(int) = Load : &:r0_53, ~mu0_2 -# 60| r0_55(int) = BitOr : r0_52, r0_54 -# 60| r0_56(glval) = VariableAddress[z] : -# 60| mu0_57(int) = Store : &:r0_56, r0_55 -# 61| r0_58(glval) = VariableAddress[x] : -# 61| r0_59(int) = Load : &:r0_58, ~mu0_2 -# 61| r0_60(glval) = VariableAddress[y] : -# 61| r0_61(int) = Load : &:r0_60, ~mu0_2 -# 61| r0_62(int) = BitXor : r0_59, r0_61 -# 61| r0_63(glval) = VariableAddress[z] : -# 61| mu0_64(int) = Store : &:r0_63, r0_62 -# 63| r0_65(glval) = VariableAddress[x] : -# 63| r0_66(int) = Load : &:r0_65, ~mu0_2 -# 63| r0_67(glval) = VariableAddress[y] : -# 63| r0_68(int) = Load : &:r0_67, ~mu0_2 -# 63| r0_69(int) = ShiftLeft : r0_66, r0_68 -# 63| r0_70(glval) = VariableAddress[z] : -# 63| mu0_71(int) = Store : &:r0_70, r0_69 -# 64| r0_72(glval) = VariableAddress[x] : -# 64| r0_73(int) = Load : &:r0_72, ~mu0_2 -# 64| r0_74(glval) = VariableAddress[y] : -# 64| r0_75(int) = Load : &:r0_74, ~mu0_2 -# 64| r0_76(int) = ShiftRight : r0_73, r0_75 -# 64| r0_77(glval) = VariableAddress[z] : -# 64| mu0_78(int) = Store : &:r0_77, r0_76 -# 66| r0_79(glval) = VariableAddress[x] : -# 66| r0_80(int) = Load : &:r0_79, ~mu0_2 -# 66| r0_81(glval) = VariableAddress[z] : -# 66| mu0_82(int) = Store : &:r0_81, r0_80 -# 68| r0_83(glval) = VariableAddress[x] : -# 68| r0_84(int) = Load : &:r0_83, ~mu0_2 -# 68| r0_85(glval) = VariableAddress[z] : -# 68| r0_86(int) = Load : &:r0_85, ~mu0_2 -# 68| r0_87(int) = Add : r0_86, r0_84 -# 68| mu0_88(int) = Store : &:r0_85, r0_87 -# 69| r0_89(glval) = VariableAddress[x] : -# 69| r0_90(int) = Load : &:r0_89, ~mu0_2 -# 69| r0_91(glval) = VariableAddress[z] : -# 69| r0_92(int) = Load : &:r0_91, ~mu0_2 -# 69| r0_93(int) = Sub : r0_92, r0_90 -# 69| mu0_94(int) = Store : &:r0_91, r0_93 -# 70| r0_95(glval) = VariableAddress[x] : -# 70| r0_96(int) = Load : &:r0_95, ~mu0_2 -# 70| r0_97(glval) = VariableAddress[z] : -# 70| r0_98(int) = Load : &:r0_97, ~mu0_2 -# 70| r0_99(int) = Mul : r0_98, r0_96 -# 70| mu0_100(int) = Store : &:r0_97, r0_99 -# 71| r0_101(glval) = VariableAddress[x] : -# 71| r0_102(int) = Load : &:r0_101, ~mu0_2 -# 71| r0_103(glval) = VariableAddress[z] : -# 71| r0_104(int) = Load : &:r0_103, ~mu0_2 -# 71| r0_105(int) = Div : r0_104, r0_102 -# 71| mu0_106(int) = Store : &:r0_103, r0_105 -# 72| r0_107(glval) = VariableAddress[x] : -# 72| r0_108(int) = Load : &:r0_107, ~mu0_2 -# 72| r0_109(glval) = VariableAddress[z] : -# 72| r0_110(int) = Load : &:r0_109, ~mu0_2 -# 72| r0_111(int) = Rem : r0_110, r0_108 -# 72| mu0_112(int) = Store : &:r0_109, r0_111 -# 74| r0_113(glval) = VariableAddress[x] : -# 74| r0_114(int) = Load : &:r0_113, ~mu0_2 -# 74| r0_115(glval) = VariableAddress[z] : -# 74| r0_116(int) = Load : &:r0_115, ~mu0_2 -# 74| r0_117(int) = BitAnd : r0_116, r0_114 -# 74| mu0_118(int) = Store : &:r0_115, r0_117 -# 75| r0_119(glval) = VariableAddress[x] : -# 75| r0_120(int) = Load : &:r0_119, ~mu0_2 -# 75| r0_121(glval) = VariableAddress[z] : -# 75| r0_122(int) = Load : &:r0_121, ~mu0_2 -# 75| r0_123(int) = BitOr : r0_122, r0_120 -# 75| mu0_124(int) = Store : &:r0_121, r0_123 -# 76| r0_125(glval) = VariableAddress[x] : -# 76| r0_126(int) = Load : &:r0_125, ~mu0_2 -# 76| r0_127(glval) = VariableAddress[z] : -# 76| r0_128(int) = Load : &:r0_127, ~mu0_2 -# 76| r0_129(int) = BitXor : r0_128, r0_126 -# 76| mu0_130(int) = Store : &:r0_127, r0_129 -# 78| r0_131(glval) = VariableAddress[x] : -# 78| r0_132(int) = Load : &:r0_131, ~mu0_2 -# 78| r0_133(glval) = VariableAddress[z] : -# 78| r0_134(int) = Load : &:r0_133, ~mu0_2 -# 78| r0_135(int) = ShiftLeft : r0_134, r0_132 -# 78| mu0_136(int) = Store : &:r0_133, r0_135 -# 79| r0_137(glval) = VariableAddress[x] : -# 79| r0_138(int) = Load : &:r0_137, ~mu0_2 -# 79| r0_139(glval) = VariableAddress[z] : -# 79| r0_140(int) = Load : &:r0_139, ~mu0_2 -# 79| r0_141(int) = ShiftRight : r0_140, r0_138 -# 79| mu0_142(int) = Store : &:r0_139, r0_141 -# 81| r0_143(glval) = VariableAddress[x] : -# 81| r0_144(int) = Load : &:r0_143, ~mu0_2 -# 81| r0_145(int) = CopyValue : r0_144 -# 81| r0_146(glval) = VariableAddress[z] : -# 81| mu0_147(int) = Store : &:r0_146, r0_145 -# 82| r0_148(glval) = VariableAddress[x] : -# 82| r0_149(int) = Load : &:r0_148, ~mu0_2 -# 82| r0_150(int) = Negate : r0_149 -# 82| r0_151(glval) = VariableAddress[z] : -# 82| mu0_152(int) = Store : &:r0_151, r0_150 -# 83| r0_153(glval) = VariableAddress[x] : -# 83| r0_154(int) = Load : &:r0_153, ~mu0_2 -# 83| r0_155(int) = BitComplement : r0_154 -# 83| r0_156(glval) = VariableAddress[z] : -# 83| mu0_157(int) = Store : &:r0_156, r0_155 -# 84| r0_158(glval) = VariableAddress[x] : -# 84| r0_159(int) = Load : &:r0_158, ~mu0_2 -# 84| r0_160(int) = Constant[0] : -# 84| r0_161(bool) = CompareNE : r0_159, r0_160 -# 84| r0_162(bool) = LogicalNot : r0_161 -# 84| r0_163(int) = Convert : r0_162 -# 84| r0_164(glval) = VariableAddress[z] : -# 84| mu0_165(int) = Store : &:r0_164, r0_163 -# 85| v0_166(void) = NoOp : -# 50| v0_167(void) = ReturnVoid : -# 50| v0_168(void) = UnmodeledUse : mu* -# 50| v0_169(void) = ExitFunction : +# 55| r0_27(glval) = VariableAddress[y] : +# 55| r0_28(int) = Load : &:r0_27, ~mu0_2 +# 55| r0_29(int) = Mul : r0_26, r0_28 +# 55| r0_30(glval) = VariableAddress[z] : +# 55| mu0_31(int) = Store : &:r0_30, r0_29 +# 55| r0_32(glval) = CopyValue : r0_30 +# 56| r0_33(glval) = VariableAddress[x] : +# 56| r0_34(int) = Load : &:r0_33, ~mu0_2 +# 56| r0_35(glval) = VariableAddress[y] : +# 56| r0_36(int) = Load : &:r0_35, ~mu0_2 +# 56| r0_37(int) = Div : r0_34, r0_36 +# 56| r0_38(glval) = VariableAddress[z] : +# 56| mu0_39(int) = Store : &:r0_38, r0_37 +# 56| r0_40(glval) = CopyValue : r0_38 +# 57| r0_41(glval) = VariableAddress[x] : +# 57| r0_42(int) = Load : &:r0_41, ~mu0_2 +# 57| r0_43(glval) = VariableAddress[y] : +# 57| r0_44(int) = Load : &:r0_43, ~mu0_2 +# 57| r0_45(int) = Rem : r0_42, r0_44 +# 57| r0_46(glval) = VariableAddress[z] : +# 57| mu0_47(int) = Store : &:r0_46, r0_45 +# 57| r0_48(glval) = CopyValue : r0_46 +# 59| r0_49(glval) = VariableAddress[x] : +# 59| r0_50(int) = Load : &:r0_49, ~mu0_2 +# 59| r0_51(glval) = VariableAddress[y] : +# 59| r0_52(int) = Load : &:r0_51, ~mu0_2 +# 59| r0_53(int) = BitAnd : r0_50, r0_52 +# 59| r0_54(glval) = VariableAddress[z] : +# 59| mu0_55(int) = Store : &:r0_54, r0_53 +# 59| r0_56(glval) = CopyValue : r0_54 +# 60| r0_57(glval) = VariableAddress[x] : +# 60| r0_58(int) = Load : &:r0_57, ~mu0_2 +# 60| r0_59(glval) = VariableAddress[y] : +# 60| r0_60(int) = Load : &:r0_59, ~mu0_2 +# 60| r0_61(int) = BitOr : r0_58, r0_60 +# 60| r0_62(glval) = VariableAddress[z] : +# 60| mu0_63(int) = Store : &:r0_62, r0_61 +# 60| r0_64(glval) = CopyValue : r0_62 +# 61| r0_65(glval) = VariableAddress[x] : +# 61| r0_66(int) = Load : &:r0_65, ~mu0_2 +# 61| r0_67(glval) = VariableAddress[y] : +# 61| r0_68(int) = Load : &:r0_67, ~mu0_2 +# 61| r0_69(int) = BitXor : r0_66, r0_68 +# 61| r0_70(glval) = VariableAddress[z] : +# 61| mu0_71(int) = Store : &:r0_70, r0_69 +# 61| r0_72(glval) = CopyValue : r0_70 +# 63| r0_73(glval) = VariableAddress[x] : +# 63| r0_74(int) = Load : &:r0_73, ~mu0_2 +# 63| r0_75(glval) = VariableAddress[y] : +# 63| r0_76(int) = Load : &:r0_75, ~mu0_2 +# 63| r0_77(int) = ShiftLeft : r0_74, r0_76 +# 63| r0_78(glval) = VariableAddress[z] : +# 63| mu0_79(int) = Store : &:r0_78, r0_77 +# 63| r0_80(glval) = CopyValue : r0_78 +# 64| r0_81(glval) = VariableAddress[x] : +# 64| r0_82(int) = Load : &:r0_81, ~mu0_2 +# 64| r0_83(glval) = VariableAddress[y] : +# 64| r0_84(int) = Load : &:r0_83, ~mu0_2 +# 64| r0_85(int) = ShiftRight : r0_82, r0_84 +# 64| r0_86(glval) = VariableAddress[z] : +# 64| mu0_87(int) = Store : &:r0_86, r0_85 +# 64| r0_88(glval) = CopyValue : r0_86 +# 66| r0_89(glval) = VariableAddress[x] : +# 66| r0_90(int) = Load : &:r0_89, ~mu0_2 +# 66| r0_91(glval) = VariableAddress[z] : +# 66| mu0_92(int) = Store : &:r0_91, r0_90 +# 66| r0_93(glval) = CopyValue : r0_91 +# 68| r0_94(glval) = VariableAddress[x] : +# 68| r0_95(int) = Load : &:r0_94, ~mu0_2 +# 68| r0_96(glval) = VariableAddress[z] : +# 68| r0_97(int) = Load : &:r0_96, ~mu0_2 +# 68| r0_98(int) = Add : r0_97, r0_95 +# 68| mu0_99(int) = Store : &:r0_96, r0_98 +# 68| r0_100(glval) = CopyValue : r0_96 +# 69| r0_101(glval) = VariableAddress[x] : +# 69| r0_102(int) = Load : &:r0_101, ~mu0_2 +# 69| r0_103(glval) = VariableAddress[z] : +# 69| r0_104(int) = Load : &:r0_103, ~mu0_2 +# 69| r0_105(int) = Sub : r0_104, r0_102 +# 69| mu0_106(int) = Store : &:r0_103, r0_105 +# 69| r0_107(glval) = CopyValue : r0_103 +# 70| r0_108(glval) = VariableAddress[x] : +# 70| r0_109(int) = Load : &:r0_108, ~mu0_2 +# 70| r0_110(glval) = VariableAddress[z] : +# 70| r0_111(int) = Load : &:r0_110, ~mu0_2 +# 70| r0_112(int) = Mul : r0_111, r0_109 +# 70| mu0_113(int) = Store : &:r0_110, r0_112 +# 70| r0_114(glval) = CopyValue : r0_110 +# 71| r0_115(glval) = VariableAddress[x] : +# 71| r0_116(int) = Load : &:r0_115, ~mu0_2 +# 71| r0_117(glval) = VariableAddress[z] : +# 71| r0_118(int) = Load : &:r0_117, ~mu0_2 +# 71| r0_119(int) = Div : r0_118, r0_116 +# 71| mu0_120(int) = Store : &:r0_117, r0_119 +# 71| r0_121(glval) = CopyValue : r0_117 +# 72| r0_122(glval) = VariableAddress[x] : +# 72| r0_123(int) = Load : &:r0_122, ~mu0_2 +# 72| r0_124(glval) = VariableAddress[z] : +# 72| r0_125(int) = Load : &:r0_124, ~mu0_2 +# 72| r0_126(int) = Rem : r0_125, r0_123 +# 72| mu0_127(int) = Store : &:r0_124, r0_126 +# 72| r0_128(glval) = CopyValue : r0_124 +# 74| r0_129(glval) = VariableAddress[x] : +# 74| r0_130(int) = Load : &:r0_129, ~mu0_2 +# 74| r0_131(glval) = VariableAddress[z] : +# 74| r0_132(int) = Load : &:r0_131, ~mu0_2 +# 74| r0_133(int) = BitAnd : r0_132, r0_130 +# 74| mu0_134(int) = Store : &:r0_131, r0_133 +# 74| r0_135(glval) = CopyValue : r0_131 +# 75| r0_136(glval) = VariableAddress[x] : +# 75| r0_137(int) = Load : &:r0_136, ~mu0_2 +# 75| r0_138(glval) = VariableAddress[z] : +# 75| r0_139(int) = Load : &:r0_138, ~mu0_2 +# 75| r0_140(int) = BitOr : r0_139, r0_137 +# 75| mu0_141(int) = Store : &:r0_138, r0_140 +# 75| r0_142(glval) = CopyValue : r0_138 +# 76| r0_143(glval) = VariableAddress[x] : +# 76| r0_144(int) = Load : &:r0_143, ~mu0_2 +# 76| r0_145(glval) = VariableAddress[z] : +# 76| r0_146(int) = Load : &:r0_145, ~mu0_2 +# 76| r0_147(int) = BitXor : r0_146, r0_144 +# 76| mu0_148(int) = Store : &:r0_145, r0_147 +# 76| r0_149(glval) = CopyValue : r0_145 +# 78| r0_150(glval) = VariableAddress[x] : +# 78| r0_151(int) = Load : &:r0_150, ~mu0_2 +# 78| r0_152(glval) = VariableAddress[z] : +# 78| r0_153(int) = Load : &:r0_152, ~mu0_2 +# 78| r0_154(int) = ShiftLeft : r0_153, r0_151 +# 78| mu0_155(int) = Store : &:r0_152, r0_154 +# 78| r0_156(glval) = CopyValue : r0_152 +# 79| r0_157(glval) = VariableAddress[x] : +# 79| r0_158(int) = Load : &:r0_157, ~mu0_2 +# 79| r0_159(glval) = VariableAddress[z] : +# 79| r0_160(int) = Load : &:r0_159, ~mu0_2 +# 79| r0_161(int) = ShiftRight : r0_160, r0_158 +# 79| mu0_162(int) = Store : &:r0_159, r0_161 +# 79| r0_163(glval) = CopyValue : r0_159 +# 81| r0_164(glval) = VariableAddress[x] : +# 81| r0_165(int) = Load : &:r0_164, ~mu0_2 +# 81| r0_166(int) = CopyValue : r0_165 +# 81| r0_167(glval) = VariableAddress[z] : +# 81| mu0_168(int) = Store : &:r0_167, r0_166 +# 81| r0_169(glval) = CopyValue : r0_167 +# 82| r0_170(glval) = VariableAddress[x] : +# 82| r0_171(int) = Load : &:r0_170, ~mu0_2 +# 82| r0_172(int) = Negate : r0_171 +# 82| r0_173(glval) = VariableAddress[z] : +# 82| mu0_174(int) = Store : &:r0_173, r0_172 +# 82| r0_175(glval) = CopyValue : r0_173 +# 83| r0_176(glval) = VariableAddress[x] : +# 83| r0_177(int) = Load : &:r0_176, ~mu0_2 +# 83| r0_178(int) = BitComplement : r0_177 +# 83| r0_179(glval) = VariableAddress[z] : +# 83| mu0_180(int) = Store : &:r0_179, r0_178 +# 83| r0_181(glval) = CopyValue : r0_179 +# 84| r0_182(glval) = VariableAddress[x] : +# 84| r0_183(int) = Load : &:r0_182, ~mu0_2 +# 84| r0_184(int) = Constant[0] : +# 84| r0_185(bool) = CompareNE : r0_183, r0_184 +# 84| r0_186(bool) = LogicalNot : r0_185 +# 84| r0_187(int) = Convert : r0_186 +# 84| r0_188(glval) = VariableAddress[z] : +# 84| mu0_189(int) = Store : &:r0_188, r0_187 +# 84| r0_190(glval) = CopyValue : r0_188 +# 85| v0_191(void) = NoOp : +# 50| v0_192(void) = ReturnVoid : +# 50| v0_193(void) = UnmodeledUse : mu* +# 50| v0_194(void) = ExitFunction : # 87| void IntegerCompare(int, int) # 87| Block 0 @@ -401,45 +431,51 @@ ir.cpp: # 90| r0_13(bool) = CompareEQ : r0_10, r0_12 # 90| r0_14(glval) = VariableAddress[b] : # 90| mu0_15(bool) = Store : &:r0_14, r0_13 -# 91| r0_16(glval) = VariableAddress[x] : -# 91| r0_17(int) = Load : &:r0_16, ~mu0_2 -# 91| r0_18(glval) = VariableAddress[y] : -# 91| r0_19(int) = Load : &:r0_18, ~mu0_2 -# 91| r0_20(bool) = CompareNE : r0_17, r0_19 -# 91| r0_21(glval) = VariableAddress[b] : -# 91| mu0_22(bool) = Store : &:r0_21, r0_20 -# 92| r0_23(glval) = VariableAddress[x] : -# 92| r0_24(int) = Load : &:r0_23, ~mu0_2 -# 92| r0_25(glval) = VariableAddress[y] : +# 90| r0_16(glval) = CopyValue : r0_14 +# 91| r0_17(glval) = VariableAddress[x] : +# 91| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 91| r0_19(glval) = VariableAddress[y] : +# 91| r0_20(int) = Load : &:r0_19, ~mu0_2 +# 91| r0_21(bool) = CompareNE : r0_18, r0_20 +# 91| r0_22(glval) = VariableAddress[b] : +# 91| mu0_23(bool) = Store : &:r0_22, r0_21 +# 91| r0_24(glval) = CopyValue : r0_22 +# 92| r0_25(glval) = VariableAddress[x] : # 92| r0_26(int) = Load : &:r0_25, ~mu0_2 -# 92| r0_27(bool) = CompareLT : r0_24, r0_26 -# 92| r0_28(glval) = VariableAddress[b] : -# 92| mu0_29(bool) = Store : &:r0_28, r0_27 -# 93| r0_30(glval) = VariableAddress[x] : -# 93| r0_31(int) = Load : &:r0_30, ~mu0_2 -# 93| r0_32(glval) = VariableAddress[y] : -# 93| r0_33(int) = Load : &:r0_32, ~mu0_2 -# 93| r0_34(bool) = CompareGT : r0_31, r0_33 -# 93| r0_35(glval) = VariableAddress[b] : -# 93| mu0_36(bool) = Store : &:r0_35, r0_34 -# 94| r0_37(glval) = VariableAddress[x] : -# 94| r0_38(int) = Load : &:r0_37, ~mu0_2 -# 94| r0_39(glval) = VariableAddress[y] : -# 94| r0_40(int) = Load : &:r0_39, ~mu0_2 -# 94| r0_41(bool) = CompareLE : r0_38, r0_40 -# 94| r0_42(glval) = VariableAddress[b] : -# 94| mu0_43(bool) = Store : &:r0_42, r0_41 -# 95| r0_44(glval) = VariableAddress[x] : -# 95| r0_45(int) = Load : &:r0_44, ~mu0_2 -# 95| r0_46(glval) = VariableAddress[y] : -# 95| r0_47(int) = Load : &:r0_46, ~mu0_2 -# 95| r0_48(bool) = CompareGE : r0_45, r0_47 -# 95| r0_49(glval) = VariableAddress[b] : -# 95| mu0_50(bool) = Store : &:r0_49, r0_48 -# 96| v0_51(void) = NoOp : -# 87| v0_52(void) = ReturnVoid : -# 87| v0_53(void) = UnmodeledUse : mu* -# 87| v0_54(void) = ExitFunction : +# 92| r0_27(glval) = VariableAddress[y] : +# 92| r0_28(int) = Load : &:r0_27, ~mu0_2 +# 92| r0_29(bool) = CompareLT : r0_26, r0_28 +# 92| r0_30(glval) = VariableAddress[b] : +# 92| mu0_31(bool) = Store : &:r0_30, r0_29 +# 92| r0_32(glval) = CopyValue : r0_30 +# 93| r0_33(glval) = VariableAddress[x] : +# 93| r0_34(int) = Load : &:r0_33, ~mu0_2 +# 93| r0_35(glval) = VariableAddress[y] : +# 93| r0_36(int) = Load : &:r0_35, ~mu0_2 +# 93| r0_37(bool) = CompareGT : r0_34, r0_36 +# 93| r0_38(glval) = VariableAddress[b] : +# 93| mu0_39(bool) = Store : &:r0_38, r0_37 +# 93| r0_40(glval) = CopyValue : r0_38 +# 94| r0_41(glval) = VariableAddress[x] : +# 94| r0_42(int) = Load : &:r0_41, ~mu0_2 +# 94| r0_43(glval) = VariableAddress[y] : +# 94| r0_44(int) = Load : &:r0_43, ~mu0_2 +# 94| r0_45(bool) = CompareLE : r0_42, r0_44 +# 94| r0_46(glval) = VariableAddress[b] : +# 94| mu0_47(bool) = Store : &:r0_46, r0_45 +# 94| r0_48(glval) = CopyValue : r0_46 +# 95| r0_49(glval) = VariableAddress[x] : +# 95| r0_50(int) = Load : &:r0_49, ~mu0_2 +# 95| r0_51(glval) = VariableAddress[y] : +# 95| r0_52(int) = Load : &:r0_51, ~mu0_2 +# 95| r0_53(bool) = CompareGE : r0_50, r0_52 +# 95| r0_54(glval) = VariableAddress[b] : +# 95| mu0_55(bool) = Store : &:r0_54, r0_53 +# 95| r0_56(glval) = CopyValue : r0_54 +# 96| v0_57(void) = NoOp : +# 87| v0_58(void) = ReturnVoid : +# 87| v0_59(void) = UnmodeledUse : mu* +# 87| v0_60(void) = ExitFunction : # 98| void IntegerCrement(int) # 98| Block 0 @@ -457,31 +493,35 @@ ir.cpp: # 101| mu0_11(int) = Store : &:r0_7, r0_10 # 101| r0_12(glval) = VariableAddress[y] : # 101| mu0_13(int) = Store : &:r0_12, r0_10 -# 102| r0_14(glval) = VariableAddress[x] : -# 102| r0_15(int) = Load : &:r0_14, ~mu0_2 -# 102| r0_16(int) = Constant[1] : -# 102| r0_17(int) = Sub : r0_15, r0_16 -# 102| mu0_18(int) = Store : &:r0_14, r0_17 -# 102| r0_19(glval) = VariableAddress[y] : -# 102| mu0_20(int) = Store : &:r0_19, r0_17 -# 103| r0_21(glval) = VariableAddress[x] : -# 103| r0_22(int) = Load : &:r0_21, ~mu0_2 -# 103| r0_23(int) = Constant[1] : -# 103| r0_24(int) = Add : r0_22, r0_23 -# 103| mu0_25(int) = Store : &:r0_21, r0_24 -# 103| r0_26(glval) = VariableAddress[y] : -# 103| mu0_27(int) = Store : &:r0_26, r0_22 -# 104| r0_28(glval) = VariableAddress[x] : -# 104| r0_29(int) = Load : &:r0_28, ~mu0_2 -# 104| r0_30(int) = Constant[1] : -# 104| r0_31(int) = Sub : r0_29, r0_30 -# 104| mu0_32(int) = Store : &:r0_28, r0_31 -# 104| r0_33(glval) = VariableAddress[y] : -# 104| mu0_34(int) = Store : &:r0_33, r0_29 -# 105| v0_35(void) = NoOp : -# 98| v0_36(void) = ReturnVoid : -# 98| v0_37(void) = UnmodeledUse : mu* -# 98| v0_38(void) = ExitFunction : +# 101| r0_14(glval) = CopyValue : r0_12 +# 102| r0_15(glval) = VariableAddress[x] : +# 102| r0_16(int) = Load : &:r0_15, ~mu0_2 +# 102| r0_17(int) = Constant[1] : +# 102| r0_18(int) = Sub : r0_16, r0_17 +# 102| mu0_19(int) = Store : &:r0_15, r0_18 +# 102| r0_20(glval) = VariableAddress[y] : +# 102| mu0_21(int) = Store : &:r0_20, r0_18 +# 102| r0_22(glval) = CopyValue : r0_20 +# 103| r0_23(glval) = VariableAddress[x] : +# 103| r0_24(int) = Load : &:r0_23, ~mu0_2 +# 103| r0_25(int) = Constant[1] : +# 103| r0_26(int) = Add : r0_24, r0_25 +# 103| mu0_27(int) = Store : &:r0_23, r0_26 +# 103| r0_28(glval) = VariableAddress[y] : +# 103| mu0_29(int) = Store : &:r0_28, r0_24 +# 103| r0_30(glval) = CopyValue : r0_28 +# 104| r0_31(glval) = VariableAddress[x] : +# 104| r0_32(int) = Load : &:r0_31, ~mu0_2 +# 104| r0_33(int) = Constant[1] : +# 104| r0_34(int) = Sub : r0_32, r0_33 +# 104| mu0_35(int) = Store : &:r0_31, r0_34 +# 104| r0_36(glval) = VariableAddress[y] : +# 104| mu0_37(int) = Store : &:r0_36, r0_32 +# 104| r0_38(glval) = CopyValue : r0_36 +# 105| v0_39(void) = NoOp : +# 98| v0_40(void) = ReturnVoid : +# 98| v0_41(void) = UnmodeledUse : mu* +# 98| v0_42(void) = ExitFunction : # 107| void IntegerCrement_LValue(int) # 107| Block 0 @@ -497,19 +537,25 @@ ir.cpp: # 110| r0_9(int) = Constant[1] : # 110| r0_10(int) = Add : r0_8, r0_9 # 110| mu0_11(int) = Store : &:r0_7, r0_10 -# 110| r0_12(glval) = VariableAddress[p] : -# 110| mu0_13(int *) = Store : &:r0_12, r0_7 -# 111| r0_14(glval) = VariableAddress[x] : -# 111| r0_15(int) = Load : &:r0_14, ~mu0_2 -# 111| r0_16(int) = Constant[1] : -# 111| r0_17(int) = Sub : r0_15, r0_16 -# 111| mu0_18(int) = Store : &:r0_14, r0_17 -# 111| r0_19(glval) = VariableAddress[p] : -# 111| mu0_20(int *) = Store : &:r0_19, r0_14 -# 112| v0_21(void) = NoOp : -# 107| v0_22(void) = ReturnVoid : -# 107| v0_23(void) = UnmodeledUse : mu* -# 107| v0_24(void) = ExitFunction : +# 110| r0_12(glval) = CopyValue : r0_7 +# 110| r0_13(int *) = CopyValue : r0_12 +# 110| r0_14(glval) = VariableAddress[p] : +# 110| mu0_15(int *) = Store : &:r0_14, r0_13 +# 110| r0_16(glval) = CopyValue : r0_14 +# 111| r0_17(glval) = VariableAddress[x] : +# 111| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 111| r0_19(int) = Constant[1] : +# 111| r0_20(int) = Sub : r0_18, r0_19 +# 111| mu0_21(int) = Store : &:r0_17, r0_20 +# 111| r0_22(glval) = CopyValue : r0_17 +# 111| r0_23(int *) = CopyValue : r0_22 +# 111| r0_24(glval) = VariableAddress[p] : +# 111| mu0_25(int *) = Store : &:r0_24, r0_23 +# 111| r0_26(glval) = CopyValue : r0_24 +# 112| v0_27(void) = NoOp : +# 107| v0_28(void) = ReturnVoid : +# 107| v0_29(void) = UnmodeledUse : mu* +# 107| v0_30(void) = ExitFunction : # 114| void FloatOps(double, double) # 114| Block 0 @@ -529,69 +575,80 @@ ir.cpp: # 117| r0_13(double) = Add : r0_10, r0_12 # 117| r0_14(glval) = VariableAddress[z] : # 117| mu0_15(double) = Store : &:r0_14, r0_13 -# 118| r0_16(glval) = VariableAddress[x] : -# 118| r0_17(double) = Load : &:r0_16, ~mu0_2 -# 118| r0_18(glval) = VariableAddress[y] : -# 118| r0_19(double) = Load : &:r0_18, ~mu0_2 -# 118| r0_20(double) = Sub : r0_17, r0_19 -# 118| r0_21(glval) = VariableAddress[z] : -# 118| mu0_22(double) = Store : &:r0_21, r0_20 -# 119| r0_23(glval) = VariableAddress[x] : -# 119| r0_24(double) = Load : &:r0_23, ~mu0_2 -# 119| r0_25(glval) = VariableAddress[y] : +# 117| r0_16(glval) = CopyValue : r0_14 +# 118| r0_17(glval) = VariableAddress[x] : +# 118| r0_18(double) = Load : &:r0_17, ~mu0_2 +# 118| r0_19(glval) = VariableAddress[y] : +# 118| r0_20(double) = Load : &:r0_19, ~mu0_2 +# 118| r0_21(double) = Sub : r0_18, r0_20 +# 118| r0_22(glval) = VariableAddress[z] : +# 118| mu0_23(double) = Store : &:r0_22, r0_21 +# 118| r0_24(glval) = CopyValue : r0_22 +# 119| r0_25(glval) = VariableAddress[x] : # 119| r0_26(double) = Load : &:r0_25, ~mu0_2 -# 119| r0_27(double) = Mul : r0_24, r0_26 -# 119| r0_28(glval) = VariableAddress[z] : -# 119| mu0_29(double) = Store : &:r0_28, r0_27 -# 120| r0_30(glval) = VariableAddress[x] : -# 120| r0_31(double) = Load : &:r0_30, ~mu0_2 -# 120| r0_32(glval) = VariableAddress[y] : -# 120| r0_33(double) = Load : &:r0_32, ~mu0_2 -# 120| r0_34(double) = Div : r0_31, r0_33 -# 120| r0_35(glval) = VariableAddress[z] : -# 120| mu0_36(double) = Store : &:r0_35, r0_34 -# 122| r0_37(glval) = VariableAddress[x] : -# 122| r0_38(double) = Load : &:r0_37, ~mu0_2 -# 122| r0_39(glval) = VariableAddress[z] : -# 122| mu0_40(double) = Store : &:r0_39, r0_38 -# 124| r0_41(glval) = VariableAddress[x] : -# 124| r0_42(double) = Load : &:r0_41, ~mu0_2 -# 124| r0_43(glval) = VariableAddress[z] : -# 124| r0_44(double) = Load : &:r0_43, ~mu0_2 -# 124| r0_45(double) = Add : r0_44, r0_42 -# 124| mu0_46(double) = Store : &:r0_43, r0_45 -# 125| r0_47(glval) = VariableAddress[x] : -# 125| r0_48(double) = Load : &:r0_47, ~mu0_2 -# 125| r0_49(glval) = VariableAddress[z] : -# 125| r0_50(double) = Load : &:r0_49, ~mu0_2 -# 125| r0_51(double) = Sub : r0_50, r0_48 -# 125| mu0_52(double) = Store : &:r0_49, r0_51 -# 126| r0_53(glval) = VariableAddress[x] : -# 126| r0_54(double) = Load : &:r0_53, ~mu0_2 -# 126| r0_55(glval) = VariableAddress[z] : -# 126| r0_56(double) = Load : &:r0_55, ~mu0_2 -# 126| r0_57(double) = Mul : r0_56, r0_54 -# 126| mu0_58(double) = Store : &:r0_55, r0_57 -# 127| r0_59(glval) = VariableAddress[x] : -# 127| r0_60(double) = Load : &:r0_59, ~mu0_2 -# 127| r0_61(glval) = VariableAddress[z] : -# 127| r0_62(double) = Load : &:r0_61, ~mu0_2 -# 127| r0_63(double) = Div : r0_62, r0_60 -# 127| mu0_64(double) = Store : &:r0_61, r0_63 -# 129| r0_65(glval) = VariableAddress[x] : -# 129| r0_66(double) = Load : &:r0_65, ~mu0_2 -# 129| r0_67(double) = CopyValue : r0_66 -# 129| r0_68(glval) = VariableAddress[z] : -# 129| mu0_69(double) = Store : &:r0_68, r0_67 -# 130| r0_70(glval) = VariableAddress[x] : -# 130| r0_71(double) = Load : &:r0_70, ~mu0_2 -# 130| r0_72(double) = Negate : r0_71 -# 130| r0_73(glval) = VariableAddress[z] : -# 130| mu0_74(double) = Store : &:r0_73, r0_72 -# 131| v0_75(void) = NoOp : -# 114| v0_76(void) = ReturnVoid : -# 114| v0_77(void) = UnmodeledUse : mu* -# 114| v0_78(void) = ExitFunction : +# 119| r0_27(glval) = VariableAddress[y] : +# 119| r0_28(double) = Load : &:r0_27, ~mu0_2 +# 119| r0_29(double) = Mul : r0_26, r0_28 +# 119| r0_30(glval) = VariableAddress[z] : +# 119| mu0_31(double) = Store : &:r0_30, r0_29 +# 119| r0_32(glval) = CopyValue : r0_30 +# 120| r0_33(glval) = VariableAddress[x] : +# 120| r0_34(double) = Load : &:r0_33, ~mu0_2 +# 120| r0_35(glval) = VariableAddress[y] : +# 120| r0_36(double) = Load : &:r0_35, ~mu0_2 +# 120| r0_37(double) = Div : r0_34, r0_36 +# 120| r0_38(glval) = VariableAddress[z] : +# 120| mu0_39(double) = Store : &:r0_38, r0_37 +# 120| r0_40(glval) = CopyValue : r0_38 +# 122| r0_41(glval) = VariableAddress[x] : +# 122| r0_42(double) = Load : &:r0_41, ~mu0_2 +# 122| r0_43(glval) = VariableAddress[z] : +# 122| mu0_44(double) = Store : &:r0_43, r0_42 +# 122| r0_45(glval) = CopyValue : r0_43 +# 124| r0_46(glval) = VariableAddress[x] : +# 124| r0_47(double) = Load : &:r0_46, ~mu0_2 +# 124| r0_48(glval) = VariableAddress[z] : +# 124| r0_49(double) = Load : &:r0_48, ~mu0_2 +# 124| r0_50(double) = Add : r0_49, r0_47 +# 124| mu0_51(double) = Store : &:r0_48, r0_50 +# 124| r0_52(glval) = CopyValue : r0_48 +# 125| r0_53(glval) = VariableAddress[x] : +# 125| r0_54(double) = Load : &:r0_53, ~mu0_2 +# 125| r0_55(glval) = VariableAddress[z] : +# 125| r0_56(double) = Load : &:r0_55, ~mu0_2 +# 125| r0_57(double) = Sub : r0_56, r0_54 +# 125| mu0_58(double) = Store : &:r0_55, r0_57 +# 125| r0_59(glval) = CopyValue : r0_55 +# 126| r0_60(glval) = VariableAddress[x] : +# 126| r0_61(double) = Load : &:r0_60, ~mu0_2 +# 126| r0_62(glval) = VariableAddress[z] : +# 126| r0_63(double) = Load : &:r0_62, ~mu0_2 +# 126| r0_64(double) = Mul : r0_63, r0_61 +# 126| mu0_65(double) = Store : &:r0_62, r0_64 +# 126| r0_66(glval) = CopyValue : r0_62 +# 127| r0_67(glval) = VariableAddress[x] : +# 127| r0_68(double) = Load : &:r0_67, ~mu0_2 +# 127| r0_69(glval) = VariableAddress[z] : +# 127| r0_70(double) = Load : &:r0_69, ~mu0_2 +# 127| r0_71(double) = Div : r0_70, r0_68 +# 127| mu0_72(double) = Store : &:r0_69, r0_71 +# 127| r0_73(glval) = CopyValue : r0_69 +# 129| r0_74(glval) = VariableAddress[x] : +# 129| r0_75(double) = Load : &:r0_74, ~mu0_2 +# 129| r0_76(double) = CopyValue : r0_75 +# 129| r0_77(glval) = VariableAddress[z] : +# 129| mu0_78(double) = Store : &:r0_77, r0_76 +# 129| r0_79(glval) = CopyValue : r0_77 +# 130| r0_80(glval) = VariableAddress[x] : +# 130| r0_81(double) = Load : &:r0_80, ~mu0_2 +# 130| r0_82(double) = Negate : r0_81 +# 130| r0_83(glval) = VariableAddress[z] : +# 130| mu0_84(double) = Store : &:r0_83, r0_82 +# 130| r0_85(glval) = CopyValue : r0_83 +# 131| v0_86(void) = NoOp : +# 114| v0_87(void) = ReturnVoid : +# 114| v0_88(void) = UnmodeledUse : mu* +# 114| v0_89(void) = ExitFunction : # 133| void FloatCompare(double, double) # 133| Block 0 @@ -611,45 +668,51 @@ ir.cpp: # 136| r0_13(bool) = CompareEQ : r0_10, r0_12 # 136| r0_14(glval) = VariableAddress[b] : # 136| mu0_15(bool) = Store : &:r0_14, r0_13 -# 137| r0_16(glval) = VariableAddress[x] : -# 137| r0_17(double) = Load : &:r0_16, ~mu0_2 -# 137| r0_18(glval) = VariableAddress[y] : -# 137| r0_19(double) = Load : &:r0_18, ~mu0_2 -# 137| r0_20(bool) = CompareNE : r0_17, r0_19 -# 137| r0_21(glval) = VariableAddress[b] : -# 137| mu0_22(bool) = Store : &:r0_21, r0_20 -# 138| r0_23(glval) = VariableAddress[x] : -# 138| r0_24(double) = Load : &:r0_23, ~mu0_2 -# 138| r0_25(glval) = VariableAddress[y] : +# 136| r0_16(glval) = CopyValue : r0_14 +# 137| r0_17(glval) = VariableAddress[x] : +# 137| r0_18(double) = Load : &:r0_17, ~mu0_2 +# 137| r0_19(glval) = VariableAddress[y] : +# 137| r0_20(double) = Load : &:r0_19, ~mu0_2 +# 137| r0_21(bool) = CompareNE : r0_18, r0_20 +# 137| r0_22(glval) = VariableAddress[b] : +# 137| mu0_23(bool) = Store : &:r0_22, r0_21 +# 137| r0_24(glval) = CopyValue : r0_22 +# 138| r0_25(glval) = VariableAddress[x] : # 138| r0_26(double) = Load : &:r0_25, ~mu0_2 -# 138| r0_27(bool) = CompareLT : r0_24, r0_26 -# 138| r0_28(glval) = VariableAddress[b] : -# 138| mu0_29(bool) = Store : &:r0_28, r0_27 -# 139| r0_30(glval) = VariableAddress[x] : -# 139| r0_31(double) = Load : &:r0_30, ~mu0_2 -# 139| r0_32(glval) = VariableAddress[y] : -# 139| r0_33(double) = Load : &:r0_32, ~mu0_2 -# 139| r0_34(bool) = CompareGT : r0_31, r0_33 -# 139| r0_35(glval) = VariableAddress[b] : -# 139| mu0_36(bool) = Store : &:r0_35, r0_34 -# 140| r0_37(glval) = VariableAddress[x] : -# 140| r0_38(double) = Load : &:r0_37, ~mu0_2 -# 140| r0_39(glval) = VariableAddress[y] : -# 140| r0_40(double) = Load : &:r0_39, ~mu0_2 -# 140| r0_41(bool) = CompareLE : r0_38, r0_40 -# 140| r0_42(glval) = VariableAddress[b] : -# 140| mu0_43(bool) = Store : &:r0_42, r0_41 -# 141| r0_44(glval) = VariableAddress[x] : -# 141| r0_45(double) = Load : &:r0_44, ~mu0_2 -# 141| r0_46(glval) = VariableAddress[y] : -# 141| r0_47(double) = Load : &:r0_46, ~mu0_2 -# 141| r0_48(bool) = CompareGE : r0_45, r0_47 -# 141| r0_49(glval) = VariableAddress[b] : -# 141| mu0_50(bool) = Store : &:r0_49, r0_48 -# 142| v0_51(void) = NoOp : -# 133| v0_52(void) = ReturnVoid : -# 133| v0_53(void) = UnmodeledUse : mu* -# 133| v0_54(void) = ExitFunction : +# 138| r0_27(glval) = VariableAddress[y] : +# 138| r0_28(double) = Load : &:r0_27, ~mu0_2 +# 138| r0_29(bool) = CompareLT : r0_26, r0_28 +# 138| r0_30(glval) = VariableAddress[b] : +# 138| mu0_31(bool) = Store : &:r0_30, r0_29 +# 138| r0_32(glval) = CopyValue : r0_30 +# 139| r0_33(glval) = VariableAddress[x] : +# 139| r0_34(double) = Load : &:r0_33, ~mu0_2 +# 139| r0_35(glval) = VariableAddress[y] : +# 139| r0_36(double) = Load : &:r0_35, ~mu0_2 +# 139| r0_37(bool) = CompareGT : r0_34, r0_36 +# 139| r0_38(glval) = VariableAddress[b] : +# 139| mu0_39(bool) = Store : &:r0_38, r0_37 +# 139| r0_40(glval) = CopyValue : r0_38 +# 140| r0_41(glval) = VariableAddress[x] : +# 140| r0_42(double) = Load : &:r0_41, ~mu0_2 +# 140| r0_43(glval) = VariableAddress[y] : +# 140| r0_44(double) = Load : &:r0_43, ~mu0_2 +# 140| r0_45(bool) = CompareLE : r0_42, r0_44 +# 140| r0_46(glval) = VariableAddress[b] : +# 140| mu0_47(bool) = Store : &:r0_46, r0_45 +# 140| r0_48(glval) = CopyValue : r0_46 +# 141| r0_49(glval) = VariableAddress[x] : +# 141| r0_50(double) = Load : &:r0_49, ~mu0_2 +# 141| r0_51(glval) = VariableAddress[y] : +# 141| r0_52(double) = Load : &:r0_51, ~mu0_2 +# 141| r0_53(bool) = CompareGE : r0_50, r0_52 +# 141| r0_54(glval) = VariableAddress[b] : +# 141| mu0_55(bool) = Store : &:r0_54, r0_53 +# 141| r0_56(glval) = CopyValue : r0_54 +# 142| v0_57(void) = NoOp : +# 133| v0_58(void) = ReturnVoid : +# 133| v0_59(void) = UnmodeledUse : mu* +# 133| v0_60(void) = ExitFunction : # 144| void FloatCrement(float) # 144| Block 0 @@ -667,31 +730,35 @@ ir.cpp: # 147| mu0_11(float) = Store : &:r0_7, r0_10 # 147| r0_12(glval) = VariableAddress[y] : # 147| mu0_13(float) = Store : &:r0_12, r0_10 -# 148| r0_14(glval) = VariableAddress[x] : -# 148| r0_15(float) = Load : &:r0_14, ~mu0_2 -# 148| r0_16(float) = Constant[1.0] : -# 148| r0_17(float) = Sub : r0_15, r0_16 -# 148| mu0_18(float) = Store : &:r0_14, r0_17 -# 148| r0_19(glval) = VariableAddress[y] : -# 148| mu0_20(float) = Store : &:r0_19, r0_17 -# 149| r0_21(glval) = VariableAddress[x] : -# 149| r0_22(float) = Load : &:r0_21, ~mu0_2 -# 149| r0_23(float) = Constant[1.0] : -# 149| r0_24(float) = Add : r0_22, r0_23 -# 149| mu0_25(float) = Store : &:r0_21, r0_24 -# 149| r0_26(glval) = VariableAddress[y] : -# 149| mu0_27(float) = Store : &:r0_26, r0_22 -# 150| r0_28(glval) = VariableAddress[x] : -# 150| r0_29(float) = Load : &:r0_28, ~mu0_2 -# 150| r0_30(float) = Constant[1.0] : -# 150| r0_31(float) = Sub : r0_29, r0_30 -# 150| mu0_32(float) = Store : &:r0_28, r0_31 -# 150| r0_33(glval) = VariableAddress[y] : -# 150| mu0_34(float) = Store : &:r0_33, r0_29 -# 151| v0_35(void) = NoOp : -# 144| v0_36(void) = ReturnVoid : -# 144| v0_37(void) = UnmodeledUse : mu* -# 144| v0_38(void) = ExitFunction : +# 147| r0_14(glval) = CopyValue : r0_12 +# 148| r0_15(glval) = VariableAddress[x] : +# 148| r0_16(float) = Load : &:r0_15, ~mu0_2 +# 148| r0_17(float) = Constant[1.0] : +# 148| r0_18(float) = Sub : r0_16, r0_17 +# 148| mu0_19(float) = Store : &:r0_15, r0_18 +# 148| r0_20(glval) = VariableAddress[y] : +# 148| mu0_21(float) = Store : &:r0_20, r0_18 +# 148| r0_22(glval) = CopyValue : r0_20 +# 149| r0_23(glval) = VariableAddress[x] : +# 149| r0_24(float) = Load : &:r0_23, ~mu0_2 +# 149| r0_25(float) = Constant[1.0] : +# 149| r0_26(float) = Add : r0_24, r0_25 +# 149| mu0_27(float) = Store : &:r0_23, r0_26 +# 149| r0_28(glval) = VariableAddress[y] : +# 149| mu0_29(float) = Store : &:r0_28, r0_24 +# 149| r0_30(glval) = CopyValue : r0_28 +# 150| r0_31(glval) = VariableAddress[x] : +# 150| r0_32(float) = Load : &:r0_31, ~mu0_2 +# 150| r0_33(float) = Constant[1.0] : +# 150| r0_34(float) = Sub : r0_32, r0_33 +# 150| mu0_35(float) = Store : &:r0_31, r0_34 +# 150| r0_36(glval) = VariableAddress[y] : +# 150| mu0_37(float) = Store : &:r0_36, r0_32 +# 150| r0_38(glval) = CopyValue : r0_36 +# 151| v0_39(void) = NoOp : +# 144| v0_40(void) = ReturnVoid : +# 144| v0_41(void) = UnmodeledUse : mu* +# 144| v0_42(void) = ExitFunction : # 153| void PointerOps(int*, int) # 153| Block 0 @@ -713,61 +780,70 @@ ir.cpp: # 157| r0_15(int *) = PointerAdd[4] : r0_12, r0_14 # 157| r0_16(glval) = VariableAddress[q] : # 157| mu0_17(int *) = Store : &:r0_16, r0_15 -# 158| r0_18(glval) = VariableAddress[i] : -# 158| r0_19(int) = Load : &:r0_18, ~mu0_2 -# 158| r0_20(glval) = VariableAddress[p] : -# 158| r0_21(int *) = Load : &:r0_20, ~mu0_2 -# 158| r0_22(int *) = PointerAdd[4] : r0_21, r0_19 -# 158| r0_23(glval) = VariableAddress[q] : -# 158| mu0_24(int *) = Store : &:r0_23, r0_22 -# 159| r0_25(glval) = VariableAddress[p] : -# 159| r0_26(int *) = Load : &:r0_25, ~mu0_2 -# 159| r0_27(glval) = VariableAddress[i] : -# 159| r0_28(int) = Load : &:r0_27, ~mu0_2 -# 159| r0_29(int *) = PointerSub[4] : r0_26, r0_28 -# 159| r0_30(glval) = VariableAddress[q] : -# 159| mu0_31(int *) = Store : &:r0_30, r0_29 -# 160| r0_32(glval) = VariableAddress[p] : -# 160| r0_33(int *) = Load : &:r0_32, ~mu0_2 -# 160| r0_34(glval) = VariableAddress[q] : -# 160| r0_35(int *) = Load : &:r0_34, ~mu0_2 -# 160| r0_36(long) = PointerDiff[4] : r0_33, r0_35 -# 160| r0_37(int) = Convert : r0_36 -# 160| r0_38(glval) = VariableAddress[i] : -# 160| mu0_39(int) = Store : &:r0_38, r0_37 -# 162| r0_40(glval) = VariableAddress[p] : -# 162| r0_41(int *) = Load : &:r0_40, ~mu0_2 -# 162| r0_42(glval) = VariableAddress[q] : -# 162| mu0_43(int *) = Store : &:r0_42, r0_41 -# 164| r0_44(glval) = VariableAddress[i] : -# 164| r0_45(int) = Load : &:r0_44, ~mu0_2 -# 164| r0_46(glval) = VariableAddress[q] : -# 164| r0_47(int *) = Load : &:r0_46, ~mu0_2 -# 164| r0_48(int *) = PointerAdd[4] : r0_47, r0_45 -# 164| mu0_49(int *) = Store : &:r0_46, r0_48 -# 165| r0_50(glval) = VariableAddress[i] : -# 165| r0_51(int) = Load : &:r0_50, ~mu0_2 -# 165| r0_52(glval) = VariableAddress[q] : -# 165| r0_53(int *) = Load : &:r0_52, ~mu0_2 -# 165| r0_54(int *) = PointerSub[4] : r0_53, r0_51 -# 165| mu0_55(int *) = Store : &:r0_52, r0_54 -# 167| r0_56(glval) = VariableAddress[p] : -# 167| r0_57(int *) = Load : &:r0_56, ~mu0_2 -# 167| r0_58(int *) = Constant[0] : -# 167| r0_59(bool) = CompareNE : r0_57, r0_58 -# 167| r0_60(glval) = VariableAddress[b] : -# 167| mu0_61(bool) = Store : &:r0_60, r0_59 -# 168| r0_62(glval) = VariableAddress[p] : -# 168| r0_63(int *) = Load : &:r0_62, ~mu0_2 -# 168| r0_64(int *) = Constant[0] : -# 168| r0_65(bool) = CompareNE : r0_63, r0_64 -# 168| r0_66(bool) = LogicalNot : r0_65 -# 168| r0_67(glval) = VariableAddress[b] : -# 168| mu0_68(bool) = Store : &:r0_67, r0_66 -# 169| v0_69(void) = NoOp : -# 153| v0_70(void) = ReturnVoid : -# 153| v0_71(void) = UnmodeledUse : mu* -# 153| v0_72(void) = ExitFunction : +# 157| r0_18(glval) = CopyValue : r0_16 +# 158| r0_19(glval) = VariableAddress[i] : +# 158| r0_20(int) = Load : &:r0_19, ~mu0_2 +# 158| r0_21(glval) = VariableAddress[p] : +# 158| r0_22(int *) = Load : &:r0_21, ~mu0_2 +# 158| r0_23(int *) = PointerAdd[4] : r0_22, r0_20 +# 158| r0_24(glval) = VariableAddress[q] : +# 158| mu0_25(int *) = Store : &:r0_24, r0_23 +# 158| r0_26(glval) = CopyValue : r0_24 +# 159| r0_27(glval) = VariableAddress[p] : +# 159| r0_28(int *) = Load : &:r0_27, ~mu0_2 +# 159| r0_29(glval) = VariableAddress[i] : +# 159| r0_30(int) = Load : &:r0_29, ~mu0_2 +# 159| r0_31(int *) = PointerSub[4] : r0_28, r0_30 +# 159| r0_32(glval) = VariableAddress[q] : +# 159| mu0_33(int *) = Store : &:r0_32, r0_31 +# 159| r0_34(glval) = CopyValue : r0_32 +# 160| r0_35(glval) = VariableAddress[p] : +# 160| r0_36(int *) = Load : &:r0_35, ~mu0_2 +# 160| r0_37(glval) = VariableAddress[q] : +# 160| r0_38(int *) = Load : &:r0_37, ~mu0_2 +# 160| r0_39(long) = PointerDiff[4] : r0_36, r0_38 +# 160| r0_40(int) = Convert : r0_39 +# 160| r0_41(glval) = VariableAddress[i] : +# 160| mu0_42(int) = Store : &:r0_41, r0_40 +# 160| r0_43(glval) = CopyValue : r0_41 +# 162| r0_44(glval) = VariableAddress[p] : +# 162| r0_45(int *) = Load : &:r0_44, ~mu0_2 +# 162| r0_46(glval) = VariableAddress[q] : +# 162| mu0_47(int *) = Store : &:r0_46, r0_45 +# 162| r0_48(glval) = CopyValue : r0_46 +# 164| r0_49(glval) = VariableAddress[i] : +# 164| r0_50(int) = Load : &:r0_49, ~mu0_2 +# 164| r0_51(glval) = VariableAddress[q] : +# 164| r0_52(int *) = Load : &:r0_51, ~mu0_2 +# 164| r0_53(int *) = PointerAdd[4] : r0_52, r0_50 +# 164| mu0_54(int *) = Store : &:r0_51, r0_53 +# 164| r0_55(glval) = CopyValue : r0_51 +# 165| r0_56(glval) = VariableAddress[i] : +# 165| r0_57(int) = Load : &:r0_56, ~mu0_2 +# 165| r0_58(glval) = VariableAddress[q] : +# 165| r0_59(int *) = Load : &:r0_58, ~mu0_2 +# 165| r0_60(int *) = PointerSub[4] : r0_59, r0_57 +# 165| mu0_61(int *) = Store : &:r0_58, r0_60 +# 165| r0_62(glval) = CopyValue : r0_58 +# 167| r0_63(glval) = VariableAddress[p] : +# 167| r0_64(int *) = Load : &:r0_63, ~mu0_2 +# 167| r0_65(int *) = Constant[0] : +# 167| r0_66(bool) = CompareNE : r0_64, r0_65 +# 167| r0_67(glval) = VariableAddress[b] : +# 167| mu0_68(bool) = Store : &:r0_67, r0_66 +# 167| r0_69(glval) = CopyValue : r0_67 +# 168| r0_70(glval) = VariableAddress[p] : +# 168| r0_71(int *) = Load : &:r0_70, ~mu0_2 +# 168| r0_72(int *) = Constant[0] : +# 168| r0_73(bool) = CompareNE : r0_71, r0_72 +# 168| r0_74(bool) = LogicalNot : r0_73 +# 168| r0_75(glval) = VariableAddress[b] : +# 168| mu0_76(bool) = Store : &:r0_75, r0_74 +# 168| r0_77(glval) = CopyValue : r0_75 +# 169| v0_78(void) = NoOp : +# 153| v0_79(void) = ReturnVoid : +# 153| v0_80(void) = UnmodeledUse : mu* +# 153| v0_81(void) = ExitFunction : # 171| void ArrayAccess(int*, int) # 171| Block 0 @@ -788,68 +864,76 @@ ir.cpp: # 174| r0_14(int) = Load : &:r0_13, ~mu0_2 # 174| r0_15(glval) = VariableAddress[x] : # 174| mu0_16(int) = Store : &:r0_15, r0_14 -# 175| r0_17(glval) = VariableAddress[p] : -# 175| r0_18(int *) = Load : &:r0_17, ~mu0_2 -# 175| r0_19(glval) = VariableAddress[i] : -# 175| r0_20(int) = Load : &:r0_19, ~mu0_2 -# 175| r0_21(glval) = PointerAdd[4] : r0_18, r0_20 -# 175| r0_22(int) = Load : &:r0_21, ~mu0_2 -# 175| r0_23(glval) = VariableAddress[x] : -# 175| mu0_24(int) = Store : &:r0_23, r0_22 -# 177| r0_25(glval) = VariableAddress[x] : -# 177| r0_26(int) = Load : &:r0_25, ~mu0_2 -# 177| r0_27(glval) = VariableAddress[p] : -# 177| r0_28(int *) = Load : &:r0_27, ~mu0_2 -# 177| r0_29(glval) = VariableAddress[i] : -# 177| r0_30(int) = Load : &:r0_29, ~mu0_2 -# 177| r0_31(glval) = PointerAdd[4] : r0_28, r0_30 -# 177| mu0_32(int) = Store : &:r0_31, r0_26 -# 178| r0_33(glval) = VariableAddress[x] : -# 178| r0_34(int) = Load : &:r0_33, ~mu0_2 -# 178| r0_35(glval) = VariableAddress[p] : -# 178| r0_36(int *) = Load : &:r0_35, ~mu0_2 -# 178| r0_37(glval) = VariableAddress[i] : -# 178| r0_38(int) = Load : &:r0_37, ~mu0_2 -# 178| r0_39(glval) = PointerAdd[4] : r0_36, r0_38 -# 178| mu0_40(int) = Store : &:r0_39, r0_34 -# 180| r0_41(glval) = VariableAddress[a] : -# 180| mu0_42(int[10]) = Uninitialized[a] : &:r0_41 -# 181| r0_43(glval) = VariableAddress[a] : -# 181| r0_44(int *) = Convert : r0_43 -# 181| r0_45(glval) = VariableAddress[i] : -# 181| r0_46(int) = Load : &:r0_45, ~mu0_2 -# 181| r0_47(glval) = PointerAdd[4] : r0_44, r0_46 -# 181| r0_48(int) = Load : &:r0_47, ~mu0_2 -# 181| r0_49(glval) = VariableAddress[x] : -# 181| mu0_50(int) = Store : &:r0_49, r0_48 -# 182| r0_51(glval) = VariableAddress[a] : -# 182| r0_52(int *) = Convert : r0_51 -# 182| r0_53(glval) = VariableAddress[i] : -# 182| r0_54(int) = Load : &:r0_53, ~mu0_2 -# 182| r0_55(glval) = PointerAdd[4] : r0_52, r0_54 -# 182| r0_56(int) = Load : &:r0_55, ~mu0_2 -# 182| r0_57(glval) = VariableAddress[x] : -# 182| mu0_58(int) = Store : &:r0_57, r0_56 -# 183| r0_59(glval) = VariableAddress[x] : -# 183| r0_60(int) = Load : &:r0_59, ~mu0_2 -# 183| r0_61(glval) = VariableAddress[a] : -# 183| r0_62(int *) = Convert : r0_61 -# 183| r0_63(glval) = VariableAddress[i] : -# 183| r0_64(int) = Load : &:r0_63, ~mu0_2 -# 183| r0_65(glval) = PointerAdd[4] : r0_62, r0_64 -# 183| mu0_66(int) = Store : &:r0_65, r0_60 -# 184| r0_67(glval) = VariableAddress[x] : -# 184| r0_68(int) = Load : &:r0_67, ~mu0_2 -# 184| r0_69(glval) = VariableAddress[a] : -# 184| r0_70(int *) = Convert : r0_69 -# 184| r0_71(glval) = VariableAddress[i] : -# 184| r0_72(int) = Load : &:r0_71, ~mu0_2 -# 184| r0_73(glval) = PointerAdd[4] : r0_70, r0_72 -# 184| mu0_74(int) = Store : &:r0_73, r0_68 -# 185| v0_75(void) = NoOp : -# 171| v0_76(void) = ReturnVoid : -# 171| v0_77(void) = UnmodeledUse : mu* -# 171| v0_78(void) = ExitFunction : +# 174| r0_17(glval) = CopyValue : r0_15 +# 175| r0_18(glval) = VariableAddress[p] : +# 175| r0_19(int *) = Load : &:r0_18, ~mu0_2 +# 175| r0_20(glval) = VariableAddress[i] : +# 175| r0_21(int) = Load : &:r0_20, ~mu0_2 +# 175| r0_22(glval) = PointerAdd[4] : r0_19, r0_21 +# 175| r0_23(int) = Load : &:r0_22, ~mu0_2 +# 175| r0_24(glval) = VariableAddress[x] : +# 175| mu0_25(int) = Store : &:r0_24, r0_23 +# 175| r0_26(glval) = CopyValue : r0_24 +# 177| r0_27(glval) = VariableAddress[x] : +# 177| r0_28(int) = Load : &:r0_27, ~mu0_2 +# 177| r0_29(glval) = VariableAddress[p] : +# 177| r0_30(int *) = Load : &:r0_29, ~mu0_2 +# 177| r0_31(glval) = VariableAddress[i] : +# 177| r0_32(int) = Load : &:r0_31, ~mu0_2 +# 177| r0_33(glval) = PointerAdd[4] : r0_30, r0_32 +# 177| mu0_34(int) = Store : &:r0_33, r0_28 +# 177| r0_35(glval) = CopyValue : r0_33 +# 178| r0_36(glval) = VariableAddress[x] : +# 178| r0_37(int) = Load : &:r0_36, ~mu0_2 +# 178| r0_38(glval) = VariableAddress[p] : +# 178| r0_39(int *) = Load : &:r0_38, ~mu0_2 +# 178| r0_40(glval) = VariableAddress[i] : +# 178| r0_41(int) = Load : &:r0_40, ~mu0_2 +# 178| r0_42(glval) = PointerAdd[4] : r0_39, r0_41 +# 178| mu0_43(int) = Store : &:r0_42, r0_37 +# 178| r0_44(glval) = CopyValue : r0_42 +# 180| r0_45(glval) = VariableAddress[a] : +# 180| mu0_46(int[10]) = Uninitialized[a] : &:r0_45 +# 181| r0_47(glval) = VariableAddress[a] : +# 181| r0_48(int *) = Convert : r0_47 +# 181| r0_49(glval) = VariableAddress[i] : +# 181| r0_50(int) = Load : &:r0_49, ~mu0_2 +# 181| r0_51(glval) = PointerAdd[4] : r0_48, r0_50 +# 181| r0_52(int) = Load : &:r0_51, ~mu0_2 +# 181| r0_53(glval) = VariableAddress[x] : +# 181| mu0_54(int) = Store : &:r0_53, r0_52 +# 181| r0_55(glval) = CopyValue : r0_53 +# 182| r0_56(glval) = VariableAddress[a] : +# 182| r0_57(int *) = Convert : r0_56 +# 182| r0_58(glval) = VariableAddress[i] : +# 182| r0_59(int) = Load : &:r0_58, ~mu0_2 +# 182| r0_60(glval) = PointerAdd[4] : r0_57, r0_59 +# 182| r0_61(int) = Load : &:r0_60, ~mu0_2 +# 182| r0_62(glval) = VariableAddress[x] : +# 182| mu0_63(int) = Store : &:r0_62, r0_61 +# 182| r0_64(glval) = CopyValue : r0_62 +# 183| r0_65(glval) = VariableAddress[x] : +# 183| r0_66(int) = Load : &:r0_65, ~mu0_2 +# 183| r0_67(glval) = VariableAddress[a] : +# 183| r0_68(int *) = Convert : r0_67 +# 183| r0_69(glval) = VariableAddress[i] : +# 183| r0_70(int) = Load : &:r0_69, ~mu0_2 +# 183| r0_71(glval) = PointerAdd[4] : r0_68, r0_70 +# 183| mu0_72(int) = Store : &:r0_71, r0_66 +# 183| r0_73(glval) = CopyValue : r0_71 +# 184| r0_74(glval) = VariableAddress[x] : +# 184| r0_75(int) = Load : &:r0_74, ~mu0_2 +# 184| r0_76(glval) = VariableAddress[a] : +# 184| r0_77(int *) = Convert : r0_76 +# 184| r0_78(glval) = VariableAddress[i] : +# 184| r0_79(int) = Load : &:r0_78, ~mu0_2 +# 184| r0_80(glval) = PointerAdd[4] : r0_77, r0_79 +# 184| mu0_81(int) = Store : &:r0_80, r0_75 +# 184| r0_82(glval) = CopyValue : r0_80 +# 185| v0_83(void) = NoOp : +# 171| v0_84(void) = ReturnVoid : +# 171| v0_85(void) = UnmodeledUse : mu* +# 171| v0_86(void) = ExitFunction : # 187| void StringLiteral(int) # 187| Block 0 @@ -902,45 +986,51 @@ ir.cpp: # 196| r0_13(bool) = CompareEQ : r0_10, r0_12 # 196| r0_14(glval) = VariableAddress[b] : # 196| mu0_15(bool) = Store : &:r0_14, r0_13 -# 197| r0_16(glval) = VariableAddress[p] : -# 197| r0_17(int *) = Load : &:r0_16, ~mu0_2 -# 197| r0_18(glval) = VariableAddress[q] : -# 197| r0_19(int *) = Load : &:r0_18, ~mu0_2 -# 197| r0_20(bool) = CompareNE : r0_17, r0_19 -# 197| r0_21(glval) = VariableAddress[b] : -# 197| mu0_22(bool) = Store : &:r0_21, r0_20 -# 198| r0_23(glval) = VariableAddress[p] : -# 198| r0_24(int *) = Load : &:r0_23, ~mu0_2 -# 198| r0_25(glval) = VariableAddress[q] : +# 196| r0_16(glval) = CopyValue : r0_14 +# 197| r0_17(glval) = VariableAddress[p] : +# 197| r0_18(int *) = Load : &:r0_17, ~mu0_2 +# 197| r0_19(glval) = VariableAddress[q] : +# 197| r0_20(int *) = Load : &:r0_19, ~mu0_2 +# 197| r0_21(bool) = CompareNE : r0_18, r0_20 +# 197| r0_22(glval) = VariableAddress[b] : +# 197| mu0_23(bool) = Store : &:r0_22, r0_21 +# 197| r0_24(glval) = CopyValue : r0_22 +# 198| r0_25(glval) = VariableAddress[p] : # 198| r0_26(int *) = Load : &:r0_25, ~mu0_2 -# 198| r0_27(bool) = CompareLT : r0_24, r0_26 -# 198| r0_28(glval) = VariableAddress[b] : -# 198| mu0_29(bool) = Store : &:r0_28, r0_27 -# 199| r0_30(glval) = VariableAddress[p] : -# 199| r0_31(int *) = Load : &:r0_30, ~mu0_2 -# 199| r0_32(glval) = VariableAddress[q] : -# 199| r0_33(int *) = Load : &:r0_32, ~mu0_2 -# 199| r0_34(bool) = CompareGT : r0_31, r0_33 -# 199| r0_35(glval) = VariableAddress[b] : -# 199| mu0_36(bool) = Store : &:r0_35, r0_34 -# 200| r0_37(glval) = VariableAddress[p] : -# 200| r0_38(int *) = Load : &:r0_37, ~mu0_2 -# 200| r0_39(glval) = VariableAddress[q] : -# 200| r0_40(int *) = Load : &:r0_39, ~mu0_2 -# 200| r0_41(bool) = CompareLE : r0_38, r0_40 -# 200| r0_42(glval) = VariableAddress[b] : -# 200| mu0_43(bool) = Store : &:r0_42, r0_41 -# 201| r0_44(glval) = VariableAddress[p] : -# 201| r0_45(int *) = Load : &:r0_44, ~mu0_2 -# 201| r0_46(glval) = VariableAddress[q] : -# 201| r0_47(int *) = Load : &:r0_46, ~mu0_2 -# 201| r0_48(bool) = CompareGE : r0_45, r0_47 -# 201| r0_49(glval) = VariableAddress[b] : -# 201| mu0_50(bool) = Store : &:r0_49, r0_48 -# 202| v0_51(void) = NoOp : -# 193| v0_52(void) = ReturnVoid : -# 193| v0_53(void) = UnmodeledUse : mu* -# 193| v0_54(void) = ExitFunction : +# 198| r0_27(glval) = VariableAddress[q] : +# 198| r0_28(int *) = Load : &:r0_27, ~mu0_2 +# 198| r0_29(bool) = CompareLT : r0_26, r0_28 +# 198| r0_30(glval) = VariableAddress[b] : +# 198| mu0_31(bool) = Store : &:r0_30, r0_29 +# 198| r0_32(glval) = CopyValue : r0_30 +# 199| r0_33(glval) = VariableAddress[p] : +# 199| r0_34(int *) = Load : &:r0_33, ~mu0_2 +# 199| r0_35(glval) = VariableAddress[q] : +# 199| r0_36(int *) = Load : &:r0_35, ~mu0_2 +# 199| r0_37(bool) = CompareGT : r0_34, r0_36 +# 199| r0_38(glval) = VariableAddress[b] : +# 199| mu0_39(bool) = Store : &:r0_38, r0_37 +# 199| r0_40(glval) = CopyValue : r0_38 +# 200| r0_41(glval) = VariableAddress[p] : +# 200| r0_42(int *) = Load : &:r0_41, ~mu0_2 +# 200| r0_43(glval) = VariableAddress[q] : +# 200| r0_44(int *) = Load : &:r0_43, ~mu0_2 +# 200| r0_45(bool) = CompareLE : r0_42, r0_44 +# 200| r0_46(glval) = VariableAddress[b] : +# 200| mu0_47(bool) = Store : &:r0_46, r0_45 +# 200| r0_48(glval) = CopyValue : r0_46 +# 201| r0_49(glval) = VariableAddress[p] : +# 201| r0_50(int *) = Load : &:r0_49, ~mu0_2 +# 201| r0_51(glval) = VariableAddress[q] : +# 201| r0_52(int *) = Load : &:r0_51, ~mu0_2 +# 201| r0_53(bool) = CompareGE : r0_50, r0_52 +# 201| r0_54(glval) = VariableAddress[b] : +# 201| mu0_55(bool) = Store : &:r0_54, r0_53 +# 201| r0_56(glval) = CopyValue : r0_54 +# 202| v0_57(void) = NoOp : +# 193| v0_58(void) = ReturnVoid : +# 193| v0_59(void) = UnmodeledUse : mu* +# 193| v0_60(void) = ExitFunction : # 204| void PointerCrement(int*) # 204| Block 0 @@ -958,31 +1048,35 @@ ir.cpp: # 207| mu0_11(int *) = Store : &:r0_7, r0_10 # 207| r0_12(glval) = VariableAddress[q] : # 207| mu0_13(int *) = Store : &:r0_12, r0_10 -# 208| r0_14(glval) = VariableAddress[p] : -# 208| r0_15(int *) = Load : &:r0_14, ~mu0_2 -# 208| r0_16(int) = Constant[1] : -# 208| r0_17(int *) = PointerSub[4] : r0_15, r0_16 -# 208| mu0_18(int *) = Store : &:r0_14, r0_17 -# 208| r0_19(glval) = VariableAddress[q] : -# 208| mu0_20(int *) = Store : &:r0_19, r0_17 -# 209| r0_21(glval) = VariableAddress[p] : -# 209| r0_22(int *) = Load : &:r0_21, ~mu0_2 -# 209| r0_23(int) = Constant[1] : -# 209| r0_24(int *) = PointerAdd[4] : r0_22, r0_23 -# 209| mu0_25(int *) = Store : &:r0_21, r0_24 -# 209| r0_26(glval) = VariableAddress[q] : -# 209| mu0_27(int *) = Store : &:r0_26, r0_22 -# 210| r0_28(glval) = VariableAddress[p] : -# 210| r0_29(int *) = Load : &:r0_28, ~mu0_2 -# 210| r0_30(int) = Constant[1] : -# 210| r0_31(int *) = PointerSub[4] : r0_29, r0_30 -# 210| mu0_32(int *) = Store : &:r0_28, r0_31 -# 210| r0_33(glval) = VariableAddress[q] : -# 210| mu0_34(int *) = Store : &:r0_33, r0_29 -# 211| v0_35(void) = NoOp : -# 204| v0_36(void) = ReturnVoid : -# 204| v0_37(void) = UnmodeledUse : mu* -# 204| v0_38(void) = ExitFunction : +# 207| r0_14(glval) = CopyValue : r0_12 +# 208| r0_15(glval) = VariableAddress[p] : +# 208| r0_16(int *) = Load : &:r0_15, ~mu0_2 +# 208| r0_17(int) = Constant[1] : +# 208| r0_18(int *) = PointerSub[4] : r0_16, r0_17 +# 208| mu0_19(int *) = Store : &:r0_15, r0_18 +# 208| r0_20(glval) = VariableAddress[q] : +# 208| mu0_21(int *) = Store : &:r0_20, r0_18 +# 208| r0_22(glval) = CopyValue : r0_20 +# 209| r0_23(glval) = VariableAddress[p] : +# 209| r0_24(int *) = Load : &:r0_23, ~mu0_2 +# 209| r0_25(int) = Constant[1] : +# 209| r0_26(int *) = PointerAdd[4] : r0_24, r0_25 +# 209| mu0_27(int *) = Store : &:r0_23, r0_26 +# 209| r0_28(glval) = VariableAddress[q] : +# 209| mu0_29(int *) = Store : &:r0_28, r0_24 +# 209| r0_30(glval) = CopyValue : r0_28 +# 210| r0_31(glval) = VariableAddress[p] : +# 210| r0_32(int *) = Load : &:r0_31, ~mu0_2 +# 210| r0_33(int) = Constant[1] : +# 210| r0_34(int *) = PointerSub[4] : r0_32, r0_33 +# 210| mu0_35(int *) = Store : &:r0_31, r0_34 +# 210| r0_36(glval) = VariableAddress[q] : +# 210| mu0_37(int *) = Store : &:r0_36, r0_32 +# 210| r0_38(glval) = CopyValue : r0_36 +# 211| v0_39(void) = NoOp : +# 204| v0_40(void) = ReturnVoid : +# 204| v0_41(void) = UnmodeledUse : mu* +# 204| v0_42(void) = ExitFunction : # 213| void CompoundAssignment() # 213| Block 0 @@ -997,36 +1091,40 @@ ir.cpp: # 216| r0_8(int) = Load : &:r0_7, ~mu0_2 # 216| r0_9(int) = Add : r0_8, r0_6 # 216| mu0_10(int) = Store : &:r0_7, r0_9 -# 219| r0_11(glval) = VariableAddress[y] : -# 219| r0_12(short) = Constant[5] : -# 219| mu0_13(short) = Store : &:r0_11, r0_12 -# 220| r0_14(glval) = VariableAddress[x] : -# 220| r0_15(int) = Load : &:r0_14, ~mu0_2 -# 220| r0_16(glval) = VariableAddress[y] : -# 220| r0_17(short) = Load : &:r0_16, ~mu0_2 -# 220| r0_18(int) = Convert : r0_17 -# 220| r0_19(int) = Add : r0_18, r0_15 -# 220| r0_20(short) = Convert : r0_19 -# 220| mu0_21(short) = Store : &:r0_16, r0_20 -# 223| r0_22(int) = Constant[1] : -# 223| r0_23(glval) = VariableAddress[y] : -# 223| r0_24(short) = Load : &:r0_23, ~mu0_2 -# 223| r0_25(short) = ShiftLeft : r0_24, r0_22 -# 223| mu0_26(short) = Store : &:r0_23, r0_25 -# 226| r0_27(glval) = VariableAddress[z] : -# 226| r0_28(long) = Constant[7] : -# 226| mu0_29(long) = Store : &:r0_27, r0_28 -# 227| r0_30(float) = Constant[2.0] : -# 227| r0_31(glval) = VariableAddress[z] : -# 227| r0_32(long) = Load : &:r0_31, ~mu0_2 -# 227| r0_33(float) = Convert : r0_32 -# 227| r0_34(float) = Add : r0_33, r0_30 -# 227| r0_35(long) = Convert : r0_34 -# 227| mu0_36(long) = Store : &:r0_31, r0_35 -# 228| v0_37(void) = NoOp : -# 213| v0_38(void) = ReturnVoid : -# 213| v0_39(void) = UnmodeledUse : mu* -# 213| v0_40(void) = ExitFunction : +# 216| r0_11(glval) = CopyValue : r0_7 +# 219| r0_12(glval) = VariableAddress[y] : +# 219| r0_13(short) = Constant[5] : +# 219| mu0_14(short) = Store : &:r0_12, r0_13 +# 220| r0_15(glval) = VariableAddress[x] : +# 220| r0_16(int) = Load : &:r0_15, ~mu0_2 +# 220| r0_17(glval) = VariableAddress[y] : +# 220| r0_18(short) = Load : &:r0_17, ~mu0_2 +# 220| r0_19(int) = Convert : r0_18 +# 220| r0_20(int) = Add : r0_19, r0_16 +# 220| r0_21(short) = Convert : r0_20 +# 220| mu0_22(short) = Store : &:r0_17, r0_21 +# 220| r0_23(glval) = CopyValue : r0_17 +# 223| r0_24(int) = Constant[1] : +# 223| r0_25(glval) = VariableAddress[y] : +# 223| r0_26(short) = Load : &:r0_25, ~mu0_2 +# 223| r0_27(short) = ShiftLeft : r0_26, r0_24 +# 223| mu0_28(short) = Store : &:r0_25, r0_27 +# 223| r0_29(glval) = CopyValue : r0_25 +# 226| r0_30(glval) = VariableAddress[z] : +# 226| r0_31(long) = Constant[7] : +# 226| mu0_32(long) = Store : &:r0_30, r0_31 +# 227| r0_33(float) = Constant[2.0] : +# 227| r0_34(glval) = VariableAddress[z] : +# 227| r0_35(long) = Load : &:r0_34, ~mu0_2 +# 227| r0_36(float) = Convert : r0_35 +# 227| r0_37(float) = Add : r0_36, r0_33 +# 227| r0_38(long) = Convert : r0_37 +# 227| mu0_39(long) = Store : &:r0_34, r0_38 +# 227| r0_40(glval) = CopyValue : r0_34 +# 228| v0_41(void) = NoOp : +# 213| v0_42(void) = ReturnVoid : +# 213| v0_43(void) = UnmodeledUse : mu* +# 213| v0_44(void) = ExitFunction : # 230| void UninitializedVariables() # 230| Block 0 @@ -1094,6 +1192,7 @@ ir.cpp: # 244| r2_1(int) = Load : &:r2_0, ~mu0_2 # 244| r2_2(glval) = VariableAddress[x] : # 244| mu2_3(int) = Store : &:r2_2, r2_1 +# 244| r2_4(glval) = CopyValue : r2_2 #-----| Goto -> Block 3 # 247| Block 3 @@ -1109,12 +1208,14 @@ ir.cpp: # 248| r4_0(int) = Constant[2] : # 248| r4_1(glval) = VariableAddress[x] : # 248| mu4_2(int) = Store : &:r4_1, r4_0 +# 248| r4_3(glval) = CopyValue : r4_1 #-----| Goto -> Block 6 # 250| Block 5 # 250| r5_0(int) = Constant[7] : # 250| r5_1(glval) = VariableAddress[x] : # 250| mu5_2(int) = Store : &:r5_1, r5_0 +# 250| r5_3(glval) = CopyValue : r5_1 #-----| Goto -> Block 6 # 251| Block 6 @@ -1142,6 +1243,7 @@ ir.cpp: # 255| r1_2(int) = Load : &:r1_1, ~mu0_2 # 255| r1_3(int) = Sub : r1_2, r1_0 # 255| mu1_4(int) = Store : &:r1_1, r1_3 +# 255| r1_5(glval) = CopyValue : r1_1 #-----| Goto (back edge) -> Block 3 # 257| Block 2 @@ -1174,11 +1276,12 @@ ir.cpp: # 261| r1_2(int) = Load : &:r1_1, ~mu0_2 # 261| r1_3(int) = Sub : r1_2, r1_0 # 261| mu1_4(int) = Store : &:r1_1, r1_3 -# 262| r1_5(glval) = VariableAddress[n] : -# 262| r1_6(int) = Load : &:r1_5, ~mu0_2 -# 262| r1_7(int) = Constant[0] : -# 262| r1_8(bool) = CompareGT : r1_6, r1_7 -# 262| v1_9(void) = ConditionalBranch : r1_8 +# 261| r1_5(glval) = CopyValue : r1_1 +# 262| r1_6(glval) = VariableAddress[n] : +# 262| r1_7(int) = Load : &:r1_6, ~mu0_2 +# 262| r1_8(int) = Constant[0] : +# 262| r1_9(bool) = CompareGT : r1_7, r1_8 +# 262| v1_10(void) = ConditionalBranch : r1_9 #-----| False -> Block 2 #-----| True (back edge) -> Block 1 @@ -1276,6 +1379,7 @@ ir.cpp: # 287| r2_3(int) = Load : &:r2_2, ~mu0_2 # 287| r2_4(int) = Add : r2_3, r2_1 # 287| mu2_5(int) = Store : &:r2_2, r2_4 +# 287| r2_6(glval) = CopyValue : r2_2 #-----| Goto (back edge) -> Block 2 # 292| void For_InitCondition() @@ -1329,6 +1433,7 @@ ir.cpp: # 299| r2_3(int) = Load : &:r2_2, ~mu0_2 # 299| r2_4(int) = Add : r2_3, r2_1 # 299| mu2_5(int) = Store : &:r2_2, r2_4 +# 299| r2_6(glval) = CopyValue : r2_2 #-----| Goto (back edge) -> Block 2 # 304| void For_ConditionUpdate() @@ -1357,6 +1462,7 @@ ir.cpp: # 306| r2_3(int) = Load : &:r2_2, ~mu0_2 # 306| r2_4(int) = Add : r2_3, r2_1 # 306| mu2_5(int) = Store : &:r2_2, r2_4 +# 306| r2_6(glval) = CopyValue : r2_2 #-----| Goto (back edge) -> Block 1 # 309| Block 3 @@ -1391,6 +1497,7 @@ ir.cpp: # 312| r2_3(int) = Load : &:r2_2, ~mu0_2 # 312| r2_4(int) = Add : r2_3, r2_1 # 312| mu2_5(int) = Store : &:r2_2, r2_4 +# 312| r2_6(glval) = CopyValue : r2_2 #-----| Goto (back edge) -> Block 1 # 315| Block 3 @@ -1424,6 +1531,7 @@ ir.cpp: # 318| r2_2(int) = Load : &:r2_1, ~mu0_2 # 318| r2_3(int) = Add : r2_2, r2_0 # 318| mu2_4(int) = Store : &:r2_1, r2_3 +# 318| r2_5(glval) = CopyValue : r2_1 #-----| Goto (back edge) -> Block 1 # 319| Block 3 @@ -1485,6 +1593,7 @@ ir.cpp: # 326| r4_3(int) = Load : &:r4_2, ~mu0_2 # 326| r4_4(int) = Add : r4_3, r4_1 # 326| mu4_5(int) = Store : &:r4_2, r4_4 +# 326| r4_6(glval) = CopyValue : r4_2 #-----| Goto (back edge) -> Block 1 # 331| Block 5 @@ -1545,16 +1654,18 @@ ir.cpp: # 342| r0_5(int) = Constant[1] : # 342| r0_6(glval) = VariableAddress[p] : # 342| r0_7(int *) = Load : &:r0_6, ~mu0_2 -# 342| mu0_8(int) = Store : &:r0_7, r0_5 -# 343| r0_9(glval) = VariableAddress[#return] : -# 343| r0_10(glval) = VariableAddress[p] : -# 343| r0_11(int *) = Load : &:r0_10, ~mu0_2 -# 343| r0_12(int) = Load : &:r0_11, ~mu0_2 -# 343| mu0_13(int) = Store : &:r0_9, r0_12 -# 341| r0_14(glval) = VariableAddress[#return] : -# 341| v0_15(void) = ReturnValue : &:r0_14, ~mu0_2 -# 341| v0_16(void) = UnmodeledUse : mu* -# 341| v0_17(void) = ExitFunction : +# 342| r0_8(glval) = CopyValue : r0_7 +# 342| mu0_9(int) = Store : &:r0_8, r0_5 +# 342| r0_10(glval) = CopyValue : r0_8 +# 343| r0_11(glval) = VariableAddress[#return] : +# 343| r0_12(glval) = VariableAddress[p] : +# 343| r0_13(int *) = Load : &:r0_12, ~mu0_2 +# 343| r0_14(int) = Load : &:r0_13, ~mu0_2 +# 343| mu0_15(int) = Store : &:r0_11, r0_14 +# 341| r0_16(glval) = VariableAddress[#return] : +# 341| v0_17(void) = ReturnValue : &:r0_16, ~mu0_2 +# 341| v0_18(void) = UnmodeledUse : mu* +# 341| v0_19(void) = ExitFunction : # 348| int* AddressOf() # 348| Block 0 @@ -1563,11 +1674,12 @@ ir.cpp: # 348| mu0_2(unknown) = UnmodeledDefinition : # 349| r0_3(glval) = VariableAddress[#return] : # 349| r0_4(glval) = VariableAddress[g] : -# 349| mu0_5(int *) = Store : &:r0_3, r0_4 -# 348| r0_6(glval) = VariableAddress[#return] : -# 348| v0_7(void) = ReturnValue : &:r0_6, ~mu0_2 -# 348| v0_8(void) = UnmodeledUse : mu* -# 348| v0_9(void) = ExitFunction : +# 349| r0_5(int *) = CopyValue : r0_4 +# 349| mu0_6(int *) = Store : &:r0_3, r0_5 +# 348| r0_7(glval) = VariableAddress[#return] : +# 348| v0_8(void) = ReturnValue : &:r0_7, ~mu0_2 +# 348| v0_9(void) = UnmodeledUse : mu* +# 348| v0_10(void) = ExitFunction : # 352| void Break(int) # 352| Block 0 @@ -1597,6 +1709,7 @@ ir.cpp: # 356| r3_2(int) = Load : &:r3_1, ~mu0_2 # 356| r3_3(int) = Sub : r3_2, r3_0 # 356| mu3_4(int) = Store : &:r3_1, r3_3 +# 356| r3_5(glval) = CopyValue : r3_1 #-----| Goto (back edge) -> Block 5 # 357| Block 4 @@ -1643,6 +1756,7 @@ ir.cpp: # 365| r3_2(int) = Load : &:r3_1, ~mu0_2 # 365| r3_3(int) = Sub : r3_2, r3_0 # 365| mu3_4(int) = Store : &:r3_1, r3_3 +# 365| r3_5(glval) = CopyValue : r3_1 #-----| Goto -> Block 4 # 361| Block 4 @@ -1717,11 +1831,12 @@ ir.cpp: # 381| r0_15(int) = Load : &:r0_14, ~mu0_2 # 381| r0_16(int) = Call : func:r0_11, 0:r0_13, 1:r0_15 # 381| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 -# 381| mu0_18(int) = Store : &:r0_7, r0_16 -# 380| r0_19(glval) = VariableAddress[#return] : -# 380| v0_20(void) = ReturnValue : &:r0_19, ~mu0_2 -# 380| v0_21(void) = UnmodeledUse : mu* -# 380| v0_22(void) = ExitFunction : +# 381| r0_18(int) = CopyValue : r0_16 +# 381| mu0_19(int) = Store : &:r0_7, r0_18 +# 380| r0_20(glval) = VariableAddress[#return] : +# 380| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 +# 380| v0_22(void) = UnmodeledUse : mu* +# 380| v0_23(void) = ExitFunction : # 384| void Switch(int) # 384| Block 0 @@ -1746,6 +1861,7 @@ ir.cpp: # 387| r1_0(int) = Constant[1234] : # 387| r1_1(glval) = VariableAddress[y] : # 387| mu1_2(int) = Store : &:r1_1, r1_0 +# 387| r1_3(glval) = CopyValue : r1_1 #-----| Goto -> Block 2 # 389| Block 2 @@ -1753,7 +1869,8 @@ ir.cpp: # 390| r2_1(int) = Constant[-1] : # 390| r2_2(glval) = VariableAddress[y] : # 390| mu2_3(int) = Store : &:r2_2, r2_1 -# 391| v2_4(void) = NoOp : +# 390| r2_4(glval) = CopyValue : r2_2 +# 391| v2_5(void) = NoOp : #-----| Goto -> Block 9 # 393| Block 3 @@ -1765,7 +1882,8 @@ ir.cpp: # 395| r4_1(int) = Constant[1] : # 395| r4_2(glval) = VariableAddress[y] : # 395| mu4_3(int) = Store : &:r4_2, r4_1 -# 396| v4_4(void) = NoOp : +# 395| r4_4(glval) = CopyValue : r4_2 +# 396| v4_5(void) = NoOp : #-----| Goto -> Block 9 # 398| Block 5 @@ -1773,6 +1891,7 @@ ir.cpp: # 399| r5_1(int) = Constant[3] : # 399| r5_2(glval) = VariableAddress[y] : # 399| mu5_3(int) = Store : &:r5_2, r5_1 +# 399| r5_4(glval) = CopyValue : r5_2 #-----| Goto -> Block 6 # 400| Block 6 @@ -1780,7 +1899,8 @@ ir.cpp: # 401| r6_1(int) = Constant[4] : # 401| r6_2(glval) = VariableAddress[y] : # 401| mu6_3(int) = Store : &:r6_2, r6_1 -# 402| v6_4(void) = NoOp : +# 401| r6_4(glval) = CopyValue : r6_2 +# 402| v6_5(void) = NoOp : #-----| Goto -> Block 9 # 404| Block 7 @@ -1788,13 +1908,15 @@ ir.cpp: # 405| r7_1(int) = Constant[0] : # 405| r7_2(glval) = VariableAddress[y] : # 405| mu7_3(int) = Store : &:r7_2, r7_1 -# 406| v7_4(void) = NoOp : +# 405| r7_4(glval) = CopyValue : r7_2 +# 406| v7_5(void) = NoOp : #-----| Goto -> Block 9 # 408| Block 8 # 408| r8_0(int) = Constant[5678] : # 408| r8_1(glval) = VariableAddress[y] : # 408| mu8_2(int) = Store : &:r8_1, r8_0 +# 408| r8_3(glval) = CopyValue : r8_1 #-----| Goto -> Block 9 # 409| Block 9 @@ -1831,20 +1953,23 @@ ir.cpp: # 428| r0_6(glval) = VariableAddress[pt] : # 428| r0_7(glval) = FieldAddress[x] : r0_6 # 428| mu0_8(int) = Store : &:r0_7, r0_5 -# 429| r0_9(glval) = VariableAddress[pt] : -# 429| r0_10(glval) = FieldAddress[x] : r0_9 -# 429| r0_11(int) = Load : &:r0_10, ~mu0_2 -# 429| r0_12(glval) = VariableAddress[pt] : -# 429| r0_13(glval) = FieldAddress[y] : r0_12 -# 429| mu0_14(int) = Store : &:r0_13, r0_11 -# 430| r0_15(glval) = VariableAddress[p] : -# 430| r0_16(glval) = VariableAddress[pt] : -# 430| r0_17(glval) = FieldAddress[y] : r0_16 -# 430| mu0_18(int *) = Store : &:r0_15, r0_17 -# 431| v0_19(void) = NoOp : -# 426| v0_20(void) = ReturnVoid : -# 426| v0_21(void) = UnmodeledUse : mu* -# 426| v0_22(void) = ExitFunction : +# 428| r0_9(glval) = CopyValue : r0_7 +# 429| r0_10(glval) = VariableAddress[pt] : +# 429| r0_11(glval) = FieldAddress[x] : r0_10 +# 429| r0_12(int) = Load : &:r0_11, ~mu0_2 +# 429| r0_13(glval) = VariableAddress[pt] : +# 429| r0_14(glval) = FieldAddress[y] : r0_13 +# 429| mu0_15(int) = Store : &:r0_14, r0_12 +# 429| r0_16(glval) = CopyValue : r0_14 +# 430| r0_17(glval) = VariableAddress[p] : +# 430| r0_18(glval) = VariableAddress[pt] : +# 430| r0_19(glval) = FieldAddress[y] : r0_18 +# 430| r0_20(int *) = CopyValue : r0_19 +# 430| mu0_21(int *) = Store : &:r0_17, r0_20 +# 431| v0_22(void) = NoOp : +# 426| v0_23(void) = ReturnVoid : +# 426| v0_24(void) = UnmodeledUse : mu* +# 426| v0_25(void) = ExitFunction : # 433| void LogicalOr(bool, bool) # 433| Block 0 @@ -1874,6 +1999,7 @@ ir.cpp: # 436| r2_0(int) = Constant[7] : # 436| r2_1(glval) = VariableAddress[x] : # 436| mu2_2(int) = Store : &:r2_1, r2_0 +# 436| r2_3(glval) = CopyValue : r2_1 #-----| Goto -> Block 3 # 439| Block 3 @@ -1894,12 +2020,14 @@ ir.cpp: # 440| r5_0(int) = Constant[1] : # 440| r5_1(glval) = VariableAddress[x] : # 440| mu5_2(int) = Store : &:r5_1, r5_0 +# 440| r5_3(glval) = CopyValue : r5_1 #-----| Goto -> Block 7 # 443| Block 6 # 443| r6_0(int) = Constant[5] : # 443| r6_1(glval) = VariableAddress[x] : # 443| mu6_2(int) = Store : &:r6_1, r6_0 +# 443| r6_3(glval) = CopyValue : r6_1 #-----| Goto -> Block 7 # 445| Block 7 @@ -1936,6 +2064,7 @@ ir.cpp: # 450| r2_0(int) = Constant[7] : # 450| r2_1(glval) = VariableAddress[x] : # 450| mu2_2(int) = Store : &:r2_1, r2_0 +# 450| r2_3(glval) = CopyValue : r2_1 #-----| Goto -> Block 3 # 453| Block 3 @@ -1956,12 +2085,14 @@ ir.cpp: # 454| r5_0(int) = Constant[1] : # 454| r5_1(glval) = VariableAddress[x] : # 454| mu5_2(int) = Store : &:r5_1, r5_0 +# 454| r5_3(glval) = CopyValue : r5_1 #-----| Goto -> Block 7 # 457| Block 6 # 457| r6_0(int) = Constant[5] : # 457| r6_1(glval) = VariableAddress[x] : # 457| mu6_2(int) = Store : &:r6_1, r6_0 +# 457| r6_3(glval) = CopyValue : r6_1 #-----| Goto -> Block 7 # 459| Block 7 @@ -1991,6 +2122,7 @@ ir.cpp: # 464| r1_0(int) = Constant[1] : # 464| r1_1(glval) = VariableAddress[x] : # 464| mu1_2(int) = Store : &:r1_1, r1_0 +# 464| r1_3(glval) = CopyValue : r1_1 #-----| Goto -> Block 2 # 467| Block 2 @@ -2011,12 +2143,14 @@ ir.cpp: # 468| r4_0(int) = Constant[2] : # 468| r4_1(glval) = VariableAddress[x] : # 468| mu4_2(int) = Store : &:r4_1, r4_0 +# 468| r4_3(glval) = CopyValue : r4_1 #-----| Goto -> Block 6 # 471| Block 5 # 471| r5_0(int) = Constant[3] : # 471| r5_1(glval) = VariableAddress[x] : # 471| mu5_2(int) = Store : &:r5_1, r5_0 +# 471| r5_3(glval) = CopyValue : r5_1 #-----| Goto -> Block 6 # 473| Block 6 @@ -2060,9 +2194,10 @@ ir.cpp: # 478| r3_1(bool) = Load : &:r3_0, ~mu0_2 # 478| r3_2(glval) = VariableAddress[x] : # 478| mu3_3(bool) = Store : &:r3_2, r3_1 -# 479| r3_4(glval) = VariableAddress[a] : -# 479| r3_5(bool) = Load : &:r3_4, ~mu0_2 -# 479| v3_6(void) = ConditionalBranch : r3_5 +# 478| r3_4(glval) = CopyValue : r3_2 +# 479| r3_5(glval) = VariableAddress[a] : +# 479| r3_6(bool) = Load : &:r3_5, ~mu0_2 +# 479| v3_7(void) = ConditionalBranch : r3_6 #-----| False -> Block 9 #-----| True -> Block 8 @@ -2091,10 +2226,11 @@ ir.cpp: # 479| r7_2(bool) = LogicalNot : r7_1 # 479| r7_3(glval) = VariableAddress[x] : # 479| mu7_4(bool) = Store : &:r7_3, r7_2 -# 480| v7_5(void) = NoOp : -# 475| v7_6(void) = ReturnVoid : -# 475| v7_7(void) = UnmodeledUse : mu* -# 475| v7_8(void) = ExitFunction : +# 479| r7_5(glval) = CopyValue : r7_3 +# 480| v7_6(void) = NoOp : +# 475| v7_7(void) = ReturnVoid : +# 475| v7_8(void) = UnmodeledUse : mu* +# 475| v7_9(void) = ExitFunction : # 479| Block 8 # 479| r8_0(glval) = VariableAddress[#temp479:11] : @@ -2120,9 +2256,10 @@ ir.cpp: # 477| r11_1(bool) = Load : &:r11_0, ~mu0_2 # 477| r11_2(glval) = VariableAddress[x] : # 477| mu11_3(bool) = Store : &:r11_2, r11_1 -# 478| r11_4(glval) = VariableAddress[a] : -# 478| r11_5(bool) = Load : &:r11_4, ~mu0_2 -# 478| v11_6(void) = ConditionalBranch : r11_5 +# 477| r11_4(glval) = CopyValue : r11_2 +# 478| r11_5(glval) = VariableAddress[a] : +# 478| r11_6(bool) = Load : &:r11_5, ~mu0_2 +# 478| v11_7(void) = ConditionalBranch : r11_6 #-----| False -> Block 5 #-----| True -> Block 4 @@ -2195,10 +2332,11 @@ ir.cpp: # 489| r1_0(glval) = VariableAddress[#temp489:6] : # 489| r1_1(glval) = Load : &:r1_0, ~mu0_2 # 489| mu1_2(int) = Store : &:r1_1, r0_9 -# 490| v1_3(void) = NoOp : -# 486| v1_4(void) = ReturnVoid : -# 486| v1_5(void) = UnmodeledUse : mu* -# 486| v1_6(void) = ExitFunction : +# 489| r1_3(glval) = CopyValue : r1_1 +# 490| v1_4(void) = NoOp : +# 486| v1_5(void) = ReturnVoid : +# 486| v1_6(void) = UnmodeledUse : mu* +# 486| v1_7(void) = ExitFunction : # 489| Block 2 # 489| r2_0(glval) = VariableAddress[x] : @@ -2257,13 +2395,15 @@ ir.cpp: # 499| r0_9(int *) = Constant[0] : # 499| r0_10(glval) = VariableAddress[p] : # 499| mu0_11(int *) = Store : &:r0_10, r0_9 -# 500| r0_12(int *) = Constant[0] : -# 500| r0_13(glval) = VariableAddress[q] : -# 500| mu0_14(int *) = Store : &:r0_13, r0_12 -# 501| v0_15(void) = NoOp : -# 496| v0_16(void) = ReturnVoid : -# 496| v0_17(void) = UnmodeledUse : mu* -# 496| v0_18(void) = ExitFunction : +# 499| r0_12(glval) = CopyValue : r0_10 +# 500| r0_13(int *) = Constant[0] : +# 500| r0_14(glval) = VariableAddress[q] : +# 500| mu0_15(int *) = Store : &:r0_14, r0_13 +# 500| r0_16(glval) = CopyValue : r0_14 +# 501| v0_17(void) = NoOp : +# 496| v0_18(void) = ReturnVoid : +# 496| v0_19(void) = UnmodeledUse : mu* +# 496| v0_20(void) = ExitFunction : # 503| void InitList(int, float) # 503| Block 0 @@ -2491,7 +2631,8 @@ ir.cpp: # 540| r3_1(int) = Load : &:r3_0, ~mu0_2 # 540| r3_2(glval) = VariableAddress[y] : # 540| mu3_3(int) = Store : &:r3_2, r3_1 -# 541| v3_4(void) = NoOp : +# 540| r3_4(glval) = CopyValue : r3_2 +# 541| v3_5(void) = NoOp : #-----| Goto -> Block 1 # 543| int EarlyReturnValue(int, int) @@ -2687,18 +2828,27 @@ ir.cpp: # 591| r0_4(glval<..(*)(..)>) = FunctionAddress[FuncPtrTarget] : # 591| mu0_5(..(*)(..)) = Store : &:r0_3, r0_4 # 592| r0_6(glval<..()(..)>) = FunctionAddress[FuncPtrTarget] : -# 592| r0_7(glval<..(*)(..)>) = VariableAddress[pfn] : -# 592| mu0_8(..(*)(..)) = Store : &:r0_7, r0_6 -# 593| r0_9(glval<..(*)(..)>) = FunctionAddress[FuncPtrTarget] : -# 593| r0_10(glval<..(*)(..)>) = VariableAddress[pfn] : -# 593| mu0_11(..(*)(..)) = Store : &:r0_10, r0_9 -# 594| r0_12(glval<..()(..)>) = FunctionAddress[FuncPtrTarget] : -# 594| r0_13(glval<..(*)(..)>) = VariableAddress[pfn] : -# 594| mu0_14(..(*)(..)) = Store : &:r0_13, r0_12 -# 595| v0_15(void) = NoOp : -# 590| v0_16(void) = ReturnVoid : -# 590| v0_17(void) = UnmodeledUse : mu* -# 590| v0_18(void) = ExitFunction : +# 592| r0_7(..(*)(..)) = CopyValue : r0_6 +# 592| r0_8(glval<..(*)(..)>) = VariableAddress[pfn] : +# 592| mu0_9(..(*)(..)) = Store : &:r0_8, r0_7 +# 592| r0_10(glval<..(*)(..)>) = CopyValue : r0_8 +# 593| r0_11(glval<..(*)(..)>) = FunctionAddress[FuncPtrTarget] : +# 593| r0_12(..(*)(..)) = CopyValue : r0_11 +# 593| r0_13(glval<..(*)(..)>) = VariableAddress[pfn] : +# 593| mu0_14(..(*)(..)) = Store : &:r0_13, r0_12 +# 593| r0_15(glval<..(*)(..)>) = CopyValue : r0_13 +# 594| r0_16(glval<..()(..)>) = FunctionAddress[FuncPtrTarget] : +# 594| r0_17(..(*)(..)) = CopyValue : r0_16 +# 594| r0_18(..(*)(..)) = CopyValue : r0_17 +# 594| r0_19(..(*)(..)) = CopyValue : r0_18 +# 594| r0_20(..(*)(..)) = CopyValue : r0_19 +# 594| r0_21(glval<..(*)(..)>) = VariableAddress[pfn] : +# 594| mu0_22(..(*)(..)) = Store : &:r0_21, r0_20 +# 594| r0_23(glval<..(*)(..)>) = CopyValue : r0_21 +# 595| v0_24(void) = NoOp : +# 590| v0_25(void) = ReturnVoid : +# 590| v0_26(void) = UnmodeledUse : mu* +# 590| v0_27(void) = ExitFunction : # 615| void DeclareObject() # 615| Block 0 @@ -2744,25 +2894,26 @@ ir.cpp: # 622| mu0_8(String) = InitializeParameter[s] : &:r0_7 # 623| r0_9(glval) = VariableAddress[r] : # 623| r0_10(String &) = Load : &:r0_9, ~mu0_2 -# 623| r0_11(glval) = Convert : r0_10 -# 623| r0_12(glval) = FunctionAddress[c_str] : -# 623| r0_13(char *) = Call : func:r0_12, this:r0_11 -# 623| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 -# 624| r0_15(glval) = VariableAddress[p] : -# 624| r0_16(String *) = Load : &:r0_15, ~mu0_2 -# 624| r0_17(String *) = Convert : r0_16 -# 624| r0_18(glval) = FunctionAddress[c_str] : -# 624| r0_19(char *) = Call : func:r0_18, this:r0_17 -# 624| mu0_20(unknown) = ^CallSideEffect : ~mu0_2 -# 625| r0_21(glval) = VariableAddress[s] : -# 625| r0_22(glval) = Convert : r0_21 -# 625| r0_23(glval) = FunctionAddress[c_str] : -# 625| r0_24(char *) = Call : func:r0_23, this:r0_22 -# 625| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 626| v0_26(void) = NoOp : -# 622| v0_27(void) = ReturnVoid : -# 622| v0_28(void) = UnmodeledUse : mu* -# 622| v0_29(void) = ExitFunction : +# 623| r0_11(glval) = CopyValue : r0_10 +# 623| r0_12(glval) = Convert : r0_11 +# 623| r0_13(glval) = FunctionAddress[c_str] : +# 623| r0_14(char *) = Call : func:r0_13, this:r0_12 +# 623| mu0_15(unknown) = ^CallSideEffect : ~mu0_2 +# 624| r0_16(glval) = VariableAddress[p] : +# 624| r0_17(String *) = Load : &:r0_16, ~mu0_2 +# 624| r0_18(String *) = Convert : r0_17 +# 624| r0_19(glval) = FunctionAddress[c_str] : +# 624| r0_20(char *) = Call : func:r0_19, this:r0_18 +# 624| mu0_21(unknown) = ^CallSideEffect : ~mu0_2 +# 625| r0_22(glval) = VariableAddress[s] : +# 625| r0_23(glval) = Convert : r0_22 +# 625| r0_24(glval) = FunctionAddress[c_str] : +# 625| r0_25(char *) = Call : func:r0_24, this:r0_23 +# 625| mu0_26(unknown) = ^CallSideEffect : ~mu0_2 +# 626| v0_27(void) = NoOp : +# 622| v0_28(void) = ReturnVoid : +# 622| v0_29(void) = UnmodeledUse : mu* +# 622| v0_30(void) = ExitFunction : # 630| int C::StaticMemberFunction(int) # 630| Block 0 @@ -2824,35 +2975,43 @@ ir.cpp: # 643| r0_5(C *) = CopyValue : r0_3 # 643| r0_6(glval) = FieldAddress[m_a] : r0_5 # 643| mu0_7(int) = Store : &:r0_6, r0_4 -# 644| r0_8(int) = Constant[1] : -# 644| r0_9(C *) = CopyValue : r0_3 -# 644| r0_10(glval) = FieldAddress[m_a] : r0_9 -# 644| mu0_11(int) = Store : &:r0_10, r0_8 -# 645| r0_12(int) = Constant[2] : -#-----| r0_13(C *) = CopyValue : r0_3 -# 645| r0_14(glval) = FieldAddress[m_a] : r0_13 -# 645| mu0_15(int) = Store : &:r0_14, r0_12 -# 646| r0_16(glval) = VariableAddress[x] : -# 646| mu0_17(int) = Uninitialized[x] : &:r0_16 -# 647| r0_18(C *) = CopyValue : r0_3 -# 647| r0_19(glval) = FieldAddress[m_a] : r0_18 -# 647| r0_20(int) = Load : &:r0_19, ~mu0_2 -# 647| r0_21(glval) = VariableAddress[x] : -# 647| mu0_22(int) = Store : &:r0_21, r0_20 -# 648| r0_23(C *) = CopyValue : r0_3 -# 648| r0_24(glval) = FieldAddress[m_a] : r0_23 -# 648| r0_25(int) = Load : &:r0_24, ~mu0_2 -# 648| r0_26(glval) = VariableAddress[x] : -# 648| mu0_27(int) = Store : &:r0_26, r0_25 -#-----| r0_28(C *) = CopyValue : r0_3 -# 649| r0_29(glval) = FieldAddress[m_a] : r0_28 -# 649| r0_30(int) = Load : &:r0_29, ~mu0_2 -# 649| r0_31(glval) = VariableAddress[x] : -# 649| mu0_32(int) = Store : &:r0_31, r0_30 -# 650| v0_33(void) = NoOp : -# 642| v0_34(void) = ReturnVoid : -# 642| v0_35(void) = UnmodeledUse : mu* -# 642| v0_36(void) = ExitFunction : +# 643| r0_8(glval) = CopyValue : r0_6 +# 644| r0_9(int) = Constant[1] : +# 644| r0_10(C *) = CopyValue : r0_3 +# 644| r0_11(glval) = CopyValue : r0_10 +# 644| r0_12(glval) = FieldAddress[m_a] : r0_11 +# 644| mu0_13(int) = Store : &:r0_12, r0_9 +# 644| r0_14(glval) = CopyValue : r0_12 +# 645| r0_15(int) = Constant[2] : +#-----| r0_16(C *) = CopyValue : r0_3 +# 645| r0_17(glval) = FieldAddress[m_a] : r0_16 +# 645| mu0_18(int) = Store : &:r0_17, r0_15 +# 645| r0_19(glval) = CopyValue : r0_17 +# 646| r0_20(glval) = VariableAddress[x] : +# 646| mu0_21(int) = Uninitialized[x] : &:r0_20 +# 647| r0_22(C *) = CopyValue : r0_3 +# 647| r0_23(glval) = FieldAddress[m_a] : r0_22 +# 647| r0_24(int) = Load : &:r0_23, ~mu0_2 +# 647| r0_25(glval) = VariableAddress[x] : +# 647| mu0_26(int) = Store : &:r0_25, r0_24 +# 647| r0_27(glval) = CopyValue : r0_25 +# 648| r0_28(C *) = CopyValue : r0_3 +# 648| r0_29(glval) = CopyValue : r0_28 +# 648| r0_30(glval) = FieldAddress[m_a] : r0_29 +# 648| r0_31(int) = Load : &:r0_30, ~mu0_2 +# 648| r0_32(glval) = VariableAddress[x] : +# 648| mu0_33(int) = Store : &:r0_32, r0_31 +# 648| r0_34(glval) = CopyValue : r0_32 +#-----| r0_35(C *) = CopyValue : r0_3 +# 649| r0_36(glval) = FieldAddress[m_a] : r0_35 +# 649| r0_37(int) = Load : &:r0_36, ~mu0_2 +# 649| r0_38(glval) = VariableAddress[x] : +# 649| mu0_39(int) = Store : &:r0_38, r0_37 +# 649| r0_40(glval) = CopyValue : r0_38 +# 650| v0_41(void) = NoOp : +# 642| v0_42(void) = ReturnVoid : +# 642| v0_43(void) = UnmodeledUse : mu* +# 642| v0_44(void) = ExitFunction : # 652| void C::MethodCalls() # 652| Block 0 @@ -2866,19 +3025,20 @@ ir.cpp: # 653| r0_7(int) = Call : func:r0_5, this:r0_4, 0:r0_6 # 653| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 # 654| r0_9(C *) = CopyValue : r0_3 -# 654| r0_10(glval) = FunctionAddress[InstanceMemberFunction] : -# 654| r0_11(int) = Constant[1] : -# 654| r0_12(int) = Call : func:r0_10, this:r0_9, 0:r0_11 -# 654| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_14(C *) = CopyValue : r0_3 -# 655| r0_15(glval) = FunctionAddress[InstanceMemberFunction] : -# 655| r0_16(int) = Constant[2] : -# 655| r0_17(int) = Call : func:r0_15, this:r0_14, 0:r0_16 -# 655| mu0_18(unknown) = ^CallSideEffect : ~mu0_2 -# 656| v0_19(void) = NoOp : -# 652| v0_20(void) = ReturnVoid : -# 652| v0_21(void) = UnmodeledUse : mu* -# 652| v0_22(void) = ExitFunction : +# 654| r0_10(glval) = CopyValue : r0_9 +# 654| r0_11(glval) = FunctionAddress[InstanceMemberFunction] : +# 654| r0_12(int) = Constant[1] : +# 654| r0_13(int) = Call : func:r0_11, this:r0_10, 0:r0_12 +# 654| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 +#-----| r0_15(C *) = CopyValue : r0_3 +# 655| r0_16(glval) = FunctionAddress[InstanceMemberFunction] : +# 655| r0_17(int) = Constant[2] : +# 655| r0_18(int) = Call : func:r0_16, this:r0_15, 0:r0_17 +# 655| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 +# 656| v0_20(void) = NoOp : +# 652| v0_21(void) = ReturnVoid : +# 652| v0_22(void) = UnmodeledUse : mu* +# 652| v0_23(void) = ExitFunction : # 658| void C::C() # 658| Block 0 @@ -2934,11 +3094,12 @@ ir.cpp: # 679| mu0_2(unknown) = UnmodeledDefinition : # 680| r0_3(glval) = VariableAddress[#return] : # 680| r0_4(glval) = VariableAddress[g] : -# 680| mu0_5(int &) = Store : &:r0_3, r0_4 -# 679| r0_6(glval) = VariableAddress[#return] : -# 679| v0_7(void) = ReturnValue : &:r0_6, ~mu0_2 -# 679| v0_8(void) = UnmodeledUse : mu* -# 679| v0_9(void) = ExitFunction : +# 680| r0_5(int &) = CopyValue : r0_4 +# 680| mu0_6(int &) = Store : &:r0_3, r0_5 +# 679| r0_7(glval) = VariableAddress[#return] : +# 679| v0_8(void) = ReturnValue : &:r0_7, ~mu0_2 +# 679| v0_9(void) = UnmodeledUse : mu* +# 679| v0_10(void) = ExitFunction : # 685| void InitReference(int) # 685| Block 0 @@ -2949,44 +3110,51 @@ ir.cpp: # 685| mu0_4(int) = InitializeParameter[x] : &:r0_3 # 686| r0_5(glval) = VariableAddress[r] : # 686| r0_6(glval) = VariableAddress[x] : -# 686| mu0_7(int &) = Store : &:r0_5, r0_6 -# 687| r0_8(glval) = VariableAddress[r2] : -# 687| r0_9(glval) = VariableAddress[r] : -# 687| r0_10(int &) = Load : &:r0_9, ~mu0_2 -# 687| mu0_11(int &) = Store : &:r0_8, r0_10 -# 688| r0_12(glval) = VariableAddress[r3] : -# 688| r0_13(glval) = FunctionAddress[ReturnReference] : -# 688| r0_14(String &) = Call : func:r0_13 -# 688| mu0_15(unknown) = ^CallSideEffect : ~mu0_2 -# 688| r0_16(glval) = Convert : r0_14 -# 688| mu0_17(String &) = Store : &:r0_12, r0_16 -# 689| v0_18(void) = NoOp : -# 685| v0_19(void) = ReturnVoid : -# 685| v0_20(void) = UnmodeledUse : mu* -# 685| v0_21(void) = ExitFunction : +# 686| r0_7(int &) = CopyValue : r0_6 +# 686| mu0_8(int &) = Store : &:r0_5, r0_7 +# 687| r0_9(glval) = VariableAddress[r2] : +# 687| r0_10(glval) = VariableAddress[r] : +# 687| r0_11(int &) = Load : &:r0_10, ~mu0_2 +# 687| r0_12(glval) = CopyValue : r0_11 +# 687| r0_13(int &) = CopyValue : r0_12 +# 687| mu0_14(int &) = Store : &:r0_9, r0_13 +# 688| r0_15(glval) = VariableAddress[r3] : +# 688| r0_16(glval) = FunctionAddress[ReturnReference] : +# 688| r0_17(String &) = Call : func:r0_16 +# 688| mu0_18(unknown) = ^CallSideEffect : ~mu0_2 +# 688| r0_19(glval) = CopyValue : r0_17 +# 688| r0_20(glval) = Convert : r0_19 +# 688| r0_21(String &) = CopyValue : r0_20 +# 688| mu0_22(String &) = Store : &:r0_15, r0_21 +# 689| v0_23(void) = NoOp : +# 685| v0_24(void) = ReturnVoid : +# 685| v0_25(void) = UnmodeledUse : mu* +# 685| v0_26(void) = ExitFunction : # 691| void ArrayReferences() # 691| Block 0 -# 691| v0_0(void) = EnterFunction : -# 691| mu0_1(unknown) = AliasedDefinition : -# 691| mu0_2(unknown) = UnmodeledDefinition : -# 692| r0_3(glval) = VariableAddress[a] : -# 692| mu0_4(int[10]) = Uninitialized[a] : &:r0_3 -# 693| r0_5(glval) = VariableAddress[ra] : -# 693| r0_6(glval) = VariableAddress[a] : -# 693| mu0_7(int(&)[10]) = Store : &:r0_5, r0_6 -# 694| r0_8(glval) = VariableAddress[x] : -# 694| r0_9(glval) = VariableAddress[ra] : -# 694| r0_10(int(&)[10]) = Load : &:r0_9, ~mu0_2 -# 694| r0_11(int *) = Convert : r0_10 -# 694| r0_12(int) = Constant[5] : -# 694| r0_13(glval) = PointerAdd[4] : r0_11, r0_12 -# 694| r0_14(int) = Load : &:r0_13, ~mu0_2 -# 694| mu0_15(int) = Store : &:r0_8, r0_14 -# 695| v0_16(void) = NoOp : -# 691| v0_17(void) = ReturnVoid : -# 691| v0_18(void) = UnmodeledUse : mu* -# 691| v0_19(void) = ExitFunction : +# 691| v0_0(void) = EnterFunction : +# 691| mu0_1(unknown) = AliasedDefinition : +# 691| mu0_2(unknown) = UnmodeledDefinition : +# 692| r0_3(glval) = VariableAddress[a] : +# 692| mu0_4(int[10]) = Uninitialized[a] : &:r0_3 +# 693| r0_5(glval) = VariableAddress[ra] : +# 693| r0_6(glval) = VariableAddress[a] : +# 693| r0_7(int(&)[10]) = CopyValue : r0_6 +# 693| mu0_8(int(&)[10]) = Store : &:r0_5, r0_7 +# 694| r0_9(glval) = VariableAddress[x] : +# 694| r0_10(glval) = VariableAddress[ra] : +# 694| r0_11(int(&)[10]) = Load : &:r0_10, ~mu0_2 +# 694| r0_12(glval) = CopyValue : r0_11 +# 694| r0_13(int *) = Convert : r0_12 +# 694| r0_14(int) = Constant[5] : +# 694| r0_15(glval) = PointerAdd[4] : r0_13, r0_14 +# 694| r0_16(int) = Load : &:r0_15, ~mu0_2 +# 694| mu0_17(int) = Store : &:r0_9, r0_16 +# 695| v0_18(void) = NoOp : +# 691| v0_19(void) = ReturnVoid : +# 691| v0_20(void) = UnmodeledUse : mu* +# 691| v0_21(void) = ExitFunction : # 697| void FunctionReferences() # 697| Block 0 @@ -2995,20 +3163,23 @@ ir.cpp: # 697| mu0_2(unknown) = UnmodeledDefinition : # 698| r0_3(glval<..(&)(..)>) = VariableAddress[rfn] : # 698| r0_4(glval<..()(..)>) = FunctionAddress[FuncPtrTarget] : -# 698| mu0_5(..(&)(..)) = Store : &:r0_3, r0_4 -# 699| r0_6(glval<..(*)(..)>) = VariableAddress[pfn] : -# 699| r0_7(glval<..(&)(..)>) = VariableAddress[rfn] : -# 699| r0_8(..(&)(..)) = Load : &:r0_7, ~mu0_2 -# 699| mu0_9(..(*)(..)) = Store : &:r0_6, r0_8 -# 700| r0_10(glval<..(&)(..)>) = VariableAddress[rfn] : -# 700| r0_11(..(&)(..)) = Load : &:r0_10, ~mu0_2 -# 700| r0_12(int) = Constant[5] : -# 700| r0_13(int) = Call : func:r0_11, 0:r0_12 -# 700| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 -# 701| v0_15(void) = NoOp : -# 697| v0_16(void) = ReturnVoid : -# 697| v0_17(void) = UnmodeledUse : mu* -# 697| v0_18(void) = ExitFunction : +# 698| r0_5(..(&)(..)) = CopyValue : r0_4 +# 698| mu0_6(..(&)(..)) = Store : &:r0_3, r0_5 +# 699| r0_7(glval<..(*)(..)>) = VariableAddress[pfn] : +# 699| r0_8(glval<..(&)(..)>) = VariableAddress[rfn] : +# 699| r0_9(..(&)(..)) = Load : &:r0_8, ~mu0_2 +# 699| r0_10(..(*)(..)) = CopyValue : r0_9 +# 699| mu0_11(..(*)(..)) = Store : &:r0_7, r0_10 +# 700| r0_12(glval<..(&)(..)>) = VariableAddress[rfn] : +# 700| r0_13(..(&)(..)) = Load : &:r0_12, ~mu0_2 +# 700| r0_14(..(*)(..)) = CopyValue : r0_13 +# 700| r0_15(int) = Constant[5] : +# 700| r0_16(int) = Call : func:r0_14, 0:r0_15 +# 700| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 +# 701| v0_18(void) = NoOp : +# 697| v0_19(void) = ReturnVoid : +# 697| v0_20(void) = UnmodeledUse : mu* +# 697| v0_21(void) = ExitFunction : # 704| int min(int, int) # 704| Block 0 @@ -3166,6 +3337,7 @@ ir.cpp: # 731| r6_4(int) = Load : &:r6_3, ~mu0_2 # 731| r6_5(glval) = VariableAddress[x] : # 731| mu6_6(int) = Store : &:r6_5, r6_4 +# 731| r6_7(glval) = CopyValue : r6_5 #-----| Goto -> Block 8 # 731| Block 7 @@ -3182,6 +3354,7 @@ ir.cpp: # 733| r8_0(int) = Constant[7] : # 733| r8_1(glval) = VariableAddress[x] : # 733| mu8_2(int) = Store : &:r8_1, r8_0 +# 733| r8_3(glval) = CopyValue : r8_1 #-----| Goto -> Block 14 # 735| Block 9 @@ -3232,19 +3405,25 @@ ir.cpp: #-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 #-----| r0_6(Base *) = CopyValue : r0_3 #-----| r0_7(glval) = FieldAddress[base_s] : r0_6 -# 745| r0_8(glval) = FunctionAddress[operator=] : -#-----| r0_9(glval) = VariableAddress[p#0] : -#-----| r0_10(Base &) = Load : &:r0_9, ~mu0_2 -#-----| r0_11(glval) = FieldAddress[base_s] : r0_10 -# 745| r0_12(String &) = Call : func:r0_8, this:r0_7, 0:r0_11 -# 745| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_14(glval) = VariableAddress[#return] : -#-----| r0_15(Base *) = CopyValue : r0_3 -#-----| mu0_16(Base &) = Store : &:r0_14, r0_15 -# 745| r0_17(glval) = VariableAddress[#return] : -# 745| v0_18(void) = ReturnValue : &:r0_17, ~mu0_2 -# 745| v0_19(void) = UnmodeledUse : mu* -# 745| v0_20(void) = ExitFunction : +#-----| r0_8(String *) = CopyValue : r0_7 +# 745| r0_9(glval) = FunctionAddress[operator=] : +#-----| r0_10(glval) = VariableAddress[p#0] : +#-----| r0_11(Base &) = Load : &:r0_10, ~mu0_2 +#-----| r0_12(glval) = CopyValue : r0_11 +#-----| r0_13(glval) = FieldAddress[base_s] : r0_12 +#-----| r0_14(String &) = CopyValue : r0_13 +# 745| r0_15(String &) = Call : func:r0_9, this:r0_8, 0:r0_14 +# 745| mu0_16(unknown) = ^CallSideEffect : ~mu0_2 +#-----| r0_17(glval) = CopyValue : r0_15 +#-----| r0_18(glval) = VariableAddress[#return] : +#-----| r0_19(Base *) = CopyValue : r0_3 +#-----| r0_20(glval) = CopyValue : r0_19 +#-----| r0_21(Base &) = CopyValue : r0_20 +#-----| mu0_22(Base &) = Store : &:r0_18, r0_21 +# 745| r0_23(glval) = VariableAddress[#return] : +# 745| v0_24(void) = ReturnValue : &:r0_23, ~mu0_2 +# 745| v0_25(void) = UnmodeledUse : mu* +# 745| v0_26(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 @@ -3306,24 +3485,35 @@ ir.cpp: # 754| r0_8(glval) = FunctionAddress[operator=] : #-----| r0_9(glval) = VariableAddress[p#0] : #-----| r0_10(Middle &) = Load : &:r0_9, ~mu0_2 -#-----| r0_11(Base *) = ConvertToBase[Middle : Base] : r0_10 -# 754| r0_12(Base &) = Call : func:r0_8, this:r0_7, 0:r0_11 -# 754| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_14(Middle *) = CopyValue : r0_3 -#-----| r0_15(glval) = FieldAddress[middle_s] : r0_14 -# 754| r0_16(glval) = FunctionAddress[operator=] : -#-----| r0_17(glval) = VariableAddress[p#0] : -#-----| r0_18(Middle &) = Load : &:r0_17, ~mu0_2 -#-----| r0_19(glval) = FieldAddress[middle_s] : r0_18 -# 754| r0_20(String &) = Call : func:r0_16, this:r0_15, 0:r0_19 -# 754| mu0_21(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_22(glval) = VariableAddress[#return] : -#-----| r0_23(Middle *) = CopyValue : r0_3 -#-----| mu0_24(Middle &) = Store : &:r0_22, r0_23 -# 754| r0_25(glval) = VariableAddress[#return] : -# 754| v0_26(void) = ReturnValue : &:r0_25, ~mu0_2 -# 754| v0_27(void) = UnmodeledUse : mu* -# 754| v0_28(void) = ExitFunction : +#-----| r0_11(glval) = CopyValue : r0_10 +#-----| r0_12(Middle *) = CopyValue : r0_11 +#-----| r0_13(Base *) = ConvertToBase[Middle : Base] : r0_12 +#-----| r0_14(glval) = CopyValue : r0_13 +#-----| r0_15(Base &) = CopyValue : r0_14 +# 754| r0_16(Base &) = Call : func:r0_8, this:r0_7, 0:r0_15 +# 754| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 +#-----| r0_18(glval) = CopyValue : r0_16 +#-----| r0_19(Middle *) = CopyValue : r0_3 +#-----| r0_20(glval) = FieldAddress[middle_s] : r0_19 +#-----| r0_21(String *) = CopyValue : r0_20 +# 754| r0_22(glval) = FunctionAddress[operator=] : +#-----| r0_23(glval) = VariableAddress[p#0] : +#-----| r0_24(Middle &) = Load : &:r0_23, ~mu0_2 +#-----| r0_25(glval) = CopyValue : r0_24 +#-----| r0_26(glval) = FieldAddress[middle_s] : r0_25 +#-----| r0_27(String &) = CopyValue : r0_26 +# 754| r0_28(String &) = Call : func:r0_22, this:r0_21, 0:r0_27 +# 754| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 +#-----| r0_30(glval) = CopyValue : r0_28 +#-----| r0_31(glval) = VariableAddress[#return] : +#-----| r0_32(Middle *) = CopyValue : r0_3 +#-----| r0_33(glval) = CopyValue : r0_32 +#-----| r0_34(Middle &) = CopyValue : r0_33 +#-----| mu0_35(Middle &) = Store : &:r0_31, r0_34 +# 754| r0_36(glval) = VariableAddress[#return] : +# 754| v0_37(void) = ReturnValue : &:r0_36, ~mu0_2 +# 754| v0_38(void) = UnmodeledUse : mu* +# 754| v0_39(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 @@ -3376,24 +3566,35 @@ ir.cpp: # 763| r0_8(glval) = FunctionAddress[operator=] : #-----| r0_9(glval) = VariableAddress[p#0] : #-----| r0_10(Derived &) = Load : &:r0_9, ~mu0_2 -#-----| r0_11(Middle *) = ConvertToBase[Derived : Middle] : r0_10 -# 763| r0_12(Middle &) = Call : func:r0_8, this:r0_7, 0:r0_11 -# 763| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_14(Derived *) = CopyValue : r0_3 -#-----| r0_15(glval) = FieldAddress[derived_s] : r0_14 -# 763| r0_16(glval) = FunctionAddress[operator=] : -#-----| r0_17(glval) = VariableAddress[p#0] : -#-----| r0_18(Derived &) = Load : &:r0_17, ~mu0_2 -#-----| r0_19(glval) = FieldAddress[derived_s] : r0_18 -# 763| r0_20(String &) = Call : func:r0_16, this:r0_15, 0:r0_19 -# 763| mu0_21(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_22(glval) = VariableAddress[#return] : -#-----| r0_23(Derived *) = CopyValue : r0_3 -#-----| mu0_24(Derived &) = Store : &:r0_22, r0_23 -# 763| r0_25(glval) = VariableAddress[#return] : -# 763| v0_26(void) = ReturnValue : &:r0_25, ~mu0_2 -# 763| v0_27(void) = UnmodeledUse : mu* -# 763| v0_28(void) = ExitFunction : +#-----| r0_11(glval) = CopyValue : r0_10 +#-----| r0_12(Derived *) = CopyValue : r0_11 +#-----| r0_13(Middle *) = ConvertToBase[Derived : Middle] : r0_12 +#-----| r0_14(glval) = CopyValue : r0_13 +#-----| r0_15(Middle &) = CopyValue : r0_14 +# 763| r0_16(Middle &) = Call : func:r0_8, this:r0_7, 0:r0_15 +# 763| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 +#-----| r0_18(glval) = CopyValue : r0_16 +#-----| r0_19(Derived *) = CopyValue : r0_3 +#-----| r0_20(glval) = FieldAddress[derived_s] : r0_19 +#-----| r0_21(String *) = CopyValue : r0_20 +# 763| r0_22(glval) = FunctionAddress[operator=] : +#-----| r0_23(glval) = VariableAddress[p#0] : +#-----| r0_24(Derived &) = Load : &:r0_23, ~mu0_2 +#-----| r0_25(glval) = CopyValue : r0_24 +#-----| r0_26(glval) = FieldAddress[derived_s] : r0_25 +#-----| r0_27(String &) = CopyValue : r0_26 +# 763| r0_28(String &) = Call : func:r0_22, this:r0_21, 0:r0_27 +# 763| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 +#-----| r0_30(glval) = CopyValue : r0_28 +#-----| r0_31(glval) = VariableAddress[#return] : +#-----| r0_32(Derived *) = CopyValue : r0_3 +#-----| r0_33(glval) = CopyValue : r0_32 +#-----| r0_34(Derived &) = CopyValue : r0_33 +#-----| mu0_35(Derived &) = Store : &:r0_31, r0_34 +# 763| r0_36(glval) = VariableAddress[#return] : +# 763| v0_37(void) = ReturnValue : &:r0_36, ~mu0_2 +# 763| v0_38(void) = UnmodeledUse : mu* +# 763| v0_39(void) = ExitFunction : # 766| void Derived::Derived() # 766| Block 0 @@ -3582,193 +3783,236 @@ ir.cpp: # 802| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 # 804| r0_15(glval) = VariableAddress[pb] : # 804| r0_16(glval) = VariableAddress[b] : -# 804| mu0_17(Base *) = Store : &:r0_15, r0_16 -# 805| r0_18(glval) = VariableAddress[pm] : -# 805| r0_19(glval) = VariableAddress[m] : -# 805| mu0_20(Middle *) = Store : &:r0_18, r0_19 -# 806| r0_21(glval) = VariableAddress[pd] : -# 806| r0_22(glval) = VariableAddress[d] : -# 806| mu0_23(Derived *) = Store : &:r0_21, r0_22 -# 808| r0_24(glval) = VariableAddress[b] : -# 808| r0_25(glval) = FunctionAddress[operator=] : -# 808| r0_26(glval) = VariableAddress[m] : -# 808| r0_27(glval) = ConvertToBase[Middle : Base] : r0_26 -# 808| r0_28(Base &) = Call : func:r0_25, this:r0_24, 0:r0_27 -# 808| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 -# 809| r0_30(glval) = VariableAddress[b] : -# 809| r0_31(glval) = FunctionAddress[operator=] : -# 809| r0_32(glval) = FunctionAddress[Base] : -# 809| r0_33(glval) = VariableAddress[m] : -# 809| r0_34(glval) = ConvertToBase[Middle : Base] : r0_33 -# 809| v0_35(void) = Call : func:r0_32, 0:r0_34 -# 809| mu0_36(unknown) = ^CallSideEffect : ~mu0_2 -# 809| r0_37(glval) = Convert : v0_35 -# 809| r0_38(Base &) = Call : func:r0_31, this:r0_30, 0:r0_37 -# 809| mu0_39(unknown) = ^CallSideEffect : ~mu0_2 -# 810| r0_40(glval) = VariableAddress[b] : -# 810| r0_41(glval) = FunctionAddress[operator=] : -# 810| r0_42(glval) = FunctionAddress[Base] : -# 810| r0_43(glval) = VariableAddress[m] : -# 810| r0_44(glval) = ConvertToBase[Middle : Base] : r0_43 -# 810| v0_45(void) = Call : func:r0_42, 0:r0_44 -# 810| mu0_46(unknown) = ^CallSideEffect : ~mu0_2 -# 810| r0_47(glval) = Convert : v0_45 -# 810| r0_48(Base &) = Call : func:r0_41, this:r0_40, 0:r0_47 -# 810| mu0_49(unknown) = ^CallSideEffect : ~mu0_2 -# 811| r0_50(glval) = VariableAddress[pm] : -# 811| r0_51(Middle *) = Load : &:r0_50, ~mu0_2 -# 811| r0_52(Base *) = ConvertToBase[Middle : Base] : r0_51 -# 811| r0_53(glval) = VariableAddress[pb] : -# 811| mu0_54(Base *) = Store : &:r0_53, r0_52 -# 812| r0_55(glval) = VariableAddress[pm] : -# 812| r0_56(Middle *) = Load : &:r0_55, ~mu0_2 -# 812| r0_57(Base *) = ConvertToBase[Middle : Base] : r0_56 -# 812| r0_58(glval) = VariableAddress[pb] : -# 812| mu0_59(Base *) = Store : &:r0_58, r0_57 -# 813| r0_60(glval) = VariableAddress[pm] : -# 813| r0_61(Middle *) = Load : &:r0_60, ~mu0_2 -# 813| r0_62(Base *) = ConvertToBase[Middle : Base] : r0_61 -# 813| r0_63(glval) = VariableAddress[pb] : -# 813| mu0_64(Base *) = Store : &:r0_63, r0_62 -# 814| r0_65(glval) = VariableAddress[pm] : -# 814| r0_66(Middle *) = Load : &:r0_65, ~mu0_2 -# 814| r0_67(Base *) = Convert : r0_66 -# 814| r0_68(glval) = VariableAddress[pb] : -# 814| mu0_69(Base *) = Store : &:r0_68, r0_67 -# 816| r0_70(glval) = VariableAddress[m] : -# 816| r0_71(glval) = FunctionAddress[operator=] : -# 816| r0_72(glval) = VariableAddress[b] : -# 816| r0_73(glval) = ConvertToDerived[Middle : Base] : r0_72 -# 816| r0_74(glval) = Convert : r0_73 -# 816| r0_75(Middle &) = Call : func:r0_71, this:r0_70, 0:r0_74 -# 816| mu0_76(unknown) = ^CallSideEffect : ~mu0_2 -# 817| r0_77(glval) = VariableAddress[m] : -# 817| r0_78(glval) = FunctionAddress[operator=] : -# 817| r0_79(glval) = VariableAddress[b] : -# 817| r0_80(glval) = ConvertToDerived[Middle : Base] : r0_79 -# 817| r0_81(glval) = Convert : r0_80 -# 817| r0_82(Middle &) = Call : func:r0_78, this:r0_77, 0:r0_81 -# 817| mu0_83(unknown) = ^CallSideEffect : ~mu0_2 -# 818| r0_84(glval) = VariableAddress[pb] : -# 818| r0_85(Base *) = Load : &:r0_84, ~mu0_2 -# 818| r0_86(Middle *) = ConvertToDerived[Middle : Base] : r0_85 -# 818| r0_87(glval) = VariableAddress[pm] : -# 818| mu0_88(Middle *) = Store : &:r0_87, r0_86 -# 819| r0_89(glval) = VariableAddress[pb] : -# 819| r0_90(Base *) = Load : &:r0_89, ~mu0_2 -# 819| r0_91(Middle *) = ConvertToDerived[Middle : Base] : r0_90 -# 819| r0_92(glval) = VariableAddress[pm] : -# 819| mu0_93(Middle *) = Store : &:r0_92, r0_91 -# 820| r0_94(glval) = VariableAddress[pb] : -# 820| r0_95(Base *) = Load : &:r0_94, ~mu0_2 -# 820| r0_96(Middle *) = Convert : r0_95 -# 820| r0_97(glval) = VariableAddress[pm] : -# 820| mu0_98(Middle *) = Store : &:r0_97, r0_96 -# 822| r0_99(glval) = VariableAddress[b] : -# 822| r0_100(glval) = FunctionAddress[operator=] : -# 822| r0_101(glval) = VariableAddress[d] : -# 822| r0_102(glval) = ConvertToBase[Derived : Middle] : r0_101 -# 822| r0_103(glval) = ConvertToBase[Middle : Base] : r0_102 -# 822| r0_104(Base &) = Call : func:r0_100, this:r0_99, 0:r0_103 -# 822| mu0_105(unknown) = ^CallSideEffect : ~mu0_2 -# 823| r0_106(glval) = VariableAddress[b] : -# 823| r0_107(glval) = FunctionAddress[operator=] : -# 823| r0_108(glval) = FunctionAddress[Base] : -# 823| r0_109(glval) = VariableAddress[d] : -# 823| r0_110(glval) = ConvertToBase[Derived : Middle] : r0_109 -# 823| r0_111(glval) = ConvertToBase[Middle : Base] : r0_110 -# 823| v0_112(void) = Call : func:r0_108, 0:r0_111 -# 823| mu0_113(unknown) = ^CallSideEffect : ~mu0_2 -# 823| r0_114(glval) = Convert : v0_112 -# 823| r0_115(Base &) = Call : func:r0_107, this:r0_106, 0:r0_114 -# 823| mu0_116(unknown) = ^CallSideEffect : ~mu0_2 -# 824| r0_117(glval) = VariableAddress[b] : -# 824| r0_118(glval) = FunctionAddress[operator=] : -# 824| r0_119(glval) = FunctionAddress[Base] : -# 824| r0_120(glval) = VariableAddress[d] : -# 824| r0_121(glval) = ConvertToBase[Derived : Middle] : r0_120 -# 824| r0_122(glval) = ConvertToBase[Middle : Base] : r0_121 -# 824| v0_123(void) = Call : func:r0_119, 0:r0_122 -# 824| mu0_124(unknown) = ^CallSideEffect : ~mu0_2 -# 824| r0_125(glval) = Convert : v0_123 -# 824| r0_126(Base &) = Call : func:r0_118, this:r0_117, 0:r0_125 -# 824| mu0_127(unknown) = ^CallSideEffect : ~mu0_2 -# 825| r0_128(glval) = VariableAddress[pd] : -# 825| r0_129(Derived *) = Load : &:r0_128, ~mu0_2 -# 825| r0_130(Middle *) = ConvertToBase[Derived : Middle] : r0_129 -# 825| r0_131(Base *) = ConvertToBase[Middle : Base] : r0_130 -# 825| r0_132(glval) = VariableAddress[pb] : -# 825| mu0_133(Base *) = Store : &:r0_132, r0_131 -# 826| r0_134(glval) = VariableAddress[pd] : -# 826| r0_135(Derived *) = Load : &:r0_134, ~mu0_2 -# 826| r0_136(Middle *) = ConvertToBase[Derived : Middle] : r0_135 -# 826| r0_137(Base *) = ConvertToBase[Middle : Base] : r0_136 -# 826| r0_138(glval) = VariableAddress[pb] : -# 826| mu0_139(Base *) = Store : &:r0_138, r0_137 -# 827| r0_140(glval) = VariableAddress[pd] : -# 827| r0_141(Derived *) = Load : &:r0_140, ~mu0_2 -# 827| r0_142(Middle *) = ConvertToBase[Derived : Middle] : r0_141 -# 827| r0_143(Base *) = ConvertToBase[Middle : Base] : r0_142 -# 827| r0_144(glval) = VariableAddress[pb] : -# 827| mu0_145(Base *) = Store : &:r0_144, r0_143 -# 828| r0_146(glval) = VariableAddress[pd] : -# 828| r0_147(Derived *) = Load : &:r0_146, ~mu0_2 -# 828| r0_148(Base *) = Convert : r0_147 -# 828| r0_149(glval) = VariableAddress[pb] : -# 828| mu0_150(Base *) = Store : &:r0_149, r0_148 -# 830| r0_151(glval) = VariableAddress[d] : -# 830| r0_152(glval) = FunctionAddress[operator=] : -# 830| r0_153(glval) = VariableAddress[b] : -# 830| r0_154(glval) = ConvertToDerived[Middle : Base] : r0_153 -# 830| r0_155(glval) = ConvertToDerived[Derived : Middle] : r0_154 -# 830| r0_156(glval) = Convert : r0_155 -# 830| r0_157(Derived &) = Call : func:r0_152, this:r0_151, 0:r0_156 -# 830| mu0_158(unknown) = ^CallSideEffect : ~mu0_2 -# 831| r0_159(glval) = VariableAddress[d] : -# 831| r0_160(glval) = FunctionAddress[operator=] : -# 831| r0_161(glval) = VariableAddress[b] : -# 831| r0_162(glval) = ConvertToDerived[Middle : Base] : r0_161 -# 831| r0_163(glval) = ConvertToDerived[Derived : Middle] : r0_162 -# 831| r0_164(glval) = Convert : r0_163 -# 831| r0_165(Derived &) = Call : func:r0_160, this:r0_159, 0:r0_164 -# 831| mu0_166(unknown) = ^CallSideEffect : ~mu0_2 -# 832| r0_167(glval) = VariableAddress[pb] : -# 832| r0_168(Base *) = Load : &:r0_167, ~mu0_2 -# 832| r0_169(Middle *) = ConvertToDerived[Middle : Base] : r0_168 -# 832| r0_170(Derived *) = ConvertToDerived[Derived : Middle] : r0_169 -# 832| r0_171(glval) = VariableAddress[pd] : -# 832| mu0_172(Derived *) = Store : &:r0_171, r0_170 -# 833| r0_173(glval) = VariableAddress[pb] : -# 833| r0_174(Base *) = Load : &:r0_173, ~mu0_2 -# 833| r0_175(Middle *) = ConvertToDerived[Middle : Base] : r0_174 -# 833| r0_176(Derived *) = ConvertToDerived[Derived : Middle] : r0_175 -# 833| r0_177(glval) = VariableAddress[pd] : -# 833| mu0_178(Derived *) = Store : &:r0_177, r0_176 -# 834| r0_179(glval) = VariableAddress[pb] : -# 834| r0_180(Base *) = Load : &:r0_179, ~mu0_2 -# 834| r0_181(Derived *) = Convert : r0_180 -# 834| r0_182(glval) = VariableAddress[pd] : -# 834| mu0_183(Derived *) = Store : &:r0_182, r0_181 -# 836| r0_184(glval) = VariableAddress[pmv] : -# 836| r0_185(MiddleVB1 *) = Constant[0] : -# 836| mu0_186(MiddleVB1 *) = Store : &:r0_184, r0_185 -# 837| r0_187(glval) = VariableAddress[pdv] : -# 837| r0_188(DerivedVB *) = Constant[0] : -# 837| mu0_189(DerivedVB *) = Store : &:r0_187, r0_188 -# 838| r0_190(glval) = VariableAddress[pmv] : -# 838| r0_191(MiddleVB1 *) = Load : &:r0_190, ~mu0_2 -# 838| r0_192(Base *) = ConvertToVirtualBase[MiddleVB1 : Base] : r0_191 -# 838| r0_193(glval) = VariableAddress[pb] : -# 838| mu0_194(Base *) = Store : &:r0_193, r0_192 -# 839| r0_195(glval) = VariableAddress[pdv] : -# 839| r0_196(DerivedVB *) = Load : &:r0_195, ~mu0_2 -# 839| r0_197(Base *) = ConvertToVirtualBase[DerivedVB : Base] : r0_196 -# 839| r0_198(glval) = VariableAddress[pb] : -# 839| mu0_199(Base *) = Store : &:r0_198, r0_197 -# 840| v0_200(void) = NoOp : -# 799| v0_201(void) = ReturnVoid : -# 799| v0_202(void) = UnmodeledUse : mu* -# 799| v0_203(void) = ExitFunction : +# 804| r0_17(Base *) = CopyValue : r0_16 +# 804| mu0_18(Base *) = Store : &:r0_15, r0_17 +# 805| r0_19(glval) = VariableAddress[pm] : +# 805| r0_20(glval) = VariableAddress[m] : +# 805| r0_21(Middle *) = CopyValue : r0_20 +# 805| mu0_22(Middle *) = Store : &:r0_19, r0_21 +# 806| r0_23(glval) = VariableAddress[pd] : +# 806| r0_24(glval) = VariableAddress[d] : +# 806| r0_25(Derived *) = CopyValue : r0_24 +# 806| mu0_26(Derived *) = Store : &:r0_23, r0_25 +# 808| r0_27(glval) = VariableAddress[b] : +# 808| r0_28(glval) = FunctionAddress[operator=] : +# 808| r0_29(glval) = VariableAddress[m] : +# 808| r0_30(glval) = ConvertToBase[Middle : Base] : r0_29 +# 808| r0_31(Base &) = CopyValue : r0_30 +# 808| r0_32(Base &) = Call : func:r0_28, this:r0_27, 0:r0_31 +# 808| mu0_33(unknown) = ^CallSideEffect : ~mu0_2 +# 808| r0_34(glval) = CopyValue : r0_32 +# 809| r0_35(glval) = VariableAddress[b] : +# 809| r0_36(glval) = FunctionAddress[operator=] : +# 809| r0_37(glval) = FunctionAddress[Base] : +# 809| r0_38(glval) = VariableAddress[m] : +# 809| r0_39(glval) = ConvertToBase[Middle : Base] : r0_38 +# 809| r0_40(Base &) = CopyValue : r0_39 +# 809| v0_41(void) = Call : func:r0_37, 0:r0_40 +# 809| mu0_42(unknown) = ^CallSideEffect : ~mu0_2 +# 809| r0_43(glval) = Convert : v0_41 +# 809| r0_44(Base &) = CopyValue : r0_43 +# 809| r0_45(Base &) = Call : func:r0_36, this:r0_35, 0:r0_44 +# 809| mu0_46(unknown) = ^CallSideEffect : ~mu0_2 +# 809| r0_47(glval) = CopyValue : r0_45 +# 810| r0_48(glval) = VariableAddress[b] : +# 810| r0_49(glval) = FunctionAddress[operator=] : +# 810| r0_50(glval) = FunctionAddress[Base] : +# 810| r0_51(glval) = VariableAddress[m] : +# 810| r0_52(glval) = ConvertToBase[Middle : Base] : r0_51 +# 810| r0_53(Base &) = CopyValue : r0_52 +# 810| v0_54(void) = Call : func:r0_50, 0:r0_53 +# 810| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 +# 810| r0_56(glval) = Convert : v0_54 +# 810| r0_57(Base &) = CopyValue : r0_56 +# 810| r0_58(Base &) = Call : func:r0_49, this:r0_48, 0:r0_57 +# 810| mu0_59(unknown) = ^CallSideEffect : ~mu0_2 +# 810| r0_60(glval) = CopyValue : r0_58 +# 811| r0_61(glval) = VariableAddress[pm] : +# 811| r0_62(Middle *) = Load : &:r0_61, ~mu0_2 +# 811| r0_63(Base *) = ConvertToBase[Middle : Base] : r0_62 +# 811| r0_64(glval) = VariableAddress[pb] : +# 811| mu0_65(Base *) = Store : &:r0_64, r0_63 +# 811| r0_66(glval) = CopyValue : r0_64 +# 812| r0_67(glval) = VariableAddress[pm] : +# 812| r0_68(Middle *) = Load : &:r0_67, ~mu0_2 +# 812| r0_69(Base *) = ConvertToBase[Middle : Base] : r0_68 +# 812| r0_70(glval) = VariableAddress[pb] : +# 812| mu0_71(Base *) = Store : &:r0_70, r0_69 +# 812| r0_72(glval) = CopyValue : r0_70 +# 813| r0_73(glval) = VariableAddress[pm] : +# 813| r0_74(Middle *) = Load : &:r0_73, ~mu0_2 +# 813| r0_75(Base *) = ConvertToBase[Middle : Base] : r0_74 +# 813| r0_76(glval) = VariableAddress[pb] : +# 813| mu0_77(Base *) = Store : &:r0_76, r0_75 +# 813| r0_78(glval) = CopyValue : r0_76 +# 814| r0_79(glval) = VariableAddress[pm] : +# 814| r0_80(Middle *) = Load : &:r0_79, ~mu0_2 +# 814| r0_81(Base *) = Convert : r0_80 +# 814| r0_82(glval) = VariableAddress[pb] : +# 814| mu0_83(Base *) = Store : &:r0_82, r0_81 +# 814| r0_84(glval) = CopyValue : r0_82 +# 816| r0_85(glval) = VariableAddress[m] : +# 816| r0_86(glval) = FunctionAddress[operator=] : +# 816| r0_87(glval) = VariableAddress[b] : +# 816| r0_88(glval) = ConvertToDerived[Middle : Base] : r0_87 +# 816| r0_89(glval) = Convert : r0_88 +# 816| r0_90(Middle &) = CopyValue : r0_89 +# 816| r0_91(Middle &) = Call : func:r0_86, this:r0_85, 0:r0_90 +# 816| mu0_92(unknown) = ^CallSideEffect : ~mu0_2 +# 816| r0_93(glval) = CopyValue : r0_91 +# 817| r0_94(glval) = VariableAddress[m] : +# 817| r0_95(glval) = FunctionAddress[operator=] : +# 817| r0_96(glval) = VariableAddress[b] : +# 817| r0_97(glval) = ConvertToDerived[Middle : Base] : r0_96 +# 817| r0_98(glval) = Convert : r0_97 +# 817| r0_99(Middle &) = CopyValue : r0_98 +# 817| r0_100(Middle &) = Call : func:r0_95, this:r0_94, 0:r0_99 +# 817| mu0_101(unknown) = ^CallSideEffect : ~mu0_2 +# 817| r0_102(glval) = CopyValue : r0_100 +# 818| r0_103(glval) = VariableAddress[pb] : +# 818| r0_104(Base *) = Load : &:r0_103, ~mu0_2 +# 818| r0_105(Middle *) = ConvertToDerived[Middle : Base] : r0_104 +# 818| r0_106(glval) = VariableAddress[pm] : +# 818| mu0_107(Middle *) = Store : &:r0_106, r0_105 +# 818| r0_108(glval) = CopyValue : r0_106 +# 819| r0_109(glval) = VariableAddress[pb] : +# 819| r0_110(Base *) = Load : &:r0_109, ~mu0_2 +# 819| r0_111(Middle *) = ConvertToDerived[Middle : Base] : r0_110 +# 819| r0_112(glval) = VariableAddress[pm] : +# 819| mu0_113(Middle *) = Store : &:r0_112, r0_111 +# 819| r0_114(glval) = CopyValue : r0_112 +# 820| r0_115(glval) = VariableAddress[pb] : +# 820| r0_116(Base *) = Load : &:r0_115, ~mu0_2 +# 820| r0_117(Middle *) = Convert : r0_116 +# 820| r0_118(glval) = VariableAddress[pm] : +# 820| mu0_119(Middle *) = Store : &:r0_118, r0_117 +# 820| r0_120(glval) = CopyValue : r0_118 +# 822| r0_121(glval) = VariableAddress[b] : +# 822| r0_122(glval) = FunctionAddress[operator=] : +# 822| r0_123(glval) = VariableAddress[d] : +# 822| r0_124(glval) = ConvertToBase[Derived : Middle] : r0_123 +# 822| r0_125(glval) = ConvertToBase[Middle : Base] : r0_124 +# 822| r0_126(Base &) = CopyValue : r0_125 +# 822| r0_127(Base &) = Call : func:r0_122, this:r0_121, 0:r0_126 +# 822| mu0_128(unknown) = ^CallSideEffect : ~mu0_2 +# 822| r0_129(glval) = CopyValue : r0_127 +# 823| r0_130(glval) = VariableAddress[b] : +# 823| r0_131(glval) = FunctionAddress[operator=] : +# 823| r0_132(glval) = FunctionAddress[Base] : +# 823| r0_133(glval) = VariableAddress[d] : +# 823| r0_134(glval) = ConvertToBase[Derived : Middle] : r0_133 +# 823| r0_135(glval) = ConvertToBase[Middle : Base] : r0_134 +# 823| r0_136(Base &) = CopyValue : r0_135 +# 823| v0_137(void) = Call : func:r0_132, 0:r0_136 +# 823| mu0_138(unknown) = ^CallSideEffect : ~mu0_2 +# 823| r0_139(glval) = Convert : v0_137 +# 823| r0_140(Base &) = CopyValue : r0_139 +# 823| r0_141(Base &) = Call : func:r0_131, this:r0_130, 0:r0_140 +# 823| mu0_142(unknown) = ^CallSideEffect : ~mu0_2 +# 823| r0_143(glval) = CopyValue : r0_141 +# 824| r0_144(glval) = VariableAddress[b] : +# 824| r0_145(glval) = FunctionAddress[operator=] : +# 824| r0_146(glval) = FunctionAddress[Base] : +# 824| r0_147(glval) = VariableAddress[d] : +# 824| r0_148(glval) = ConvertToBase[Derived : Middle] : r0_147 +# 824| r0_149(glval) = ConvertToBase[Middle : Base] : r0_148 +# 824| r0_150(Base &) = CopyValue : r0_149 +# 824| v0_151(void) = Call : func:r0_146, 0:r0_150 +# 824| mu0_152(unknown) = ^CallSideEffect : ~mu0_2 +# 824| r0_153(glval) = Convert : v0_151 +# 824| r0_154(Base &) = CopyValue : r0_153 +# 824| r0_155(Base &) = Call : func:r0_145, this:r0_144, 0:r0_154 +# 824| mu0_156(unknown) = ^CallSideEffect : ~mu0_2 +# 824| r0_157(glval) = CopyValue : r0_155 +# 825| r0_158(glval) = VariableAddress[pd] : +# 825| r0_159(Derived *) = Load : &:r0_158, ~mu0_2 +# 825| r0_160(Middle *) = ConvertToBase[Derived : Middle] : r0_159 +# 825| r0_161(Base *) = ConvertToBase[Middle : Base] : r0_160 +# 825| r0_162(glval) = VariableAddress[pb] : +# 825| mu0_163(Base *) = Store : &:r0_162, r0_161 +# 825| r0_164(glval) = CopyValue : r0_162 +# 826| r0_165(glval) = VariableAddress[pd] : +# 826| r0_166(Derived *) = Load : &:r0_165, ~mu0_2 +# 826| r0_167(Middle *) = ConvertToBase[Derived : Middle] : r0_166 +# 826| r0_168(Base *) = ConvertToBase[Middle : Base] : r0_167 +# 826| r0_169(glval) = VariableAddress[pb] : +# 826| mu0_170(Base *) = Store : &:r0_169, r0_168 +# 826| r0_171(glval) = CopyValue : r0_169 +# 827| r0_172(glval) = VariableAddress[pd] : +# 827| r0_173(Derived *) = Load : &:r0_172, ~mu0_2 +# 827| r0_174(Middle *) = ConvertToBase[Derived : Middle] : r0_173 +# 827| r0_175(Base *) = ConvertToBase[Middle : Base] : r0_174 +# 827| r0_176(glval) = VariableAddress[pb] : +# 827| mu0_177(Base *) = Store : &:r0_176, r0_175 +# 827| r0_178(glval) = CopyValue : r0_176 +# 828| r0_179(glval) = VariableAddress[pd] : +# 828| r0_180(Derived *) = Load : &:r0_179, ~mu0_2 +# 828| r0_181(Base *) = Convert : r0_180 +# 828| r0_182(glval) = VariableAddress[pb] : +# 828| mu0_183(Base *) = Store : &:r0_182, r0_181 +# 828| r0_184(glval) = CopyValue : r0_182 +# 830| r0_185(glval) = VariableAddress[d] : +# 830| r0_186(glval) = FunctionAddress[operator=] : +# 830| r0_187(glval) = VariableAddress[b] : +# 830| r0_188(glval) = ConvertToDerived[Middle : Base] : r0_187 +# 830| r0_189(glval) = ConvertToDerived[Derived : Middle] : r0_188 +# 830| r0_190(glval) = Convert : r0_189 +# 830| r0_191(Derived &) = CopyValue : r0_190 +# 830| r0_192(Derived &) = Call : func:r0_186, this:r0_185, 0:r0_191 +# 830| mu0_193(unknown) = ^CallSideEffect : ~mu0_2 +# 830| r0_194(glval) = CopyValue : r0_192 +# 831| r0_195(glval) = VariableAddress[d] : +# 831| r0_196(glval) = FunctionAddress[operator=] : +# 831| r0_197(glval) = VariableAddress[b] : +# 831| r0_198(glval) = ConvertToDerived[Middle : Base] : r0_197 +# 831| r0_199(glval) = ConvertToDerived[Derived : Middle] : r0_198 +# 831| r0_200(glval) = Convert : r0_199 +# 831| r0_201(Derived &) = CopyValue : r0_200 +# 831| r0_202(Derived &) = Call : func:r0_196, this:r0_195, 0:r0_201 +# 831| mu0_203(unknown) = ^CallSideEffect : ~mu0_2 +# 831| r0_204(glval) = CopyValue : r0_202 +# 832| r0_205(glval) = VariableAddress[pb] : +# 832| r0_206(Base *) = Load : &:r0_205, ~mu0_2 +# 832| r0_207(Middle *) = ConvertToDerived[Middle : Base] : r0_206 +# 832| r0_208(Derived *) = ConvertToDerived[Derived : Middle] : r0_207 +# 832| r0_209(glval) = VariableAddress[pd] : +# 832| mu0_210(Derived *) = Store : &:r0_209, r0_208 +# 832| r0_211(glval) = CopyValue : r0_209 +# 833| r0_212(glval) = VariableAddress[pb] : +# 833| r0_213(Base *) = Load : &:r0_212, ~mu0_2 +# 833| r0_214(Middle *) = ConvertToDerived[Middle : Base] : r0_213 +# 833| r0_215(Derived *) = ConvertToDerived[Derived : Middle] : r0_214 +# 833| r0_216(glval) = VariableAddress[pd] : +# 833| mu0_217(Derived *) = Store : &:r0_216, r0_215 +# 833| r0_218(glval) = CopyValue : r0_216 +# 834| r0_219(glval) = VariableAddress[pb] : +# 834| r0_220(Base *) = Load : &:r0_219, ~mu0_2 +# 834| r0_221(Derived *) = Convert : r0_220 +# 834| r0_222(glval) = VariableAddress[pd] : +# 834| mu0_223(Derived *) = Store : &:r0_222, r0_221 +# 834| r0_224(glval) = CopyValue : r0_222 +# 836| r0_225(glval) = VariableAddress[pmv] : +# 836| r0_226(MiddleVB1 *) = Constant[0] : +# 836| mu0_227(MiddleVB1 *) = Store : &:r0_225, r0_226 +# 837| r0_228(glval) = VariableAddress[pdv] : +# 837| r0_229(DerivedVB *) = Constant[0] : +# 837| mu0_230(DerivedVB *) = Store : &:r0_228, r0_229 +# 838| r0_231(glval) = VariableAddress[pmv] : +# 838| r0_232(MiddleVB1 *) = Load : &:r0_231, ~mu0_2 +# 838| r0_233(Base *) = ConvertToVirtualBase[MiddleVB1 : Base] : r0_232 +# 838| r0_234(glval) = VariableAddress[pb] : +# 838| mu0_235(Base *) = Store : &:r0_234, r0_233 +# 838| r0_236(glval) = CopyValue : r0_234 +# 839| r0_237(glval) = VariableAddress[pdv] : +# 839| r0_238(DerivedVB *) = Load : &:r0_237, ~mu0_2 +# 839| r0_239(Base *) = ConvertToVirtualBase[DerivedVB : Base] : r0_238 +# 839| r0_240(glval) = VariableAddress[pb] : +# 839| mu0_241(Base *) = Store : &:r0_240, r0_239 +# 839| r0_242(glval) = CopyValue : r0_240 +# 840| v0_243(void) = NoOp : +# 799| v0_244(void) = ReturnVoid : +# 799| v0_245(void) = UnmodeledUse : mu* +# 799| v0_246(void) = ExitFunction : # 842| void PolymorphicBase::PolymorphicBase() # 842| Block 0 @@ -3826,42 +4070,48 @@ ir.cpp: # 851| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 # 853| r0_11(glval) = VariableAddress[pb] : # 853| r0_12(glval) = VariableAddress[b] : -# 853| mu0_13(PolymorphicBase *) = Store : &:r0_11, r0_12 -# 854| r0_14(glval) = VariableAddress[pd] : -# 854| r0_15(glval) = VariableAddress[d] : -# 854| mu0_16(PolymorphicDerived *) = Store : &:r0_14, r0_15 -# 857| r0_17(glval) = VariableAddress[pd] : -# 857| r0_18(PolymorphicDerived *) = Load : &:r0_17, ~mu0_2 -# 857| r0_19(PolymorphicBase *) = CheckedConvertOrNull : r0_18 -# 857| r0_20(glval) = VariableAddress[pb] : -# 857| mu0_21(PolymorphicBase *) = Store : &:r0_20, r0_19 -# 858| r0_22(glval) = VariableAddress[rb] : -# 858| r0_23(glval) = VariableAddress[d] : -# 858| r0_24(glval) = CheckedConvertOrThrow : r0_23 -# 858| mu0_25(PolymorphicBase &) = Store : &:r0_22, r0_24 -# 860| r0_26(glval) = VariableAddress[pb] : -# 860| r0_27(PolymorphicBase *) = Load : &:r0_26, ~mu0_2 -# 860| r0_28(PolymorphicDerived *) = CheckedConvertOrNull : r0_27 -# 860| r0_29(glval) = VariableAddress[pd] : -# 860| mu0_30(PolymorphicDerived *) = Store : &:r0_29, r0_28 -# 861| r0_31(glval) = VariableAddress[rd] : -# 861| r0_32(glval) = VariableAddress[b] : -# 861| r0_33(glval) = CheckedConvertOrThrow : r0_32 -# 861| mu0_34(PolymorphicDerived &) = Store : &:r0_31, r0_33 -# 863| r0_35(glval) = VariableAddress[pv] : -# 863| r0_36(glval) = VariableAddress[pb] : -# 863| r0_37(PolymorphicBase *) = Load : &:r0_36, ~mu0_2 -# 863| r0_38(void *) = DynamicCastToVoid : r0_37 -# 863| mu0_39(void *) = Store : &:r0_35, r0_38 -# 864| r0_40(glval) = VariableAddress[pcv] : -# 864| r0_41(glval) = VariableAddress[pd] : -# 864| r0_42(PolymorphicDerived *) = Load : &:r0_41, ~mu0_2 -# 864| r0_43(void *) = DynamicCastToVoid : r0_42 -# 864| mu0_44(void *) = Store : &:r0_40, r0_43 -# 865| v0_45(void) = NoOp : -# 849| v0_46(void) = ReturnVoid : -# 849| v0_47(void) = UnmodeledUse : mu* -# 849| v0_48(void) = ExitFunction : +# 853| r0_13(PolymorphicBase *) = CopyValue : r0_12 +# 853| mu0_14(PolymorphicBase *) = Store : &:r0_11, r0_13 +# 854| r0_15(glval) = VariableAddress[pd] : +# 854| r0_16(glval) = VariableAddress[d] : +# 854| r0_17(PolymorphicDerived *) = CopyValue : r0_16 +# 854| mu0_18(PolymorphicDerived *) = Store : &:r0_15, r0_17 +# 857| r0_19(glval) = VariableAddress[pd] : +# 857| r0_20(PolymorphicDerived *) = Load : &:r0_19, ~mu0_2 +# 857| r0_21(PolymorphicBase *) = CheckedConvertOrNull : r0_20 +# 857| r0_22(glval) = VariableAddress[pb] : +# 857| mu0_23(PolymorphicBase *) = Store : &:r0_22, r0_21 +# 857| r0_24(glval) = CopyValue : r0_22 +# 858| r0_25(glval) = VariableAddress[rb] : +# 858| r0_26(glval) = VariableAddress[d] : +# 858| r0_27(glval) = CheckedConvertOrThrow : r0_26 +# 858| r0_28(PolymorphicBase &) = CopyValue : r0_27 +# 858| mu0_29(PolymorphicBase &) = Store : &:r0_25, r0_28 +# 860| r0_30(glval) = VariableAddress[pb] : +# 860| r0_31(PolymorphicBase *) = Load : &:r0_30, ~mu0_2 +# 860| r0_32(PolymorphicDerived *) = CheckedConvertOrNull : r0_31 +# 860| r0_33(glval) = VariableAddress[pd] : +# 860| mu0_34(PolymorphicDerived *) = Store : &:r0_33, r0_32 +# 860| r0_35(glval) = CopyValue : r0_33 +# 861| r0_36(glval) = VariableAddress[rd] : +# 861| r0_37(glval) = VariableAddress[b] : +# 861| r0_38(glval) = CheckedConvertOrThrow : r0_37 +# 861| r0_39(PolymorphicDerived &) = CopyValue : r0_38 +# 861| mu0_40(PolymorphicDerived &) = Store : &:r0_36, r0_39 +# 863| r0_41(glval) = VariableAddress[pv] : +# 863| r0_42(glval) = VariableAddress[pb] : +# 863| r0_43(PolymorphicBase *) = Load : &:r0_42, ~mu0_2 +# 863| r0_44(void *) = DynamicCastToVoid : r0_43 +# 863| mu0_45(void *) = Store : &:r0_41, r0_44 +# 864| r0_46(glval) = VariableAddress[pcv] : +# 864| r0_47(glval) = VariableAddress[pd] : +# 864| r0_48(PolymorphicDerived *) = Load : &:r0_47, ~mu0_2 +# 864| r0_49(void *) = DynamicCastToVoid : r0_48 +# 864| mu0_50(void *) = Store : &:r0_46, r0_49 +# 865| v0_51(void) = NoOp : +# 849| v0_52(void) = ReturnVoid : +# 849| v0_53(void) = UnmodeledUse : mu* +# 849| v0_54(void) = ExitFunction : # 867| void String::String() # 867| Block 0 @@ -3895,36 +4145,46 @@ ir.cpp: # 874| r0_11(char *) = Convert : r0_10 # 874| r0_12(glval) = VariableAddress[p] : # 874| mu0_13(char *) = Store : &:r0_12, r0_11 -# 875| r0_14(glval) = VariableAddress[a] : -# 875| r0_15(char *) = Convert : r0_14 -# 875| r0_16(int) = Constant[0] : -# 875| r0_17(glval) = PointerAdd[1] : r0_15, r0_16 -# 875| r0_18(char *) = Convert : r0_17 -# 875| r0_19(glval) = VariableAddress[p] : -# 875| mu0_20(char *) = Store : &:r0_19, r0_18 -# 876| r0_21(glval) = StringConstant["test"] : -# 876| r0_22(char *) = Convert : r0_21 -# 876| r0_23(int) = Constant[0] : -# 876| r0_24(glval) = PointerAdd[1] : r0_22, r0_23 -# 876| r0_25(glval) = VariableAddress[p] : -# 876| mu0_26(char *) = Store : &:r0_25, r0_24 -# 877| r0_27(glval) = VariableAddress[ra] : -# 877| r0_28(glval) = VariableAddress[a] : -# 877| mu0_29(char(&)[5]) = Store : &:r0_27, r0_28 -# 878| r0_30(glval) = VariableAddress[rs] : -# 878| r0_31(glval) = StringConstant["test"] : -# 878| mu0_32(char(&)[5]) = Store : &:r0_30, r0_31 -# 879| r0_33(glval) = VariableAddress[pa] : -# 879| r0_34(glval) = VariableAddress[a] : -# 879| r0_35(char(*)[5]) = Convert : r0_34 -# 879| mu0_36(char(*)[5]) = Store : &:r0_33, r0_35 -# 880| r0_37(glval) = StringConstant["test"] : -# 880| r0_38(glval) = VariableAddress[pa] : -# 880| mu0_39(char(*)[5]) = Store : &:r0_38, r0_37 -# 881| v0_40(void) = NoOp : -# 871| v0_41(void) = ReturnVoid : -# 871| v0_42(void) = UnmodeledUse : mu* -# 871| v0_43(void) = ExitFunction : +# 874| r0_14(glval) = CopyValue : r0_12 +# 875| r0_15(glval) = VariableAddress[a] : +# 875| r0_16(char *) = Convert : r0_15 +# 875| r0_17(int) = Constant[0] : +# 875| r0_18(glval) = PointerAdd[1] : r0_16, r0_17 +# 875| r0_19(char *) = CopyValue : r0_18 +# 875| r0_20(char *) = Convert : r0_19 +# 875| r0_21(glval) = VariableAddress[p] : +# 875| mu0_22(char *) = Store : &:r0_21, r0_20 +# 875| r0_23(glval) = CopyValue : r0_21 +# 876| r0_24(glval) = StringConstant["test"] : +# 876| r0_25(char *) = Convert : r0_24 +# 876| r0_26(int) = Constant[0] : +# 876| r0_27(glval) = PointerAdd[1] : r0_25, r0_26 +# 876| r0_28(char *) = CopyValue : r0_27 +# 876| r0_29(glval) = VariableAddress[p] : +# 876| mu0_30(char *) = Store : &:r0_29, r0_28 +# 876| r0_31(glval) = CopyValue : r0_29 +# 877| r0_32(glval) = VariableAddress[ra] : +# 877| r0_33(glval) = VariableAddress[a] : +# 877| r0_34(char(&)[5]) = CopyValue : r0_33 +# 877| mu0_35(char(&)[5]) = Store : &:r0_32, r0_34 +# 878| r0_36(glval) = VariableAddress[rs] : +# 878| r0_37(glval) = StringConstant["test"] : +# 878| r0_38(char(&)[5]) = CopyValue : r0_37 +# 878| mu0_39(char(&)[5]) = Store : &:r0_36, r0_38 +# 879| r0_40(glval) = VariableAddress[pa] : +# 879| r0_41(glval) = VariableAddress[a] : +# 879| r0_42(char(*)[5]) = CopyValue : r0_41 +# 879| r0_43(char(*)[5]) = Convert : r0_42 +# 879| mu0_44(char(*)[5]) = Store : &:r0_40, r0_43 +# 880| r0_45(glval) = StringConstant["test"] : +# 880| r0_46(char(*)[5]) = CopyValue : r0_45 +# 880| r0_47(glval) = VariableAddress[pa] : +# 880| mu0_48(char(*)[5]) = Store : &:r0_47, r0_46 +# 880| r0_49(glval) = CopyValue : r0_47 +# 881| v0_50(void) = NoOp : +# 871| v0_51(void) = ReturnVoid : +# 871| v0_52(void) = UnmodeledUse : mu* +# 871| v0_53(void) = ExitFunction : # 883| void FuncPtrConversions(int(*)(int), void*) # 883| Block 0 @@ -3940,15 +4200,17 @@ ir.cpp: # 884| r0_9(void *) = Convert : r0_8 # 884| r0_10(glval) = VariableAddress[p] : # 884| mu0_11(void *) = Store : &:r0_10, r0_9 -# 885| r0_12(glval) = VariableAddress[p] : -# 885| r0_13(void *) = Load : &:r0_12, ~mu0_2 -# 885| r0_14(..(*)(..)) = Convert : r0_13 -# 885| r0_15(glval<..(*)(..)>) = VariableAddress[pfn] : -# 885| mu0_16(..(*)(..)) = Store : &:r0_15, r0_14 -# 886| v0_17(void) = NoOp : -# 883| v0_18(void) = ReturnVoid : -# 883| v0_19(void) = UnmodeledUse : mu* -# 883| v0_20(void) = ExitFunction : +# 884| r0_12(glval) = CopyValue : r0_10 +# 885| r0_13(glval) = VariableAddress[p] : +# 885| r0_14(void *) = Load : &:r0_13, ~mu0_2 +# 885| r0_15(..(*)(..)) = Convert : r0_14 +# 885| r0_16(glval<..(*)(..)>) = VariableAddress[pfn] : +# 885| mu0_17(..(*)(..)) = Store : &:r0_16, r0_15 +# 885| r0_18(glval<..(*)(..)>) = CopyValue : r0_16 +# 886| v0_19(void) = NoOp : +# 883| v0_20(void) = ReturnVoid : +# 883| v0_21(void) = UnmodeledUse : mu* +# 883| v0_22(void) = ExitFunction : # 888| void VarArgUsage(int) # 888| Block 0 @@ -4246,7 +4508,8 @@ ir.cpp: # 967| mu0_13(bool) = Store : &:r0_7, r0_12 # 967| r0_14(glval) = VariableAddress[b] : # 967| r0_15(bool) = Load : &:r0_14, ~mu0_2 -# 967| v0_16(void) = ConditionalBranch : r0_15 +# 967| r0_16(bool) = CopyValue : r0_15 +# 967| v0_17(void) = ConditionalBranch : r0_16 #-----| False -> Block 2 #-----| True -> Block 1 @@ -4254,6 +4517,7 @@ ir.cpp: # 968| r1_0(int) = Constant[5] : # 968| r1_1(glval) = VariableAddress[x] : # 968| mu1_2(int) = Store : &:r1_1, r1_0 +# 968| r1_3(glval) = CopyValue : r1_1 #-----| Goto -> Block 6 # 970| Block 2 @@ -4268,7 +4532,8 @@ ir.cpp: # 970| r2_8(int) = Load : &:r2_7, ~mu0_2 # 970| r2_9(int) = Constant[0] : # 970| r2_10(bool) = CompareNE : r2_8, r2_9 -# 970| v2_11(void) = ConditionalBranch : r2_10 +# 970| r2_11(bool) = CopyValue : r2_10 +# 970| v2_12(void) = ConditionalBranch : r2_11 #-----| False -> Block 4 #-----| True -> Block 3 @@ -4276,17 +4541,20 @@ ir.cpp: # 971| r3_0(int) = Constant[7] : # 971| r3_1(glval) = VariableAddress[y] : # 971| mu3_2(int) = Store : &:r3_1, r3_0 +# 971| r3_3(glval) = CopyValue : r3_1 #-----| Goto -> Block 6 # 973| Block 4 # 973| r4_0(glval) = VariableAddress[p] : # 973| r4_1(glval) = VariableAddress[x] : -# 973| mu4_2(int *) = Store : &:r4_0, r4_1 -# 973| r4_3(glval) = VariableAddress[p] : -# 973| r4_4(int *) = Load : &:r4_3, ~mu0_2 -# 973| r4_5(int *) = Constant[0] : -# 973| r4_6(bool) = CompareNE : r4_4, r4_5 -# 973| v4_7(void) = ConditionalBranch : r4_6 +# 973| r4_2(int *) = CopyValue : r4_1 +# 973| mu4_3(int *) = Store : &:r4_0, r4_2 +# 973| r4_4(glval) = VariableAddress[p] : +# 973| r4_5(int *) = Load : &:r4_4, ~mu0_2 +# 973| r4_6(int *) = Constant[0] : +# 973| r4_7(bool) = CompareNE : r4_5, r4_6 +# 973| r4_8(bool) = CopyValue : r4_7 +# 973| v4_9(void) = ConditionalBranch : r4_8 #-----| False -> Block 6 #-----| True -> Block 5 @@ -4294,7 +4562,9 @@ ir.cpp: # 974| r5_0(int) = Constant[2] : # 974| r5_1(glval) = VariableAddress[p] : # 974| r5_2(int *) = Load : &:r5_1, ~mu0_2 -# 974| mu5_3(int) = Store : &:r5_2, r5_0 +# 974| r5_3(glval) = CopyValue : r5_2 +# 974| mu5_4(int) = Store : &:r5_3, r5_0 +# 974| r5_5(glval) = CopyValue : r5_3 #-----| Goto -> Block 6 # 976| Block 6 @@ -4330,7 +4600,8 @@ ir.cpp: # 981| r2_8(int) = Load : &:r2_7, ~mu0_2 # 981| r2_9(int) = Constant[0] : # 981| r2_10(bool) = CompareNE : r2_8, r2_9 -# 981| v2_11(void) = ConditionalBranch : r2_10 +# 981| r2_11(bool) = CopyValue : r2_10 +# 981| v2_12(void) = ConditionalBranch : r2_11 #-----| False -> Block 4 #-----| True -> Block 3 @@ -4341,12 +4612,14 @@ ir.cpp: # 983| Block 4 # 983| r4_0(glval) = VariableAddress[p] : # 983| r4_1(glval) = VariableAddress[x] : -# 983| mu4_2(int *) = Store : &:r4_0, r4_1 -# 983| r4_3(glval) = VariableAddress[p] : -# 983| r4_4(int *) = Load : &:r4_3, ~mu0_2 -# 983| r4_5(int *) = Constant[0] : -# 983| r4_6(bool) = CompareNE : r4_4, r4_5 -# 983| v4_7(void) = ConditionalBranch : r4_6 +# 983| r4_2(int *) = CopyValue : r4_1 +# 983| mu4_3(int *) = Store : &:r4_0, r4_2 +# 983| r4_4(glval) = VariableAddress[p] : +# 983| r4_5(int *) = Load : &:r4_4, ~mu0_2 +# 983| r4_6(int *) = Constant[0] : +# 983| r4_7(bool) = CompareNE : r4_5, r4_6 +# 983| r4_8(bool) = CopyValue : r4_7 +# 983| v4_9(void) = ConditionalBranch : r4_8 #-----| False -> Block 6 #-----| True -> Block 5 @@ -4370,7 +4643,8 @@ ir.cpp: # 979| mu7_6(bool) = Store : &:r7_0, r7_5 # 979| r7_7(glval) = VariableAddress[b] : # 979| r7_8(bool) = Load : &:r7_7, ~mu0_2 -# 979| v7_9(void) = ConditionalBranch : r7_8 +# 979| r7_9(bool) = CopyValue : r7_8 +# 979| v7_10(void) = ConditionalBranch : r7_9 #-----| False -> Block 2 #-----| True -> Block 1 @@ -4428,6 +4702,7 @@ ir.cpp: # 995| r1_1(int) = Load : &:r1_0, ~mu0_2 # 995| r1_2(glval) = VariableAddress[w] : # 995| mu1_3(int) = Store : &:r1_2, r1_1 +# 995| r1_4(glval) = CopyValue : r1_2 #-----| Goto -> Block 3 # 997| Block 2 @@ -4435,6 +4710,7 @@ ir.cpp: # 997| r2_1(int) = Load : &:r2_0, ~mu0_2 # 997| r2_2(glval) = VariableAddress[w] : # 997| mu2_3(int) = Store : &:r2_2, r2_1 +# 997| r2_4(glval) = CopyValue : r2_2 #-----| Goto -> Block 3 # 999| Block 3 @@ -4544,147 +4820,159 @@ ir.cpp: # 1031| void Lambda(int, String const&) # 1031| Block 0 -# 1031| v0_0(void) = EnterFunction : -# 1031| mu0_1(unknown) = AliasedDefinition : -# 1031| mu0_2(unknown) = UnmodeledDefinition : -# 1031| r0_3(glval) = VariableAddress[x] : -# 1031| mu0_4(int) = InitializeParameter[x] : &:r0_3 -# 1031| r0_5(glval) = VariableAddress[s] : -# 1031| mu0_6(String &) = InitializeParameter[s] : &:r0_5 -# 1032| r0_7(glval) = VariableAddress[lambda_empty] : -# 1032| r0_8(glval) = VariableAddress[#temp1032:23] : -# 1032| mu0_9(decltype([...](...){...})) = Uninitialized[#temp1032:23] : &:r0_8 -# 1032| r0_10(decltype([...](...){...})) = Load : &:r0_8, ~mu0_2 -# 1032| mu0_11(decltype([...](...){...})) = Store : &:r0_7, r0_10 -# 1033| r0_12(char) = Constant[65] : -# 1034| r0_13(glval) = VariableAddress[lambda_ref] : -# 1034| r0_14(glval) = VariableAddress[#temp1034:21] : -# 1034| mu0_15(decltype([...](...){...})) = Uninitialized[#temp1034:21] : &:r0_14 -# 1034| r0_16(glval) = FieldAddress[s] : r0_14 -#-----| r0_17(glval) = VariableAddress[s] : -#-----| r0_18(String &) = Load : &:r0_17, ~mu0_2 -# 1034| mu0_19(String &) = Store : &:r0_16, r0_18 -# 1034| r0_20(glval) = FieldAddress[x] : r0_14 -#-----| r0_21(glval) = VariableAddress[x] : -#-----| mu0_22(int &) = Store : &:r0_20, r0_21 -# 1034| r0_23(decltype([...](...){...})) = Load : &:r0_14, ~mu0_2 -# 1034| mu0_24(decltype([...](...){...})) = Store : &:r0_13, r0_23 -# 1035| r0_25(glval) = VariableAddress[lambda_ref] : -# 1035| r0_26(glval) = Convert : r0_25 -# 1035| r0_27(glval) = FunctionAddress[operator()] : -# 1035| r0_28(float) = Constant[1.0] : -# 1035| r0_29(char) = Call : func:r0_27, this:r0_26, 0:r0_28 -# 1035| mu0_30(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| r0_31(glval) = VariableAddress[lambda_val] : -# 1036| r0_32(glval) = FunctionAddress[(constructor)] : -# 1036| r0_33(glval) = VariableAddress[#temp1036:21] : -# 1036| mu0_34(decltype([...](...){...})) = Uninitialized[#temp1036:21] : &:r0_33 -# 1036| r0_35(glval) = FieldAddress[s] : r0_33 -#-----| r0_36(glval) = FunctionAddress[String] : -#-----| v0_37(void) = Call : func:r0_36, this:r0_35 -#-----| mu0_38(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| r0_39(glval) = FieldAddress[x] : r0_33 -#-----| r0_40(glval) = VariableAddress[x] : -#-----| r0_41(int) = Load : &:r0_40, ~mu0_2 -#-----| mu0_42(int) = Store : &:r0_39, r0_41 -# 1036| r0_43(decltype([...](...){...})) = Load : &:r0_33, ~mu0_2 -# 1036| v0_44(void) = Call : func:r0_32, this:r0_31, 0:r0_43 -# 1036| mu0_45(unknown) = ^CallSideEffect : ~mu0_2 -# 1037| r0_46(glval) = VariableAddress[lambda_val] : -# 1037| r0_47(glval) = Convert : r0_46 -# 1037| r0_48(glval) = FunctionAddress[operator()] : -# 1037| r0_49(float) = Constant[2.0] : -# 1037| r0_50(char) = Call : func:r0_48, this:r0_47, 0:r0_49 -# 1037| mu0_51(unknown) = ^CallSideEffect : ~mu0_2 -# 1038| r0_52(glval) = VariableAddress[lambda_ref_explicit] : -# 1038| r0_53(glval) = VariableAddress[#temp1038:30] : -# 1038| mu0_54(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_53 -# 1038| r0_55(glval) = FieldAddress[s] : r0_53 -# 1038| r0_56(glval) = VariableAddress[s] : -# 1038| r0_57(String &) = Load : &:r0_56, ~mu0_2 -# 1038| mu0_58(String &) = Store : &:r0_55, r0_57 -# 1038| r0_59(decltype([...](...){...})) = Load : &:r0_53, ~mu0_2 -# 1038| mu0_60(decltype([...](...){...})) = Store : &:r0_52, r0_59 -# 1039| r0_61(glval) = VariableAddress[lambda_ref_explicit] : -# 1039| r0_62(glval) = Convert : r0_61 -# 1039| r0_63(glval) = FunctionAddress[operator()] : -# 1039| r0_64(float) = Constant[3.0] : -# 1039| r0_65(char) = Call : func:r0_63, this:r0_62, 0:r0_64 -# 1039| mu0_66(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| r0_67(glval) = VariableAddress[lambda_val_explicit] : -# 1040| r0_68(glval) = FunctionAddress[(constructor)] : -# 1040| r0_69(glval) = VariableAddress[#temp1040:30] : -# 1040| mu0_70(decltype([...](...){...})) = Uninitialized[#temp1040:30] : &:r0_69 -# 1040| r0_71(glval) = FieldAddress[s] : r0_69 -#-----| r0_72(glval) = FunctionAddress[String] : -#-----| v0_73(void) = Call : func:r0_72, this:r0_71 -#-----| mu0_74(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| r0_75(decltype([...](...){...})) = Load : &:r0_69, ~mu0_2 -# 1040| v0_76(void) = Call : func:r0_68, this:r0_67, 0:r0_75 -# 1040| mu0_77(unknown) = ^CallSideEffect : ~mu0_2 -# 1041| r0_78(glval) = VariableAddress[lambda_val_explicit] : -# 1041| r0_79(glval) = Convert : r0_78 -# 1041| r0_80(glval) = FunctionAddress[operator()] : -# 1041| r0_81(float) = Constant[4.0] : -# 1041| r0_82(char) = Call : func:r0_80, this:r0_79, 0:r0_81 -# 1041| mu0_83(unknown) = ^CallSideEffect : ~mu0_2 -# 1042| r0_84(glval) = VariableAddress[lambda_mixed_explicit] : -# 1042| r0_85(glval) = VariableAddress[#temp1042:32] : -# 1042| mu0_86(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_85 -# 1042| r0_87(glval) = FieldAddress[s] : r0_85 -# 1042| r0_88(glval) = VariableAddress[s] : -# 1042| r0_89(String &) = Load : &:r0_88, ~mu0_2 -# 1042| mu0_90(String &) = Store : &:r0_87, r0_89 -# 1042| r0_91(glval) = FieldAddress[x] : r0_85 -# 1042| r0_92(glval) = VariableAddress[x] : -# 1042| r0_93(int) = Load : &:r0_92, ~mu0_2 -# 1042| mu0_94(int) = Store : &:r0_91, r0_93 -# 1042| r0_95(decltype([...](...){...})) = Load : &:r0_85, ~mu0_2 -# 1042| mu0_96(decltype([...](...){...})) = Store : &:r0_84, r0_95 -# 1043| r0_97(glval) = VariableAddress[lambda_mixed_explicit] : -# 1043| r0_98(glval) = Convert : r0_97 -# 1043| r0_99(glval) = FunctionAddress[operator()] : -# 1043| r0_100(float) = Constant[5.0] : -# 1043| r0_101(char) = Call : func:r0_99, this:r0_98, 0:r0_100 -# 1043| mu0_102(unknown) = ^CallSideEffect : ~mu0_2 -# 1044| r0_103(glval) = VariableAddress[r] : -# 1044| r0_104(glval) = VariableAddress[x] : -# 1044| r0_105(int) = Load : &:r0_104, ~mu0_2 -# 1044| r0_106(int) = Constant[1] : -# 1044| r0_107(int) = Sub : r0_105, r0_106 -# 1044| mu0_108(int) = Store : &:r0_103, r0_107 -# 1045| r0_109(glval) = VariableAddress[lambda_inits] : -# 1045| r0_110(glval) = VariableAddress[#temp1045:23] : -# 1045| mu0_111(decltype([...](...){...})) = Uninitialized[#temp1045:23] : &:r0_110 -# 1045| r0_112(glval) = FieldAddress[s] : r0_110 -# 1045| r0_113(glval) = VariableAddress[s] : -# 1045| r0_114(String &) = Load : &:r0_113, ~mu0_2 -# 1045| mu0_115(String &) = Store : &:r0_112, r0_114 -# 1045| r0_116(glval) = FieldAddress[x] : r0_110 -# 1045| r0_117(glval) = VariableAddress[x] : -# 1045| r0_118(int) = Load : &:r0_117, ~mu0_2 -# 1045| mu0_119(int) = Store : &:r0_116, r0_118 -# 1045| r0_120(glval) = FieldAddress[i] : r0_110 -# 1045| r0_121(glval) = VariableAddress[x] : -# 1045| r0_122(int) = Load : &:r0_121, ~mu0_2 -# 1045| r0_123(int) = Constant[1] : -# 1045| r0_124(int) = Add : r0_122, r0_123 -# 1045| mu0_125(int) = Store : &:r0_120, r0_124 -# 1045| r0_126(glval) = FieldAddress[j] : r0_110 -# 1045| r0_127(glval) = VariableAddress[r] : -# 1045| mu0_128(int &) = Store : &:r0_126, r0_127 -# 1045| r0_129(decltype([...](...){...})) = Load : &:r0_110, ~mu0_2 -# 1045| mu0_130(decltype([...](...){...})) = Store : &:r0_109, r0_129 -# 1046| r0_131(glval) = VariableAddress[lambda_inits] : -# 1046| r0_132(glval) = Convert : r0_131 -# 1046| r0_133(glval) = FunctionAddress[operator()] : -# 1046| r0_134(float) = Constant[6.0] : -# 1046| r0_135(char) = Call : func:r0_133, this:r0_132, 0:r0_134 -# 1046| mu0_136(unknown) = ^CallSideEffect : ~mu0_2 -# 1047| v0_137(void) = NoOp : -# 1031| v0_138(void) = ReturnVoid : -# 1031| v0_139(void) = UnmodeledUse : mu* -# 1031| v0_140(void) = ExitFunction : +# 1031| v0_0(void) = EnterFunction : +# 1031| mu0_1(unknown) = AliasedDefinition : +# 1031| mu0_2(unknown) = UnmodeledDefinition : +# 1031| r0_3(glval) = VariableAddress[x] : +# 1031| mu0_4(int) = InitializeParameter[x] : &:r0_3 +# 1031| r0_5(glval) = VariableAddress[s] : +# 1031| mu0_6(String &) = InitializeParameter[s] : &:r0_5 +# 1032| r0_7(glval) = VariableAddress[lambda_empty] : +# 1032| r0_8(glval) = VariableAddress[#temp1032:23] : +# 1032| mu0_9(decltype([...](...){...})) = Uninitialized[#temp1032:23] : &:r0_8 +# 1032| r0_10(decltype([...](...){...})) = Load : &:r0_8, ~mu0_2 +# 1032| mu0_11(decltype([...](...){...})) = Store : &:r0_7, r0_10 +# 1033| r0_12(char) = Constant[65] : +# 1034| r0_13(glval) = VariableAddress[lambda_ref] : +# 1034| r0_14(glval) = VariableAddress[#temp1034:21] : +# 1034| mu0_15(decltype([...](...){...})) = Uninitialized[#temp1034:21] : &:r0_14 +# 1034| r0_16(glval) = FieldAddress[s] : r0_14 +#-----| r0_17(glval) = VariableAddress[s] : +#-----| r0_18(String &) = Load : &:r0_17, ~mu0_2 +# 1034| r0_19(glval) = CopyValue : r0_18 +# 1034| r0_20(String &) = CopyValue : r0_19 +# 1034| mu0_21(String &) = Store : &:r0_16, r0_20 +# 1034| r0_22(glval) = FieldAddress[x] : r0_14 +#-----| r0_23(glval) = VariableAddress[x] : +#-----| r0_24(int &) = CopyValue : r0_23 +#-----| mu0_25(int &) = Store : &:r0_22, r0_24 +# 1034| r0_26(decltype([...](...){...})) = Load : &:r0_14, ~mu0_2 +# 1034| mu0_27(decltype([...](...){...})) = Store : &:r0_13, r0_26 +# 1035| r0_28(glval) = VariableAddress[lambda_ref] : +# 1035| r0_29(glval) = Convert : r0_28 +# 1035| r0_30(glval) = FunctionAddress[operator()] : +# 1035| r0_31(float) = Constant[1.0] : +# 1035| r0_32(char) = Call : func:r0_30, this:r0_29, 0:r0_31 +# 1035| mu0_33(unknown) = ^CallSideEffect : ~mu0_2 +# 1036| r0_34(glval) = VariableAddress[lambda_val] : +# 1036| r0_35(glval) = FunctionAddress[(constructor)] : +# 1036| r0_36(glval) = VariableAddress[#temp1036:21] : +# 1036| mu0_37(decltype([...](...){...})) = Uninitialized[#temp1036:21] : &:r0_36 +# 1036| r0_38(glval) = FieldAddress[s] : r0_36 +#-----| r0_39(glval) = FunctionAddress[String] : +#-----| v0_40(void) = Call : func:r0_39, this:r0_38 +#-----| mu0_41(unknown) = ^CallSideEffect : ~mu0_2 +# 1036| r0_42(glval) = FieldAddress[x] : r0_36 +#-----| r0_43(glval) = VariableAddress[x] : +#-----| r0_44(int) = Load : &:r0_43, ~mu0_2 +#-----| mu0_45(int) = Store : &:r0_42, r0_44 +# 1036| r0_46(decltype([...](...){...})) = Load : &:r0_36, ~mu0_2 +# 1036| r0_47(lambda [] type at line 1036, col. 21 &) = CopyValue : r0_46 +# 1036| v0_48(void) = Call : func:r0_35, this:r0_34, 0:r0_47 +# 1036| mu0_49(unknown) = ^CallSideEffect : ~mu0_2 +# 1037| r0_50(glval) = VariableAddress[lambda_val] : +# 1037| r0_51(glval) = Convert : r0_50 +# 1037| r0_52(glval) = FunctionAddress[operator()] : +# 1037| r0_53(float) = Constant[2.0] : +# 1037| r0_54(char) = Call : func:r0_52, this:r0_51, 0:r0_53 +# 1037| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 +# 1038| r0_56(glval) = VariableAddress[lambda_ref_explicit] : +# 1038| r0_57(glval) = VariableAddress[#temp1038:30] : +# 1038| mu0_58(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_57 +# 1038| r0_59(glval) = FieldAddress[s] : r0_57 +# 1038| r0_60(glval) = VariableAddress[s] : +# 1038| r0_61(String &) = Load : &:r0_60, ~mu0_2 +# 1038| r0_62(glval) = CopyValue : r0_61 +# 1038| r0_63(String &) = CopyValue : r0_62 +# 1038| mu0_64(String &) = Store : &:r0_59, r0_63 +# 1038| r0_65(decltype([...](...){...})) = Load : &:r0_57, ~mu0_2 +# 1038| mu0_66(decltype([...](...){...})) = Store : &:r0_56, r0_65 +# 1039| r0_67(glval) = VariableAddress[lambda_ref_explicit] : +# 1039| r0_68(glval) = Convert : r0_67 +# 1039| r0_69(glval) = FunctionAddress[operator()] : +# 1039| r0_70(float) = Constant[3.0] : +# 1039| r0_71(char) = Call : func:r0_69, this:r0_68, 0:r0_70 +# 1039| mu0_72(unknown) = ^CallSideEffect : ~mu0_2 +# 1040| r0_73(glval) = VariableAddress[lambda_val_explicit] : +# 1040| r0_74(glval) = FunctionAddress[(constructor)] : +# 1040| r0_75(glval) = VariableAddress[#temp1040:30] : +# 1040| mu0_76(decltype([...](...){...})) = Uninitialized[#temp1040:30] : &:r0_75 +# 1040| r0_77(glval) = FieldAddress[s] : r0_75 +#-----| r0_78(glval) = FunctionAddress[String] : +#-----| v0_79(void) = Call : func:r0_78, this:r0_77 +#-----| mu0_80(unknown) = ^CallSideEffect : ~mu0_2 +# 1040| r0_81(decltype([...](...){...})) = Load : &:r0_75, ~mu0_2 +# 1040| r0_82(lambda [] type at line 1040, col. 30 &) = CopyValue : r0_81 +# 1040| v0_83(void) = Call : func:r0_74, this:r0_73, 0:r0_82 +# 1040| mu0_84(unknown) = ^CallSideEffect : ~mu0_2 +# 1041| r0_85(glval) = VariableAddress[lambda_val_explicit] : +# 1041| r0_86(glval) = Convert : r0_85 +# 1041| r0_87(glval) = FunctionAddress[operator()] : +# 1041| r0_88(float) = Constant[4.0] : +# 1041| r0_89(char) = Call : func:r0_87, this:r0_86, 0:r0_88 +# 1041| mu0_90(unknown) = ^CallSideEffect : ~mu0_2 +# 1042| r0_91(glval) = VariableAddress[lambda_mixed_explicit] : +# 1042| r0_92(glval) = VariableAddress[#temp1042:32] : +# 1042| mu0_93(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_92 +# 1042| r0_94(glval) = FieldAddress[s] : r0_92 +# 1042| r0_95(glval) = VariableAddress[s] : +# 1042| r0_96(String &) = Load : &:r0_95, ~mu0_2 +# 1042| r0_97(glval) = CopyValue : r0_96 +# 1042| r0_98(String &) = CopyValue : r0_97 +# 1042| mu0_99(String &) = Store : &:r0_94, r0_98 +# 1042| r0_100(glval) = FieldAddress[x] : r0_92 +# 1042| r0_101(glval) = VariableAddress[x] : +# 1042| r0_102(int) = Load : &:r0_101, ~mu0_2 +# 1042| mu0_103(int) = Store : &:r0_100, r0_102 +# 1042| r0_104(decltype([...](...){...})) = Load : &:r0_92, ~mu0_2 +# 1042| mu0_105(decltype([...](...){...})) = Store : &:r0_91, r0_104 +# 1043| r0_106(glval) = VariableAddress[lambda_mixed_explicit] : +# 1043| r0_107(glval) = Convert : r0_106 +# 1043| r0_108(glval) = FunctionAddress[operator()] : +# 1043| r0_109(float) = Constant[5.0] : +# 1043| r0_110(char) = Call : func:r0_108, this:r0_107, 0:r0_109 +# 1043| mu0_111(unknown) = ^CallSideEffect : ~mu0_2 +# 1044| r0_112(glval) = VariableAddress[r] : +# 1044| r0_113(glval) = VariableAddress[x] : +# 1044| r0_114(int) = Load : &:r0_113, ~mu0_2 +# 1044| r0_115(int) = Constant[1] : +# 1044| r0_116(int) = Sub : r0_114, r0_115 +# 1044| mu0_117(int) = Store : &:r0_112, r0_116 +# 1045| r0_118(glval) = VariableAddress[lambda_inits] : +# 1045| r0_119(glval) = VariableAddress[#temp1045:23] : +# 1045| mu0_120(decltype([...](...){...})) = Uninitialized[#temp1045:23] : &:r0_119 +# 1045| r0_121(glval) = FieldAddress[s] : r0_119 +# 1045| r0_122(glval) = VariableAddress[s] : +# 1045| r0_123(String &) = Load : &:r0_122, ~mu0_2 +# 1045| r0_124(glval) = CopyValue : r0_123 +# 1045| r0_125(String &) = CopyValue : r0_124 +# 1045| mu0_126(String &) = Store : &:r0_121, r0_125 +# 1045| r0_127(glval) = FieldAddress[x] : r0_119 +# 1045| r0_128(glval) = VariableAddress[x] : +# 1045| r0_129(int) = Load : &:r0_128, ~mu0_2 +# 1045| mu0_130(int) = Store : &:r0_127, r0_129 +# 1045| r0_131(glval) = FieldAddress[i] : r0_119 +# 1045| r0_132(glval) = VariableAddress[x] : +# 1045| r0_133(int) = Load : &:r0_132, ~mu0_2 +# 1045| r0_134(int) = Constant[1] : +# 1045| r0_135(int) = Add : r0_133, r0_134 +# 1045| mu0_136(int) = Store : &:r0_131, r0_135 +# 1045| r0_137(glval) = FieldAddress[j] : r0_119 +# 1045| r0_138(glval) = VariableAddress[r] : +# 1045| r0_139(int &) = CopyValue : r0_138 +# 1045| mu0_140(int &) = Store : &:r0_137, r0_139 +# 1045| r0_141(decltype([...](...){...})) = Load : &:r0_119, ~mu0_2 +# 1045| mu0_142(decltype([...](...){...})) = Store : &:r0_118, r0_141 +# 1046| r0_143(glval) = VariableAddress[lambda_inits] : +# 1046| r0_144(glval) = Convert : r0_143 +# 1046| r0_145(glval) = FunctionAddress[operator()] : +# 1046| r0_146(float) = Constant[6.0] : +# 1046| r0_147(char) = Call : func:r0_145, this:r0_144, 0:r0_146 +# 1046| mu0_148(unknown) = ^CallSideEffect : ~mu0_2 +# 1047| v0_149(void) = NoOp : +# 1031| v0_150(void) = ReturnVoid : +# 1031| v0_151(void) = UnmodeledUse : mu* +# 1031| v0_152(void) = ExitFunction : # 1032| void (void Lambda(int, String const&))::(lambda [] type at line 1032, col. 23)::(constructor)((void Lambda(int, String const&))::(lambda [] type at line 1032, col. 23)&&) # 1032| Block 0 @@ -4741,20 +5029,21 @@ ir.cpp: #-----| r0_7(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 #-----| r0_8(glval) = FieldAddress[s] : r0_7 #-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1034| r0_10(glval) = FunctionAddress[c_str] : -# 1034| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1034| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_13(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 -#-----| r0_14(glval) = FieldAddress[x] : r0_13 -#-----| r0_15(int &) = Load : &:r0_14, ~mu0_2 -# 1034| r0_16(int) = Load : &:r0_15, ~mu0_2 -# 1034| r0_17(glval) = PointerAdd[1] : r0_11, r0_16 -# 1034| r0_18(char) = Load : &:r0_17, ~mu0_2 -# 1034| mu0_19(char) = Store : &:r0_6, r0_18 -# 1034| r0_20(glval) = VariableAddress[#return] : -# 1034| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 -# 1034| v0_22(void) = UnmodeledUse : mu* -# 1034| v0_23(void) = ExitFunction : +# 1034| r0_10(glval) = CopyValue : r0_9 +# 1034| r0_11(glval) = FunctionAddress[c_str] : +# 1034| r0_12(char *) = Call : func:r0_11, this:r0_10 +# 1034| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +#-----| r0_14(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 +#-----| r0_15(glval) = FieldAddress[x] : r0_14 +#-----| r0_16(int &) = Load : &:r0_15, ~mu0_2 +# 1034| r0_17(int) = Load : &:r0_16, ~mu0_2 +# 1034| r0_18(glval) = PointerAdd[1] : r0_12, r0_17 +# 1034| r0_19(char) = Load : &:r0_18, ~mu0_2 +# 1034| mu0_20(char) = Store : &:r0_6, r0_19 +# 1034| r0_21(glval) = VariableAddress[#return] : +# 1034| v0_22(void) = ReturnValue : &:r0_21, ~mu0_2 +# 1034| v0_23(void) = UnmodeledUse : mu* +# 1034| v0_24(void) = ExitFunction : # 1036| void (void Lambda(int, String const&))::(lambda [] type at line 1036, col. 21)::~() # 1036| Block 0 @@ -4808,17 +5097,18 @@ ir.cpp: #-----| r0_7(lambda [] type at line 1038, col. 30 *) = CopyValue : r0_3 #-----| r0_8(glval) = FieldAddress[s] : r0_7 #-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1038| r0_10(glval) = FunctionAddress[c_str] : -# 1038| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1038| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 1038| r0_13(int) = Constant[0] : -# 1038| r0_14(glval) = PointerAdd[1] : r0_11, r0_13 -# 1038| r0_15(char) = Load : &:r0_14, ~mu0_2 -# 1038| mu0_16(char) = Store : &:r0_6, r0_15 -# 1038| r0_17(glval) = VariableAddress[#return] : -# 1038| v0_18(void) = ReturnValue : &:r0_17, ~mu0_2 -# 1038| v0_19(void) = UnmodeledUse : mu* -# 1038| v0_20(void) = ExitFunction : +# 1038| r0_10(glval) = CopyValue : r0_9 +# 1038| r0_11(glval) = FunctionAddress[c_str] : +# 1038| r0_12(char *) = Call : func:r0_11, this:r0_10 +# 1038| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +# 1038| r0_14(int) = Constant[0] : +# 1038| r0_15(glval) = PointerAdd[1] : r0_12, r0_14 +# 1038| r0_16(char) = Load : &:r0_15, ~mu0_2 +# 1038| mu0_17(char) = Store : &:r0_6, r0_16 +# 1038| r0_18(glval) = VariableAddress[#return] : +# 1038| v0_19(void) = ReturnValue : &:r0_18, ~mu0_2 +# 1038| v0_20(void) = UnmodeledUse : mu* +# 1038| v0_21(void) = ExitFunction : # 1040| void (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::(constructor)((void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)&&) # 1040| Block 0 @@ -4887,19 +5177,20 @@ ir.cpp: #-----| r0_7(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 #-----| r0_8(glval) = FieldAddress[s] : r0_7 #-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1042| r0_10(glval) = FunctionAddress[c_str] : -# 1042| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1042| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_13(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 -#-----| r0_14(glval) = FieldAddress[x] : r0_13 -#-----| r0_15(int) = Load : &:r0_14, ~mu0_2 -# 1042| r0_16(glval) = PointerAdd[1] : r0_11, r0_15 -# 1042| r0_17(char) = Load : &:r0_16, ~mu0_2 -# 1042| mu0_18(char) = Store : &:r0_6, r0_17 -# 1042| r0_19(glval) = VariableAddress[#return] : -# 1042| v0_20(void) = ReturnValue : &:r0_19, ~mu0_2 -# 1042| v0_21(void) = UnmodeledUse : mu* -# 1042| v0_22(void) = ExitFunction : +# 1042| r0_10(glval) = CopyValue : r0_9 +# 1042| r0_11(glval) = FunctionAddress[c_str] : +# 1042| r0_12(char *) = Call : func:r0_11, this:r0_10 +# 1042| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +#-----| r0_14(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 +#-----| r0_15(glval) = FieldAddress[x] : r0_14 +#-----| r0_16(int) = Load : &:r0_15, ~mu0_2 +# 1042| r0_17(glval) = PointerAdd[1] : r0_12, r0_16 +# 1042| r0_18(char) = Load : &:r0_17, ~mu0_2 +# 1042| mu0_19(char) = Store : &:r0_6, r0_18 +# 1042| r0_20(glval) = VariableAddress[#return] : +# 1042| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 +# 1042| v0_22(void) = UnmodeledUse : mu* +# 1042| v0_23(void) = ExitFunction : # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 23)::operator()(float) const # 1045| Block 0 @@ -4913,28 +5204,29 @@ ir.cpp: #-----| r0_7(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 #-----| r0_8(glval) = FieldAddress[s] : r0_7 #-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1045| r0_10(glval) = FunctionAddress[c_str] : -# 1045| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1045| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_13(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -#-----| r0_14(glval) = FieldAddress[x] : r0_13 -#-----| r0_15(int) = Load : &:r0_14, ~mu0_2 -#-----| r0_16(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -# 1045| r0_17(glval) = FieldAddress[i] : r0_16 -# 1045| r0_18(int) = Load : &:r0_17, ~mu0_2 -# 1045| r0_19(int) = Add : r0_15, r0_18 -#-----| r0_20(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -# 1045| r0_21(glval) = FieldAddress[j] : r0_20 -# 1045| r0_22(int &) = Load : &:r0_21, ~mu0_2 -# 1045| r0_23(int) = Load : &:r0_22, ~mu0_2 -# 1045| r0_24(int) = Sub : r0_19, r0_23 -# 1045| r0_25(glval) = PointerAdd[1] : r0_11, r0_24 -# 1045| r0_26(char) = Load : &:r0_25, ~mu0_2 -# 1045| mu0_27(char) = Store : &:r0_6, r0_26 -# 1045| r0_28(glval) = VariableAddress[#return] : -# 1045| v0_29(void) = ReturnValue : &:r0_28, ~mu0_2 -# 1045| v0_30(void) = UnmodeledUse : mu* -# 1045| v0_31(void) = ExitFunction : +# 1045| r0_10(glval) = CopyValue : r0_9 +# 1045| r0_11(glval) = FunctionAddress[c_str] : +# 1045| r0_12(char *) = Call : func:r0_11, this:r0_10 +# 1045| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +#-----| r0_14(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +#-----| r0_15(glval) = FieldAddress[x] : r0_14 +#-----| r0_16(int) = Load : &:r0_15, ~mu0_2 +#-----| r0_17(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +# 1045| r0_18(glval) = FieldAddress[i] : r0_17 +# 1045| r0_19(int) = Load : &:r0_18, ~mu0_2 +# 1045| r0_20(int) = Add : r0_16, r0_19 +#-----| r0_21(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +# 1045| r0_22(glval) = FieldAddress[j] : r0_21 +# 1045| r0_23(int &) = Load : &:r0_22, ~mu0_2 +# 1045| r0_24(int) = Load : &:r0_23, ~mu0_2 +# 1045| r0_25(int) = Sub : r0_20, r0_24 +# 1045| r0_26(glval) = PointerAdd[1] : r0_12, r0_25 +# 1045| r0_27(char) = Load : &:r0_26, ~mu0_2 +# 1045| mu0_28(char) = Store : &:r0_6, r0_27 +# 1045| r0_29(glval) = VariableAddress[#return] : +# 1045| v0_30(void) = ReturnValue : &:r0_29, ~mu0_2 +# 1045| v0_31(void) = UnmodeledUse : mu* +# 1045| v0_32(void) = ExitFunction : # 1068| void RangeBasedFor(vector const&) # 1068| Block 0 @@ -4946,132 +5238,144 @@ ir.cpp: # 1069| r0_5(glval &>) = VariableAddress[(__range)] : # 1069| r0_6(glval &>) = VariableAddress[v] : # 1069| r0_7(vector &) = Load : &:r0_6, ~mu0_2 -# 1069| mu0_8(vector &) = Store : &:r0_5, r0_7 -# 1069| r0_9(glval) = VariableAddress[(__begin)] : -#-----| r0_10(glval &>) = VariableAddress[(__range)] : -#-----| r0_11(vector &) = Load : &:r0_10, ~mu0_2 -# 1069| r0_12(glval) = FunctionAddress[begin] : -# 1069| r0_13(iterator) = Call : func:r0_12, this:r0_11 -# 1069| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 -# 1069| mu0_15(iterator) = Store : &:r0_9, r0_13 -# 1069| r0_16(glval) = VariableAddress[(__end)] : -#-----| r0_17(glval &>) = VariableAddress[(__range)] : -#-----| r0_18(vector &) = Load : &:r0_17, ~mu0_2 -# 1069| r0_19(glval) = FunctionAddress[end] : -# 1069| r0_20(iterator) = Call : func:r0_19, this:r0_18 -# 1069| mu0_21(unknown) = ^CallSideEffect : ~mu0_2 -# 1069| mu0_22(iterator) = Store : &:r0_16, r0_20 -#-----| Goto -> Block 1 +# 1069| r0_8(glval>) = CopyValue : r0_7 +# 1069| r0_9(vector &) = CopyValue : r0_8 +# 1069| mu0_10(vector &) = Store : &:r0_5, r0_9 +# 1069| r0_11(glval) = VariableAddress[(__begin)] : +#-----| r0_12(glval &>) = VariableAddress[(__range)] : +#-----| r0_13(vector &) = Load : &:r0_12, ~mu0_2 +#-----| r0_14(glval>) = CopyValue : r0_13 +# 1069| r0_15(glval) = FunctionAddress[begin] : +# 1069| r0_16(iterator) = Call : func:r0_15, this:r0_14 +# 1069| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 +# 1069| mu0_18(iterator) = Store : &:r0_11, r0_16 +# 1069| r0_19(glval) = VariableAddress[(__end)] : +#-----| r0_20(glval &>) = VariableAddress[(__range)] : +#-----| r0_21(vector &) = Load : &:r0_20, ~mu0_2 +#-----| r0_22(glval>) = CopyValue : r0_21 +# 1069| r0_23(glval) = FunctionAddress[end] : +# 1069| r0_24(iterator) = Call : func:r0_23, this:r0_22 +# 1069| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +# 1069| mu0_26(iterator) = Store : &:r0_19, r0_24 +#-----| Goto -> Block 3 -#-----| Block 1 -#-----| r1_0(glval) = VariableAddress[(__begin)] : -#-----| r1_1(glval) = Convert : r1_0 -# 1069| r1_2(glval) = FunctionAddress[operator!=] : -#-----| r1_3(glval) = VariableAddress[(__end)] : -#-----| r1_4(iterator) = Load : &:r1_3, ~mu0_2 -# 1069| r1_5(bool) = Call : func:r1_2, this:r1_1, 0:r1_4 -# 1069| mu1_6(unknown) = ^CallSideEffect : ~mu0_2 -# 1069| v1_7(void) = ConditionalBranch : r1_5 -#-----| False -> Block 5 -#-----| True -> Block 2 +# 1077| Block 1 +# 1077| v1_0(void) = NoOp : +#-----| Goto -> Block 2 -# 1069| Block 2 -# 1069| r2_0(glval) = VariableAddress[e] : -#-----| r2_1(glval) = VariableAddress[(__begin)] : -#-----| r2_2(glval) = Convert : r2_1 -# 1069| r2_3(glval) = FunctionAddress[operator*] : -# 1069| r2_4(int &) = Call : func:r2_3, this:r2_2 -# 1069| mu2_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1069| r2_6(int) = Load : &:r2_4, ~mu0_2 -# 1069| mu2_7(int) = Store : &:r2_0, r2_6 -# 1070| r2_8(glval) = VariableAddress[e] : -# 1070| r2_9(int) = Load : &:r2_8, ~mu0_2 -# 1070| r2_10(int) = Constant[0] : -# 1070| r2_11(bool) = CompareGT : r2_9, r2_10 -# 1070| v2_12(void) = ConditionalBranch : r2_11 -#-----| False -> Block 4 -#-----| True -> Block 3 +# 1079| Block 2 +# 1079| v2_0(void) = NoOp : +# 1080| v2_1(void) = NoOp : +# 1068| v2_2(void) = ReturnVoid : +# 1068| v2_3(void) = UnmodeledUse : mu* +# 1068| v2_4(void) = ExitFunction : -# 1071| Block 3 -# 1071| v3_0(void) = NoOp : -#-----| Goto -> Block 4 +#-----| Block 3 +#-----| r3_0(glval) = VariableAddress[(__begin)] : +#-----| r3_1(glval) = Convert : r3_0 +# 1069| r3_2(glval) = FunctionAddress[operator!=] : +#-----| r3_3(glval) = VariableAddress[(__end)] : +#-----| r3_4(iterator) = Load : &:r3_3, ~mu0_2 +# 1069| r3_5(bool) = Call : func:r3_2, this:r3_1, 0:r3_4 +# 1069| mu3_6(unknown) = ^CallSideEffect : ~mu0_2 +# 1069| v3_7(void) = ConditionalBranch : r3_5 +#-----| False -> Block 7 +#-----| True -> Block 4 # 1069| Block 4 -# 1069| v4_0(void) = NoOp : -#-----| r4_1(glval) = VariableAddress[(__begin)] : -# 1069| r4_2(glval) = FunctionAddress[operator++] : -# 1069| r4_3(iterator &) = Call : func:r4_2, this:r4_1 -# 1069| mu4_4(unknown) = ^CallSideEffect : ~mu0_2 -#-----| Goto (back edge) -> Block 1 +# 1069| r4_0(glval) = VariableAddress[e] : +#-----| r4_1(glval) = VariableAddress[(__begin)] : +#-----| r4_2(glval) = Convert : r4_1 +# 1069| r4_3(glval) = FunctionAddress[operator*] : +# 1069| r4_4(int &) = Call : func:r4_3, this:r4_2 +# 1069| mu4_5(unknown) = ^CallSideEffect : ~mu0_2 +# 1069| r4_6(int) = Load : &:r4_4, ~mu0_2 +# 1069| mu4_7(int) = Store : &:r4_0, r4_6 +# 1070| r4_8(glval) = VariableAddress[e] : +# 1070| r4_9(int) = Load : &:r4_8, ~mu0_2 +# 1070| r4_10(int) = Constant[0] : +# 1070| r4_11(bool) = CompareGT : r4_9, r4_10 +# 1070| v4_12(void) = ConditionalBranch : r4_11 +#-----| False -> Block 6 +#-----| True -> Block 5 -# 1075| Block 5 -# 1075| r5_0(glval &>) = VariableAddress[(__range)] : -# 1075| r5_1(glval &>) = VariableAddress[v] : -# 1075| r5_2(vector &) = Load : &:r5_1, ~mu0_2 -# 1075| mu5_3(vector &) = Store : &:r5_0, r5_2 -# 1075| r5_4(glval) = VariableAddress[(__begin)] : -#-----| r5_5(glval &>) = VariableAddress[(__range)] : -#-----| r5_6(vector &) = Load : &:r5_5, ~mu0_2 -# 1075| r5_7(glval) = FunctionAddress[begin] : -# 1075| r5_8(iterator) = Call : func:r5_7, this:r5_6 -# 1075| mu5_9(unknown) = ^CallSideEffect : ~mu0_2 -# 1075| mu5_10(iterator) = Store : &:r5_4, r5_8 -# 1075| r5_11(glval) = VariableAddress[(__end)] : -#-----| r5_12(glval &>) = VariableAddress[(__range)] : -#-----| r5_13(vector &) = Load : &:r5_12, ~mu0_2 -# 1075| r5_14(glval) = FunctionAddress[end] : -# 1075| r5_15(iterator) = Call : func:r5_14, this:r5_13 -# 1075| mu5_16(unknown) = ^CallSideEffect : ~mu0_2 -# 1075| mu5_17(iterator) = Store : &:r5_11, r5_15 +# 1071| Block 5 +# 1071| v5_0(void) = NoOp : #-----| Goto -> Block 6 -#-----| Block 6 -#-----| r6_0(glval) = VariableAddress[(__begin)] : -#-----| r6_1(glval) = Convert : r6_0 -# 1075| r6_2(glval) = FunctionAddress[operator!=] : -#-----| r6_3(glval) = VariableAddress[(__end)] : -#-----| r6_4(iterator) = Load : &:r6_3, ~mu0_2 -# 1075| r6_5(bool) = Call : func:r6_2, this:r6_1, 0:r6_4 -# 1075| mu6_6(unknown) = ^CallSideEffect : ~mu0_2 -# 1075| v6_7(void) = ConditionalBranch : r6_5 -#-----| False -> Block 10 -#-----| True -> Block 8 +# 1069| Block 6 +# 1069| v6_0(void) = NoOp : +#-----| r6_1(glval) = VariableAddress[(__begin)] : +# 1069| r6_2(glval) = FunctionAddress[operator++] : +# 1069| r6_3(iterator &) = Call : func:r6_2, this:r6_1 +# 1069| mu6_4(unknown) = ^CallSideEffect : ~mu0_2 +# 1069| r6_5(glval) = CopyValue : r6_3 +#-----| Goto (back edge) -> Block 3 -#-----| Block 7 -#-----| r7_0(glval) = VariableAddress[(__begin)] : -# 1075| r7_1(glval) = FunctionAddress[operator++] : -# 1075| r7_2(iterator &) = Call : func:r7_1, this:r7_0 -# 1075| mu7_3(unknown) = ^CallSideEffect : ~mu0_2 -#-----| Goto (back edge) -> Block 6 +# 1075| Block 7 +# 1075| r7_0(glval &>) = VariableAddress[(__range)] : +# 1075| r7_1(glval &>) = VariableAddress[v] : +# 1075| r7_2(vector &) = Load : &:r7_1, ~mu0_2 +# 1075| r7_3(glval>) = CopyValue : r7_2 +# 1075| r7_4(vector &) = CopyValue : r7_3 +# 1075| mu7_5(vector &) = Store : &:r7_0, r7_4 +# 1075| r7_6(glval) = VariableAddress[(__begin)] : +#-----| r7_7(glval &>) = VariableAddress[(__range)] : +#-----| r7_8(vector &) = Load : &:r7_7, ~mu0_2 +#-----| r7_9(glval>) = CopyValue : r7_8 +# 1075| r7_10(glval) = FunctionAddress[begin] : +# 1075| r7_11(iterator) = Call : func:r7_10, this:r7_9 +# 1075| mu7_12(unknown) = ^CallSideEffect : ~mu0_2 +# 1075| mu7_13(iterator) = Store : &:r7_6, r7_11 +# 1075| r7_14(glval) = VariableAddress[(__end)] : +#-----| r7_15(glval &>) = VariableAddress[(__range)] : +#-----| r7_16(vector &) = Load : &:r7_15, ~mu0_2 +#-----| r7_17(glval>) = CopyValue : r7_16 +# 1075| r7_18(glval) = FunctionAddress[end] : +# 1075| r7_19(iterator) = Call : func:r7_18, this:r7_17 +# 1075| mu7_20(unknown) = ^CallSideEffect : ~mu0_2 +# 1075| mu7_21(iterator) = Store : &:r7_14, r7_19 +#-----| Goto -> Block 8 -# 1075| Block 8 -# 1075| r8_0(glval) = VariableAddress[e] : -#-----| r8_1(glval) = VariableAddress[(__begin)] : -#-----| r8_2(glval) = Convert : r8_1 -# 1075| r8_3(glval) = FunctionAddress[operator*] : -# 1075| r8_4(int &) = Call : func:r8_3, this:r8_2 -# 1075| mu8_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1075| r8_6(glval) = Convert : r8_4 -# 1075| mu8_7(int &) = Store : &:r8_0, r8_6 -# 1076| r8_8(glval) = VariableAddress[e] : -# 1076| r8_9(int &) = Load : &:r8_8, ~mu0_2 -# 1076| r8_10(int) = Load : &:r8_9, ~mu0_2 -# 1076| r8_11(int) = Constant[5] : -# 1076| r8_12(bool) = CompareLT : r8_10, r8_11 -# 1076| v8_13(void) = ConditionalBranch : r8_12 -#-----| False -> Block 7 -#-----| True -> Block 9 +#-----| Block 8 +#-----| r8_0(glval) = VariableAddress[(__begin)] : +#-----| r8_1(glval) = Convert : r8_0 +# 1075| r8_2(glval) = FunctionAddress[operator!=] : +#-----| r8_3(glval) = VariableAddress[(__end)] : +#-----| r8_4(iterator) = Load : &:r8_3, ~mu0_2 +# 1075| r8_5(bool) = Call : func:r8_2, this:r8_1, 0:r8_4 +# 1075| mu8_6(unknown) = ^CallSideEffect : ~mu0_2 +# 1075| v8_7(void) = ConditionalBranch : r8_5 +#-----| False -> Block 2 +#-----| True -> Block 10 -# 1077| Block 9 -# 1077| v9_0(void) = NoOp : -#-----| Goto -> Block 10 +#-----| Block 9 +#-----| r9_0(glval) = VariableAddress[(__begin)] : +# 1075| r9_1(glval) = FunctionAddress[operator++] : +# 1075| r9_2(iterator &) = Call : func:r9_1, this:r9_0 +# 1075| mu9_3(unknown) = ^CallSideEffect : ~mu0_2 +# 1075| r9_4(glval) = CopyValue : r9_2 +#-----| Goto (back edge) -> Block 8 -# 1079| Block 10 -# 1079| v10_0(void) = NoOp : -# 1080| v10_1(void) = NoOp : -# 1068| v10_2(void) = ReturnVoid : -# 1068| v10_3(void) = UnmodeledUse : mu* -# 1068| v10_4(void) = ExitFunction : +# 1075| Block 10 +# 1075| r10_0(glval) = VariableAddress[e] : +#-----| r10_1(glval) = VariableAddress[(__begin)] : +#-----| r10_2(glval) = Convert : r10_1 +# 1075| r10_3(glval) = FunctionAddress[operator*] : +# 1075| r10_4(int &) = Call : func:r10_3, this:r10_2 +# 1075| mu10_5(unknown) = ^CallSideEffect : ~mu0_2 +# 1075| r10_6(glval) = CopyValue : r10_4 +# 1075| r10_7(glval) = Convert : r10_6 +# 1075| r10_8(int &) = CopyValue : r10_7 +# 1075| mu10_9(int &) = Store : &:r10_0, r10_8 +# 1076| r10_10(glval) = VariableAddress[e] : +# 1076| r10_11(int &) = Load : &:r10_10, ~mu0_2 +# 1076| r10_12(int) = Load : &:r10_11, ~mu0_2 +# 1076| r10_13(int) = Constant[5] : +# 1076| r10_14(bool) = CompareLT : r10_12, r10_13 +# 1076| v10_15(void) = ConditionalBranch : r10_14 +#-----| False -> Block 9 +#-----| True -> Block 1 # 1099| int AsmStmt(int) # 1099| Block 0 @@ -5154,6 +5458,7 @@ ir.cpp: # 1130| r2_2(int) = Constant[1] : # 1130| r2_3(int) = Add : r2_1, r2_2 # 1130| mu2_4(int) = Store : &:r2_0, r2_3 +# 1130| r2_5(glval) = CopyValue : r2_0 #-----| Goto (back edge) -> Block 1 # 1130| Block 3 @@ -5219,6 +5524,7 @@ ir.cpp: # 1140| r6_4(int) = Load : &:r6_3, ~mu0_2 # 1140| r6_5(glval) = VariableAddress[x] : # 1140| mu6_6(int) = Store : &:r6_5, r6_4 +# 1140| r6_7(glval) = CopyValue : r6_5 #-----| Goto -> Block 8 # 1140| Block 7 @@ -5235,6 +5541,7 @@ ir.cpp: # 1142| r8_0(int) = Constant[7] : # 1142| r8_1(glval) = VariableAddress[x] : # 1142| mu8_2(int) = Store : &:r8_1, r8_0 +# 1142| r8_3(glval) = CopyValue : r8_1 #-----| Goto -> Block 13 # 1144| Block 9 @@ -5309,28 +5616,30 @@ ir.cpp: # 1156| r0_34(int) = Load : &:r0_33, ~mu0_2 # 1156| r0_35(glval) = PointerAdd[4] : r0_32, r0_34 # 1156| mu0_36(int) = Store : &:r0_35, r0_31 -# 1157| r0_37(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4_shuffle] : -# 1157| r0_38(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : -# 1157| r0_39(__attribute((vector_size(16))) int) = Load : &:r0_38, ~mu0_2 -# 1157| r0_40(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : -# 1157| r0_41(__attribute((vector_size(16))) int) = Load : &:r0_40, ~mu0_2 -#-----| r0_42(int) = Constant[3] : -# 1157| r0_43(int) = Constant[2] : -# 1157| r0_44(int) = Constant[1] : -# 1157| r0_45(int) = Constant[0] : -# 1157| r0_46(__attribute((vector_size(16))) int) = BuiltIn[__builtin_shufflevector] : 0:r0_39, 1:r0_41, 2:r0_42, 3:r0_43, 4:r0_44, 5:r0_45 -# 1157| mu0_47(__attribute((vector_size(16))) int) = Store : &:r0_37, r0_46 -# 1158| r0_48(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : -# 1158| r0_49(__attribute((vector_size(16))) int) = Load : &:r0_48, ~mu0_2 -# 1158| r0_50(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4_shuffle] : -# 1158| r0_51(__attribute((vector_size(16))) int) = Load : &:r0_50, ~mu0_2 -# 1158| r0_52(__attribute((vector_size(16))) int) = Add : r0_49, r0_51 -# 1158| r0_53(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : -# 1158| mu0_54(__attribute((vector_size(16))) int) = Store : &:r0_53, r0_52 -# 1159| v0_55(void) = NoOp : -# 1153| v0_56(void) = ReturnVoid : -# 1153| v0_57(void) = UnmodeledUse : mu* -# 1153| v0_58(void) = ExitFunction : +# 1156| r0_37(glval) = CopyValue : r0_35 +# 1157| r0_38(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4_shuffle] : +# 1157| r0_39(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : +# 1157| r0_40(__attribute((vector_size(16))) int) = Load : &:r0_39, ~mu0_2 +# 1157| r0_41(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : +# 1157| r0_42(__attribute((vector_size(16))) int) = Load : &:r0_41, ~mu0_2 +#-----| r0_43(int) = Constant[3] : +# 1157| r0_44(int) = Constant[2] : +# 1157| r0_45(int) = Constant[1] : +# 1157| r0_46(int) = Constant[0] : +# 1157| r0_47(__attribute((vector_size(16))) int) = BuiltIn[__builtin_shufflevector] : 0:r0_40, 1:r0_42, 2:r0_43, 3:r0_44, 4:r0_45, 5:r0_46 +# 1157| mu0_48(__attribute((vector_size(16))) int) = Store : &:r0_38, r0_47 +# 1158| r0_49(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : +# 1158| r0_50(__attribute((vector_size(16))) int) = Load : &:r0_49, ~mu0_2 +# 1158| r0_51(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4_shuffle] : +# 1158| r0_52(__attribute((vector_size(16))) int) = Load : &:r0_51, ~mu0_2 +# 1158| r0_53(__attribute((vector_size(16))) int) = Add : r0_50, r0_52 +# 1158| r0_54(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : +# 1158| mu0_55(__attribute((vector_size(16))) int) = Store : &:r0_54, r0_53 +# 1158| r0_56(glval<__attribute((vector_size(16))) int>) = CopyValue : r0_54 +# 1159| v0_57(void) = NoOp : +# 1153| v0_58(void) = ReturnVoid : +# 1153| v0_59(void) = UnmodeledUse : mu* +# 1153| v0_60(void) = ExitFunction : perf-regression.cpp: # 6| void Big::Big() 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 fe11d99f31f..f3f5101dcb4 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 @@ -211,8 +211,10 @@ ssa.cpp: # 70| r1_3(int) = Constant[1] : # 70| r1_4(char *) = PointerAdd[1] : r1_2, r1_3 # 70| m1_5(char *) = Store : &:r1_1, r1_4 -# 70| m1_6(char) = Store : &:r1_2, r1_0 -# 70| m1_7(unknown) = Chi : total:m3_0, partial:m1_6 +# 70| r1_6(glval) = CopyValue : r1_2 +# 70| m1_7(char) = Store : &:r1_6, r1_0 +# 70| m1_8(unknown) = Chi : total:m3_0, partial:m1_7 +# 70| r1_9(glval) = CopyValue : r1_6 #-----| Goto (back edge) -> Block 3 # 71| Block 2 @@ -222,7 +224,7 @@ ssa.cpp: # 68| v2_3(void) = ExitFunction : # 69| Block 3 -# 69| m3_0(unknown) = Phi : from 0:~m0_1, from 1:~m1_7 +# 69| m3_0(unknown) = Phi : from 0:~m0_1, from 1:~m1_8 # 69| m3_1(int) = Phi : from 0:m0_4, from 1:m3_7 # 69| m3_2(char *) = Phi : from 0:m0_6, from 1:m1_5 # 69| r3_3(glval) = VariableAddress[n] : @@ -262,20 +264,23 @@ ssa.cpp: # 80| r1_0(int) = Constant[3] : # 80| r1_1(glval) = VariableAddress[x] : # 80| m1_2(int) = Store : &:r1_1, r1_0 -# 81| r1_3(int) = Constant[4] : -# 81| r1_4(glval) = VariableAddress[y] : -# 81| m1_5(int) = Store : &:r1_4, r1_3 +# 80| r1_3(glval) = CopyValue : r1_1 +# 81| r1_4(int) = Constant[4] : +# 81| r1_5(glval) = VariableAddress[y] : +# 81| m1_6(int) = Store : &:r1_5, r1_4 +# 81| r1_7(glval) = CopyValue : r1_5 #-----| Goto -> Block 3 # 84| Block 2 # 84| r2_0(int) = Constant[5] : # 84| r2_1(glval) = VariableAddress[x] : # 84| m2_2(int) = Store : &:r2_1, r2_0 +# 84| r2_3(glval) = CopyValue : r2_1 #-----| Goto -> Block 3 # 86| Block 3 # 86| m3_0(int) = Phi : from 1:m1_2, from 2:m2_2 -# 86| m3_1(int) = Phi : from 1:m1_5, from 2:m0_10 +# 86| m3_1(int) = Phi : from 1:m1_6, from 2:m0_10 # 86| r3_2(glval) = VariableAddress[x_merge] : # 86| r3_3(glval) = VariableAddress[x] : # 86| r3_4(int) = Load : &:r3_3, m3_0 @@ -323,14 +328,15 @@ ssa.cpp: # 96| m0_9(Point) = Store : &:r0_6, r0_8 # 97| r0_10(glval) = FunctionAddress[Escape] : # 97| r0_11(glval) = VariableAddress[a] : -# 97| r0_12(void *) = Convert : r0_11 -# 97| v0_13(void) = Call : func:r0_10, 0:r0_12 -# 97| m0_14(unknown) = ^CallSideEffect : ~m0_5 -# 97| m0_15(unknown) = Chi : total:m0_5, partial:m0_14 -# 98| v0_16(void) = NoOp : -# 95| v0_17(void) = ReturnVoid : -# 95| v0_18(void) = UnmodeledUse : mu* -# 95| v0_19(void) = ExitFunction : +# 97| r0_12(Point *) = CopyValue : r0_11 +# 97| r0_13(void *) = Convert : r0_12 +# 97| v0_14(void) = Call : func:r0_10, 0:r0_13 +# 97| m0_15(unknown) = ^CallSideEffect : ~m0_5 +# 97| m0_16(unknown) = Chi : total:m0_5, partial:m0_15 +# 98| v0_17(void) = NoOp : +# 95| v0_18(void) = ReturnVoid : +# 95| v0_19(void) = UnmodeledUse : mu* +# 95| v0_20(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -374,14 +380,15 @@ ssa.cpp: # 107| m0_15(int) = Store : &:r0_11, r0_14 # 108| r0_16(glval) = FunctionAddress[Escape] : # 108| r0_17(glval) = VariableAddress[a] : -# 108| r0_18(void *) = Convert : r0_17 -# 108| v0_19(void) = Call : func:r0_16, 0:r0_18 -# 108| m0_20(unknown) = ^CallSideEffect : ~m0_5 -# 108| m0_21(unknown) = Chi : total:m0_5, partial:m0_20 -# 109| v0_22(void) = NoOp : -# 105| v0_23(void) = ReturnVoid : -# 105| v0_24(void) = UnmodeledUse : mu* -# 105| v0_25(void) = ExitFunction : +# 108| r0_18(Point *) = CopyValue : r0_17 +# 108| r0_19(void *) = Convert : r0_18 +# 108| v0_20(void) = Call : func:r0_16, 0:r0_19 +# 108| m0_21(unknown) = ^CallSideEffect : ~m0_5 +# 108| m0_22(unknown) = Chi : total:m0_5, partial:m0_21 +# 109| v0_23(void) = NoOp : +# 105| v0_24(void) = ReturnVoid : +# 105| v0_25(void) = UnmodeledUse : mu* +# 105| v0_26(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -441,14 +448,15 @@ ssa.cpp: # 118| m0_23(Point) = Store : &:r0_20, r0_22 # 119| r0_24(glval) = FunctionAddress[Escape] : # 119| r0_25(glval) = VariableAddress[a] : -# 119| r0_26(void *) = Convert : r0_25 -# 119| v0_27(void) = Call : func:r0_24, 0:r0_26 -# 119| m0_28(unknown) = ^CallSideEffect : ~m0_19 -# 119| m0_29(unknown) = Chi : total:m0_19, partial:m0_28 -# 120| v0_30(void) = NoOp : -# 116| v0_31(void) = ReturnVoid : -# 116| v0_32(void) = UnmodeledUse : mu* -# 116| v0_33(void) = ExitFunction : +# 119| r0_26(Point *) = CopyValue : r0_25 +# 119| r0_27(void *) = Convert : r0_26 +# 119| v0_28(void) = Call : func:r0_24, 0:r0_27 +# 119| m0_29(unknown) = ^CallSideEffect : ~m0_19 +# 119| m0_30(unknown) = Chi : total:m0_19, partial:m0_29 +# 120| v0_31(void) = NoOp : +# 116| v0_32(void) = ReturnVoid : +# 116| v0_33(void) = UnmodeledUse : mu* +# 116| v0_34(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -484,6 +492,7 @@ ssa.cpp: # 125| r1_3(glval) = FieldAddress[x] : r1_2 # 125| m1_4(int) = Store : &:r1_3, r1_1 # 125| m1_5(Point) = Chi : total:m0_18, partial:m1_4 +# 125| r1_6(glval) = CopyValue : r1_3 #-----| Goto -> Block 3 # 128| Block 2 @@ -493,6 +502,7 @@ ssa.cpp: # 128| r2_3(glval) = FieldAddress[x] : r2_2 # 128| m2_4(int) = Store : &:r2_3, r2_1 # 128| m2_5(Point) = Chi : total:m0_18, partial:m2_4 +# 128| r2_6(glval) = CopyValue : r2_3 #-----| Goto -> Block 3 # 130| Block 3 @@ -546,6 +556,7 @@ ssa.cpp: # 137| r1_3(glval) = FieldAddress[x] : r1_2 # 137| m1_4(int) = Store : &:r1_3, r1_1 # 137| m1_5(Point) = Chi : total:m0_18, partial:m1_4 +# 137| r1_6(glval) = CopyValue : r1_3 #-----| Goto -> Block 3 # 140| Block 2 @@ -553,6 +564,7 @@ ssa.cpp: # 140| r2_1(Point) = Load : &:r2_0, m0_6 # 140| r2_2(glval) = VariableAddress[a] : # 140| m2_3(Point) = Store : &:r2_2, r2_1 +# 140| r2_4(glval) = CopyValue : r2_2 #-----| Goto -> Block 3 # 142| Block 3 @@ -602,6 +614,7 @@ ssa.cpp: # 148| r1_3(glval) = FieldAddress[x] : r1_2 # 148| m1_4(int) = Store : &:r1_3, r1_1 # 148| m1_5(Point) = Chi : total:m0_18, partial:m1_4 +# 148| r1_6(glval) = CopyValue : r1_3 #-----| Goto -> Block 3 # 151| Block 2 @@ -609,6 +622,7 @@ ssa.cpp: # 151| r2_1(Point) = Load : &:r2_0, m0_6 # 151| r2_2(glval) = VariableAddress[a] : # 151| m2_3(Point) = Store : &:r2_2, r2_1 +# 151| r2_4(glval) = CopyValue : r2_2 #-----| Goto -> Block 3 # 153| Block 3 @@ -657,6 +671,7 @@ ssa.cpp: # 159| r1_4(glval) = FieldAddress[x] : r1_3 # 159| m1_5(int) = Store : &:r1_4, r1_1 # 159| m1_6(Rect) = Chi : total:m0_18, partial:m1_5 +# 159| r1_7(glval) = CopyValue : r1_4 #-----| Goto -> Block 3 # 162| Block 2 @@ -664,6 +679,7 @@ ssa.cpp: # 162| r2_1(Rect) = Load : &:r2_0, m0_6 # 162| r2_2(glval) = VariableAddress[a] : # 162| m2_3(Rect) = Store : &:r2_2, r2_1 +# 162| r2_4(glval) = CopyValue : r2_2 #-----| Goto -> Block 3 # 164| Block 3 @@ -698,19 +714,22 @@ ssa.cpp: # 174| r0_15(glval) = VariableAddress[w] : # 174| r0_16(glval) = FieldAddress[f] : r0_15 # 174| m0_17(int) = Store : &:r0_16, r0_14 -# 175| r0_18(glval) = VariableAddress[w] : -# 175| r0_19(glval) = FieldAddress[f] : r0_18 -# 175| r0_20(int) = Load : &:r0_19, m0_17 -# 175| r0_21(glval) = VariableAddress[a] : -# 175| m0_22(int) = Store : &:r0_21, r0_20 -# 176| r0_23(glval) = VariableAddress[w] : -# 176| r0_24(Wrapper) = Load : &:r0_23, ~m0_17 -# 176| r0_25(glval) = VariableAddress[x] : -# 176| m0_26(Wrapper) = Store : &:r0_25, r0_24 -# 177| v0_27(void) = NoOp : -# 171| v0_28(void) = ReturnVoid : -# 171| v0_29(void) = UnmodeledUse : mu* -# 171| v0_30(void) = ExitFunction : +# 174| r0_18(glval) = CopyValue : r0_16 +# 175| r0_19(glval) = VariableAddress[w] : +# 175| r0_20(glval) = FieldAddress[f] : r0_19 +# 175| r0_21(int) = Load : &:r0_20, m0_17 +# 175| r0_22(glval) = VariableAddress[a] : +# 175| m0_23(int) = Store : &:r0_22, r0_21 +# 175| r0_24(glval) = CopyValue : r0_22 +# 176| r0_25(glval) = VariableAddress[w] : +# 176| r0_26(Wrapper) = Load : &:r0_25, ~m0_17 +# 176| r0_27(glval) = VariableAddress[x] : +# 176| m0_28(Wrapper) = Store : &:r0_27, r0_26 +# 176| r0_29(glval) = CopyValue : r0_27 +# 177| v0_30(void) = NoOp : +# 171| v0_31(void) = ReturnVoid : +# 171| v0_32(void) = UnmodeledUse : mu* +# 171| v0_33(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 @@ -791,19 +810,21 @@ ssa.cpp: # 200| r0_27(int) = Load : &:r0_26, m0_19 # 200| r0_28(int) = Add : r0_27, r0_24 # 200| m0_29(int) = Store : &:r0_26, r0_28 -# 201| r0_30(glval) = FunctionAddress[abs] : -# 201| r0_31(glval) = VariableAddress[x] : -# 201| r0_32(int) = Load : &:r0_31, m0_8 -# 201| r0_33(int) = Call : func:r0_30, 0:r0_32 -# 201| r0_34(glval) = VariableAddress[ret] : -# 201| r0_35(int) = Load : &:r0_34, m0_29 -# 201| r0_36(int) = Add : r0_35, r0_33 -# 201| m0_37(int) = Store : &:r0_34, r0_36 -# 202| r0_38(glval) = VariableAddress[#return] : -# 202| r0_39(glval) = VariableAddress[ret] : -# 202| r0_40(int) = Load : &:r0_39, m0_37 -# 202| m0_41(int) = Store : &:r0_38, r0_40 -# 198| r0_42(glval) = VariableAddress[#return] : -# 198| v0_43(void) = ReturnValue : &:r0_42, m0_41 -# 198| v0_44(void) = UnmodeledUse : mu* -# 198| v0_45(void) = ExitFunction : +# 200| r0_30(glval) = CopyValue : r0_26 +# 201| r0_31(glval) = FunctionAddress[abs] : +# 201| r0_32(glval) = VariableAddress[x] : +# 201| r0_33(int) = Load : &:r0_32, m0_8 +# 201| r0_34(int) = Call : func:r0_31, 0:r0_33 +# 201| r0_35(glval) = VariableAddress[ret] : +# 201| r0_36(int) = Load : &:r0_35, m0_29 +# 201| r0_37(int) = Add : r0_36, r0_34 +# 201| m0_38(int) = Store : &:r0_35, r0_37 +# 201| r0_39(glval) = CopyValue : r0_35 +# 202| r0_40(glval) = VariableAddress[#return] : +# 202| r0_41(glval) = VariableAddress[ret] : +# 202| r0_42(int) = Load : &:r0_41, m0_38 +# 202| m0_43(int) = Store : &:r0_40, r0_42 +# 198| r0_44(glval) = VariableAddress[#return] : +# 198| v0_45(void) = ReturnValue : &:r0_44, m0_43 +# 198| v0_46(void) = UnmodeledUse : mu* +# 198| v0_47(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index ce0d9323340..57330c88ce9 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -214,7 +214,9 @@ ssa.cpp: # 70| r1_3(int) = Constant[1] : # 70| r1_4(char *) = PointerAdd[1] : r1_2, r1_3 # 70| m1_5(char *) = Store : &:r1_1, r1_4 -# 70| mu1_6(char) = Store : &:r1_2, r1_0 +# 70| r1_6(glval) = CopyValue : r1_2 +# 70| mu1_7(char) = Store : &:r1_6, r1_0 +# 70| r1_8(glval) = CopyValue : r1_6 #-----| Goto (back edge) -> Block 3 # 71| Block 2 @@ -263,20 +265,23 @@ ssa.cpp: # 80| r1_0(int) = Constant[3] : # 80| r1_1(glval) = VariableAddress[x] : # 80| m1_2(int) = Store : &:r1_1, r1_0 -# 81| r1_3(int) = Constant[4] : -# 81| r1_4(glval) = VariableAddress[y] : -# 81| m1_5(int) = Store : &:r1_4, r1_3 +# 80| r1_3(glval) = CopyValue : r1_1 +# 81| r1_4(int) = Constant[4] : +# 81| r1_5(glval) = VariableAddress[y] : +# 81| m1_6(int) = Store : &:r1_5, r1_4 +# 81| r1_7(glval) = CopyValue : r1_5 #-----| Goto -> Block 3 # 84| Block 2 # 84| r2_0(int) = Constant[5] : # 84| r2_1(glval) = VariableAddress[x] : # 84| m2_2(int) = Store : &:r2_1, r2_0 +# 84| r2_3(glval) = CopyValue : r2_1 #-----| Goto -> Block 3 # 86| Block 3 # 86| m3_0(int) = Phi : from 1:m1_2, from 2:m2_2 -# 86| m3_1(int) = Phi : from 1:m1_5, from 2:m0_10 +# 86| m3_1(int) = Phi : from 1:m1_6, from 2:m0_10 # 86| r3_2(glval) = VariableAddress[x_merge] : # 86| r3_3(glval) = VariableAddress[x] : # 86| r3_4(int) = Load : &:r3_3, m3_0 @@ -323,13 +328,14 @@ ssa.cpp: # 96| m0_8(Point) = Store : &:r0_5, r0_7 # 97| r0_9(glval) = FunctionAddress[Escape] : # 97| r0_10(glval) = VariableAddress[a] : -# 97| r0_11(void *) = Convert : r0_10 -# 97| v0_12(void) = Call : func:r0_9, 0:r0_11 -# 97| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -# 98| v0_14(void) = NoOp : -# 95| v0_15(void) = ReturnVoid : -# 95| v0_16(void) = UnmodeledUse : mu* -# 95| v0_17(void) = ExitFunction : +# 97| r0_11(Point *) = CopyValue : r0_10 +# 97| r0_12(void *) = Convert : r0_11 +# 97| v0_13(void) = Call : func:r0_9, 0:r0_12 +# 97| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 +# 98| v0_15(void) = NoOp : +# 95| v0_16(void) = ReturnVoid : +# 95| v0_17(void) = UnmodeledUse : mu* +# 95| v0_18(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -372,13 +378,14 @@ ssa.cpp: # 107| m0_14(int) = Store : &:r0_10, r0_13 # 108| r0_15(glval) = FunctionAddress[Escape] : # 108| r0_16(glval) = VariableAddress[a] : -# 108| r0_17(void *) = Convert : r0_16 -# 108| v0_18(void) = Call : func:r0_15, 0:r0_17 -# 108| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 -# 109| v0_20(void) = NoOp : -# 105| v0_21(void) = ReturnVoid : -# 105| v0_22(void) = UnmodeledUse : mu* -# 105| v0_23(void) = ExitFunction : +# 108| r0_17(Point *) = CopyValue : r0_16 +# 108| r0_18(void *) = Convert : r0_17 +# 108| v0_19(void) = Call : func:r0_15, 0:r0_18 +# 108| mu0_20(unknown) = ^CallSideEffect : ~mu0_2 +# 109| v0_21(void) = NoOp : +# 105| v0_22(void) = ReturnVoid : +# 105| v0_23(void) = UnmodeledUse : mu* +# 105| v0_24(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -433,13 +440,14 @@ ssa.cpp: # 118| m0_20(Point) = Store : &:r0_17, r0_19 # 119| r0_21(glval) = FunctionAddress[Escape] : # 119| r0_22(glval) = VariableAddress[a] : -# 119| r0_23(void *) = Convert : r0_22 -# 119| v0_24(void) = Call : func:r0_21, 0:r0_23 -# 119| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 120| v0_26(void) = NoOp : -# 116| v0_27(void) = ReturnVoid : -# 116| v0_28(void) = UnmodeledUse : mu* -# 116| v0_29(void) = ExitFunction : +# 119| r0_23(Point *) = CopyValue : r0_22 +# 119| r0_24(void *) = Convert : r0_23 +# 119| v0_25(void) = Call : func:r0_21, 0:r0_24 +# 119| mu0_26(unknown) = ^CallSideEffect : ~mu0_2 +# 120| v0_27(void) = NoOp : +# 116| v0_28(void) = ReturnVoid : +# 116| v0_29(void) = UnmodeledUse : mu* +# 116| v0_30(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -472,6 +480,7 @@ ssa.cpp: # 125| r1_2(glval) = VariableAddress[a] : # 125| r1_3(glval) = FieldAddress[x] : r1_2 # 125| mu1_4(int) = Store : &:r1_3, r1_1 +# 125| r1_5(glval) = CopyValue : r1_3 #-----| Goto -> Block 3 # 128| Block 2 @@ -480,6 +489,7 @@ ssa.cpp: # 128| r2_2(glval) = VariableAddress[a] : # 128| r2_3(glval) = FieldAddress[x] : r2_2 # 128| mu2_4(int) = Store : &:r2_3, r2_1 +# 128| r2_5(glval) = CopyValue : r2_3 #-----| Goto -> Block 3 # 130| Block 3 @@ -528,6 +538,7 @@ ssa.cpp: # 137| r1_2(glval) = VariableAddress[a] : # 137| r1_3(glval) = FieldAddress[x] : r1_2 # 137| mu1_4(int) = Store : &:r1_3, r1_1 +# 137| r1_5(glval) = CopyValue : r1_3 #-----| Goto -> Block 3 # 140| Block 2 @@ -535,6 +546,7 @@ ssa.cpp: # 140| r2_1(Point) = Load : &:r2_0, m0_6 # 140| r2_2(glval) = VariableAddress[a] : # 140| mu2_3(Point) = Store : &:r2_2, r2_1 +# 140| r2_4(glval) = CopyValue : r2_2 #-----| Goto -> Block 3 # 142| Block 3 @@ -579,6 +591,7 @@ ssa.cpp: # 148| r1_2(glval) = VariableAddress[a] : # 148| r1_3(glval) = FieldAddress[x] : r1_2 # 148| mu1_4(int) = Store : &:r1_3, r1_1 +# 148| r1_5(glval) = CopyValue : r1_3 #-----| Goto -> Block 3 # 151| Block 2 @@ -586,6 +599,7 @@ ssa.cpp: # 151| r2_1(Point) = Load : &:r2_0, m0_6 # 151| r2_2(glval) = VariableAddress[a] : # 151| mu2_3(Point) = Store : &:r2_2, r2_1 +# 151| r2_4(glval) = CopyValue : r2_2 #-----| Goto -> Block 3 # 153| Block 3 @@ -630,6 +644,7 @@ ssa.cpp: # 159| r1_3(glval) = FieldAddress[topLeft] : r1_2 # 159| r1_4(glval) = FieldAddress[x] : r1_3 # 159| mu1_5(int) = Store : &:r1_4, r1_1 +# 159| r1_6(glval) = CopyValue : r1_4 #-----| Goto -> Block 3 # 162| Block 2 @@ -637,6 +652,7 @@ ssa.cpp: # 162| r2_1(Rect) = Load : &:r2_0, m0_6 # 162| r2_2(glval) = VariableAddress[a] : # 162| mu2_3(Rect) = Store : &:r2_2, r2_1 +# 162| r2_4(glval) = CopyValue : r2_2 #-----| Goto -> Block 3 # 164| Block 3 @@ -670,19 +686,22 @@ ssa.cpp: # 174| r0_15(glval) = VariableAddress[w] : # 174| r0_16(glval) = FieldAddress[f] : r0_15 # 174| mu0_17(int) = Store : &:r0_16, r0_14 -# 175| r0_18(glval) = VariableAddress[w] : -# 175| r0_19(glval) = FieldAddress[f] : r0_18 -# 175| r0_20(int) = Load : &:r0_19, ~mu0_2 -# 175| r0_21(glval) = VariableAddress[a] : -# 175| m0_22(int) = Store : &:r0_21, r0_20 -# 176| r0_23(glval) = VariableAddress[w] : -# 176| r0_24(Wrapper) = Load : &:r0_23, ~mu0_2 -# 176| r0_25(glval) = VariableAddress[x] : -# 176| m0_26(Wrapper) = Store : &:r0_25, r0_24 -# 177| v0_27(void) = NoOp : -# 171| v0_28(void) = ReturnVoid : -# 171| v0_29(void) = UnmodeledUse : mu* -# 171| v0_30(void) = ExitFunction : +# 174| r0_18(glval) = CopyValue : r0_16 +# 175| r0_19(glval) = VariableAddress[w] : +# 175| r0_20(glval) = FieldAddress[f] : r0_19 +# 175| r0_21(int) = Load : &:r0_20, ~mu0_2 +# 175| r0_22(glval) = VariableAddress[a] : +# 175| m0_23(int) = Store : &:r0_22, r0_21 +# 175| r0_24(glval) = CopyValue : r0_22 +# 176| r0_25(glval) = VariableAddress[w] : +# 176| r0_26(Wrapper) = Load : &:r0_25, ~mu0_2 +# 176| r0_27(glval) = VariableAddress[x] : +# 176| m0_28(Wrapper) = Store : &:r0_27, r0_26 +# 176| r0_29(glval) = CopyValue : r0_27 +# 177| v0_30(void) = NoOp : +# 171| v0_31(void) = ReturnVoid : +# 171| v0_32(void) = UnmodeledUse : mu* +# 171| v0_33(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 @@ -757,19 +776,21 @@ ssa.cpp: # 200| r0_27(int) = Load : &:r0_26, m0_19 # 200| r0_28(int) = Add : r0_27, r0_24 # 200| m0_29(int) = Store : &:r0_26, r0_28 -# 201| r0_30(glval) = FunctionAddress[abs] : -# 201| r0_31(glval) = VariableAddress[x] : -# 201| r0_32(int) = Load : &:r0_31, m0_8 -# 201| r0_33(int) = Call : func:r0_30, 0:r0_32 -# 201| r0_34(glval) = VariableAddress[ret] : -# 201| r0_35(int) = Load : &:r0_34, m0_29 -# 201| r0_36(int) = Add : r0_35, r0_33 -# 201| m0_37(int) = Store : &:r0_34, r0_36 -# 202| r0_38(glval) = VariableAddress[#return] : -# 202| r0_39(glval) = VariableAddress[ret] : -# 202| r0_40(int) = Load : &:r0_39, m0_37 -# 202| m0_41(int) = Store : &:r0_38, r0_40 -# 198| r0_42(glval) = VariableAddress[#return] : -# 198| v0_43(void) = ReturnValue : &:r0_42, m0_41 -# 198| v0_44(void) = UnmodeledUse : mu* -# 198| v0_45(void) = ExitFunction : +# 200| r0_30(glval) = CopyValue : r0_26 +# 201| r0_31(glval) = FunctionAddress[abs] : +# 201| r0_32(glval) = VariableAddress[x] : +# 201| r0_33(int) = Load : &:r0_32, m0_8 +# 201| r0_34(int) = Call : func:r0_31, 0:r0_33 +# 201| r0_35(glval) = VariableAddress[ret] : +# 201| r0_36(int) = Load : &:r0_35, m0_29 +# 201| r0_37(int) = Add : r0_36, r0_34 +# 201| m0_38(int) = Store : &:r0_35, r0_37 +# 201| r0_39(glval) = CopyValue : r0_35 +# 202| r0_40(glval) = VariableAddress[#return] : +# 202| r0_41(glval) = VariableAddress[ret] : +# 202| r0_42(int) = Load : &:r0_41, m0_38 +# 202| m0_43(int) = Store : &:r0_40, r0_42 +# 198| r0_44(glval) = VariableAddress[#return] : +# 198| v0_45(void) = ReturnValue : &:r0_44, m0_43 +# 198| v0_46(void) = UnmodeledUse : mu* +# 198| v0_47(void) = ExitFunction : From 3c95205f2e67287aa7f577ce1050cbcab554910b Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Mon, 23 Sep 2019 14:37:31 +0100 Subject: [PATCH 0203/1227] Minor fixes for array related translation More accurate type sizes using language specific predicates from `IRCSharpLanguage.qll`. Added immediate operands for some `PointerX` (add, sub) instructions. Some other minor consistency fixes. --- .../raw/internal/TranslatedElement.qll | 5 +- .../raw/internal/TranslatedExpr.qll | 59 ++++++++++-------- .../raw/internal/TranslatedInitialization.qll | 5 ++ .../test/library-tests/ir/ir/raw_ir.expected | 62 +++++++++---------- 4 files changed, 71 insertions(+), 60 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll index 874b90ead77..2dae729e883 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll @@ -194,8 +194,9 @@ predicate needsLoad(Expr expr) { * Holds if we should ignore the `Load` instruction for `expr` when generating IR. */ private predicate ignoreLoad(Expr expr) { - // No load needed for the qualifier - // in an array access + // No load needed for the qualifier of an array access, + // since we use the instruction `ElementsAddress` + // to get the address of the first element in an array expr = any(ArrayAccess aa).getQualifier() or // No load is needed for the lvalue in an assignment such as: diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 7be38a6598b..2b806299802 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -414,7 +414,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { this.getOpcode() instanceof Opcode::PointerAdd or this.getOpcode() instanceof Opcode::PointerSub ) and - result = 4 //max(getResultType().(PointerType).getSize()) + result = Language::getTypeSize(this.getResultType().(PointerType).getReferentType()) } final TranslatedExpr getOperand() { result = getTranslatedExpr(expr.getOperand()) } @@ -578,7 +578,6 @@ class TranslatedArrayAccess extends TranslatedNonConstantExpr { ( // The successor of a `PointerAdd` is an `ElementsAddress` if // that `PointerAdd` is not the last `PointerAdd` instruction. - index < getRank() - 1 and tag = PointerAddTag(index) and result = this.getInstruction(ElementsAddressTag(index + 1)) or @@ -607,10 +606,7 @@ class TranslatedArrayAccess extends TranslatedNonConstantExpr { result = this.getInstruction(PointerAddTag(child.getAST().getIndex())) } - override Instruction getResult() { - result = this.getInstruction(PointerAddTag(getRank() - 1)) //and - //result.getResultType() = expr.getType() - } + override Instruction getResult() { result = this.getInstruction(PointerAddTag(getRank() - 1)) } override predicate hasInstruction( Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue @@ -663,12 +659,14 @@ class TranslatedArrayAccess extends TranslatedNonConstantExpr { } override int getInstructionElementSize(InstructionTag tag) { - tag = PointerAddTag(_) and - // TODO: Fix sizes once we have type sizes - result = 4 + exists(int index | + inBounds(index) and + tag = PointerAddTag(index) and + result = Language::getTypeSize(expr.getQualifier().getType().(ArrayType).getElementType()) + ) } - private TranslatedExpr getBaseOperand() { result = getTranslatedExpr(expr.getChild(-1)) } + private TranslatedExpr getBaseOperand() { result = getTranslatedExpr(expr.getQualifier()) } private TranslatedExpr getOffsetOperand(int index) { this.inBounds(index) and @@ -1248,16 +1246,14 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr { opcode instanceof Opcode::PointerSub or opcode instanceof Opcode::PointerDiff ) and - result = 8 //max(getPointerOperand().getResultType().(PointerType).getReferentType().getSize()) TODO: SIZE AGAIN + result = Language::getTypeSize(this.getPointerOperand().getResultType()) ) } - // private TranslatedExpr getPointerOperand() { - // if swapOperandsOnOp() then - // result = this.getRightOperand() - // else - // result = this.getLeftOperand() - // } + private TranslatedExpr getPointerOperand() { + if swapOperandsOnOp() then result = this.getRightOperand() else result = this.getLeftOperand() + } + private predicate swapOperandsOnOp() { // Swap the operands on a pointer add 'i + p', so that the pointer operand // always comes first. Note that we still evaluate the operands @@ -1444,9 +1440,19 @@ class TranslatedAssignOperation extends TranslatedAssignment { } private Opcode getOpcode() { - expr instanceof AssignAddExpr and result instanceof Opcode::Add + expr instanceof AssignAddExpr and + ( + if expr.getRValue().getType() instanceof PointerType + then result instanceof Opcode::PointerAdd + else result instanceof Opcode::Add + ) or - expr instanceof AssignSubExpr and result instanceof Opcode::Sub + expr instanceof AssignSubExpr and + ( + if expr.getRValue().getType() instanceof PointerType + then result instanceof Opcode::PointerSub + else result instanceof Opcode::Sub + ) or expr instanceof AssignMulExpr and result instanceof Opcode::Mul or @@ -1462,10 +1468,7 @@ class TranslatedAssignOperation extends TranslatedAssignment { or expr instanceof AssignLShiftExpr and result instanceof Opcode::ShiftLeft or - expr instanceof AssignRShiftExpr and result instanceof Opcode::ShiftRight // or - // TODO: THE CASES ABOVE DEAL WITH POINTERS - // expr instanceof AssignPointerAddExpr and result instanceof Opcode::PointerAdd or - // expr instanceof AssignPointerSubExpr and result instanceof Opcode::PointerSub + expr instanceof AssignRShiftExpr and result instanceof Opcode::ShiftRight } override predicate hasInstruction( @@ -1500,11 +1503,13 @@ class TranslatedAssignOperation extends TranslatedAssignment { override int getInstructionElementSize(InstructionTag tag) { tag = AssignOperationOpTag() and exists(Opcode opcode | - opcode = getOpcode() and - // TODO: ADD AND SUB FOR POITNER ARITH (WAS POINTERADD AND POINTERSUB) - (opcode instanceof Opcode::Add or opcode instanceof Opcode::Sub) + opcode = this.getOpcode() and + ( + opcode instanceof Opcode::PointerAdd or + opcode instanceof Opcode::PointerSub + ) ) and - result = 8 //max(getResultType().(PointerType).getReferentType().getSize()) TODO: DEAL WITH SIZE + result = Language::getTypeSize(getResultType().(PointerType).getReferentType()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll index 89be95151e6..d0d98a4918a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -249,6 +249,11 @@ abstract class TranslatedElementInitialization extends TranslatedElement { ) } + override int getInstructionElementSize(InstructionTag tag) { + tag = getElementAddressTag() and + result = Language::getTypeSize(getElementType()) + } + override string getInstructionConstantValue(InstructionTag tag) { tag = getElementIndexTag() and result = getElementIndex().toString() diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index 4df18a24f6f..d22186feae5 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -8,15 +8,15 @@ array.cs: # 4| r0_4(glval) = VariableAddress[one_dim] : # 4| mu0_5(Int32[]) = Uninitialized[one_dim] : &:r0_4 # 4| r0_6(Int32) = Constant[0] : -# 4| r0_7(glval) = PointerAdd : r0_4, r0_6 +# 4| r0_7(glval) = PointerAdd[4] : r0_4, r0_6 # 4| r0_8(Int32) = Constant[100] : # 4| mu0_9(Int32) = Store : &:r0_7, r0_8 # 4| r0_10(Int32) = Constant[1] : -# 4| r0_11(glval) = PointerAdd : r0_4, r0_10 +# 4| r0_11(glval) = PointerAdd[4] : r0_4, r0_10 # 4| r0_12(Int32) = Constant[101] : # 4| mu0_13(Int32) = Store : &:r0_11, r0_12 # 4| r0_14(Int32) = Constant[2] : -# 4| r0_15(glval) = PointerAdd : r0_4, r0_14 +# 4| r0_15(glval) = PointerAdd[4] : r0_4, r0_14 # 4| r0_16(Int32) = Constant[102] : # 4| mu0_17(Int32) = Store : &:r0_15, r0_16 # 5| r0_18(Int32) = Constant[1000] : @@ -64,23 +64,23 @@ array.cs: # 15| r0_4(glval) = VariableAddress[a] : # 15| mu0_5(Int32[,]) = Uninitialized[a] : &:r0_4 # 15| r0_6(Int32) = Constant[0] : -# 15| r0_7(glval) = PointerAdd : r0_4, r0_6 +# 15| r0_7(glval) = PointerAdd[8] : r0_4, r0_6 # 15| r0_8(Int32) = Constant[0] : -# 15| r0_9(glval) = PointerAdd : r0_7, r0_8 +# 15| r0_9(glval) = PointerAdd[4] : r0_7, r0_8 # 15| r0_10(Int32) = Constant[100] : # 15| mu0_11(Int32) = Store : &:r0_9, r0_10 # 15| r0_12(Int32) = Constant[1] : -# 15| r0_13(glval) = PointerAdd : r0_7, r0_12 +# 15| r0_13(glval) = PointerAdd[4] : r0_7, r0_12 # 15| r0_14(Int32) = Constant[101] : # 15| mu0_15(Int32) = Store : &:r0_13, r0_14 # 15| r0_16(Int32) = Constant[1] : -# 15| r0_17(glval) = PointerAdd : r0_4, r0_16 +# 15| r0_17(glval) = PointerAdd[8] : r0_4, r0_16 # 15| r0_18(Int32) = Constant[0] : -# 15| r0_19(glval) = PointerAdd : r0_17, r0_18 +# 15| r0_19(glval) = PointerAdd[4] : r0_17, r0_18 # 15| r0_20(Int32) = Constant[102] : # 15| mu0_21(Int32) = Store : &:r0_19, r0_20 # 15| r0_22(Int32) = Constant[1] : -# 15| r0_23(glval) = PointerAdd : r0_17, r0_22 +# 15| r0_23(glval) = PointerAdd[4] : r0_17, r0_22 # 15| r0_24(Int32) = Constant[103] : # 15| mu0_25(Int32) = Store : &:r0_23, r0_24 # 16| r0_26(glval) = VariableAddress[b] : @@ -88,45 +88,45 @@ array.cs: # 17| r0_28(glval) = VariableAddress[c] : # 17| mu0_29(Int32[,]) = Uninitialized[c] : &:r0_28 # 17| r0_30(Int32) = Constant[0] : -# 17| r0_31(glval) = PointerAdd : r0_28, r0_30 +# 17| r0_31(glval) = PointerAdd[8] : r0_28, r0_30 # 17| r0_32(Int32) = Constant[0] : -# 17| r0_33(glval) = PointerAdd : r0_31, r0_32 +# 17| r0_33(glval) = PointerAdd[4] : r0_31, r0_32 # 17| r0_34(Int32) = Constant[100] : # 17| mu0_35(Int32) = Store : &:r0_33, r0_34 # 17| r0_36(Int32) = Constant[1] : -# 17| r0_37(glval) = PointerAdd : r0_31, r0_36 +# 17| r0_37(glval) = PointerAdd[4] : r0_31, r0_36 # 17| r0_38(Int32) = Constant[101] : # 17| mu0_39(Int32) = Store : &:r0_37, r0_38 # 17| r0_40(Int32) = Constant[1] : -# 17| r0_41(glval) = PointerAdd : r0_28, r0_40 +# 17| r0_41(glval) = PointerAdd[8] : r0_28, r0_40 # 17| r0_42(Int32) = Constant[0] : -# 17| r0_43(glval) = PointerAdd : r0_41, r0_42 +# 17| r0_43(glval) = PointerAdd[4] : r0_41, r0_42 # 17| r0_44(Int32) = Constant[102] : # 17| mu0_45(Int32) = Store : &:r0_43, r0_44 # 17| r0_46(Int32) = Constant[1] : -# 17| r0_47(glval) = PointerAdd : r0_41, r0_46 +# 17| r0_47(glval) = PointerAdd[4] : r0_41, r0_46 # 17| r0_48(Int32) = Constant[103] : # 17| mu0_49(Int32) = Store : &:r0_47, r0_48 # 18| r0_50(glval) = VariableAddress[d] : # 18| mu0_51(Int32[,]) = Uninitialized[d] : &:r0_50 # 18| r0_52(Int32) = Constant[0] : -# 18| r0_53(glval) = PointerAdd : r0_50, r0_52 +# 18| r0_53(glval) = PointerAdd[8] : r0_50, r0_52 # 18| r0_54(Int32) = Constant[0] : -# 18| r0_55(glval) = PointerAdd : r0_53, r0_54 +# 18| r0_55(glval) = PointerAdd[4] : r0_53, r0_54 # 18| r0_56(Int32) = Constant[100] : # 18| mu0_57(Int32) = Store : &:r0_55, r0_56 # 18| r0_58(Int32) = Constant[1] : -# 18| r0_59(glval) = PointerAdd : r0_53, r0_58 +# 18| r0_59(glval) = PointerAdd[4] : r0_53, r0_58 # 18| r0_60(Int32) = Constant[101] : # 18| mu0_61(Int32) = Store : &:r0_59, r0_60 # 18| r0_62(Int32) = Constant[1] : -# 18| r0_63(glval) = PointerAdd : r0_50, r0_62 +# 18| r0_63(glval) = PointerAdd[8] : r0_50, r0_62 # 18| r0_64(Int32) = Constant[0] : -# 18| r0_65(glval) = PointerAdd : r0_63, r0_64 +# 18| r0_65(glval) = PointerAdd[4] : r0_63, r0_64 # 18| r0_66(Int32) = Constant[102] : # 18| mu0_67(Int32) = Store : &:r0_65, r0_66 # 18| r0_68(Int32) = Constant[1] : -# 18| r0_69(glval) = PointerAdd : r0_63, r0_68 +# 18| r0_69(glval) = PointerAdd[4] : r0_63, r0_68 # 18| r0_70(Int32) = Constant[103] : # 18| mu0_71(Int32) = Store : &:r0_69, r0_70 # 19| r0_72(glval) = VariableAddress[e] : @@ -489,31 +489,31 @@ foreach.cs: # 5| r0_3(glval) = VariableAddress[a_array] : # 5| mu0_4(Int32[]) = Uninitialized[a_array] : &:r0_3 # 5| r0_5(Int32) = Constant[0] : -# 5| r0_6(glval) = PointerAdd : r0_3, r0_5 +# 5| r0_6(glval) = PointerAdd[4] : r0_3, r0_5 # 5| r0_7(Int32) = Constant[1] : # 5| mu0_8(Int32) = Store : &:r0_6, r0_7 # 5| r0_9(Int32) = Constant[1] : -# 5| r0_10(glval) = PointerAdd : r0_3, r0_9 +# 5| r0_10(glval) = PointerAdd[4] : r0_3, r0_9 # 5| r0_11(Int32) = Constant[2] : # 5| mu0_12(Int32) = Store : &:r0_10, r0_11 # 5| r0_13(Int32) = Constant[2] : -# 5| r0_14(glval) = PointerAdd : r0_3, r0_13 +# 5| r0_14(glval) = PointerAdd[4] : r0_3, r0_13 # 5| r0_15(Int32) = Constant[3] : # 5| mu0_16(Int32) = Store : &:r0_14, r0_15 # 5| r0_17(Int32) = Constant[3] : -# 5| r0_18(glval) = PointerAdd : r0_3, r0_17 +# 5| r0_18(glval) = PointerAdd[4] : r0_3, r0_17 # 5| r0_19(Int32) = Constant[4] : # 5| mu0_20(Int32) = Store : &:r0_18, r0_19 # 5| r0_21(Int32) = Constant[4] : -# 5| r0_22(glval) = PointerAdd : r0_3, r0_21 +# 5| r0_22(glval) = PointerAdd[4] : r0_3, r0_21 # 5| r0_23(Int32) = Constant[5] : # 5| mu0_24(Int32) = Store : &:r0_22, r0_23 # 5| r0_25(Int32) = Constant[5] : -# 5| r0_26(glval) = PointerAdd : r0_3, r0_25 +# 5| r0_26(glval) = PointerAdd[4] : r0_3, r0_25 # 5| r0_27(Int32) = Constant[6] : # 5| mu0_28(Int32) = Store : &:r0_26, r0_27 # 5| r0_29(Int32) = Constant[6] : -# 5| r0_30(glval) = PointerAdd : r0_3, r0_29 +# 5| r0_30(glval) = PointerAdd[4] : r0_3, r0_29 # 5| r0_31(Int32) = Constant[7] : # 5| mu0_32(Int32) = Store : &:r0_30, r0_31 # 7| r0_33(glval) = VariableAddress[#temp7:9] : @@ -1265,15 +1265,15 @@ pointers.cs: # 39| r0_43(glval) = VariableAddress[arr] : # 39| mu0_44(Int32[]) = Uninitialized[arr] : &:r0_43 # 39| r0_45(Int32) = Constant[0] : -# 39| r0_46(glval) = PointerAdd : r0_43, r0_45 +# 39| r0_46(glval) = PointerAdd[4] : r0_43, r0_45 # 39| r0_47(Int32) = Constant[1] : # 39| mu0_48(Int32) = Store : &:r0_46, r0_47 # 39| r0_49(Int32) = Constant[1] : -# 39| r0_50(glval) = PointerAdd : r0_43, r0_49 +# 39| r0_50(glval) = PointerAdd[4] : r0_43, r0_49 # 39| r0_51(Int32) = Constant[2] : # 39| mu0_52(Int32) = Store : &:r0_50, r0_51 # 39| r0_53(Int32) = Constant[2] : -# 39| r0_54(glval) = PointerAdd : r0_43, r0_53 +# 39| r0_54(glval) = PointerAdd[4] : r0_43, r0_53 # 39| r0_55(Int32) = Constant[3] : # 39| mu0_56(Int32) = Store : &:r0_54, r0_55 # 40| r0_57(glval) = FunctionAddress[addone] : From a34c0d4200667c9a9c5ee6bd769ca4e8cff7311e Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 23 Sep 2019 15:39:32 +0200 Subject: [PATCH 0204/1227] C++: Autoformat TranslatedExpr.qll --- .../code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index e9e7cf59cb0..fb6cc3f8570 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -2556,8 +2556,8 @@ predicate exprNeedsCopyIfNotLoaded(Expr expr) { expr instanceof AddressOfExpr or expr instanceof BuiltInOperationBuiltInAddressOf - // No case for ParenthesisExpr to avoid getting too many instructions or + // No case for ParenthesisExpr to avoid getting too many instructions expr instanceof ReferenceDereferenceExpr or expr instanceof ReferenceToExpr From ae503b29826ec4652835f835440c46297e7e7a6f Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Mon, 23 Sep 2019 14:42:34 +0100 Subject: [PATCH 0205/1227] Remove incorrect `Load` Removed an incorrect `Load` op generated by propery accesses. --- .../raw/internal/TranslatedElement.qll | 3 ++ .../test/library-tests/ir/ir/raw_ir.expected | 36 +++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll index 2dae729e883..a0d666f7903 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll @@ -212,6 +212,9 @@ private predicate ignoreLoad(Expr expr) { // address is the final value of the expression expr.getParent() instanceof AddressOfExpr or + // A property access does not need a load since it is a call + expr instanceof PropertyAccess + or // If expr is a variable access used as the qualifier for a field access and // its target variable is a value type variable, // ignore the load since the address of a variable that is a value type is diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index d22186feae5..5a3ade51b6b 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -1169,20 +1169,19 @@ pointers.cs: # 5| r0_8(glval) = FunctionAddress[get_Length] : # 5| r0_9(Int32) = Call : func:r0_8, this:r0_7 # 5| mu0_10(null) = ^CallSideEffect : ~mu0_2 -# 5| r0_11(Int32) = Load : &:r0_9, ~mu0_2 -# 5| mu0_12(Int32) = Store : &:r0_5, r0_11 -# 6| r0_13(glval) = VariableAddress[b] : -# 6| r0_14(glval) = VariableAddress[arr] : -# 6| r0_15(Int32[]) = Load : &:r0_14, ~mu0_2 -# 6| r0_16(Int32*) = Convert : r0_15 -# 6| mu0_17(Int32*) = Store : &:r0_13, r0_15 -# 8| r0_18(glval) = VariableAddress[p] : -# 8| r0_19(glval) = VariableAddress[b] : -# 8| r0_20(Int32*) = Load : &:r0_19, ~mu0_2 -# 8| mu0_21(Int32*) = Store : &:r0_18, r0_20 -# 9| r0_22(glval) = VariableAddress[i] : -# 9| r0_23(Int32) = Constant[0] : -# 9| mu0_24(Int32) = Store : &:r0_22, r0_23 +# 5| mu0_11(Int32) = Store : &:r0_5, r0_9 +# 6| r0_12(glval) = VariableAddress[b] : +# 6| r0_13(glval) = VariableAddress[arr] : +# 6| r0_14(Int32[]) = Load : &:r0_13, ~mu0_2 +# 6| r0_15(Int32*) = Convert : r0_14 +# 6| mu0_16(Int32*) = Store : &:r0_12, r0_14 +# 8| r0_17(glval) = VariableAddress[p] : +# 8| r0_18(glval) = VariableAddress[b] : +# 8| r0_19(Int32*) = Load : &:r0_18, ~mu0_2 +# 8| mu0_20(Int32*) = Store : &:r0_17, r0_19 +# 9| r0_21(glval) = VariableAddress[i] : +# 9| r0_22(Int32) = Constant[0] : +# 9| mu0_23(Int32) = Store : &:r0_21, r0_22 #-----| Goto -> Block 2 # 3| Block 1 @@ -1357,11 +1356,10 @@ prop.cs: # 30| r0_18(glval) = FunctionAddress[get_Prop] : # 30| r0_19(Int32) = Call : func:r0_18, this:r0_17 # 30| mu0_20(null) = ^CallSideEffect : ~mu0_2 -# 30| r0_21(Int32) = Load : &:r0_19, ~mu0_2 -# 30| mu0_22(Int32) = Store : &:r0_15, r0_21 -# 26| v0_23(Void) = ReturnVoid : -# 26| v0_24(Void) = UnmodeledUse : mu* -# 26| v0_25(Void) = ExitFunction : +# 30| mu0_21(Int32) = Store : &:r0_15, r0_19 +# 26| v0_22(Void) = ReturnVoid : +# 26| v0_23(Void) = UnmodeledUse : mu* +# 26| v0_24(Void) = ExitFunction : simple_call.cs: # 5| System.Int32 test_simple_call.f() From 7f76947af01b445656681f8757e790def7ad6cc2 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Mon, 23 Sep 2019 15:03:38 +0100 Subject: [PATCH 0206/1227] Autoformat --- .../ir/implementation/raw/internal/TranslatedElement.qll | 2 +- .../csharp/ir/implementation/raw/internal/TranslatedExpr.qll | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll index a0d666f7903..879ac4d1384 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll @@ -194,7 +194,7 @@ predicate needsLoad(Expr expr) { * Holds if we should ignore the `Load` instruction for `expr` when generating IR. */ private predicate ignoreLoad(Expr expr) { - // No load needed for the qualifier of an array access, + // No load needed for the qualifier of an array access, // since we use the instruction `ElementsAddress` // to get the address of the first element in an array expr = any(ArrayAccess aa).getQualifier() diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 2b806299802..8e83de3e027 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1447,7 +1447,7 @@ class TranslatedAssignOperation extends TranslatedAssignment { else result instanceof Opcode::Add ) or - expr instanceof AssignSubExpr and + expr instanceof AssignSubExpr and ( if expr.getRValue().getType() instanceof PointerType then result instanceof Opcode::PointerSub @@ -1505,7 +1505,7 @@ class TranslatedAssignOperation extends TranslatedAssignment { exists(Opcode opcode | opcode = this.getOpcode() and ( - opcode instanceof Opcode::PointerAdd or + opcode instanceof Opcode::PointerAdd or opcode instanceof Opcode::PointerSub ) ) and From 6b28f3371373a81cf4c00862409fd676803f7561 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Mon, 16 Sep 2019 16:22:11 +0100 Subject: [PATCH 0207/1227] C++: Update test for fix to namespace members Generation of IDs for namespace members has been fixed to generate unique IDs for variables of the same name but in different namespaces. Update the same_name test to validate this. --- .../test/library-tests/namespaces/same_name/decls.expected | 3 ++- .../test/library-tests/namespaces/same_name/same_name.cpp | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cpp/ql/test/library-tests/namespaces/same_name/decls.expected b/cpp/ql/test/library-tests/namespaces/same_name/decls.expected index 8a6d70aee19..45816564a85 100644 --- a/cpp/ql/test/library-tests/namespaces/same_name/decls.expected +++ b/cpp/ql/test/library-tests/namespaces/same_name/decls.expected @@ -7,5 +7,6 @@ | file://:0:0:0:0 | (global namespace) | file://:0:0:0:0 | p#0 | | file://:0:0:0:0 | (global namespace) | file://:0:0:0:0 | p#0 | | file://:0:0:0:0 | (global namespace) | file://:0:0:0:0 | reg_save_area | -| same_name.cpp:4:11:4:21 | namespace_a | same_name.cpp:2:11:2:11 | c | +| file://:0:0:0:0 | (global namespace) | same_name.cpp:2:11:2:11 | c | | same_name.cpp:4:11:4:21 | namespace_a | same_name.cpp:6:12:6:12 | c | +| same_name.cpp:9:11:9:21 | namespace_b | same_name.cpp:11:12:11:12 | c | diff --git a/cpp/ql/test/library-tests/namespaces/same_name/same_name.cpp b/cpp/ql/test/library-tests/namespaces/same_name/same_name.cpp index 8f45748a1d7..63fda6f06ef 100644 --- a/cpp/ql/test/library-tests/namespaces/same_name/same_name.cpp +++ b/cpp/ql/test/library-tests/namespaces/same_name/same_name.cpp @@ -8,9 +8,5 @@ namespace namespace_a namespace namespace_b { - //const int c = 1; - // - // this example is causing a DBCheck failure along the lines of: - // - // [INVALID_KEY] Relation namespacembrs((@namespace parentid, unique @namespacembr memberid)): Value 132 of key field memberid occurs in several tuples. Two such tuples are: (134,132) and (144,132) + const int c = 1; } From d4fca848989caa1cc2bc3e9cfe31c891ebf87edc Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Mon, 23 Sep 2019 16:53:08 +0100 Subject: [PATCH 0208/1227] JavaScript: Improve XSS sanitizer detection. We now use local data flow to detect more regexp-based sanitizers. --- change-notes/1.23/analysis-javascript.md | 6 ++++-- .../ql/src/semmle/javascript/security/dataflow/Xss.qll | 2 +- .../ql/test/query-tests/Security/CWE-079/sanitiser.js | 7 ++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md index aeaf9ad3924..7ba8b0e7543 100644 --- a/change-notes/1.23/analysis-javascript.md +++ b/change-notes/1.23/analysis-javascript.md @@ -22,14 +22,16 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| | Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false-positive results | This rule now recognizes additional ways delimiters can be stripped away. | -| Client-side cross-site scripting (`js/xss`) | More results | More potential vulnerabilities involving functions that manipulate DOM attributes are now recognized. | +| Client-side cross-site scripting (`js/xss`) | More results, fewer false-positive results | More potential vulnerabilities involving functions that manipulate DOM attributes are now recognized, and more sanitizers are detected. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving functions that manipulate DOM event handler attributes are now recognized. | | Hard-coded credentials (`js/hardcoded-credentials`) | Fewer false-positive results | This rule now flags fewer password examples. | | Illegal invocation (`js/illegal-invocation`) | Fewer false-positive results | This rule now correctly handles methods named `call` and `apply`. | -| Incorrect suffix check (`js/incorrect-suffix-check`) | Fewer false-positive results | The query recognizes valid checks in more cases. +| Incorrect suffix check (`js/incorrect-suffix-check`) | Fewer false-positive results | The query recognizes valid checks in more cases. | | Network data written to file (`js/http-to-file-access`) | Fewer false-positive results | This query has been renamed to better match its intended purpose, and now only considers network data untrusted. | | Password in configuration file (`js/password-in-configuration-file`) | Fewer false-positive results | This rule now flags fewer password examples. | | Prototype pollution (`js/prototype-pollution`) | More results | The query now highlights vulnerable uses of jQuery and Angular, and the results are shown on LGTM by default. | +| Reflected cross-site scripting (`js/reflected-xss`) | Fewer false-positive results | The query now recognizes more sanitizers. | +| Stored cross-site scripting (`js/stored-xss`) | Fewer false-positive results | The query now recognizes more sanitizers. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now treats responses from servers as untrusted. | ## Changes to QL libraries diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 6a2845b7068..0f76bfa4d40 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -34,7 +34,7 @@ module Shared { MetacharEscapeSanitizer() { getMethodName() = "replace" and exists(RegExpConstant c | - c.getLiteral() = getArgument(0).asExpr() and + c.getLiteral() = getArgument(0).getALocalSource().asExpr() and c.getValue().regexpMatch("['\"&<>]") ) } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/sanitiser.js b/javascript/ql/test/query-tests/Security/CWE-079/sanitiser.js index 8f33abc005a..cc2aa55033d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/sanitiser.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/sanitiser.js @@ -1,8 +1,9 @@ function escapeHtml(s) { + var amp = /&/g, lt = //g; return s.toString() - .replace(/&/g, '&') - .replace(//g, '>'); + .replace(amp, '&') + .replace(lt, '<') + .replace(gt, '>'); } function escapeAttr(s) { From 1dab4e0e2658bf3103d55a825c241aec4467a00f Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Fri, 20 Sep 2019 15:30:31 +0100 Subject: [PATCH 0209/1227] Initial commit, C++ files --- .../ir/implementation/unaliased_ssa/IR.qll | 29 + .../implementation/unaliased_ssa/IRBlock.qll | 210 +++ .../unaliased_ssa/IRFunction.qll | 81 + .../implementation/unaliased_ssa/IRSanity.ql | 8 + .../implementation/unaliased_ssa/IRSanity.qll | 2 + .../unaliased_ssa/IRVariable.qll | 145 ++ .../unaliased_ssa/Instruction.qll | 1480 +++++++++++++++++ .../implementation/unaliased_ssa/Operand.qll | 460 +++++ .../implementation/unaliased_ssa/PrintIR.ql | 8 + .../implementation/unaliased_ssa/PrintIR.qll | 260 +++ .../constant/ConstantAnalysis.qll | 54 + .../constant/PrintConstantAnalysis.qll | 11 + .../internal/ConstantAnalysisInternal.qll | 1 + .../unaliased_ssa/gvn/ValueNumbering.qll | 315 ++++ .../gvn/internal/ValueNumberingInternal.qll | 1 + .../unaliased_ssa/internal/AliasAnalysis.qll | 326 ++++ .../internal/AliasAnalysisInternal.qll | 1 + .../unaliased_ssa/internal/IRBlockImports.qll | 1 + .../unaliased_ssa/internal/IRImports.qll | 2 + .../unaliased_ssa/internal/IRInternal.qll | 2 + .../internal/IRVariableImports.qll | 4 + .../internal/InstructionImports.qll | 4 + .../unaliased_ssa/internal/OperandImports.qll | 3 + .../unaliased_ssa/internal/PrintIRImports.qll | 1 + .../unaliased_ssa/internal/PrintSSA.qll | 126 ++ .../internal/SSAConstruction.qll | 881 ++++++++++ .../internal/SSAConstructionInternal.qll | 5 + .../unaliased_ssa/internal/SimpleSSA.qll | 87 + .../internal/reachability/Dominance.qll | 22 + .../reachability/DominanceInternal.qll | 9 + .../internal/reachability/PrintDominance.qll | 21 + .../reachability/PrintReachableBlock.qll | 17 + .../internal/reachability/ReachableBlock.qll | 53 + .../reachability/ReachableBlockInternal.qll | 2 + 34 files changed, 4632 insertions(+) create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.ql create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll new file mode 100644 index 00000000000..278040f8ab8 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll @@ -0,0 +1,29 @@ +import IRFunction +import Instruction +import IRBlock +import IRVariable +import Operand +private import internal.IRImports as Imports +import Imports::EdgeKind +import Imports::MemoryAccessKind + +private newtype TIRPropertyProvider = MkIRPropertyProvider() + +/** + * Class that provides additional properties to be dumped for IR instructions and blocks when using + * the PrintIR module. Libraries that compute additional facts about IR elements can extend the + * single instance of this class to specify the additional properties computed by the library. + */ +class IRPropertyProvider extends TIRPropertyProvider { + string toString() { result = "IRPropertyProvider" } + + /** + * Gets the value of the property named `key` for the specified instruction. + */ + string getInstructionProperty(Instruction instruction, string key) { none() } + + /** + * Gets the value of the property named `key` for the specified block. + */ + string getBlockProperty(IRBlock block, string key) { none() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll new file mode 100644 index 00000000000..e0322a00e15 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -0,0 +1,210 @@ +private import internal.IRInternal +import Instruction +private import internal.IRBlockImports as Imports +import Imports::EdgeKind +private import Cached + +/** + * A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only + * incoming edges at the beginning of the sequence and the only outgoing edges at the end of the + * sequence. + * + * This class does not contain any members that query the predecessor or successor edges of the + * block. This allows different classes that extend `IRBlockBase` to expose different subsets of + * edges (e.g. ignoring unreachable edges). + * + * Most consumers should use the class `IRBlock`. + */ +class IRBlockBase extends TIRBlock { + final string toString() { result = getFirstInstruction(this).toString() } + + final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + + final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } + + /** + * Gets the zero-based index of the block within its function. This is used + * by debugging and printing code only. + */ + int getDisplayIndex() { + this = rank[result + 1](IRBlock funcBlock | + funcBlock.getEnclosingFunction() = getEnclosingFunction() + | + funcBlock order by funcBlock.getUniqueId() + ) + } + + final Instruction getInstruction(int index) { result = getInstruction(this, index) } + + final PhiInstruction getAPhiInstruction() { + Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() + } + + final Instruction getAnInstruction() { + result = getInstruction(_) or + result = getAPhiInstruction() + } + + final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + + final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + + final int getInstructionCount() { result = getInstructionCount(this) } + + final IRFunction getEnclosingIRFunction() { + result = getFirstInstruction(this).getEnclosingIRFunction() + } + + final Language::Function getEnclosingFunction() { + result = getFirstInstruction(this).getEnclosingFunction() + } +} + +/** + * A basic block with additional information about its predecessor and successor edges. Each edge + * corresponds to the control flow between the last instruction of one block and the first + * instruction of another block. + */ +class IRBlock extends IRBlockBase { + final IRBlock getASuccessor() { blockSuccessor(this, result) } + + final IRBlock getAPredecessor() { blockSuccessor(result, this) } + + final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + + final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + + final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + + final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + + final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + + pragma[noinline] + final IRBlock dominanceFrontier() { + dominates(result.getAPredecessor()) and + not strictlyDominates(result) + } + + /** + * Holds if this block is reachable from the entry point of its function + */ + final predicate isReachableFromFunctionEntry() { + this = getEnclosingIRFunction().getEntryBlock() or + getAPredecessor().isReachableFromFunctionEntry() + } +} + +private predicate startsBasicBlock(Instruction instr) { + not instr instanceof PhiInstruction and + ( + count(Instruction predecessor | instr = predecessor.getASuccessor()) != 1 // Multiple predecessors or no predecessor + or + exists(Instruction predecessor | + instr = predecessor.getASuccessor() and + strictcount(Instruction other | other = predecessor.getASuccessor()) > 1 + ) // Predecessor has multiple successors + or + exists(Instruction predecessor, EdgeKind kind | + instr = predecessor.getSuccessor(kind) and + not kind instanceof GotoEdge + ) // Incoming edge is not a GotoEdge + or + exists(Instruction predecessor | + instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _) + ) // A back edge enters this instruction + ) +} + +private predicate isEntryBlock(TIRBlock block) { + block = MkIRBlock(any(EnterFunctionInstruction enter)) +} + +cached +private module Cached { + cached + newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) } + + /** Holds if `i2` follows `i1` in a `IRBlock`. */ + private predicate adjacentInBlock(Instruction i1, Instruction i2) { + exists(GotoEdge edgeKind | i2 = i1.getSuccessor(edgeKind)) and + not startsBasicBlock(i2) + } + + /** Holds if `i` is the `index`th instruction the block starting with `first`. */ + private Instruction getInstructionFromFirst(Instruction first, int index) = + shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index) + + /** Holds if `i` is the `index`th instruction in `block`. */ + cached + Instruction getInstruction(TIRBlock block, int index) { + result = getInstructionFromFirst(getFirstInstruction(block), index) + } + + cached + int getInstructionCount(TIRBlock block) { result = strictcount(getInstruction(block, _)) } + + cached + predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) { + exists(Instruction predLast, Instruction succFirst | + predLast = getInstruction(pred, getInstructionCount(pred) - 1) and + succFirst = predLast.getSuccessor(kind) and + succ = MkIRBlock(succFirst) + ) + } + + pragma[noinline] + private predicate blockIdentity(TIRBlock b1, TIRBlock b2) { b1 = b2 } + + pragma[noopt] + cached + predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) { + backEdgeSuccessorRaw(pred, succ, kind) + or + // See the QLDoc on `backEdgeSuccessorRaw`. + exists(TIRBlock pred2 | + // Joining with `blockIdentity` is a performance trick to get + // `forwardEdgeRaw` on the RHS of a join, where it's fast. + blockIdentity(pred, pred2) and + forwardEdgeRaw+(pred, pred2) + ) and + blockSuccessor(pred, succ, kind) + } + + /** + * Holds if there is an edge from `pred` to `succ` that is not a back edge. + */ + private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) { + exists(EdgeKind kind | + blockSuccessor(pred, succ, kind) and + not backEdgeSuccessorRaw(pred, succ, kind) + ) + } + + /** + * Holds if the `kind`-edge from `pred` to `succ` is a back edge according to + * `Construction`. + * + * There could be loops of non-back-edges if there is a flaw in the IR + * construction or back-edge detection, and this could cause non-termination + * of subsequent analysis. To prevent that, a subsequent predicate further + * classifies all edges as back edges if they are involved in a loop of + * non-back-edges. + */ + private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) { + exists(Instruction predLast, Instruction succFirst | + predLast = getInstruction(pred, getInstructionCount(pred) - 1) and + succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and + succ = MkIRBlock(succFirst) + ) + } + + cached + predicate blockSuccessor(TIRBlock pred, TIRBlock succ) { blockSuccessor(pred, succ, _) } + + cached + predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) = + idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) +} + +Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll new file mode 100644 index 00000000000..1e9c2d1d913 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -0,0 +1,81 @@ +private import internal.IRInternal +import Instruction + +private newtype TIRFunction = + MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } + +/** + * Represents the IR for a function. + */ +class IRFunction extends TIRFunction { + Language::Function func; + + IRFunction() { this = MkIRFunction(func) } + + final string toString() { result = "IR: " + func.toString() } + + /** + * Gets the function whose IR is represented. + */ + final Language::Function getFunction() { result = func } + + /** + * Gets the location of the function. + */ + final Language::Location getLocation() { result = func.getLocation() } + + /** + * Gets the entry point for this function. + */ + pragma[noinline] + final EnterFunctionInstruction getEnterFunctionInstruction() { + result.getEnclosingIRFunction() = this + } + + /** + * Gets the exit point for this function. + */ + pragma[noinline] + final ExitFunctionInstruction getExitFunctionInstruction() { + result.getEnclosingIRFunction() = this + } + + pragma[noinline] + final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { + result.getEnclosingIRFunction() = this + } + + pragma[noinline] + final UnmodeledUseInstruction getUnmodeledUseInstruction() { + result.getEnclosingIRFunction() = this + } + + /** + * Gets the single return instruction for this function. + */ + pragma[noinline] + final ReturnInstruction getReturnInstruction() { result.getEnclosingIRFunction() = this } + + /** + * Gets the variable used to hold the return value of this function. If this + * function does not return a value, this predicate does not hold. + */ + pragma[noinline] + final IRReturnVariable getReturnVariable() { result.getEnclosingIRFunction() = this } + + /** + * Gets the block containing the entry point of this function. + */ + pragma[noinline] + final IRBlock getEntryBlock() { result.getFirstInstruction() = getEnterFunctionInstruction() } + + /** + * Gets all instructions in this function. + */ + final Instruction getAnInstruction() { result.getEnclosingIRFunction() = this } + + /** + * Gets all blocks in this function. + */ + final IRBlock getABlock() { result.getEnclosingIRFunction() = this } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql new file mode 100644 index 00000000000..eee45030caf --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql @@ -0,0 +1,8 @@ +/** + * @name SSA IR Sanity Check + * @description Performs sanity checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/ssa-ir-sanity-check + */ + +import IRSanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll new file mode 100644 index 00000000000..3921472dc8e --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll @@ -0,0 +1,2 @@ +private import IR +import InstructionSanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll new file mode 100644 index 00000000000..a7ca4593ac4 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -0,0 +1,145 @@ +private import internal.IRInternal +import IRFunction +private import internal.IRVariableImports as Imports +import Imports::TempVariableTag +private import Imports::IRUtilities +private import Imports::TTempVariableTag +private import Imports::TIRVariable + +IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { + result.getVariable() = var and + result.getEnclosingFunction() = func +} + +/** + * Represents a variable referenced by the IR for a function. The variable may + * be a user-declared variable (`IRUserVariable`) or a temporary variable + * generated by the AST-to-IR translation (`IRTempVariable`). + */ +abstract class IRVariable extends TIRVariable { + Language::Function func; + + abstract string toString(); + + /** + * Gets the type of the variable. + */ + abstract Language::Type getType(); + + /** + * Gets the AST node that declared this variable, or that introduced this + * variable as part of the AST-to-IR translation. + */ + abstract Language::AST getAST(); + + /** + * Gets an identifier string for the variable. This identifier is unique + * within the function. + */ + abstract string getUniqueId(); + + /** + * Gets the source location of this variable. + */ + final Language::Location getLocation() { result = getAST().getLocation() } + + /** + * Gets the IR for the function that references this variable. + */ + final IRFunction getEnclosingIRFunction() { result.getFunction() = func } + + /** + * Gets the function that references this variable. + */ + final Language::Function getEnclosingFunction() { result = func } +} + +/** + * Represents a user-declared variable referenced by the IR for a function. + */ +class IRUserVariable extends IRVariable, TIRUserVariable { + Language::Variable var; + Language::Type type; + + IRUserVariable() { this = TIRUserVariable(var, type, func) } + + final override string toString() { result = getVariable().toString() } + + final override Language::AST getAST() { result = var } + + final override string getUniqueId() { + result = getVariable().toString() + " " + getVariable().getLocation().toString() + } + + final override Language::Type getType() { result = type } + + /** + * Gets the original user-declared variable. + */ + Language::Variable getVariable() { result = var } +} + +/** + * Represents a variable (user-declared or temporary) that is allocated on the + * stack. This includes all parameters, non-static local variables, and + * temporary variables. + */ +abstract class IRAutomaticVariable extends IRVariable { } + +class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable { + override Language::AutomaticVariable var; + + IRAutomaticUserVariable() { Language::isVariableAutomatic(var) } + + final override Language::AutomaticVariable getVariable() { result = var } +} + +class IRStaticUserVariable extends IRUserVariable { + override Language::StaticVariable var; + + IRStaticUserVariable() { not Language::isVariableAutomatic(var) } + + final override Language::StaticVariable getVariable() { result = var } +} + +IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { + result.getAST() = ast and + result.getTag() = tag +} + +class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { + Language::AST ast; + TempVariableTag tag; + Language::Type type; + + IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } + + final override Language::Type getType() { result = type } + + final override Language::AST getAST() { result = ast } + + final override string getUniqueId() { + result = "Temp: " + Construction::getTempVariableUniqueId(this) + } + + final TempVariableTag getTag() { result = tag } + + override string toString() { + result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" + + ast.getLocation().getStartColumn().toString() + } + + string getBaseString() { result = "#temp" } +} + +class IRReturnVariable extends IRTempVariable { + IRReturnVariable() { tag = ReturnValueTempVar() } + + final override string toString() { result = "#return" } +} + +class IRThrowVariable extends IRTempVariable { + IRThrowVariable() { tag = ThrowTempVar() } + + override string getBaseString() { result = "#throw" } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll new file mode 100644 index 00000000000..43f9663d2cd --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -0,0 +1,1480 @@ +private import internal.IRInternal +import IRFunction +import IRBlock +import IRVariable +import Operand +private import internal.InstructionImports as Imports +import Imports::EdgeKind +import Imports::MemoryAccessKind +import Imports::Opcode +private import Imports::OperandTag + +module InstructionSanity { + /** + * Holds if the instruction `instr` should be expected to have an operand + * with operand tag `tag`. Only holds for singleton operand tags. Tags with + * parameters, such as `PhiInputOperand` and `PositionalArgumentOperand` are handled + * separately in `unexpectedOperand`. + */ + private predicate expectsOperand(Instruction instr, OperandTag tag) { + exists(Opcode opcode | + opcode = instr.getOpcode() and + ( + opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag + or + opcode instanceof BinaryOpcode and + ( + tag instanceof LeftOperandTag or + tag instanceof RightOperandTag + ) + or + opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag + or + opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand + or + opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag + or + opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag + or + opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag + or + opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag + or + opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag + or + opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag + or + opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag + or + ( + opcode instanceof ReadSideEffectOpcode or + opcode instanceof MayWriteSideEffectOpcode or + opcode instanceof Opcode::InlineAsm + ) and + tag instanceof SideEffectOperandTag + ) + ) + } + + /** + * Holds if instruction `instr` is missing an expected operand with tag `tag`. + */ + query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { + exists(OperandTag tag | + expectsOperand(instr, tag) and + not exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + message = "Instruction '" + instr.getOpcode().toString() + + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } + + /** + * Holds if instruction `instr` has an unexpected operand with tag `tag`. + */ + query predicate unexpectedOperand(Instruction instr, OperandTag tag) { + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not expectsOperand(instr, tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) + } + + /** + * Holds if instruction `instr` has multiple operands with tag `tag`. + */ + query predicate duplicateOperand(Instruction instr, OperandTag tag) { + strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) > 1 and + not tag instanceof UnmodeledUseOperandTag + } + + /** + * Holds if `Phi` instruction `instr` is missing an operand corresponding to + * the predecessor block `pred`. + */ + query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) + } + + query predicate missingOperandType(Operand operand, string message) { + exists(Language::Function func | + not exists(operand.getType()) and + func = operand.getUse().getEnclosingFunction() and + message = "Operand missing type in function '" + Language::getIdentityString(func) + "'." + ) + } + + /** + * Holds if an instruction, other than `ExitFunction`, has no successors. + */ + query predicate instructionWithoutSuccessor(Instruction instr) { + not exists(instr.getASuccessor()) and + not instr instanceof ExitFunctionInstruction and + // Phi instructions aren't linked into the instruction-level flow graph. + not instr instanceof PhiInstruction and + not instr instanceof UnreachedInstruction + } + + /** + * Holds if there are multiple (`n`) edges of kind `kind` from `source`, + * where `target` is among the targets of those edges. + */ + query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + source.getSuccessor(kind) = target + } + + /** + * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * contains no element that can cause loops. + */ + query predicate unexplainedLoop(Language::Function f, Instruction instr) { + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) + } + + /** + * Holds if a `Phi` instruction is present in a block with fewer than two + * predecessors. + */ + query predicate unnecessaryPhiInstruction(PhiInstruction instr) { + count(instr.getBlock().getAPredecessor()) < 2 + } + + /** + * Holds if operand `operand` consumes a value that was defined in + * a different function. + */ + query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { + operand.getUse() = instr and + operand.getAnyDef() = defInstr and + instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() + } + + /** + * Holds if instruction `instr` is not in exactly one block. + */ + query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { + blockCount = count(instr.getBlock()) and + blockCount != 1 + } + + private predicate forwardEdge(IRBlock b1, IRBlock b2) { + b1.getASuccessor() = b2 and + not b1.getBackEdgeSuccessor(_) = b2 + } + + /** + * Holds if `f` contains a loop in which no edge is a back edge. + * + * This check ensures we don't have too _few_ back edges. + */ + query predicate containsLoopOfForwardEdges(IRFunction f) { + exists(IRBlock block | + forwardEdge+(block, block) and + block.getEnclosingIRFunction() = f + ) + } + + /** + * Holds if `block` is reachable from its function entry point but would not + * be reachable by traversing only forward edges. This check is skipped for + * functions containing `goto` statements as the property does not generally + * hold there. + * + * This check ensures we don't have too _many_ back edges. + */ + query predicate lostReachability(IRBlock block) { + exists(IRFunction f, IRBlock entry | + entry = f.getEntryBlock() and + entry.getASuccessor+() = block and + not forwardEdge+(entry, block) and + not Language::hasGoto(f.getFunction()) + ) + } + + /** + * Holds if the number of back edges differs between the `Instruction` graph + * and the `IRBlock` graph. + */ + query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { + fromInstr = count(Instruction i1, Instruction i2 | + i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = count(IRBlock b1, IRBlock b2 | + b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock + } + + /** + * Gets the point in the function at which the specified operand is evaluated. For most operands, + * this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point + * of evaluation is at the end of the corresponding predecessor block. + */ + private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) { + block = operand.(PhiInputOperand).getPredecessorBlock() and + index = block.getInstructionCount() + or + exists(Instruction use | + use = operand.(NonPhiOperand).getUse() and + block.getInstruction(index) = use + ) + } + + /** + * Holds if `useOperand` has a definition that does not dominate the use. + */ + query predicate useNotDominatedByDefinition( + Operand useOperand, string message, IRFunction func, string funcText + ) { + exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | + not useOperand.getUse() instanceof UnmodeledUseInstruction and + pointOfEvaluation(useOperand, useBlock, useIndex) and + defInstr = useOperand.getAnyDef() and + ( + defInstr instanceof PhiInstruction and + defBlock = defInstr.getBlock() and + defIndex = -1 + or + defBlock.getInstruction(defIndex) = defInstr + ) and + not ( + defBlock.strictlyDominates(useBlock) + or + defBlock = useBlock and + defIndex < useIndex + ) and + message = "Operand '" + useOperand.toString() + + "' is not dominated by its definition in function '$@'." and + func = useOperand.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } +} + +/** + * Represents a single operation in the IR. + */ +class Instruction extends Construction::TInstruction { + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } + + /** + * Gets a string showing the result, opcode, and operands of the instruction, equivalent to what + * would be printed by PrintIR.ql. For example: + * + * `mu0_28(int) = Store r0_26, r0_27` + */ + final string getDumpString() { + result = getResultString() + " = " + getOperationString() + " " + getOperandsString() + } + + /** + * Gets a string describing the operation of this instruction. This includes + * the opcode and the immediate value, if any. For example: + * + * VariableAddress[x] + */ + final string getOperationString() { + if exists(getImmediateString()) + then result = getOperationPrefix() + getOpcode().toString() + "[" + getImmediateString() + "]" + else result = getOperationPrefix() + getOpcode().toString() + } + + /** + * Gets a string describing the immediate value of this instruction, if any. + */ + string getImmediateString() { none() } + + private string getOperationPrefix() { + if this instanceof SideEffectInstruction then result = "^" else result = "" + } + + private string getResultPrefix() { + if getResultType() instanceof Language::VoidType + then result = "v" + else + if hasMemoryResult() + then if isResultModeled() then result = "m" else result = "mu" + else result = "r" + } + + /** + * Gets the zero-based index of this instruction within its block. This is + * used by debugging and printing code only. + */ + int getDisplayIndexInBlock() { + exists(IRBlock block | + block = getBlock() and + ( + exists(int index, int phiCount | + phiCount = count(block.getAPhiInstruction()) and + this = block.getInstruction(index) and + result = index + phiCount + ) + or + this instanceof PhiInstruction and + this = rank[result + 1](PhiInstruction phiInstr | + phiInstr = block.getAPhiInstruction() + | + phiInstr order by phiInstr.getUniqueId() + ) + ) + ) + } + + bindingset[type] + private string getValueCategoryString(string type) { + if isGLValue() then result = "glval<" + type + ">" else result = type + } + + string getResultTypeString() { + exists(string valcat | + valcat = getValueCategoryString(getResultType().toString()) and + if + getResultType() instanceof Language::UnknownType and + not isGLValue() and + exists(getResultSize()) + then result = valcat + "[" + getResultSize().toString() + "]" + else result = valcat + ) + } + + /** + * Gets a human-readable string that uniquely identifies this instruction + * within the function. This string is used to refer to this instruction when + * printing IR dumps. + * + * Example: `r1_1` + */ + string getResultId() { + result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" + + getDisplayIndexInBlock().toString() + } + + /** + * Gets a string describing the result of this instruction, suitable for + * display in IR dumps. This consists of the result ID plus the type of the + * result. + * + * Example: `r1_1(int*)` + */ + final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" } + + /** + * Gets a string describing the operands of this instruction, suitable for + * display in IR dumps. + * + * Example: `func:r3_4, this:r3_5` + */ + string getOperandsString() { + result = concat(Operand operand | + operand = getAnOperand() + | + operand.getDumpString(), ", " order by operand.getDumpSortOrder() + ) + } + + /** + * Gets a string identifier for this function that is unique among all + * instructions in the same function. + * + * This is used for sorting IR output for tests, and is likely to be + * inefficient for any other use. + */ + final string getUniqueId() { result = Construction::getInstructionUniqueId(this) } + + /** + * Gets the basic block that contains this instruction. + */ + final IRBlock getBlock() { result.getAnInstruction() = this } + + /** + * Gets the function that contains this instruction. + */ + final Language::Function getEnclosingFunction() { + result = getEnclosingIRFunction().getFunction() + } + + /** + * Gets the IRFunction object that contains the IR for this instruction. + */ + final IRFunction getEnclosingIRFunction() { + result = Construction::getInstructionEnclosingIRFunction(this) + } + + /** + * Gets the AST that caused this instruction to be generated. + */ + final Language::AST getAST() { result = Construction::getInstructionAST(this) } + + /** + * Gets the location of the source code for this instruction. + */ + final Language::Location getLocation() { result = getAST().getLocation() } + + /** + * Gets the `Expr` whose result is computed by this instruction, if any. + */ + final Language::Expr getConvertedResultExpression() { + result = Construction::getInstructionConvertedResultExpression(this) + } + + /** + * Gets the unconverted `Expr` whose result is computed by this instruction, if any. + */ + final Language::Expr getUnconvertedResultExpression() { + result = Construction::getInstructionUnconvertedResultExpression(this) + } + + /** + * Gets the type of the result produced by this instruction. If the + * instruction does not produce a result, its result type will be `VoidType`. + * + * If `isGLValue()` holds, then the result type of this instruction should be + * thought of as "pointer to `getResultType()`". + */ + final Language::Type getResultType() { Construction::instructionHasType(this, result, _) } + + /** + * Holds if the result produced by this instruction is a glvalue. If this + * holds, the result of the instruction represents the address of a location, + * and the type of the location is given by `getResultType()`. If this does + * not hold, the result of the instruction represents a value whose type is + * given by `getResultType()`. + * + * For example, the statement `y = x;` generates the following IR: + * r1_0(glval: int) = VariableAddress[x] + * r1_1(int) = Load r1_0, mu0_1 + * r1_2(glval: int) = VariableAddress[y] + * mu1_3(int) = Store r1_2, r1_1 + * + * The result of each `VariableAddress` instruction is a glvalue of type + * `int`, representing the address of the corresponding integer variable. The + * result of the `Load` instruction is a prvalue of type `int`, representing + * the integer value loaded from variable `x`. + */ + final predicate isGLValue() { Construction::instructionHasType(this, _, true) } + + /** + * Gets the size of the result produced by this instruction, in bytes. If the + * result does not have a known constant size, this predicate does not hold. + * + * If `this.isGLValue()` holds for this instruction, the value of + * `getResultSize()` will always be the size of a pointer. + */ + final int getResultSize() { + if isGLValue() + then + // a glvalue is always pointer-sized. + result = Language::getPointerSize() + else + if getResultType() instanceof Language::UnknownType + then result = Construction::getInstructionResultSize(this) + else result = Language::getTypeSize(getResultType()) + } + + /** + * Gets the opcode that specifies the operation performed by this instruction. + */ + final Opcode getOpcode() { result = Construction::getInstructionOpcode(this) } + + /** + * Gets all direct uses of the result of this instruction. The result can be + * an `Operand` for which `isDefinitionInexact` holds. + */ + final Operand getAUse() { result.getAnyDef() = this } + + /** + * Gets all of this instruction's operands. + */ + final Operand getAnOperand() { result.getUse() = this } + + /** + * Holds if this instruction produces a memory result. + */ + final predicate hasMemoryResult() { exists(getResultMemoryAccess()) } + + /** + * Gets the kind of memory access performed by this instruction's result. + * Holds only for instructions with a memory result. + */ + MemoryAccessKind getResultMemoryAccess() { none() } + + /** + * Gets the operand that holds the memory address to which this instruction stores its + * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` + * is `r1`. + */ + final AddressOperand getResultAddressOperand() { + getResultMemoryAccess().usesAddressOperand() and + result.getUse() = this + } + + /** + * Gets the instruction that holds the exact memory address to which this instruction stores its + * result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()` + * is the instruction that defines `r1`. + */ + final Instruction getResultAddress() { result = getResultAddressOperand().getDef() } + + /** + * Holds if the result of this instruction is precisely modeled in SSA. Always + * holds for a register result. For a memory result, a modeled result is + * connected to its actual uses. An unmodeled result is connected to the + * `UnmodeledUse` instruction. + * + * For example: + * ``` + * int x = 1; + * int *p = &x; + * int y = *p; + * ``` + * In non-aliased SSA, `x` will not be modeled because it has its address + * taken. In that case, `isResultModeled()` would not hold for the result of + * the `Store` to `x`. + */ + final predicate isResultModeled() { + // Register results are always in SSA form. + not hasMemoryResult() or + Construction::hasModeledMemoryResult(this) + } + + /** + * Gets the successor of this instruction along the control flow edge + * specified by `kind`. + */ + final Instruction getSuccessor(EdgeKind kind) { + result = Construction::getInstructionSuccessor(this, kind) + } + + /** + * Gets the a _back-edge successor_ of this instruction along the control + * flow edge specified by `kind`. A back edge in the control-flow graph is + * intuitively the edge that goes back around a loop. If all back edges are + * removed from the control-flow graph, it becomes acyclic. + */ + final Instruction getBackEdgeSuccessor(EdgeKind kind) { + // We don't take these edges from + // `Construction::getInstructionBackEdgeSuccessor` since that relation has + // not been treated to remove any loops that might be left over due to + // flaws in the IR construction or back-edge detection. + exists(IRBlock block | + block = this.getBlock() and + this = block.getLastInstruction() and + result = block.getBackEdgeSuccessor(kind).getFirstInstruction() + ) + } + + /** + * Gets all direct successors of this instruction. + */ + final Instruction getASuccessor() { result = getSuccessor(_) } + + /** + * Gets a predecessor of this instruction such that the predecessor reaches + * this instruction along the control flow edge specified by `kind`. + */ + final Instruction getPredecessor(EdgeKind kind) { result.getSuccessor(kind) = this } + + /** + * Gets all direct predecessors of this instruction. + */ + final Instruction getAPredecessor() { result = getPredecessor(_) } +} + +class VariableInstruction extends Instruction { + IRVariable var; + + VariableInstruction() { var = Construction::getInstructionVariable(this) } + + final override string getImmediateString() { result = var.toString() } + + final IRVariable getVariable() { result = var } +} + +class FieldInstruction extends Instruction { + Language::Field field; + + FieldInstruction() { field = Construction::getInstructionField(this) } + + final override string getImmediateString() { result = field.toString() } + + final Language::Field getField() { result = field } +} + +class FunctionInstruction extends Instruction { + Language::Function funcSymbol; + + FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + + final override string getImmediateString() { result = funcSymbol.toString() } + + final Language::Function getFunctionSymbol() { result = funcSymbol } +} + +class ConstantValueInstruction extends Instruction { + string value; + + ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + + final override string getImmediateString() { result = value } + + final string getValue() { result = value } +} + +class EnterFunctionInstruction extends Instruction { + EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } +} + +class VariableAddressInstruction extends VariableInstruction { + VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } +} + +class InitializeParameterInstruction extends VariableInstruction { + InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + + final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } +} + +/** + * An instruction that initializes the `this` pointer parameter of the enclosing function. + */ +class InitializeThisInstruction extends Instruction { + InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } +} + +class FieldAddressInstruction extends FieldInstruction { + FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + + final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + + final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } +} + +/** + * An instruction that produces a well-defined but unknown result and has + * unknown side effects, including side effects that are not conservatively + * modeled in the SSA graph. + * + * This type of instruction appears when there is an `ErrorExpr` in the AST, + * meaning that the extractor could not understand the expression and therefore + * produced a partial AST. Queries that give alerts when some action is _not_ + * taken may want to ignore any function that contains an `ErrorInstruction`. + */ +class ErrorInstruction extends Instruction { + ErrorInstruction() { getOpcode() instanceof Opcode::Error } +} + +class UninitializedInstruction extends VariableInstruction { + UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } + + /** + * Gets the variable that is uninitialized. + */ + final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } +} + +class NoOpInstruction extends Instruction { + NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } +} + +class ReturnInstruction extends Instruction { + ReturnInstruction() { getOpcode() instanceof ReturnOpcode } +} + +class ReturnVoidInstruction extends ReturnInstruction { + ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } +} + +class ReturnValueInstruction extends ReturnInstruction { + ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + + final LoadOperand getReturnValueOperand() { result = getAnOperand() } + + final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } +} + +class CopyInstruction extends Instruction { + CopyInstruction() { getOpcode() instanceof CopyOpcode } + + Operand getSourceValueOperand() { none() } + + final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } +} + +class CopyValueInstruction extends CopyInstruction, UnaryInstruction { + CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } + + final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } +} + +class LoadInstruction extends CopyInstruction { + LoadInstruction() { getOpcode() instanceof Opcode::Load } + + final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + + final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + + final override LoadOperand getSourceValueOperand() { result = getAnOperand() } +} + +class StoreInstruction extends CopyInstruction { + StoreInstruction() { getOpcode() instanceof Opcode::Store } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } + + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } + + final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } +} + +class ConditionalBranchInstruction extends Instruction { + ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + + final ConditionOperand getConditionOperand() { result = getAnOperand() } + + final Instruction getCondition() { result = getConditionOperand().getDef() } + + final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + + final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } +} + +class ExitFunctionInstruction extends Instruction { + ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } +} + +class ConstantInstruction extends ConstantValueInstruction { + ConstantInstruction() { getOpcode() instanceof Opcode::Constant } +} + +class IntegerConstantInstruction extends ConstantInstruction { + IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } +} + +class FloatConstantInstruction extends ConstantInstruction { + FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } +} + +class StringConstantInstruction extends Instruction { + Language::StringLiteral value; + + StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) } + + final override string getImmediateString() { result = Language::getStringLiteralText(value) } + + final Language::StringLiteral getValue() { result = value } +} + +class BinaryInstruction extends Instruction { + BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + + final LeftOperand getLeftOperand() { result = getAnOperand() } + + final RightOperand getRightOperand() { result = getAnOperand() } + + final Instruction getLeft() { result = getLeftOperand().getDef() } + + final Instruction getRight() { result = getRightOperand().getDef() } + + /** + * Holds if this instruction's operands are `op1` and `op2`, in either order. + */ + final predicate hasOperands(Operand op1, Operand op2) { + op1 = getLeftOperand() and op2 = getRightOperand() + or + op1 = getRightOperand() and op2 = getLeftOperand() + } +} + +class ArithmeticInstruction extends Instruction { + ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } +} + +class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } + +class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } + +class AddInstruction extends BinaryArithmeticInstruction { + AddInstruction() { getOpcode() instanceof Opcode::Add } +} + +class SubInstruction extends BinaryArithmeticInstruction { + SubInstruction() { getOpcode() instanceof Opcode::Sub } +} + +class MulInstruction extends BinaryArithmeticInstruction { + MulInstruction() { getOpcode() instanceof Opcode::Mul } +} + +class DivInstruction extends BinaryArithmeticInstruction { + DivInstruction() { getOpcode() instanceof Opcode::Div } +} + +class RemInstruction extends BinaryArithmeticInstruction { + RemInstruction() { getOpcode() instanceof Opcode::Rem } +} + +class NegateInstruction extends UnaryArithmeticInstruction { + NegateInstruction() { getOpcode() instanceof Opcode::Negate } +} + +class BitwiseInstruction extends Instruction { + BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } +} + +class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } + +class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } + +class BitAndInstruction extends BinaryBitwiseInstruction { + BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } +} + +class BitOrInstruction extends BinaryBitwiseInstruction { + BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } +} + +class BitXorInstruction extends BinaryBitwiseInstruction { + BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } +} + +class ShiftLeftInstruction extends BinaryBitwiseInstruction { + ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } +} + +class ShiftRightInstruction extends BinaryBitwiseInstruction { + ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } +} + +class PointerArithmeticInstruction extends BinaryInstruction { + int elementSize; + + PointerArithmeticInstruction() { + getOpcode() instanceof PointerArithmeticOpcode and + elementSize = Construction::getInstructionElementSize(this) + } + + final override string getImmediateString() { result = elementSize.toString() } + + final int getElementSize() { result = elementSize } +} + +class PointerOffsetInstruction extends PointerArithmeticInstruction { + PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } +} + +class PointerAddInstruction extends PointerOffsetInstruction { + PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } +} + +class PointerSubInstruction extends PointerOffsetInstruction { + PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } +} + +class PointerDiffInstruction extends PointerArithmeticInstruction { + PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } +} + +class UnaryInstruction extends Instruction { + UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + + final UnaryOperand getUnaryOperand() { result = getAnOperand() } + + final Instruction getUnary() { result = getUnaryOperand().getDef() } +} + +class ConvertInstruction extends UnaryInstruction { + ConvertInstruction() { getOpcode() instanceof Opcode::Convert } +} + +/** + * Represents an instruction that converts between two addresses + * related by inheritance. + */ +class InheritanceConversionInstruction extends UnaryInstruction { + Language::Class baseClass; + Language::Class derivedClass; + + InheritanceConversionInstruction() { + Construction::getInstructionInheritance(this, baseClass, derivedClass) + } + + final override string getImmediateString() { + result = derivedClass.toString() + " : " + baseClass.toString() + } + + /** + * Gets the `ClassDerivation` for the inheritance relationship between + * the base and derived classes. This predicate does not hold if the + * conversion is to an indirect virtual base class. + */ + final Language::ClassDerivation getDerivation() { + result.getBaseClass() = baseClass and result.getDerivedClass() = derivedClass + } + + /** + * Gets the base class of the conversion. This will be either a direct + * base class of the derived class, or a virtual base class of the + * derived class. + */ + final Language::Class getBaseClass() { result = baseClass } + + /** + * Gets the derived class of the conversion. + */ + final Language::Class getDerivedClass() { result = derivedClass } +} + +/** + * Represents an instruction that converts from the address of a derived class + * to the address of a direct non-virtual base class. + */ +class ConvertToBaseInstruction extends InheritanceConversionInstruction { + ConvertToBaseInstruction() { getOpcode() instanceof Opcode::ConvertToBase } +} + +/** + * Represents an instruction that converts from the address of a derived class + * to the address of a virtual base class. + */ +class ConvertToVirtualBaseInstruction extends InheritanceConversionInstruction { + ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } +} + +/** + * Represents an instruction that converts from the address of a base class + * to the address of a direct non-virtual derived class. + */ +class ConvertToDerivedInstruction extends InheritanceConversionInstruction { + ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } +} + +class BitComplementInstruction extends UnaryBitwiseInstruction { + BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } +} + +class LogicalNotInstruction extends UnaryInstruction { + LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } +} + +class CompareInstruction extends BinaryInstruction { + CompareInstruction() { getOpcode() instanceof CompareOpcode } +} + +class CompareEQInstruction extends CompareInstruction { + CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } +} + +class CompareNEInstruction extends CompareInstruction { + CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } +} + +/** + * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + */ +class RelationalInstruction extends CompareInstruction { + RelationalInstruction() { getOpcode() instanceof RelationalOpcode } + + /** + * Gets the operand on the "greater" (or "greater-or-equal") side + * of this relational instruction, that is, the side that is larger + * if the overall instruction evaluates to `true`; for example on + * `x <= 20` this is the `20`, and on `y > 0` it is `y`. + */ + Instruction getGreater() { none() } + + /** + * Gets the operand on the "lesser" (or "lesser-or-equal") side + * of this relational instruction, that is, the side that is smaller + * if the overall instruction evaluates to `true`; for example on + * `x <= 20` this is `x`, and on `y > 0` it is the `0`. + */ + Instruction getLesser() { none() } + + /** + * Holds if this relational instruction is strict (is not an "or-equal" instruction). + */ + predicate isStrict() { none() } +} + +class CompareLTInstruction extends RelationalInstruction { + CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } + + override Instruction getLesser() { result = getLeft() } + + override Instruction getGreater() { result = getRight() } + + override predicate isStrict() { any() } +} + +class CompareGTInstruction extends RelationalInstruction { + CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } + + override Instruction getLesser() { result = getRight() } + + override Instruction getGreater() { result = getLeft() } + + override predicate isStrict() { any() } +} + +class CompareLEInstruction extends RelationalInstruction { + CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } + + override Instruction getLesser() { result = getLeft() } + + override Instruction getGreater() { result = getRight() } + + override predicate isStrict() { none() } +} + +class CompareGEInstruction extends RelationalInstruction { + CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } + + override Instruction getLesser() { result = getRight() } + + override Instruction getGreater() { result = getLeft() } + + override predicate isStrict() { none() } +} + +class SwitchInstruction extends Instruction { + SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + + final ConditionOperand getExpressionOperand() { result = getAnOperand() } + + final Instruction getExpression() { result = getExpressionOperand().getDef() } + + final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + + final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } +} + +/** + * An instruction that calls a function. + */ +class CallInstruction extends Instruction { + CallInstruction() { getOpcode() instanceof Opcode::Call } + + /** + * Gets the operand the specifies the target function of the call. + */ + final CallTargetOperand getCallTargetOperand() { result = getAnOperand() } + + /** + * Gets the `Instruction` that computes the target function of the call. This is usually a + * `FunctionAddress` instruction, but can also be an arbitrary instruction that produces a + * function pointer. + */ + final Instruction getCallTarget() { result = getCallTargetOperand().getDef() } + + /** + * Gets all of the argument operands of the call, including the `this` pointer, if any. + */ + final ArgumentOperand getAnArgumentOperand() { result = getAnOperand() } + + /** + * Gets the `Function` that the call targets, if this is statically known. + */ + final Language::Function getStaticCallTarget() { + result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + } + + /** + * Gets all of the arguments of the call, including the `this` pointer, if any. + */ + final Instruction getAnArgument() { result = getAnArgumentOperand().getDef() } + + /** + * Gets the `this` pointer argument operand of the call, if any. + */ + final ThisArgumentOperand getThisArgumentOperand() { result = getAnOperand() } + + /** + * Gets the `this` pointer argument of the call, if any. + */ + final Instruction getThisArgument() { result = getThisArgumentOperand().getDef() } + + /** + * Gets the argument operand at the specified index. + */ + final PositionalArgumentOperand getPositionalArgumentOperand(int index) { + result = getAnOperand() and + result.getIndex() = index + } + + /** + * Gets the argument at the specified index. + */ + final Instruction getPositionalArgument(int index) { + result = getPositionalArgumentOperand(index).getDef() + } +} + +/** + * An instruction representing a side effect of a function call. + */ +class SideEffectInstruction extends Instruction { + SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + + final Instruction getPrimaryInstruction() { + result = Construction::getPrimaryInstructionForSideEffect(this) + } +} + +/** + * An instruction representing the side effect of a function call on any memory that might be + * accessed by that call. + */ +class CallSideEffectInstruction extends SideEffectInstruction { + CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect } + + final override MemoryAccessKind getResultMemoryAccess() { + result instanceof EscapedMayMemoryAccess + } +} + +/** + * An instruction representing the side effect of a function call on any memory that might be read + * by that call. + */ +class CallReadSideEffectInstruction extends SideEffectInstruction { + CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } +} + +/** + * An instruction representing the read of an indirect parameter within a function call. + */ +class IndirectReadSideEffectInstruction extends SideEffectInstruction { + IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } +} + +/** + * An instruction representing the read of an indirect buffer parameter within a function call. + */ +class BufferReadSideEffectInstruction extends SideEffectInstruction { + BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } +} + +/** + * An instruction representing the write of an indirect parameter within a function call. + */ +class IndirectWriteSideEffectInstruction extends SideEffectInstruction { + IndirectWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectWriteSideEffect } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } +} + +/** + * An instruction representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ +class BufferWriteSideEffectInstruction extends SideEffectInstruction { + BufferWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferWriteSideEffect } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } +} + +/** + * An instruction representing the potential write of an indirect parameter within a function call. + * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. + * written. + */ +class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { + IndirectMayWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::IndirectMayWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { + result instanceof IndirectMayMemoryAccess + } +} + +/** + * An instruction representing the write of an indirect buffer parameter within a function call. + * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. + */ +class BufferMayWriteSideEffectInstruction extends SideEffectInstruction { + BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } + + final override MemoryAccessKind getResultMemoryAccess() { + result instanceof BufferMayMemoryAccess + } +} + +/** + * An instruction representing a GNU or MSVC inline assembly statement. + */ +class InlineAsmInstruction extends Instruction { + InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm } + + final override MemoryAccessKind getResultMemoryAccess() { + result instanceof EscapedMayMemoryAccess + } +} + +/** + * An instruction that throws an exception. + */ +class ThrowInstruction extends Instruction { + ThrowInstruction() { getOpcode() instanceof ThrowOpcode } +} + +/** + * An instruction that throws a new exception. + */ +class ThrowValueInstruction extends ThrowInstruction { + ThrowValueInstruction() { getOpcode() instanceof Opcode::ThrowValue } + + /** + * Gets the address operand of the exception thrown by this instruction. + */ + final AddressOperand getExceptionAddressOperand() { result = getAnOperand() } + + /** + * Gets the address of the exception thrown by this instruction. + */ + final Instruction getExceptionAddress() { result = getExceptionAddressOperand().getDef() } + + /** + * Gets the operand for the exception thrown by this instruction. + */ + final LoadOperand getExceptionOperand() { result = getAnOperand() } + + /** + * Gets the exception thrown by this instruction. + */ + final Instruction getException() { result = getExceptionOperand().getDef() } +} + +/** + * An instruction that re-throws the current exception. + */ +class ReThrowInstruction extends ThrowInstruction { + ReThrowInstruction() { getOpcode() instanceof Opcode::ReThrow } +} + +/** + * An instruction that exits the current function by propagating an exception. + */ +class UnwindInstruction extends Instruction { + UnwindInstruction() { getOpcode() instanceof Opcode::Unwind } +} + +/** + * An instruction that starts a `catch` handler. + */ +class CatchInstruction extends Instruction { + CatchInstruction() { getOpcode() instanceof CatchOpcode } +} + +/** + * An instruction that catches an exception of a specific type. + */ +class CatchByTypeInstruction extends CatchInstruction { + Language::Type exceptionType; + + CatchByTypeInstruction() { + getOpcode() instanceof Opcode::CatchByType and + exceptionType = Construction::getInstructionExceptionType(this) + } + + final override string getImmediateString() { result = exceptionType.toString() } + + /** + * Gets the type of exception to be caught. + */ + final Language::Type getExceptionType() { result = exceptionType } +} + +/** + * An instruction that catches any exception. + */ +class CatchAnyInstruction extends CatchInstruction { + CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } +} + +class UnmodeledDefinitionInstruction extends Instruction { + UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } + + final override MemoryAccessKind getResultMemoryAccess() { + result instanceof UnmodeledMemoryAccess + } +} + +/** + * An instruction that initializes all escaped memory. + */ +class AliasedDefinitionInstruction extends Instruction { + AliasedDefinitionInstruction() { getOpcode() instanceof Opcode::AliasedDefinition } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess } +} + +class UnmodeledUseInstruction extends Instruction { + UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } + + override string getOperandsString() { result = "mu*" } +} + +/** + * An instruction representing the choice of one of multiple input values based on control flow. + * + * A `PhiInstruction` is inserted at the beginning of a block whenever two different definitions of + * the same variable reach that block. The `PhiInstruction` will have one operand corresponding to + * each control flow predecessor of the block, with that operand representing the version of the + * variable that flows from that predecessor. The result value of the `PhiInstruction` will be + * a copy of whichever operand corresponds to the actual predecessor that entered the block at + * runtime. + */ +class PhiInstruction extends Instruction { + PhiInstruction() { getOpcode() instanceof Opcode::Phi } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof PhiMemoryAccess } + + /** + * Gets all of the instruction's `PhiInputOperand`s, representing the values that flow from each predecessor block. + */ + final PhiInputOperand getAnInputOperand() { result = this.getAnOperand() } + + /** + * Gets an instruction that defines the input to one of the operands of this + * instruction. It's possible for more than one operand to have the same + * defining instruction, so this predicate will have the same number of + * results as `getAnInputOperand()` or fewer. + */ + pragma[noinline] + final Instruction getAnInput() { result = this.getAnInputOperand().getDef() } +} + +/** + * An instruction representing the effect that a write to a memory may have on potential aliases of + * that memory. + * + * A `ChiInstruction` is inserted immediately after an instruction that writes to memory. The + * `ChiInstruction` has two operands. The first operand, given by `getTotalOperand()`, represents + * the previous state of all of the memory that might be aliased by the memory write. The second + * operand, given by `getPartialOperand()`, represents the memory that was actually modified by the + * memory write. The result of the `ChiInstruction` represents the same memory as + * `getTotalOperand()`, updated to include the changes due to the value that was actually stored by + * the memory write. + * + * As an example, suppose that variable `p` and `q` are pointers that may or may not point to the + * same memory: + * ``` + * *p = 5; + * x = *q; + * ``` + * + * The IR would look like: + * ``` + * r1_1 = VariableAddress[p] + * r1_2 = Load r1_1, m0_0 // Load the value of `p` + * r1_3 = Constant[5] + * m1_4 = Store r1_2, r1_3 // Store to `*p` + * m1_5 = ^Chi m0_1, m1_4 // Side effect of the previous Store on aliased memory + * r1_6 = VariableAddress[x] + * r1_7 = VariableAddress[q] + * r1_8 = Load r1_7, m0_2 // Load the value of `q` + * r1_9 = Load r1_8, m1_5 // Load the value of `*q` + * m1_10 = Store r1_6, r1_9 // Store to x + * ``` + * + * Note the `Chi` instruction after the store to `*p`. The indicates that the previous contents of + * aliased memory (`m0_1`) are merged with the new value written by the store (`m1_4`), producing a + * new version of aliased memory (`m1_5`). On the subsequent load from `*q`, the source operand of + * `*q` is `m1_5`, indicating that the store to `*p` may (or may not) have updated the memory + * pointed to by `q`. + * + * For more information about how `Chi` instructions are used to model memory side effects, see + * https://link.springer.com/content/pdf/10.1007%2F3-540-61053-7_66.pdf. + */ +class ChiInstruction extends Instruction { + ChiInstruction() { getOpcode() instanceof Opcode::Chi } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof ChiTotalMemoryAccess } + + /** + * Gets the operand that represents the previous state of all memory that might be aliased by the + * memory write. + */ + final ChiTotalOperand getTotalOperand() { result = getAnOperand() } + + /** + * Gets the operand that represents the previous state of all memory that might be aliased by the + * memory write. + */ + final Instruction getTotal() { result = getTotalOperand().getDef() } + + /** + * Gets the operand that represents the new value written by the memory write. + */ + final ChiPartialOperand getPartialOperand() { result = getAnOperand() } + + /** + * Gets the operand that represents the new value written by the memory write. + */ + final Instruction getPartial() { result = getPartialOperand().getDef() } +} + +/** + * An instruction representing unreachable code. Inserted in place of the original target + * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is + * infeasible. + */ +class UnreachedInstruction extends Instruction { + UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } +} + +/** + * An instruction representing a built-in operation. This is used to represent + * operations such as access to variable argument lists. + */ +class BuiltInOperationInstruction extends Instruction { + Language::BuiltInOperation operation; + + BuiltInOperationInstruction() { + getOpcode() instanceof BuiltInOperationOpcode and + operation = Construction::getInstructionBuiltInOperation(this) + } + + final Language::BuiltInOperation getBuiltInOperation() { result = operation } +} + +/** + * An instruction representing a built-in operation that does not have a specific opcode. The + * actual operation is specified by the `getBuiltInOperation()` predicate. + */ +class BuiltInInstruction extends BuiltInOperationInstruction { + BuiltInInstruction() { getOpcode() instanceof Opcode::BuiltIn } + + final override string getImmediateString() { result = getBuiltInOperation().toString() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll new file mode 100644 index 00000000000..1ced8ef3282 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -0,0 +1,460 @@ +private import internal.IRInternal +import Instruction +import IRBlock +private import internal.OperandImports as Imports +import Imports::MemoryAccessKind +import Imports::Overlap +private import Imports::OperandTag + +cached +private newtype TOperand = + TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { + defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and + not isInCycle(useInstr) + } or + TNonPhiMemoryOperand( + Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap + ) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not isInCycle(useInstr) + } or + TPhiOperand( + PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap + ) { + defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) + } + +/** Gets a non-phi instruction that defines an operand of `instr`. */ +private Instruction getNonPhiOperandDef(Instruction instr) { + result = Construction::getRegisterOperandDefinition(instr, _) + or + result = Construction::getMemoryOperandDefinition(instr, _, _) +} + +/** + * Holds if `instr` is part of a cycle in the operand graph that doesn't go + * through a phi instruction and therefore should be impossible. + * + * If such cycles are present, either due to a programming error in the IR + * generation or due to a malformed database, it can cause infinite loops in + * analyses that assume a cycle-free graph of non-phi operands. Therefore it's + * better to remove these operands than to leave cycles in the operand graph. + */ +pragma[noopt] +private predicate isInCycle(Instruction instr) { + instr instanceof Instruction and + getNonPhiOperandDef+(instr) = instr +} + +/** + * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. + */ +class Operand extends TOperand { + string toString() { result = "Operand" } + + final Language::Location getLocation() { result = getUse().getLocation() } + + final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } + + /** + * Gets the `Instruction` that consumes this operand. + */ + Instruction getUse() { none() } + + /** + * Gets the `Instruction` whose result is the value of the operand. Unlike + * `getDef`, this also has a result when `isDefinitionInexact` holds, which + * means that the resulting instruction may only _partially_ or _potentially_ + * be the value of this operand. + */ + Instruction getAnyDef() { none() } + + /** + * Gets the `Instruction` whose result is the value of the operand. Unlike + * `getAnyDef`, this also has no result when `isDefinitionInexact` holds, + * which means that the resulting instruction must always be exactly the be + * the value of this operand. + */ + final Instruction getDef() { + result = this.getAnyDef() and + getDefinitionOverlap() instanceof MustExactlyOverlap + } + + /** + * DEPRECATED: renamed to `getUse`. + * + * Gets the `Instruction` that consumes this operand. + */ + deprecated final Instruction getUseInstruction() { result = getUse() } + + /** + * DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this + * predicate is `getAnyDef`, but most uses of this predicate should probably + * be replaced with `getDef`. + * + * Gets the `Instruction` whose result is the value of the operand. + */ + deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() } + + /** + * Gets the overlap relationship between the operand's definition and its use. + */ + Overlap getDefinitionOverlap() { none() } + + /** + * Holds if the result of the definition instruction does not exactly overlap this use. + */ + final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap } + + /** + * Gets a prefix to use when dumping the operand in an operand list. + */ + string getDumpLabel() { result = "" } + + /** + * Gets a string describing this operand, suitable for display in IR dumps. This consists of the + * result ID of the instruction consumed by the operand, plus a label identifying the operand + * kind. + * + * For example: `this:r3_5` + */ + final string getDumpString() { + result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + } + + /** + * Gets a string prefix to prepend to the operand's definition ID in an IR dump, specifying whether the operand is + * an exact or inexact use of its definition. For an inexact use, the prefix is "~". For an exact use, the prefix is + * the empty string. + */ + private string getInexactSpecifier() { + if isDefinitionInexact() then result = "~" else result = "" + } + + /** + * Get the order in which the operand should be sorted in the operand list. + */ + int getDumpSortOrder() { result = -1 } + + /** + * Gets the type of the value consumed by this operand. This is usually the same as the + * result type of the definition instruction consumed by this operand. For register operands, + * this is always the case. For some memory operands, the operand type may be different from + * the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + Language::Type getType() { result = getAnyDef().getResultType() } + + /** + * Holds if the value consumed by this operand is a glvalue. If this + * holds, the value of the operand represents the address of a location, + * and the type of the location is given by `getType()`. If this does + * not hold, the value of the operand represents a value whose type is + * given by `getResultType()`. + */ + predicate isGLValue() { getAnyDef().isGLValue() } + + /** + * Gets the size of the value consumed by this operand, in bytes. If the operand does not have + * a known constant size, this predicate does not hold. + */ + int getSize() { result = Language::getTypeSize(getType()) } +} + +/** + * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). + */ +class MemoryOperand extends Operand { + MemoryOperand() { + this = TNonPhiMemoryOperand(_, _, _, _) or + this = TPhiOperand(_, _, _, _) + } + + override predicate isGLValue() { + // A `MemoryOperand` can never be a glvalue + none() + } + + /** + * Gets the kind of memory access performed by the operand. + */ + MemoryAccessKind getMemoryAccess() { none() } + + /** + * Returns the operand that holds the memory address from which the current operand loads its + * value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2` + * is `r1`. + */ + final AddressOperand getAddressOperand() { + getMemoryAccess().usesAddressOperand() and + result.getUse() = getUse() + } +} + +/** + * An operand that is not an operand of a `PhiInstruction`. + */ +class NonPhiOperand extends Operand { + Instruction useInstr; + Instruction defInstr; + OperandTag tag; + + NonPhiOperand() { + this = TRegisterOperand(useInstr, tag, defInstr) or + this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + } + + final override Instruction getUse() { result = useInstr } + + final override Instruction getAnyDef() { result = defInstr } + + final override string getDumpLabel() { result = tag.getLabel() } + + final override int getDumpSortOrder() { result = tag.getSortOrder() } + + final OperandTag getOperandTag() { result = tag } +} + +/** + * An operand that consumes a register (non-memory) result. + */ +class RegisterOperand extends NonPhiOperand, TRegisterOperand { + override RegisterOperandTag tag; + + final override Overlap getDefinitionOverlap() { + // All register results overlap exactly with their uses. + result instanceof MustExactlyOverlap + } +} + +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { + override MemoryOperandTag tag; + Overlap overlap; + + NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + + final override Overlap getDefinitionOverlap() { result = overlap } +} + +class TypedOperand extends NonPhiMemoryOperand { + override TypedOperandTag tag; + + final override Language::Type getType() { + result = Construction::getInstructionOperandType(useInstr, tag) + } +} + +/** + * The address operand of an instruction that loads or stores a value from + * memory (e.g. `Load`, `Store`). + */ +class AddressOperand extends RegisterOperand { + override AddressOperandTag tag; + + override string toString() { result = "Address" } +} + +/** + * The source value operand of an instruction that loads a value from memory (e.g. `Load`, + * `ReturnValue`, `ThrowValue`). + */ +class LoadOperand extends TypedOperand { + override LoadOperandTag tag; + + override string toString() { result = "Load" } + + final override MemoryAccessKind getMemoryAccess() { result instanceof IndirectMemoryAccess } +} + +/** + * The source value operand of a `Store` instruction. + */ +class StoreValueOperand extends RegisterOperand { + override StoreValueOperandTag tag; + + override string toString() { result = "StoreValue" } +} + +/** + * The sole operand of a unary instruction (e.g. `Convert`, `Negate`, `Copy`). + */ +class UnaryOperand extends RegisterOperand { + override UnaryOperandTag tag; + + override string toString() { result = "Unary" } +} + +/** + * The left operand of a binary instruction (e.g. `Add`, `CompareEQ`). + */ +class LeftOperand extends RegisterOperand { + override LeftOperandTag tag; + + override string toString() { result = "Left" } +} + +/** + * The right operand of a binary instruction (e.g. `Add`, `CompareEQ`). + */ +class RightOperand extends RegisterOperand { + override RightOperandTag tag; + + override string toString() { result = "Right" } +} + +/** + * The condition operand of a `ConditionalBranch` or `Switch` instruction. + */ +class ConditionOperand extends RegisterOperand { + override ConditionOperandTag tag; + + override string toString() { result = "Condition" } +} + +/** + * An operand of the special `UnmodeledUse` instruction, representing a value + * whose set of uses is unknown. + */ +class UnmodeledUseOperand extends NonPhiMemoryOperand { + override UnmodeledUseOperandTag tag; + + override string toString() { result = "UnmodeledUse" } + + final override MemoryAccessKind getMemoryAccess() { result instanceof UnmodeledMemoryAccess } +} + +/** + * The operand representing the target function of an `Call` instruction. + */ +class CallTargetOperand extends RegisterOperand { + override CallTargetOperandTag tag; + + override string toString() { result = "CallTarget" } +} + +/** + * An operand representing an argument to a function call. This includes both + * positional arguments (represented by `PositionalArgumentOperand`) and the + * implicit `this` argument, if any (represented by `ThisArgumentOperand`). + */ +class ArgumentOperand extends RegisterOperand { + override ArgumentOperandTag tag; +} + +/** + * An operand representing the implicit 'this' argument to a member function + * call. + */ +class ThisArgumentOperand extends ArgumentOperand { + override ThisArgumentOperandTag tag; + + override string toString() { result = "ThisArgument" } +} + +/** + * An operand representing an argument to a function call. + */ +class PositionalArgumentOperand extends ArgumentOperand { + override PositionalArgumentOperandTag tag; + int argIndex; + + PositionalArgumentOperand() { argIndex = tag.getArgIndex() } + + override string toString() { result = "Arg(" + argIndex + ")" } + + /** + * Gets the zero-based index of the argument. + */ + final int getIndex() { result = argIndex } +} + +class SideEffectOperand extends TypedOperand { + override SideEffectOperandTag tag; + + final override int getSize() { + if getType() instanceof Language::UnknownType + then result = Construction::getInstructionOperandSize(useInstr, tag) + else result = Language::getTypeSize(getType()) + } + + override MemoryAccessKind getMemoryAccess() { + useInstr instanceof CallSideEffectInstruction and + result instanceof EscapedMayMemoryAccess + or + useInstr instanceof CallReadSideEffectInstruction and + result instanceof EscapedMayMemoryAccess + or + useInstr instanceof IndirectReadSideEffectInstruction and + result instanceof IndirectMemoryAccess + or + useInstr instanceof BufferReadSideEffectInstruction and + result instanceof BufferMemoryAccess + or + useInstr instanceof IndirectWriteSideEffectInstruction and + result instanceof IndirectMemoryAccess + or + useInstr instanceof BufferWriteSideEffectInstruction and + result instanceof BufferMemoryAccess + or + useInstr instanceof IndirectMayWriteSideEffectInstruction and + result instanceof IndirectMayMemoryAccess + or + useInstr instanceof BufferMayWriteSideEffectInstruction and + result instanceof BufferMayMemoryAccess + } +} + +/** + * An operand of a `PhiInstruction`. + */ +class PhiInputOperand extends MemoryOperand, TPhiOperand { + PhiInstruction useInstr; + Instruction defInstr; + IRBlock predecessorBlock; + Overlap overlap; + + PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + + override string toString() { result = "Phi" } + + final override PhiInstruction getUse() { result = useInstr } + + final override Instruction getAnyDef() { result = defInstr } + + final override Overlap getDefinitionOverlap() { result = overlap } + + final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() } + + final override string getDumpLabel() { + result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" + } + + /** + * Gets the predecessor block from which this value comes. + */ + final IRBlock getPredecessorBlock() { result = predecessorBlock } + + final override MemoryAccessKind getMemoryAccess() { result instanceof PhiMemoryAccess } +} + +/** + * The total operand of a Chi node, representing the previous value of the memory. + */ +class ChiTotalOperand extends NonPhiMemoryOperand { + override ChiTotalOperandTag tag; + + override string toString() { result = "ChiTotal" } + + final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } +} + +/** + * The partial operand of a Chi node, representing the value being written to part of the memory. + */ +class ChiPartialOperand extends NonPhiMemoryOperand { + override ChiPartialOperandTag tag; + + override string toString() { result = "ChiPartial" } + + final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.ql new file mode 100644 index 00000000000..83e2e37234b --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.ql @@ -0,0 +1,8 @@ +/** + * @name Print SSA IR + * @description Outputs a representation of the SSA IR graph + * @id cpp/print-ssa-ir + * @kind graph + */ + +import PrintIR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll new file mode 100644 index 00000000000..c24756a2212 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll @@ -0,0 +1,260 @@ +private import internal.IRInternal +private import IR +private import internal.PrintIRImports as Imports +import Imports::IRConfiguration + +private newtype TPrintIRConfiguration = MkPrintIRConfiguration() + +/** + * The query can extend this class to control which functions are printed. + */ +class PrintIRConfiguration extends TPrintIRConfiguration { + string toString() { result = "PrintIRConfiguration" } + + /** + * Holds if the IR for `func` should be printed. By default, holds for all + * functions. + */ + predicate shouldPrintFunction(Language::Function func) { any() } +} + +private predicate shouldPrintFunction(Language::Function func) { + exists(PrintIRConfiguration config | config.shouldPrintFunction(func)) +} + +/** + * Override of `IRConfiguration` to only create IR for the functions that are to be dumped. + */ +private class FilteredIRConfiguration extends IRConfiguration { + override predicate shouldCreateIRForFunction(Language::Function func) { + shouldPrintFunction(func) + } +} + +private string getAdditionalInstructionProperty(Instruction instr, string key) { + exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key)) +} + +private string getAdditionalBlockProperty(IRBlock block, string key) { + exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key)) +} + +private newtype TPrintableIRNode = + TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or + TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or + TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) } + +/** + * A node to be emitted in the IR graph. + */ +abstract class PrintableIRNode extends TPrintableIRNode { + abstract string toString(); + + /** + * Gets the location to be emitted for the node. + */ + abstract Language::Location getLocation(); + + /** + * Gets the label to be emitted for the node. + */ + abstract string getLabel(); + + /** + * Gets the order in which the node appears in its parent node. + */ + abstract int getOrder(); + + /** + * Gets the parent of this node. + */ + abstract PrintableIRNode getParent(); + + /** + * Gets the kind of graph represented by this node ("graph" or "tree"). + */ + string getGraphKind() { none() } + + /** + * Holds if this node should always be rendered as text, even in a graphical + * viewer. + */ + predicate forceText() { none() } + + /** + * Gets the value of the node property with the specified key. + */ + string getProperty(string key) { + key = "semmle.label" and result = getLabel() + or + key = "semmle.order" and result = getOrder().toString() + or + key = "semmle.graphKind" and result = getGraphKind() + or + key = "semmle.forceText" and forceText() and result = "true" + } +} + +/** + * An IR graph node representing a `IRFunction` object. + */ +class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { + IRFunction irFunc; + + PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } + + override string toString() { result = irFunc.toString() } + + override Language::Location getLocation() { result = irFunc.getLocation() } + + override string getLabel() { result = Language::getIdentityString(irFunc.getFunction()) } + + override int getOrder() { + this = rank[result + 1](PrintableIRFunction orderedFunc, Language::Location location | + location = orderedFunc.getIRFunction().getLocation() + | + orderedFunc + order by + location.getFile().getAbsolutePath(), location.getStartLine(), location.getStartColumn(), + orderedFunc.getLabel() + ) + } + + final override PrintableIRNode getParent() { none() } + + final IRFunction getIRFunction() { result = irFunc } +} + +/** + * An IR graph node representing an `IRBlock` object. + */ +class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { + IRBlock block; + + PrintableIRBlock() { this = TPrintableIRBlock(block) } + + override string toString() { result = getLabel() } + + override Language::Location getLocation() { result = block.getLocation() } + + override string getLabel() { result = "Block " + block.getDisplayIndex().toString() } + + override int getOrder() { result = block.getDisplayIndex() } + + final override string getGraphKind() { result = "tree" } + + final override predicate forceText() { any() } + + final override PrintableIRFunction getParent() { + result.getIRFunction() = block.getEnclosingIRFunction() + } + + override string getProperty(string key) { + result = PrintableIRNode.super.getProperty(key) or + result = getAdditionalBlockProperty(block, key) + } + + final IRBlock getBlock() { result = block } +} + +/** + * An IR graph node representing an `Instruction`. + */ +class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { + Instruction instr; + + PrintableInstruction() { this = TPrintableInstruction(instr) } + + override string toString() { result = instr.toString() } + + override Language::Location getLocation() { result = instr.getLocation() } + + override string getLabel() { + exists(IRBlock block | + instr = block.getAnInstruction() and + exists( + string resultString, string operationString, string operandsString, int resultWidth, + int operationWidth + | + resultString = instr.getResultString() and + operationString = instr.getOperationString() and + operandsString = instr.getOperandsString() and + columnWidths(block, resultWidth, operationWidth) and + result = resultString + getPaddingString(resultWidth - resultString.length()) + " = " + + operationString + getPaddingString(operationWidth - operationString.length()) + " : " + + operandsString + ) + ) + } + + override int getOrder() { result = instr.getDisplayIndexInBlock() } + + final override PrintableIRBlock getParent() { result.getBlock() = instr.getBlock() } + + final Instruction getInstruction() { result = instr } + + override string getProperty(string key) { + result = PrintableIRNode.super.getProperty(key) or + result = getAdditionalInstructionProperty(instr, key) + } +} + +private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) { + resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and + operationWidth = max(Instruction instr | + instr.getBlock() = block + | + instr.getOperationString().length() + ) +} + +private int maxColumnWidth() { + result = max(Instruction instr, int width | + width = instr.getResultString().length() or + width = instr.getOperationString().length() or + width = instr.getOperandsString().length() + | + width + ) +} + +private string getPaddingString(int n) { + n = 0 and result = "" + or + n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " +} + +query predicate nodes(PrintableIRNode node, string key, string value) { + value = node.getProperty(key) +} + +private int getSuccessorIndex(IRBlock pred, IRBlock succ) { + succ = rank[result + 1](IRBlock aSucc, EdgeKind kind | + aSucc = pred.getSuccessor(kind) + | + aSucc order by kind.toString() + ) +} + +query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { + exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | + predBlock = pred.getBlock() and + succBlock = succ.getBlock() and + predBlock.getSuccessor(kind) = succBlock and + ( + ( + key = "semmle.label" and + if predBlock.getBackEdgeSuccessor(kind) = succBlock + then value = kind.toString() + " (back edge)" + else value = kind.toString() + ) + or + key = "semmle.order" and + value = getSuccessorIndex(predBlock, succBlock).toString() + ) + ) +} + +query predicate parents(PrintableIRNode child, PrintableIRNode parent) { + parent = child.getParent() +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll new file mode 100644 index 00000000000..40076b817a1 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll @@ -0,0 +1,54 @@ +private import internal.ConstantAnalysisInternal +private import semmle.code.cpp.ir.internal.IntegerPartial +private import IR + +language[monotonicAggregates] +int getConstantValue(Instruction instr) { + result = instr.(IntegerConstantInstruction).getValue().toInt() + or + result = getBinaryInstructionValue(instr) + or + result = neg(getConstantValue(instr.(NegateInstruction).getUnary())) + or + result = getConstantValue(instr.(CopyInstruction).getSourceValue()) + or + exists(PhiInstruction phi | + phi = instr and + result = max(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) and + result = min(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) + ) +} + +pragma[noinline] +private predicate binaryInstructionOperands(BinaryInstruction instr, int left, int right) { + left = getConstantValue(instr.getLeft()) and + right = getConstantValue(instr.getRight()) +} + +pragma[noinline] +private int getBinaryInstructionValue(BinaryInstruction instr) { + exists(int left, int right | + binaryInstructionOperands(instr, left, right) and + ( + instr instanceof AddInstruction and result = add(left, right) + or + instr instanceof SubInstruction and result = sub(left, right) + or + instr instanceof MulInstruction and result = mul(left, right) + or + instr instanceof DivInstruction and result = div(left, right) + or + instr instanceof CompareEQInstruction and result = compareEQ(left, right) + or + instr instanceof CompareNEInstruction and result = compareNE(left, right) + or + instr instanceof CompareLTInstruction and result = compareLT(left, right) + or + instr instanceof CompareGTInstruction and result = compareGT(left, right) + or + instr instanceof CompareLEInstruction and result = compareLE(left, right) + or + instr instanceof CompareGEInstruction and result = compareGE(left, right) + ) + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll new file mode 100644 index 00000000000..57a7cf594ca --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll @@ -0,0 +1,11 @@ +private import internal.ConstantAnalysisInternal +private import semmle.code.cpp.ir.internal.IntegerConstant +private import ConstantAnalysis +import IR + +private class ConstantAnalysisPropertyProvider extends IRPropertyProvider { + override string getInstructionProperty(Instruction instr, string key) { + key = "ConstantValue" and + result = getValue(getConstantValue(instr)).toString() + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll new file mode 100644 index 00000000000..9b4f813a10b --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll new file mode 100644 index 00000000000..e3e52df8931 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -0,0 +1,315 @@ +private import internal.ValueNumberingInternal +private import cpp +private import IR + +/** + * Provides additional information about value numbering in IR dumps. + */ +class ValueNumberPropertyProvider extends IRPropertyProvider { + override string getInstructionProperty(Instruction instr, string key) { + exists(ValueNumber vn | + vn = valueNumber(instr) and + key = "valnum" and + if strictcount(vn.getAnInstruction()) > 1 then result = vn.toString() else result = "unique" + ) + } +} + +newtype TValueNumber = + TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) { + variableAddressValueNumber(_, irFunc, var) + } or + TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) { + initializeParameterValueNumber(_, irFunc, var) + } or + TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or + TConstantValueNumber(IRFunction irFunc, Type type, string value) { + constantValueNumber(_, irFunc, type, value) + } or + TStringConstantValueNumber(IRFunction irFunc, Type type, string value) { + stringConstantValueNumber(_, irFunc, type, value) + } or + TFieldAddressValueNumber(IRFunction irFunc, Field field, ValueNumber objectAddress) { + fieldAddressValueNumber(_, irFunc, field, objectAddress) + } or + TBinaryValueNumber( + IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand + ) { + binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand) + } or + TPointerArithmeticValueNumber( + IRFunction irFunc, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, + ValueNumber rightOperand + ) { + pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand) + } or + TUnaryValueNumber(IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand) { + unaryValueNumber(_, irFunc, opcode, type, operand) + } or + TInheritanceConversionValueNumber( + IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand + ) { + inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) + } or + TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) } + +/** + * The value number assigned to a particular set of instructions that produce equivalent results. + */ +class ValueNumber extends TValueNumber { + final string toString() { result = getExampleInstruction().getResultId() } + + final Location getLocation() { result = getExampleInstruction().getLocation() } + + /** + * Gets the instructions that have been assigned this value number. This will always produce at + * least one result. + */ + final Instruction getAnInstruction() { this = valueNumber(result) } + + /** + * Gets one of the instructions that was assigned this value number. The chosen instuction is + * deterministic but arbitrary. Intended for use only in debugging. + */ + final Instruction getExampleInstruction() { + result = min(Instruction instr | + instr = getAnInstruction() + | + instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock() + ) + } + + /** + * Gets an `Operand` whose definition is exact and has this value number. + */ + final Operand getAUse() { this = valueNumber(result.getDef()) } +} + +/** + * A `CopyInstruction` whose source operand's value is congruent to the definition of that source + * operand. + * For example: + * ``` + * Point p = { 1, 2 }; + * Point q = p; + * int a = p.x; + * ``` + * The use of `p` on line 2 is linked to the definition of `p` on line 1, and is congruent to that + * definition because it accesses the exact same memory. + * The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not + * congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`. + */ +private class CongruentCopyInstruction extends CopyInstruction { + CongruentCopyInstruction() { + this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap + } +} + +/** + * Holds if this library knows how to assign a value number to the specified instruction, other than + * a `unique` value number that is never shared by multiple instructions. + */ +private predicate numberableInstruction(Instruction instr) { + instr instanceof VariableAddressInstruction + or + instr instanceof InitializeParameterInstruction + or + instr instanceof InitializeThisInstruction + or + instr instanceof ConstantInstruction + or + instr instanceof StringConstantInstruction + or + instr instanceof FieldAddressInstruction + or + instr instanceof BinaryInstruction + or + instr instanceof UnaryInstruction and not instr instanceof CopyInstruction + or + instr instanceof PointerArithmeticInstruction + or + instr instanceof CongruentCopyInstruction +} + +private predicate variableAddressValueNumber( + VariableAddressInstruction instr, IRFunction irFunc, IRVariable var +) { + instr.getEnclosingIRFunction() = irFunc and + instr.getVariable() = var +} + +private predicate initializeParameterValueNumber( + InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var +) { + instr.getEnclosingIRFunction() = irFunc and + instr.getVariable() = var +} + +private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { + instr.getEnclosingIRFunction() = irFunc +} + +private predicate constantValueNumber( + ConstantInstruction instr, IRFunction irFunc, Type type, string value +) { + instr.getEnclosingIRFunction() = irFunc and + instr.getResultType() = type and + instr.getValue() = value +} + +private predicate stringConstantValueNumber( + StringConstantInstruction instr, IRFunction irFunc, Type type, string value +) { + instr.getEnclosingIRFunction() = irFunc and + instr.getResultType() = type and + instr.getValue().getValue() = value +} + +private predicate fieldAddressValueNumber( + FieldAddressInstruction instr, IRFunction irFunc, Field field, ValueNumber objectAddress +) { + instr.getEnclosingIRFunction() = irFunc and + instr.getField() = field and + valueNumber(instr.getObjectAddress()) = objectAddress +} + +private predicate binaryValueNumber( + BinaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, + ValueNumber rightOperand +) { + instr.getEnclosingIRFunction() = irFunc and + not instr instanceof PointerArithmeticInstruction and + instr.getOpcode() = opcode and + instr.getResultType() = type and + valueNumber(instr.getLeft()) = leftOperand and + valueNumber(instr.getRight()) = rightOperand +} + +private predicate pointerArithmeticValueNumber( + PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, Type type, int elementSize, + ValueNumber leftOperand, ValueNumber rightOperand +) { + instr.getEnclosingIRFunction() = irFunc and + instr.getOpcode() = opcode and + instr.getResultType() = type and + instr.getElementSize() = elementSize and + valueNumber(instr.getLeft()) = leftOperand and + valueNumber(instr.getRight()) = rightOperand +} + +private predicate unaryValueNumber( + UnaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand +) { + instr.getEnclosingIRFunction() = irFunc and + not instr instanceof InheritanceConversionInstruction and + not instr instanceof CopyInstruction and + instr.getOpcode() = opcode and + instr.getResultType() = type and + valueNumber(instr.getUnary()) = operand +} + +private predicate inheritanceConversionValueNumber( + InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode, Class baseClass, + Class derivedClass, ValueNumber operand +) { + instr.getEnclosingIRFunction() = irFunc and + instr.getOpcode() = opcode and + instr.getBaseClass() = baseClass and + instr.getDerivedClass() = derivedClass and + valueNumber(instr.getUnary()) = operand +} + +/** + * Holds if `instr` should be assigned a unique value number because this library does not know how + * to determine if two instances of that instruction are equivalent. + */ +private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) { + instr.getEnclosingIRFunction() = irFunc and + not instr.getResultType() instanceof VoidType and + not numberableInstruction(instr) +} + +/** + * Gets the value number assigned to `instr`, if any. Returns at most one result. + */ +cached +ValueNumber valueNumber(Instruction instr) { + result = nonUniqueValueNumber(instr) + or + exists(IRFunction irFunc | + uniqueValueNumber(instr, irFunc) and + result = TUniqueValueNumber(irFunc, instr) + ) +} + +/** + * Gets the value number assigned to the exact definition of `op`, if any. + * Returns at most one result. + */ +ValueNumber valueNumberOfOperand(Operand op) { result = valueNumber(op.getDef()) } + +/** + * Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique + * value number. + */ +private ValueNumber nonUniqueValueNumber(Instruction instr) { + exists(IRFunction irFunc | + irFunc = instr.getEnclosingIRFunction() and + ( + exists(IRVariable var | + variableAddressValueNumber(instr, irFunc, var) and + result = TVariableAddressValueNumber(irFunc, var) + ) + or + exists(IRVariable var | + initializeParameterValueNumber(instr, irFunc, var) and + result = TInitializeParameterValueNumber(irFunc, var) + ) + or + initializeThisValueNumber(instr, irFunc) and + result = TInitializeThisValueNumber(irFunc) + or + exists(Type type, string value | + constantValueNumber(instr, irFunc, type, value) and + result = TConstantValueNumber(irFunc, type, value) + ) + or + exists(Type type, string value | + stringConstantValueNumber(instr, irFunc, type, value) and + result = TStringConstantValueNumber(irFunc, type, value) + ) + or + exists(Field field, ValueNumber objectAddress | + fieldAddressValueNumber(instr, irFunc, field, objectAddress) and + result = TFieldAddressValueNumber(irFunc, field, objectAddress) + ) + or + exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand | + binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and + result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand) + ) + or + exists(Opcode opcode, Type type, ValueNumber operand | + unaryValueNumber(instr, irFunc, opcode, type, operand) and + result = TUnaryValueNumber(irFunc, opcode, type, operand) + ) + or + exists(Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand | + inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and + result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) + ) + or + exists( + Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand + | + pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, + rightOperand) and + result = TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, + rightOperand) + ) + or + // The value number of a copy is just the value number of its source value. + result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue()) + ) + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll new file mode 100644 index 00000000000..9b4f813a10b --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll new file mode 100644 index 00000000000..dc50ef01354 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -0,0 +1,326 @@ +private import AliasAnalysisInternal +private import cpp +private import InputIR +private import semmle.code.cpp.ir.internal.IntegerConstant as Ints +private import semmle.code.cpp.models.interfaces.Alias + +private class IntValue = Ints::IntValue; + +/** + * Converts the bit count in `bits` to a byte count and a bit count in the form + * bytes:bits. + */ +bindingset[bits] +string bitsToBytesAndBits(int bits) { result = (bits / 8).toString() + ":" + (bits % 8).toString() } + +/** + * Gets a printable string for a bit offset with possibly unknown value. + */ +bindingset[bitOffset] +string getBitOffsetString(IntValue bitOffset) { + if Ints::hasValue(bitOffset) + then + if bitOffset >= 0 + then result = "+" + bitsToBytesAndBits(bitOffset) + else result = "-" + bitsToBytesAndBits(Ints::neg(bitOffset)) + else result = "+?" +} + +/** + * Gets the offset of field `field` in bits. + */ +private IntValue getFieldBitOffset(Field field) { + if field instanceof BitField + then result = Ints::add(Ints::mul(field.getByteOffset(), 8), field.(BitField).getBitOffset()) + else result = Ints::mul(field.getByteOffset(), 8) +} + +/** + * Holds if the operand `tag` of instruction `instr` is used in a way that does + * not result in any address held in that operand from escaping beyond the + * instruction. + */ +private predicate operandIsConsumedWithoutEscaping(Operand operand) { + // The source/destination address of a Load/Store does not escape (but the + // loaded/stored value could). + operand instanceof AddressOperand + or + exists(Instruction instr | + instr = operand.getUse() and + ( + // Neither operand of a Compare escapes. + instr instanceof CompareInstruction + or + // Neither operand of a PointerDiff escapes. + instr instanceof PointerDiffInstruction + or + // Converting an address to a `bool` does not escape the address. + instr.(ConvertInstruction).getResultType() instanceof BoolType + ) + ) + or + // Some standard function arguments never escape + isNeverEscapesArgument(operand) +} + +private predicate operandEscapesDomain(Operand operand) { + not operandIsConsumedWithoutEscaping(operand) and + not operandIsPropagated(operand, _) and + not isArgumentForParameter(_, operand, _) and + not isOnlyEscapesViaReturnArgument(operand) and + not operand.getUse() instanceof ReturnValueInstruction and + not operand instanceof PhiInputOperand +} + +/** + * If the result of instruction `instr` is an integer constant, returns the + * value of that constant. Otherwise, returns unknown. + */ +IntValue getConstantValue(Instruction instr) { + if instr instanceof IntegerConstantInstruction + then result = instr.(IntegerConstantInstruction).getValue().toInt() + else result = Ints::unknown() +} + +/** + * Computes the offset, in bits, by which the result of `instr` differs from the + * pointer argument to `instr`, if that offset is a constant. Otherwise, returns + * unknown. + */ +IntValue getPointerBitOffset(PointerOffsetInstruction instr) { + exists(IntValue bitOffset | + bitOffset = Ints::mul(Ints::mul(getConstantValue(instr.getRight()), instr.getElementSize()), 8) and + ( + instr instanceof PointerAddInstruction and result = bitOffset + or + instr instanceof PointerSubInstruction and result = Ints::neg(bitOffset) + ) + ) +} + +/** + * Holds if any address held in operand `tag` of instruction `instr` is + * propagated to the result of `instr`, offset by the number of bits in + * `bitOffset`. If the address is propagated, but the offset is not known to be + * a constant, then `bitOffset` is unknown. + */ +private predicate operandIsPropagated(Operand operand, IntValue bitOffset) { + exists(Instruction instr | + instr = operand.getUse() and + ( + // Converting to a non-virtual base class adds the offset of the base class. + exists(ConvertToBaseInstruction convert | + convert = instr and + bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8) + ) + or + // Converting to a derived class subtracts the offset of the base class. + exists(ConvertToDerivedInstruction convert | + convert = instr and + bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8)) + ) + or + // Converting to a virtual base class adds an unknown offset. + instr instanceof ConvertToVirtualBaseInstruction and + bitOffset = Ints::unknown() + or + // Conversion to another pointer type propagates the source address. + exists(ConvertInstruction convert, Type resultType | + convert = instr and + resultType = convert.getResultType() and + ( + resultType instanceof PointerType or + resultType instanceof Class //REVIEW: Remove when all glvalues are pointers + ) and + bitOffset = 0 + ) + or + // Adding an integer to or subtracting an integer from a pointer propagates + // the address with an offset. + bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) + or + // Computing a field address from a pointer propagates the address plus the + // offset of the field. + bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) + or + // A copy propagates the source value. + operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0 + or + // Some functions are known to propagate an argument + isAlwaysReturnedArgument(operand) and bitOffset = 0 + ) + ) +} + +private predicate operandEscapesNonReturn(Operand operand) { + // The address is propagated to the result of the instruction, and that result itself is returned + operandIsPropagated(operand, _) and resultEscapesNonReturn(operand.getUse()) + or + // The operand is used in a function call which returns it, and the return value is then returned + exists(CallInstruction ci, Instruction init | + isArgumentForParameter(ci, operand, init) and + ( + resultMayReachReturn(init) and + resultEscapesNonReturn(ci) + or + resultEscapesNonReturn(init) + ) + ) + or + isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse()) + or + operand instanceof PhiInputOperand and + resultEscapesNonReturn(operand.getUse()) + or + operandEscapesDomain(operand) +} + +private predicate operandMayReachReturn(Operand operand) { + // The address is propagated to the result of the instruction, and that result itself is returned + operandIsPropagated(operand, _) and + resultMayReachReturn(operand.getUse()) + or + // The operand is used in a function call which returns it, and the return value is then returned + exists(CallInstruction ci, Instruction init | + isArgumentForParameter(ci, operand, init) and + resultMayReachReturn(init) and + resultMayReachReturn(ci) + ) + or + // The address is returned + operand.getUse() instanceof ReturnValueInstruction + or + isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse()) + or + operand instanceof PhiInputOperand and + resultMayReachReturn(operand.getUse()) +} + +private predicate operandReturned(Operand operand, IntValue bitOffset) { + // The address is propagated to the result of the instruction, and that result itself is returned + exists(IntValue bitOffset1, IntValue bitOffset2 | + operandIsPropagated(operand, bitOffset1) and + resultReturned(operand.getUse(), bitOffset2) and + bitOffset = Ints::add(bitOffset1, bitOffset2) + ) + or + // The operand is used in a function call which returns it, and the return value is then returned + exists(CallInstruction ci, Instruction init, IntValue bitOffset1, IntValue bitOffset2 | + isArgumentForParameter(ci, operand, init) and + resultReturned(init, bitOffset1) and + resultReturned(ci, bitOffset2) and + bitOffset = Ints::add(bitOffset1, bitOffset2) + ) + or + // The address is returned + operand.getUse() instanceof ReturnValueInstruction and + bitOffset = 0 + or + isOnlyEscapesViaReturnArgument(operand) and + resultReturned(operand.getUse(), _) and + bitOffset = Ints::unknown() +} + +private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { + exists(Function f | + ci = operand.getUse() and + f = ci.getStaticCallTarget() and + ( + init.(InitializeParameterInstruction).getParameter() = f + .getParameter(operand.(PositionalArgumentOperand).getIndex()) + or + init instanceof InitializeThisInstruction and + init.getEnclosingFunction() = f and + operand instanceof ThisArgumentOperand + ) and + not f.isVirtual() and + not f instanceof AliasFunction + ) +} + +private predicate isAlwaysReturnedArgument(Operand operand) { + exists(AliasFunction f | + f = operand.getUse().(CallInstruction).getStaticCallTarget() and + f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex()) + ) +} + +private predicate isOnlyEscapesViaReturnArgument(Operand operand) { + exists(AliasFunction f | + f = operand.getUse().(CallInstruction).getStaticCallTarget() and + f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex()) + ) +} + +private predicate isNeverEscapesArgument(Operand operand) { + exists(AliasFunction f | + f = operand.getUse().(CallInstruction).getStaticCallTarget() and + f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex()) + ) +} + +private predicate resultReturned(Instruction instr, IntValue bitOffset) { + operandReturned(instr.getAUse(), bitOffset) +} + +private predicate resultMayReachReturn(Instruction instr) { operandMayReachReturn(instr.getAUse()) } + +/** + * Holds if any address held in the result of instruction `instr` escapes + * outside the domain of the analysis. + */ +private predicate resultEscapesNonReturn(Instruction instr) { + // The result escapes if it has at least one use that escapes. + operandEscapesNonReturn(instr.getAUse()) +} + +/** + * Holds if the address of the specified local variable or parameter escapes the + * domain of the analysis. + */ +private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) { + // The variable's address escapes if the result of any + // VariableAddressInstruction that computes the variable's address escapes. + exists(VariableAddressInstruction instr | + instr.getVariable() = var and + resultEscapesNonReturn(instr) + ) +} + +/** + * Holds if the address of the specified variable escapes the domain of the + * analysis. + */ +predicate variableAddressEscapes(IRVariable var) { + automaticVariableAddressEscapes(var.(IRAutomaticVariable)) + or + // All variables with static storage duration have their address escape. + not var instanceof IRAutomaticVariable +} + +/** + * Holds if the result of instruction `instr` points within variable `var`, at + * bit offset `bitOffset` within the variable. If the result points within + * `var`, but at an unknown or non-constant offset, then `bitOffset` is unknown. + */ +predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) { + // The address of a variable points to that variable, at offset 0. + instr.(VariableAddressInstruction).getVariable() = var and + bitOffset = 0 + or + exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset | + operand = instr.getAnOperand() and + // If an operand is propagated, then the result points to the same variable, + // offset by the bit offset from the propagation. + resultPointsTo(operand.getAnyDef(), var, originalBitOffset) and + ( + operandIsPropagated(operand, propagatedBitOffset) + or + exists(CallInstruction ci, Instruction init | + isArgumentForParameter(ci, operand, init) and + resultReturned(init, propagatedBitOffset) + ) + ) and + bitOffset = Ints::add(originalBitOffset, propagatedBitOffset) + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll new file mode 100644 index 00000000000..8a9e43e14a3 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.raw.IR as InputIR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll new file mode 100644 index 00000000000..d1b46ed35c8 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll new file mode 100644 index 00000000000..74f7b4a2b64 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll new file mode 100644 index 00000000000..ff26415fd43 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.internal.IRCppLanguage as Language +import SSAConstruction as Construction diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll new file mode 100644 index 00000000000..1f0f5eaccde --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll @@ -0,0 +1,4 @@ +import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag +import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities +import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag +import semmle.code.cpp.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll new file mode 100644 index 00000000000..0138af075dc --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll @@ -0,0 +1,4 @@ +import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import semmle.code.cpp.ir.implementation.Opcode as Opcode +import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll new file mode 100644 index 00000000000..e626662ccf2 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll @@ -0,0 +1,3 @@ +import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import semmle.code.cpp.ir.internal.Overlap as Overlap +import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll new file mode 100644 index 00000000000..46254a6e3f2 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll new file mode 100644 index 00000000000..a5c09c6401b --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll @@ -0,0 +1,126 @@ +private import SSAConstructionInternal +private import OldIR +private import Alias +private import SSAConstruction +private import DebugSSA + +/** + * Property provide that dumps the memory access of each result. Useful for debugging SSA + * construction. + */ +class PropertyProvider extends IRPropertyProvider { + override string getInstructionProperty(Instruction instruction, string key) { + exists(MemoryLocation location | + location = getResultMemoryLocation(instruction) and + ( + key = "ResultMemoryLocation" and result = location.toString() + or + key = "ResultVirtualVariable" and result = location.getVirtualVariable().toString() + ) + ) + or + exists(MemoryLocation location | + location = getOperandMemoryLocation(instruction.getAnOperand()) and + ( + key = "OperandMemoryAccess" and result = location.toString() + or + key = "OperandVirtualVariable" and result = location.getVirtualVariable().toString() + ) + ) + or + exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | + hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and + defBlock.getInstruction(defIndex) = instruction and + key = "DefinitionRank[" + useLocation.toString() + "]" and + result = defRank.toString() + ) + or + exists(MemoryLocation useLocation, IRBlock useBlock, int useRank | + hasUseAtRank(useLocation, useBlock, useRank, instruction) and + key = "UseRank[" + useLocation.toString() + "]" and + result = useRank.toString() + ) + or + exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | + hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and + defBlock.getInstruction(defIndex) = instruction and + key = "DefinitionReachesUse[" + useLocation.toString() + "]" and + result = strictconcat(IRBlock useBlock, int useRank, int useIndex | + exists(Instruction useInstruction | + hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and + useBlock.getInstruction(useIndex) = useInstruction and + definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank) + ) + | + useBlock.getDisplayIndex().toString() + "_" + useIndex, ", " + order by + useBlock.getDisplayIndex(), useIndex + ) + ) + } + + override string getBlockProperty(IRBlock block, string key) { + exists(MemoryLocation useLocation, int defRank, int defIndex | + hasDefinitionAtRank(useLocation, _, block, defRank, defIndex) and + defIndex = -1 and + key = "DefinitionRank(Phi)[" + useLocation.toString() + "]" and + result = defRank.toString() + ) + or + exists(MemoryLocation useLocation, MemoryLocation defLocation, int defRank, int defIndex | + hasDefinitionAtRank(useLocation, defLocation, block, defRank, defIndex) and + defIndex = -1 and + key = "DefinitionReachesUse(Phi)[" + useLocation.toString() + "]" and + result = strictconcat(IRBlock useBlock, int useRank, int useIndex | + exists(Instruction useInstruction | + hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and + useBlock.getInstruction(useIndex) = useInstruction and + definitionReachesUse(useLocation, block, defRank, useBlock, useRank) and + exists(getOverlap(defLocation, useLocation)) + ) + | + useBlock.getDisplayIndex().toString() + "_" + useIndex, ", " + order by + useBlock.getDisplayIndex(), useIndex + ) + ) + or + exists( + MemoryLocation useLocation, IRBlock predBlock, IRBlock defBlock, int defIndex, Overlap overlap + | + hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex, overlap) and + key = "PhiUse[" + useLocation.toString() + " from " + predBlock.getDisplayIndex().toString() + + "]" and + result = defBlock.getDisplayIndex().toString() + "_" + defIndex + " (" + overlap.toString() + + ")" + ) + or + key = "LiveOnEntry" and + result = strictconcat(MemoryLocation useLocation | + locationLiveOnEntryToBlock(useLocation, block) + | + useLocation.toString(), ", " order by useLocation.toString() + ) + or + key = "LiveOnExit" and + result = strictconcat(MemoryLocation useLocation | + locationLiveOnExitFromBlock(useLocation, block) + | + useLocation.toString(), ", " order by useLocation.toString() + ) + or + key = "DefsLiveOnEntry" and + result = strictconcat(MemoryLocation defLocation | + definitionLiveOnEntryToBlock(defLocation, block) + | + defLocation.toString(), ", " order by defLocation.toString() + ) + or + key = "DefsLiveOnExit" and + result = strictconcat(MemoryLocation defLocation | + definitionLiveOnExitFromBlock(defLocation, block) + | + defLocation.toString(), ", " order by defLocation.toString() + ) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll new file mode 100644 index 00000000000..1ca6e099795 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -0,0 +1,881 @@ +import SSAConstructionInternal +private import cpp +private import semmle.code.cpp.ir.implementation.Opcode +private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.Overlap +private import NewIR + +private class OldBlock = Reachability::ReachableBlock; + +private class OldInstruction = Reachability::ReachableInstruction; + +import Cached + +cached +private module Cached { + private IRBlock getNewBlock(OldBlock oldBlock) { + result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) + } + + cached + predicate functionHasIR(Function func) { + exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) + } + + cached + OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) } + + private IRVariable getNewIRVariable(OldIR::IRVariable var) { + // This is just a type cast. Both classes derive from the same newtype. + result = var + } + + cached + newtype TInstruction = + WrappedInstruction(OldInstruction oldInstruction) { + not oldInstruction instanceof OldIR::PhiInstruction + } or + Phi(OldBlock block, Alias::MemoryLocation defLocation) { + definitionHasPhiNode(defLocation, block) + } or + Chi(OldInstruction oldInstruction) { + not oldInstruction instanceof OldIR::PhiInstruction and + hasChiNode(_, oldInstruction) + } or + Unreached(Function function) { + exists(OldInstruction oldInstruction | + function = oldInstruction.getEnclosingFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) + } + + cached + predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) { + exists(OldIR::IRTempVariable var | + var.getEnclosingFunction() = func and + var.getAST() = ast and + var.getTag() = tag and + var.getType() = type + ) + } + + cached + predicate hasModeledMemoryResult(Instruction instruction) { + exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or + instruction instanceof PhiInstruction or // Phis always have modeled results + instruction instanceof ChiInstruction // Chis always have modeled results + } + + cached + Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { + exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand | + oldInstruction = getOldInstruction(instruction) and + oldOperand = oldInstruction.getAnOperand() and + tag = oldOperand.getOperandTag() and + result = getNewInstruction(oldOperand.getAnyDef()) + ) + } + + cached + Instruction getMemoryOperandDefinition( + Instruction instruction, MemoryOperandTag tag, Overlap overlap + ) { + exists(OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand | + oldInstruction = getOldInstruction(instruction) and + oldOperand = oldInstruction.getAnOperand() and + tag = oldOperand.getOperandTag() and + ( + ( + if exists(Alias::getOperandMemoryLocation(oldOperand)) + then + exists( + OldBlock useBlock, int useRank, Alias::MemoryLocation useLocation, + Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset + | + useLocation = Alias::getOperandMemoryLocation(oldOperand) and + hasDefinitionAtRank(useLocation, defLocation, defBlock, defRank, defOffset) and + hasUseAtRank(useLocation, useBlock, useRank, oldInstruction) and + definitionReachesUse(useLocation, defBlock, defRank, useBlock, useRank) and + overlap = Alias::getOverlap(defLocation, useLocation) and + result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation) + ) + else ( + result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and + overlap instanceof MustTotallyOverlap + ) + ) + or + // Connect any definitions that are not being modeled in SSA to the + // `UnmodeledUse` instruction. + exists(OldInstruction oldDefinition | + instruction instanceof UnmodeledUseInstruction and + tag instanceof UnmodeledUseOperandTag and + oldDefinition = oldOperand.getAnyDef() and + not exists(Alias::getResultMemoryLocation(oldDefinition)) and + result = getNewInstruction(oldDefinition) and + overlap instanceof MustTotallyOverlap + ) + ) + ) + or + instruction = Chi(getOldInstruction(result)) and + tag instanceof ChiPartialOperandTag and + overlap instanceof MustExactlyOverlap + or + exists(IRFunction f | + tag instanceof UnmodeledUseOperandTag and + result = f.getUnmodeledDefinitionInstruction() and + instruction = f.getUnmodeledUseInstruction() and + overlap instanceof MustTotallyOverlap + ) + or + tag instanceof ChiTotalOperandTag and + result = getChiInstructionTotalOperand(instruction) and + overlap instanceof MustExactlyOverlap + } + + cached + Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) { + exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | + oldInstruction = getOldInstruction(instr) and + oldOperand = oldInstruction.getAnOperand() and + tag = oldOperand.getOperandTag() and + result = oldOperand.getType() + ) + } + + cached + int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) { + exists(OldInstruction oldInstruction, OldIR::SideEffectOperand oldOperand | + oldInstruction = getOldInstruction(instr) and + oldOperand = oldInstruction.getAnOperand() and + tag = oldOperand.getOperandTag() and + // Only return a result for operands that need an explicit result size. + oldOperand.getType() instanceof UnknownType and + result = oldOperand.getSize() + ) + } + + cached + Instruction getPhiOperandDefinition( + PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap + ) { + exists( + Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, + OldBlock predBlock, OldBlock defBlock, int defOffset + | + hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset, + overlap) and + instr = Phi(phiBlock, useLocation) and + newPredecessorBlock = getNewBlock(predBlock) and + result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation) + ) + } + + cached + Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) { + exists( + Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, + OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank + | + chiInstr = Chi(oldInstr) and + vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and + hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and + hasUseAtRank(vvar, useBlock, useRank, oldInstr) and + definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and + result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar) + ) + } + + cached + Instruction getPhiInstructionBlockStart(PhiInstruction instr) { + exists(OldBlock oldBlock | + instr = Phi(oldBlock, _) and + result = getNewInstruction(oldBlock.getFirstInstruction()) + ) + } + + cached + Expr getInstructionConvertedResultExpression(Instruction instruction) { + result = getOldInstruction(instruction).getConvertedResultExpression() + } + + cached + Expr getInstructionUnconvertedResultExpression(Instruction instruction) { + result = getOldInstruction(instruction).getUnconvertedResultExpression() + } + + /** + * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, + * that node is its successor in the new successor relation, and the Chi node's successors are + * the new instructions generated from the successors of the old instruction + */ + cached + Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { + if hasChiNode(_, getOldInstruction(instruction)) + then + result = Chi(getOldInstruction(instruction)) and + kind instanceof GotoEdge + else ( + exists(OldInstruction oldInstruction | + oldInstruction = getOldInstruction(instruction) and + ( + if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) + then result = Unreached(instruction.getEnclosingFunction()) + else result = getNewInstruction(oldInstruction.getSuccessor(kind)) + ) + ) + or + exists(OldInstruction oldInstruction | + instruction = Chi(oldInstruction) and + result = getNewInstruction(oldInstruction.getSuccessor(kind)) + ) + ) + } + + cached + Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { + exists(OldInstruction oldInstruction | + not Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) and + // There is only one case for the translation into `result` because the + // SSA construction never inserts extra instructions _before_ an existing + // instruction. + getOldInstruction(result) = oldInstruction.getBackEdgeSuccessor(kind) and + // There are two cases for the translation into `instruction` because the + // SSA construction might have inserted a chi node _after_ + // `oldInstruction`, in which case the back edge should come out of the + // chi node instead. + if hasChiNode(_, oldInstruction) + then instruction = Chi(oldInstruction) + else instruction = getNewInstruction(oldInstruction) + ) + } + + cached + Locatable getInstructionAST(Instruction instruction) { + exists(OldInstruction oldInstruction | + instruction = WrappedInstruction(oldInstruction) + or + instruction = Chi(oldInstruction) + | + result = oldInstruction.getAST() + ) + or + exists(OldBlock block | + instruction = Phi(block, _) and + result = block.getFirstInstruction().getAST() + ) + or + instruction = Unreached(result) + } + + cached + predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) { + exists(OldInstruction oldInstruction | + instruction = WrappedInstruction(oldInstruction) and + type = oldInstruction.getResultType() and + if oldInstruction.isGLValue() then isGLValue = true else isGLValue = false + ) + or + exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | + instruction = Chi(oldInstruction) and + hasChiNode(vvar, oldInstruction) and + type = vvar.getType() and + isGLValue = false + ) + or + exists(Alias::MemoryLocation location | + instruction = Phi(_, location) and + type = location.getType() and + isGLValue = false + ) + or + instruction = Unreached(_) and + type instanceof VoidType and + isGLValue = false + } + + cached + Opcode getInstructionOpcode(Instruction instruction) { + exists(OldInstruction oldInstruction | + instruction = WrappedInstruction(oldInstruction) and + result = oldInstruction.getOpcode() + ) + or + instruction instanceof Chi and + result instanceof Opcode::Chi + or + instruction instanceof Phi and + result instanceof Opcode::Phi + or + instruction instanceof Unreached and + result instanceof Opcode::Unreached + } + + cached + IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { + exists(OldInstruction oldInstruction | + instruction = WrappedInstruction(oldInstruction) + or + instruction = Chi(oldInstruction) + | + result.getFunction() = oldInstruction.getEnclosingFunction() + ) + or + exists(OldBlock block | + instruction = Phi(block, _) and + result.getFunction() = block.getEnclosingFunction() + ) + or + instruction = Unreached(result.getFunction()) + } + + cached + IRVariable getInstructionVariable(Instruction instruction) { + result = getNewIRVariable(getOldInstruction(instruction) + .(OldIR::VariableInstruction) + .getVariable()) + } + + cached + Field getInstructionField(Instruction instruction) { + result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() + } + + cached + Function getInstructionFunction(Instruction instruction) { + result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() + } + + cached + string getInstructionConstantValue(Instruction instruction) { + result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() + } + + cached + StringLiteral getInstructionStringLiteral(Instruction instruction) { + result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue() + } + + cached + BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { + result = getOldInstruction(instruction) + .(OldIR::BuiltInOperationInstruction) + .getBuiltInOperation() + } + + cached + Type getInstructionExceptionType(Instruction instruction) { + result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() + } + + cached + int getInstructionElementSize(Instruction instruction) { + result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() + } + + cached + int getInstructionResultSize(Instruction instruction) { + // Only return a result for instructions that needed an explicit result size. + instruction.getResultType() instanceof UnknownType and + result = getOldInstruction(instruction).getResultSize() + } + + cached + predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { + exists(OldIR::InheritanceConversionInstruction oldInstr | + oldInstr = getOldInstruction(instruction) and + baseClass = oldInstr.getBaseClass() and + derivedClass = oldInstr.getDerivedClass() + ) + } + + cached + Instruction getPrimaryInstructionForSideEffect(Instruction instruction) { + exists(OldIR::SideEffectInstruction oldInstruction | + oldInstruction = getOldInstruction(instruction) and + result = getNewInstruction(oldInstruction.getPrimaryInstruction()) + ) + or + exists(OldIR::Instruction oldInstruction | + instruction = Chi(oldInstruction) and + result = getNewInstruction(oldInstruction) + ) + } +} + +private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } + +/** + * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition + * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the + * original definition location is a member. + */ +private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) { + exists(Alias::MemoryLocation defLocation | + defLocation = Alias::getResultMemoryLocation(def) and + defLocation.getVirtualVariable() = vvar and + // If the definition totally (or exactly) overlaps the virtual variable, then there's no need for a `Chi` + // instruction. + Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap + ) +} + +private import PhiInsertion + +/** + * Module to handle insertion of `Phi` instructions at the correct blocks. We insert a `Phi` instruction at the + * beginning of a block for a given location when that block is on the dominance frontier of a definition of the + * location and there is a use of that location reachable from that block without an intervening definition of the + * location. + * Within the approach outlined above, we treat a location slightly differently depending on whether or not it is a + * virtual variable. For a virtual variable, we will insert a `Phi` instruction on the dominance frontier if there is + * a use of any member location of that virtual variable that is reachable from the `Phi` instruction. For a location + * that is not a virtual variable, we insert a `Phi` instruction only if there is an exactly-overlapping use of the + * location reachable from the `Phi` instruction. This ensures that we insert a `Phi` instruction for a non-virtual + * variable only if doing so would allow dataflow analysis to get a more precise result than if we just used a `Phi` + * instruction for the virtual variable as a whole. + */ +private module PhiInsertion { + /** + * Holds if a `Phi` instruction needs to be inserted for location `defLocation` at the beginning of block `phiBlock`. + */ + predicate definitionHasPhiNode(Alias::MemoryLocation defLocation, OldBlock phiBlock) { + exists(OldBlock defBlock | + phiBlock = Dominance::getDominanceFrontier(defBlock) and + definitionHasDefinitionInBlock(defLocation, defBlock) and + /* We can also eliminate those nodes where the definition is not live on any incoming edge */ + definitionLiveOnEntryToBlock(defLocation, phiBlock) + ) + } + + /** + * Holds if the memory location `defLocation` has a definition in block `block`, either because of an existing + * instruction, a `Phi` node, or a `Chi` node. + */ + private predicate definitionHasDefinitionInBlock(Alias::MemoryLocation defLocation, OldBlock block) { + definitionHasPhiNode(defLocation, block) + or + exists(OldInstruction def, Alias::MemoryLocation resultLocation | + def.getBlock() = block and + resultLocation = Alias::getResultMemoryLocation(def) and + ( + defLocation = resultLocation + or + // For a virtual variable, any definition of a member location will either generate a `Chi` node that defines + // the virtual variable, or will totally overlap the virtual variable. Either way, treat this as a definition of + // the virtual variable. + defLocation = resultLocation.getVirtualVariable() + ) + ) + } + + /** + * Holds if there is a use at (`block`, `index`) that could consume the result of a `Phi` instruction for + * `defLocation`. + */ + private predicate definitionHasUse(Alias::MemoryLocation defLocation, OldBlock block, int index) { + exists(OldInstruction use | + block.getInstruction(index) = use and + if defLocation instanceof Alias::VirtualVariable + then ( + exists(Alias::MemoryLocation useLocation | + // For a virtual variable, any use of a location that is a member of the virtual variable counts as a use. + useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and + defLocation = useLocation.getVirtualVariable() + ) + or + // A `Chi` instruction consumes the enclosing virtual variable of its use location. + hasChiNode(defLocation, use) + ) else ( + // For other locations, only an exactly-overlapping use of the same location counts as a use. + defLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and + Alias::getOverlap(defLocation, defLocation) instanceof MustExactlyOverlap + ) + ) + } + + /** + * Holds if the location `defLocation` is redefined at (`block`, `index`). A location is considered "redefined" if + * there is a definition that would prevent a previous definition of `defLocation` from being consumed as the operand + * of a `Phi` node that occurs after the redefinition. + */ + private predicate definitionHasRedefinition( + Alias::MemoryLocation defLocation, OldBlock block, int index + ) { + exists(OldInstruction redef, Alias::MemoryLocation redefLocation | + block.getInstruction(index) = redef and + redefLocation = Alias::getResultMemoryLocation(redef) and + if defLocation instanceof Alias::VirtualVariable + then + // For a virtual variable, the definition may be consumed by any use of a location that is a member of the + // virtual variable. Thus, the definition is live until a subsequent redefinition of the entire virtual + // variable. + exists(Overlap overlap | + overlap = Alias::getOverlap(redefLocation, defLocation) and + not overlap instanceof MayPartiallyOverlap + ) + else + // For other locations, the definition may only be consumed by an exactly-overlapping use of the same location. + // Thus, the definition is live until a subsequent definition of any location that may overlap the original + // definition location. + exists(Alias::getOverlap(redefLocation, defLocation)) + ) + } + + /** + * Holds if the definition `defLocation` is live on entry to block `block`. The definition is live if there is at + * least one use of that definition before any intervening instruction that redefines the definition location. + */ + predicate definitionLiveOnEntryToBlock(Alias::MemoryLocation defLocation, OldBlock block) { + exists(int firstAccess | + definitionHasUse(defLocation, block, firstAccess) and + firstAccess = min(int index | + definitionHasUse(defLocation, block, index) + or + definitionHasRedefinition(defLocation, block, index) + ) + ) + or + definitionLiveOnExitFromBlock(defLocation, block) and + not definitionHasRedefinition(defLocation, block, _) + } + + /** + * Holds if the definition `defLocation` is live on exit from block `block`. The definition is live on exit if it is + * live on entry to any of the successors of `block`. + */ + pragma[noinline] + predicate definitionLiveOnExitFromBlock(Alias::MemoryLocation defLocation, OldBlock block) { + definitionLiveOnEntryToBlock(defLocation, block.getAFeasibleSuccessor()) + } +} + +private import DefUse + +/** + * Module containing the predicates that connect uses to their reaching definition. The reaching definitions are + * computed separately for each unique use `MemoryLocation`. An instruction is treated as a definition of a use location + * if the defined location overlaps the use location in any way. Thus, a single instruction may serve as a definition + * for multiple use locations, since a single definition location may overlap many use locations. + * + * Definitions and uses are identified by a block and an integer "offset". An offset of -1 indicates the definition + * from a `Phi` instruction at the beginning of the block. An offset of 2*i indicates a definition or use on the + * instruction at index `i` in the block. An offset of 2*i+1 indicates a definition or use on the `Chi` instruction that + * will be inserted immediately after the instruction at index `i` in the block. + * + * For a given use location, each definition and use is also assigned a "rank" within its block. The rank is simply the + * one-based index of that definition or use within the list of definitions and uses of that location within the block, + * ordered by offset. The rank allows the various reachability predicates to be computed more efficiently than they + * would if based solely on offset, since the set of possible ranks is dense while the set of possible offsets is + * potentially very sparse. + */ +module DefUse { + /** + * Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`. + */ + bindingset[defOffset, defLocation] + pragma[inline] + Instruction getDefinitionOrChiInstruction( + OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation + ) { + defOffset >= 0 and + exists(OldInstruction oldInstr | + oldInstr = defBlock.getInstruction(defOffset / 2) and + if (defOffset % 2) > 0 + then + // An odd offset corresponds to the `Chi` instruction. + result = Chi(oldInstr) + else + // An even offset corresponds to the original instruction. + result = getNewInstruction(oldInstr) + ) + or + defOffset < 0 and + result = Phi(defBlock, defLocation) + } + + /** + * Gets the rank index of a hyphothetical use one instruction past the end of + * the block. This index can be used to determine if a definition reaches the + * end of the block, even if the definition is the last instruction in the + * block. + */ + private int exitRank(Alias::MemoryLocation useLocation, OldBlock block) { + result = max(int rankIndex | defUseRank(useLocation, block, rankIndex, _)) + 1 + } + + /** + * Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at + * (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`, where `defBlock` and + * `useBlock` are the same block. + */ + private predicate definitionReachesUseWithinBlock( + Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock useBlock, + int useRank + ) { + defBlock = useBlock and + hasDefinitionAtRank(useLocation, _, defBlock, defRank, _) and + hasUseAtRank(useLocation, useBlock, useRank, _) and + definitionReachesRank(useLocation, defBlock, defRank, useRank) + } + + /** + * Holds if a definition that overlaps `useLocation` at (`defBlock`, `defRank`) reaches the use of `useLocation` at + * (`useBlock`, `useRank`) without any intervening definitions that overlap `useLocation`. + */ + predicate definitionReachesUse( + Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock useBlock, + int useRank + ) { + hasUseAtRank(useLocation, useBlock, useRank, _) and + ( + definitionReachesUseWithinBlock(useLocation, defBlock, defRank, useBlock, useRank) + or + definitionReachesEndOfBlock(useLocation, defBlock, defRank, useBlock.getAFeasiblePredecessor()) and + not definitionReachesUseWithinBlock(useLocation, useBlock, _, useBlock, useRank) + ) + } + + /** + * Holds if the definition that overlaps `useLocation` at `(block, defRank)` reaches the rank + * index `reachesRank` in block `block`. + */ + private predicate definitionReachesRank( + Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank + ) { + hasDefinitionAtRank(useLocation, _, block, defRank, _) and + reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite. + ( + // The def always reaches the next use, even if there is also a def on the + // use instruction. + reachesRank = defRank + 1 + or + // If the def reached the previous rank, it also reaches the current rank, + // unless there was another def at the previous rank. + definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and + not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _) + ) + } + + /** + * Holds if the definition that overlaps `useLocation` at `(defBlock, defRank)` reaches the end of + * block `block` without any intervening definitions that overlap `useLocation`. + */ + predicate definitionReachesEndOfBlock( + Alias::MemoryLocation useLocation, OldBlock defBlock, int defRank, OldBlock block + ) { + hasDefinitionAtRank(useLocation, _, defBlock, defRank, _) and + ( + // If we're looking at the def's own block, just see if it reaches the exit + // rank of the block. + block = defBlock and + locationLiveOnExitFromBlock(useLocation, defBlock) and + definitionReachesRank(useLocation, defBlock, defRank, exitRank(useLocation, defBlock)) + or + exists(OldBlock idom | + definitionReachesEndOfBlock(useLocation, defBlock, defRank, idom) and + noDefinitionsSinceIDominator(useLocation, idom, block) + ) + ) + } + + pragma[noinline] + private predicate noDefinitionsSinceIDominator( + Alias::MemoryLocation useLocation, OldBlock idom, OldBlock block + ) { + Dominance::blockImmediatelyDominates(idom, block) and // It is sufficient to traverse the dominator graph, cf. discussion above. + locationLiveOnExitFromBlock(useLocation, block) and + not hasDefinition(useLocation, _, block, _) + } + + /** + * Holds if the specified `useLocation` is live on entry to `block`. This holds if there is a use of `useLocation` + * that is reachable from the start of `block` without passing through a definition that overlaps `useLocation`. + * Note that even a partially-overlapping definition blocks liveness, because such a definition will insert a `Chi` + * instruction whose result totally overlaps the location. + */ + predicate locationLiveOnEntryToBlock(Alias::MemoryLocation useLocation, OldBlock block) { + definitionHasPhiNode(useLocation, block) + or + exists(int firstAccess | + hasUse(useLocation, block, firstAccess, _) and + firstAccess = min(int offset | + hasUse(useLocation, block, offset, _) + or + hasNonPhiDefinition(useLocation, _, block, offset) + ) + ) + or + locationLiveOnExitFromBlock(useLocation, block) and + not hasNonPhiDefinition(useLocation, _, block, _) + } + + /** + * Holds if the specified `useLocation` is live on exit from `block`. + */ + pragma[noinline] + predicate locationLiveOnExitFromBlock(Alias::MemoryLocation useLocation, OldBlock block) { + locationLiveOnEntryToBlock(useLocation, block.getAFeasibleSuccessor()) + } + + /** + * Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`. + * This predicate does not include definitions for Phi nodes. + */ + private predicate hasNonPhiDefinition( + Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block, int offset + ) { + exists(OldInstruction def, Overlap overlap, int index | + defLocation = Alias::getResultMemoryLocation(def) and + block.getInstruction(index) = def and + overlap = Alias::getOverlap(defLocation, useLocation) and + if overlap instanceof MayPartiallyOverlap + then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction. + else offset = index * 2 // The use will be connected to the definition on the original instruction. + ) + } + + /** + * Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`. + * This predicate includes definitions for Phi nodes (at offset -1). + */ + private predicate hasDefinition( + Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block, int offset + ) { + ( + // If there is a Phi node for the use location itself, treat that as a definition at offset -1. + offset = -1 and + if definitionHasPhiNode(useLocation, block) + then defLocation = useLocation + else ( + definitionHasPhiNode(defLocation, block) and + defLocation = useLocation.getVirtualVariable() + ) + ) + or + hasNonPhiDefinition(useLocation, defLocation, block, offset) + } + + /** + * Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`. + * `rankIndex` is the rank of the definition as computed by `defUseRank()`. + */ + predicate hasDefinitionAtRank( + Alias::MemoryLocation useLocation, Alias::MemoryLocation defLocation, OldBlock block, + int rankIndex, int offset + ) { + hasDefinition(useLocation, defLocation, block, offset) and + defUseRank(useLocation, block, rankIndex, offset) + } + + /** + * Holds if there is a use of `useLocation` on instruction `use` at offset `offset` in block `block`. + */ + private predicate hasUse( + Alias::MemoryLocation useLocation, OldBlock block, int offset, OldInstruction use + ) { + exists(int index | + block.getInstruction(index) = use and + ( + // A direct use of the location. + useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2 + or + // A `Chi` instruction will include a use of the virtual variable. + hasChiNode(useLocation, use) and offset = (index * 2) + 1 + ) + ) + } + + /** + * Holds if there is a use of memory location `useLocation` on instruction `use` in block `block`. `rankIndex` is the + * rank of the use use as computed by `defUseRank`. + */ + predicate hasUseAtRank( + Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, OldInstruction use + ) { + exists(int offset | + hasUse(useLocation, block, offset, use) and + defUseRank(useLocation, block, rankIndex, offset) + ) + } + + /** + * Holds if there is a definition at offset `offset` in block `block` that overlaps memory location `useLocation`, or + * a use of `useLocation` at offset `offset` in block `block`. `rankIndex` is the sequence number of the definition + * or use within `block`, counting only uses of `useLocation` and definitions that overlap `useLocation`. + */ + private predicate defUseRank( + Alias::MemoryLocation useLocation, OldBlock block, int rankIndex, int offset + ) { + offset = rank[rankIndex](int j | + hasDefinition(useLocation, _, block, j) or hasUse(useLocation, block, j, _) + ) + } + + /** + * Holds if the `Phi` instruction for location `useLocation` at the beginning of block `phiBlock` has an operand along + * the incoming edge from `predBlock`, where that operand's definition is at offset `defOffset` in block `defBlock`, + * and overlaps the use operand with overlap relationship `overlap`. + */ + pragma[inline] + predicate hasPhiOperandDefinition( + Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, + OldBlock predBlock, OldBlock defBlock, int defOffset, Overlap overlap + ) { + exists(int defRank | + definitionHasPhiNode(useLocation, phiBlock) and + predBlock = phiBlock.getAFeasiblePredecessor() and + hasDefinitionAtRank(useLocation, defLocation, defBlock, defRank, defOffset) and + definitionReachesEndOfBlock(useLocation, defBlock, defRank, predBlock) and + overlap = Alias::getOverlap(defLocation, useLocation) + ) + } +} + +/** + * Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the + * `DebugSSA` module, which is then imported by PrintSSA. + */ +module DebugSSA { + import PhiInsertion + import DefUse +} + +import CachedForDebugging + +cached +private module CachedForDebugging { + cached + string getTempVariableUniqueId(IRTempVariable var) { + result = getOldTempVariable(var).getUniqueId() + } + + cached + string getInstructionUniqueId(Instruction instr) { + exists(OldInstruction oldInstr | + oldInstr = getOldInstruction(instr) and + result = "NonSSA: " + oldInstr.getUniqueId() + ) + or + exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | + instr = Phi(phiBlock, location) and + result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + + location.getUniqueId() and + if location instanceof Alias::VirtualVariable + then + // Sort Phi nodes for virtual variables before Phi nodes for member locations. + specificity = "g" + else specificity = "s" + ) + or + instr = Unreached(_) and + result = "Unreached" + } + + private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) { + result.getEnclosingFunction() = var.getEnclosingFunction() and + result.getAST() = var.getAST() and + result.getTag() = var.getTag() + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll new file mode 100644 index 00000000000..dc19a8130d9 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -0,0 +1,5 @@ +import semmle.code.cpp.ir.implementation.raw.IR as OldIR +import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability +import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance +import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR +import SimpleSSA as Alias diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll new file mode 100644 index 00000000000..7cca5855a20 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -0,0 +1,87 @@ +import AliasAnalysis +private import cpp +private import semmle.code.cpp.ir.implementation.raw.IR +private import semmle.code.cpp.ir.internal.IntegerConstant as Ints +private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.Overlap + +private class IntValue = Ints::IntValue; + +private predicate hasResultMemoryAccess( + Instruction instr, IRVariable var, Type type, IntValue bitOffset +) { + resultPointsTo(instr.getResultAddressOperand().getAnyDef(), var, bitOffset) and + type = instr.getResultType() +} + +private predicate hasOperandMemoryAccess( + MemoryOperand operand, IRVariable var, Type type, IntValue bitOffset +) { + resultPointsTo(operand.getAddressOperand().getAnyDef(), var, bitOffset) and + type = operand.getType() +} + +/** + * Holds if the specified variable should be modeled in SSA form. For unaliased SSA, we only model a variable if its + * address never escapes and all reads and writes of that variable access the entire variable using the original type + * of the variable. + */ +private predicate isVariableModeled(IRVariable var) { + not variableAddressEscapes(var) and + // There's no need to check for the right size. An `IRVariable` never has an `UnknownType`, so the test for + // `type = var.getType()` is sufficient. + forall(Instruction instr, Type type, IntValue bitOffset | + hasResultMemoryAccess(instr, var, type, bitOffset) + | + bitOffset = 0 and + type = var.getType() + ) and + forall(MemoryOperand operand, Type type, IntValue bitOffset | + hasOperandMemoryAccess(operand, var, type, bitOffset) + | + bitOffset = 0 and + type = var.getType() + ) +} + +private newtype TMemoryLocation = MkMemoryLocation(IRVariable var) { isVariableModeled(var) } + +private MemoryLocation getMemoryLocation(IRVariable var) { result.getIRVariable() = var } + +class MemoryLocation extends TMemoryLocation { + IRVariable var; + + MemoryLocation() { this = MkMemoryLocation(var) } + + final string toString() { result = var.toString() } + + final IRVariable getIRVariable() { result = var } + + final VirtualVariable getVirtualVariable() { result = this } + + final Type getType() { result = var.getType() } + + final string getUniqueId() { result = var.getUniqueId() } +} + +class VirtualVariable extends MemoryLocation { } + +Overlap getOverlap(MemoryLocation def, MemoryLocation use) { + def = use and result instanceof MustExactlyOverlap + or + none() // Avoid compiler error in SSAConstruction +} + +MemoryLocation getResultMemoryLocation(Instruction instr) { + exists(IRVariable var | + hasResultMemoryAccess(instr, var, _, _) and + result = getMemoryLocation(var) + ) +} + +MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { + exists(IRVariable var | + hasOperandMemoryAccess(operand, var, _, _) and + result = getMemoryLocation(var) + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll new file mode 100644 index 00000000000..cddc3e23d7e --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll @@ -0,0 +1,22 @@ +private import DominanceInternal + +predicate blockImmediatelyDominates(Graph::Block dominator, Graph::Block block) = + idominance(Graph::isEntryBlock/1, Graph::blockSuccessor/2)(_, dominator, block) + +predicate blockStrictlyDominates(Graph::Block dominator, Graph::Block block) { + blockImmediatelyDominates+(dominator, block) +} + +predicate blockDominates(Graph::Block dominator, Graph::Block block) { + blockStrictlyDominates(dominator, block) or dominator = block +} + +Graph::Block getDominanceFrontier(Graph::Block dominator) { + Graph::blockSuccessor(dominator, result) and + not blockImmediatelyDominates(dominator, result) + or + exists(Graph::Block prev | result = getDominanceFrontier(prev) | + blockImmediatelyDominates(dominator, prev) and + not blockImmediatelyDominates(dominator, result) + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll new file mode 100644 index 00000000000..cee8fa1543b --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll @@ -0,0 +1,9 @@ +private import ReachableBlock as Reachability + +private module ReachabilityGraph = Reachability::Graph; + +module Graph { + import Reachability::Graph + + class Block = Reachability::ReachableBlock; +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll new file mode 100644 index 00000000000..71a3a88ef8d --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll @@ -0,0 +1,21 @@ +private import DominanceInternal +private import ReachableBlockInternal +private import Dominance +import IR + +private class DominancePropertyProvider extends IRPropertyProvider { + override string getBlockProperty(IRBlock block, string key) { + exists(IRBlock dominator | + blockImmediatelyDominates(dominator, block) and + key = "ImmediateDominator" and + result = "Block " + dominator.getDisplayIndex().toString() + ) + or + key = "DominanceFrontier" and + result = strictconcat(IRBlock frontierBlock | + frontierBlock = getDominanceFrontier(block) + | + frontierBlock.getDisplayIndex().toString(), ", " order by frontierBlock.getDisplayIndex() + ) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll new file mode 100644 index 00000000000..6befad72336 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll @@ -0,0 +1,17 @@ +private import ReachableBlockInternal +private import ReachableBlock +import IR + +private class ReachableBlockPropertyProvider extends IRPropertyProvider { + override string getBlockProperty(IRBlock block, string key) { + not block instanceof ReachableBlock and + key = "Unreachable" and + result = "true" + or + exists(EdgeKind kind | + isInfeasibleEdge(block, kind) and + key = "Infeasible(" + kind.toString() + ")" and + result = "true" + ) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll new file mode 100644 index 00000000000..25a53bbefe8 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll @@ -0,0 +1,53 @@ +private import ReachableBlockInternal +private import IR +private import ConstantAnalysis + +predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) { + exists(int conditionValue | + conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and + if conditionValue = 0 then kind instanceof TrueEdge else kind instanceof FalseEdge + ) +} + +pragma[noinline] +predicate isInfeasibleEdge(IRBlockBase block, EdgeKind kind) { + isInfeasibleInstructionSuccessor(block.getLastInstruction(), kind) +} + +private IRBlock getAFeasiblePredecessorBlock(IRBlock successor) { + exists(EdgeKind kind | + result.getSuccessor(kind) = successor and + not isInfeasibleEdge(result, kind) + ) +} + +private predicate isBlockReachable(IRBlock block) { + exists(IRFunction f | getAFeasiblePredecessorBlock*(block) = f.getEntryBlock()) +} + +/** + * An IR block that is reachable from the entry block of the function, considering only feasible + * edges. + */ +class ReachableBlock extends IRBlockBase { + ReachableBlock() { isBlockReachable(this) } + + final ReachableBlock getAFeasiblePredecessor() { result = getAFeasiblePredecessorBlock(this) } + + final ReachableBlock getAFeasibleSuccessor() { this = getAFeasiblePredecessorBlock(result) } +} + +/** + * An instruction that is contained in a reachable block. + */ +class ReachableInstruction extends Instruction { + ReachableInstruction() { this.getBlock() instanceof ReachableBlock } +} + +module Graph { + predicate isEntryBlock(ReachableBlock block) { exists(IRFunction f | block = f.getEntryBlock()) } + + predicate blockSuccessor(ReachableBlock pred, ReachableBlock succ) { + succ = pred.getAFeasibleSuccessor() + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll new file mode 100644 index 00000000000..61dc1a50399 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR +import semmle.code.cpp.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis From 17e6b80a34dff5b95ace012649b436dc914cae26 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Mon, 23 Sep 2019 15:27:15 +0100 Subject: [PATCH 0210/1227] Added C# implementation --- csharp/ql/src/semmle/code/csharp/ir/IR.qll | 2 +- .../semmle/code/csharp/ir/IRConfiguration.qll | 4 +- .../ql/src/semmle/code/csharp/ir/PrintIR.ql | 2 +- .../ql/src/semmle/code/csharp/ir/PrintIR.qll | 2 +- .../semmle/code/csharp/ir/ValueNumbering.qll | 2 +- .../constant/ConstantAnalysis.qll | 2 +- .../constant/PrintConstantAnalysis.qll | 2 +- .../internal/ConstantAnalysisInternal.qll | 2 +- .../unaliased_ssa/gvn/ValueNumbering.qll | 2 +- .../gvn/internal/ValueNumberingInternal.qll | 2 +- .../unaliased_ssa/internal/AliasAnalysis.qll | 159 +++++++++--------- .../internal/AliasAnalysisInternal.qll | 2 +- .../unaliased_ssa/internal/IRBlockImports.qll | 2 +- .../unaliased_ssa/internal/IRImports.qll | 4 +- .../unaliased_ssa/internal/IRInternal.qll | 2 +- .../internal/IRVariableImports.qll | 8 +- .../internal/InstructionImports.qll | 8 +- .../unaliased_ssa/internal/OperandImports.qll | 6 +- .../unaliased_ssa/internal/PrintIRImports.qll | 2 +- .../internal/SSAConstruction.qll | 51 +++--- .../internal/SSAConstructionInternal.qll | 8 +- .../unaliased_ssa/internal/SimpleSSA.qll | 10 +- .../ir/ir/unaliased_ssa_sanity.expected | 15 ++ .../ir/ir/unaliased_ssa_sanity.qlref | 1 + 24 files changed, 163 insertions(+), 137 deletions(-) create mode 100644 csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected create mode 100644 csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref diff --git a/csharp/ql/src/semmle/code/csharp/ir/IR.qll b/csharp/ql/src/semmle/code/csharp/ir/IR.qll index eab1ca1aee9..24eaa1efd85 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/IR.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/IR.qll @@ -3,4 +3,4 @@ * publicly as the "IR". */ -import implementation.raw.IR +import implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll b/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll index a76d0457c0b..a6b2deb9cb0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll @@ -15,5 +15,7 @@ class IRConfiguration extends TIRConfiguration { /** * Holds if IR should be created for callable `callable`. By default, holds for all callables. */ - predicate shouldCreateIRForFunction(Callable callable) { any() } + predicate shouldCreateIRForFunction(Callable callable) { + callable.getLocation().getFile().getExtension() = "cs" + } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql b/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql index be1474d7b1c..c9c836fa252 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql +++ b/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql @@ -5,4 +5,4 @@ * @kind graph */ -import implementation.raw.PrintIR +import implementation.unaliased_ssa.PrintIR diff --git a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.qll b/csharp/ql/src/semmle/code/csharp/ir/PrintIR.qll index aa71fa09584..711c134210c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/PrintIR.qll @@ -1 +1 @@ -import implementation.raw.PrintIR +import implementation.unaliased_ssa.PrintIR diff --git a/csharp/ql/src/semmle/code/csharp/ir/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/ValueNumbering.qll index 2e535f60b44..f6cdc912a12 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/ValueNumbering.qll @@ -1 +1 @@ -import implementation.raw.gvn.ValueNumbering +import implementation.unaliased_ssa.gvn.ValueNumbering diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll index 40076b817a1..f9e1cc7f412 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.cpp.ir.internal.IntegerPartial +private import semmle.code.csharp.ir.internal.IntegerPartial private import IR language[monotonicAggregates] diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll index 57a7cf594ca..1145d5bb2ab 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.cpp.ir.internal.IntegerConstant +private import semmle.code.csharp.ir.internal.IntegerConstant private import ConstantAnalysis import IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll index 9b4f813a10b..188c68483ad 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll @@ -1 +1 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR +import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index e3e52df8931..53b4f5c9647 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -1,5 +1,5 @@ private import internal.ValueNumberingInternal -private import cpp +private import csharp private import IR /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll index 9b4f813a10b..188c68483ad 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -1 +1 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR +import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index dc50ef01354..4bb9f75d182 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -1,8 +1,7 @@ private import AliasAnalysisInternal -private import cpp +private import csharp private import InputIR -private import semmle.code.cpp.ir.internal.IntegerConstant as Ints -private import semmle.code.cpp.models.interfaces.Alias +private import semmle.code.csharp.ir.internal.IntegerConstant as Ints private class IntValue = Ints::IntValue; @@ -26,17 +25,16 @@ string getBitOffsetString(IntValue bitOffset) { else result = "+?" } +///** +// * Gets the offset of field `field` in bits. +// */ +//private IntValue getFieldBitOffset(Field field) { +// if field instanceof BitField +// then result = Ints::add(Ints::mul(field.getByteOffset(), 8), field.(BitField).getBitOffset()) +// else result = Ints::mul(field.getByteOffset(), 8) +//} /** - * Gets the offset of field `field` in bits. - */ -private IntValue getFieldBitOffset(Field field) { - if field instanceof BitField - then result = Ints::add(Ints::mul(field.getByteOffset(), 8), field.(BitField).getBitOffset()) - else result = Ints::mul(field.getByteOffset(), 8) -} - -/** - * Holds if the operand `tag` of instruction `instr` is used in a way that does + * Holds if the operand `operand` of instruction `instr` is used in a way that does * not result in any address held in that operand from escaping beyond the * instruction. */ @@ -53,21 +51,18 @@ private predicate operandIsConsumedWithoutEscaping(Operand operand) { or // Neither operand of a PointerDiff escapes. instr instanceof PointerDiffInstruction - or - // Converting an address to a `bool` does not escape the address. - instr.(ConvertInstruction).getResultType() instanceof BoolType ) ) - or - // Some standard function arguments never escape - isNeverEscapesArgument(operand) + // or + // // Some standard function arguments never escape + // isNeverEscapesArgument(operand) } private predicate operandEscapesDomain(Operand operand) { not operandIsConsumedWithoutEscaping(operand) and not operandIsPropagated(operand, _) and not isArgumentForParameter(_, operand, _) and - not isOnlyEscapesViaReturnArgument(operand) and + // not isOnlyEscapesViaReturnArgument(operand) and not operand.getUse() instanceof ReturnValueInstruction and not operand instanceof PhiInputOperand } @@ -99,7 +94,7 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) { } /** - * Holds if any address held in operand `tag` of instruction `instr` is + * Holds if any address held in operand `operand` of instruction `instr` is * propagated to the result of `instr`, offset by the number of bits in * `bitOffset`. If the address is propagated, but the offset is not known to be * a constant, then `bitOffset` is unknown. @@ -108,29 +103,36 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) { exists(Instruction instr | instr = operand.getUse() and ( - // Converting to a non-virtual base class adds the offset of the base class. - exists(ConvertToBaseInstruction convert | - convert = instr and - bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8) - ) - or - // Converting to a derived class subtracts the offset of the base class. - exists(ConvertToDerivedInstruction convert | - convert = instr and - bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8)) - ) - or - // Converting to a virtual base class adds an unknown offset. - instr instanceof ConvertToVirtualBaseInstruction and - bitOffset = Ints::unknown() - or + // REVIEW: See the REVIEW comment bellow + // // Converting to a non-virtual base class adds the offset of the base class. + // exists(ConvertToBaseInstruction convert | + // convert = instr and + // bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8) + // ) + // or + // // Converting to a derived class subtracts the offset of the base class. + // exists(ConvertToDerivedInstruction convert | + // convert = instr and + // bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8)) + // ) + // or + // // Converting to a virtual base class adds an unknown offset. + // instr instanceof ConvertToVirtualBaseInstruction and + // bitOffset = Ints::unknown() + // or + // REVIEW: In the C# IR, we should ignore the above types of conversion all together, + // since first of all they do not provide correct information (nothing is known + // for sure about heap allocated objects) and second of all even if we create a + // virtual memory model for the IR I don't think such conversions provide any meaningful + // information; // Conversion to another pointer type propagates the source address. + // REVIEW: Is this needed? exists(ConvertInstruction convert, Type resultType | convert = instr and resultType = convert.getResultType() and ( resultType instanceof PointerType or - resultType instanceof Class //REVIEW: Remove when all glvalues are pointers + resultType instanceof RefType ) and bitOffset = 0 ) @@ -139,15 +141,15 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) { // the address with an offset. bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or - // Computing a field address from a pointer propagates the address plus the - // offset of the field. - bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) - or + // or + // // Computing a field address from a pointer propagates the address plus the + // // offset of the field. + // bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) // A copy propagates the source value. operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0 - or - // Some functions are known to propagate an argument - isAlwaysReturnedArgument(operand) and bitOffset = 0 + // or + // // Some functions are known to propagate an argument + // isAlwaysReturnedArgument(operand) and bitOffset = 0 ) ) } @@ -167,8 +169,8 @@ private predicate operandEscapesNonReturn(Operand operand) { ) ) or - isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse()) - or + // or + // isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse()) operand instanceof PhiInputOperand and resultEscapesNonReturn(operand.getUse()) or @@ -190,8 +192,8 @@ private predicate operandMayReachReturn(Operand operand) { // The address is returned operand.getUse() instanceof ReturnValueInstruction or - isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse()) - or + // or + // isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse()) operand instanceof PhiInputOperand and resultMayReachReturn(operand.getUse()) } @@ -216,49 +218,50 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { operand.getUse() instanceof ReturnValueInstruction and bitOffset = 0 or - isOnlyEscapesViaReturnArgument(operand) and + // isOnlyEscapesViaReturnArgument(operand) and resultReturned(operand.getUse(), _) and bitOffset = Ints::unknown() } private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { - exists(Function f | + exists(Callable c | ci = operand.getUse() and - f = ci.getStaticCallTarget() and + c = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = f + init.(InitializeParameterInstruction).getParameter() = c .getParameter(operand.(PositionalArgumentOperand).getIndex()) or init instanceof InitializeThisInstruction and - init.getEnclosingFunction() = f and + init.getEnclosingFunction() = c and operand instanceof ThisArgumentOperand - ) and - not f.isVirtual() and - not f instanceof AliasFunction - ) -} - -private predicate isAlwaysReturnedArgument(Operand operand) { - exists(AliasFunction f | - f = operand.getUse().(CallInstruction).getStaticCallTarget() and - f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex()) - ) -} - -private predicate isOnlyEscapesViaReturnArgument(Operand operand) { - exists(AliasFunction f | - f = operand.getUse().(CallInstruction).getStaticCallTarget() and - f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex()) - ) -} - -private predicate isNeverEscapesArgument(Operand operand) { - exists(AliasFunction f | - f = operand.getUse().(CallInstruction).getStaticCallTarget() and - f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex()) + ) // and + // not f.isVirtual() and + // not f instanceof AliasFunction ) } +// REVIEW: Those three predicates are used to model the behaviour of C++ library functions +// for which the code was not accessible, so we should ignore them +//private predicate isAlwaysReturnedArgument(Operand operand) { +// exists(AliasFunction f | +// f = operand.getUse().(CallInstruction).getStaticCallTarget() and +// f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex()) +// ) +//} +// +//private predicate isOnlyEscapesViaReturnArgument(Operand operand) { +// exists(AliasFunction f | +// f = operand.getUse().(CallInstruction).getStaticCallTarget() and +// f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex()) +// ) +//} +// +//private predicate isNeverEscapesArgument(Operand operand) { +// exists(AliasFunction f | +// f = operand.getUse().(CallInstruction).getStaticCallTarget() and +// f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex()) +// ) +//} private predicate resultReturned(Instruction instr, IntValue bitOffset) { operandReturned(instr.getAUse(), bitOffset) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll index 8a9e43e14a3..64d671c76c4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll @@ -1 +1 @@ -import semmle.code.cpp.ir.implementation.raw.IR as InputIR +import semmle.code.csharp.ir.implementation.raw.IR as InputIR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll index d1b46ed35c8..9aa0d93de1f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll @@ -1 +1 @@ -import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll index 74f7b4a2b64..b5abc1049f3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll @@ -1,2 +1,2 @@ -import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll index ff26415fd43..bd89bcdbdc9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll @@ -1,2 +1,2 @@ -import semmle.code.cpp.ir.internal.IRCppLanguage as Language +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language import SSAConstruction as Construction diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll index 1f0f5eaccde..20c299416ef 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll @@ -1,4 +1,4 @@ -import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag -import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities -import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag -import semmle.code.cpp.ir.implementation.internal.TIRVariable as TIRVariable +import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag +import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities +import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag +import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll index 0138af075dc..da9b8e6e877 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll @@ -1,4 +1,4 @@ -import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.cpp.ir.implementation.Opcode as Opcode -import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import semmle.code.csharp.ir.implementation.Opcode as Opcode +import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll index e626662ccf2..13667df7276 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll @@ -1,3 +1,3 @@ -import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.cpp.ir.internal.Overlap as Overlap -import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import semmle.code.csharp.ir.internal.Overlap as Overlap +import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll index 46254a6e3f2..a74b4bffbc4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll @@ -1 +1 @@ -import semmle.code.cpp.ir.IRConfiguration as IRConfiguration +import semmle.code.csharp.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 1ca6e099795..8f2ed18f060 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,9 +1,9 @@ import SSAConstructionInternal -private import cpp -private import semmle.code.cpp.ir.implementation.Opcode -private import semmle.code.cpp.ir.implementation.internal.OperandTag -private import semmle.code.cpp.ir.internal.Overlap +private import semmle.code.csharp.ir.implementation.Opcode +private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.Overlap private import NewIR +private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language private class OldBlock = Reachability::ReachableBlock; @@ -18,7 +18,7 @@ private module Cached { } cached - predicate functionHasIR(Function func) { + predicate functionHasIR(Language::Function func) { exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) } @@ -42,7 +42,7 @@ private module Cached { not oldInstruction instanceof OldIR::PhiInstruction and hasChiNode(_, oldInstruction) } or - Unreached(Function function) { + Unreached(Language::Function function) { exists(OldInstruction oldInstruction | function = oldInstruction.getEnclosingFunction() and Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) @@ -50,7 +50,9 @@ private module Cached { } cached - predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) { + predicate hasTempVariable( + Language::Function func, Language::AST ast, TempVariableTag tag, Language::Type type + ) { exists(OldIR::IRTempVariable var | var.getEnclosingFunction() = func and var.getAST() = ast and @@ -135,7 +137,7 @@ private module Cached { } cached - Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) { + Language::Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) { exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | oldInstruction = getOldInstruction(instr) and oldOperand = oldInstruction.getAnOperand() and @@ -151,7 +153,7 @@ private module Cached { oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and // Only return a result for operands that need an explicit result size. - oldOperand.getType() instanceof UnknownType and + oldOperand.getType() instanceof Language::UnknownType and result = oldOperand.getSize() ) } @@ -196,20 +198,21 @@ private module Cached { } cached - Expr getInstructionConvertedResultExpression(Instruction instruction) { + Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { result = getOldInstruction(instruction).getConvertedResultExpression() } cached - Expr getInstructionUnconvertedResultExpression(Instruction instruction) { + Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { result = getOldInstruction(instruction).getUnconvertedResultExpression() } - /** + /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are * the new instructions generated from the successors of the old instruction */ + cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) @@ -252,7 +255,7 @@ private module Cached { } cached - Locatable getInstructionAST(Instruction instruction) { + Language::AST getInstructionAST(Instruction instruction) { exists(OldInstruction oldInstruction | instruction = WrappedInstruction(oldInstruction) or @@ -270,7 +273,7 @@ private module Cached { } cached - predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) { + predicate instructionHasType(Instruction instruction, Language::Type type, boolean isGLValue) { exists(OldInstruction oldInstruction | instruction = WrappedInstruction(oldInstruction) and type = oldInstruction.getResultType() and @@ -291,7 +294,7 @@ private module Cached { ) or instruction = Unreached(_) and - type instanceof VoidType and + type instanceof Language::VoidType and isGLValue = false } @@ -338,12 +341,12 @@ private module Cached { } cached - Field getInstructionField(Instruction instruction) { + Language::Field getInstructionField(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() } cached - Function getInstructionFunction(Instruction instruction) { + Language::Function getInstructionFunction(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() } @@ -353,19 +356,19 @@ private module Cached { } cached - StringLiteral getInstructionStringLiteral(Instruction instruction) { + Language::StringLiteral getInstructionStringLiteral(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue() } cached - BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { + Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { result = getOldInstruction(instruction) .(OldIR::BuiltInOperationInstruction) .getBuiltInOperation() } cached - Type getInstructionExceptionType(Instruction instruction) { + Language::Type getInstructionExceptionType(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() } @@ -377,12 +380,14 @@ private module Cached { cached int getInstructionResultSize(Instruction instruction) { // Only return a result for instructions that needed an explicit result size. - instruction.getResultType() instanceof UnknownType and + instruction.getResultType() instanceof Language::UnknownType and result = getOldInstruction(instruction).getResultSize() } cached - predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { + predicate getInstructionInheritance( + Instruction instruction, Language::Class baseClass, Language::Class derivedClass + ) { exists(OldIR::InheritanceConversionInstruction oldInstr | oldInstr = getOldInstruction(instruction) and baseClass = oldInstr.getBaseClass() and @@ -834,7 +839,7 @@ module DefUse { } /** - * Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the + * Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the * `DebugSSA` module, which is then imported by PrintSSA. */ module DebugSSA { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index dc19a8130d9..a4ced8d6d7c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -1,5 +1,5 @@ -import semmle.code.cpp.ir.implementation.raw.IR as OldIR -import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability -import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance -import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR +import semmle.code.csharp.ir.implementation.raw.IR as OldIR +import semmle.code.csharp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability +import semmle.code.csharp.ir.implementation.raw.internal.reachability.Dominance as Dominance +import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as NewIR import SimpleSSA as Alias diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index 7cca5855a20..42f582f7df2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -1,9 +1,9 @@ import AliasAnalysis -private import cpp -private import semmle.code.cpp.ir.implementation.raw.IR -private import semmle.code.cpp.ir.internal.IntegerConstant as Ints -private import semmle.code.cpp.ir.implementation.internal.OperandTag -private import semmle.code.cpp.ir.internal.Overlap +private import csharp +private import semmle.code.csharp.ir.implementation.raw.IR +private import semmle.code.csharp.ir.internal.IntegerConstant as Ints +private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.Overlap private class IntValue = Ints::IntValue; diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected new file mode 100644 index 00000000000..ae680785ce6 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -0,0 +1,15 @@ +missingOperand +unexpectedOperand +duplicateOperand +missingPhiOperand +missingOperandType +instructionWithoutSuccessor +ambiguousSuccessors +unexplainedLoop +unnecessaryPhiInstruction +operandAcrossFunctions +instructionWithoutUniqueBlock +containsLoopOfForwardEdges +lostReachability +backEdgeCountMismatch +useNotDominatedByDefinition diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref new file mode 100644 index 00000000000..4ee5a4fdd33 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref @@ -0,0 +1 @@ +semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql From c156d6a5551c07354a581fa5c827f4f9217522cb Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Mon, 23 Sep 2019 17:34:08 +0100 Subject: [PATCH 0211/1227] Autoformat QL --- docs/language/learn-ql/ql-etudes/river-crossing-1.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql index 8ad670cc7a3..ae218f37e82 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql +++ b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql @@ -76,7 +76,7 @@ class State extends string { exists(int stepsSoFar, string pathSoFar, Cargo cargo | result = this.reachesVia(pathSoFar, stepsSoFar).safeFerry(cargo) and steps = stepsSoFar + 1 and - // We expect a solution in 7 steps, but you can choose any value here. + // We expect a solution in 7 steps, but you can choose any value here. steps <= 7 and path = pathSoFar + "\n Ferry " + cargo ) From a86a15d2809e383b69f67063f59254d99012b890 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Mon, 23 Sep 2019 17:13:07 +0100 Subject: [PATCH 0212/1227] Fix problem with `IsExpr` The translation of `IsExpr` created a sanity check to fail since it generated a Phi node that had only one source: if a variable was declared as part of the `IsExpr`, a conditional branch was generated, and the variable was defined only in the true successor; this has been changes so that the declaration happens before the conditional branch, and the variable is uninitialized (this removed the need for the `isInitializedByElement` predicate from `TranslatedDeclarationBase`, so that has been removed) and only the assignment happens in the true successor block (so now the two inputs of the Phi node are the result of the `Uninitialized` instruction and the `Store` instruction from the true successor block). --- .../semmle/code/csharp/ir/IRConfiguration.qll | 2 +- .../raw/internal/TranslatedDeclaration.qll | 2 -- .../raw/internal/TranslatedExpr.qll | 14 ++++++------- .../common/TranslatedDeclarationBase.qll | 20 +++---------------- ...TranslatedCompilerGeneratedDeclaration.qll | 4 ---- .../test/library-tests/ir/ir/raw_ir.expected | 11 +++++----- 6 files changed, 17 insertions(+), 36 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll b/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll index a6b2deb9cb0..8d9fdec751d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll @@ -15,7 +15,7 @@ class IRConfiguration extends TIRConfiguration { /** * Holds if IR should be created for callable `callable`. By default, holds for all callables. */ - predicate shouldCreateIRForFunction(Callable callable) { + predicate shouldCreateIRForFunction(Callable callable) { callable.getLocation().getFile().getExtension() = "cs" } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll index 7e30160285c..9cd0a0a34fc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll @@ -72,6 +72,4 @@ class TranslatedLocalVariableDeclaration extends TranslatedLocalDeclaration, // then the simple variable initialization result = getTranslatedInitialization(var.getInitializer()) } - - override predicate isInitializedByElement() { expr.getParent() instanceof IsExpr } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 8e83de3e027..2f0be8366c0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1792,18 +1792,18 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { this.hasVar() and tag = GeneratedBranchTag() and ( - tag = GeneratedBranchTag() and kind instanceof TrueEdge and - result = getPatternVarDecl().getFirstInstruction() + result = this.getInstruction(InitializerStoreTag()) or - tag = GeneratedBranchTag() and kind instanceof FalseEdge and result = this.getParent().getChildSuccessor(this) ) or tag = GeneratedConstantTag() and kind instanceof GotoEdge and - result = this.getInstruction(GeneratedNEQTag()) + if this.hasVar() + then result = this.getPatternVarDecl().getFirstInstruction() + else result = this.getInstruction(GeneratedNEQTag()) } override Instruction getChildSuccessor(TranslatedElement child) { @@ -1811,8 +1811,8 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { result = this.getInstruction(ConvertTag()) or this.hasVar() and - child = getPatternVarDecl() and - result = this.getInstruction(InitializerStoreTag()) + child = this.getPatternVarDecl() and + result = this.getInstruction(GeneratedNEQTag()) } override predicate hasInstruction( @@ -1842,7 +1842,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { this.hasVar() and tag = GeneratedBranchTag() and opcode instanceof Opcode::ConditionalBranch and - resultType = expr.getType() and + resultType instanceof VoidType and isLValue = false } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll index fbf5db28ec8..2dfd1b745e0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll @@ -39,12 +39,7 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement { kind instanceof GotoEdge and if hasUninitializedInstruction() then result = getInstruction(InitializerStoreTag()) - else - if isInitializedByElement() - then - // initialization is done by an element - result = getParent().getChildSuccessor(this) - else result = getInitialization().getFirstInstruction() + else result = getInitialization().getFirstInstruction() ) or hasUninitializedInstruction() and @@ -75,11 +70,8 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement { * desugaring process. */ predicate hasUninitializedInstruction() { - ( - not exists(getInitialization()) or - getInitialization() instanceof TranslatedListInitialization - ) and - not isInitializedByElement() + not exists(getInitialization()) or + getInitialization() instanceof TranslatedListInitialization } Instruction getVarAddress() { result = getInstruction(InitializerVariableAddressTag()) } @@ -101,10 +93,4 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement { * as a different step, but do it during the declaration. */ abstract TranslatedElement getInitialization(); - - /** - * Holds if a declaration is not explicitly initialized, - * but will be implicitly initialized by an element. - */ - abstract predicate isInitializedByElement(); } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll index 5820a8b8309..3083a91e706 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll @@ -72,10 +72,6 @@ abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDecla // element override LocalVariable getDeclVar() { none() } - // A compiler generated element always has an explicit - // initialization - override predicate isInitializedByElement() { none() } - override Type getVarType() { result = getIRVariable().getType() } /** diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index 5a3ade51b6b..16d15ff3aa8 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -806,8 +806,10 @@ isexpr.cs: # 13| r0_13(Object) = Load : &:r0_12, ~mu0_2 # 13| r0_14(Is_A) = CheckedConvertOrNull : r0_13 # 13| r0_15(Is_A) = Constant[0] : -# 13| r0_16(Boolean) = CompareNE : r0_14, r0_15 -# 13| r0_17(Boolean) = ConditionalBranch : r0_16 +# 13| r0_16(glval) = VariableAddress[tmp] : +# 13| mu0_17(Is_A) = Uninitialized[tmp] : &:r0_16 +# 13| r0_18(Boolean) = CompareNE : r0_14, r0_15 +# 13| v0_19(Void) = ConditionalBranch : r0_18 #-----| False -> Block 2 #-----| True -> Block 3 @@ -817,13 +819,12 @@ isexpr.cs: # 8| v1_2(Void) = ExitFunction : # 13| Block 2 -# 13| v2_0(Void) = ConditionalBranch : r0_16 +# 13| v2_0(Void) = ConditionalBranch : r0_18 #-----| False -> Block 5 #-----| True -> Block 4 # 13| Block 3 -# 13| r3_0(glval) = VariableAddress[tmp] : -# 13| mu3_1(Is_A) = Store : &:r3_0, r0_14 +# 13| mu3_0(Is_A) = Store : &:r0_16, r0_14 #-----| Goto -> Block 2 # 15| Block 4 From 61b372b062d3f0262cbe90c3cb96de21e9276f28 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Mon, 23 Sep 2019 17:30:05 +0100 Subject: [PATCH 0213/1227] Add Go to supported languages topic and update release number --- docs/language/global-sphinx-files/global-conf.py | 4 ++-- docs/language/support/versions-compilers.csv | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/language/global-sphinx-files/global-conf.py b/docs/language/global-sphinx-files/global-conf.py index 260783d9117..84912a8c538 100644 --- a/docs/language/global-sphinx-files/global-conf.py +++ b/docs/language/global-sphinx-files/global-conf.py @@ -56,9 +56,9 @@ def setup(sphinx): # built documents. # # The short X.Y version. -version = u'1.22' +version = u'1.22.1' # The full version, including alpha/beta/rc tags. -release = u'1.22' +release = u'1.22.1' copyright = u'2019 Semmle Ltd' author = u'Semmle Ltd' diff --git a/docs/language/support/versions-compilers.csv b/docs/language/support/versions-compilers.csv index 4a59214c47f..b70ac87335f 100644 --- a/docs/language/support/versions-compilers.csv +++ b/docs/language/support/versions-compilers.csv @@ -10,6 +10,7 @@ C#,C# up to 7.3. with .NET up to 4.8 [3]_.,"Microsoft Visual Studio up to 2019, .NET Core up to 2.2","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" COBOL,ANSI 85 or newer [4]_.,Not applicable,"``.cbl``, ``.CBL``, ``.cpy``, ``.CPY``, ``.copy``, ``.COPY``" +Go, "Go up to 1.13", "Go 1.11 or more recent", ``.go`` Java,"Java 6 to 12 [5]_.","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [6]_.",``.java`` From 300e580874d8768544f66416388594b79ada171f Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 23 Sep 2019 15:43:15 -0700 Subject: [PATCH 0214/1227] C++: Implement language-neutral IR type system The C++ IR currently has a very clunky way of specifying the type of an IR entity (`Instruction`, `Operand`, `IRVariable`, etc.). There are three separate predicates: `getType()`, `isGLValue()`, and `getSize()`. All three are necessary, rather than just having a `getType()` predicate, because some IR entities have types that are not represented via an existing `Type` object in the AST. Examples include the type for an lvalue returned from a `VariableAddress` instruction, the type for an array slice being zero-initialized in a variable initializer, and several others. It is very easy for QL code to just check the `getType()` predicate, while forgetting to use `isGLValue()` to determine if that type is the actual type of the entity (the prvalue case) or the type referred to by a glvalue entity. Furthermore, the C++ type system creates potentially many different `Type` objects for the same underlying type (e.g. typedefs, using declarations, `const`/`volatile` qualifiers, etc.), making it more difficult to tell when two entities have semantically equivalent types. In addition, other languages for which we want to enable the IR have somewhat different type systems. The various language type systems differ in their structure, although they tend to share the basic building blocks necessary for the IR. To address all of the above problems, I've introduced a new class hierarchy, rooted at the class `IRType`, that represents a bare-bones type system that is independent of source language (at least across C/C++/C#/Java). A type's identity is based on its kind (signed integer, unsigned integer, floating-point, Boolean, blob, etc.), size and in the case of blob types, a "tag" to differentiate between different classes and structs. No distinction is made between, say `signed int` and plain `int`, or between different language integer types that have the same signedness and size (e.g. `unsigned int` vs. `wchar_t` on Linux). `IRType` is intended for use by language-agnostic IR-based analyses, including range analysis, dataflow, SSA construction, and alias analysis. The set of available `IRType`s is determined by predicate provided by the language library implementation (e.g. `hasSignedIntegerType(int byteSize)`. In addition to `IRType`, each language now defines a type alias named `LanguageType`, representing the type of an IR entity in more language-specific terms. The only predicate requried on `LanguageType` is `getIRType()`, which returns the single `IRType` object for the language-neutral representation of that `LanguageType`. All other predicates on and subclasses of `LanguageType` are language-specific. There may be many instances of `LanguageType` that map to a given `IRType`, to allow for typedefs, etc. Most of the changes are mechanical changes in the IR construction code, to return the correct type for each IR entity. SSA construction has also been updated to avoid dependencies on language-specific types. I have not yet removed the original `getType()` predicates that just return `Type`. These can be removed once we move the remaining existing libraries to use `IRType`. Test results are, by design, pretty much unchanged. Once case changed for inline asm, because the previously IR generation for it played a little fast and loose with the input/output expressions. The test case now includes both input and output variables. The generated IR for `Conditional_LValue` is now more correct, because we now have a way to represent an lvalue of an lvalue. `syntax-zoo` is still a hot mess. Most of the changed outputs are due to wobble from having multiple functions with the same name, but with a slightly different order of evaluation due to the type changes. Others are wobble from already-invalid IR. A couple non-wobbly places have improved slightly, though. The C# part of this change is waiting for #2005 to be merged, since that has some of the necessary C# implementation. --- .../code/cpp/ir/implementation/IRType.qll | 257 +++++++++ .../cpp/ir/implementation/aliased_ssa/IR.qll | 1 + .../implementation/aliased_ssa/IRSanity.qll | 1 + .../implementation/aliased_ssa/IRVariable.qll | 25 +- .../aliased_ssa/Instruction.qll | 62 +-- .../ir/implementation/aliased_ssa/Operand.qll | 48 +- .../aliased_ssa/internal/AliasedSSA.qll | 96 ++-- .../aliased_ssa/internal/IRImports.qll | 1 + .../internal/IRVariableImports.qll | 1 + .../aliased_ssa/internal/OperandImports.qll | 1 + .../aliased_ssa/internal/PrintSSA.qll | 64 ++- .../aliased_ssa/internal/SSAConstruction.qll | 72 +-- .../internal/SSAConstructionInternal.qll | 1 + .../internal/IRTypeInternal.qll | 1 + .../implementation/internal/TIRVariable.qll | 4 +- .../code/cpp/ir/implementation/raw/IR.qll | 1 + .../cpp/ir/implementation/raw/IRSanity.qll | 1 + .../cpp/ir/implementation/raw/IRVariable.qll | 25 +- .../cpp/ir/implementation/raw/Instruction.qll | 62 +-- .../cpp/ir/implementation/raw/Operand.qll | 48 +- .../raw/internal/IRConstruction.qll | 33 +- .../implementation/raw/internal/IRImports.qll | 1 + .../raw/internal/IRVariableImports.qll | 1 + .../raw/internal/OperandImports.qll | 1 + .../raw/internal/TranslatedCall.qll | 33 +- .../raw/internal/TranslatedCondition.qll | 16 +- .../internal/TranslatedDeclarationEntry.qll | 13 +- .../raw/internal/TranslatedElement.qll | 22 +- .../raw/internal/TranslatedExpr.qll | 398 ++++++-------- .../raw/internal/TranslatedFunction.qll | 91 ++-- .../raw/internal/TranslatedInitialization.qll | 114 ++-- .../raw/internal/TranslatedStmt.qll | 139 ++--- .../ir/implementation/unaliased_ssa/IR.qll | 1 + .../implementation/unaliased_ssa/IRSanity.qll | 1 + .../unaliased_ssa/IRVariable.qll | 25 +- .../unaliased_ssa/Instruction.qll | 62 +-- .../implementation/unaliased_ssa/Operand.qll | 48 +- .../unaliased_ssa/internal/IRImports.qll | 1 + .../internal/IRVariableImports.qll | 1 + .../unaliased_ssa/internal/OperandImports.qll | 1 + .../unaliased_ssa/internal/PrintSSA.qll | 64 ++- .../internal/SSAConstruction.qll | 72 +-- .../internal/SSAConstructionInternal.qll | 1 + .../unaliased_ssa/internal/SimpleSSA.qll | 21 +- .../semmle/code/cpp/ir/internal/CppType.qll | 500 ++++++++++++++++++ .../code/cpp/ir/internal/IRCppLanguage.qll | 7 + .../library-tests/ir/ir/PrintAST.expected | 20 +- .../ir/ir/aliased_ssa_sanity.expected | 2 + cpp/ql/test/library-tests/ir/ir/ir.cpp | 4 +- .../test/library-tests/ir/ir/raw_ir.expected | 66 +-- .../library-tests/ir/ir/raw_sanity.expected | 2 + .../ir/ir/unaliased_ssa_sanity.expected | 2 + .../ir/ssa/aliased_ssa_ir.expected | 42 +- .../ir/ssa/aliased_ssa_sanity.expected | 2 + .../ir/ssa/unaliased_ssa_ir.expected | 32 +- .../ir/ssa/unaliased_ssa_sanity.expected | 2 + .../syntax-zoo/aliased_ssa_sanity.expected | 6 +- .../syntax-zoo/raw_sanity.expected | 9 +- .../syntax-zoo/unaliased_ssa_sanity.expected | 6 +- .../implementation/internal/TIRVariable.qll | 4 +- .../code/csharp/ir/implementation/raw/IR.qll | 1 + .../csharp/ir/implementation/raw/IRSanity.qll | 1 + .../ir/implementation/raw/IRVariable.qll | 25 +- .../ir/implementation/raw/Instruction.qll | 62 +-- .../csharp/ir/implementation/raw/Operand.qll | 48 +- 65 files changed, 1758 insertions(+), 1017 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRTypeInternal.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll new file mode 100644 index 00000000000..19202f5d49c --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -0,0 +1,257 @@ +/** + * Minimal, language-neutral type system for the IR. + */ + +private import internal.IRTypeInternal + +newtype TIRType = + TIRVoidType() or + TIRUnknownType() or + TIRErrorType() or + TIRBooleanType(int byteSize) { + Language::hasBooleanType(byteSize) + } or + TIRSignedIntegerType(int byteSize) { + Language::hasSignedIntegerType(byteSize) + } or + TIRUnsignedIntegerType(int byteSize) { + Language::hasUnsignedIntegerType(byteSize) + } or + TIRFloatingPointType(int byteSize) { + Language::hasFloatingPointType(byteSize) + } or + TIRAddressType(int byteSize) { + Language::hasAddressType(byteSize) + } or + TIRFunctionAddressType(int byteSize) { + Language::hasFunctionAddressType(byteSize) + } or + TIRBlobType(Language::BlobTypeTag tag, int byteSize) { + Language::hasBlobType(tag, byteSize) + } + +/** + * The language-neutral type of an IR `Instruction`, `Operand`, or `IRVariable`. + * The interface to `IRType` and its subclasses is the same across all languages for which the IR + * is supported, so analyses that expect to be used for multiple languages should generally use + * `IRType` rather than a language-specific type. + * + * Many types from the language-specific type system will map to a single canonical `IRType`. Two + * types that map to the same `IRType` are considered equivalent by the IR. As an example, in C++, + * all pointer types map to the same instance of `IRAddressType`. + */ +class IRType extends TIRType { + abstract string toString(); + + /** + * Gets a string that uniquely identifies this `IRType`. This string is often the same as the + * result of `IRType.toString()`, but for some types it may be more verbose to ensure uniqueness. + */ + string getIdentityString() { + result = toString() + } + + /** + * Gets the size of the type, in bytes, if known. + * + * This will hold for all `IRType` objects except `IRUnknownType`. + */ + abstract int getByteSize(); + + /** + * Gets a single instance of `LanguageType` that maps to this `IRType`. + */ + abstract Language::LanguageType getCanonicalLanguageType(); +} + +/** + * An unknown type. Generally used to represent results and operands that access an unknown set of + * memory locations, such as the side effects of a function call. + */ +class IRUnknownType extends IRType, TIRUnknownType { + final override string toString() { result = "unknown" } + + final override int getByteSize() { none() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalUnknownType() + } +} + +/** + * A void type, which has no values. Used to represent the result type of an instruction that does + * not produce a result. + */ +class IRVoidType extends IRType, TIRVoidType { + final override string toString() { result = "void" } + + final override int getByteSize() { result = 0 } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalVoidType() + } +} + +/** + * An error type. Used when an error in the source code prevents the extractor from determining the + * proper type. + */ +class IRErrorType extends IRType, TIRErrorType { + final override string toString() { result = "error" } + + final override int getByteSize() { result = 0 } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalErrorType() + } +} + +private class IRSizedType extends IRType { + int byteSize; + + IRSizedType() { + this = TIRBooleanType(byteSize) or + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) or + this = TIRFloatingPointType(byteSize) or + this = TIRAddressType(byteSize) or + this = TIRFunctionAddressType(byteSize) or + this = TIRBlobType(_, byteSize) + } + + abstract override string toString(); + + final override int getByteSize() { result = byteSize } + + abstract override Language::LanguageType getCanonicalLanguageType(); +} + +/** + * A Boolean type, which can hold the values `true` (non-zero) or `false` (zero). + */ +class IRBooleanType extends IRSizedType, TIRBooleanType { + final override string toString() { result = "bool" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalBooleanType(byteSize) + } +} + +/** + * A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and + * `IRFloatingPointType`. + */ +class IRNumericType extends IRSizedType { + IRNumericType() { + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) or + this = TIRFloatingPointType(byteSize) + } + + abstract override string toString(); + + abstract override Language::LanguageType getCanonicalLanguageType(); +} + +/** + * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed + * integer, as well as character types whose representation is signed. + */ +class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { + final override string toString() { result = "int" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalSignedIntegerType(byteSize) + } +} + +/** + * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an + * unsigned integer, as well as character types whose representation is unsigned. + */ +class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { + final override string toString() { result = "uint" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalUnsignedIntegerType(byteSize) + } +} + +/** + * A floating-point type. + */ +class IRFloatingPointType extends IRNumericType, TIRFloatingPointType { + final override string toString() { result = "float" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalFloatingPointType(byteSize) + } +} + +/** + * An address type, representing the memory address of data. Used to represent pointers, references, + * and lvalues, include those that are garbage collected. + * + * The address of a function is represented by the separate `IRFunctionAddressType`. + */ +class IRAddressType extends IRSizedType, TIRAddressType { + final override string toString() { result = "addr" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalAddressType(byteSize) + } +} + +/** + * An address type, representing the memory address of code. Used to represent function pointers, + * function references, and the target of a direct function call. + */ +class IRFunctionAddressType extends IRSizedType, TIRFunctionAddressType { + final override string toString() { result = "func" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalFunctionAddressType(byteSize) + } +} + +/** + * A type with known size that does not fit any of the other kinds of type. Used to represent + * classes, structs, unions, fixed-size arrays, pointers-to-member, and more. + */ +class IRBlobType extends IRSizedType, TIRBlobType { + Language::BlobTypeTag tag; + + IRBlobType() { + this = TIRBlobType(tag, byteSize) + } + + final override string toString() { + result = "blob" + byteSize.toString() + "{" + tag.toString() + "}" + } + + final override string getIdentityString() { + result = "blob" + byteSize.toString() + "{" + Language::getBlobTagIdentityString(tag) + "}" + } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalBlobType(tag, byteSize) + } + + /** + * Gets the "tag" that differentiates this type from other incompatible blob types that have the + * same size. + */ + final Language::BlobTypeTag getTag() { result = tag } +} + +module IRTypeSanity { + query predicate missingCanonicalLanguageType(IRType type, string message) { + not exists(type.getCanonicalLanguageType()) and + message = "Type does not have a canonical `LanguageType`" + } + + query predicate multipleCanonicalLanguageTypes(IRType type, string message) { + strictcount(type.getCanonicalLanguageType()) > 1 and + message = "Type has multiple canonical `LanguageType`s: " + concat(type.getCanonicalLanguageType().toString(), ", ") + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll index 278040f8ab8..badd48552a5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll @@ -5,6 +5,7 @@ import IRVariable import Operand private import internal.IRImports as Imports import Imports::EdgeKind +import Imports::IRType import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll index 3921472dc8e..6ee2e687015 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll @@ -1,2 +1,3 @@ private import IR import InstructionSanity +import IRTypeSanity \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index a7ca4593ac4..d17b810785e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -5,6 +5,7 @@ import Imports::TempVariableTag private import Imports::IRUtilities private import Imports::TTempVariableTag private import Imports::TIRVariable +private import Imports::IRType IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { result.getVariable() = var and @@ -24,7 +25,21 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - abstract Language::Type getType(); + final Language::Type getType() { + getLanguageType().hasType(result, false) + } + + /** + * Gets the language-neutral type of the variable. + */ + final IRType getIRType() { + result = getLanguageType().getIRType() + } + + /** + * Gets the type of the variable. + */ + abstract Language::LanguageType getLanguageType(); /** * Gets the AST node that declared this variable, or that introduced this @@ -59,7 +74,7 @@ abstract class IRVariable extends TIRVariable { */ class IRUserVariable extends IRVariable, TIRUserVariable { Language::Variable var; - Language::Type type; + Language::LanguageType type; IRUserVariable() { this = TIRUserVariable(var, type, func) } @@ -71,7 +86,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable { result = getVariable().toString() + " " + getVariable().getLocation().toString() } - final override Language::Type getType() { result = type } + final override Language::LanguageType getLanguageType() { result = type } /** * Gets the original user-declared variable. @@ -110,11 +125,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { Language::AST ast; TempVariableTag tag; - Language::Type type; + Language::LanguageType type; IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - final override Language::Type getType() { result = type } + final override Language::LanguageType getLanguageType() { result = type } final override Language::AST getAST() { result = ast } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 43f9663d2cd..f84871e227d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -113,10 +113,13 @@ module InstructionSanity { } query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func | + exists(Language::Function func, Instruction use | not exists(operand.getType()) and - func = operand.getUse().getEnclosingFunction() and - message = "Operand missing type in function '" + Language::getIdentityString(func) + "'." + use = operand.getUse() and + func = use.getEnclosingFunction() and + message = "Operand '" + operand.toString() + "' of instruction '" + + use.getOpcode().toString() + "' missing type in function '" + + Language::getIdentityString(func) + "'." ) } @@ -344,23 +347,6 @@ class Instruction extends Construction::TInstruction { ) } - bindingset[type] - private string getValueCategoryString(string type) { - if isGLValue() then result = "glval<" + type + ">" else result = type - } - - string getResultTypeString() { - exists(string valcat | - valcat = getValueCategoryString(getResultType().toString()) and - if - getResultType() instanceof Language::UnknownType and - not isGLValue() and - exists(getResultSize()) - then result = valcat + "[" + getResultSize().toString() + "]" - else result = valcat - ) - } - /** * Gets a human-readable string that uniquely identifies this instruction * within the function. This string is used to refer to this instruction when @@ -380,7 +366,9 @@ class Instruction extends Construction::TInstruction { * * Example: `r1_1(int*)` */ - final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" } + final string getResultString() { + result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")" + } /** * Gets a string describing the operands of this instruction, suitable for @@ -448,6 +436,10 @@ class Instruction extends Construction::TInstruction { result = Construction::getInstructionUnconvertedResultExpression(this) } + final Language::LanguageType getResultLanguageType() { + result = Construction::getInstructionResultType(this) + } + /** * Gets the type of the result produced by this instruction. If the * instruction does not produce a result, its result type will be `VoidType`. @@ -455,7 +447,16 @@ class Instruction extends Construction::TInstruction { * If `isGLValue()` holds, then the result type of this instruction should be * thought of as "pointer to `getResultType()`". */ - final Language::Type getResultType() { Construction::instructionHasType(this, result, _) } + final Language::Type getResultType() { + exists(Language::LanguageType resultType, Language::Type langType | + resultType = getResultLanguageType() and + ( + resultType.hasType(langType, _) or + not resultType.hasType(_, _) and result instanceof Language::UnknownType + ) and + result = langType.getUnspecifiedType() + ) + } /** * Holds if the result produced by this instruction is a glvalue. If this @@ -475,7 +476,9 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::instructionHasType(this, _, true) } + final predicate isGLValue() { + Construction::getInstructionResultType(this).hasType(_, true) + } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -485,14 +488,7 @@ class Instruction extends Construction::TInstruction { * `getResultSize()` will always be the size of a pointer. */ final int getResultSize() { - if isGLValue() - then - // a glvalue is always pointer-sized. - result = Language::getPointerSize() - else - if getResultType() instanceof Language::UnknownType - then result = Construction::getInstructionResultSize(this) - else result = Language::getTypeSize(getResultType()) + result = Construction::getInstructionResultType(this).getByteSize() } /** @@ -1300,7 +1296,7 @@ class CatchInstruction extends Instruction { * An instruction that catches an exception of a specific type. */ class CatchByTypeInstruction extends CatchInstruction { - Language::Type exceptionType; + Language::LanguageType exceptionType; CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and @@ -1312,7 +1308,7 @@ class CatchByTypeInstruction extends CatchInstruction { /** * Gets the type of exception to be caught. */ - final Language::Type getExceptionType() { result = exceptionType } + final Language::LanguageType getExceptionType() { result = exceptionType } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 1ced8ef3282..e3485825064 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -1,9 +1,10 @@ private import internal.IRInternal -import Instruction -import IRBlock +private import Instruction +private import IRBlock private import internal.OperandImports as Imports -import Imports::MemoryAccessKind -import Imports::Overlap +private import Imports::MemoryAccessKind +private import Imports::IRType +private import Imports::Overlap private import Imports::OperandTag cached @@ -143,22 +144,40 @@ class Operand extends TOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - Language::Type getType() { result = getAnyDef().getResultType() } + Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() } + + /** + * Gets the language-neutral type of the value consumed by this operand. This is usually the same + * as the result type of the definition instruction consumed by this operand. For register + * operands, this is always the case. For some memory operands, the operand type may be different + * from the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + final IRType getIRType() { result = getLanguageType().getIRType() } + + /** + * Gets the type of the value consumed by this operand. This is usually the same as the + * result type of the definition instruction consumed by this operand. For register operands, + * this is always the case. For some memory operands, the operand type may be different from + * the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + final Language::Type getType() { getLanguageType().hasType(result, _) } /** * Holds if the value consumed by this operand is a glvalue. If this * holds, the value of the operand represents the address of a location, * and the type of the location is given by `getType()`. If this does * not hold, the value of the operand represents a value whose type is - * given by `getResultType()`. + * given by `getType()`. */ - predicate isGLValue() { getAnyDef().isGLValue() } + final predicate isGLValue() { getLanguageType().hasType(_, true) } /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. */ - int getSize() { result = Language::getTypeSize(getType()) } + final int getSize() { result = getLanguageType().getByteSize() } } /** @@ -170,11 +189,6 @@ class MemoryOperand extends Operand { this = TPhiOperand(_, _, _, _) } - override predicate isGLValue() { - // A `MemoryOperand` can never be a glvalue - none() - } - /** * Gets the kind of memory access performed by the operand. */ @@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; - final override Language::Type getType() { + final override Language::LanguageType getLanguageType() { result = Construction::getInstructionOperandType(useInstr, tag) } } @@ -371,12 +385,6 @@ class PositionalArgumentOperand extends ArgumentOperand { class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - final override int getSize() { - if getType() instanceof Language::UnknownType - then result = Construction::getInstructionOperandSize(useInstr, tag) - else result = Language::getTypeSize(getType()) - } - override MemoryAccessKind getMemoryAccess() { useInstr instanceof CallSideEffectInstruction and result instanceof EscapedMayMemoryAccess diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll index 95ddffb2274..0e19379f6b6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll @@ -1,6 +1,6 @@ -private import cpp import AliasAnalysis import semmle.code.cpp.ir.internal.Overlap +private import semmle.code.cpp.ir.internal.IRCppLanguage as Language private import semmle.code.cpp.Print private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR private import semmle.code.cpp.ir.internal.IntegerConstant as Ints @@ -10,29 +10,39 @@ private import semmle.code.cpp.ir.implementation.internal.OperandTag private class IntValue = Ints::IntValue; private predicate hasResultMemoryAccess( - Instruction instr, IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset + Instruction instr, IRVariable var, IRType type, Language::LanguageType languageType, + IntValue startBitOffset, IntValue endBitOffset ) { resultPointsTo(instr.getResultAddress(), var, startBitOffset) and - type = instr.getResultType() and - if exists(instr.getResultSize()) - then endBitOffset = Ints::add(startBitOffset, Ints::mul(instr.getResultSize(), 8)) + languageType = instr.getResultLanguageType() and + type = languageType.getIRType() and + if exists(type.getByteSize()) + then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8)) else endBitOffset = Ints::unknown() } private predicate hasOperandMemoryAccess( - MemoryOperand operand, IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset + MemoryOperand operand, IRVariable var, IRType type, Language::LanguageType languageType, + IntValue startBitOffset, IntValue endBitOffset ) { resultPointsTo(operand.getAddressOperand().getAnyDef(), var, startBitOffset) and - type = operand.getType() and - if exists(operand.getSize()) - then endBitOffset = Ints::add(startBitOffset, Ints::mul(operand.getSize(), 8)) + languageType = operand.getLanguageType() and + type = languageType.getIRType() and + if exists(type.getByteSize()) + then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8)) else endBitOffset = Ints::unknown() } private newtype TMemoryLocation = - TVariableMemoryLocation(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset) { - hasResultMemoryAccess(_, var, type, startBitOffset, endBitOffset) or - hasOperandMemoryAccess(_, var, type, startBitOffset, endBitOffset) + TVariableMemoryLocation( + IRVariable var, IRType type, Language::LanguageType languageType, IntValue startBitOffset, + IntValue endBitOffset + ) { + ( + hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset) or + hasOperandMemoryAccess(_, var, type, _, startBitOffset, endBitOffset) + ) and + languageType = type.getCanonicalLanguageType() } or TUnknownMemoryLocation(IRFunction irFunc) or TUnknownVirtualVariable(IRFunction irFunc) @@ -49,9 +59,11 @@ abstract class MemoryLocation extends TMemoryLocation { abstract VirtualVariable getVirtualVariable(); - abstract Type getType(); + abstract Language::LanguageType getType(); abstract string getUniqueId(); + + final IRType getIRType() { result = getType().getIRType() } } abstract class VirtualVariable extends MemoryLocation { } @@ -62,20 +74,34 @@ abstract class VirtualVariable extends MemoryLocation { } */ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation { IRVariable var; - Type type; + IRType type; + Language::LanguageType languageType; IntValue startBitOffset; IntValue endBitOffset; VariableMemoryLocation() { - this = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset) + this = TVariableMemoryLocation(var, type, languageType, startBitOffset, endBitOffset) } final override string toString() { result = var.toString() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" + - type.toString() + ">" + type.toString() + ", " + languageType.toString() + ">" } - final override Type getType() { result = type } + final override Language::LanguageType getType() { + if + strictcount(Language::LanguageType accessType | + hasResultMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset) or + hasOperandMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset) + ) = 1 + then + // All of the accesses have the same `LanguageType`, so just use that. + hasResultMemoryAccess(_, var, type, result, startBitOffset, endBitOffset) or + hasOperandMemoryAccess(_, var, type, result, startBitOffset, endBitOffset) + else + // There is no single type for all accesses, so just use the canonical one for this `IRType`. + result = type.getCanonicalLanguageType() + } final IntValue getStartBitOffset() { result = startBitOffset } @@ -85,13 +111,14 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation { final override string getUniqueId() { result = var.getUniqueId() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" + - getTypeIdentityString(type) + ">" + type.getIdentityString() + ">" } final override VirtualVariable getVirtualVariable() { if variableAddressEscapes(var) then result = TUnknownVirtualVariable(var.getEnclosingIRFunction()) - else result = TVariableMemoryLocation(var, var.getType(), 0, var.getType().getSize() * 8) + else + result = TVariableMemoryLocation(var, var.getIRType(), _, 0, var.getIRType().getByteSize() * 8) } /** @@ -99,7 +126,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation { */ final predicate coversEntireVariable() { startBitOffset = 0 and - endBitOffset = var.getType().getSize() * 8 + endBitOffset = var.getIRType().getByteSize() * 8 } } @@ -111,7 +138,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation { class VariableVirtualVariable extends VariableMemoryLocation, VirtualVariable { VariableVirtualVariable() { not variableAddressEscapes(var) and - type = var.getType() and + type = var.getIRType() and coversEntireVariable() } } @@ -128,7 +155,9 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation { final override VirtualVariable getVirtualVariable() { result = TUnknownVirtualVariable(irFunc) } - final override Type getType() { result instanceof UnknownType } + final override Language::LanguageType getType() { + result = any(IRUnknownType type).getCanonicalLanguageType() + } final override string getUniqueId() { result = "{Unknown}" } } @@ -143,7 +172,9 @@ class UnknownVirtualVariable extends TUnknownVirtualVariable, VirtualVariable { final override string toString() { result = "{AllAliased}" } - final override Type getType() { result instanceof UnknownType } + final override Language::LanguageType getType() { + result = any(IRUnknownType type).getCanonicalLanguageType() + } final override string getUniqueId() { result = " " + toString() } @@ -177,7 +208,7 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) { intervalOverlap = getVariableMemoryLocationOverlap(def, use) and if intervalOverlap instanceof MustExactlyOverlap then - if def.getType() = use.getType() + if def.getIRType() = use.getIRType() then // The def and use types match, so it's an exact overlap. result instanceof MustExactlyOverlap @@ -282,11 +313,11 @@ MemoryLocation getResultMemoryLocation(Instruction instr) { ( ( kind.usesAddressOperand() and - if hasResultMemoryAccess(instr, _, _, _, _) + if hasResultMemoryAccess(instr, _, _, _, _, _) then - exists(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset | - hasResultMemoryAccess(instr, var, type, startBitOffset, endBitOffset) and - result = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset) + exists(IRVariable var, IRType type, IntValue startBitOffset, IntValue endBitOffset | + hasResultMemoryAccess(instr, var, type, _, startBitOffset, endBitOffset) and + result = TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset) ) else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction()) ) @@ -306,11 +337,11 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { ( ( kind.usesAddressOperand() and - if hasOperandMemoryAccess(operand, _, _, _, _) + if hasOperandMemoryAccess(operand, _, _, _, _, _) then - exists(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset | - hasOperandMemoryAccess(operand, var, type, startBitOffset, endBitOffset) and - result = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset) + exists(IRVariable var, IRType type, IntValue startBitOffset, IntValue endBitOffset | + hasOperandMemoryAccess(operand, var, type, _, startBitOffset, endBitOffset) and + result = TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset) ) else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction()) ) @@ -323,3 +354,4 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { ) ) } + diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRImports.qll index 74f7b4a2b64..42d6e7db693 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRImports.qll @@ -1,2 +1,3 @@ import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRVariableImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRVariableImports.qll index 1f0f5eaccde..8c60565defc 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRVariableImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRVariableImports.qll @@ -1,3 +1,4 @@ +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandImports.qll index e626662ccf2..3c781579cee 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandImports.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll index a5c09c6401b..c73826bd4c8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll @@ -4,34 +4,52 @@ private import Alias private import SSAConstruction private import DebugSSA +bindingset[offset] +private string getKeySuffixForOffset(int offset) { + if offset % 2 = 0 then result = "" else result = "_Chi" +} + +bindingset[offset] +private int getIndexForOffset(int offset) { result = offset / 2 } + /** * Property provide that dumps the memory access of each result. Useful for debugging SSA * construction. */ class PropertyProvider extends IRPropertyProvider { override string getInstructionProperty(Instruction instruction, string key) { - exists(MemoryLocation location | - location = getResultMemoryLocation(instruction) and - ( - key = "ResultMemoryLocation" and result = location.toString() - or - key = "ResultVirtualVariable" and result = location.getVirtualVariable().toString() + key = "ResultMemoryLocation" and + result = strictconcat(MemoryLocation loc | + loc = getResultMemoryLocation(instruction) + | + loc.toString(), "," ) - ) or - exists(MemoryLocation location | - location = getOperandMemoryLocation(instruction.getAnOperand()) and - ( - key = "OperandMemoryAccess" and result = location.toString() - or - key = "OperandVirtualVariable" and result = location.getVirtualVariable().toString() + key = "ResultVirtualVariable" and + result = strictconcat(MemoryLocation loc | + loc = getResultMemoryLocation(instruction) + | + loc.getVirtualVariable().toString(), "," ) - ) or - exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | - hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and - defBlock.getInstruction(defIndex) = instruction and - key = "DefinitionRank[" + useLocation.toString() + "]" and + key = "OperandMemoryLocation" and + result = strictconcat(MemoryLocation loc | + loc = getOperandMemoryLocation(instruction.getAnOperand()) + | + loc.toString(), "," + ) + or + key = "OperandVirtualVariable" and + result = strictconcat(MemoryLocation loc | + loc = getOperandMemoryLocation(instruction.getAnOperand()) + | + loc.getVirtualVariable().toString(), "," + ) + or + exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset | + hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and + defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and + key = "DefinitionRank" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + "]" and result = defRank.toString() ) or @@ -41,10 +59,11 @@ class PropertyProvider extends IRPropertyProvider { result = useRank.toString() ) or - exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | - hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and - defBlock.getInstruction(defIndex) = instruction and - key = "DefinitionReachesUse[" + useLocation.toString() + "]" and + exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset | + hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and + defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and + key = "DefinitionReachesUse" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + + "]" and result = strictconcat(IRBlock useBlock, int useRank, int useIndex | exists(Instruction useInstruction | hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and @@ -124,3 +143,4 @@ class PropertyProvider extends IRPropertyProvider { ) } } + diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 1ca6e099795..9c1b52ed4e5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,4 @@ import SSAConstructionInternal -private import cpp private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.internal.Overlap @@ -18,7 +17,7 @@ private module Cached { } cached - predicate functionHasIR(Function func) { + predicate functionHasIR(Language::Function func) { exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) } @@ -42,7 +41,7 @@ private module Cached { not oldInstruction instanceof OldIR::PhiInstruction and hasChiNode(_, oldInstruction) } or - Unreached(Function function) { + Unreached(Language::Function function) { exists(OldInstruction oldInstruction | function = oldInstruction.getEnclosingFunction() and Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) @@ -50,12 +49,14 @@ private module Cached { } cached - predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) { + predicate hasTempVariable( + Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type + ) { exists(OldIR::IRTempVariable var | var.getEnclosingFunction() = func and var.getAST() = ast and var.getTag() = tag and - var.getType() = type + var.getLanguageType() = type ) } @@ -135,24 +136,12 @@ private module Cached { } cached - Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) { + Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) { exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | oldInstruction = getOldInstruction(instr) and oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and - result = oldOperand.getType() - ) - } - - cached - int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) { - exists(OldInstruction oldInstruction, OldIR::SideEffectOperand oldOperand | - oldInstruction = getOldInstruction(instr) and - oldOperand = oldInstruction.getAnOperand() and - tag = oldOperand.getOperandTag() and - // Only return a result for operands that need an explicit result size. - oldOperand.getType() instanceof UnknownType and - result = oldOperand.getSize() + result = oldOperand.getLanguageType() ) } @@ -196,20 +185,21 @@ private module Cached { } cached - Expr getInstructionConvertedResultExpression(Instruction instruction) { + Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { result = getOldInstruction(instruction).getConvertedResultExpression() } cached - Expr getInstructionUnconvertedResultExpression(Instruction instruction) { + Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { result = getOldInstruction(instruction).getUnconvertedResultExpression() } - /** + /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are * the new instructions generated from the successors of the old instruction */ + cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) @@ -252,7 +242,7 @@ private module Cached { } cached - Locatable getInstructionAST(Instruction instruction) { + Language::AST getInstructionAST(Instruction instruction) { exists(OldInstruction oldInstruction | instruction = WrappedInstruction(oldInstruction) or @@ -270,29 +260,25 @@ private module Cached { } cached - predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) { + Language::LanguageType getInstructionResultType(Instruction instruction) { exists(OldInstruction oldInstruction | instruction = WrappedInstruction(oldInstruction) and - type = oldInstruction.getResultType() and - if oldInstruction.isGLValue() then isGLValue = true else isGLValue = false + result = oldInstruction.getResultLanguageType() ) or exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | instruction = Chi(oldInstruction) and hasChiNode(vvar, oldInstruction) and - type = vvar.getType() and - isGLValue = false + result = vvar.getType() ) or exists(Alias::MemoryLocation location | instruction = Phi(_, location) and - type = location.getType() and - isGLValue = false + result = location.getType() ) or instruction = Unreached(_) and - type instanceof VoidType and - isGLValue = false + result = Language::getVoidType() } cached @@ -338,12 +324,12 @@ private module Cached { } cached - Field getInstructionField(Instruction instruction) { + Language::Field getInstructionField(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() } cached - Function getInstructionFunction(Instruction instruction) { + Language::Function getInstructionFunction(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() } @@ -353,19 +339,19 @@ private module Cached { } cached - StringLiteral getInstructionStringLiteral(Instruction instruction) { + Language::StringLiteral getInstructionStringLiteral(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue() } cached - BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { + Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { result = getOldInstruction(instruction) .(OldIR::BuiltInOperationInstruction) .getBuiltInOperation() } cached - Type getInstructionExceptionType(Instruction instruction) { + Language::LanguageType getInstructionExceptionType(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() } @@ -375,14 +361,9 @@ private module Cached { } cached - int getInstructionResultSize(Instruction instruction) { - // Only return a result for instructions that needed an explicit result size. - instruction.getResultType() instanceof UnknownType and - result = getOldInstruction(instruction).getResultSize() - } - - cached - predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { + predicate getInstructionInheritance( + Instruction instruction, Language::Class baseClass, Language::Class derivedClass + ) { exists(OldIR::InheritanceConversionInstruction oldInstr | oldInstr = getOldInstruction(instruction) and baseClass = oldInstr.getBaseClass() and @@ -879,3 +860,4 @@ private module CachedForDebugging { result.getTag() = var.getTag() } } + diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll index 5eebc0b9516..c0922aff891 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll @@ -2,4 +2,5 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR +import semmle.code.cpp.ir.internal.IRCppLanguage as Language import AliasedSSA as Alias diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRTypeInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRTypeInternal.qll new file mode 100644 index 00000000000..bd6c2f4c151 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRTypeInternal.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.internal.IRCppLanguage as Language diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll index 908a208b83a..fea67ef5ecd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll @@ -2,11 +2,11 @@ private import TIRVariableInternal private import Imports::TempVariableTag newtype TIRVariable = - TIRUserVariable(Language::Variable var, Language::Type type, Language::Function func) { + TIRUserVariable(Language::Variable var, Language::LanguageType type, Language::Function func) { Construction::hasUserVariable(func, var, type) } or TIRTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::Type type + Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type ) { Construction::hasTempVariable(func, ast, tag, type) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll index 278040f8ab8..badd48552a5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll @@ -5,6 +5,7 @@ import IRVariable import Operand private import internal.IRImports as Imports import Imports::EdgeKind +import Imports::IRType import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll index 3921472dc8e..6ee2e687015 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll @@ -1,2 +1,3 @@ private import IR import InstructionSanity +import IRTypeSanity \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index a7ca4593ac4..d17b810785e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -5,6 +5,7 @@ import Imports::TempVariableTag private import Imports::IRUtilities private import Imports::TTempVariableTag private import Imports::TIRVariable +private import Imports::IRType IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { result.getVariable() = var and @@ -24,7 +25,21 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - abstract Language::Type getType(); + final Language::Type getType() { + getLanguageType().hasType(result, false) + } + + /** + * Gets the language-neutral type of the variable. + */ + final IRType getIRType() { + result = getLanguageType().getIRType() + } + + /** + * Gets the type of the variable. + */ + abstract Language::LanguageType getLanguageType(); /** * Gets the AST node that declared this variable, or that introduced this @@ -59,7 +74,7 @@ abstract class IRVariable extends TIRVariable { */ class IRUserVariable extends IRVariable, TIRUserVariable { Language::Variable var; - Language::Type type; + Language::LanguageType type; IRUserVariable() { this = TIRUserVariable(var, type, func) } @@ -71,7 +86,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable { result = getVariable().toString() + " " + getVariable().getLocation().toString() } - final override Language::Type getType() { result = type } + final override Language::LanguageType getLanguageType() { result = type } /** * Gets the original user-declared variable. @@ -110,11 +125,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { Language::AST ast; TempVariableTag tag; - Language::Type type; + Language::LanguageType type; IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - final override Language::Type getType() { result = type } + final override Language::LanguageType getLanguageType() { result = type } final override Language::AST getAST() { result = ast } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 43f9663d2cd..f84871e227d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -113,10 +113,13 @@ module InstructionSanity { } query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func | + exists(Language::Function func, Instruction use | not exists(operand.getType()) and - func = operand.getUse().getEnclosingFunction() and - message = "Operand missing type in function '" + Language::getIdentityString(func) + "'." + use = operand.getUse() and + func = use.getEnclosingFunction() and + message = "Operand '" + operand.toString() + "' of instruction '" + + use.getOpcode().toString() + "' missing type in function '" + + Language::getIdentityString(func) + "'." ) } @@ -344,23 +347,6 @@ class Instruction extends Construction::TInstruction { ) } - bindingset[type] - private string getValueCategoryString(string type) { - if isGLValue() then result = "glval<" + type + ">" else result = type - } - - string getResultTypeString() { - exists(string valcat | - valcat = getValueCategoryString(getResultType().toString()) and - if - getResultType() instanceof Language::UnknownType and - not isGLValue() and - exists(getResultSize()) - then result = valcat + "[" + getResultSize().toString() + "]" - else result = valcat - ) - } - /** * Gets a human-readable string that uniquely identifies this instruction * within the function. This string is used to refer to this instruction when @@ -380,7 +366,9 @@ class Instruction extends Construction::TInstruction { * * Example: `r1_1(int*)` */ - final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" } + final string getResultString() { + result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")" + } /** * Gets a string describing the operands of this instruction, suitable for @@ -448,6 +436,10 @@ class Instruction extends Construction::TInstruction { result = Construction::getInstructionUnconvertedResultExpression(this) } + final Language::LanguageType getResultLanguageType() { + result = Construction::getInstructionResultType(this) + } + /** * Gets the type of the result produced by this instruction. If the * instruction does not produce a result, its result type will be `VoidType`. @@ -455,7 +447,16 @@ class Instruction extends Construction::TInstruction { * If `isGLValue()` holds, then the result type of this instruction should be * thought of as "pointer to `getResultType()`". */ - final Language::Type getResultType() { Construction::instructionHasType(this, result, _) } + final Language::Type getResultType() { + exists(Language::LanguageType resultType, Language::Type langType | + resultType = getResultLanguageType() and + ( + resultType.hasType(langType, _) or + not resultType.hasType(_, _) and result instanceof Language::UnknownType + ) and + result = langType.getUnspecifiedType() + ) + } /** * Holds if the result produced by this instruction is a glvalue. If this @@ -475,7 +476,9 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::instructionHasType(this, _, true) } + final predicate isGLValue() { + Construction::getInstructionResultType(this).hasType(_, true) + } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -485,14 +488,7 @@ class Instruction extends Construction::TInstruction { * `getResultSize()` will always be the size of a pointer. */ final int getResultSize() { - if isGLValue() - then - // a glvalue is always pointer-sized. - result = Language::getPointerSize() - else - if getResultType() instanceof Language::UnknownType - then result = Construction::getInstructionResultSize(this) - else result = Language::getTypeSize(getResultType()) + result = Construction::getInstructionResultType(this).getByteSize() } /** @@ -1300,7 +1296,7 @@ class CatchInstruction extends Instruction { * An instruction that catches an exception of a specific type. */ class CatchByTypeInstruction extends CatchInstruction { - Language::Type exceptionType; + Language::LanguageType exceptionType; CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and @@ -1312,7 +1308,7 @@ class CatchByTypeInstruction extends CatchInstruction { /** * Gets the type of exception to be caught. */ - final Language::Type getExceptionType() { result = exceptionType } + final Language::LanguageType getExceptionType() { result = exceptionType } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 1ced8ef3282..e3485825064 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -1,9 +1,10 @@ private import internal.IRInternal -import Instruction -import IRBlock +private import Instruction +private import IRBlock private import internal.OperandImports as Imports -import Imports::MemoryAccessKind -import Imports::Overlap +private import Imports::MemoryAccessKind +private import Imports::IRType +private import Imports::Overlap private import Imports::OperandTag cached @@ -143,22 +144,40 @@ class Operand extends TOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - Language::Type getType() { result = getAnyDef().getResultType() } + Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() } + + /** + * Gets the language-neutral type of the value consumed by this operand. This is usually the same + * as the result type of the definition instruction consumed by this operand. For register + * operands, this is always the case. For some memory operands, the operand type may be different + * from the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + final IRType getIRType() { result = getLanguageType().getIRType() } + + /** + * Gets the type of the value consumed by this operand. This is usually the same as the + * result type of the definition instruction consumed by this operand. For register operands, + * this is always the case. For some memory operands, the operand type may be different from + * the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + final Language::Type getType() { getLanguageType().hasType(result, _) } /** * Holds if the value consumed by this operand is a glvalue. If this * holds, the value of the operand represents the address of a location, * and the type of the location is given by `getType()`. If this does * not hold, the value of the operand represents a value whose type is - * given by `getResultType()`. + * given by `getType()`. */ - predicate isGLValue() { getAnyDef().isGLValue() } + final predicate isGLValue() { getLanguageType().hasType(_, true) } /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. */ - int getSize() { result = Language::getTypeSize(getType()) } + final int getSize() { result = getLanguageType().getByteSize() } } /** @@ -170,11 +189,6 @@ class MemoryOperand extends Operand { this = TPhiOperand(_, _, _, _) } - override predicate isGLValue() { - // A `MemoryOperand` can never be a glvalue - none() - } - /** * Gets the kind of memory access performed by the operand. */ @@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; - final override Language::Type getType() { + final override Language::LanguageType getLanguageType() { result = Construction::getInstructionOperandType(useInstr, tag) } } @@ -371,12 +385,6 @@ class PositionalArgumentOperand extends ArgumentOperand { class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - final override int getSize() { - if getType() instanceof Language::UnknownType - then result = Construction::getInstructionOperandSize(useInstr, tag) - else result = Language::getTypeSize(getType()) - } - override MemoryAccessKind getMemoryAccess() { useInstr instanceof CallSideEffectInstruction and result instanceof EscapedMayMemoryAccess diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 43283db2bc1..5907e051631 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -1,6 +1,8 @@ private import cpp import semmle.code.cpp.ir.implementation.raw.IR private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.CppType +private import semmle.code.cpp.ir.internal.Overlap private import semmle.code.cpp.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition @@ -25,16 +27,16 @@ private module Cached { cached newtype TInstruction = MkInstruction(TranslatedElement element, InstructionTag tag) { - element.hasInstruction(_, tag, _, _) + element.hasInstruction(_, tag, _) } cached - predicate hasUserVariable(Function func, Variable var, Type type) { + predicate hasUserVariable(Function func, Variable var, CppType type) { getTranslatedFunction(func).hasUserVariable(var, type) } cached - predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) { + predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) { exists(TranslatedElement element | element.getAST() = ast and func = element.getFunction() and @@ -82,22 +84,16 @@ private module Cached { } cached - Type getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { + CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as // the result type of the load. - result = instruction.(LoadInstruction).getResultType() + result = instruction.(LoadInstruction).getResultLanguageType() or not instruction instanceof LoadInstruction and result = getInstructionTranslatedElement(instruction) .getInstructionOperandType(getInstructionTag(instruction), tag) } - cached - int getInstructionOperandSize(Instruction instruction, SideEffectOperandTag tag) { - result = getInstructionTranslatedElement(instruction) - .getInstructionOperandSize(getInstructionTag(instruction), tag) - } - cached Instruction getPhiOperandDefinition( PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap @@ -217,15 +213,15 @@ private module Cached { } cached - predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) { + CppType getInstructionResultType(Instruction instruction) { getInstructionTranslatedElement(instruction) - .hasInstruction(_, getInstructionTag(instruction), type, isGLValue) + .hasInstruction(_, getInstructionTag(instruction), result) } cached Opcode getInstructionOpcode(Instruction instruction) { getInstructionTranslatedElement(instruction) - .hasInstruction(result, getInstructionTag(instruction), _, _) + .hasInstruction(result, getInstructionTag(instruction), _) } cached @@ -272,7 +268,7 @@ private module Cached { } cached - Type getInstructionExceptionType(Instruction instruction) { + CppType getInstructionExceptionType(Instruction instruction) { result = getInstructionTranslatedElement(instruction) .getInstructionExceptionType(getInstructionTag(instruction)) } @@ -299,6 +295,13 @@ private module Cached { ) } + cached + predicate needsUnknownBlobType(int byteSize) { + exists(TranslatedElement element | + element.needsUnknownBlobType(byteSize) + ) + } + cached int getInstructionResultSize(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRImports.qll index 74f7b4a2b64..42d6e7db693 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRImports.qll @@ -1,2 +1,3 @@ import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll index 1f0f5eaccde..8c60565defc 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll @@ -1,3 +1,4 @@ +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandImports.qll index e626662ccf2..3c781579cee 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandImports.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 14168217d9b..72117091683 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -1,6 +1,7 @@ private import cpp private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.models.interfaces.SideEffect private import InstructionTag private import TranslatedElement @@ -30,13 +31,10 @@ abstract class TranslatedCall extends TranslatedExpr { else result = getFirstCallTargetInstruction() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = CallTag() and opcode instanceof Opcode::Call and - resultType = getCallResultType() and - isGLValue = false + resultType = getTypeForPRValue(getCallResultType()) or hasSideEffect() and tag = CallSideEffectTag() and @@ -44,13 +42,12 @@ abstract class TranslatedCall extends TranslatedExpr { if hasWriteSideEffect() then ( opcode instanceof Opcode::CallSideEffect and - resultType instanceof UnknownType + resultType = getUnknownType() ) else ( opcode instanceof Opcode::CallReadSideEffect and - resultType instanceof VoidType + resultType = getVoidType() ) - ) and - isGLValue = false + ) } override Instruction getChildSuccessor(TranslatedElement child) { @@ -105,11 +102,11 @@ abstract class TranslatedCall extends TranslatedExpr { result = getEnclosingFunction().getUnmodeledDefinitionInstruction() } - final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { tag = CallSideEffectTag() and hasSideEffect() and operandTag instanceof SideEffectOperandTag and - result instanceof UnknownType + result = getUnknownType() } final override Instruction getResult() { result = getInstruction(CallTag()) } @@ -205,18 +202,12 @@ abstract class TranslatedDirectCall extends TranslatedCall { final override Instruction getCallTargetResult() { result = getInstruction(CallTargetTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { - TranslatedCall.super.hasInstruction(opcode, tag, resultType, isGLValue) + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + TranslatedCall.super.hasInstruction(opcode, tag, resultType) or tag = CallTargetTag() and opcode instanceof Opcode::FunctionAddress and - // The database does not contain a `FunctionType` for a function unless - // its address was taken, so we'll just use glval instead of - // glval. - resultType instanceof UnknownType and - isGLValue = true + resultType = getFunctionGLValueType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -234,7 +225,7 @@ abstract class TranslatedDirectCall extends TranslatedCall { abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedCall { override Call expr; - final override Type getCallResultType() { result = getResultType() } + final override Type getCallResultType() { result = expr.getType() } final override predicate hasArguments() { exists(expr.getArgument(0)) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll index 6c501ef4284..e2fc86db7ce 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll @@ -1,6 +1,7 @@ private import cpp private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.CppType private import InstructionTag private import TranslatedElement private import TranslatedExpr @@ -37,9 +38,7 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio final override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -105,9 +104,7 @@ abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeConditio result = getLeftOperand().getFirstInstruction() } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -163,13 +160,10 @@ class TranslatedValueCondition extends TranslatedCondition, TTranslatedValueCond override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = ValueConditionConditionalBranchTag() and opcode instanceof Opcode::ConditionalBranch and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() } override Instruction getChildSuccessor(TranslatedElement child) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll index 1efe8cf9f78..294a539ec31 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll @@ -1,7 +1,8 @@ private import cpp private import semmle.code.cpp.ir.implementation.Opcode -private import semmle.code.cpp.ir.internal.IRUtilities private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.CppType +private import semmle.code.cpp.ir.internal.IRUtilities private import InstructionTag private import TranslatedElement private import TranslatedExpr @@ -54,19 +55,15 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali result = getInstruction(InitializerVariableAddressTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getVariableType(getVariable()) and - isGLValue = true + resultType = getTypeForGLValue(getVariableType(getVariable())) or hasUninitializedInstruction() and tag = InitializerStoreTag() and opcode instanceof Opcode::Uninitialized and - resultType = getVariableType(getVariable()) and - isGLValue = false + resultType = getTypeForPRValue(getVariableType(getVariable())) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 23d3036ca15..929484de2a8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -3,6 +3,7 @@ import semmle.code.cpp.ir.implementation.raw.IR private import semmle.code.cpp.ir.IRConfiguration private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition @@ -10,11 +11,6 @@ private import TranslatedFunction private import TranslatedStmt private import IRConstruction -/** - * Gets the built-in `int` type. - */ -Type getIntType() { result.(IntType).isImplicitlySigned() } - /** * Gets the "real" parent of `expr`. This predicate treats conversions as if * they were explicit nodes in the expression tree, rather than as implicit @@ -65,8 +61,8 @@ private predicate ignoreExprAndDescendants(Expr expr) { ) or // Do not translate input/output variables in GNU asm statements - getRealParent(expr) instanceof AsmStmt - or +// getRealParent(expr) instanceof AsmStmt +// or ignoreExprAndDescendants(getRealParent(expr)) // recursive case or // We do not yet translate destructors properly, so for now we ignore any @@ -494,9 +490,7 @@ abstract class TranslatedElement extends TTranslatedElement { * If the instruction does not return a result, `resultType` should be * `VoidType`. */ - abstract predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ); + abstract predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType); /** * Gets the `Function` that contains this element. @@ -536,7 +530,7 @@ abstract class TranslatedElement extends TTranslatedElement { * `tag` must be unique for each variable generated from the same AST node * (not just from the same `TranslatedElement`). */ - predicate hasTempVariable(TempVariableTag tag, Type type) { none() } + predicate hasTempVariable(TempVariableTag tag, CppType type) { none() } /** * If the instruction specified by `tag` is a `FunctionInstruction`, gets the @@ -575,6 +569,8 @@ abstract class TranslatedElement extends TTranslatedElement { */ int getInstructionResultSize(InstructionTag tag) { none() } + predicate needsUnknownBlobType(int byteSize) { none() } + /** * If the instruction specified by `tag` is a `StringConstantInstruction`, * gets the `StringLiteral` for that instruction. @@ -590,7 +586,7 @@ abstract class TranslatedElement extends TTranslatedElement { * If the instruction specified by `tag` is a `CatchByTypeInstruction`, * gets the type of the exception to be caught. */ - Type getInstructionExceptionType(InstructionTag tag) { none() } + CppType getInstructionExceptionType(InstructionTag tag) { none() } /** * If the instruction specified by `tag` is an `InheritanceConversionInstruction`, @@ -609,7 +605,7 @@ abstract class TranslatedElement extends TTranslatedElement { /** * Gets the type of the memory operand specified by `operandTag` on the the instruction specified by `tag`. */ - Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } + CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } /** * Gets the size of the memory operand specified by `operandTag` on the the instruction specified by `tag`. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index fa8eeb36adb..33a5ccfeced 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1,6 +1,8 @@ private import cpp +private import semmle.code.cpp.ir.implementation.IRType private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition @@ -51,10 +53,23 @@ abstract class TranslatedExpr extends TranslatedElement { */ abstract predicate producesExprResult(); + final CppType getResultType() { + if isResultGLValue() then + result = getTypeForGLValue(expr.getType()) + else + result = getTypeForPRValue(expr.getType()) + } + /** - * Gets the type of the result produced by this expression. + * Holds if the result of this `TranslatedExpr` is a glvalue. */ - final Type getResultType() { result = expr.getUnspecifiedType() } + private predicate isResultGLValue() { + expr.isGLValueCategory() + or + // If this TranslatedExpr doesn't produce the result, then it must represent + // a glvalue that is then loaded by a TranslatedLoad. + not producesExprResult() + } final override Locatable getAST() { result = expr } @@ -91,25 +106,6 @@ abstract class TranslatedCoreExpr extends TranslatedExpr { // is the only TranslatedExpr. ignoreLoad(expr) } - - /** - * Returns `true` if the result of this `TranslatedExpr` is a glvalue, or - * `false` if the result is a prvalue. - * - * This predicate returns a `boolean` value instead of just a being a plain - * predicate because all of the subclass predicates that call it require a - * `boolean` value. - */ - final boolean isResultGLValue() { - if - expr.isGLValueCategory() - or - // If this TranslatedExpr doesn't produce the result, then it must represent - // a glvalue that is then loaded by a TranslatedLoad. - not producesExprResult() - then result = true - else result = false - } } class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, @@ -120,38 +116,32 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { ( tag = ConditionValueTrueTempAddressTag() or tag = ConditionValueFalseTempAddressTag() or tag = ConditionValueResultTempAddressTag() ) and opcode instanceof Opcode::VariableAddress and - resultType = getResultType() and - isGLValue = true + resultType = getTypeForGLValue(expr.getType()) or ( tag = ConditionValueTrueConstantTag() or tag = ConditionValueFalseConstantTag() ) and opcode instanceof Opcode::Constant and - resultType = getResultType() and - isGLValue = isResultGLValue() + resultType = getResultType() or ( tag = ConditionValueTrueStoreTag() or tag = ConditionValueFalseStoreTag() ) and opcode instanceof Opcode::Store and - resultType = getResultType() and - isGLValue = isResultGLValue() + resultType = getResultType() or tag = ConditionValueResultLoadTag() and opcode instanceof Opcode::Load and - resultType = getResultType() and - isGLValue = isResultGLValue() + resultType = getResultType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -212,9 +202,9 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, ) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CppType type) { tag = ConditionValueTempVar() and - type = getResultType() + type = getTypeForPRValue(expr.getType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -262,13 +252,10 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad { override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = expr.getUnspecifiedType() and - if expr.isGLValueCategory() then isGLValue = true else isGLValue = false + resultType = getResultType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -324,9 +311,7 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr { child = getRightOperand() and result = getParent().getChildSuccessor(this) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -341,6 +326,10 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr { } } +private int getElementSize(Type type) { + result = max(type.getUnspecifiedType().(PointerType).getBaseType().getSize()) +} + abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { override CrementOperation expr; @@ -349,9 +338,9 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { final override string getInstructionConstantValue(InstructionTag tag) { tag = CrementConstantTag() and exists(Type resultType | - resultType = getResultType() and + resultType = expr.getUnspecifiedType() and ( - resultType instanceof IntegralType and result = "1" + resultType instanceof IntegralOrEnumType and result = "1" or resultType instanceof FloatingPointType and result = "1.0" or @@ -360,38 +349,37 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { ) } - private Type getConstantType() { + private CppType getConstantType() { exists(Type resultType | - resultType = getResultType() and + resultType = expr.getUnspecifiedType() and ( - resultType instanceof ArithmeticType and result = resultType - or + ( + resultType instanceof ArithmeticType and + result = getTypeForPRValue(expr.getType()) + ) or resultType instanceof PointerType and result = getIntType() ) ) } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue + Opcode opcode, InstructionTag tag, CppType resultType ) { - isGLValue = false and - ( - tag = CrementLoadTag() and - opcode instanceof Opcode::Load and - resultType = getResultType() - or - tag = CrementConstantTag() and - opcode instanceof Opcode::Constant and - resultType = getConstantType() - or - tag = CrementOpTag() and - opcode = getOpcode() and - resultType = getResultType() - or - tag = CrementStoreTag() and - opcode instanceof Opcode::Store and - resultType = getResultType() - ) + tag = CrementLoadTag() and + opcode instanceof Opcode::Load and + resultType = getTypeForPRValue(expr.getType()) + or + tag = CrementConstantTag() and + opcode instanceof Opcode::Constant and + resultType = getConstantType() + or + tag = CrementOpTag() and + opcode = getOpcode() and + resultType = getTypeForPRValue(expr.getType()) + or + tag = CrementStoreTag() and + opcode instanceof Opcode::Store and + resultType = getTypeForPRValue(expr.getType()) } final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -452,7 +440,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { getOpcode() instanceof Opcode::PointerAdd or getOpcode() instanceof Opcode::PointerSub ) and - result = max(getResultType().(PointerType).getBaseType().getSize()) + result = getElementSize(expr.getType()) } final TranslatedExpr getOperand() { @@ -461,7 +449,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { final Opcode getOpcode() { exists(Type resultType | - resultType = getResultType() and + resultType = expr.getUnspecifiedType() and ( ( expr instanceof IncrementOperation and @@ -542,13 +530,10 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr { override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::PointerAdd and - resultType = getResultType() and - isGLValue = true + resultType = getTypeForGLValue(expr.getType()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -564,7 +549,7 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr { override int getInstructionElementSize(InstructionTag tag) { tag = OnlyInstructionTag() and - result = max(getResultType().getSize()) + result = max(expr.getUnspecifiedType().getSize()) } private TranslatedExpr getBaseOperand() { @@ -587,9 +572,7 @@ abstract class TranslatedTransparentExpr extends TranslatedNonConstantExpr { child = getOperand() and result = getParent().getChildSuccessor(this) } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -632,7 +615,9 @@ class TranslatedTransparentConversion extends TranslatedTransparentExpr { ) } - override TranslatedExpr getOperand() { result = getTranslatedExpr(expr.getExpr()) } + override TranslatedExpr getOperand() { + result = getTranslatedExpr(expr.getExpr()) + } } class TranslatedThisExpr extends TranslatedNonConstantExpr { @@ -640,13 +625,10 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr { final override TranslatedElement getChild(int id) { none() } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::CopyValue and - resultType = expr.getUnspecifiedType() and - isGLValue = false + resultType = getResultType() } final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } @@ -707,13 +689,10 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::VariableAddress and - resultType = getResultType() and - isGLValue = true + resultType = getTypeForGLValue(expr.getType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -733,13 +712,10 @@ class TranslatedFieldAccess extends TranslatedVariableAccess { result = getQualifier().getResult() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::FieldAddress and - resultType = getResultType() and - isGLValue = true + resultType = getTypeForGLValue(expr.getType()) } override Field getInstructionField(InstructionTag tag) { @@ -763,13 +739,10 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr { kind instanceof GotoEdge } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::FunctionAddress and - resultType = expr.getUnspecifiedType() and - isGLValue = true + resultType = getResultType() } override Function getInstructionFunction(InstructionTag tag) { @@ -811,15 +784,10 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedVal none() } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode = getOpcode() and - resultType = getResultType() and - if expr.isGLValueCategory() or expr.hasLValueToRValueConversion() - then isGLValue = true - else isGLValue = false + resultType = getResultType() } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -865,13 +833,10 @@ abstract class TranslatedSingleInstructionExpr extends TranslatedNonConstantExpr */ abstract Opcode getOpcode(); - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { opcode = getOpcode() and tag = OnlyInstructionTag() and - resultType = getResultType() and - isGLValue = isResultGLValue() + resultType = getResultType() } final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } @@ -945,13 +910,10 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio child = getOperand() and result = getInstruction(OnlyInstructionTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode = getOpcode() and - resultType = getResultType() and - isGLValue = isResultGLValue() + resultType = getResultType() } override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } @@ -996,7 +958,7 @@ class TranslatedDynamicCast extends TranslatedSingleInstructionConversion { override Opcode getOpcode() { exists(Type resultType | - resultType = getResultType() and + resultType = expr.getUnspecifiedType() and if resultType instanceof PointerType then if resultType.(PointerType).getBaseType() instanceof VoidType @@ -1054,19 +1016,14 @@ class TranslatedBoolConversion extends TranslatedConversion { child = getOperand() and result = getInstruction(BoolConversionConstantTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { - isGLValue = false and - ( - tag = BoolConversionConstantTag() and - opcode instanceof Opcode::Constant and - resultType = getOperand().getResultType() - or - tag = BoolConversionCompareTag() and - opcode instanceof Opcode::CompareNE and - resultType instanceof BoolType - ) + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + tag = BoolConversionConstantTag() and + opcode instanceof Opcode::Constant and + resultType = getOperand().getResultType() + or + tag = BoolConversionCompareTag() and + opcode instanceof Opcode::CompareNE and + resultType = getBoolType() } override Instruction getResult() { result = getInstruction(BoolConversionCompareTag()) } @@ -1197,7 +1154,7 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr { opcode instanceof Opcode::PointerSub or opcode instanceof Opcode::PointerDiff ) and - result = max(getPointerOperand().getResultType().(PointerType).getBaseType().getSize()) + result = getElementSize(getPointerOperand().getExpr().getType()) ) } @@ -1282,13 +1239,10 @@ class TranslatedAssignExpr extends TranslatedAssignment { result = getInstruction(AssignmentStoreTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = AssignmentStoreTag() and opcode instanceof Opcode::Store and - resultType = getResultType() and - isGLValue = false + resultType = getTypeForPRValue(expr.getType()) // Always a prvalue } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -1365,14 +1319,15 @@ class TranslatedAssignOperation extends TranslatedAssignment { // anyway. If we really want to model this case perfectly, we'll need the // extractor to tell us what the promoted type of the left operand would // be. - result = getLeftOperand().getResultType() + result = getLeftOperand().getExpr().getType() else // The right operand has already been converted to the type of the op. - result = getRightOperand().getResultType() + result = getRightOperand().getExpr().getType() } private predicate leftOperandNeedsConversion() { - getConvertedLeftOperandType() != getLeftOperand().getResultType() + getConvertedLeftOperandType().getUnspecifiedType() != + getLeftOperand().getExpr().getUnspecifiedType() } private Opcode getOpcode() { @@ -1401,32 +1356,27 @@ class TranslatedAssignOperation extends TranslatedAssignment { expr instanceof AssignPointerSubExpr and result instanceof Opcode::PointerSub } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { - isGLValue = false and + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + tag = AssignOperationLoadTag() and + opcode instanceof Opcode::Load and + resultType = getTypeForPRValue(getLeftOperand().getExpr().getType()) + or + tag = AssignOperationOpTag() and + opcode = getOpcode() and + resultType = getTypeForPRValue(getConvertedLeftOperandType()) + or + tag = AssignmentStoreTag() and + opcode instanceof Opcode::Store and + resultType = getTypeForPRValue(expr.getType()) // Always a prvalue + or + leftOperandNeedsConversion() and + opcode instanceof Opcode::Convert and ( - tag = AssignOperationLoadTag() and - opcode instanceof Opcode::Load and - resultType = getLeftOperand().getResultType() + tag = AssignOperationConvertLeftTag() and + resultType = getTypeForPRValue(getConvertedLeftOperandType()) or - tag = AssignOperationOpTag() and - opcode = getOpcode() and - resultType = getConvertedLeftOperandType() - or - tag = AssignmentStoreTag() and - opcode instanceof Opcode::Store and - resultType = getResultType() - or - leftOperandNeedsConversion() and - opcode instanceof Opcode::Convert and - ( - tag = AssignOperationConvertLeftTag() and - resultType = getConvertedLeftOperandType() - or - tag = AssignOperationConvertResultTag() and - resultType = getLeftOperand().getResultType() - ) + tag = AssignOperationConvertResultTag() and + resultType = getTypeForPRValue(getLeftOperand().getExpr().getType()) ) } @@ -1436,7 +1386,7 @@ class TranslatedAssignOperation extends TranslatedAssignment { opcode = getOpcode() and (opcode instanceof Opcode::PointerAdd or opcode instanceof Opcode::PointerSub) ) and - result = max(getResultType().(PointerType).getBaseType().getSize()) + result = getElementSize(expr.getType()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -1518,13 +1468,10 @@ class TranslatedConstantAllocationSize extends TranslatedAllocationSize { final override Instruction getFirstInstruction() { result = getInstruction(AllocationSizeTag()) } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = AllocationSizeTag() and opcode instanceof Opcode::Constant and - resultType = expr.getAllocator().getParameter(0).getUnspecifiedType() and - isGLValue = false + resultType = getTypeForPRValue(expr.getAllocator().getParameter(0).getType()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -1557,11 +1504,8 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize { final override Instruction getFirstInstruction() { result = getExtent().getFirstInstruction() } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { - isGLValue = false and - resultType = expr.getAllocator().getParameter(0).getUnspecifiedType() and + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + resultType = getTypeForPRValue(expr.getAllocator().getParameter(0).getType()) and ( // Convert the extent to `size_t`, because the AST doesn't do this already. tag = AllocationExtentConvertTag() and opcode instanceof Opcode::Convert @@ -1633,7 +1577,9 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect tag = CallTargetTag() and result = expr.getAllocator() } - final override Type getCallResultType() { result = expr.getAllocator().getUnspecifiedType() } + final override Type getCallResultType() { + result = expr.getAllocator().getType() + } final override TranslatedExpr getQualifier() { none() } @@ -1684,13 +1630,10 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St final override TranslatedElement getChild(int id) { id = 0 and result = getDestructorCall() } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::FieldAddress and - resultType = expr.getTarget().getUnspecifiedType() and - isGLValue = true + resultType = getTypeForGLValue(expr.getTarget().getType()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -1737,9 +1680,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { not resultIsVoid() and ( ( @@ -1750,8 +1691,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont tag = ConditionValueResultTempAddressTag() ) and opcode instanceof Opcode::VariableAddress and - resultType = getResultType() and - isGLValue = true + ( + if expr.isGLValueCategory() + then resultType = getTypeForGLValue(any(UnknownType t)) // glvalue to a glvalue + else resultType = getTypeForGLValue(expr.getType()) // glvalue to the result type + ) or ( not thenIsVoid() and tag = ConditionValueTrueStoreTag() @@ -1759,13 +1703,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont not elseIsVoid() and tag = ConditionValueFalseStoreTag() ) and opcode instanceof Opcode::Store and - resultType = getResultType() and - isGLValue = false + resultType = getResultType() or tag = ConditionValueResultLoadTag() and opcode instanceof Opcode::Load and - resultType = getResultType() and - isGLValue = isResultGLValue() + resultType = getResultType() ) } @@ -1833,7 +1775,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont ) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CppType type) { not resultIsVoid() and tag = ConditionValueTempVar() and type = getResultType() @@ -1893,7 +1835,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont } private predicate thenIsVoid() { - getThen().getResultType() instanceof VoidType + getThen().getResultType().getIRType() instanceof IRVoidType or // A `ThrowExpr.getType()` incorrectly returns the type of exception being // thrown, rather than `void`. Handle that case here. @@ -1901,14 +1843,14 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont } private predicate elseIsVoid() { - getElse().getResultType() instanceof VoidType + getElse().getResultType().getIRType() instanceof IRVoidType or // A `ThrowExpr.getType()` incorrectly returns the type of exception being // thrown, rather than `void`. Handle that case here. expr.getElse() instanceof ThrowExpr } - private predicate resultIsVoid() { getResultType() instanceof VoidType } + private predicate resultIsVoid() { getResultType().getIRType() instanceof IRVoidType } } /** @@ -1917,13 +1859,10 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr { override ThrowExpr expr; - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = ThrowTag() and opcode = getThrowOpcode() and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -1950,15 +1889,12 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex result = getInstruction(InitializerVariableAddressTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { - TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType, isGLValue) + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType) or tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getExceptionType() and - isGLValue = true + resultType = getTypeForGLValue(getExceptionType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -1979,9 +1915,9 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex result = getIRTempVariable(expr, ThrowTempVar()) } - final override predicate hasTempVariable(TempVariableTag tag, Type type) { + final override predicate hasTempVariable(TempVariableTag tag, CppType type) { tag = ThrowTempVar() and - type = getExceptionType() + type = getTypeForPRValue(getExceptionType()) } final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -1995,10 +1931,10 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex ) } - final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { tag = ThrowTag() and operandTag instanceof LoadOperandTag and - result = getExceptionType() + result = getTypeForPRValue(getExceptionType()) } override Instruction getTargetAddress() { @@ -2013,7 +1949,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex final override Opcode getThrowOpcode() { result instanceof Opcode::ThrowValue } - private Type getExceptionType() { result = expr.getUnspecifiedType() } + private Type getExceptionType() { result = expr.getType() } } /** @@ -2071,13 +2007,10 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr { ) } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode = getOpcode() and - resultType = getResultType() and - isGLValue = isResultGLValue() + resultType = getResultType() } final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -2144,13 +2077,10 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr, In id = 1 and result = getInitialization() } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::Convert and - resultType = getResultType() and - isGLValue = false + resultType = getResultType() } final override Instruction getFirstInstruction() { @@ -2311,9 +2241,7 @@ class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr { child = getConditionExpr() and result = getParent().getChildSuccessor(this) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -2362,23 +2290,18 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont result = getInstruction(LoadTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getResultType() and - isGLValue = true + resultType = getTypeForGLValue(expr.getType()) or tag = InitializerStoreTag() and opcode instanceof Opcode::Uninitialized and - resultType = getResultType() and - isGLValue = false + resultType = getTypeForPRValue(expr.getType()) or tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = getResultType() and - isGLValue = false + resultType = getTypeForPRValue(expr.getType()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -2404,16 +2327,16 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont result = getTempVariable(LambdaTempVar()) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CppType type) { tag = LambdaTempVar() and - type = getResultType() + type = getTypeForPRValue(expr.getType()) } final override Instruction getTargetAddress() { result = getInstruction(InitializerVariableAddressTag()) } - final override Type getTargetType() { result = getResultType() } + final override Type getTargetType() { result = expr.getType() } private predicate hasInitializer() { exists(getInitialization()) } @@ -2444,13 +2367,10 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr { result = getInstruction(OnlyInstructionTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { opcode instanceof Opcode::CopyValue and tag instanceof OnlyInstructionTag and - resultType = expr.getType() and - isGLValue = false + resultType = getResultType() } override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index a035f8b9b31..72e074d0e92 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -1,6 +1,7 @@ private import cpp import semmle.code.cpp.ir.implementation.raw.IR private import semmle.code.cpp.ir.implementation.Opcode +private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.ir.internal.IRUtilities private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.internal.TempVariableTag @@ -115,55 +116,46 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or ( child = getDestructorDestructionList() and - if getReturnType() instanceof VoidType - then result = getInstruction(ReturnTag()) - else result = getInstruction(ReturnValueAddressTag()) + if hasReturnValue() + then result = getInstruction(ReturnValueAddressTag()) + else result = getInstruction(ReturnTag()) ) } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { ( tag = EnterFunctionTag() and opcode instanceof Opcode::EnterFunction and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() or tag = UnmodeledDefinitionTag() and opcode instanceof Opcode::UnmodeledDefinition and - resultType instanceof UnknownType and - isGLValue = false + resultType = getUnknownType() or tag = AliasedDefinitionTag() and opcode instanceof Opcode::AliasedDefinition and - resultType instanceof UnknownType and - isGLValue = false + resultType = getUnknownType() or tag = InitializeThisTag() and opcode instanceof Opcode::InitializeThis and - resultType = getThisType() and - isGLValue = true + resultType = getTypeForGLValue(getThisType()) or tag = ReturnValueAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getReturnType() and - not resultType instanceof VoidType and - isGLValue = true + resultType = getTypeForGLValue(getReturnType()) and + hasReturnValue() or ( tag = ReturnTag() and - resultType instanceof VoidType and - isGLValue = false and - if getReturnType() instanceof VoidType - then opcode instanceof Opcode::ReturnVoid - else opcode instanceof Opcode::ReturnValue + resultType = getVoidType() and + if hasReturnValue() + then opcode instanceof Opcode::ReturnValue + else opcode instanceof Opcode::ReturnVoid ) or tag = UnwindTag() and opcode instanceof Opcode::Unwind and - resultType instanceof VoidType and - isGLValue = false and + resultType = getVoidType() and ( // Only generate the `Unwind` instruction if there is any exception // handling present in the function. @@ -173,13 +165,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or tag = UnmodeledUseTag() and opcode instanceof Opcode::UnmodeledUse and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() or tag = ExitFunctionTag() and opcode instanceof Opcode::ExitFunction and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() ) } @@ -198,7 +188,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = getUnmodeledDefinitionInstruction() or tag = ReturnTag() and - not getReturnType() instanceof VoidType and + hasReturnValue() and ( operandTag instanceof AddressOperandTag and result = getInstruction(ReturnValueAddressTag()) @@ -208,11 +198,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { ) } - final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { tag = ReturnTag() and - not getReturnType() instanceof VoidType and + hasReturnValue() and operandTag instanceof LoadOperandTag and - result = getReturnType() + result = getTypeForPRValue(getReturnType()) } final override IRVariable getInstructionVariable(InstructionTag tag) { @@ -220,10 +210,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = getReturnVariable() } - final override predicate hasTempVariable(TempVariableTag tag, Type type) { + final override predicate hasTempVariable(TempVariableTag tag, CppType type) { tag = ReturnValueTempVar() and - type = getReturnType() and - not type instanceof VoidType + hasReturnValue() and + type = getTypeForPRValue(getReturnType()) } /** @@ -241,6 +231,13 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = getIRTempVariable(func, ReturnValueTempVar()) } + /** + * Holds if the function has a non-`void` return type. + */ + final predicate hasReturnValue() { + not func.getUnspecifiedType() instanceof VoidType + } + /** * Gets the single `UnmodeledDefinition` instruction for this function. */ @@ -271,7 +268,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { * parameters and local variables, plus any global variables or static data members that are * directly accessed by the function. */ - final predicate hasUserVariable(Variable var, Type type) { + final predicate hasUserVariable(Variable var, CppType type) { ( ( var instanceof GlobalOrNamespaceVariable @@ -287,10 +284,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or var.(Parameter).getCatchBlock().getEnclosingFunction() = func ) and - type = getVariableType(var) + type = getTypeForPRValue(getVariableType(var)) } - final private Type getReturnType() { result = func.getUnspecifiedType() } + final Type getReturnType() { result = func.getType() } } /** @@ -335,18 +332,14 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter { final override Instruction getChildSuccessor(TranslatedElement child) { none() } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getVariableType(param) and - isGLValue = true + resultType = getTypeForGLValue(getVariableType(param)) or tag = InitializerStoreTag() and opcode instanceof Opcode::InitializeParameter and - resultType = getVariableType(param) and - isGLValue = false + resultType = getTypeForPRValue(getVariableType(param)) } final override IRVariable getInstructionVariable(InstructionTag tag) { @@ -404,9 +397,7 @@ class TranslatedConstructorInitList extends TranslatedElement, InitializationCon else result = getParent().getChildSuccessor(this) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -469,9 +460,7 @@ class TranslatedDestructorDestructionList extends TranslatedElement, else result = getParent().getChildSuccessor(this) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll index 01c29d422f4..9f4b5660021 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -1,6 +1,7 @@ private import cpp private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.CppType private import InstructionTag private import TranslatedElement private import TranslatedExpr @@ -79,9 +80,7 @@ abstract class TranslatedListInitialization extends TranslatedInitialization, In ) } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -150,13 +149,10 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio not expr instanceof StringLiteral } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = InitializerStoreTag() and opcode instanceof Opcode::Store and - resultType = getContext().getTargetType() and - isGLValue = false + resultType = getTypeForPRValue(getContext().getTargetType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -188,20 +184,16 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio class TranslatedStringLiteralInitialization extends TranslatedDirectInitialization { override StringLiteral expr; - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { // Load the string literal to make it a prvalue of type `char[len]` tag = InitializerLoadStringTag() and opcode instanceof Opcode::Load and - resultType = getInitializer().getResultType() and - isGLValue = false + resultType = getTypeForPRValue(expr.getType()) or // Store the string into the target. tag = InitializerStoreTag() and opcode instanceof Opcode::Store and - resultType = getInitializer().getResultType() and - isGLValue = false + resultType = getTypeForPRValue(expr.getType()) or exists(int startIndex, int elementCount | // If the initializer string isn't large enough to fill the target, then @@ -213,26 +205,22 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati // space in the target array. tag = ZeroPadStringConstantTag() and opcode instanceof Opcode::Constant and - resultType instanceof UnknownType and - isGLValue = false + resultType = getUnknownBlobType(elementCount * getElementType().getSize()) or // The index of the first element to be zero initialized. tag = ZeroPadStringElementIndexTag() and opcode instanceof Opcode::Constant and - resultType = getIntType() and - isGLValue = false + resultType = getIntType() or // Compute the address of the first element to be zero initialized. tag = ZeroPadStringElementAddressTag() and opcode instanceof Opcode::PointerAdd and - resultType = getElementType() and - isGLValue = true + resultType = getTypeForGLValue(getElementType()) or // Store the constant zero into the remainder of the string. tag = ZeroPadStringStoreTag() and opcode instanceof Opcode::Store and - resultType instanceof UnknownType and - isGLValue = false + resultType = getUnknownBlobType(elementCount * getElementType().getSize()) ) ) } @@ -326,6 +314,13 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati ) } + override predicate needsUnknownBlobType(int byteSize) { + exists(int elementCount | + zeroInitRange(_, elementCount) and + byteSize = elementCount * getElementType().getSize() + ) + } + override int getInstructionResultSize(InstructionTag tag) { exists(int elementCount | zeroInitRange(_, elementCount) and @@ -338,7 +333,7 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati } private Type getElementType() { - result = getContext().getTargetType().(ArrayType).getBaseType().getUnspecifiedType() + result = getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType() } /** @@ -348,7 +343,7 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati private predicate zeroInitRange(int startIndex, int elementCount) { exists(int targetCount | startIndex = expr.getUnspecifiedType().(ArrayType).getArraySize() and - targetCount = getContext().getTargetType().(ArrayType).getArraySize() and + targetCount = getContext().getTargetType().getUnspecifiedType().(ArrayType).getArraySize() and elementCount = targetCount - startIndex and elementCount > 0 ) @@ -359,9 +354,7 @@ class TranslatedConstructorInitialization extends TranslatedDirectInitialization StructorCallContext { override ConstructorCall expr; - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -412,13 +405,10 @@ abstract class TranslatedFieldInitialization extends TranslatedElement { */ final int getOrder() { result = field.getInitializationOrder() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = getFieldAddressTag() and opcode instanceof Opcode::FieldAddress and - resultType = field.getUnspecifiedType() and - isGLValue = true + resultType = getTypeForGLValue(field.getType()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -481,20 +471,16 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization, TTranslatedFieldValueInitialization { TranslatedFieldValueInitialization() { this = TTranslatedFieldValueInitialization(ast, field) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { - TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType, isGLValue) + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType) or tag = getFieldDefaultValueTag() and opcode instanceof Opcode::Constant and - resultType = field.getUnspecifiedType() and - isGLValue = false + resultType = getTypeForPRValue(field.getType()) or tag = getFieldDefaultValueStoreTag() and opcode instanceof Opcode::Store and - resultType = field.getUnspecifiedType() and - isGLValue = false + resultType = getTypeForPRValue(field.getUnspecifiedType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -557,18 +543,14 @@ abstract class TranslatedElementInitialization extends TranslatedElement { final override Instruction getFirstInstruction() { result = getInstruction(getElementIndexTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = getElementIndexTag() and opcode instanceof Opcode::Constant and - resultType = getIntType() and - isGLValue = false + resultType = getIntType() or tag = getElementAddressTag() and opcode instanceof Opcode::PointerAdd and - resultType = getElementType() and - isGLValue = true + resultType = getTypeForGLValue(getElementType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -606,7 +588,7 @@ abstract class TranslatedElementInitialization extends TranslatedElement { final ArrayOrVectorAggregateLiteral getInitList() { result = initList } - final Type getElementType() { result = initList.getElementType().getUnspecifiedType() } + final Type getElementType() { result = initList.getElementType() } } /** @@ -659,20 +641,16 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati this = TTranslatedElementValueInitialization(initList, elementIndex, elementCount) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { - TranslatedElementInitialization.super.hasInstruction(opcode, tag, resultType, isGLValue) + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + TranslatedElementInitialization.super.hasInstruction(opcode, tag, resultType) or tag = getElementDefaultValueTag() and opcode instanceof Opcode::Constant and - resultType = getDefaultValueType() and - isGLValue = false + resultType = getDefaultValueType() or tag = getElementDefaultValueStoreTag() and opcode instanceof Opcode::Store and - resultType = getDefaultValueType() and - isGLValue = false + resultType = getDefaultValueType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -726,6 +704,10 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati override int getElementIndex() { result = elementIndex } + override predicate needsUnknownBlobType(int byteSize) { + elementCount != 0 and byteSize = elementCount * getElementType().getSize() + } + private InstructionTag getElementDefaultValueTag() { result = InitializerElementDefaultValueTag() } @@ -734,8 +716,11 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati result = InitializerElementDefaultValueStoreTag() } - private Type getDefaultValueType() { - if elementCount = 1 then result = getElementType() else result instanceof UnknownType + private CppType getDefaultValueType() { + if elementCount = 1 then + result = getTypeForPRValue(getElementType()) + else + result = getUnknownBlobType(elementCount * getElementType().getSize()) } } @@ -766,13 +751,10 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStructor { final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::ConvertToBase and - resultType = call.getTarget().getDeclaringType().getUnspecifiedType() and - isGLValue = true + resultType = getTypeForGLValue(call.getTarget().getDeclaringType()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -822,9 +804,7 @@ class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromC result = getStructorCall().getFirstInstruction() } - final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index d84e9fc1c4e..f1fd2575b3b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -1,6 +1,7 @@ private import cpp private import semmle.code.cpp.ir.internal.IRUtilities private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition @@ -35,13 +36,10 @@ class TranslatedEmptyStmt extends TranslatedStmt { override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::NoOp and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -63,9 +61,7 @@ class TranslatedDeclStmt extends TranslatedStmt { override TranslatedElement getChild(int id) { result = getDeclarationEntry(id) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -112,9 +108,7 @@ class TranslatedExprStmt extends TranslatedStmt { override TranslatedElement getChild(int id) { id = 0 and result = getExpr() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -145,13 +139,10 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationCont result = getInstruction(InitializerVariableAddressTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getEnclosingFunction().getReturnVariable().getType() and - isGLValue = true + resultType = getTypeForGLValue(getEnclosingFunction().getReturnType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -174,7 +165,9 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationCont result = getInstruction(InitializerVariableAddressTag()) } - override Type getTargetType() { result = getEnclosingFunction().getReturnVariable().getType() } + override Type getTargetType() { + result = getEnclosingFunction().getReturnType() + } TranslatedInitialization getInitialization() { result = getTranslatedInitialization(stmt.getExpr().getFullyConverted()) @@ -188,13 +181,10 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt { override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::NoOp and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -218,9 +208,7 @@ class TranslatedTryStmt extends TranslatedStmt { result = getHandler(id - 1) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -262,14 +250,11 @@ class TranslatedBlock extends TranslatedStmt { override TranslatedElement getChild(int id) { result = getStmt(id) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { isEmpty() and opcode instanceof Opcode::NoOp and tag = OnlyInstructionTag() and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() } override Instruction getFirstInstruction() { @@ -330,13 +315,10 @@ abstract class TranslatedHandler extends TranslatedStmt { class TranslatedCatchByTypeHandler extends TranslatedHandler { TranslatedCatchByTypeHandler() { exists(stmt.getParameter()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = CatchTag() and opcode instanceof Opcode::CatchByType and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() } override TranslatedElement getChild(int id) { @@ -362,9 +344,9 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler { ) } - override Type getInstructionExceptionType(InstructionTag tag) { + override CppType getInstructionExceptionType(InstructionTag tag) { tag = CatchTag() and - result = stmt.getParameter().getType() + result = getTypeForPRValue(stmt.getParameter().getType()) } private TranslatedParameter getParameter() { @@ -378,13 +360,10 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler { class TranslatedCatchAnyHandler extends TranslatedHandler { TranslatedCatchAnyHandler() { not exists(stmt.getParameter()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = CatchTag() and opcode instanceof Opcode::CatchAny and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -436,9 +415,7 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext { result = getParent().getChildSuccessor(this) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } } @@ -466,9 +443,7 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext { id = 1 and result = getBody() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -597,9 +572,7 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext { result = getCondition().getFirstInstruction() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { none() } @@ -649,13 +622,10 @@ class TranslatedJumpStmt extends TranslatedStmt { override TranslatedElement getChild(int id) { none() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and opcode instanceof Opcode::NoOp and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -693,13 +663,10 @@ class TranslatedSwitchStmt extends TranslatedStmt { id = 1 and result = getBody() } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = SwitchBranchTag() and opcode instanceof Opcode::Switch and - resultType instanceof VoidType and - isGLValue = false + resultType = getVoidType() } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -727,37 +694,20 @@ class TranslatedSwitchStmt extends TranslatedStmt { class TranslatedAsmStmt extends TranslatedStmt { override AsmStmt stmt; - override TranslatedElement getChild(int id) { none() } + override TranslatedExpr getChild(int id) { + result = getTranslatedExpr(stmt.getChild(id).(Expr).getFullyConverted()) + } override Instruction getFirstInstruction() { - if exists(stmt.getChild(0)) - then result = getInstruction(AsmInputTag(0)) + if exists(getChild(0)) + then result = getChild(0).getFirstInstruction() else result = getInstruction(AsmTag()) } - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue - ) { + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = AsmTag() and opcode instanceof Opcode::InlineAsm and - resultType instanceof UnknownType and - isGLValue = false - or - exists(int index, VariableAccess va | - tag = AsmInputTag(index) and - stmt.getChild(index) = va and - opcode instanceof Opcode::VariableAddress and - resultType = va.getType().getUnspecifiedType() and - isGLValue = true - ) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - exists(int index | - tag = AsmInputTag(index) and - result = getIRUserVariable(stmt.getEnclosingFunction(), - stmt.getChild(index).(VariableAccess).getTarget()) - ) + resultType = getUnknownType() } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -768,29 +718,28 @@ class TranslatedAsmStmt extends TranslatedStmt { exists(int index | tag = AsmTag() and operandTag = asmOperand(index) and - result = getInstruction(AsmInputTag(index)) + result = getChild(index).getResult() ) } - final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { tag = AsmTag() and operandTag instanceof SideEffectOperandTag and - result instanceof UnknownType + result = getUnknownType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = AsmTag() and result = getParent().getChildSuccessor(this) and kind instanceof GotoEdge - or + } + + override Instruction getChildSuccessor(TranslatedElement child) { exists(int index | - tag = AsmInputTag(index) and - kind instanceof GotoEdge and - if exists(stmt.getChild(index + 1)) - then result = getInstruction(AsmInputTag(index + 1)) + child = getChild(index) and + if exists(getChild(index + 1)) + then result = getChild(index + 1).getFirstInstruction() else result = getInstruction(AsmTag()) ) } - - override Instruction getChildSuccessor(TranslatedElement child) { none() } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll index 278040f8ab8..badd48552a5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll @@ -5,6 +5,7 @@ import IRVariable import Operand private import internal.IRImports as Imports import Imports::EdgeKind +import Imports::IRType import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll index 3921472dc8e..6ee2e687015 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll @@ -1,2 +1,3 @@ private import IR import InstructionSanity +import IRTypeSanity \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index a7ca4593ac4..d17b810785e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -5,6 +5,7 @@ import Imports::TempVariableTag private import Imports::IRUtilities private import Imports::TTempVariableTag private import Imports::TIRVariable +private import Imports::IRType IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { result.getVariable() = var and @@ -24,7 +25,21 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - abstract Language::Type getType(); + final Language::Type getType() { + getLanguageType().hasType(result, false) + } + + /** + * Gets the language-neutral type of the variable. + */ + final IRType getIRType() { + result = getLanguageType().getIRType() + } + + /** + * Gets the type of the variable. + */ + abstract Language::LanguageType getLanguageType(); /** * Gets the AST node that declared this variable, or that introduced this @@ -59,7 +74,7 @@ abstract class IRVariable extends TIRVariable { */ class IRUserVariable extends IRVariable, TIRUserVariable { Language::Variable var; - Language::Type type; + Language::LanguageType type; IRUserVariable() { this = TIRUserVariable(var, type, func) } @@ -71,7 +86,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable { result = getVariable().toString() + " " + getVariable().getLocation().toString() } - final override Language::Type getType() { result = type } + final override Language::LanguageType getLanguageType() { result = type } /** * Gets the original user-declared variable. @@ -110,11 +125,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { Language::AST ast; TempVariableTag tag; - Language::Type type; + Language::LanguageType type; IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - final override Language::Type getType() { result = type } + final override Language::LanguageType getLanguageType() { result = type } final override Language::AST getAST() { result = ast } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 43f9663d2cd..f84871e227d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -113,10 +113,13 @@ module InstructionSanity { } query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func | + exists(Language::Function func, Instruction use | not exists(operand.getType()) and - func = operand.getUse().getEnclosingFunction() and - message = "Operand missing type in function '" + Language::getIdentityString(func) + "'." + use = operand.getUse() and + func = use.getEnclosingFunction() and + message = "Operand '" + operand.toString() + "' of instruction '" + + use.getOpcode().toString() + "' missing type in function '" + + Language::getIdentityString(func) + "'." ) } @@ -344,23 +347,6 @@ class Instruction extends Construction::TInstruction { ) } - bindingset[type] - private string getValueCategoryString(string type) { - if isGLValue() then result = "glval<" + type + ">" else result = type - } - - string getResultTypeString() { - exists(string valcat | - valcat = getValueCategoryString(getResultType().toString()) and - if - getResultType() instanceof Language::UnknownType and - not isGLValue() and - exists(getResultSize()) - then result = valcat + "[" + getResultSize().toString() + "]" - else result = valcat - ) - } - /** * Gets a human-readable string that uniquely identifies this instruction * within the function. This string is used to refer to this instruction when @@ -380,7 +366,9 @@ class Instruction extends Construction::TInstruction { * * Example: `r1_1(int*)` */ - final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" } + final string getResultString() { + result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")" + } /** * Gets a string describing the operands of this instruction, suitable for @@ -448,6 +436,10 @@ class Instruction extends Construction::TInstruction { result = Construction::getInstructionUnconvertedResultExpression(this) } + final Language::LanguageType getResultLanguageType() { + result = Construction::getInstructionResultType(this) + } + /** * Gets the type of the result produced by this instruction. If the * instruction does not produce a result, its result type will be `VoidType`. @@ -455,7 +447,16 @@ class Instruction extends Construction::TInstruction { * If `isGLValue()` holds, then the result type of this instruction should be * thought of as "pointer to `getResultType()`". */ - final Language::Type getResultType() { Construction::instructionHasType(this, result, _) } + final Language::Type getResultType() { + exists(Language::LanguageType resultType, Language::Type langType | + resultType = getResultLanguageType() and + ( + resultType.hasType(langType, _) or + not resultType.hasType(_, _) and result instanceof Language::UnknownType + ) and + result = langType.getUnspecifiedType() + ) + } /** * Holds if the result produced by this instruction is a glvalue. If this @@ -475,7 +476,9 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::instructionHasType(this, _, true) } + final predicate isGLValue() { + Construction::getInstructionResultType(this).hasType(_, true) + } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -485,14 +488,7 @@ class Instruction extends Construction::TInstruction { * `getResultSize()` will always be the size of a pointer. */ final int getResultSize() { - if isGLValue() - then - // a glvalue is always pointer-sized. - result = Language::getPointerSize() - else - if getResultType() instanceof Language::UnknownType - then result = Construction::getInstructionResultSize(this) - else result = Language::getTypeSize(getResultType()) + result = Construction::getInstructionResultType(this).getByteSize() } /** @@ -1300,7 +1296,7 @@ class CatchInstruction extends Instruction { * An instruction that catches an exception of a specific type. */ class CatchByTypeInstruction extends CatchInstruction { - Language::Type exceptionType; + Language::LanguageType exceptionType; CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and @@ -1312,7 +1308,7 @@ class CatchByTypeInstruction extends CatchInstruction { /** * Gets the type of exception to be caught. */ - final Language::Type getExceptionType() { result = exceptionType } + final Language::LanguageType getExceptionType() { result = exceptionType } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 1ced8ef3282..e3485825064 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -1,9 +1,10 @@ private import internal.IRInternal -import Instruction -import IRBlock +private import Instruction +private import IRBlock private import internal.OperandImports as Imports -import Imports::MemoryAccessKind -import Imports::Overlap +private import Imports::MemoryAccessKind +private import Imports::IRType +private import Imports::Overlap private import Imports::OperandTag cached @@ -143,22 +144,40 @@ class Operand extends TOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - Language::Type getType() { result = getAnyDef().getResultType() } + Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() } + + /** + * Gets the language-neutral type of the value consumed by this operand. This is usually the same + * as the result type of the definition instruction consumed by this operand. For register + * operands, this is always the case. For some memory operands, the operand type may be different + * from the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + final IRType getIRType() { result = getLanguageType().getIRType() } + + /** + * Gets the type of the value consumed by this operand. This is usually the same as the + * result type of the definition instruction consumed by this operand. For register operands, + * this is always the case. For some memory operands, the operand type may be different from + * the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + final Language::Type getType() { getLanguageType().hasType(result, _) } /** * Holds if the value consumed by this operand is a glvalue. If this * holds, the value of the operand represents the address of a location, * and the type of the location is given by `getType()`. If this does * not hold, the value of the operand represents a value whose type is - * given by `getResultType()`. + * given by `getType()`. */ - predicate isGLValue() { getAnyDef().isGLValue() } + final predicate isGLValue() { getLanguageType().hasType(_, true) } /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. */ - int getSize() { result = Language::getTypeSize(getType()) } + final int getSize() { result = getLanguageType().getByteSize() } } /** @@ -170,11 +189,6 @@ class MemoryOperand extends Operand { this = TPhiOperand(_, _, _, _) } - override predicate isGLValue() { - // A `MemoryOperand` can never be a glvalue - none() - } - /** * Gets the kind of memory access performed by the operand. */ @@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; - final override Language::Type getType() { + final override Language::LanguageType getLanguageType() { result = Construction::getInstructionOperandType(useInstr, tag) } } @@ -371,12 +385,6 @@ class PositionalArgumentOperand extends ArgumentOperand { class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - final override int getSize() { - if getType() instanceof Language::UnknownType - then result = Construction::getInstructionOperandSize(useInstr, tag) - else result = Language::getTypeSize(getType()) - } - override MemoryAccessKind getMemoryAccess() { useInstr instanceof CallSideEffectInstruction and result instanceof EscapedMayMemoryAccess diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRImports.qll index 74f7b4a2b64..42d6e7db693 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRImports.qll @@ -1,2 +1,3 @@ import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll index 1f0f5eaccde..8c60565defc 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll @@ -1,3 +1,4 @@ +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandImports.qll index e626662ccf2..3c781579cee 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandImports.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll index a5c09c6401b..c73826bd4c8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll @@ -4,34 +4,52 @@ private import Alias private import SSAConstruction private import DebugSSA +bindingset[offset] +private string getKeySuffixForOffset(int offset) { + if offset % 2 = 0 then result = "" else result = "_Chi" +} + +bindingset[offset] +private int getIndexForOffset(int offset) { result = offset / 2 } + /** * Property provide that dumps the memory access of each result. Useful for debugging SSA * construction. */ class PropertyProvider extends IRPropertyProvider { override string getInstructionProperty(Instruction instruction, string key) { - exists(MemoryLocation location | - location = getResultMemoryLocation(instruction) and - ( - key = "ResultMemoryLocation" and result = location.toString() - or - key = "ResultVirtualVariable" and result = location.getVirtualVariable().toString() + key = "ResultMemoryLocation" and + result = strictconcat(MemoryLocation loc | + loc = getResultMemoryLocation(instruction) + | + loc.toString(), "," ) - ) or - exists(MemoryLocation location | - location = getOperandMemoryLocation(instruction.getAnOperand()) and - ( - key = "OperandMemoryAccess" and result = location.toString() - or - key = "OperandVirtualVariable" and result = location.getVirtualVariable().toString() + key = "ResultVirtualVariable" and + result = strictconcat(MemoryLocation loc | + loc = getResultMemoryLocation(instruction) + | + loc.getVirtualVariable().toString(), "," ) - ) or - exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | - hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and - defBlock.getInstruction(defIndex) = instruction and - key = "DefinitionRank[" + useLocation.toString() + "]" and + key = "OperandMemoryLocation" and + result = strictconcat(MemoryLocation loc | + loc = getOperandMemoryLocation(instruction.getAnOperand()) + | + loc.toString(), "," + ) + or + key = "OperandVirtualVariable" and + result = strictconcat(MemoryLocation loc | + loc = getOperandMemoryLocation(instruction.getAnOperand()) + | + loc.getVirtualVariable().toString(), "," + ) + or + exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset | + hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and + defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and + key = "DefinitionRank" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + "]" and result = defRank.toString() ) or @@ -41,10 +59,11 @@ class PropertyProvider extends IRPropertyProvider { result = useRank.toString() ) or - exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | - hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and - defBlock.getInstruction(defIndex) = instruction and - key = "DefinitionReachesUse[" + useLocation.toString() + "]" and + exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset | + hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and + defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and + key = "DefinitionReachesUse" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + + "]" and result = strictconcat(IRBlock useBlock, int useRank, int useIndex | exists(Instruction useInstruction | hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and @@ -124,3 +143,4 @@ class PropertyProvider extends IRPropertyProvider { ) } } + diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 1ca6e099795..9c1b52ed4e5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,4 @@ import SSAConstructionInternal -private import cpp private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.internal.Overlap @@ -18,7 +17,7 @@ private module Cached { } cached - predicate functionHasIR(Function func) { + predicate functionHasIR(Language::Function func) { exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) } @@ -42,7 +41,7 @@ private module Cached { not oldInstruction instanceof OldIR::PhiInstruction and hasChiNode(_, oldInstruction) } or - Unreached(Function function) { + Unreached(Language::Function function) { exists(OldInstruction oldInstruction | function = oldInstruction.getEnclosingFunction() and Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) @@ -50,12 +49,14 @@ private module Cached { } cached - predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) { + predicate hasTempVariable( + Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type + ) { exists(OldIR::IRTempVariable var | var.getEnclosingFunction() = func and var.getAST() = ast and var.getTag() = tag and - var.getType() = type + var.getLanguageType() = type ) } @@ -135,24 +136,12 @@ private module Cached { } cached - Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) { + Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) { exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | oldInstruction = getOldInstruction(instr) and oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and - result = oldOperand.getType() - ) - } - - cached - int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) { - exists(OldInstruction oldInstruction, OldIR::SideEffectOperand oldOperand | - oldInstruction = getOldInstruction(instr) and - oldOperand = oldInstruction.getAnOperand() and - tag = oldOperand.getOperandTag() and - // Only return a result for operands that need an explicit result size. - oldOperand.getType() instanceof UnknownType and - result = oldOperand.getSize() + result = oldOperand.getLanguageType() ) } @@ -196,20 +185,21 @@ private module Cached { } cached - Expr getInstructionConvertedResultExpression(Instruction instruction) { + Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { result = getOldInstruction(instruction).getConvertedResultExpression() } cached - Expr getInstructionUnconvertedResultExpression(Instruction instruction) { + Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { result = getOldInstruction(instruction).getUnconvertedResultExpression() } - /** + /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are * the new instructions generated from the successors of the old instruction */ + cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) @@ -252,7 +242,7 @@ private module Cached { } cached - Locatable getInstructionAST(Instruction instruction) { + Language::AST getInstructionAST(Instruction instruction) { exists(OldInstruction oldInstruction | instruction = WrappedInstruction(oldInstruction) or @@ -270,29 +260,25 @@ private module Cached { } cached - predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) { + Language::LanguageType getInstructionResultType(Instruction instruction) { exists(OldInstruction oldInstruction | instruction = WrappedInstruction(oldInstruction) and - type = oldInstruction.getResultType() and - if oldInstruction.isGLValue() then isGLValue = true else isGLValue = false + result = oldInstruction.getResultLanguageType() ) or exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | instruction = Chi(oldInstruction) and hasChiNode(vvar, oldInstruction) and - type = vvar.getType() and - isGLValue = false + result = vvar.getType() ) or exists(Alias::MemoryLocation location | instruction = Phi(_, location) and - type = location.getType() and - isGLValue = false + result = location.getType() ) or instruction = Unreached(_) and - type instanceof VoidType and - isGLValue = false + result = Language::getVoidType() } cached @@ -338,12 +324,12 @@ private module Cached { } cached - Field getInstructionField(Instruction instruction) { + Language::Field getInstructionField(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() } cached - Function getInstructionFunction(Instruction instruction) { + Language::Function getInstructionFunction(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() } @@ -353,19 +339,19 @@ private module Cached { } cached - StringLiteral getInstructionStringLiteral(Instruction instruction) { + Language::StringLiteral getInstructionStringLiteral(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue() } cached - BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { + Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { result = getOldInstruction(instruction) .(OldIR::BuiltInOperationInstruction) .getBuiltInOperation() } cached - Type getInstructionExceptionType(Instruction instruction) { + Language::LanguageType getInstructionExceptionType(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() } @@ -375,14 +361,9 @@ private module Cached { } cached - int getInstructionResultSize(Instruction instruction) { - // Only return a result for instructions that needed an explicit result size. - instruction.getResultType() instanceof UnknownType and - result = getOldInstruction(instruction).getResultSize() - } - - cached - predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { + predicate getInstructionInheritance( + Instruction instruction, Language::Class baseClass, Language::Class derivedClass + ) { exists(OldIR::InheritanceConversionInstruction oldInstr | oldInstr = getOldInstruction(instruction) and baseClass = oldInstr.getBaseClass() and @@ -879,3 +860,4 @@ private module CachedForDebugging { result.getTag() = var.getTag() } } + diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index dc19a8130d9..4cfbdfe831e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -2,4 +2,5 @@ import semmle.code.cpp.ir.implementation.raw.IR as OldIR import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR +import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SimpleSSA as Alias diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index 7cca5855a20..5577799513c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -1,24 +1,24 @@ import AliasAnalysis -private import cpp private import semmle.code.cpp.ir.implementation.raw.IR private import semmle.code.cpp.ir.internal.IntegerConstant as Ints private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.internal.IRCppLanguage as Language private import semmle.code.cpp.ir.internal.Overlap private class IntValue = Ints::IntValue; private predicate hasResultMemoryAccess( - Instruction instr, IRVariable var, Type type, IntValue bitOffset + Instruction instr, IRVariable var, Language::LanguageType type, IntValue bitOffset ) { resultPointsTo(instr.getResultAddressOperand().getAnyDef(), var, bitOffset) and - type = instr.getResultType() + type = instr.getResultLanguageType() } private predicate hasOperandMemoryAccess( - MemoryOperand operand, IRVariable var, Type type, IntValue bitOffset + MemoryOperand operand, IRVariable var, Language::LanguageType type, IntValue bitOffset ) { resultPointsTo(operand.getAddressOperand().getAnyDef(), var, bitOffset) and - type = operand.getType() + type = operand.getLanguageType() } /** @@ -30,17 +30,17 @@ private predicate isVariableModeled(IRVariable var) { not variableAddressEscapes(var) and // There's no need to check for the right size. An `IRVariable` never has an `UnknownType`, so the test for // `type = var.getType()` is sufficient. - forall(Instruction instr, Type type, IntValue bitOffset | + forall(Instruction instr, Language::LanguageType type, IntValue bitOffset | hasResultMemoryAccess(instr, var, type, bitOffset) | bitOffset = 0 and - type = var.getType() + type.getIRType() = var.getIRType() ) and - forall(MemoryOperand operand, Type type, IntValue bitOffset | + forall(MemoryOperand operand, Language::LanguageType type, IntValue bitOffset | hasOperandMemoryAccess(operand, var, type, bitOffset) | bitOffset = 0 and - type = var.getType() + type.getIRType() = var.getIRType() ) } @@ -59,7 +59,7 @@ class MemoryLocation extends TMemoryLocation { final VirtualVariable getVirtualVariable() { result = this } - final Type getType() { result = var.getType() } + final Language::LanguageType getType() { result = var.getLanguageType() } final string getUniqueId() { result = var.getUniqueId() } } @@ -85,3 +85,4 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { result = getMemoryLocation(var) ) } + diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll new file mode 100644 index 00000000000..5af6b402ee3 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -0,0 +1,500 @@ +private import cpp +private import semmle.code.cpp.Print +private import semmle.code.cpp.ir.implementation.IRType +private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction + +/** + * Works around an extractor bug where a function reference gets a size of one byte. + */ +private int getTypeSizeWorkaround(Type type) { + exists(Type unspecifiedType | + unspecifiedType = type.getUnspecifiedType() and + ( + unspecifiedType instanceof FunctionReferenceType and + result = any(NullPointerType t).getSize() + or + exists(PointerToMemberType ptmType | + ptmType = unspecifiedType and + ( + if ptmType.getBaseType().getUnspecifiedType() instanceof RoutineType + then result = any(NullPointerType t).getSize() * 2 + else result = any(NullPointerType t).getSize() + ) + ) + ) + ) +} + +private int getTypeSize(Type type) { + if exists(getTypeSizeWorkaround(type)) + then result = getTypeSizeWorkaround(type) + else result = type.getSize() +} + +/** + * Holds if an `IRBooleanType` with the specified `byteSize` should exist. + */ +predicate hasBooleanType(int byteSize) { + byteSize = getTypeSize(any(BoolType type)) +} + +private predicate isSigned(IntegralOrEnumType type) { + type.(IntegralType).isSigned() or + exists(Enum enumType | + enumType = type.getUnspecifiedType() and + ( + enumType.getExplicitUnderlyingType().getUnspecifiedType().(IntegralType).isSigned() or + not exists(enumType.getExplicitUnderlyingType()) // Assume signed. + ) + ) +} + +private predicate isSignedIntegerType(IntegralOrEnumType type) { + isSigned(type) and not type instanceof BoolType +} + +private predicate isUnsignedIntegerType(IntegralOrEnumType type) { + not isSigned(type) and not type instanceof BoolType +} + +/** + * Holds if an `IRSignedIntegerType` with the specified `byteSize` should exist. + */ +predicate hasSignedIntegerType(int byteSize) { + byteSize = any(IntegralOrEnumType type | isSignedIntegerType(type)).getSize() +} + +/** + * Holds if an `IRUnsignedIntegerType` with the specified `byteSize` should exist. + */ +predicate hasUnsignedIntegerType(int byteSize) { + byteSize = any(IntegralOrEnumType type | isUnsignedIntegerType(type)).getSize() +} + +/** + * Holds if an `IRFloatingPointType` with the specified `byteSize` should exist. + */ +predicate hasFloatingPointType(int byteSize) { + byteSize = any(FloatingPointType type).getSize() +} + +private predicate isPointerIshType(Type type) { + type instanceof PointerType or + type instanceof ReferenceType or + type instanceof NullPointerType +} + +/** + * Holds if an `IRAddressType` with the specified `byteSize` should exist. + */ +predicate hasAddressType(int byteSize) { + // This covers all pointers, all references, and because it also looks at `NullPointerType`, it + // should always return a result that makes sense for arbitrary glvalues as well. + byteSize = any(Type type | isPointerIshType(type)).getSize() +} + +/** + * Holds if an `IRFunctionAddressType` with the specified `byteSize` should exist. + */ +predicate hasFunctionAddressType(int byteSize) { + byteSize = any(NullPointerType type).getSize() or // Covers function lvalues + byteSize = getTypeSize(any(FunctionPointerIshType type)) +} + +private predicate isBlobType(Type type) { + ( + exists(type.getSize()) and // Only include complete types + ( + type instanceof ArrayType or + type instanceof Class or + type instanceof GNUVectorType + ) + ) or + type instanceof PointerToMemberType // PTMs are missing size info +} + +/** + * Holds if an `IRBlobType` with the specified `tag` and `byteSize` should exist. + */ +predicate hasBlobType(Type tag, int byteSize) { + isBlobType(tag) and byteSize = getTypeSize(tag) + or + tag instanceof UnknownType and IRConstruction::needsUnknownBlobType(byteSize) +} + +/** + * Gets the `IRType` that represents a prvalue of the specified `Type`. + */ +private IRType getIRTypeForPRValue(Type type) { + exists(Type unspecifiedType | + unspecifiedType = type.getUnspecifiedType() | + ( + isBlobType(unspecifiedType) and + exists(IRBlobType blobType | + blobType = result | + blobType.getByteSize() = getTypeSize(type) and + blobType.getTag() = unspecifiedType + ) + ) or + unspecifiedType instanceof BoolType and result.(IRBooleanType).getByteSize() = type.getSize() or + isSignedIntegerType(unspecifiedType) and result.(IRSignedIntegerType).getByteSize() = type.getSize() or + isUnsignedIntegerType(unspecifiedType) and result.(IRUnsignedIntegerType).getByteSize() = type.getSize() or + unspecifiedType instanceof FloatingPointType and result.(IRFloatingPointType).getByteSize() = type.getSize() or + isPointerIshType(unspecifiedType) and result.(IRAddressType).getByteSize() = type.getSize() or + unspecifiedType instanceof FunctionPointerIshType and result.(IRFunctionAddressType).getByteSize() = getTypeSize(type) or + unspecifiedType instanceof VoidType and result instanceof IRVoidType or + unspecifiedType instanceof ErroneousType and result instanceof IRErrorType or + unspecifiedType instanceof UnknownType and result instanceof IRUnknownType + ) +} + +private newtype TCppType = + TPRValueType(Type type) { + exists(getIRTypeForPRValue(type)) + } or + TFunctionGLValueType() or + TGLValueAddressType(Type type) { + any() + } or + TUnknownBlobType(int byteSize) { + IRConstruction::needsUnknownBlobType(byteSize) + } or + TUnknownType() + +/** + * The C++ type of an IR entity. + * This cannot just be `Type` for a couple reasons: + * - Some types needed by the IR might not exist in the database (e.g. `RoutineType`s for functions + * that are always called directly) + * - Some types needed by the IR are not representable in the C++ type system (e.g. the result type + * of a `VariableAddress` where the variable is of reference type) + */ +class CppType extends TCppType { + string toString() { + result = "" + } + + /** Gets a string used in IR dumps */ + string getDumpString() { result = toString() } + + /** Gets the size of the type in bytes, if known. */ + final int getByteSize() { result = getIRType().getByteSize() } + + /** + * Gets the `IRType` that represents this `CppType`. Many different `CppType`s can map to a single + * `IRType`. + */ + abstract IRType getIRType(); + + /** + * Holds if the `CppType` represents a prvalue of type `Type` (if `isGLValue` is `false`), or if + * it represents a glvalue of type `Type` (if `isGLValue` is `true`). + */ + abstract predicate hasType(Type type, boolean isGLValue); +} + +/** + * A `CppType` that wraps an existing `Type` (either as a prvalue or a glvalue). + */ +private class CppWrappedType extends CppType { + Type ctype; + + CppWrappedType() { + this = TPRValueType(ctype) or + this = TGLValueAddressType(ctype) + } + + abstract override IRType getIRType(); + abstract override predicate hasType(Type type, boolean isGLValue); +} + +/** + * A `CppType` that represents a prvalue of an existing `Type`. + */ +private class CppPRValueType extends CppWrappedType, TPRValueType { + override final string toString() { result = ctype.toString() } + + override final string getDumpString() { result = ctype.getUnspecifiedType().toString() } + + override final IRType getIRType() { result = getIRTypeForPRValue(ctype) } + + override final predicate hasType(Type type, boolean isGLValue) { + type = ctype and + isGLValue = false + } +} + +/** + * A `CppType` that has unknown type but a known size. Generally to represent synthesized types that + * occur in certain cases during IR construction, such as the type of a zero-initialized segment of + * a partially-initialized array. + */ +private class CppUnknownBlobType extends CppType, TUnknownBlobType { + int byteSize; + + CppUnknownBlobType() { + this = TUnknownBlobType(byteSize) + } + + override final string toString() { + result = "unknown[" + byteSize.toString() + "]" + } + + override final IRBlobType getIRType() { + result.getByteSize() = byteSize + } + + override predicate hasType(Type type, boolean isGLValue) { + type instanceof UnknownType and isGLValue = false + } +} + +/** + * A `CppType` that represents a glvalue of an existing `Type`. + */ +private class CppGLValueAddressType extends CppWrappedType, TGLValueAddressType { + override final string toString() { + result = "glval<" + ctype.toString() + ">" + } + + override final string getDumpString() { + result = "glval<" + ctype.getUnspecifiedType().toString() + ">" + } + + override final IRAddressType getIRType() { + result.getByteSize() = any(NullPointerType t).getSize() + } + + override final predicate hasType(Type type, boolean isGLValue) { + type = ctype and + isGLValue = true + } +} + +/** + * A `CppType` that represents a function lvalue. + */ +private class CppFunctionGLValueType extends CppType, TFunctionGLValueType { + override final string toString() { + result = "glval" + } + + override final IRFunctionAddressType getIRType() { + result.getByteSize() = any(NullPointerType type).getSize() + } + + override final predicate hasType(Type type, boolean isGLValue) { + type instanceof UnknownType and isGLValue = true + } +} + +/** + * A `CppType` that represents an unknown type. + */ +private class CppUnknownType extends CppType, TUnknownType { + override final string toString() { + result = any(UnknownType type).toString() + } + + override final IRUnknownType getIRType() { + any() + } + + override final predicate hasType(Type type, boolean isGLValue) { + type instanceof UnknownType and isGLValue = false + } +} + +/** + * Gets the single instance of `CppUnknownType`. + */ +CppUnknownType getUnknownType() { + any() +} + +/** + * Gets the `CppType` that represents a prvalue of type `void`. + */ +CppPRValueType getVoidType() { + exists(VoidType voidType | + result.hasType(voidType, false) + ) +} + +/** + * Gets the `CppType` that represents a prvalue of type `type`. + */ +CppType getTypeForPRValue(Type type) { + if type instanceof UnknownType + then result instanceof CppUnknownType + else result.hasType(type, false) +} + +/** + * Gets the `CppType` that represents a glvalue of type `type`. + */ +CppType getTypeForGLValue(Type type) { + result.hasType(type, true) +} + +/** + * Gets the `CppType` that represents a prvalue of type `int`. + */ +CppPRValueType getIntType() { + exists(IntType type | + type.isImplicitlySigned() and + result.hasType(type, false) + ) +} + +/** + * Gets the `CppType` that represents a prvalue of type `bool`. + */ +CppPRValueType getBoolType() { + exists(BoolType type | + result.hasType(type, false) + ) +} + +/** + * Gets the `CppType` that represents a glvalue of function type. + */ +CppFunctionGLValueType getFunctionGLValueType() { + any() +} + +/** + * Gets the `CppType` that represents a blob of unknown type with size `byteSize`. + */ +CppUnknownBlobType getUnknownBlobType(int byteSize) { + result.getByteSize() = byteSize +} + +/** + * Gets the `CppType` that is the canonical type for an `IRBooleanType` with the specified + * `byteSize`. + */ +CppWrappedType getCanonicalBooleanType(int byteSize) { + exists(BoolType type | + result = TPRValueType(type) and byteSize = type.getSize() + ) +} + +/** + * Compute the sorting priority of an `IntegralType` based on its signedness. + */ +private int getSignPriority(IntegralType type) { + /* + Explicitly unsigned types sort first. Explicitly signed types sort last. Types with no explicit + signedness sort in between. This lets us always choose `int` over `signed int`, while also + choosing `unsigned char`+`char` when `char` is signed, and `unsigned char`+`signed char` when + `char` is unsigned. + */ + if type.isExplicitlyUnsigned() + then result = 2 + else if type.isExplicitlySigned() + then result = 0 + else result = 1 +} + +/** + * Gets the sort priority of an `IntegralType` based on its kind. + */ +private int getKindPriority(IntegralType type) { + /* + `CharType` sorts lower so that we prefer the plain integer types when they have the same size as + a `CharType`. + */ + if type instanceof CharType + then result = 0 + else result = 1 +} + +/** + * Gets the `CppType` that is the canonical type for an `IRSignedIntegerType` with the specified + * `byteSize`. + */ +CppPRValueType getCanonicalSignedIntegerType(int byteSize) { + result = TPRValueType(max(IntegralType type | type.isSigned() and type.getSize() = byteSize | + type order by getKindPriority(type), getSignPriority(type), type.toString() desc)) +} + +/** + * Gets the `CppType` that is the canonical type for an `IRUnsignedIntegerType` with the specified + * `byteSize`. + */ +CppPRValueType getCanonicalUnsignedIntegerType(int byteSize) { + result = TPRValueType(max(IntegralType type | type.isUnsigned() and type.getSize() = byteSize | + type order by getKindPriority(type), getSignPriority(type), type.toString() desc)) +} + +/** + * Gets the `CppType` that is the canonical type for an `IRFloatingPointType` with the specified + * `byteSize`. + */ +CppPRValueType getCanonicalFloatingPointType(int byteSize) { + result = TPRValueType(max(FloatingPointType type | type.getSize() = byteSize | + type order by type.toString() desc)) +} + +/** + * Gets the `CppType` that is the canonical type for an `IRAddressType` with the specified + * `byteSize`. + */ +CppPRValueType getCanonicalAddressType(int byteSize) { + // We just use `NullPointerType`, since it should be unique. + exists(NullPointerType type | + type.getSize() = byteSize and + result = TPRValueType(type) + ) +} + +/** + * Gets the `CppType` that is the canonical type for an `IRFunctionAddressType` with the specified + * `byteSize`. + */ +CppFunctionGLValueType getCanonicalFunctionAddressType(int byteSize) { + result.getByteSize() = byteSize +} + +/** + * Gets the `CppType` that is the canonical type for `IRErrorType`. + */ +CppPRValueType getCanonicalErrorType() { + result = TPRValueType(any(ErroneousType type)) +} + +/** + * Gets the `CppType` that is the canonical type for `IRUnknownType`. + */ +CppUnknownType getCanonicalUnknownType() { + any() +} + +/** + * Gets the `CppType` that is the canonical type for `IRVoidType`. + */ +CppPRValueType getCanonicalVoidType() { + result = TPRValueType(any(VoidType type)) +} + +/** + * Gets the `CppType` that is the canonical type for an `IRBlobType` with the specified `tag` and + * `byteSize`. + */ +CppType getCanonicalBlobType(Type tag, int byteSize) { + isBlobType(tag) and + result = TPRValueType(tag.getUnspecifiedType()) and + getTypeSize(tag) = byteSize + or + tag instanceof UnknownType and result = getUnknownBlobType(byteSize) +} + +/** + * Gets a string that uniquely identifies an `IRBlobType` tag. This may be different from the usual + * `toString()` of the tag in order to ensure uniqueness. + */ +string getBlobTagIdentityString(Type tag) { + hasBlobType(tag, _) and + result = getTypeIdentityString(tag) +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll index cda661bd216..56622b2e37a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll @@ -1,6 +1,13 @@ private import cpp as Cpp private import semmle.code.cpp.Print as Print private import IRUtilities +private import semmle.code.cpp.ir.implementation.IRType +private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction +import CppType + +class LanguageType = CppType; + +class BlobTypeTag = Cpp::Type; class Function = Cpp::Function; diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index d675fa95d21..e32f682fcaf 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -7795,16 +7795,16 @@ ir.cpp: # 1101| 0: [VariableAccess] x # 1101| Type = [IntType] int # 1101| ValueCategory = prvalue(load) -# 1104| [TopLevelFunction] void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) +# 1104| [TopLevelFunction] void AsmStmtWithOutputs(unsigned int&, unsigned int, unsigned int&, unsigned int) # 1104| params: # 1104| 0: [Parameter] a # 1104| Type = [LValueReferenceType] unsigned int & # 1104| 1: [Parameter] b -# 1104| Type = [LValueReferenceType] unsigned int & +# 1104| Type = [IntType] unsigned int # 1104| 2: [Parameter] c # 1104| Type = [LValueReferenceType] unsigned int & # 1104| 3: [Parameter] d -# 1104| Type = [LValueReferenceType] unsigned int & +# 1104| Type = [IntType] unsigned int # 1105| body: [Block] { ... } # 1106| 0: [AsmStmt] asm statement # 1109| 0: [ReferenceDereferenceExpr] (reference dereference) @@ -7813,24 +7813,18 @@ ir.cpp: # 1109| expr: [VariableAccess] a # 1109| Type = [LValueReferenceType] unsigned int & # 1109| ValueCategory = prvalue(load) -# 1109| 1: [ReferenceDereferenceExpr] (reference dereference) +# 1109| 1: [VariableAccess] b # 1109| Type = [IntType] unsigned int # 1109| ValueCategory = lvalue -# 1109| expr: [VariableAccess] b -# 1109| Type = [LValueReferenceType] unsigned int & -# 1109| ValueCategory = prvalue(load) # 1109| 2: [ReferenceDereferenceExpr] (reference dereference) # 1109| Type = [IntType] unsigned int -# 1109| ValueCategory = lvalue +# 1109| ValueCategory = prvalue(load) # 1109| expr: [VariableAccess] c # 1109| Type = [LValueReferenceType] unsigned int & # 1109| ValueCategory = prvalue(load) -# 1109| 3: [ReferenceDereferenceExpr] (reference dereference) +# 1109| 3: [VariableAccess] d # 1109| Type = [IntType] unsigned int -# 1109| ValueCategory = lvalue -# 1109| expr: [VariableAccess] d -# 1109| Type = [LValueReferenceType] unsigned int & -# 1109| ValueCategory = prvalue(load) +# 1109| ValueCategory = prvalue(load) # 1111| 1: [ReturnStmt] return ... # 1113| [TopLevelFunction] void ExternDeclarations() # 1113| params: diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected index ae680785ce6..28d42be0d96 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected @@ -13,3 +13,5 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +missingCanonicalLanguageType +multipleCanonicalLanguageTypes diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index 672c8d1ab81..5ca9dbec64d 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -1101,12 +1101,12 @@ int AsmStmt(int x) { return x; } -static void AsmStmtWithOutputs(unsigned int& a, unsigned int& b, unsigned int& c, unsigned int& d) +static void AsmStmtWithOutputs(unsigned int& a, unsigned int b, unsigned int& c, unsigned int d) { __asm__ __volatile__ ( "cpuid\n\t" - : "+a" (a), "+b" (b), "+c" (c), "+d" (d) + : "+a" (a), "+b" (b) : "c" (c), "d" (d) ); } diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 20f15e4f772..6335565402a 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -2192,24 +2192,24 @@ ir.cpp: #-----| True -> Block 2 # 489| Block 1 -# 489| r1_0(glval) = VariableAddress[#temp489:6] : -# 489| r1_1(glval) = Load : &:r1_0, ~mu0_2 -# 489| mu1_2(int) = Store : &:r1_1, r0_9 -# 490| v1_3(void) = NoOp : -# 486| v1_4(void) = ReturnVoid : -# 486| v1_5(void) = UnmodeledUse : mu* -# 486| v1_6(void) = ExitFunction : +# 489| r1_0(glval) = VariableAddress[#temp489:6] : +# 489| r1_1(glval) = Load : &:r1_0, ~mu0_2 +# 489| mu1_2(int) = Store : &:r1_1, r0_9 +# 490| v1_3(void) = NoOp : +# 486| v1_4(void) = ReturnVoid : +# 486| v1_5(void) = UnmodeledUse : mu* +# 486| v1_6(void) = ExitFunction : # 489| Block 2 -# 489| r2_0(glval) = VariableAddress[x] : -# 489| r2_1(glval) = VariableAddress[#temp489:6] : -# 489| mu2_2(int) = Store : &:r2_1, r2_0 +# 489| r2_0(glval) = VariableAddress[x] : +# 489| r2_1(glval) = VariableAddress[#temp489:6] : +# 489| mu2_2(glval) = Store : &:r2_1, r2_0 #-----| Goto -> Block 1 # 489| Block 3 -# 489| r3_0(glval) = VariableAddress[y] : -# 489| r3_1(glval) = VariableAddress[#temp489:6] : -# 489| mu3_2(int) = Store : &:r3_1, r3_0 +# 489| r3_0(glval) = VariableAddress[y] : +# 489| r3_1(glval) = VariableAddress[#temp489:6] : +# 489| mu3_2(glval) = Store : &:r3_1, r3_0 #-----| Goto -> Block 1 # 492| void Conditional_Void(bool) @@ -2684,12 +2684,12 @@ ir.cpp: # 590| mu0_1(unknown) = AliasedDefinition : # 590| mu0_2(unknown) = UnmodeledDefinition : # 591| r0_3(glval<..(*)(..)>) = VariableAddress[pfn] : -# 591| r0_4(glval<..(*)(..)>) = FunctionAddress[FuncPtrTarget] : +# 591| r0_4(..(*)(..)) = FunctionAddress[FuncPtrTarget] : # 591| mu0_5(..(*)(..)) = Store : &:r0_3, r0_4 # 592| r0_6(glval<..()(..)>) = FunctionAddress[FuncPtrTarget] : # 592| r0_7(glval<..(*)(..)>) = VariableAddress[pfn] : # 592| mu0_8(..(*)(..)) = Store : &:r0_7, r0_6 -# 593| r0_9(glval<..(*)(..)>) = FunctionAddress[FuncPtrTarget] : +# 593| r0_9(..(*)(..)) = FunctionAddress[FuncPtrTarget] : # 593| r0_10(glval<..(*)(..)>) = VariableAddress[pfn] : # 593| mu0_11(..(*)(..)) = Store : &:r0_10, r0_9 # 594| r0_12(glval<..()(..)>) = FunctionAddress[FuncPtrTarget] : @@ -4535,7 +4535,7 @@ ir.cpp: # 1029| mu0_2(unknown) = UnmodeledDefinition : # 1029| r0_3(glval) = InitializeThis : # 1029| r0_4(glval<..(*)(..)>) = VariableAddress[#return] : -# 1029| r0_5(glval<..(*)(..)>) = FunctionAddress[_FUN] : +# 1029| r0_5(..(*)(..)) = FunctionAddress[_FUN] : # 1029| mu0_6(..(*)(..)) = Store : &:r0_4, r0_5 # 1029| r0_7(glval<..(*)(..)>) = VariableAddress[#return] : # 1029| v0_8(void) = ReturnValue : &:r0_7, ~mu0_2 @@ -4722,7 +4722,7 @@ ir.cpp: # 1032| mu0_2(unknown) = UnmodeledDefinition : # 1032| r0_3(glval) = InitializeThis : # 1032| r0_4(glval<..(*)(..)>) = VariableAddress[#return] : -# 1032| r0_5(glval<..(*)(..)>) = FunctionAddress[_FUN] : +# 1032| r0_5(..(*)(..)) = FunctionAddress[_FUN] : # 1032| mu0_6(..(*)(..)) = Store : &:r0_4, r0_5 # 1032| r0_7(glval<..(*)(..)>) = VariableAddress[#return] : # 1032| v0_8(void) = ReturnValue : &:r0_7, ~mu0_2 @@ -5090,28 +5090,32 @@ ir.cpp: # 1099| v0_12(void) = UnmodeledUse : mu* # 1099| v0_13(void) = ExitFunction : -# 1104| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) +# 1104| void AsmStmtWithOutputs(unsigned int&, unsigned int, unsigned int&, unsigned int) # 1104| Block 0 # 1104| v0_0(void) = EnterFunction : # 1104| mu0_1(unknown) = AliasedDefinition : # 1104| mu0_2(unknown) = UnmodeledDefinition : # 1104| r0_3(glval) = VariableAddress[a] : # 1104| mu0_4(unsigned int &) = InitializeParameter[a] : &:r0_3 -# 1104| r0_5(glval) = VariableAddress[b] : -# 1104| mu0_6(unsigned int &) = InitializeParameter[b] : &:r0_5 +# 1104| r0_5(glval) = VariableAddress[b] : +# 1104| mu0_6(unsigned int) = InitializeParameter[b] : &:r0_5 # 1104| r0_7(glval) = VariableAddress[c] : # 1104| mu0_8(unsigned int &) = InitializeParameter[c] : &:r0_7 -# 1104| r0_9(glval) = VariableAddress[d] : -# 1104| mu0_10(unsigned int &) = InitializeParameter[d] : &:r0_9 -# 1106| r0_11(glval) = VariableAddress[a] : -# 1106| r0_12(glval) = VariableAddress[b] : -# 1106| r0_13(glval) = VariableAddress[c] : -# 1106| r0_14(glval) = VariableAddress[d] : -# 1106| mu0_15(unknown) = InlineAsm : ~mu0_2, 0:r0_11, 1:r0_12, 2:r0_13, 3:r0_14 -# 1111| v0_16(void) = NoOp : -# 1104| v0_17(void) = ReturnVoid : -# 1104| v0_18(void) = UnmodeledUse : mu* -# 1104| v0_19(void) = ExitFunction : +# 1104| r0_9(glval) = VariableAddress[d] : +# 1104| mu0_10(unsigned int) = InitializeParameter[d] : &:r0_9 +# 1109| r0_11(glval) = VariableAddress[a] : +# 1109| r0_12(unsigned int &) = Load : &:r0_11, ~mu0_2 +# 1109| r0_13(glval) = VariableAddress[b] : +# 1109| r0_14(glval) = VariableAddress[c] : +# 1109| r0_15(unsigned int &) = Load : &:r0_14, ~mu0_2 +# 1109| r0_16(unsigned int) = Load : &:r0_15, ~mu0_2 +# 1109| r0_17(glval) = VariableAddress[d] : +# 1109| r0_18(unsigned int) = Load : &:r0_17, ~mu0_2 +# 1106| mu0_19(unknown) = InlineAsm : ~mu0_2, 0:r0_12, 1:r0_13, 2:r0_16, 3:r0_18 +# 1111| v0_20(void) = NoOp : +# 1104| v0_21(void) = ReturnVoid : +# 1104| v0_22(void) = UnmodeledUse : mu* +# 1104| v0_23(void) = ExitFunction : # 1113| void ExternDeclarations() # 1113| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected index ae680785ce6..28d42be0d96 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected @@ -13,3 +13,5 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +missingCanonicalLanguageType +multipleCanonicalLanguageTypes diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected index ae680785ce6..28d42be0d96 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -13,3 +13,5 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +missingCanonicalLanguageType +multipleCanonicalLanguageTypes 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 fe11d99f31f..791e79acfb4 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 @@ -738,26 +738,28 @@ ssa.cpp: # 184| mu0_2(unknown) = UnmodeledDefinition : # 184| r0_3(glval) = VariableAddress[a] : # 184| m0_4(unsigned int &) = InitializeParameter[a] : &:r0_3 -# 184| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 -# 184| r0_6(glval) = VariableAddress[b] : -# 184| m0_7(unsigned int &) = InitializeParameter[b] : &:r0_6 -# 184| m0_8(unknown) = Chi : total:m0_5, partial:m0_7 -# 184| r0_9(glval) = VariableAddress[c] : -# 184| m0_10(unsigned int &) = InitializeParameter[c] : &:r0_9 -# 184| m0_11(unknown) = Chi : total:m0_8, partial:m0_10 -# 184| r0_12(glval) = VariableAddress[d] : -# 184| m0_13(unsigned int &) = InitializeParameter[d] : &:r0_12 -# 184| m0_14(unknown) = Chi : total:m0_11, partial:m0_13 -# 186| r0_15(glval) = VariableAddress[a] : -# 186| r0_16(glval) = VariableAddress[b] : -# 186| r0_17(glval) = VariableAddress[c] : -# 186| r0_18(glval) = VariableAddress[d] : -# 186| m0_19(unknown) = InlineAsm : ~mu0_2, 0:r0_15, 1:r0_16, 2:r0_17, 3:r0_18 -# 186| m0_20(unknown) = Chi : total:m0_14, partial:m0_19 -# 192| v0_21(void) = NoOp : -# 184| v0_22(void) = ReturnVoid : -# 184| v0_23(void) = UnmodeledUse : mu* -# 184| v0_24(void) = ExitFunction : +# 184| r0_5(glval) = VariableAddress[b] : +# 184| m0_6(unsigned int &) = InitializeParameter[b] : &:r0_5 +# 184| r0_7(glval) = VariableAddress[c] : +# 184| m0_8(unsigned int &) = InitializeParameter[c] : &:r0_7 +# 184| r0_9(glval) = VariableAddress[d] : +# 184| m0_10(unsigned int &) = InitializeParameter[d] : &:r0_9 +# 189| r0_11(glval) = VariableAddress[a] : +# 189| r0_12(unsigned int &) = Load : &:r0_11, m0_4 +# 189| r0_13(glval) = VariableAddress[b] : +# 189| r0_14(unsigned int &) = Load : &:r0_13, m0_6 +# 190| r0_15(glval) = VariableAddress[c] : +# 190| r0_16(unsigned int &) = Load : &:r0_15, m0_8 +# 190| r0_17(unsigned int) = Load : &:r0_16, ~m0_1 +# 190| r0_18(glval) = VariableAddress[d] : +# 190| r0_19(unsigned int &) = Load : &:r0_18, m0_10 +# 190| r0_20(unsigned int) = Load : &:r0_19, ~m0_1 +# 186| m0_21(unknown) = InlineAsm : ~mu0_2, 0:r0_12, 1:r0_14, 2:r0_17, 3:r0_20 +# 186| m0_22(unknown) = Chi : total:m0_1, partial:m0_21 +# 192| v0_23(void) = NoOp : +# 184| v0_24(void) = ReturnVoid : +# 184| v0_25(void) = UnmodeledUse : mu* +# 184| v0_26(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected index ae680785ce6..28d42be0d96 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected @@ -13,3 +13,5 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +missingCanonicalLanguageType +multipleCanonicalLanguageTypes diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index ce0d9323340..2167d8a86ce 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -708,22 +708,28 @@ ssa.cpp: # 184| mu0_1(unknown) = AliasedDefinition : # 184| mu0_2(unknown) = UnmodeledDefinition : # 184| r0_3(glval) = VariableAddress[a] : -# 184| mu0_4(unsigned int &) = InitializeParameter[a] : &:r0_3 +# 184| m0_4(unsigned int &) = InitializeParameter[a] : &:r0_3 # 184| r0_5(glval) = VariableAddress[b] : -# 184| mu0_6(unsigned int &) = InitializeParameter[b] : &:r0_5 +# 184| m0_6(unsigned int &) = InitializeParameter[b] : &:r0_5 # 184| r0_7(glval) = VariableAddress[c] : -# 184| mu0_8(unsigned int &) = InitializeParameter[c] : &:r0_7 +# 184| m0_8(unsigned int &) = InitializeParameter[c] : &:r0_7 # 184| r0_9(glval) = VariableAddress[d] : -# 184| mu0_10(unsigned int &) = InitializeParameter[d] : &:r0_9 -# 186| r0_11(glval) = VariableAddress[a] : -# 186| r0_12(glval) = VariableAddress[b] : -# 186| r0_13(glval) = VariableAddress[c] : -# 186| r0_14(glval) = VariableAddress[d] : -# 186| mu0_15(unknown) = InlineAsm : ~mu0_2, 0:r0_11, 1:r0_12, 2:r0_13, 3:r0_14 -# 192| v0_16(void) = NoOp : -# 184| v0_17(void) = ReturnVoid : -# 184| v0_18(void) = UnmodeledUse : mu* -# 184| v0_19(void) = ExitFunction : +# 184| m0_10(unsigned int &) = InitializeParameter[d] : &:r0_9 +# 189| r0_11(glval) = VariableAddress[a] : +# 189| r0_12(unsigned int &) = Load : &:r0_11, m0_4 +# 189| r0_13(glval) = VariableAddress[b] : +# 189| r0_14(unsigned int &) = Load : &:r0_13, m0_6 +# 190| r0_15(glval) = VariableAddress[c] : +# 190| r0_16(unsigned int &) = Load : &:r0_15, m0_8 +# 190| r0_17(unsigned int) = Load : &:r0_16, ~mu0_2 +# 190| r0_18(glval) = VariableAddress[d] : +# 190| r0_19(unsigned int &) = Load : &:r0_18, m0_10 +# 190| r0_20(unsigned int) = Load : &:r0_19, ~mu0_2 +# 186| mu0_21(unknown) = InlineAsm : ~mu0_2, 0:r0_12, 1:r0_14, 2:r0_17, 3:r0_20 +# 192| v0_22(void) = NoOp : +# 184| v0_23(void) = ReturnVoid : +# 184| v0_24(void) = UnmodeledUse : mu* +# 184| v0_25(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected index ae680785ce6..28d42be0d96 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected @@ -13,3 +13,5 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +missingCanonicalLanguageType +multipleCanonicalLanguageTypes diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index 5e76fb042be..b2dc47ce096 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -14,7 +14,7 @@ instructionWithoutSuccessor | condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | | condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | | cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | +| misc.c:171:10:171:13 | VariableAddress: definition of str2 | | misc.c:219:47:219:48 | InitializeParameter: sp | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | | ms_try_mix.cpp:11:12:11:15 | Chi: call to C | @@ -22,7 +22,7 @@ instructionWithoutSuccessor | ms_try_mix.cpp:48:10:48:13 | Chi: call to C | | pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} | | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | -| vla.c:5:9:5:14 | Uninitialized: definition of matrix | +| vla.c:5:9:5:14 | VariableAddress: definition of matrix | | vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | ambiguousSuccessors | allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | @@ -541,3 +541,5 @@ lostReachability | range_analysis.c:371:37:371:39 | Constant: 500 | backEdgeCountMismatch useNotDominatedByDefinition +missingCanonicalLanguageType +multipleCanonicalLanguageTypes diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index b9c4bd7eba5..d99a5e854ff 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -35,10 +35,12 @@ instructionWithoutSuccessor | file://:0:0:0:0 | CompareNE: (bool)... | | file://:0:0:0:0 | CompareNE: (bool)... | | file://:0:0:0:0 | CompareNE: (bool)... | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | +| misc.c:171:10:171:13 | VariableAddress: definition of str2 | | misc.c:171:15:171:31 | Add: ... + ... | +| misc.c:173:10:173:12 | VariableAddress: definition of buf | | misc.c:173:14:173:26 | Mul: ... * ... | | misc.c:173:37:173:39 | Store: array to pointer conversion | +| misc.c:174:10:174:15 | VariableAddress: definition of matrix | | misc.c:174:17:174:22 | CallSideEffect: call to getInt | | misc.c:174:30:174:35 | CallSideEffect: call to getInt | | misc.c:174:55:174:60 | Store: (char ****)... | @@ -78,7 +80,7 @@ instructionWithoutSuccessor | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | | stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) | | stmt_in_type.cpp:5:53:5:53 | Constant: 1 | -| vla.c:5:9:5:14 | Uninitialized: definition of matrix | +| vla.c:5:9:5:14 | VariableAddress: definition of matrix | | vla.c:5:16:5:19 | Load: argc | | vla.c:5:22:5:25 | CallReadSideEffect: call to atoi | | vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | @@ -87,6 +89,7 @@ instructionWithoutSuccessor | vla.c:13:12:13:14 | Uninitialized: definition of var | | vla.c:14:36:14:47 | Add: ... + ... | | vla.c:14:53:14:65 | Mul: ... * ... | +| vla.c:14:69:14:72 | VariableAddress: definition of buf2 | | vla.c:14:74:14:79 | CallSideEffect: call to getInt | | vla.c:14:92:14:94 | Store: (char *)... | ambiguousSuccessors @@ -687,3 +690,5 @@ useNotDominatedByDefinition | vla.c:14:40:14:45 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | vla.c:11:6:11:16 | IR: vla_typedef | void vla_typedef() | | vla.c:14:58:14:63 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | vla.c:11:6:11:16 | IR: vla_typedef | void vla_typedef() | | vla.c:14:74:14:79 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | vla.c:11:6:11:16 | IR: vla_typedef | void vla_typedef() | +missingCanonicalLanguageType +multipleCanonicalLanguageTypes diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index ab5362cb06c..8d05e647437 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -23,7 +23,7 @@ instructionWithoutSuccessor | condition_decls.cpp:41:22:41:23 | CallSideEffect: call to BoxedInt | | condition_decls.cpp:48:52:48:53 | CallSideEffect: call to BoxedInt | | cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | +| misc.c:171:10:171:13 | VariableAddress: definition of str2 | | misc.c:219:47:219:48 | InitializeParameter: sp | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | | ms_try_mix.cpp:11:12:11:15 | CallSideEffect: call to C | @@ -31,7 +31,7 @@ instructionWithoutSuccessor | ms_try_mix.cpp:48:10:48:13 | CallSideEffect: call to C | | pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} | | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | -| vla.c:5:9:5:14 | Uninitialized: definition of matrix | +| vla.c:5:9:5:14 | VariableAddress: definition of matrix | | vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | ambiguousSuccessors | allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | @@ -550,3 +550,5 @@ lostReachability | range_analysis.c:371:37:371:39 | Constant: 500 | backEdgeCountMismatch useNotDominatedByDefinition +missingCanonicalLanguageType +multipleCanonicalLanguageTypes diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll index 908a208b83a..fea67ef5ecd 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll @@ -2,11 +2,11 @@ private import TIRVariableInternal private import Imports::TempVariableTag newtype TIRVariable = - TIRUserVariable(Language::Variable var, Language::Type type, Language::Function func) { + TIRUserVariable(Language::Variable var, Language::LanguageType type, Language::Function func) { Construction::hasUserVariable(func, var, type) } or TIRTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::Type type + Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type ) { Construction::hasTempVariable(func, ast, tag, type) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll index 278040f8ab8..badd48552a5 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll @@ -5,6 +5,7 @@ import IRVariable import Operand private import internal.IRImports as Imports import Imports::EdgeKind +import Imports::IRType import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll index 3921472dc8e..6ee2e687015 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll @@ -1,2 +1,3 @@ private import IR import InstructionSanity +import IRTypeSanity \ No newline at end of file diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll index a7ca4593ac4..d17b810785e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll @@ -5,6 +5,7 @@ import Imports::TempVariableTag private import Imports::IRUtilities private import Imports::TTempVariableTag private import Imports::TIRVariable +private import Imports::IRType IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { result.getVariable() = var and @@ -24,7 +25,21 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - abstract Language::Type getType(); + final Language::Type getType() { + getLanguageType().hasType(result, false) + } + + /** + * Gets the language-neutral type of the variable. + */ + final IRType getIRType() { + result = getLanguageType().getIRType() + } + + /** + * Gets the type of the variable. + */ + abstract Language::LanguageType getLanguageType(); /** * Gets the AST node that declared this variable, or that introduced this @@ -59,7 +74,7 @@ abstract class IRVariable extends TIRVariable { */ class IRUserVariable extends IRVariable, TIRUserVariable { Language::Variable var; - Language::Type type; + Language::LanguageType type; IRUserVariable() { this = TIRUserVariable(var, type, func) } @@ -71,7 +86,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable { result = getVariable().toString() + " " + getVariable().getLocation().toString() } - final override Language::Type getType() { result = type } + final override Language::LanguageType getLanguageType() { result = type } /** * Gets the original user-declared variable. @@ -110,11 +125,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { Language::AST ast; TempVariableTag tag; - Language::Type type; + Language::LanguageType type; IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - final override Language::Type getType() { result = type } + final override Language::LanguageType getLanguageType() { result = type } final override Language::AST getAST() { result = ast } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 43f9663d2cd..f84871e227d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -113,10 +113,13 @@ module InstructionSanity { } query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func | + exists(Language::Function func, Instruction use | not exists(operand.getType()) and - func = operand.getUse().getEnclosingFunction() and - message = "Operand missing type in function '" + Language::getIdentityString(func) + "'." + use = operand.getUse() and + func = use.getEnclosingFunction() and + message = "Operand '" + operand.toString() + "' of instruction '" + + use.getOpcode().toString() + "' missing type in function '" + + Language::getIdentityString(func) + "'." ) } @@ -344,23 +347,6 @@ class Instruction extends Construction::TInstruction { ) } - bindingset[type] - private string getValueCategoryString(string type) { - if isGLValue() then result = "glval<" + type + ">" else result = type - } - - string getResultTypeString() { - exists(string valcat | - valcat = getValueCategoryString(getResultType().toString()) and - if - getResultType() instanceof Language::UnknownType and - not isGLValue() and - exists(getResultSize()) - then result = valcat + "[" + getResultSize().toString() + "]" - else result = valcat - ) - } - /** * Gets a human-readable string that uniquely identifies this instruction * within the function. This string is used to refer to this instruction when @@ -380,7 +366,9 @@ class Instruction extends Construction::TInstruction { * * Example: `r1_1(int*)` */ - final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" } + final string getResultString() { + result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")" + } /** * Gets a string describing the operands of this instruction, suitable for @@ -448,6 +436,10 @@ class Instruction extends Construction::TInstruction { result = Construction::getInstructionUnconvertedResultExpression(this) } + final Language::LanguageType getResultLanguageType() { + result = Construction::getInstructionResultType(this) + } + /** * Gets the type of the result produced by this instruction. If the * instruction does not produce a result, its result type will be `VoidType`. @@ -455,7 +447,16 @@ class Instruction extends Construction::TInstruction { * If `isGLValue()` holds, then the result type of this instruction should be * thought of as "pointer to `getResultType()`". */ - final Language::Type getResultType() { Construction::instructionHasType(this, result, _) } + final Language::Type getResultType() { + exists(Language::LanguageType resultType, Language::Type langType | + resultType = getResultLanguageType() and + ( + resultType.hasType(langType, _) or + not resultType.hasType(_, _) and result instanceof Language::UnknownType + ) and + result = langType.getUnspecifiedType() + ) + } /** * Holds if the result produced by this instruction is a glvalue. If this @@ -475,7 +476,9 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::instructionHasType(this, _, true) } + final predicate isGLValue() { + Construction::getInstructionResultType(this).hasType(_, true) + } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -485,14 +488,7 @@ class Instruction extends Construction::TInstruction { * `getResultSize()` will always be the size of a pointer. */ final int getResultSize() { - if isGLValue() - then - // a glvalue is always pointer-sized. - result = Language::getPointerSize() - else - if getResultType() instanceof Language::UnknownType - then result = Construction::getInstructionResultSize(this) - else result = Language::getTypeSize(getResultType()) + result = Construction::getInstructionResultType(this).getByteSize() } /** @@ -1300,7 +1296,7 @@ class CatchInstruction extends Instruction { * An instruction that catches an exception of a specific type. */ class CatchByTypeInstruction extends CatchInstruction { - Language::Type exceptionType; + Language::LanguageType exceptionType; CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and @@ -1312,7 +1308,7 @@ class CatchByTypeInstruction extends CatchInstruction { /** * Gets the type of exception to be caught. */ - final Language::Type getExceptionType() { result = exceptionType } + final Language::LanguageType getExceptionType() { result = exceptionType } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index 1ced8ef3282..e3485825064 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -1,9 +1,10 @@ private import internal.IRInternal -import Instruction -import IRBlock +private import Instruction +private import IRBlock private import internal.OperandImports as Imports -import Imports::MemoryAccessKind -import Imports::Overlap +private import Imports::MemoryAccessKind +private import Imports::IRType +private import Imports::Overlap private import Imports::OperandTag cached @@ -143,22 +144,40 @@ class Operand extends TOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - Language::Type getType() { result = getAnyDef().getResultType() } + Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() } + + /** + * Gets the language-neutral type of the value consumed by this operand. This is usually the same + * as the result type of the definition instruction consumed by this operand. For register + * operands, this is always the case. For some memory operands, the operand type may be different + * from the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + final IRType getIRType() { result = getLanguageType().getIRType() } + + /** + * Gets the type of the value consumed by this operand. This is usually the same as the + * result type of the definition instruction consumed by this operand. For register operands, + * this is always the case. For some memory operands, the operand type may be different from + * the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + final Language::Type getType() { getLanguageType().hasType(result, _) } /** * Holds if the value consumed by this operand is a glvalue. If this * holds, the value of the operand represents the address of a location, * and the type of the location is given by `getType()`. If this does * not hold, the value of the operand represents a value whose type is - * given by `getResultType()`. + * given by `getType()`. */ - predicate isGLValue() { getAnyDef().isGLValue() } + final predicate isGLValue() { getLanguageType().hasType(_, true) } /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. */ - int getSize() { result = Language::getTypeSize(getType()) } + final int getSize() { result = getLanguageType().getByteSize() } } /** @@ -170,11 +189,6 @@ class MemoryOperand extends Operand { this = TPhiOperand(_, _, _, _) } - override predicate isGLValue() { - // A `MemoryOperand` can never be a glvalue - none() - } - /** * Gets the kind of memory access performed by the operand. */ @@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; - final override Language::Type getType() { + final override Language::LanguageType getLanguageType() { result = Construction::getInstructionOperandType(useInstr, tag) } } @@ -371,12 +385,6 @@ class PositionalArgumentOperand extends ArgumentOperand { class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - final override int getSize() { - if getType() instanceof Language::UnknownType - then result = Construction::getInstructionOperandSize(useInstr, tag) - else result = Language::getTypeSize(getType()) - } - override MemoryAccessKind getMemoryAccess() { useInstr instanceof CallSideEffectInstruction and result instanceof EscapedMayMemoryAccess From 49276e09c5c5bb334bd81068e756194af4507b2a Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Tue, 24 Sep 2019 11:23:27 +0100 Subject: [PATCH 0215/1227] C++: Add aggregate literals to sideEffects test --- .../library-tests/sideEffects/exprs/exprs.c | 19 +++++++++++++++++- .../sideEffects/exprs/exprs.expected | 20 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/sideEffects/exprs/exprs.c b/cpp/ql/test/library-tests/sideEffects/exprs/exprs.c index e560a88929f..6e2c4ef615b 100644 --- a/cpp/ql/test/library-tests/sideEffects/exprs/exprs.c +++ b/cpp/ql/test/library-tests/sideEffects/exprs/exprs.c @@ -1,5 +1,5 @@ -void f1(int p) { +int f1(int p) { int i; for ( @@ -11,3 +11,20 @@ void f1(int p) { return p; } + +int global_int; + +int f2(void) { + global_int = 3; + return 1; +} + +int f3(void) { + return 2; +} + +void f4(void) { + int is0[3] = { 3, 4, 5 }; + int is1[3] = { 3, f2(), 5 }; + int is2[3] = { 3, f3(), 5 }; +} diff --git a/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected b/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected index 0d48d60e227..f21f75d8880 100644 --- a/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected +++ b/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected @@ -10,6 +10,26 @@ | exprs.c:9:3:9:5 | ++ ... | | mayBeImpure | | | exprs.c:9:5:9:5 | p | isPure | | | | exprs.c:12:12:12:12 | p | isPure | | | +| exprs.c:18:5:18:14 | global_int | isPure | | | +| exprs.c:18:5:18:18 | ... = ... | | mayBeImpure | mayBeGloballyImpure | +| exprs.c:18:18:18:18 | 3 | isPure | | | +| exprs.c:19:12:19:12 | 1 | isPure | | | +| exprs.c:23:12:23:12 | 2 | isPure | | | +| exprs.c:27:13:27:13 | 3 | isPure | | | +| exprs.c:27:17:27:28 | {...} | isPure | | | +| exprs.c:27:20:27:20 | 3 | isPure | | | +| exprs.c:27:23:27:23 | 4 | isPure | | | +| exprs.c:27:26:27:26 | 5 | isPure | | | +| exprs.c:28:13:28:13 | 3 | isPure | | | +| exprs.c:28:17:28:31 | {...} | | mayBeImpure | mayBeGloballyImpure | +| exprs.c:28:20:28:20 | 3 | isPure | | | +| exprs.c:28:23:28:24 | call to f2 | | mayBeImpure | mayBeGloballyImpure | +| exprs.c:28:29:28:29 | 5 | isPure | | | +| exprs.c:29:13:29:13 | 3 | isPure | | | +| exprs.c:29:17:29:31 | {...} | isPure | | | +| exprs.c:29:20:29:20 | 3 | isPure | | | +| exprs.c:29:23:29:24 | call to f3 | isPure | | | +| exprs.c:29:29:29:29 | 5 | isPure | | | | exprs.cpp:7:10:7:16 | (...) | isPure | | | | exprs.cpp:7:10:7:16 | (reference to) | isPure | | | | exprs.cpp:7:11:7:15 | * ... | isPure | | | From b75bf06649df642ed47b5686ed874c82834ea632 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 24 Sep 2019 13:00:21 +0200 Subject: [PATCH 0216/1227] C++: Accept test changes in other IR tests --- .../signanalysis/SignAnalysis.expected | 30 ++ .../syntax-zoo/aliased_ssa_sanity.expected | 2 +- .../syntax-zoo/raw_sanity.expected | 21 +- .../syntax-zoo/unaliased_ssa_sanity.expected | 2 +- .../GlobalValueNumbering/ir_gvn.expected | 262 ++++++++++-------- 5 files changed, 192 insertions(+), 125 deletions(-) diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected b/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected index cdc15c4b45a..4dc280b6ca9 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected @@ -13,6 +13,7 @@ | bounded_bounds.c:16:12:16:12 | Load: x | negative strictlyNegative | | bounded_bounds.c:16:12:16:12 | Store: x | negative strictlyNegative | | inline_assembly.c:9:23:9:23 | Uninitialized: definition of y | positive | +| inline_assembly.c:10:3:10:7 | CopyValue: ... = ... | positive strictlyPositive | | inline_assembly.c:10:3:10:7 | Store: ... = ... | positive strictlyPositive | | inline_assembly.c:10:7:10:7 | Constant: (unsigned int)... | positive strictlyPositive | | inline_assembly.c:12:32:12:32 | Load: y | positive strictlyPositive | @@ -27,8 +28,10 @@ | minmax.c:18:37:18:37 | Load: x | positive strictlyPositive | | minmax.c:18:40:18:40 | Load: y | positive strictlyPositive | | minmax.c:18:43:18:43 | Load: z | positive strictlyPositive | +| minmax.c:20:2:24:3 | CopyValue: ... = ... | positive | | minmax.c:20:2:24:3 | Store: ... = ... | positive | | minmax.c:20:6:24:3 | CopyValue: (statement expression) | positive | +| minmax.c:22:18:22:22 | CopyValue: ... = ... | positive strictlyPositive | | minmax.c:22:18:22:22 | Store: ... = ... | positive strictlyPositive | | minmax.c:22:22:22:22 | Load: x | positive strictlyPositive | | minmax.c:23:3:23:3 | Load: t | positive | @@ -37,6 +40,7 @@ | minmax.c:26:40:26:40 | Load: y | positive strictlyPositive | | minmax.c:26:43:26:43 | Load: z | positive | | test.c:7:10:7:10 | Phi: p | positive | +| test.c:8:5:8:19 | CopyValue: ... = ... | positive strictlyPositive | | test.c:8:5:8:19 | Store: ... = ... | positive strictlyPositive | | test.c:8:13:8:17 | Load: count | positive | | test.c:8:13:8:19 | Add: ... + ... | positive strictlyPositive | @@ -44,6 +48,7 @@ | test.c:10:10:10:14 | Load: count | positive | | test.c:10:10:10:14 | Store: count | positive | | test.c:15:10:15:10 | Phi: p | positive | +| test.c:16:5:16:26 | CopyValue: ... = ... | positive | | test.c:16:5:16:26 | Store: ... = ... | positive | | test.c:16:13:16:26 | Rem: ... % ... | positive | | test.c:16:14:16:18 | Load: count | positive | @@ -57,6 +62,7 @@ | test.c:24:5:24:11 | Constant: ... ++ | positive strictlyPositive | | test.c:24:5:24:11 | Load: ... ++ | positive | | test.c:24:5:24:11 | Store: ... ++ | positive strictlyPositive | +| test.c:25:5:25:22 | CopyValue: ... = ... | positive | | test.c:25:5:25:22 | Store: ... = ... | positive | | test.c:25:13:25:17 | Load: count | positive strictlyPositive | | test.c:25:13:25:22 | Rem: ... % ... | positive | @@ -67,6 +73,7 @@ | test.c:33:15:33:15 | Phi: i | positive | | test.c:33:15:33:15 | Phi: i | positive | | test.c:33:19:33:19 | Constant: 2 | positive strictlyPositive | +| test.c:33:22:33:28 | CopyValue: ... = ... | positive strictlyPositive | | test.c:33:22:33:28 | Store: ... = ... | positive strictlyPositive | | test.c:33:26:33:26 | Load: i | positive | | test.c:33:26:33:28 | Add: ... + ... | positive strictlyPositive | @@ -101,6 +108,7 @@ | test.c:51:15:51:17 | Add: ... + ... | positive strictlyPositive | | test.c:51:17:51:17 | Constant: 2 | positive strictlyPositive | | test.c:51:21:51:21 | Constant: 4 | positive strictlyPositive | +| test.c:51:24:51:30 | CopyValue: ... = ... | positive strictlyPositive | | test.c:51:24:51:30 | Store: ... = ... | positive strictlyPositive | | test.c:51:28:51:28 | Load: i | positive | | test.c:51:28:51:30 | Add: ... + ... | positive strictlyPositive | @@ -459,6 +467,7 @@ | test.c:343:5:343:7 | Constant: ... ++ | positive strictlyPositive | | test.c:343:5:343:7 | Load: ... ++ | positive | | test.c:343:5:343:7 | Store: ... ++ | positive strictlyPositive | +| test.c:345:3:345:7 | CopyValue: ... = ... | positive strictlyPositive | | test.c:345:3:345:7 | Store: ... = ... | positive strictlyPositive | | test.c:345:7:345:7 | Load: i | positive strictlyPositive | | test.c:346:7:346:7 | Load: x | positive | @@ -474,6 +483,7 @@ | test.c:356:36:356:37 | Uninitialized: definition of y6 | positive | | test.c:356:40:356:41 | Uninitialized: definition of y7 | positive | | test.c:356:44:356:45 | Uninitialized: definition of y8 | positive | +| test.c:357:3:357:23 | CopyValue: ... = ... | positive | | test.c:357:3:357:23 | Store: ... = ... | positive | | test.c:357:8:357:8 | Load: x | positive | | test.c:357:8:357:23 | Load: ... ? ... : ... | positive | @@ -483,6 +493,7 @@ | test.c:357:12:357:14 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:357:18:357:18 | Load: x | positive | | test.c:357:22:357:23 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:358:3:358:24 | CopyValue: ... = ... | positive | | test.c:358:3:358:24 | Store: ... = ... | positive | | test.c:358:8:358:8 | Load: x | positive | | test.c:358:8:358:24 | Load: ... ? ... : ... | positive | @@ -494,6 +505,7 @@ | test.c:358:24:358:24 | Load: x | positive | | test.c:365:7:365:7 | Load: x | positive | | test.c:365:11:365:13 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:366:5:366:15 | CopyValue: ... = ... | positive | | test.c:366:5:366:15 | Store: ... = ... | positive | | test.c:366:10:366:10 | Load: x | positive | | test.c:366:10:366:15 | Load: ... ? ... : ... | positive | @@ -501,6 +513,7 @@ | test.c:366:10:366:15 | Store: ... ? ... : ... | positive | | test.c:366:10:366:15 | Store: ... ? ... : ... | positive strictlyPositive | | test.c:366:15:366:15 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:367:5:367:17 | CopyValue: ... = ... | positive | | test.c:367:5:367:17 | Store: ... = ... | positive | | test.c:367:10:367:10 | Load: x | positive | | test.c:367:10:367:17 | Load: ... ? ... : ... | positive | @@ -508,6 +521,7 @@ | test.c:367:10:367:17 | Store: ... ? ... : ... | positive | | test.c:367:10:367:17 | Store: ... ? ... : ... | positive strictlyPositive | | test.c:367:15:367:17 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:368:5:368:21 | CopyValue: ... = ... | positive strictlyPositive | | test.c:368:5:368:21 | Store: ... = ... | positive strictlyPositive | | test.c:368:10:368:21 | Load: ... ? ... : ... | positive strictlyPositive | | test.c:368:10:368:21 | Store: ... ? ... : ... | positive strictlyPositive | @@ -515,6 +529,7 @@ | test.c:368:11:368:13 | Add: ... + ... | positive strictlyPositive | | test.c:368:13:368:13 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:368:19:368:21 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:369:5:369:36 | CopyValue: ... = ... | positive strictlyPositive | | test.c:369:5:369:36 | Store: ... = ... | positive strictlyPositive | | test.c:369:10:369:36 | Convert: (unsigned int)... | positive strictlyPositive | | test.c:369:10:369:36 | Load: ... ? ... : ... | positive strictlyPositive | @@ -524,6 +539,7 @@ | test.c:369:27:369:29 | Add: ... + ... | positive strictlyPositive | | test.c:369:29:369:29 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:369:36:369:36 | Constant: 5 | positive strictlyPositive | +| test.c:370:5:370:38 | CopyValue: ... = ... | positive strictlyPositive | | test.c:370:5:370:38 | Store: ... = ... | positive strictlyPositive | | test.c:370:10:370:38 | Convert: (unsigned int)... | positive strictlyPositive | | test.c:370:10:370:38 | Load: ... ? ... : ... | positive strictlyPositive | @@ -533,6 +549,7 @@ | test.c:370:27:370:29 | Add: ... + ... | positive strictlyPositive | | test.c:370:29:370:29 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:370:36:370:38 | Constant: 500 | positive strictlyPositive | +| test.c:371:5:371:39 | CopyValue: ... = ... | positive strictlyPositive | | test.c:371:5:371:39 | Store: ... = ... | positive strictlyPositive | | test.c:371:10:371:39 | Convert: (unsigned int)... | positive strictlyPositive | | test.c:371:10:371:39 | Load: ... ? ... : ... | positive strictlyPositive | @@ -570,6 +587,7 @@ | test.c:378:24:378:25 | Uninitialized: definition of y3 | positive | | test.c:378:28:378:29 | Uninitialized: definition of y4 | positive | | test.c:378:32:378:33 | Uninitialized: definition of y5 | positive | +| test.c:379:3:379:24 | CopyValue: ... = ... | positive strictlyPositive | | test.c:379:3:379:24 | Store: ... = ... | positive strictlyPositive | | test.c:379:8:379:8 | Load: x | positive | | test.c:379:8:379:24 | Load: ... ? ... : ... | positive strictlyPositive | @@ -579,6 +597,7 @@ | test.c:379:12:379:14 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:379:18:379:18 | Load: x | positive strictlyPositive | | test.c:379:22:379:24 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:380:3:380:25 | CopyValue: ... = ... | positive strictlyPositive | | test.c:380:3:380:25 | Store: ... = ... | positive strictlyPositive | | test.c:380:8:380:8 | Load: x | positive | | test.c:380:8:380:25 | Load: ... ? ... : ... | positive strictlyPositive | @@ -588,14 +607,18 @@ | test.c:380:13:380:15 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:380:19:380:21 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:380:25:380:25 | Load: x | positive strictlyPositive | +| test.c:381:3:381:11 | CopyValue: ... = ... | positive strictlyPositive | | test.c:381:3:381:11 | Store: ... = ... | positive strictlyPositive | | test.c:381:8:381:11 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:382:3:382:11 | CopyValue: ... = ... | positive strictlyPositive | | test.c:382:3:382:11 | Store: ... = ... | positive strictlyPositive | | test.c:382:8:382:11 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:383:3:383:11 | CopyValue: ... = ... | positive strictlyPositive | | test.c:383:3:383:11 | Store: ... = ... | positive strictlyPositive | | test.c:383:8:383:11 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:384:7:384:7 | Load: x | positive | | test.c:384:12:384:14 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:385:5:385:21 | CopyValue: ... = ... | positive strictlyPositive | | test.c:385:5:385:21 | Store: ... = ... | positive strictlyPositive | | test.c:385:10:385:21 | Load: ... ? ... : ... | positive strictlyPositive | | test.c:385:10:385:21 | Store: ... ? ... : ... | positive strictlyPositive | @@ -603,6 +626,7 @@ | test.c:385:11:385:15 | Sub: ... - ... | positive | | test.c:385:13:385:15 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:385:21:385:21 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:386:5:386:21 | CopyValue: ... = ... | positive strictlyPositive | | test.c:386:5:386:21 | Store: ... = ... | positive strictlyPositive | | test.c:386:10:386:21 | Load: ... ? ... : ... | positive strictlyPositive | | test.c:386:10:386:21 | Store: ... ? ... : ... | positive strictlyPositive | @@ -610,6 +634,7 @@ | test.c:386:11:386:15 | Sub: ... - ... | positive | | test.c:386:13:386:15 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:386:21:386:21 | Constant: (unsigned int)... | positive strictlyPositive | +| test.c:387:5:387:38 | CopyValue: ... = ... | positive strictlyPositive | | test.c:387:5:387:38 | Store: ... = ... | positive strictlyPositive | | test.c:387:10:387:38 | Convert: (unsigned int)... | positive strictlyPositive | | test.c:387:10:387:38 | Load: ... ? ... : ... | positive strictlyPositive | @@ -644,17 +669,22 @@ | test.c:394:34:394:36 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:395:16:395:17 | Uninitialized: definition of y1 | positive | | test.c:396:16:396:17 | Uninitialized: definition of y2 | positive | +| test.c:397:3:397:15 | CopyValue: ... = ... | positive strictlyPositive | | test.c:397:3:397:15 | Store: ... = ... | positive strictlyPositive | | test.c:397:9:397:11 | Add: ++ ... | positive strictlyPositive | | test.c:397:9:397:11 | Constant: ++ ... | positive strictlyPositive | | test.c:397:9:397:11 | Load: ++ ... | positive | | test.c:397:9:397:11 | Store: ++ ... | positive strictlyPositive | +| test.c:397:9:397:14 | CopyValue: ... , ... | positive strictlyPositive | | test.c:397:14:397:14 | Load: y | positive strictlyPositive | +| test.c:398:3:398:23 | CopyValue: ... = ... | positive strictlyPositive | | test.c:398:3:398:23 | Store: ... = ... | positive strictlyPositive | | test.c:398:9:398:11 | Add: ... ++ | positive strictlyPositive | | test.c:398:9:398:11 | Constant: ... ++ | positive strictlyPositive | | test.c:398:9:398:11 | Load: ... ++ | positive strictlyPositive | | test.c:398:9:398:11 | Store: ... ++ | positive strictlyPositive | +| test.c:398:9:398:19 | CopyValue: ... , ... | positive strictlyPositive | +| test.c:398:9:398:22 | CopyValue: ... , ... | positive strictlyPositive | | test.c:398:14:398:19 | Add: ... += ... | positive strictlyPositive | | test.c:398:14:398:19 | Load: ... += ... | positive strictlyPositive | | test.c:398:14:398:19 | Store: ... += ... | positive strictlyPositive | diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index 5e76fb042be..a8f98105b08 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -21,7 +21,7 @@ instructionWithoutSuccessor | ms_try_mix.cpp:28:12:28:15 | Chi: call to C | | ms_try_mix.cpp:48:10:48:13 | Chi: call to C | | pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} | -| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | +| stmt_expr.cpp:27:5:27:15 | CopyValue: ... = ... | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | | vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | ambiguousSuccessors diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index b9c4bd7eba5..e8b34aff726 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -1,9 +1,10 @@ missingOperand -| condition_decls.cpp:16:6:16:20 | ConditionalBranch: (condition decl) | Instruction 'ConditionalBranch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | -| condition_decls.cpp:26:3:36:3 | Switch: switch (...) ... | Instruction 'Switch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | -| condition_decls.cpp:41:9:41:23 | ConditionalBranch: (condition decl) | Instruction 'ConditionalBranch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | -| condition_decls.cpp:48:39:48:53 | ConditionalBranch: (condition decl) | Instruction 'ConditionalBranch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | +| condition_decls.cpp:16:6:16:20 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | +| condition_decls.cpp:26:10:26:24 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | +| condition_decls.cpp:41:9:41:23 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | +| condition_decls.cpp:48:39:48:53 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | +| misc.c:220:3:223:3 | CopyValue: ... = ... | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | @@ -47,13 +48,13 @@ instructionWithoutSuccessor | misc.c:222:10:222:10 | Store: 2 | | ms_assume.cpp:20:12:20:12 | Constant: (bool)... | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| ms_try_except.cpp:7:13:7:17 | Store: ... = ... | +| ms_try_except.cpp:7:13:7:17 | CopyValue: ... = ... | | ms_try_except.cpp:9:19:9:19 | Load: j | -| ms_try_except.cpp:10:13:10:17 | Store: ... = ... | -| ms_try_except.cpp:14:13:14:17 | Store: ... = ... | -| ms_try_except.cpp:17:13:17:17 | Store: ... = ... | +| ms_try_except.cpp:10:13:10:17 | CopyValue: ... = ... | +| ms_try_except.cpp:14:13:14:17 | CopyValue: ... = ... | +| ms_try_except.cpp:17:13:17:17 | CopyValue: ... = ... | | ms_try_except.cpp:19:17:19:21 | Sub: ... - ... | -| ms_try_except.cpp:20:9:20:13 | Store: ... = ... | +| ms_try_except.cpp:20:9:20:13 | CopyValue: ... = ... | | ms_try_mix.cpp:11:12:11:15 | CallSideEffect: call to C | | ms_try_mix.cpp:16:13:16:19 | ThrowValue: throw ... | | ms_try_mix.cpp:18:16:18:19 | CallSideEffect: call to C | @@ -75,7 +76,7 @@ instructionWithoutSuccessor | static_init_templates.cpp:97:27:97:36 | Convert: (void *)... | | static_init_templates.cpp:105:27:105:27 | Constant: (void *)... | | static_init_templates.cpp:105:27:105:27 | Constant: (void *)... | -| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | +| stmt_expr.cpp:27:5:27:15 | CopyValue: ... = ... | | stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) | | stmt_in_type.cpp:5:53:5:53 | Constant: 1 | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index ab5362cb06c..c8cee7b2a7c 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -30,7 +30,7 @@ instructionWithoutSuccessor | ms_try_mix.cpp:28:12:28:15 | CallSideEffect: call to C | | ms_try_mix.cpp:48:10:48:13 | CallSideEffect: call to C | | pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} | -| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | +| stmt_expr.cpp:27:5:27:15 | CopyValue: ... = ... | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | | vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | ambiguousSuccessors diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected index 8be4cf4e2c1..4bc9f90cc60 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected @@ -40,34 +40,40 @@ test.cpp: # 5| valnum = r0_7 # 5| m0_19(int) = Store : &:r0_18, r0_17 # 5| valnum = r0_17 -# 6| r0_20(glval) = VariableAddress[p0] : +# 5| r0_20(glval) = CopyValue : r0_18 +# 5| valnum = r0_7 +# 6| r0_21(glval) = VariableAddress[p0] : # 6| valnum = r0_3 -# 6| r0_21(int) = Load : &:r0_20, m0_4 +# 6| r0_22(int) = Load : &:r0_21, m0_4 # 6| valnum = m0_4 -# 6| r0_22(glval) = VariableAddress[p1] : +# 6| r0_23(glval) = VariableAddress[p1] : # 6| valnum = r0_5 -# 6| r0_23(int) = Load : &:r0_22, m0_6 +# 6| r0_24(int) = Load : &:r0_23, m0_6 # 6| valnum = m0_6 -# 6| r0_24(int) = Add : r0_21, r0_23 +# 6| r0_25(int) = Add : r0_22, r0_24 # 6| valnum = r0_17 -# 6| r0_25(glval) = VariableAddress[x] : +# 6| r0_26(glval) = VariableAddress[x] : # 6| valnum = r0_7 -# 6| m0_26(int) = Store : &:r0_25, r0_24 +# 6| m0_27(int) = Store : &:r0_26, r0_25 # 6| valnum = r0_17 -# 7| r0_27(glval) = VariableAddress[x] : +# 6| r0_28(glval) = CopyValue : r0_26 +# 6| valnum = r0_7 +# 7| r0_29(glval) = VariableAddress[x] : # 7| valnum = r0_7 -# 7| r0_28(int) = Load : &:r0_27, m0_26 +# 7| r0_30(int) = Load : &:r0_29, m0_27 # 7| valnum = r0_17 -# 7| r0_29(glval) = VariableAddress[y] : +# 7| r0_31(glval) = VariableAddress[y] : # 7| valnum = r0_9 -# 7| m0_30(int) = Store : &:r0_29, r0_28 +# 7| m0_32(int) = Store : &:r0_31, r0_30 # 7| valnum = r0_17 -# 8| v0_31(void) = NoOp : -# 1| r0_32(glval) = VariableAddress[#return] : +# 7| r0_33(glval) = CopyValue : r0_31 +# 7| valnum = r0_9 +# 8| v0_34(void) = NoOp : +# 1| r0_35(glval) = VariableAddress[#return] : # 1| valnum = unique -# 1| v0_33(void) = ReturnValue : &:r0_32 -# 1| v0_34(void) = UnmodeledUse : mu* -# 1| v0_35(void) = ExitFunction : +# 1| v0_36(void) = ReturnValue : &:r0_35 +# 1| v0_37(void) = UnmodeledUse : mu* +# 1| v0_38(void) = ExitFunction : # 12| int test01(int, int) # 12| Block 0 @@ -116,40 +122,46 @@ test.cpp: # 16| valnum = r0_7 # 16| m0_22(int) = Store : &:r0_21, r0_20 # 16| valnum = r0_20 -# 17| r0_23(glval) = VariableAddress[p0] : +# 16| r0_23(glval) = CopyValue : r0_21 +# 16| valnum = r0_7 +# 17| r0_24(glval) = VariableAddress[p0] : # 17| valnum = r0_3 -# 17| r0_24(int) = Load : &:r0_23, m0_4 +# 17| r0_25(int) = Load : &:r0_24, m0_4 # 17| valnum = m0_4 -# 17| r0_25(glval) = VariableAddress[p1] : +# 17| r0_26(glval) = VariableAddress[p1] : # 17| valnum = r0_5 -# 17| r0_26(int) = Load : &:r0_25, m0_6 +# 17| r0_27(int) = Load : &:r0_26, m0_6 # 17| valnum = m0_6 -# 17| r0_27(int) = Add : r0_24, r0_26 +# 17| r0_28(int) = Add : r0_25, r0_27 # 17| valnum = r0_17 -# 17| r0_28(glval) = VariableAddress[global01] : +# 17| r0_29(glval) = VariableAddress[global01] : # 17| valnum = r0_18 -# 17| r0_29(int) = Load : &:r0_28, ~m0_1 +# 17| r0_30(int) = Load : &:r0_29, ~m0_1 # 17| valnum = unique -# 17| r0_30(int) = Add : r0_27, r0_29 -# 17| valnum = r0_30 -# 17| r0_31(glval) = VariableAddress[x] : +# 17| r0_31(int) = Add : r0_28, r0_30 +# 17| valnum = r0_31 +# 17| r0_32(glval) = VariableAddress[x] : # 17| valnum = r0_7 -# 17| m0_32(int) = Store : &:r0_31, r0_30 -# 17| valnum = r0_30 -# 18| r0_33(glval) = VariableAddress[x] : +# 17| m0_33(int) = Store : &:r0_32, r0_31 +# 17| valnum = r0_31 +# 17| r0_34(glval) = CopyValue : r0_32 +# 17| valnum = r0_7 +# 18| r0_35(glval) = VariableAddress[x] : # 18| valnum = r0_7 -# 18| r0_34(int) = Load : &:r0_33, m0_32 -# 18| valnum = r0_30 -# 18| r0_35(glval) = VariableAddress[y] : +# 18| r0_36(int) = Load : &:r0_35, m0_33 +# 18| valnum = r0_31 +# 18| r0_37(glval) = VariableAddress[y] : # 18| valnum = r0_9 -# 18| m0_36(int) = Store : &:r0_35, r0_34 -# 18| valnum = r0_30 -# 19| v0_37(void) = NoOp : -# 12| r0_38(glval) = VariableAddress[#return] : +# 18| m0_38(int) = Store : &:r0_37, r0_36 +# 18| valnum = r0_31 +# 18| r0_39(glval) = CopyValue : r0_37 +# 18| valnum = r0_9 +# 19| v0_40(void) = NoOp : +# 12| r0_41(glval) = VariableAddress[#return] : # 12| valnum = unique -# 12| v0_39(void) = ReturnValue : &:r0_38 -# 12| v0_40(void) = UnmodeledUse : mu* -# 12| v0_41(void) = ExitFunction : +# 12| v0_42(void) = ReturnValue : &:r0_41 +# 12| v0_43(void) = UnmodeledUse : mu* +# 12| v0_44(void) = ExitFunction : # 25| int test02(int, int) # 25| Block 0 @@ -198,47 +210,53 @@ test.cpp: # 29| valnum = r0_7 # 29| m0_22(int) = Store : &:r0_21, r0_20 # 29| valnum = r0_20 -# 30| r0_23(glval) = FunctionAddress[change_global02] : +# 29| r0_23(glval) = CopyValue : r0_21 +# 29| valnum = r0_7 +# 30| r0_24(glval) = FunctionAddress[change_global02] : # 30| valnum = unique -# 30| v0_24(void) = Call : func:r0_23 -# 30| m0_25(unknown) = ^CallSideEffect : ~m0_1 +# 30| v0_25(void) = Call : func:r0_24 +# 30| m0_26(unknown) = ^CallSideEffect : ~m0_1 # 30| valnum = unique -# 30| m0_26(unknown) = Chi : total:m0_1, partial:m0_25 +# 30| m0_27(unknown) = Chi : total:m0_1, partial:m0_26 # 30| valnum = unique -# 31| r0_27(glval) = VariableAddress[p0] : +# 31| r0_28(glval) = VariableAddress[p0] : # 31| valnum = r0_3 -# 31| r0_28(int) = Load : &:r0_27, m0_4 +# 31| r0_29(int) = Load : &:r0_28, m0_4 # 31| valnum = m0_4 -# 31| r0_29(glval) = VariableAddress[p1] : +# 31| r0_30(glval) = VariableAddress[p1] : # 31| valnum = r0_5 -# 31| r0_30(int) = Load : &:r0_29, m0_6 +# 31| r0_31(int) = Load : &:r0_30, m0_6 # 31| valnum = m0_6 -# 31| r0_31(int) = Add : r0_28, r0_30 +# 31| r0_32(int) = Add : r0_29, r0_31 # 31| valnum = r0_17 -# 31| r0_32(glval) = VariableAddress[global02] : +# 31| r0_33(glval) = VariableAddress[global02] : # 31| valnum = r0_18 -# 31| r0_33(int) = Load : &:r0_32, ~m0_26 +# 31| r0_34(int) = Load : &:r0_33, ~m0_27 # 31| valnum = unique -# 31| r0_34(int) = Add : r0_31, r0_33 -# 31| valnum = r0_34 -# 31| r0_35(glval) = VariableAddress[x] : +# 31| r0_35(int) = Add : r0_32, r0_34 +# 31| valnum = r0_35 +# 31| r0_36(glval) = VariableAddress[x] : # 31| valnum = r0_7 -# 31| m0_36(int) = Store : &:r0_35, r0_34 -# 31| valnum = r0_34 -# 32| r0_37(glval) = VariableAddress[x] : +# 31| m0_37(int) = Store : &:r0_36, r0_35 +# 31| valnum = r0_35 +# 31| r0_38(glval) = CopyValue : r0_36 +# 31| valnum = r0_7 +# 32| r0_39(glval) = VariableAddress[x] : # 32| valnum = r0_7 -# 32| r0_38(int) = Load : &:r0_37, m0_36 -# 32| valnum = r0_34 -# 32| r0_39(glval) = VariableAddress[y] : +# 32| r0_40(int) = Load : &:r0_39, m0_37 +# 32| valnum = r0_35 +# 32| r0_41(glval) = VariableAddress[y] : # 32| valnum = r0_9 -# 32| m0_40(int) = Store : &:r0_39, r0_38 -# 32| valnum = r0_34 -# 33| v0_41(void) = NoOp : -# 25| r0_42(glval) = VariableAddress[#return] : +# 32| m0_42(int) = Store : &:r0_41, r0_40 +# 32| valnum = r0_35 +# 32| r0_43(glval) = CopyValue : r0_41 +# 32| valnum = r0_9 +# 33| v0_44(void) = NoOp : +# 25| r0_45(glval) = VariableAddress[#return] : # 25| valnum = unique -# 25| v0_43(void) = ReturnValue : &:r0_42 -# 25| v0_44(void) = UnmodeledUse : mu* -# 25| v0_45(void) = ExitFunction : +# 25| v0_46(void) = ReturnValue : &:r0_45 +# 25| v0_47(void) = UnmodeledUse : mu* +# 25| v0_48(void) = ExitFunction : # 39| int test03(int, int, int*) # 39| Block 0 @@ -291,50 +309,60 @@ test.cpp: # 43| valnum = r0_9 # 43| m0_24(int) = Store : &:r0_23, r0_22 # 43| valnum = r0_22 -# 44| r0_25(int) = Constant[0] : -# 44| valnum = r0_25 -# 44| r0_26(glval) = VariableAddress[p2] : +# 43| r0_25(glval) = CopyValue : r0_23 +# 43| valnum = r0_9 +# 44| r0_26(int) = Constant[0] : +# 44| valnum = r0_26 +# 44| r0_27(glval) = VariableAddress[p2] : # 44| valnum = r0_7 -# 44| r0_27(int *) = Load : &:r0_26, m0_8 +# 44| r0_28(int *) = Load : &:r0_27, m0_8 # 44| valnum = m0_8 -# 44| m0_28(int) = Store : &:r0_27, r0_25 -# 44| valnum = r0_25 -# 44| m0_29(unknown) = Chi : total:m0_1, partial:m0_28 +# 44| r0_29(glval) = CopyValue : r0_28 +# 44| valnum = m0_8 +# 44| m0_30(int) = Store : &:r0_29, r0_26 +# 44| valnum = r0_26 +# 44| m0_31(unknown) = Chi : total:m0_1, partial:m0_30 # 44| valnum = unique -# 45| r0_30(glval) = VariableAddress[p0] : +# 44| r0_32(glval) = CopyValue : r0_29 +# 44| valnum = m0_8 +# 45| r0_33(glval) = VariableAddress[p0] : # 45| valnum = r0_3 -# 45| r0_31(int) = Load : &:r0_30, m0_4 +# 45| r0_34(int) = Load : &:r0_33, m0_4 # 45| valnum = m0_4 -# 45| r0_32(glval) = VariableAddress[p1] : +# 45| r0_35(glval) = VariableAddress[p1] : # 45| valnum = r0_5 -# 45| r0_33(int) = Load : &:r0_32, m0_6 +# 45| r0_36(int) = Load : &:r0_35, m0_6 # 45| valnum = m0_6 -# 45| r0_34(int) = Add : r0_31, r0_33 -# 45| valnum = r0_19 -# 45| r0_35(glval) = VariableAddress[global03] : -# 45| valnum = r0_20 -# 45| r0_36(int) = Load : &:r0_35, ~m0_29 -# 45| valnum = unique # 45| r0_37(int) = Add : r0_34, r0_36 -# 45| valnum = r0_37 -# 45| r0_38(glval) = VariableAddress[x] : +# 45| valnum = r0_19 +# 45| r0_38(glval) = VariableAddress[global03] : +# 45| valnum = r0_20 +# 45| r0_39(int) = Load : &:r0_38, ~m0_31 +# 45| valnum = unique +# 45| r0_40(int) = Add : r0_37, r0_39 +# 45| valnum = r0_40 +# 45| r0_41(glval) = VariableAddress[x] : # 45| valnum = r0_9 -# 45| m0_39(int) = Store : &:r0_38, r0_37 -# 45| valnum = r0_37 -# 46| r0_40(glval) = VariableAddress[x] : +# 45| m0_42(int) = Store : &:r0_41, r0_40 +# 45| valnum = r0_40 +# 45| r0_43(glval) = CopyValue : r0_41 +# 45| valnum = r0_9 +# 46| r0_44(glval) = VariableAddress[x] : # 46| valnum = r0_9 -# 46| r0_41(int) = Load : &:r0_40, m0_39 -# 46| valnum = r0_37 -# 46| r0_42(glval) = VariableAddress[y] : +# 46| r0_45(int) = Load : &:r0_44, m0_42 +# 46| valnum = r0_40 +# 46| r0_46(glval) = VariableAddress[y] : # 46| valnum = r0_11 -# 46| m0_43(int) = Store : &:r0_42, r0_41 -# 46| valnum = r0_37 -# 47| v0_44(void) = NoOp : -# 39| r0_45(glval) = VariableAddress[#return] : +# 46| m0_47(int) = Store : &:r0_46, r0_45 +# 46| valnum = r0_40 +# 46| r0_48(glval) = CopyValue : r0_46 +# 46| valnum = r0_11 +# 47| v0_49(void) = NoOp : +# 39| r0_50(glval) = VariableAddress[#return] : # 39| valnum = unique -# 39| v0_46(void) = ReturnValue : &:r0_45 -# 39| v0_47(void) = UnmodeledUse : mu* -# 39| v0_48(void) = ExitFunction : +# 39| v0_51(void) = ReturnValue : &:r0_50 +# 39| v0_52(void) = UnmodeledUse : mu* +# 39| v0_53(void) = ExitFunction : # 49| unsigned int my_strspn(char const*, char const*) # 49| Block 0 @@ -391,6 +419,8 @@ test.cpp: # 55| valnum = r0_7 # 55| m2_3(char *) = Store : &:r2_2, r2_1 # 55| valnum = m0_6 +# 55| r2_4(glval) = CopyValue : r2_2 +# 55| valnum = r0_7 #-----| Goto -> Block 3 # 56| Block 3 @@ -572,6 +602,8 @@ test.cpp: # 80| valnum = r0_5 # 80| m1_6(signed short) = Store : &:r1_5, r1_4 # 80| valnum = r1_4 +# 80| r1_7(glval) = CopyValue : r1_5 +# 80| valnum = r0_5 #-----| Goto -> Block 2 # 82| Block 2 @@ -648,10 +680,12 @@ test.cpp: # 88| valnum = r0_9 # 88| m3_4(int) = Store : &:r3_3, r3_2 # 88| valnum = m3_0 -# 89| v3_5(void) = NoOp : -# 84| v3_6(void) = ReturnVoid : -# 84| v3_7(void) = UnmodeledUse : mu* -# 84| v3_8(void) = ExitFunction : +# 88| r3_5(glval) = CopyValue : r3_3 +# 88| valnum = r0_9 +# 89| v3_6(void) = NoOp : +# 84| v3_7(void) = ReturnVoid : +# 84| v3_8(void) = UnmodeledUse : mu* +# 84| v3_9(void) = ExitFunction : # 91| int regression_test00() # 91| Block 0 @@ -668,21 +702,23 @@ test.cpp: # 92| valnum = r0_3 # 92| m0_6(int) = Store : &:r0_5, r0_4 # 92| valnum = r0_4 -# 92| m0_7(int) = Store : &:r0_3, r0_4 +# 92| r0_7(int) = CopyValue : r0_4 # 92| valnum = r0_4 -# 93| r0_8(glval) = VariableAddress[#return] : -# 93| valnum = r0_8 -# 93| r0_9(glval) = VariableAddress[x] : +# 92| m0_8(int) = Store : &:r0_3, r0_7 +# 92| valnum = r0_4 +# 93| r0_9(glval) = VariableAddress[#return] : +# 93| valnum = r0_9 +# 93| r0_10(glval) = VariableAddress[x] : # 93| valnum = r0_3 -# 93| r0_10(int) = Load : &:r0_9, m0_7 +# 93| r0_11(int) = Load : &:r0_10, m0_8 # 93| valnum = r0_4 -# 93| m0_11(int) = Store : &:r0_8, r0_10 +# 93| m0_12(int) = Store : &:r0_9, r0_11 # 93| valnum = r0_4 -# 91| r0_12(glval) = VariableAddress[#return] : -# 91| valnum = r0_8 -# 91| v0_13(void) = ReturnValue : &:r0_12, m0_11 -# 91| v0_14(void) = UnmodeledUse : mu* -# 91| v0_15(void) = ExitFunction : +# 91| r0_13(glval) = VariableAddress[#return] : +# 91| valnum = r0_9 +# 91| v0_14(void) = ReturnValue : &:r0_13, m0_12 +# 91| v0_15(void) = UnmodeledUse : mu* +# 91| v0_16(void) = ExitFunction : # 104| int inheritanceConversions(Derived*) # 104| Block 0 From 9228cf83fa8cfa59b97c6541d70f54e71700f4de Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Tue, 24 Sep 2019 12:02:18 +0100 Subject: [PATCH 0217/1227] Address PR comments --- .../semmle/code/csharp/ir/IRConfiguration.qll | 4 +- .../unaliased_ssa/internal/AliasAnalysis.qll | 62 +++++++------------ 2 files changed, 24 insertions(+), 42 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll b/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll index 8d9fdec751d..a76d0457c0b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll @@ -15,7 +15,5 @@ class IRConfiguration extends TIRConfiguration { /** * Holds if IR should be created for callable `callable`. By default, holds for all callables. */ - predicate shouldCreateIRForFunction(Callable callable) { - callable.getLocation().getFile().getExtension() = "cs" - } + predicate shouldCreateIRForFunction(Callable callable) { any() } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index 4bb9f75d182..43d5a378793 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -53,16 +53,16 @@ private predicate operandIsConsumedWithoutEscaping(Operand operand) { instr instanceof PointerDiffInstruction ) ) - // or - // // Some standard function arguments never escape - // isNeverEscapesArgument(operand) + or + // Some standard function arguments never escape + isNeverEscapesArgument(operand) } private predicate operandEscapesDomain(Operand operand) { not operandIsConsumedWithoutEscaping(operand) and not operandIsPropagated(operand, _) and not isArgumentForParameter(_, operand, _) and - // not isOnlyEscapesViaReturnArgument(operand) and + not isOnlyEscapesViaReturnArgument(operand) and not operand.getUse() instanceof ReturnValueInstruction and not operand instanceof PhiInputOperand } @@ -126,7 +126,6 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) { // virtual memory model for the IR I don't think such conversions provide any meaningful // information; // Conversion to another pointer type propagates the source address. - // REVIEW: Is this needed? exists(ConvertInstruction convert, Type resultType | convert = instr and resultType = convert.getResultType() and @@ -141,15 +140,16 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) { // the address with an offset. bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or - // or - // // Computing a field address from a pointer propagates the address plus the - // // offset of the field. - // bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) + // Computing a field address from a pointer propagates the address plus the + // offset of the field. + // TODO: Fix once class layout is synthesized + // bitOffset = Ints::unknown() + //or // A copy propagates the source value. operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0 - // or - // // Some functions are known to propagate an argument - // isAlwaysReturnedArgument(operand) and bitOffset = 0 + or + // Some functions are known to propagate an argument + isAlwaysReturnedArgument(operand) and bitOffset = 0 ) ) } @@ -169,8 +169,8 @@ private predicate operandEscapesNonReturn(Operand operand) { ) ) or - // or - // isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse()) + isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse()) + or operand instanceof PhiInputOperand and resultEscapesNonReturn(operand.getUse()) or @@ -192,8 +192,8 @@ private predicate operandMayReachReturn(Operand operand) { // The address is returned operand.getUse() instanceof ReturnValueInstruction or - // or - // isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse()) + isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse()) + or operand instanceof PhiInputOperand and resultMayReachReturn(operand.getUse()) } @@ -218,7 +218,7 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { operand.getUse() instanceof ReturnValueInstruction and bitOffset = 0 or - // isOnlyEscapesViaReturnArgument(operand) and + isOnlyEscapesViaReturnArgument(operand) and resultReturned(operand.getUse(), _) and bitOffset = Ints::unknown() } @@ -240,28 +240,12 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In ) } -// REVIEW: Those three predicates are used to model the behaviour of C++ library functions -// for which the code was not accessible, so we should ignore them -//private predicate isAlwaysReturnedArgument(Operand operand) { -// exists(AliasFunction f | -// f = operand.getUse().(CallInstruction).getStaticCallTarget() and -// f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex()) -// ) -//} -// -//private predicate isOnlyEscapesViaReturnArgument(Operand operand) { -// exists(AliasFunction f | -// f = operand.getUse().(CallInstruction).getStaticCallTarget() and -// f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex()) -// ) -//} -// -//private predicate isNeverEscapesArgument(Operand operand) { -// exists(AliasFunction f | -// f = operand.getUse().(CallInstruction).getStaticCallTarget() and -// f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex()) -// ) -//} +private predicate isAlwaysReturnedArgument(Operand operand) { none() } + +private predicate isOnlyEscapesViaReturnArgument(Operand operand) { none() } + +private predicate isNeverEscapesArgument(Operand operand) { none() } + private predicate resultReturned(Instruction instr, IntValue bitOffset) { operandReturned(instr.getAUse(), bitOffset) } From f25602bf1c5d2973f2e722834e230aff367bcf85 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Fri, 20 Sep 2019 16:50:21 +0100 Subject: [PATCH 0218/1227] Initial, C++ implementation --- .../code/csharp/ir/rangeanalysis/Bound.qll | 79 +++ .../csharp/ir/rangeanalysis/RangeAnalysis.qll | 612 ++++++++++++++++++ .../csharp/ir/rangeanalysis/RangeUtils.qll | 80 +++ .../csharp/ir/rangeanalysis/SignAnalysis.qll | 581 +++++++++++++++++ 4 files changed, 1352 insertions(+) create mode 100644 csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll new file mode 100644 index 00000000000..fe0e211087c --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll @@ -0,0 +1,79 @@ +import cpp +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.ir.ValueNumbering + +private newtype TBound = + TBoundZero() or + TBoundValueNumber(ValueNumber vn) { + exists(Instruction i | + vn.getAnInstruction() = i and + ( + i.getResultType() instanceof IntegralType or + i.getResultType() instanceof PointerType + ) and + not vn.getAnInstruction() instanceof ConstantInstruction + | + i instanceof PhiInstruction + or + i instanceof InitializeParameterInstruction + or + i instanceof CallInstruction + or + i instanceof VariableAddressInstruction + or + i instanceof FieldAddressInstruction + or + i.(LoadInstruction).getSourceAddress() instanceof VariableAddressInstruction + or + i.(LoadInstruction).getSourceAddress() instanceof FieldAddressInstruction + or + i.getAUse() instanceof ArgumentOperand + ) + } + +/** + * A bound that may be inferred for an expression plus/minus an integer delta. + */ +abstract class Bound extends TBound { + abstract string toString(); + + /** Gets an expression that equals this bound plus `delta`. */ + abstract Instruction getInstruction(int delta); + + /** Gets an expression that equals this bound. */ + Instruction getInstruction() { result = getInstruction(0) } + + abstract Location getLocation(); +} + +/** + * The bound that corresponds to the integer 0. This is used to represent all + * integer bounds as bounds are always accompanied by an added integer delta. + */ +class ZeroBound extends Bound, TBoundZero { + override string toString() { result = "0" } + + override Instruction getInstruction(int delta) { + result.(ConstantValueInstruction).getValue().toInt() = delta + } + + override Location getLocation() { result instanceof UnknownDefaultLocation } +} + +/** + * A bound corresponding to the value of an `Instruction`. + */ +class ValueNumberBound extends Bound, TBoundValueNumber { + ValueNumber vn; + + ValueNumberBound() { this = TBoundValueNumber(vn) } + + /** Gets the SSA variable that equals this bound. */ + override Instruction getInstruction(int delta) { + this = TBoundValueNumber(valueNumber(result)) and delta = 0 + } + + override string toString() { result = vn.getExampleInstruction().toString() } + + override Location getLocation() { result = vn.getLocation() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll new file mode 100644 index 00000000000..50fe6ab9a55 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll @@ -0,0 +1,612 @@ +/** + * Provides classes and predicates for range analysis. + * + * An inferred bound can either be a specific integer or a `ValueNumber` + * representing the abstract value of a set of `Instruction`s. + * + * If an inferred bound relies directly on a condition, then this condition is + * reported as the reason for the bound. + */ + +/* + * This library tackles range analysis as a flow problem. Consider e.g.: + * ``` + * len = arr.length; + * if (x < len) { ... y = x-1; ... y ... } + * ``` + * In this case we would like to infer `y <= arr.length - 2`, and this is + * accomplished by tracking the bound through a sequence of steps: + * ``` + * arr.length --> len = .. --> x < len --> x-1 --> y = .. --> y + * ``` + * + * In its simplest form the step relation `I1 --> I2` relates two `Instruction`s + * such that `I1 <= B` implies `I2 <= B` for any `B` (with a second separate + * step relation handling lower bounds). Examples of such steps include + * assignments `I2 = I1` and conditions `x <= I1` where `I2` is a use of `x` + * guarded by the condition. + * + * In order to handle subtractions and additions with constants, and strict + * comparisons, the step relation is augmented with an integer delta. With this + * generalization `I1 --(delta)--> I2` relates two `Instruction`s and an integer + * such that `I1 <= B` implies `I2 <= B + delta` for any `B`. This corresponds + * to the predicate `boundFlowStep`. + * + * The complete range analysis is then implemented as the transitive closure of + * the step relation summing the deltas along the way. If `I1` transitively + * steps to `I2`, `delta` is the sum of deltas along the path, and `B` is an + * interesting bound equal to the value of `I1` then `I2 <= B + delta`. This + * corresponds to the predicate `boundedInstruction`. + * + * Bounds come in two forms: either they are relative to zero (and thus provide + * a constant bound), or they are relative to some program value. This value is + * represented by the `ValueNumber` class, each instance of which represents a + * set of `Instructions` that must have the same value. + * + * Phi nodes need a little bit of extra handling. Consider `x0 = phi(x1, x2)`. + * There are essentially two cases: + * - If `x1 <= B + d1` and `x2 <= B + d2` then `x0 <= B + max(d1,d2)`. + * - If `x1 <= B + d1` and `x2 <= x0 + d2` with `d2 <= 0` then `x0 <= B + d1`. + * The first case is for whenever a bound can be proven without taking looping + * into account. The second case is relevant when `x2` comes from a back-edge + * where we can prove that the variable has been non-increasing through the + * loop-iteration as this means that any upper bound that holds prior to the + * loop also holds for the variable during the loop. + * This generalizes to a phi node with `n` inputs, so if + * `x0 = phi(x1, ..., xn)` and `xi <= B + delta` for one of the inputs, then we + * also have `x0 <= B + delta` if we can prove either: + * - `xj <= B + d` with `d <= delta` or + * - `xj <= x0 + d` with `d <= 0` + * for each input `xj`. + * + * As all inferred bounds can be related directly to a path in the source code + * the only source of non-termination is if successive redundant (and thereby + * increasingly worse) bounds are calculated along a loop in the source code. + * We prevent this by weakening the bound to a small finite set of bounds when + * a path follows a second back-edge (we postpone weakening till the second + * back-edge as a precise bound might require traversing a loop once). + */ + +import cpp +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.controlflow.IRGuards +private import semmle.code.cpp.ir.ValueNumbering +private import RangeUtils +private import SignAnalysis +import Bound + +cached +private module RangeAnalysisCache { + cached + module RangeAnalysisPublic { + /** + * Holds if `b + delta` is a valid bound for `i`. + * - `upper = true` : `i <= b + delta` + * - `upper = false` : `i >= b + delta` + * + * The reason for the bound is given by `reason` and may be either a condition + * or `NoReason` if the bound was proven directly without the use of a bounding + * condition. + */ + cached + predicate boundedInstruction(Instruction i, Bound b, int delta, boolean upper, Reason reason) { + boundedInstruction(i, b, delta, upper, _, _, reason) + } + + /** + * Holds if `b + delta` is a valid bound for `op`. + * - `upper = true` : `op <= b + delta` + * - `upper = false` : `op >= b + delta` + * + * The reason for the bound is given by `reason` and may be either a condition + * or `NoReason` if the bound was proven directly without the use of a bounding + * condition. + */ + cached + predicate boundedOperand(Operand op, Bound b, int delta, boolean upper, Reason reason) { + boundedNonPhiOperand(op, b, delta, upper, _, _, reason) + or + boundedPhiOperand(op, b, delta, upper, _, _, reason) + } + } + + /** + * Holds if `guard = boundFlowCond(_, _, _, _, _) or guard = eqFlowCond(_, _, _, _, _)`. + */ + cached + predicate possibleReason(IRGuardCondition guard) { + guard = boundFlowCond(_, _, _, _, _) + or + guard = eqFlowCond(_, _, _, _, _) + } +} + +private import RangeAnalysisCache +import RangeAnalysisPublic + +/** + * Gets a condition that tests whether `vn` equals `bound + delta`. + * + * If the condition evaluates to `testIsTrue`: + * - `isEq = true` : `vn == bound + delta` + * - `isEq = false` : `vn != bound + delta` + */ +private IRGuardCondition eqFlowCond( + ValueNumber vn, Operand bound, int delta, boolean isEq, boolean testIsTrue +) { + result.comparesEq(vn.getAUse(), bound, delta, isEq, testIsTrue) +} + +/** + * Holds if `op1 + delta` is a valid bound for `op2`. + * - `upper = true` : `op2 <= op1 + delta` + * - `upper = false` : `op2 >= op1 + delta` + */ +private predicate boundFlowStepSsa( + NonPhiOperand op2, Operand op1, int delta, boolean upper, Reason reason +) { + exists(IRGuardCondition guard, boolean testIsTrue | + guard = boundFlowCond(valueNumberOfOperand(op2), op1, delta, upper, testIsTrue) and + guard.controls(op2.getUse().getBlock(), testIsTrue) and + reason = TCondReason(guard) + ) +} + +/** + * Gets a condition that tests whether `vn` is bounded by `bound + delta`. + * + * If the condition evaluates to `testIsTrue`: + * - `upper = true` : `vn <= bound + delta` + * - `upper = false` : `vn >= bound + delta` + */ +private IRGuardCondition boundFlowCond( + ValueNumber vn, NonPhiOperand bound, int delta, boolean upper, boolean testIsTrue +) { + exists(int d | + result.comparesLt(vn.getAUse(), bound, d, upper, testIsTrue) and + // `comparesLt` provides bounds of the form `x < y + k` or `x >= y + k`, but we need + // `x <= y + k` so we strengthen here. `testIsTrue` has the same semantics in `comparesLt` as + // it does here, so we don't need to account for it. + if upper = true then delta = d - 1 else delta = d + ) + or + result = eqFlowCond(vn, bound, delta, true, testIsTrue) and + (upper = true or upper = false) +} + +private newtype TReason = + TNoReason() or + TCondReason(IRGuardCondition guard) { possibleReason(guard) } + +/** + * A reason for an inferred bound. This can either be `CondReason` if the bound + * is due to a specific condition, or `NoReason` if the bound is inferred + * without going through a bounding condition. + */ +abstract class Reason extends TReason { + abstract string toString(); +} + +class NoReason extends Reason, TNoReason { + override string toString() { result = "NoReason" } +} + +class CondReason extends Reason, TCondReason { + IRGuardCondition getCond() { this = TCondReason(result) } + + override string toString() { result = getCond().toString() } +} + +/** + * Holds if a cast from `fromtyp` to `totyp` can be ignored for the purpose of + * range analysis. + */ +pragma[inline] +private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { + fromtyp.getSize() < totyp.getSize() and + ( + fromtyp.isUnsigned() + or + totyp.isSigned() + ) + or + fromtyp.getSize() <= totyp.getSize() and + ( + fromtyp.isSigned() and + totyp.isSigned() + or + fromtyp.isUnsigned() and + totyp.isUnsigned() + ) +} + +private class SafeCastInstruction extends ConvertInstruction { + SafeCastInstruction() { + safeCast(getResultType(), getUnary().getResultType()) + or + getResultType() instanceof PointerType and + getUnary().getResultType() instanceof PointerType + } +} + +/** + * Holds if `typ` is a small integral type with the given lower and upper bounds. + */ +private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { + typ.isSigned() and typ.getSize() = 1 and lowerbound = -128 and upperbound = 127 + or + typ.isUnsigned() and typ.getSize() = 1 and lowerbound = 0 and upperbound = 255 + or + typ.isSigned() and typ.getSize() = 2 and lowerbound = -32768 and upperbound = 32767 + or + typ.isUnsigned() and typ.getSize() = 2 and lowerbound = 0 and upperbound = 65535 +} + +/** + * A cast to a small integral type that may overflow or underflow. + */ +private class NarrowingCastInstruction extends ConvertInstruction { + NarrowingCastInstruction() { + not this instanceof SafeCastInstruction and + typeBound(getResultType(), _, _) + } + + /** Gets the lower bound of the resulting type. */ + int getLowerBound() { typeBound(getResultType(), result, _) } + + /** Gets the upper bound of the resulting type. */ + int getUpperBound() { typeBound(getResultType(), _, result) } +} + +/** + * Holds if `op + delta` is a valid bound for `i`. + * - `upper = true` : `i <= op + delta` + * - `upper = false` : `i >= op + delta` + */ +private predicate boundFlowStep(Instruction i, NonPhiOperand op, int delta, boolean upper) { + valueFlowStep(i, op, delta) and + (upper = true or upper = false) + or + i.(SafeCastInstruction).getAnOperand() = op and + delta = 0 and + (upper = true or upper = false) + or + exists(Operand x | + i.(AddInstruction).getAnOperand() = op and + i.(AddInstruction).getAnOperand() = x and + op != x + | + not exists(getValue(getConstantValue(op.getUse()))) and + not exists(getValue(getConstantValue(x.getUse()))) and + if strictlyPositive(x) + then upper = false and delta = 1 + else + if positive(x) + then upper = false and delta = 0 + else + if strictlyNegative(x) + then upper = true and delta = -1 + else + if negative(x) + then upper = true and delta = 0 + else none() + ) + or + exists(Operand x | + exists(SubInstruction sub | + i = sub and + sub.getLeftOperand() = op and + sub.getRightOperand() = x + ) + | + // `x` with constant value is covered by valueFlowStep + not exists(getValue(getConstantValue(x.getUse()))) and + if strictlyPositive(x) + then upper = true and delta = -1 + else + if positive(x) + then upper = true and delta = 0 + else + if strictlyNegative(x) + then upper = false and delta = 1 + else + if negative(x) + then upper = false and delta = 0 + else none() + ) + or + i.(RemInstruction).getRightOperand() = op and positive(op) and delta = -1 and upper = true + or + i.(RemInstruction).getLeftOperand() = op and positive(op) and delta = 0 and upper = true + or + i.(BitAndInstruction).getAnOperand() = op and positive(op) and delta = 0 and upper = true + or + i.(BitOrInstruction).getAnOperand() = op and + positiveInstruction(i) and + delta = 0 and + upper = false + // TODO: min, max, rand +} + +private predicate boundFlowStepMul(Instruction i1, Operand op, int factor) { + exists(Instruction c, int k | k = getValue(getConstantValue(c)) and k > 0 | + i1.(MulInstruction).hasOperands(op, c.getAUse()) and factor = k + or + exists(ShiftLeftInstruction i | + i = i1 and i.getLeftOperand() = op and i.getRightOperand() = c.getAUse() and factor = 2.pow(k) + ) + ) +} + +private predicate boundFlowStepDiv(Instruction i1, Operand op, int factor) { + exists(Instruction c, int k | k = getValue(getConstantValue(c)) and k > 0 | + exists(DivInstruction i | + i = i1 and i.getLeftOperand() = op and i.getRight() = c and factor = k + ) + or + exists(ShiftRightInstruction i | + i = i1 and i.getLeftOperand() = op and i.getRight() = c and factor = 2.pow(k) + ) + ) +} + +/** + * Holds if `b` is a valid bound for `op` + */ +pragma[noinline] +private predicate boundedNonPhiOperand( + NonPhiOperand op, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, + Reason reason +) { + exists(NonPhiOperand op2, int d1, int d2 | + boundFlowStepSsa(op, op2, d1, upper, reason) and + boundedNonPhiOperand(op2, b, d2, upper, fromBackEdge, origdelta, _) and + delta = d1 + d2 + ) + or + boundedInstruction(op.getDef(), b, delta, upper, fromBackEdge, origdelta, reason) + or + exists(int d, Reason r1, Reason r2 | + boundedNonPhiOperand(op, b, d, upper, fromBackEdge, origdelta, r2) + | + unequalOperand(op, b, d, r1) and + ( + upper = true and delta = d - 1 + or + upper = false and delta = d + 1 + ) and + ( + reason = r1 + or + reason = r2 and not r2 instanceof NoReason + ) + ) +} + +/** + * Holds if `op1 + delta` is a valid bound for `op2`. + * - `upper = true` : `op2 <= op1 + delta` + * - `upper = false` : `op2 >= op1 + delta` + */ +private predicate boundFlowStepPhi( + PhiInputOperand op2, Operand op1, int delta, boolean upper, Reason reason +) { + op2.getDef().(CopyInstruction).getSourceValueOperand() = op1 and + (upper = true or upper = false) and + reason = TNoReason() and + delta = 0 + or + exists(IRGuardCondition guard, boolean testIsTrue | + guard = boundFlowCond(valueNumberOfOperand(op2), op1, delta, upper, testIsTrue) and + guard.controlsEdge(op2.getPredecessorBlock(), op2.getUse().getBlock(), testIsTrue) and + reason = TCondReason(guard) + ) +} + +private predicate boundedPhiOperand( + PhiInputOperand op, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, + Reason reason +) { + exists(NonPhiOperand op2, int d1, int d2, Reason r1, Reason r2 | + boundFlowStepPhi(op, op2, d1, upper, r1) and + boundedNonPhiOperand(op2, b, d2, upper, fromBackEdge, origdelta, r2) and + delta = d1 + d2 and + (if r1 instanceof NoReason then reason = r2 else reason = r1) + ) + or + boundedInstruction(op.getDef(), b, delta, upper, fromBackEdge, origdelta, reason) + or + exists(int d, Reason r1, Reason r2 | + boundedInstruction(op.getDef(), b, d, upper, fromBackEdge, origdelta, r2) + | + unequalOperand(op, b, d, r1) and + ( + upper = true and delta = d - 1 + or + upper = false and delta = d + 1 + ) and + ( + reason = r1 + or + reason = r2 and not r2 instanceof NoReason + ) + ) +} + +/** Holds if `op2 != op1 + delta` at `pos`. */ +private predicate unequalFlowStep(Operand op2, Operand op1, int delta, Reason reason) { + exists(IRGuardCondition guard, boolean testIsTrue | + guard = eqFlowCond(valueNumberOfOperand(op2), op1, delta, false, testIsTrue) and + guard.controls(op2.getUse().getBlock(), testIsTrue) and + reason = TCondReason(guard) + ) +} + +/** + * Holds if `op != b + delta` at `pos`. + */ +private predicate unequalOperand(Operand op, Bound b, int delta, Reason reason) { + exists(Operand op2, int d1, int d2 | + unequalFlowStep(op, op2, d1, reason) and + boundedNonPhiOperand(op2, b, d2, true, _, _, _) and + boundedNonPhiOperand(op2, b, d2, false, _, _, _) and + delta = d1 + d2 + ) +} + +private predicate boundedPhiCandValidForEdge( + PhiInstruction phi, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, + Reason reason, PhiInputOperand op +) { + boundedPhiCand(phi, upper, b, delta, fromBackEdge, origdelta, reason) and + ( + exists(int d | boundedPhiInp1(phi, op, b, d, upper) | upper = true and d <= delta) + or + exists(int d | boundedPhiInp1(phi, op, b, d, upper) | upper = false and d >= delta) + or + selfBoundedPhiInp(phi, op, upper) + ) +} + +/** Weakens a delta to lie in the range `[-1..1]`. */ +bindingset[delta, upper] +private int weakenDelta(boolean upper, int delta) { + delta in [-1 .. 1] and result = delta + or + upper = true and result = -1 and delta < -1 + or + upper = false and result = 1 and delta > 1 +} + +private predicate boundedPhiInp( + PhiInstruction phi, PhiInputOperand op, Bound b, int delta, boolean upper, boolean fromBackEdge, + int origdelta, Reason reason +) { + phi.getAnOperand() = op and + exists(int d, boolean fromBackEdge0 | + boundedPhiOperand(op, b, d, upper, fromBackEdge0, origdelta, reason) + or + b.(ValueNumberBound).getInstruction() = op.getDef() and + d = 0 and + (upper = true or upper = false) and + fromBackEdge0 = false and + origdelta = 0 and + reason = TNoReason() + | + if backEdge(phi, op) + then + fromBackEdge = true and + ( + fromBackEdge0 = true and delta = weakenDelta(upper, d - origdelta) + origdelta + or + fromBackEdge0 = false and delta = d + ) + else ( + delta = d and fromBackEdge = fromBackEdge0 + ) + ) +} + +pragma[noinline] +private predicate boundedPhiInp1( + PhiInstruction phi, PhiInputOperand op, Bound b, int delta, boolean upper +) { + boundedPhiInp(phi, op, b, delta, upper, _, _, _) +} + +private predicate selfBoundedPhiInp(PhiInstruction phi, PhiInputOperand op, boolean upper) { + exists(int d, ValueNumberBound phibound | + phibound.getInstruction() = phi and + boundedPhiInp(phi, op, phibound, d, upper, _, _, _) and + ( + upper = true and d <= 0 + or + upper = false and d >= 0 + ) + ) +} + +pragma[noinline] +private predicate boundedPhiCand( + PhiInstruction phi, boolean upper, Bound b, int delta, boolean fromBackEdge, int origdelta, + Reason reason +) { + exists(PhiInputOperand op | + boundedPhiInp(phi, op, b, delta, upper, fromBackEdge, origdelta, reason) + ) +} + +/** + * Holds if the value being cast has an upper (for `upper = true`) or lower + * (for `upper = false`) bound within the bounds of the resulting type. + * For `upper = true` this means that the cast will not overflow and for + * `upper = false` this means that the cast will not underflow. + */ +private predicate safeNarrowingCast(NarrowingCastInstruction cast, boolean upper) { + exists(int bound | + boundedNonPhiOperand(cast.getAnOperand(), any(ZeroBound zb), bound, upper, _, _, _) + | + upper = true and bound <= cast.getUpperBound() + or + upper = false and bound >= cast.getLowerBound() + ) +} + +pragma[noinline] +private predicate boundedCastExpr( + NarrowingCastInstruction cast, Bound b, int delta, boolean upper, boolean fromBackEdge, + int origdelta, Reason reason +) { + boundedNonPhiOperand(cast.getAnOperand(), b, delta, upper, fromBackEdge, origdelta, reason) +} + +/** + * Holds if `b + delta` is a valid bound for `i`. + * - `upper = true` : `i <= b + delta` + * - `upper = false` : `i >= b + delta` + */ +private predicate boundedInstruction( + Instruction i, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, + Reason reason +) { + i instanceof PhiInstruction and + forex(PhiInputOperand op | op = i.getAnOperand() | + boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op) + ) + or + i = b.getInstruction(delta) and + (upper = true or upper = false) and + fromBackEdge = false and + origdelta = delta and + reason = TNoReason() + or + exists(Operand mid, int d1, int d2 | + boundFlowStep(i, mid, d1, upper) and + boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and + delta = d1 + d2 and + not exists(getValue(getConstantValue(i))) + ) + or + exists(Operand mid, int factor, int d | + boundFlowStepMul(i, mid, factor) and + boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and + b instanceof ZeroBound and + delta = d * factor and + not exists(getValue(getConstantValue(i))) + ) + or + exists(Operand mid, int factor, int d | + boundFlowStepDiv(i, mid, factor) and + boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and + d >= 0 and + b instanceof ZeroBound and + delta = d / factor and + not exists(getValue(getConstantValue(i))) + ) + or + exists(NarrowingCastInstruction cast | + cast = i and + safeNarrowingCast(cast, upper.booleanNot()) and + boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason) + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll new file mode 100644 index 00000000000..52782bcda30 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll @@ -0,0 +1,80 @@ +import cpp +private import semmle.code.cpp.ir.IR +// TODO: move this dependency +import semmle.code.cpp.ir.internal.IntegerConstant + +// TODO: move this out of test code +language[monotonicAggregates] +IntValue getConstantValue(Instruction instr) { + result = instr.(IntegerConstantInstruction).getValue().toInt() + or + exists(BinaryInstruction binInstr, IntValue left, IntValue right | + binInstr = instr and + left = getConstantValue(binInstr.getLeft()) and + right = getConstantValue(binInstr.getRight()) and + ( + binInstr instanceof AddInstruction and result = add(left, right) + or + binInstr instanceof SubInstruction and result = sub(left, right) + or + binInstr instanceof MulInstruction and result = mul(left, right) + or + binInstr instanceof DivInstruction and result = div(left, right) + ) + ) + or + result = getConstantValue(instr.(CopyInstruction).getSourceValue()) + or + exists(PhiInstruction phi | + phi = instr and + result = max(PhiInputOperand operand | + operand = phi.getAnOperand() + | + getConstantValue(operand.getDef()) + ) and + result = min(PhiInputOperand operand | + operand = phi.getAnOperand() + | + getConstantValue(operand.getDef()) + ) + ) +} + +predicate valueFlowStep(Instruction i, Operand op, int delta) { + i.(CopyInstruction).getSourceValueOperand() = op and delta = 0 + or + exists(Operand x | + i.(AddInstruction).getAnOperand() = op and + i.(AddInstruction).getAnOperand() = x and + op != x + | + delta = getValue(getConstantValue(x.getDef())) + ) + or + exists(Operand x | + i.(SubInstruction).getLeftOperand() = op and + i.(SubInstruction).getRightOperand() = x + | + delta = -getValue(getConstantValue(x.getDef())) + ) + or + exists(Operand x | + i.(PointerAddInstruction).getAnOperand() = op and + i.(PointerAddInstruction).getAnOperand() = x and + op != x + | + delta = i.(PointerAddInstruction).getElementSize() * getValue(getConstantValue(x.getDef())) + ) + or + exists(Operand x | + i.(PointerSubInstruction).getLeftOperand() = op and + i.(PointerSubInstruction).getRightOperand() = x + | + delta = i.(PointerSubInstruction).getElementSize() * -getValue(getConstantValue(x.getDef())) + ) +} + +predicate backEdge(PhiInstruction phi, PhiInputOperand op) { + phi.getAnOperand() = op and + phi.getBlock() = op.getPredecessorBlock().getBackEdgeSuccessor(_) +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll new file mode 100644 index 00000000000..ca641f826ef --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll @@ -0,0 +1,581 @@ +/** + * Provides sign analysis to determine whether expression are always positive + * or negative. + * + * The analysis is implemented as an abstract interpretation over the + * three-valued domain `{negative, zero, positive}`. + */ + +import cpp +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.controlflow.IRGuards +private import semmle.code.cpp.ir.ValueNumbering +private import SignAnalysisCached + +private newtype TSign = + TNeg() or + TZero() or + TPos() + +private class Sign extends TSign { + string toString() { + result = "-" and this = TNeg() + or + result = "0" and this = TZero() + or + result = "+" and this = TPos() + } + + Sign inc() { + this = TNeg() and result = TNeg() + or + this = TNeg() and result = TZero() + or + this = TZero() and result = TPos() + or + this = TPos() and result = TPos() + } + + Sign dec() { result.inc() = this } + + Sign neg() { + this = TNeg() and result = TPos() + or + this = TZero() and result = TZero() + or + this = TPos() and result = TNeg() + } + + Sign bitnot() { + this = TNeg() and result = TPos() + or + this = TNeg() and result = TZero() + or + this = TZero() and result = TNeg() + or + this = TPos() and result = TNeg() + } + + Sign add(Sign s) { + this = TZero() and result = s + or + s = TZero() and result = this + or + this = s and this = result + or + this = TPos() and s = TNeg() + or + this = TNeg() and s = TPos() + } + + Sign mul(Sign s) { + result = TZero() and this = TZero() + or + result = TZero() and s = TZero() + or + result = TNeg() and this = TPos() and s = TNeg() + or + result = TNeg() and this = TNeg() and s = TPos() + or + result = TPos() and this = TPos() and s = TPos() + or + result = TPos() and this = TNeg() and s = TNeg() + } + + Sign div(Sign s) { + result = TZero() and s = TNeg() + or + result = TZero() and s = TPos() + or + result = TNeg() and this = TPos() and s = TNeg() + or + result = TNeg() and this = TNeg() and s = TPos() + or + result = TPos() and this = TPos() and s = TPos() + or + result = TPos() and this = TNeg() and s = TNeg() + } + + Sign rem(Sign s) { + result = TZero() and s = TNeg() + or + result = TZero() and s = TPos() + or + result = this and s = TNeg() + or + result = this and s = TPos() + } + + Sign bitand(Sign s) { + result = TZero() and this = TZero() + or + result = TZero() and s = TZero() + or + result = TZero() and this = TPos() + or + result = TZero() and s = TPos() + or + result = TNeg() and this = TNeg() and s = TNeg() + or + result = TPos() and this = TNeg() and s = TPos() + or + result = TPos() and this = TPos() and s = TNeg() + or + result = TPos() and this = TPos() and s = TPos() + } + + Sign bitor(Sign s) { + result = TZero() and this = TZero() and s = TZero() + or + result = TNeg() and this = TNeg() + or + result = TNeg() and s = TNeg() + or + result = TPos() and this = TPos() and s = TZero() + or + result = TPos() and this = TZero() and s = TPos() + or + result = TPos() and this = TPos() and s = TPos() + } + + Sign bitxor(Sign s) { + result = TZero() and this = s + or + result = this and s = TZero() + or + result = s and this = TZero() + or + result = TPos() and this = TPos() and s = TPos() + or + result = TNeg() and this = TNeg() and s = TPos() + or + result = TNeg() and this = TPos() and s = TNeg() + or + result = TPos() and this = TNeg() and s = TNeg() + } + + Sign lshift(Sign s) { + result = TZero() and this = TZero() + or + result = this and s = TZero() + or + this != TZero() and s != TZero() + } + + Sign rshift(Sign s) { + result = TZero() and this = TZero() + or + result = this and s = TZero() + or + result = TNeg() and this = TNeg() + or + result != TNeg() and this = TPos() and s != TZero() + } + + Sign urshift(Sign s) { + result = TZero() and this = TZero() + or + result = this and s = TZero() + or + result != TZero() and this = TNeg() and s != TZero() + or + result != TNeg() and this = TPos() and s != TZero() + } +} + +private Sign certainInstructionSign(Instruction inst) { + exists(int i | inst.(IntegerConstantInstruction).getValue().toInt() = i | + i < 0 and result = TNeg() + or + i = 0 and result = TZero() + or + i > 0 and result = TPos() + ) + or + exists(float f | f = inst.(FloatConstantInstruction).getValue().toFloat() | + f < 0 and result = TNeg() + or + f = 0 and result = TZero() + or + f > 0 and result = TPos() + ) +} + +private newtype CastKind = + TWiden() or + TSame() or + TNarrow() + +private CastKind getCastKind(ConvertInstruction ci) { + exists(int fromSize, int toSize | + toSize = ci.getResultSize() and + fromSize = ci.getUnary().getResultSize() + | + fromSize < toSize and + result = TWiden() + or + fromSize = toSize and + result = TSame() + or + fromSize > toSize and + result = TNarrow() + ) +} + +private predicate bindBool(boolean bool) { + bool = true or + bool = false +} + +private Sign castSign(Sign s, boolean fromSigned, boolean toSigned, CastKind ck) { + result = TZero() and + ( + bindBool(fromSigned) and + bindBool(toSigned) and + s = TZero() + or + bindBool(fromSigned) and + bindBool(toSigned) and + ck = TNarrow() + ) + or + result = TPos() and + ( + bindBool(fromSigned) and + bindBool(toSigned) and + s = TPos() + or + bindBool(fromSigned) and + bindBool(toSigned) and + s = TNeg() and + ck = TNarrow() + or + fromSigned = true and + toSigned = false and + s = TNeg() + ) + or + result = TNeg() and + ( + fromSigned = true and + toSigned = true and + s = TNeg() + or + fromSigned = false and + toSigned = true and + s = TPos() and + ck != TWiden() + ) +} + +/** Holds if the sign of `e` is too complicated to determine. */ +private predicate unknownSign(Instruction i) { + // REVIEW: This should probably be a list of the instructions that we _do_ understand, rather than + // the ones we don't understand. Currently, if we try to compute the sign of an instruction that + // we don't understand, and it isn't on this list, we incorrectly compute the sign as "none" + // instead of "+,0,-". + // Even better, we could track the state of each instruction as a power set of {non-negative, + // non-positive, non-zero}, which would mean that the representation of the sign of an unknown + // value would be the empty set. + ( + i instanceof UnmodeledDefinitionInstruction + or + i instanceof UninitializedInstruction + or + i instanceof InitializeParameterInstruction + or + i instanceof BuiltInOperationInstruction + or + i instanceof CallInstruction + or + i instanceof ChiInstruction + ) +} + +/** + * Holds if `lowerbound` is a lower bound for `bounded`. This is restricted + * to only include bounds for which we might determine a sign. + */ +private predicate lowerBound( + IRGuardCondition comp, Operand lowerbound, Operand bounded, boolean isStrict +) { + exists(int adjustment, Operand compared | + valueNumberOfOperand(bounded) = valueNumberOfOperand(compared) and + ( + isStrict = true and + adjustment = 0 + or + isStrict = false and + adjustment = 1 + ) and + comp.ensuresLt(lowerbound, compared, adjustment, bounded.getUse().getBlock(), true) + ) +} + +/** + * Holds if `upperbound` is an upper bound for `bounded` at `pos`. This is restricted + * to only include bounds for which we might determine a sign. + */ +private predicate upperBound( + IRGuardCondition comp, Operand upperbound, Operand bounded, boolean isStrict +) { + exists(int adjustment, Operand compared | + valueNumberOfOperand(bounded) = valueNumberOfOperand(compared) and + ( + isStrict = true and + adjustment = 0 + or + isStrict = false and + adjustment = 1 + ) and + comp.ensuresLt(compared, upperbound, adjustment, bounded.getUse().getBlock(), true) + ) +} + +/** + * Holds if `eqbound` is an equality/inequality for `bounded` at `pos`. This is + * restricted to only include bounds for which we might determine a sign. The + * boolean `isEq` gives the polarity: + * - `isEq = true` : `bounded = eqbound` + * - `isEq = false` : `bounded != eqbound` + */ +private predicate eqBound(IRGuardCondition guard, Operand eqbound, Operand bounded, boolean isEq) { + exists(Operand compared | + valueNumberOfOperand(bounded) = valueNumberOfOperand(compared) and + guard.ensuresEq(compared, eqbound, 0, bounded.getUse().getBlock(), isEq) + ) +} + +/** + * Holds if `bound` is a bound for `v` at `pos` that needs to be positive in + * order for `v` to be positive. + */ +private predicate posBound(IRGuardCondition comp, Operand bound, Operand op) { + upperBound(comp, bound, op, _) or + eqBound(comp, bound, op, true) +} + +/** + * Holds if `bound` is a bound for `v` at `pos` that needs to be negative in + * order for `v` to be negative. + */ +private predicate negBound(IRGuardCondition comp, Operand bound, Operand op) { + lowerBound(comp, bound, op, _) or + eqBound(comp, bound, op, true) +} + +/** + * Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v` + * can be zero. + */ +private predicate zeroBound(IRGuardCondition comp, Operand bound, Operand op) { + lowerBound(comp, bound, op, _) or + upperBound(comp, bound, op, _) or + eqBound(comp, bound, op, _) +} + +/** Holds if `bound` allows `v` to be positive at `pos`. */ +private predicate posBoundOk(IRGuardCondition comp, Operand bound, Operand op) { + posBound(comp, bound, op) and TPos() = operandSign(bound) +} + +/** Holds if `bound` allows `v` to be negative at `pos`. */ +private predicate negBoundOk(IRGuardCondition comp, Operand bound, Operand op) { + negBound(comp, bound, op) and TNeg() = operandSign(bound) +} + +/** Holds if `bound` allows `v` to be zero at `pos`. */ +private predicate zeroBoundOk(IRGuardCondition comp, Operand bound, Operand op) { + lowerBound(comp, bound, op, _) and TNeg() = operandSign(bound) + or + lowerBound(comp, bound, op, false) and TZero() = operandSign(bound) + or + upperBound(comp, bound, op, _) and TPos() = operandSign(bound) + or + upperBound(comp, bound, op, false) and TZero() = operandSign(bound) + or + eqBound(comp, bound, op, true) and TZero() = operandSign(bound) + or + eqBound(comp, bound, op, false) and TZero() != operandSign(bound) +} + +private Sign binaryOpLhsSign(BinaryInstruction i) { result = operandSign(i.getLeftOperand()) } + +private Sign binaryOpRhsSign(BinaryInstruction i) { result = operandSign(i.getRightOperand()) } + +pragma[noinline] +private predicate binaryOpSigns(BinaryInstruction i, Sign lhs, Sign rhs) { + lhs = binaryOpLhsSign(i) and + rhs = binaryOpRhsSign(i) +} + +private Sign unguardedOperandSign(Operand operand) { + result = instructionSign(operand.getDef()) and + not hasGuard(operand, result) +} + +private Sign guardedOperandSign(Operand operand) { + result = instructionSign(operand.getDef()) and + hasGuard(operand, result) +} + +private Sign guardedOperandSignOk(Operand operand) { + result = TPos() and + forex(IRGuardCondition guard, Operand bound | posBound(guard, bound, operand) | + posBoundOk(guard, bound, operand) + ) + or + result = TNeg() and + forex(IRGuardCondition guard, Operand bound | negBound(guard, bound, operand) | + negBoundOk(guard, bound, operand) + ) + or + result = TZero() and + forex(IRGuardCondition guard, Operand bound | zeroBound(guard, bound, operand) | + zeroBoundOk(guard, bound, operand) + ) +} + +/** + * Holds if there is a bound that might restrict whether `v` has the sign `s` + * at `pos`. + */ +private predicate hasGuard(Operand op, Sign s) { + s = TPos() and posBound(_, _, op) + or + s = TNeg() and negBound(_, _, op) + or + s = TZero() and zeroBound(_, _, op) +} + +cached +module SignAnalysisCached { + /** + * Gets a sign that `operand` may have at `pos`, taking guards into account. + */ + cached + Sign operandSign(Operand operand) { + result = unguardedOperandSign(operand) + or + result = guardedOperandSign(operand) and + result = guardedOperandSignOk(operand) + or + // `result` is unconstrained if the definition is inexact. Then any sign is possible. + operand.isDefinitionInexact() + } + + cached + Sign instructionSign(Instruction i) { + result = certainInstructionSign(i) + or + not exists(certainInstructionSign(i)) and + not ( + result = TNeg() and + i.getResultType().(IntegralType).isUnsigned() + ) and + ( + unknownSign(i) + or + exists(ConvertInstruction ci, Instruction prior, boolean fromSigned, boolean toSigned | + i = ci and + prior = ci.getUnary() and + (if ci.getResultType().(IntegralType).isSigned() then toSigned = true else toSigned = false) and + ( + if prior.getResultType().(IntegralType).isSigned() + then fromSigned = true + else fromSigned = false + ) and + result = castSign(operandSign(ci.getAnOperand()), fromSigned, toSigned, getCastKind(ci)) + ) + or + result = operandSign(i.(CopyInstruction).getSourceValueOperand()) + or + result = operandSign(i.(BitComplementInstruction).getAnOperand()).bitnot() + or + result = operandSign(i.(NegateInstruction).getAnOperand()).neg() + or + exists(Sign s1, Sign s2 | binaryOpSigns(i, s1, s2) | + i instanceof AddInstruction and result = s1.add(s2) + or + i instanceof SubInstruction and result = s1.add(s2.neg()) + or + i instanceof MulInstruction and result = s1.mul(s2) + or + i instanceof DivInstruction and result = s1.div(s2) + or + i instanceof RemInstruction and result = s1.rem(s2) + or + i instanceof BitAndInstruction and result = s1.bitand(s2) + or + i instanceof BitOrInstruction and result = s1.bitor(s2) + or + i instanceof BitXorInstruction and result = s1.bitxor(s2) + or + i instanceof ShiftLeftInstruction and result = s1.lshift(s2) + or + i instanceof ShiftRightInstruction and + i.getResultType().(IntegralType).isSigned() and + result = s1.rshift(s2) + or + i instanceof ShiftRightInstruction and + not i.getResultType().(IntegralType).isSigned() and + result = s1.urshift(s2) + ) + or + // use hasGuard here? + result = operandSign(i.(PhiInstruction).getAnOperand()) + ) + } +} + +/** Holds if `i` can be positive and cannot be negative. */ +predicate positiveInstruction(Instruction i) { + instructionSign(i) = TPos() and + not instructionSign(i) = TNeg() +} + +/** Holds if `i` at `pos` can be positive at and cannot be negative. */ +predicate positive(Operand op) { + operandSign(op) = TPos() and + not operandSign(op) = TNeg() +} + +/** Holds if `i` can be negative and cannot be positive. */ +predicate negativeInstruction(Instruction i) { + instructionSign(i) = TNeg() and + not instructionSign(i) = TPos() +} + +/** Holds if `i` at `pos` can be negative and cannot be positive. */ +predicate negative(Operand op) { + operandSign(op) = TNeg() and + not operandSign(op) = TPos() +} + +/** Holds if `i` is strictly positive. */ +predicate strictlyPositiveInstruction(Instruction i) { + instructionSign(i) = TPos() and + not instructionSign(i) = TNeg() and + not instructionSign(i) = TZero() +} + +/** Holds if `i` is strictly positive at `pos`. */ +predicate strictlyPositive(Operand op) { + operandSign(op) = TPos() and + not operandSign(op) = TNeg() and + not operandSign(op) = TZero() +} + +/** Holds if `i` is strictly negative. */ +predicate strictlyNegativeInstruction(Instruction i) { + instructionSign(i) = TNeg() and + not instructionSign(i) = TPos() and + not instructionSign(i) = TZero() +} + +/** Holds if `i` is strictly negative at `pos`. */ +predicate strictlyNegative(Operand op) { + operandSign(op) = TNeg() and + not operandSign(op) = TPos() and + not operandSign(op) = TZero() +} From 1b47f80a7a082b9f9a74689ebdb231206a407197 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Fri, 20 Sep 2019 16:51:14 +0100 Subject: [PATCH 0219/1227] C# implementation --- .../code/csharp/ir/internal/IRGuards.qll | 667 ++++++++++++++++++ .../code/csharp/ir/rangeanalysis/Bound.qll | 8 +- .../csharp/ir/rangeanalysis/RangeAnalysis.qll | 45 +- .../csharp/ir/rangeanalysis/RangeUtils.qll | 13 +- .../csharp/ir/rangeanalysis/SignAnalysis.qll | 22 +- 5 files changed, 725 insertions(+), 30 deletions(-) create mode 100644 csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll new file mode 100644 index 00000000000..4912de9403e --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll @@ -0,0 +1,667 @@ +import csharp +import semmle.code.csharp.controlflow.BasicBlocks +import semmle.code.csharp.ir.IR + +/** + * Holds if `block` consists of an `UnreachedInstruction`. + * + * We avoiding reporting an unreached block as being controlled by a guard. The unreached block + * has the AST for the `Function` itself, which tends to confuse mapping between the AST `BasicBlock` + * and the `IRBlock`. + */ +private predicate isUnreachedBlock(IRBlock block) { + block.getFirstInstruction() instanceof UnreachedInstruction +} + +/** + * A Boolean condition in the AST that guards one or more basic blocks. This includes + * operands of logical operators but not switch statements. + */ +cached +class GuardCondition extends Expr { + cached + GuardCondition() { + exists(IRGuardCondition ir | this = ir.getUnconvertedResultExpression()) + or + // no binary operators in the IR + exists(GuardCondition gc | this.(BinaryLogicalOperation).getAnOperand() = gc) + or + // the IR short-circuits if(!x) + // don't produce a guard condition for `y = !x` and other non-short-circuited cases + not exists(Instruction inst | this = inst.getAST()) and + exists(IRGuardCondition ir | this.(LogicalNotExpr).getOperand() = ir.getAST()) + } + + /** + * Holds if this condition controls `block`, meaning that `block` is only + * entered if the value of this condition is `testIsTrue`. + * + * Illustration: + * + * ``` + * [ (testIsTrue) ] + * [ this ----------------succ ---- controlled ] + * [ | | ] + * [ (testIsFalse) | ------ ... ] + * [ other ] + * ``` + * + * The predicate holds if all paths to `controlled` go via the `testIsTrue` + * edge of the control-flow graph. In other words, the `testIsTrue` edge + * must dominate `controlled`. This means that `controlled` must be + * dominated by both `this` and `succ` (the target of the `testIsTrue` + * edge). It also means that any other edge into `succ` must be a back-edge + * from a node which is dominated by `succ`. + * + * The short-circuit boolean operations have slightly surprising behavior + * here: because the operation itself only dominates one branch (due to + * being short-circuited) then it will only control blocks dominated by the + * true (for `&&`) or false (for `||`) branch. + */ + cached + predicate controls(BasicBlock controlled, boolean testIsTrue) { none() } + + /** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */ + cached + predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { + none() + } + + /** + * Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`. + * If `isLessThan = false` then this implies `left >= right + k`. + */ + cached + predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { none() } + + /** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */ + cached + predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) { + none() + } + + /** + * Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`. + * If `areEqual = false` then this implies `left != right + k`. + */ + cached + predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) { none() } +} + +/** + * Holds if the truth of the binary logical expression `blo` having value `wholeIsTrue` + * implies that the truth of the child expression `part` has truth value `partIsTrue`. + * + * For example if the binary operation: + * ``` + * x && y + * ``` + * is true, `x` and `y` must also be true, so `impliesValue(x, true, true)` and + * `impliesValue(y, true, true)` hold. + */ +private predicate impliesValue( + BinaryLogicalOperation blo, Expr part, boolean partIsTrue, boolean wholeIsTrue +) { + blo instanceof LogicalAndExpr and + ( + wholeIsTrue = true and partIsTrue = true and part = blo.getAnOperand() + or + wholeIsTrue = true and + impliesValue(blo.getAnOperand().(BinaryLogicalOperation), part, partIsTrue, true) + ) + or + blo instanceof LogicalOrExpr and + ( + wholeIsTrue = false and partIsTrue = false and part = blo.getAnOperand() + or + wholeIsTrue = false and + impliesValue(blo.getAnOperand().(BinaryLogicalOperation), part, partIsTrue, false) + ) +} + +/** + * A binary logical operator in the AST that guards one or more basic blocks. + */ +private class GuardConditionFromBinaryLogicalOperator extends GuardCondition { + GuardConditionFromBinaryLogicalOperator() { + exists(GuardCondition gc | this.(BinaryLogicalOperation).getAnOperand() = gc) + } + + override predicate controls(BasicBlock controlled, boolean testIsTrue) { + exists(BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs | + this = binop and + lhs = binop.getLeftOperand() and + rhs = binop.getRightOperand() and + lhs.controls(controlled, testIsTrue) and + rhs.controls(controlled, testIsTrue) + ) + } + + override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { + exists(boolean partIsTrue, GuardCondition part | + impliesValue(this.(BinaryLogicalOperation), part, partIsTrue, testIsTrue) + | + part.comparesLt(left, right, k, isLessThan, partIsTrue) + ) + } + + override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { + exists(boolean testIsTrue | + comparesLt(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue) + ) + } + + override predicate comparesEq(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { + exists(boolean partIsTrue, GuardCondition part | + impliesValue(this.(BinaryLogicalOperation), part, partIsTrue, testIsTrue) + | + part.comparesEq(left, right, k, isLessThan, partIsTrue) + ) + } + + override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { + exists(boolean testIsTrue | + comparesEq(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue) + ) + } +} + +/** + * A `!` operator in the AST that guards one or more basic blocks, and does not have a corresponding + * IR instruction. + */ +private class GuardConditionFromShortCircuitNot extends GuardCondition, LogicalNotExpr { + GuardConditionFromShortCircuitNot() { + not exists(Instruction inst | this = inst.getAST()) and + exists(IRGuardCondition ir | getOperand() = ir.getAST()) + } + + override predicate controls(BasicBlock controlled, boolean testIsTrue) { + getOperand().(GuardCondition).controls(controlled, testIsTrue.booleanNot()) + } + + override predicate comparesLt(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) { + getOperand().(GuardCondition).comparesLt(left, right, k, areEqual, testIsTrue.booleanNot()) + } + + override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean testIsTrue) { + getOperand().(GuardCondition).ensuresLt(left, right, k, block, testIsTrue.booleanNot()) + } + + override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) { + getOperand().(GuardCondition).comparesEq(left, right, k, areEqual, testIsTrue.booleanNot()) + } + + override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean testIsTrue) { + getOperand().(GuardCondition).ensuresEq(left, right, k, block, testIsTrue.booleanNot()) + } +} + +/** + * A Boolean condition in the AST that guards one or more basic blocks and has a corresponding IR + * instruction. + */ +private class GuardConditionFromIR extends GuardCondition { + IRGuardCondition ir; + + GuardConditionFromIR() { this = ir.getUnconvertedResultExpression() } + + override predicate controls(BasicBlock controlled, boolean testIsTrue) { + // This condition must determine the flow of control; that is, this + // node must be a top-level condition. + this.controlsBlock1(controlled, testIsTrue) + } + + /** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */ + override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) { + exists(Instruction li, Instruction ri | + li.getUnconvertedResultExpression() = left and + ri.getUnconvertedResultExpression() = right and + ir.comparesLt(li.getAUse(), ri.getAUse(), k, isLessThan, testIsTrue) + ) + } + + /** + * Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`. + * If `isLessThan = false` then this implies `left >= right + k`. + */ + override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) { + exists(Instruction li, Instruction ri, boolean testIsTrue | + li.getUnconvertedResultExpression() = left and + ri.getUnconvertedResultExpression() = right and + ir.comparesLt(li.getAUse(), ri.getAUse(), k, isLessThan, testIsTrue) and + this.controls(block, testIsTrue) + ) + } + + /** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */ + override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) { + exists(Instruction li, Instruction ri | + li.getUnconvertedResultExpression() = left and + ri.getUnconvertedResultExpression() = right and + ir.comparesEq(li.getAUse(), ri.getAUse(), k, areEqual, testIsTrue) + ) + } + + /** + * Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`. + * If `areEqual = false` then this implies `left != right + k`. + */ + override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) { + exists(Instruction li, Instruction ri, boolean testIsTrue | + li.getUnconvertedResultExpression() = left and + ri.getUnconvertedResultExpression() = right and + ir.comparesEq(li.getAUse(), ri.getAUse(), k, areEqual, testIsTrue) and + this.controls(block, testIsTrue) + ) + } + + /** + * Holds if this condition controls `block`, meaning that `block` is only + * entered if the value of this condition is `testIsTrue`. This helper + * predicate does not necessarily hold for binary logical operations like + * `&&` and `||`. See the detailed explanation on predicate `controls`. + */ + private predicate controlsBlock1(BasicBlock controlled, boolean testIsTrue) { + exists(IRBlock irb | + forex(IRGuardCondition inst | inst = ir | inst.controls(irb, testIsTrue)) and + irb.getAnInstruction().getAST().(ControlFlowElement).getAControlFlowNode().getBasicBlock() = controlled and + not isUnreachedBlock(irb) + ) + } +} + +/** + * A Boolean condition in the IR that guards one or more basic blocks. This includes + * operands of logical operators but not switch statements. Note that `&&` and `||` + * don't have an explicit representation in the IR, and therefore will not appear as + * IRGuardConditions. + */ +cached +class IRGuardCondition extends Instruction { + ConditionalBranchInstruction branch; + + cached + IRGuardCondition() { branch = get_branch_for_condition(this) } + + /** + * Holds if this condition controls `block`, meaning that `block` is only + * entered if the value of this condition is `testIsTrue`. + * + * Illustration: + * + * ``` + * [ (testIsTrue) ] + * [ this ----------------succ ---- controlled ] + * [ | | ] + * [ (testIsFalse) | ------ ... ] + * [ other ] + * ``` + * + * The predicate holds if all paths to `controlled` go via the `testIsTrue` + * edge of the control-flow graph. In other words, the `testIsTrue` edge + * must dominate `controlled`. This means that `controlled` must be + * dominated by both `this` and `succ` (the target of the `testIsTrue` + * edge). It also means that any other edge into `succ` must be a back-edge + * from a node which is dominated by `succ`. + * + * The short-circuit boolean operations have slightly surprising behavior + * here: because the operation itself only dominates one branch (due to + * being short-circuited) then it will only control blocks dominated by the + * true (for `&&`) or false (for `||`) branch. + */ + cached + predicate controls(IRBlock controlled, boolean testIsTrue) { + // This condition must determine the flow of control; that is, this + // node must be a top-level condition. + this.controlsBlock(controlled, testIsTrue) + or + exists(IRGuardCondition ne | + this = ne.(LogicalNotInstruction).getUnary() and + ne.controls(controlled, testIsTrue.booleanNot()) + ) + } + + cached + predicate controlsEdge(IRBlock pred, IRBlock succ, boolean testIsTrue) { + pred.getASuccessor() = succ and + controls(pred, testIsTrue) + or + hasBranchEdge(succ, testIsTrue) and + branch.getCondition() = this and + branch.getBlock() = pred + } + + /** + * Holds if `branch` jumps directly to `succ` when this condition is `testIsTrue`. + * + * This predicate is intended to help with situations in which an inference can only be made + * based on an edge between a block with multiple successors and a block with multiple + * predecessors. For example, in the following situation, an inference can be made about the + * value of `x` at the end of the `if` statement, but there is no block which is controlled by + * the `if` statement when `x >= y`. + * ``` + * if (x < y) { + * x = y; + * } + * return x; + * ``` + */ + private predicate hasBranchEdge(IRBlock succ, boolean testIsTrue) { + branch.getCondition() = this and + ( + testIsTrue = true and + succ.getFirstInstruction() = branch.getTrueSuccessor() + or + testIsTrue = false and + succ.getFirstInstruction() = branch.getFalseSuccessor() + ) + } + + /** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */ + cached + predicate comparesLt(Operand left, Operand right, int k, boolean isLessThan, boolean testIsTrue) { + compares_lt(this, left, right, k, isLessThan, testIsTrue) + } + + /** + * Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`. + * If `isLessThan = false` then this implies `left >= right + k`. + */ + cached + predicate ensuresLt(Operand left, Operand right, int k, IRBlock block, boolean isLessThan) { + exists(boolean testIsTrue | + compares_lt(this, left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue) + ) + } + + /** + * Holds if (determined by this guard) `left < right + k` must be `isLessThan` on the edge from + * `pred` to `succ`. If `isLessThan = false` then this implies `left >= right + k`. + */ + cached + predicate ensuresLtEdge( + Operand left, Operand right, int k, IRBlock pred, IRBlock succ, boolean isLessThan + ) { + exists(boolean testIsTrue | + compares_lt(this, left, right, k, isLessThan, testIsTrue) and + this.controlsEdge(pred, succ, testIsTrue) + ) + } + + /** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */ + cached + predicate comparesEq(Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue) { + compares_eq(this, left, right, k, areEqual, testIsTrue) + } + + /** + * Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`. + * If `areEqual = false` then this implies `left != right + k`. + */ + cached + predicate ensuresEq(Operand left, Operand right, int k, IRBlock block, boolean areEqual) { + exists(boolean testIsTrue | + compares_eq(this, left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue) + ) + } + + /** + * Holds if (determined by this guard) `left == right + k` must be `areEqual` on the edge from + * `pred` to `succ`. If `areEqual = false` then this implies `left != right + k`. + */ + cached + predicate ensuresEqEdge( + Operand left, Operand right, int k, IRBlock pred, IRBlock succ, boolean areEqual + ) { + exists(boolean testIsTrue | + compares_eq(this, left, right, k, areEqual, testIsTrue) and + this.controlsEdge(pred, succ, testIsTrue) + ) + } + + /** + * Holds if this condition controls `block`, meaning that `block` is only + * entered if the value of this condition is `testIsTrue`. This helper + * predicate does not necessarily hold for binary logical operations like + * `&&` and `||`. See the detailed explanation on predicate `controls`. + */ + private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) { + not isUnreachedBlock(controlled) and + exists(IRBlock branchBlock | branchBlock.getAnInstruction() = branch | + exists(IRBlock succ | + testIsTrue = true and succ.getFirstInstruction() = branch.getTrueSuccessor() + or + testIsTrue = false and succ.getFirstInstruction() = branch.getFalseSuccessor() + | + branch.getCondition() = this and + succ.dominates(controlled) and + forall(IRBlock pred | pred.getASuccessor() = succ | + pred = branchBlock or succ.dominates(pred) or not pred.isReachableFromFunctionEntry() + ) + ) + ) + } +} + +private ConditionalBranchInstruction get_branch_for_condition(Instruction guard) { + result.getCondition() = guard + or + exists(LogicalNotInstruction cond | + result = get_branch_for_condition(cond) and cond.getUnary() = guard + ) +} + +/** + * Holds if `left == right + k` is `areEqual` given that test is `testIsTrue`. + * + * Beware making mistaken logical implications here relating `areEqual` and `testIsTrue`. + */ +private predicate compares_eq( + Instruction test, Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue +) { + /* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */ + exists(boolean eq | simple_comparison_eq(test, left, right, k, eq) | + areEqual = true and testIsTrue = eq + or + areEqual = false and testIsTrue = eq.booleanNot() + ) + or + // I think this is handled by forwarding in controlsBlock. + //or + //logical_comparison_eq(test, left, right, k, areEqual, testIsTrue) + /* a == b + k => b == a - k */ + exists(int mk | k = -mk | compares_eq(test, right, left, mk, areEqual, testIsTrue)) + or + complex_eq(test, left, right, k, areEqual, testIsTrue) + or + /* (x is true => (left == right + k)) => (!x is false => (left == right + k)) */ + exists(boolean isFalse | testIsTrue = isFalse.booleanNot() | + compares_eq(test.(LogicalNotInstruction).getUnary(), left, right, k, areEqual, isFalse) + ) +} + +/** Rearrange various simple comparisons into `left == right + k` form. */ +private predicate simple_comparison_eq( + CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual +) { + left = cmp.getLeftOperand() and + cmp instanceof CompareEQInstruction and + right = cmp.getRightOperand() and + k = 0 and + areEqual = true + or + left = cmp.getLeftOperand() and + cmp instanceof CompareNEInstruction and + right = cmp.getRightOperand() and + k = 0 and + areEqual = false +} + +private predicate complex_eq( + CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue +) { + sub_eq(cmp, left, right, k, areEqual, testIsTrue) + or + add_eq(cmp, left, right, k, areEqual, testIsTrue) +} + +/* + * Simplification of inequality expressions + * Simplify conditions in the source to the canonical form l < r + k. + */ + +/** Holds if `left < right + k` evaluates to `isLt` given that test is `testIsTrue`. */ +private predicate compares_lt( + Instruction test, Operand left, Operand right, int k, boolean isLt, boolean testIsTrue +) { + /* In the simple case, the test is the comparison, so isLt = testIsTrue */ + simple_comparison_lt(test, left, right, k) and isLt = true and testIsTrue = true + or + simple_comparison_lt(test, left, right, k) and isLt = false and testIsTrue = false + or + complex_lt(test, left, right, k, isLt, testIsTrue) + or + /* (not (left < right + k)) => (left >= right + k) */ + exists(boolean isGe | isLt = isGe.booleanNot() | + compares_ge(test, left, right, k, isGe, testIsTrue) + ) + or + /* (x is true => (left < right + k)) => (!x is false => (left < right + k)) */ + exists(boolean isFalse | testIsTrue = isFalse.booleanNot() | + compares_lt(test.(LogicalNotInstruction).getUnary(), left, right, k, isLt, isFalse) + ) +} + +/** `(a < b + k) => (b > a - k) => (b >= a + (1-k))` */ +private predicate compares_ge( + Instruction test, Operand left, Operand right, int k, boolean isGe, boolean testIsTrue +) { + exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, testIsTrue)) +} + +/** Rearrange various simple comparisons into `left < right + k` form. */ +private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Operand right, int k) { + left = cmp.getLeftOperand() and + cmp instanceof CompareLTInstruction and + right = cmp.getRightOperand() and + k = 0 + or + left = cmp.getLeftOperand() and + cmp instanceof CompareLEInstruction and + right = cmp.getRightOperand() and + k = 1 + or + right = cmp.getLeftOperand() and + cmp instanceof CompareGTInstruction and + left = cmp.getRightOperand() and + k = 0 + or + right = cmp.getLeftOperand() and + cmp instanceof CompareGEInstruction and + left = cmp.getRightOperand() and + k = 1 +} + +private predicate complex_lt( + CompareInstruction cmp, Operand left, Operand right, int k, boolean isLt, boolean testIsTrue +) { + sub_lt(cmp, left, right, k, isLt, testIsTrue) + or + add_lt(cmp, left, right, k, isLt, testIsTrue) +} + +// left - x < right + c => left < right + (c+x) +// left < (right - x) + c => left < right + (c-x) +private predicate sub_lt( + CompareInstruction cmp, Operand left, Operand right, int k, boolean isLt, boolean testIsTrue +) { + exists(SubInstruction lhs, int c, int x | + compares_lt(cmp, lhs.getAUse(), right, c, isLt, testIsTrue) and + left = lhs.getLeftOperand() and + x = int_value(lhs.getRight()) and + k = c + x + ) + or + exists(SubInstruction rhs, int c, int x | + compares_lt(cmp, left, rhs.getAUse(), c, isLt, testIsTrue) and + right = rhs.getLeftOperand() and + x = int_value(rhs.getRight()) and + k = c - x + ) +} + +// left + x < right + c => left < right + (c-x) +// left < (right + x) + c => left < right + (c+x) +private predicate add_lt( + CompareInstruction cmp, Operand left, Operand right, int k, boolean isLt, boolean testIsTrue +) { + exists(AddInstruction lhs, int c, int x | + compares_lt(cmp, lhs.getAUse(), right, c, isLt, testIsTrue) and + ( + left = lhs.getLeftOperand() and x = int_value(lhs.getRight()) + or + left = lhs.getRightOperand() and x = int_value(lhs.getLeft()) + ) and + k = c - x + ) + or + exists(AddInstruction rhs, int c, int x | + compares_lt(cmp, left, rhs.getAUse(), c, isLt, testIsTrue) and + ( + right = rhs.getLeftOperand() and x = int_value(rhs.getRight()) + or + right = rhs.getRightOperand() and x = int_value(rhs.getLeft()) + ) and + k = c + x + ) +} + +// left - x == right + c => left == right + (c+x) +// left == (right - x) + c => left == right + (c-x) +private predicate sub_eq( + CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue +) { + exists(SubInstruction lhs, int c, int x | + compares_eq(cmp, lhs.getAUse(), right, c, areEqual, testIsTrue) and + left = lhs.getLeftOperand() and + x = int_value(lhs.getRight()) and + k = c + x + ) + or + exists(SubInstruction rhs, int c, int x | + compares_eq(cmp, left, rhs.getAUse(), c, areEqual, testIsTrue) and + right = rhs.getLeftOperand() and + x = int_value(rhs.getRight()) and + k = c - x + ) +} + +// left + x == right + c => left == right + (c-x) +// left == (right + x) + c => left == right + (c+x) +private predicate add_eq( + CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue +) { + exists(AddInstruction lhs, int c, int x | + compares_eq(cmp, lhs.getAUse(), right, c, areEqual, testIsTrue) and + ( + left = lhs.getLeftOperand() and x = int_value(lhs.getRight()) + or + left = lhs.getRightOperand() and x = int_value(lhs.getLeft()) + ) and + k = c - x + ) + or + exists(AddInstruction rhs, int c, int x | + compares_eq(cmp, left, rhs.getAUse(), c, areEqual, testIsTrue) and + ( + right = rhs.getLeftOperand() and x = int_value(rhs.getRight()) + or + right = rhs.getRightOperand() and x = int_value(rhs.getLeft()) + ) and + k = c + x + ) +} + +/** The int value of integer constant expression. */ +private int int_value(Instruction i) { result = i.(IntegerConstantInstruction).getValue().toInt() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll index fe0e211087c..8cde0baddfc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll @@ -1,6 +1,6 @@ -import cpp -private import semmle.code.cpp.ir.IR -private import semmle.code.cpp.ir.ValueNumbering +import csharp +private import semmle.code.csharp.ir.IR +private import semmle.code.csharp.ir.ValueNumbering private newtype TBound = TBoundZero() or @@ -57,7 +57,7 @@ class ZeroBound extends Bound, TBoundZero { result.(ConstantValueInstruction).getValue().toInt() = delta } - override Location getLocation() { result instanceof UnknownDefaultLocation } + override Location getLocation() { result instanceof EmptyLocation } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll index 50fe6ab9a55..81c5dc0ec33 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll @@ -67,10 +67,10 @@ * back-edge as a precise bound might require traversing a loop once). */ -import cpp -private import semmle.code.cpp.ir.IR -private import semmle.code.cpp.controlflow.IRGuards -private import semmle.code.cpp.ir.ValueNumbering +import csharp +private import semmle.code.csharp.ir.IR +private import semmle.code.csharp.ir.internal.IRGuards +private import semmle.code.csharp.ir.ValueNumbering private import RangeUtils private import SignAnalysis import Bound @@ -205,18 +205,18 @@ pragma[inline] private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { fromtyp.getSize() < totyp.getSize() and ( - fromtyp.isUnsigned() + fromtyp instanceof UnsignedIntegralType or - totyp.isSigned() + totyp instanceof SignedIntegralType ) or fromtyp.getSize() <= totyp.getSize() and ( - fromtyp.isSigned() and - totyp.isSigned() + fromtyp instanceof SignedIntegralType and + totyp instanceof SignedIntegralType or - fromtyp.isUnsigned() and - totyp.isUnsigned() + fromtyp instanceof UnsignedIntegralType and + totyp instanceof UnsignedIntegralType ) } @@ -233,13 +233,19 @@ private class SafeCastInstruction extends ConvertInstruction { * Holds if `typ` is a small integral type with the given lower and upper bounds. */ private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { - typ.isSigned() and typ.getSize() = 1 and lowerbound = -128 and upperbound = 127 + typ instanceof SignedIntegralType and typ.getSize() = 1 and lowerbound = -128 and upperbound = 127 or - typ.isUnsigned() and typ.getSize() = 1 and lowerbound = 0 and upperbound = 255 + typ instanceof UnsignedIntegralType and typ.getSize() = 1 and lowerbound = 0 and upperbound = 255 or - typ.isSigned() and typ.getSize() = 2 and lowerbound = -32768 and upperbound = 32767 + typ instanceof SignedIntegralType and + typ.getSize() = 2 and + lowerbound = -32768 and + upperbound = 32767 or - typ.isUnsigned() and typ.getSize() = 2 and lowerbound = 0 and upperbound = 65535 + typ instanceof UnsignedIntegralType and + typ.getSize() = 2 and + lowerbound = 0 and + upperbound = 65535 } /** @@ -609,4 +615,15 @@ private predicate boundedInstruction( safeNarrowingCast(cast, upper.booleanNot()) and boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason) ) + or + exists(PropertyAccess pa | + i.(CallInstruction).getAST() = pa and + pa.getProperty().getName() = "Length" and + b instanceof ZeroBound and + delta = origdelta and + (upper = true or upper = false) and + fromBackEdge = false and + delta = getArrayDim(pa.getQualifier().(VariableAccess).getTarget()) and + reason = TNoReason() + ) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll index 52782bcda30..b2f912dabfd 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll @@ -1,7 +1,7 @@ -import cpp -private import semmle.code.cpp.ir.IR +import csharp +private import semmle.code.csharp.ir.IR // TODO: move this dependency -import semmle.code.cpp.ir.internal.IntegerConstant +import semmle.code.csharp.ir.internal.IntegerConstant // TODO: move this out of test code language[monotonicAggregates] @@ -40,6 +40,13 @@ IntValue getConstantValue(Instruction instr) { ) } +IntValue getArrayDim(Variable arr) { + exists(ArrayCreation ac | + arr.getInitializer() = ac and + result = ac.getInitializer().getNumberOfElements() + ) +} + predicate valueFlowStep(Instruction i, Operand op, int delta) { i.(CopyInstruction).getSourceValueOperand() = op and delta = 0 or diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll index ca641f826ef..1cba4d7e732 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll @@ -6,10 +6,10 @@ * three-valued domain `{negative, zero, positive}`. */ -import cpp -private import semmle.code.cpp.ir.IR -private import semmle.code.cpp.controlflow.IRGuards -private import semmle.code.cpp.ir.ValueNumbering +import csharp +private import semmle.code.csharp.ir.IR +private import semmle.code.csharp.ir.internal.IRGuards +private import semmle.code.csharp.ir.ValueNumbering private import SignAnalysisCached private newtype TSign = @@ -471,7 +471,7 @@ module SignAnalysisCached { not exists(certainInstructionSign(i)) and not ( result = TNeg() and - i.getResultType().(IntegralType).isUnsigned() + i.getResultType() instanceof UnsignedIntegralType ) and ( unknownSign(i) @@ -479,9 +479,13 @@ module SignAnalysisCached { exists(ConvertInstruction ci, Instruction prior, boolean fromSigned, boolean toSigned | i = ci and prior = ci.getUnary() and - (if ci.getResultType().(IntegralType).isSigned() then toSigned = true else toSigned = false) and ( - if prior.getResultType().(IntegralType).isSigned() + if ci.getResultType() instanceof SignedIntegralType + then toSigned = true + else toSigned = false + ) and + ( + if prior.getResultType() instanceof SignedIntegralType then fromSigned = true else fromSigned = false ) and @@ -514,11 +518,11 @@ module SignAnalysisCached { i instanceof ShiftLeftInstruction and result = s1.lshift(s2) or i instanceof ShiftRightInstruction and - i.getResultType().(IntegralType).isSigned() and + i.getResultType().(IntegralType) instanceof SignedIntegralType and result = s1.rshift(s2) or i instanceof ShiftRightInstruction and - not i.getResultType().(IntegralType).isSigned() and + not i.getResultType().(IntegralType) instanceof SignedIntegralType and result = s1.urshift(s2) ) or From 3f4713f0f5fee44da0d690d8757a6be27eff3c33 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Fri, 20 Sep 2019 16:52:52 +0100 Subject: [PATCH 0220/1227] Add tests and query --- .../ir/offbyone/OffByOneRA.expected | 7 ++ .../library-tests/ir/offbyone/OffByOneRA.ql | 65 +++++++++++ .../library-tests/ir/offbyone/buildSnap.qlref | 1 + .../ql/test/library-tests/ir/offbyone/null.cs | 5 + .../ql/test/library-tests/ir/offbyone/test.cs | 104 ++++++++++++++++++ .../ir/rangeanalysis/RangeAnalysis.expected | 18 +++ .../ir/rangeanalysis/RangeAnalysis.ql | 26 +++++ .../library-tests/ir/rangeanalysis/null.cs | 5 + .../library-tests/ir/rangeanalysis/test.cs | 78 +++++++++++++ 9 files changed, 309 insertions(+) create mode 100644 csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected create mode 100644 csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql create mode 100644 csharp/ql/test/library-tests/ir/offbyone/buildSnap.qlref create mode 100644 csharp/ql/test/library-tests/ir/offbyone/null.cs create mode 100644 csharp/ql/test/library-tests/ir/offbyone/test.cs create mode 100644 csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected create mode 100644 csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql create mode 100644 csharp/ql/test/library-tests/ir/rangeanalysis/null.cs create mode 100644 csharp/ql/test/library-tests/ir/rangeanalysis/test.cs diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected new file mode 100644 index 00000000000..9b8d568e64d --- /dev/null +++ b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected @@ -0,0 +1,7 @@ +| test.cs:10:17:10:21 | test1 | test.cs:17:41:17:51 | access to array element | This array access is ok, the index is at most the lenth of the array + -1 | +| test.cs:21:17:21:21 | test2 | test.cs:33:41:33:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | +| test.cs:37:17:37:21 | test3 | test.cs:50:41:50:51 | access to array element | This array access is ok, the index is at most the lenth of the array + -1 | +| test.cs:54:17:54:21 | test4 | test.cs:64:41:64:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | +| test.cs:68:17:68:21 | test5 | test.cs:74:22:74:27 | access to indexer | This array access might be out of bounds, as the index might be equal to the array length | +| test.cs:78:17:78:21 | test6 | test.cs:87:41:87:55 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | +| test.cs:91:17:91:21 | test7 | test.cs:101:41:101:50 | access to array element | This array access might be out of bounds, as the index might be equal to the array length + 1 | diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql new file mode 100644 index 00000000000..7271996557a --- /dev/null +++ b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql @@ -0,0 +1,65 @@ +import csharp +import semmle.code.csharp.ir.IR +import semmle.code.csharp.ir.rangeanalysis.RangeAnalysis + +/** + * Holds if the index expression of `aa` is less than or equal to the array length plus `k`. + */ +predicate boundedArrayAccess(ElementAccess aa, int k) { + exists(Instruction index, Instruction usage, Bound b, int delta | + ( + // indexer access + usage.(CallInstruction).getAST() = aa + or + // array access + usage.(PointerAddInstruction).getAST() = aa + ) and + usage.getAnOperand().getDef() = index and + boundedInstruction(index, b, delta, true, _) + | + exists(PropertyAccess pa | + k = delta and + b.getInstruction().getAST() = pa and + pa.getProperty().getName() = "Length" and + pa.(QualifiableExpr).getQualifier().(VariableAccess).getTarget() = aa + .getQualifier() + .(VariableAccess) + .getTarget() + ) + or + exists(ArrayCreation ac | + ac.getParent().(LocalVariableDeclExpr).getVariable() = aa + .getQualifier() + .(VariableAccess) + .getTarget() and + b instanceof ZeroBound and + if exists(ac.getLengthArgument(0)) + then k = delta - ac.getLengthArgument(0).getValue().toInt() + else + if exists(ac.getInitializer()) + then k = delta - ac.getInitializer().getNumberOfElements() + else none() + ) + ) +} + +/** + * Holds if the index expression is less than or equal to the array length plus `k`, + * but not necessarily less than or equal to the array length plus `k-1`. + */ +predicate bestArrayAccessBound(ElementAccess aa, int k) { + k = min(int k0 | boundedArrayAccess(aa, k0)) +} + +from ElementAccess aa, int k, string msg, string add +where + bestArrayAccessBound(aa, k) and + (if k = 0 then add = "" else add = " + " + k) and + ( + if k >= 0 + then + msg = "This array access might be out of bounds, as the index might be equal to the array length" + + add + else msg = "This array access is ok, the index is at most the lenth of the array " + add + ) +select aa.getEnclosingCallable(), aa, msg diff --git a/csharp/ql/test/library-tests/ir/offbyone/buildSnap.qlref b/csharp/ql/test/library-tests/ir/offbyone/buildSnap.qlref new file mode 100644 index 00000000000..637dac3c9b8 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/offbyone/buildSnap.qlref @@ -0,0 +1 @@ +Likely Bugs/Collections/ContainerLengthCmpOffByOne.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/offbyone/null.cs b/csharp/ql/test/library-tests/ir/offbyone/null.cs new file mode 100644 index 00000000000..a1d7adf1511 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/offbyone/null.cs @@ -0,0 +1,5 @@ +class Null { + public static void Main() { + object o = null; + } +} diff --git a/csharp/ql/test/library-tests/ir/offbyone/test.cs b/csharp/ql/test/library-tests/ir/offbyone/test.cs new file mode 100644 index 00000000000..7315a84820f --- /dev/null +++ b/csharp/ql/test/library-tests/ir/offbyone/test.cs @@ -0,0 +1,104 @@ +class ContainerLengthOffByOne +{ + public int[] arr; + public string str; + + public static void fun(int elem) + { + } + + public void test1() + { + int len1 = this.arr.Length; + int len2 = len1 + 1; + // OK + for(int i = 0; i < len2 - 1; i++) + { + ContainerLengthOffByOne.fun(this.arr[i]); + } + } + + public void test2() { + int len1 = this.arr.Length; + + int len2; + if (len1 % 2 == 0) + len2 = len1 + 1; + else + len2 = len1; + // Not OK, PHI node where the upper bound + // exceeds the size of the array. + for(int i = 0; i < len2; i++) + { + ContainerLengthOffByOne.fun(this.arr[i]); + } + } + + public void test3() { + int len1 = this.arr.Length; + int len2 = len1 - 1; + + int len3; + if (len2 % 2 == 0) + len3 = len2 + 1; + else + len3 = len2; + // OK, PHI node has bounds that ensure + // we don't get an off by one error. + for(int i = 0; i < len3; i++) + { + ContainerLengthOffByOne.fun(this.arr[i]); + } + } + + public void test4() { + int len1 = this.arr.Length; + + int len2 = len1 + 1; + int len3 = len2 - 1; + int len4 = len3 + 2; + int len5 = len4 - 1; + // Not OK, len5 is off by one. + for(int i = 0; i < len5; i++) + { + ContainerLengthOffByOne.fun(this.arr[i]); + } + } + + public void test5() + { + int len = this.str.Length; + // Not OK; test for indexers + for (int i = 0; i <= len; i++) + { + char c = str[i]; + } + } + + public void test6() + { + int len = this.arr.Length - 2; + int len1 = len + 3; + int len2 = len1 - 1; + // Not OK, of by one + // The test shows that more complex expressions are treated correctly + for (int i = 0; i < len2; i++) + { + ContainerLengthOffByOne.fun(this.arr[i + 1]); + } + } + + public void test7() + { + int[] arrInit = { 1, 2, 3 }; + int len = (arrInit.Length * 2 + 2) / 2 * 2; + int len1 = len / 2 - 3 + 4; + // Not OK, len1 == this.arrInit + 1 + // This test shows that array initializer's length + // are used in bounds + for (int i = 0; i < len1; i++) + { + ContainerLengthOffByOne.fun(arrInit[i]); + } + } +} diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected new file mode 100644 index 00000000000..36ffe7efbba --- /dev/null +++ b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected @@ -0,0 +1,18 @@ +| test.cs:19:12:19:12 | Store: access to parameter x | test.cs:15:24:15:24 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:19:12:19:12 | Store: access to parameter x | test.cs:15:31:15:31 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cs:16:9:16:13 | test.cs:16:9:16:13 | +| test.cs:19:12:19:12 | Store: access to parameter x | test.cs:15:31:15:31 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:29:12:29:12 | Store: access to parameter x | test.cs:23:24:23:24 | InitializeParameter: x | -2 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:29:12:29:12 | Store: access to parameter x | test.cs:23:31:23:31 | InitializeParameter: y | -2 | false | CompareLT: ... < ... | test.cs:24:9:24:13 | test.cs:24:9:24:13 | +| test.cs:36:12:36:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:36:12:36:12 | Load: access to local variable i | test.cs:33:25:33:25 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cs:35:20:35:24 | test.cs:35:20:35:24 | +| test.cs:39:12:39:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 1 | false | CompareGT: ... > ... | test.cs:38:20:38:24 | test.cs:38:20:38:24 | +| test.cs:39:12:39:12 | Load: access to local variable i | test.cs:33:25:33:25 | InitializeParameter: x | 0 | true | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:39:12:39:12 | Load: access to local variable i | test.cs:35:20:35:20 | Phi: access to local variable i | 0 | true | CompareLT: ... < ... | test.cs:35:20:35:24 | test.cs:35:20:35:24 | +| test.cs:42:12:42:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:42:12:42:12 | Load: access to local variable i | test.cs:33:25:33:25 | InitializeParameter: x | 1 | true | CompareLT: ... < ... | test.cs:41:20:41:28 | test.cs:41:20:41:28 | +| test.cs:42:12:42:12 | Load: access to local variable i | test.cs:35:20:35:20 | Phi: access to local variable i | 1 | true | CompareLT: ... < ... | test.cs:41:20:41:28 | test.cs:41:20:41:28 | +| test.cs:42:12:42:12 | Load: access to local variable i | test.cs:38:20:38:20 | Phi: access to local variable i | 0 | false | CompareGT: ... > ... | test.cs:38:20:38:24 | test.cs:38:20:38:24 | +| test.cs:49:13:49:17 | Load: access to parameter begin | test.cs:47:33:47:37 | InitializeParameter: begin | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:58:14:58:14 | Load: access to parameter x | test.cs:55:32:55:32 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cs:57:11:57:15 | test.cs:57:11:57:15 | +| test.cs:58:14:58:14 | Load: access to parameter x | test.cs:55:39:55:39 | InitializeParameter: z | -2 | true | CompareLT: ... < ... | test.cs:57:11:57:15 | test.cs:57:11:57:15 | +| test.cs:63:14:63:14 | Load: access to parameter x | test.cs:55:32:55:32 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cs:61:9:61:13 | test.cs:61:9:61:13 | diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql new file mode 100644 index 00000000000..4b1f324d40c --- /dev/null +++ b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql @@ -0,0 +1,26 @@ +import semmle.code.csharp.ir.rangeanalysis.RangeAnalysis +import semmle.code.csharp.ir.IR +import semmle.code.csharp.ir.internal.IRGuards +import semmle.code.csharp.ir.ValueNumbering + +query predicate instructionBounds( + Instruction i, Bound b, int delta, boolean upper, Reason reason, Location reasonLoc +) { + ( + i.getAUse() instanceof ArgumentOperand + or + exists(ReturnValueInstruction retInstr | retInstr.getReturnValueOperand() = i.getAUse()) + ) and + ( + upper = true and + delta = min(int d | boundedInstruction(i, b, d, upper, reason)) + or + upper = false and + delta = max(int d | boundedInstruction(i, b, d, upper, reason)) + ) and + not valueNumber(b.getInstruction()) = valueNumber(i) and + if reason instanceof CondReason + then reasonLoc = reason.(CondReason).getCond().getLocation() + else reasonLoc instanceof EmptyLocation +} + diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/null.cs b/csharp/ql/test/library-tests/ir/rangeanalysis/null.cs new file mode 100644 index 00000000000..a1d7adf1511 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/rangeanalysis/null.cs @@ -0,0 +1,5 @@ +class Null { + public static void Main() { + object o = null; + } +} diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/test.cs b/csharp/ql/test/library-tests/ir/rangeanalysis/test.cs new file mode 100644 index 00000000000..221312b1449 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/rangeanalysis/test.cs @@ -0,0 +1,78 @@ +class RangeAnalysis { + static void sink(int val) { + + } + + static unsafe void sinkp(int* p) { + + } + + static int source() { + return 0; + } + + // Guards, inference, critical edges + static int test1(int x, int y) { + if (x < y) { + x = y; + } + return x; + } + + // Bounds mergers at phi nodes + static int test2(int x, int y) { + if (x < y) { + x = y; + } else { + x = x-2; + } + return x; + } + + // for loops + static void test3(int x) { + int y = x; + for(int i = 0; i < x; i++) { + sink(i); + } + for(int i = y; i > 0; i--) { + sink(i); + } + for(int i = 0; i < y + 2; i++) { + sink(i); + } + } + + // pointer bounds + unsafe static void test4(int *begin, int *end) { + while (begin < end) { + sinkp(begin); + begin++; + } + } + + // bound propagation through conditionals + static void test5(int x, int y, int z) { + if (y < z) { + if (x < y) { + sink(x); + } + } + if (x < y) { + if (y < z) { + sink(x); // x < z is not inferred here + } + } + } + + unsafe static void addone(int[] arr) + { + int length = arr.Length; + fixed (int* b = arr) + { + int *p = b; + for(int i = 0; i <= length; i++) + *p++ += 1; + } + } +} From f870b21d2f8eaf095131aae2cd7ce70574b17e14 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 24 Sep 2019 16:25:56 +0200 Subject: [PATCH 0221/1227] Python: Use Builtin::special for floats ClassValue We could find no reason for using `Builtin::builtin` instead of `Builtin::special`. Since all the other base types use `special`, and the old Object API is using `special`, let's also do that :) --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 9dcd2bdd824..35392f456df 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -572,7 +572,7 @@ module ClassValue { /** Get the `ClassValue` for the `float` class. */ ClassValue float_() { - result = TBuiltinClassObject(Builtin::builtin("float")) + result = TBuiltinClassObject(Builtin::special("float")) } /** Get the `ClassValue` for the `bytes` class (also called `str` in Python 2). */ From 752615fb5641ffc3fcfde010bb6eb59bcb6dc7fa Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 24 Sep 2019 16:54:35 +0200 Subject: [PATCH 0222/1227] Python: Fix doc for Expr::isDeletion --- python/ql/src/semmle/python/Exprs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/Exprs.qll b/python/ql/src/semmle/python/Exprs.qll index c6e608830be..264bc826150 100644 --- a/python/ql/src/semmle/python/Exprs.qll +++ b/python/ql/src/semmle/python/Exprs.qll @@ -671,7 +671,7 @@ class Name extends Name_ { v = this.getVariable() } - /** Whether this expression is a definition */ + /** Whether this expression is a deletion */ predicate isDeletion() { py_expr_contexts(_, 2, this) } From d6e4a2afef24ec6b289bca9666ff45edf51ce075 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Tue, 24 Sep 2019 10:47:16 +0100 Subject: [PATCH 0223/1227] Autoformat --- .../src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll | 2 +- csharp/ql/test/library-tests/ir/offbyone/buildSnap.qlref | 1 - csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) delete mode 100644 csharp/ql/test/library-tests/ir/offbyone/buildSnap.qlref diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll index 81c5dc0ec33..35cb6900c1c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll @@ -616,7 +616,7 @@ private predicate boundedInstruction( boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason) ) or - exists(PropertyAccess pa | + exists(PropertyAccess pa | i.(CallInstruction).getAST() = pa and pa.getProperty().getName() = "Length" and b instanceof ZeroBound and diff --git a/csharp/ql/test/library-tests/ir/offbyone/buildSnap.qlref b/csharp/ql/test/library-tests/ir/offbyone/buildSnap.qlref deleted file mode 100644 index 637dac3c9b8..00000000000 --- a/csharp/ql/test/library-tests/ir/offbyone/buildSnap.qlref +++ /dev/null @@ -1 +0,0 @@ -Likely Bugs/Collections/ContainerLengthCmpOffByOne.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql index 4b1f324d40c..0eed018495a 100644 --- a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql +++ b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql @@ -4,7 +4,7 @@ import semmle.code.csharp.ir.internal.IRGuards import semmle.code.csharp.ir.ValueNumbering query predicate instructionBounds( - Instruction i, Bound b, int delta, boolean upper, Reason reason, Location reasonLoc + Instruction i, Bound b, int delta, boolean upper, Reason reason, Location reasonLoc ) { ( i.getAUse() instanceof ArgumentOperand @@ -23,4 +23,3 @@ query predicate instructionBounds( then reasonLoc = reason.(CondReason).getCond().getLocation() else reasonLoc instanceof EmptyLocation } - From 344169610078f251ff3fccee3d951c9a3d09e5ec Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Tue, 24 Sep 2019 17:28:14 +0100 Subject: [PATCH 0224/1227] Apply suggestions from code review --- .../learn-ql/ql-etudes/river-crossing-1.ql | 32 +++++++------ .../learn-ql/ql-etudes/river-crossing.ql | 39 +++++++++------- .../learn-ql/ql-etudes/river-crossing.rst | 45 ++++++++++--------- 3 files changed, 67 insertions(+), 49 deletions(-) diff --git a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql index ae218f37e82..c0b95918d7c 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql +++ b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql @@ -32,34 +32,40 @@ class Shore extends string { /** A record of where everything is. */ class State extends string { - Shore man; + Shore manShore; - Shore goat; + Shore goatShore; - Shore cabbage; + Shore cabbageShore; - Shore wolf; + Shore wolfShore; - State() { this = man + "," + goat + "," + cabbage + "," + wolf } + State() { this = manShore + "," + goatShore + "," + cabbageShore + "," + wolfShore } State ferry(Cargo cargo) { - cargo = "Nothing" and result = man.other() + "," + goat + "," + cabbage + "," + wolf + cargo = "Nothing" and + result = manShore.other() + "," + goatShore + "," + cabbageShore + "," + wolfShore or - cargo = "Goat" and result = man.other() + "," + goat.other() + "," + cabbage + "," + wolf + cargo = "Goat" and + result = manShore.other() + "," + goatShore.other() + "," + cabbageShore + "," + wolfShore or - cargo = "Cabbage" and result = man.other() + "," + goat + "," + cabbage.other() + "," + wolf + cargo = "Cabbage" and + result = manShore.other() + "," + goatShore + "," + cabbageShore.other() + "," + wolfShore or - cargo = "Wolf" and result = man.other() + "," + goat + "," + cabbage + "," + wolf.other() + cargo = "Wolf" and + result = manShore.other() + "," + goatShore + "," + cabbageShore + "," + wolfShore.other() } /** - * Holds if predator and prey are on the same shore and the man - * is not present. + * Holds if eating occurs. This happens when predator and prey are on the same shore + * and the man is not present. */ - predicate eats(Shore predator, Shore prey) { predator = prey and man != predator } + predicate eating(Shore predatorShore, Shore preyShore) { + predatorShore = preyShore and manShore != predatorShore + } /** Holds if nothing gets eaten in this state. */ - predicate isSafe() { not (eats(goat, cabbage) or eats(wolf, goat)) } + predicate isSafe() { not (eating(goatShore, cabbageShore) or eating(wolfShore, goatShore)) } /** Returns the state that is reached after safely ferrying a cargo item. */ State safeFerry(Cargo cargo) { result = this.ferry(cargo) and result.isSafe() } diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.ql b/docs/language/learn-ql/ql-etudes/river-crossing.ql index 5a21adc90ee..58a3ada6ab1 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.ql +++ b/docs/language/learn-ql/ql-etudes/river-crossing.ql @@ -1,4 +1,4 @@ -/** +/** * @name River crossing puzzle * @description This implements the classical puzzle where a man is trying to * ferry a goat, a cabbage, and a wolf across a river. @@ -38,41 +38,47 @@ class Shore extends string { } /** Renders the state as a string. */ -string renderState(Shore man, Shore goat, Shore cabbage, Shore wolf) { - result = man + "," + goat + "," + cabbage + "," + wolf +string renderState(Shore manShore, Shore goatShore, Shore cabbageShore, Shore wolfShore) { + result = manShore + "," + goatShore + "," + cabbageShore + "," + wolfShore } /** A record of where everything is. */ class State extends string { - Shore man; + Shore manShore; - Shore goat; + Shore goatShore; - Shore cabbage; + Shore cabbageShore; - Shore wolf; + Shore wolfShore; - State() { this = renderState(man, goat, cabbage, wolf) } + State() { this = renderState(manShore, goatShore, cabbageShore, wolfShore) } /** Returns the state that is reached after ferrying a particular cargo item. */ State ferry(Cargo cargo) { - cargo = "Nothing" and result = renderState(man.other(), goat, cabbage, wolf) + cargo = "Nothing" and + result = renderState(manShore.other(), goatShore, cabbageShore, wolfShore) or - cargo = "Goat" and result = renderState(man.other(), goat.other(), cabbage, wolf) + cargo = "Goat" and + result = renderState(manShore.other(), goatShore.other(), cabbageShore, wolfShore) or - cargo = "Cabbage" and result = renderState(man.other(), goat, cabbage.other(), wolf) + cargo = "Cabbage" and + result = renderState(manShore.other(), goatShore, cabbageShore.other(), wolfShore) or - cargo = "Wolf" and result = renderState(man.other(), goat, cabbage, wolf.other()) + cargo = "Wolf" and + result = renderState(manShore.other(), goatShore, cabbageShore, wolfShore.other()) } /** - * Holds if predator and prey are on the same shore and the man - * is not present. + * Holds if eating occurs. This happens when predator and prey are on the same shore + * and the man is not present. */ - predicate eats(Shore predator, Shore prey) { predator = prey and man != predator } + predicate eating(Shore predatorShore, Shore preyShore) { + predatorShore = preyShore and manShore != predatorShore + } /** Holds if nothing gets eaten in this state. */ - predicate isSafe() { not (eats(goat, cabbage) or eats(wolf, goat)) } + predicate isSafe() { not (eating(goatShore, cabbageShore) or eating(wolfShore, goatShore)) } /** Returns the state that is reached after safely ferrying a cargo item. */ State safeFerry(Cargo cargo) { result = this.ferry(cargo) and result.isSafe() } @@ -112,3 +118,4 @@ class GoalState extends State { from string path where any(InitialState i).reachesVia(path, _) = any(GoalState g) select path + diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.rst b/docs/language/learn-ql/ql-etudes/river-crossing.rst index e5fce99b98e..1b5b1883739 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.rst +++ b/docs/language/learn-ql/ql-etudes/river-crossing.rst @@ -47,7 +47,8 @@ a piece of cargo. Second, any item can be on one of two shores. Let's call these the "left shore" and the "right shore". Define a class ``Shore`` containing ``"Left"`` and ``"Right"``. -It would be helpful to express "the other shore". You can do this by defining a member predicate +It would be helpful to express "the other shore" to model moving from one side of the river to the other. +You can do this by defining a member predicate ``other`` in the class ``Shore`` such that ``"Left".other()`` returns ``"Right"`` and vice versa. .. container:: toggle @@ -59,8 +60,8 @@ It would be helpful to express "the other shore". You can do this by defining a .. literalinclude:: river-crossing.ql :lines: 25-38 -We also want a way to keep track of where the man, the goat, the cabbage, and the wolf are—call this combined -information the "state". Define a class ``State`` that encodes this information. +We also want a way to keep track of where the man, the goat, the cabbage, and the wolf are at any point. We can call this combined +information the "state". Define a class ``State`` that encodes the location of each piece of cargo. For example, if the man is on the left shore, the goat on the right shore, and the cabbage and wolf on the left shore, the state should be ``Left, Right, Left, Left``. @@ -74,9 +75,10 @@ temporary variables in the body of a class are called `fields `__ +One way to restrict our paths to a finite number of river crossings is to define a +`member predicate `__ ``State reachesVia(string path, int steps)``. The result of this predicate is any state that is reachable from the current state (``this``) via the given path in a specified finite number of steps. @@ -176,10 +180,11 @@ for example ``steps <= 7``. *Show/hide code* .. literalinclude:: river-crossing-1.ql - :lines: 67-83 + :lines: 73-89 However, although this ensures that the solution is finite, it can still contain loops if the upper bound -for ``steps`` is large. +for ``steps`` is large. In other words, you could get an inefficient solution by revisiting the same state +multiple times. Instead of picking an arbitrary upper bound for the number of steps, you can avoid counting steps altogether. If you keep track of states that have already been visited and ensure @@ -205,7 +210,7 @@ the given path without revisiting any previously visited states. *Show/hide code* .. literalinclude:: river-crossing.ql - :lines: 80-99 + :lines: 86-105 Display the results ~~~~~~~~~~~~~~~~~~~ @@ -220,7 +225,7 @@ that returns the resulting path. *Show/hide code* .. literalinclude:: river-crossing.ql - :lines: 112-114 + :lines: 118-120 For now, the path defined in the above predicate ``reachesVia`` just lists the order of cargo items to ferry. You could tweak the predicates and the select clause to make the solution clearer. Here are some suggestions: @@ -240,5 +245,5 @@ Here are some more example QL queries that solve the river crossing puzzle: - Solutions described in more detail: https://lgtm.com/query/4550752404102766320/ - Solutions displayed in a more visual way: https://lgtm.com/query/5824364611285694673/ -.. TODO: Add more examples +.. TODO: Add more examples + check that the queries are "tidied up" and clear. From 7e14e2a950752d0e214e92ae0a277d1589d26b77 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Tue, 24 Sep 2019 17:52:34 -0700 Subject: [PATCH 0225/1227] [zlaski/what-buffer-function] Rename references to `BufferFunction` to `ArrayFunction`. --- .../src/semmle/code/cpp/models/interfaces/ArrayFunction.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/ArrayFunction.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/ArrayFunction.qll index 59b96d7eddf..5d63b0a9196 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/ArrayFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/ArrayFunction.qll @@ -1,9 +1,9 @@ /** * Provides an abstract class for accurate modeling of input and output buffers * in library functions when source code is not available. To use this QL - * library, create a QL class extending `BufferFunction` with a characteristic + * library, create a QL class extending `ArrayFunction` with a characteristic * predicate that selects the function or set of functions you are trying to - * model. Within that class, override the predicates provided by `BufferFunction` + * model. Within that class, override the predicates provided by `ArrayFunction` * to match the flow within that function. Finally, add a private import * statement to `CustomModels.qll` */ From a6d619cfe1f44f3d89808c58041d1fd0ba5adc6d Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Tue, 24 Sep 2019 18:17:34 -0700 Subject: [PATCH 0226/1227] [zlaski/what-buffer-function] Rename `CustomModels` to `Models` --- cpp/ql/src/semmle/code/cpp/models/interfaces/ArrayFunction.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/ArrayFunction.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/ArrayFunction.qll index 5d63b0a9196..cb4c531ebec 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/ArrayFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/ArrayFunction.qll @@ -5,7 +5,7 @@ * predicate that selects the function or set of functions you are trying to * model. Within that class, override the predicates provided by `ArrayFunction` * to match the flow within that function. Finally, add a private import - * statement to `CustomModels.qll` + * statement to `Models.qll` */ import semmle.code.cpp.Function From 0aafa0b0e23f94921b2b699d8b76b7549aad14b7 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 25 Sep 2019 08:55:55 +0200 Subject: [PATCH 0227/1227] C++: Accept test changes in IR sanity queries These looks harmless. --- .../library-tests/syntax-zoo/aliased_ssa_sanity.expected | 2 +- cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected | 7 ++++--- .../library-tests/syntax-zoo/unaliased_ssa_sanity.expected | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index 5e76fb042be..0891f1e0b6c 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -20,7 +20,7 @@ instructionWithoutSuccessor | ms_try_mix.cpp:11:12:11:15 | Chi: call to C | | ms_try_mix.cpp:28:12:28:15 | Chi: call to C | | ms_try_mix.cpp:48:10:48:13 | Chi: call to C | -| pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} | +| pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} | | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | | vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index b9c4bd7eba5..e3e241f35e8 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -7,7 +7,7 @@ missingOperand | misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | -| pointer_to_member.cpp:35:13:35:19 | FieldAddress: x1 | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() | +| pointer_to_member.cpp:36:13:36:19 | FieldAddress: x1 | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() | | range_analysis.c:368:10:368:21 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) | | range_analysis.c:369:10:369:36 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) | | range_analysis.c:370:10:370:38 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) | @@ -66,7 +66,7 @@ instructionWithoutSuccessor | ms_try_mix.cpp:48:10:48:13 | CallSideEffect: call to C | | ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... | | ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } | -| pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} | +| pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} | | static_init_templates.cpp:80:27:80:36 | Convert: (void *)... | | static_init_templates.cpp:80:27:80:36 | Convert: (void *)... | | static_init_templates.cpp:89:27:89:36 | Convert: (void *)... | @@ -673,7 +673,8 @@ useNotDominatedByDefinition | ms_try_mix.cpp:38:16:38:19 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | ms_try_mix.cpp:27:6:27:19 | IR: ms_finally_mix | void ms_finally_mix(int) | | ms_try_mix.cpp:41:12:41:15 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | ms_try_mix.cpp:27:6:27:19 | IR: ms_finally_mix | void ms_finally_mix(int) | | ms_try_mix.cpp:51:5:51:11 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | ms_try_mix.cpp:47:6:47:28 | IR: ms_empty_finally_at_end | void ms_empty_finally_at_end() | -| pointer_to_member.cpp:35:13:35:19 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() | +| pointer_to_member.cpp:36:11:36:30 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() | +| pointer_to_member.cpp:36:13:36:19 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | pointer_to_member.cpp:32:6:32:14 | IR: pmIsConst | void pmIsConst() | | stmt_expr.cpp:30:20:30:21 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | stmt_expr.cpp:21:6:21:6 | IR: g | void stmtexpr::g(int) | | stmt_expr.cpp:31:16:31:18 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | stmt_expr.cpp:21:6:21:6 | IR: g | void stmtexpr::g(int) | | try_catch.cpp:21:13:21:24 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) | diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index ab5362cb06c..d68395fe136 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -29,7 +29,7 @@ instructionWithoutSuccessor | ms_try_mix.cpp:11:12:11:15 | CallSideEffect: call to C | | ms_try_mix.cpp:28:12:28:15 | CallSideEffect: call to C | | ms_try_mix.cpp:48:10:48:13 | CallSideEffect: call to C | -| pointer_to_member.cpp:35:11:35:21 | FieldAddress: {...} | +| pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} | | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | | vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | From 665564f8098bab47bde89c5c3395437d828c7e4c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 24 Sep 2019 10:36:27 +0200 Subject: [PATCH 0228/1227] C#: Add more tests for `cs/local-not-disposed` --- .../NoDisposeCallOnLocalIDisposable.cs | 11 +++++++++-- .../NoDisposeCallOnLocalIDisposable.expected | 4 +++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs index aa325c33bdc..e6dbe37f2ce 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs @@ -1,4 +1,4 @@ -// semmle-extractor-options: --cil /r:System.Xml.dll /r:System.Xml.ReaderWriter.dll /r:System.Private.Xml.dll /r:System.ComponentModel.Primitives.dll /r:System.IO.Compression.dll /r:System.Runtime.Extensions.dll +// semmle-extractor-options: --cil /langversion:8.0 /r:System.Xml.dll /r:System.Xml.ReaderWriter.dll /r:System.Private.Xml.dll /r:System.ComponentModel.Primitives.dll /r:System.IO.Compression.dll /r:System.Runtime.Extensions.dll using System; using System.Text; @@ -51,6 +51,7 @@ class Test // BAD: No Dispose call var c1d = new Timer(TimerProc); var fs = new FileStream("", FileMode.CreateNew, FileAccess.Write); + new FileStream("", FileMode.CreateNew, FileAccess.Write).Fluent(); // GOOD: Disposed via wrapper fs = new FileStream("", FileMode.CreateNew, FileAccess.Write); @@ -65,6 +66,7 @@ class Test d = new GZipStream(fs, CompressionMode.Compress); dProp = new Timer(TimerProc); this[0] = new Timer(TimerProc); + d = new FileStream("", FileMode.CreateNew, FileAccess.Write).Fluent(); // FALSE POSITIVE // GOOD: Passed to another IDisposable using (var reader = new StreamReader(new FileStream("", FileMode.Open))) @@ -90,6 +92,11 @@ class Test void TimerProc(object obj) { } + + public void Dispose() { } } -// semmle-extractor-options: /langversion:8.0 +static class Extensions +{ + public static FileStream Fluent(this FileStream fs) => fs; +} diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected index 2b9899736cc..5f1dea40571 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected @@ -1,4 +1,6 @@ | NoDisposeCallOnLocalIDisposable.cs:52:19:52:38 | object creation of type Timer | Disposable 'Timer' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposable.cs:53:18:53:73 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | -| NoDisposeCallOnLocalIDisposable.cs:74:25:74:71 | call to method Create | Disposable 'XmlReader' is created here but is not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:54:9:54:64 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:69:13:69:68 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:76:25:76:71 | call to method Create | Disposable 'XmlReader' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposableBad.cs:8:22:8:56 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | From afdb78833329346f5026fd4b1b7f55a82ee34f49 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 24 Sep 2019 10:36:54 +0200 Subject: [PATCH 0229/1227] C#: Refactor `cs/local-not-disposed` using data flow library --- csharp/ql/src/API Abuse/Dispose.qll | 18 --- .../NoDisposeCallOnLocalIDisposable.ql | 129 +++++++++++------- .../NoDisposeCallOnLocalIDisposable.cs | 2 +- .../NoDisposeCallOnLocalIDisposable.expected | 1 - 4 files changed, 81 insertions(+), 69 deletions(-) diff --git a/csharp/ql/src/API Abuse/Dispose.qll b/csharp/ql/src/API Abuse/Dispose.qll index 657ecbd8033..e8036ad36cd 100644 --- a/csharp/ql/src/API Abuse/Dispose.qll +++ b/csharp/ql/src/API Abuse/Dispose.qll @@ -59,22 +59,4 @@ class LocalScopeDisposableCreation extends Call { ) ) } - - /** - * Gets an expression that, if it is disposed of, will imply that the object - * created by this creation is disposed of as well. - */ - Expr getADisposeTarget() { result = getADisposeTarget0().asExpr() } - - private DataFlow::Node getADisposeTarget0() { - result = exprNode(this) - or - exists(DataFlow::Node mid | mid = this.getADisposeTarget0() | - localFlowStep(mid, result) - or - result.asExpr() = any(LocalScopeDisposableCreation other | - other.getAnArgument() = mid.asExpr() - ) - ) - } } diff --git a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql index 27849480052..a0d5d0870b1 100644 --- a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql +++ b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql @@ -18,60 +18,91 @@ import Dispose import semmle.code.csharp.frameworks.System import semmle.code.csharp.commons.Disposal -/** Holds if expression `e` escapes the local method scope. */ -predicate escapes(Expr e) { - // Things that return escape - exists(Callable c | c.canReturn(e) or c.canYieldReturn(e)) - or - // Things that are assigned to fields, properties, or indexers escape the scope - exists(AssignableDefinition def, Assignable a | - def.getSource() = e and - a = def.getTarget() - | - a instanceof Field or - a instanceof Property or - a instanceof Indexer - ) - or - // Things that are added to a collection of some kind are likely to escape the scope - exists(MethodCall mc | mc.getTarget().hasName("Add") | mc.getAnArgument() = e) +private class ReturnNode extends DataFlow::ExprNode { + ReturnNode() { + exists(Callable c, Expr e | e = this.getExpr() | c.canReturn(e) or c.canYieldReturn(e)) + } } -/** Holds if the `disposable` is a whitelisted result. */ -predicate isWhitelisted(LocalScopeDisposableCreation disposable) { - exists(MethodCall mc | - // Close can often be used instead of Dispose - mc.getTarget().hasName("Close") +private class Conf extends DataFlow::Configuration { + Conf() { this = "NoDisposeCallOnLocalIDisposable" } + + override predicate isSource(DataFlow::Node node) { + node.asExpr() = any(LocalScopeDisposableCreation disposable | + // Only care about library types - user types often have spurious IDisposable declarations + disposable.getType().fromLibrary() and + // WebControls are usually disposed automatically + not disposable.getType() instanceof WebControl + ) + } + + override predicate isSink(DataFlow::Node node) { + // Things that return may be disposed elsewhere + node instanceof ReturnNode or - // Used as an alias for Dispose - mc.getTarget().hasName("Clear") - | - mc.getQualifier() = disposable.getADisposeTarget() + exists(Expr e | e = node.asExpr() | + // Disposables constructed in the initializer of a `using` are safe + exists(UsingStmt us | us.getAnExpr() = e) + or + // Foreach calls Dispose + exists(ForeachStmt fs | fs.getIterableExpr() = e) + or + // As are disposables on which the Dispose method is called explicitly + exists(MethodCall mc | + mc.getTarget() instanceof DisposeMethod and + mc.getQualifier() = e + ) + or + // A disposing method + exists(Call c, Parameter p | e = c.getArgumentForParameter(p) | mayBeDisposed(p)) + or + // Things that are assigned to fields, properties, or indexers may be disposed + exists(AssignableDefinition def, Assignable a | + def.getSource() = e and + a = def.getTarget() + | + a instanceof Field or + a instanceof Property or + a instanceof Indexer + ) + or + // Things that are added to a collection of some kind are likely to escape the scope + exists(MethodCall mc | mc.getAnArgument() = e | mc.getTarget().hasName("Add")) + or + exists(MethodCall mc | mc.getQualifier() = e | + // Close can often be used instead of Dispose + mc.getTarget().hasName("Close") + or + // Used as an alias for Dispose + mc.getTarget().hasName("Clear") + ) + ) + } + + override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + node2.asExpr() = any(LocalScopeDisposableCreation other | other.getAnArgument() = node1.asExpr()) + } + + override predicate isBarrierOut(DataFlow::Node node) { + this.isSink(node) and + not node instanceof ReturnNode + } +} + +/** Holds if `disposable` may not be disposed. */ +predicate mayNotBeDiposed(LocalScopeDisposableCreation disposable) { + exists(Conf conf, DataFlow::ExprNode e | + e.getExpr() = disposable and + conf.isSource(e) and + not exists(DataFlow::Node sink | + conf.hasFlow(DataFlow::exprNode(disposable), sink) | + sink instanceof ReturnNode + implies + sink.getEnclosingCallable() = disposable.getEnclosingCallable() + ) ) - or - // WebControls are usually disposed automatically - disposable.getType() instanceof WebControl } from LocalScopeDisposableCreation disposable -// The disposable is local scope - the lifetime is the execution of this method -where - not escapes(disposable.getADisposeTarget()) and - // Only care about library types - user types often have spurious IDisposable declarations - disposable.getType().fromLibrary() and - // Disposables constructed in the initializer of a `using` are safe - not exists(UsingStmt us | us.getAnExpr() = disposable.getADisposeTarget()) and - // Foreach calls Dispose - not exists(ForeachStmt fs | fs.getIterableExpr() = disposable.getADisposeTarget()) and - // As are disposables on which the Dispose method is called explicitly - not exists(MethodCall mc | - mc.getTarget() instanceof DisposeMethod and - mc.getQualifier() = disposable.getADisposeTarget() - ) and - // Ignore whitelisted results - not isWhitelisted(disposable) and - // Not passed to a disposing method - not exists(Call c, Parameter p | disposable.getADisposeTarget() = c.getArgumentForParameter(p) | - mayBeDisposed(p) - ) +where mayNotBeDiposed(disposable) select disposable, "Disposable '" + disposable.getType() + "' is created here but is not disposed." diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs index e6dbe37f2ce..45caec0022d 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs @@ -66,7 +66,7 @@ class Test d = new GZipStream(fs, CompressionMode.Compress); dProp = new Timer(TimerProc); this[0] = new Timer(TimerProc); - d = new FileStream("", FileMode.CreateNew, FileAccess.Write).Fluent(); // FALSE POSITIVE + d = new FileStream("", FileMode.CreateNew, FileAccess.Write).Fluent(); // GOOD: Passed to another IDisposable using (var reader = new StreamReader(new FileStream("", FileMode.Open))) diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected index 5f1dea40571..aa70ad5a1cd 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected @@ -1,6 +1,5 @@ | NoDisposeCallOnLocalIDisposable.cs:52:19:52:38 | object creation of type Timer | Disposable 'Timer' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposable.cs:53:18:53:73 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposable.cs:54:9:54:64 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | -| NoDisposeCallOnLocalIDisposable.cs:69:13:69:68 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposable.cs:76:25:76:71 | call to method Create | Disposable 'XmlReader' is created here but is not disposed. | | NoDisposeCallOnLocalIDisposableBad.cs:8:22:8:56 | object creation of type FileStream | Disposable 'FileStream' is created here but is not disposed. | From 7c1594df139318671b1807225b6a59b9171ea4f9 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 25 Sep 2019 10:14:49 +0200 Subject: [PATCH 0230/1227] Java: Slight precision improvement for getter/setter detection. --- .../dataflow/internal/DataFlowImplCommon.qll | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 240913001d5..49d592a0e8a 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -30,19 +30,19 @@ private module ImplCommon { * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps, not taking call contexts into account. */ - private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { + private predicate parameterValueFlowCand(ParameterNode p, Node node) { p = node or exists(Node mid | - parameterValueFlowNoCtx(p, mid) and + parameterValueFlowCand(p, mid) and simpleLocalFlowStep(mid, node) and compatibleTypes(p.getType(), node.getType()) ) or // flow through a callable exists(Node arg | - parameterValueFlowNoCtx(p, arg) and - argumentValueFlowsThroughNoCtx(arg, node) and + parameterValueFlowCand(p, arg) and + argumentValueFlowsThroughCand(arg, node) and compatibleTypes(p.getType(), node.getType()) ) } @@ -52,16 +52,16 @@ private module ImplCommon { * callable using only value-preserving steps, not taking call contexts * into account. */ - private predicate parameterValueFlowsThroughNoCtx(ParameterNode p, ReturnKind kind) { - parameterValueFlowNoCtx(p, getAReturnNodeOfKind(kind)) + private predicate parameterValueFlowsThroughCand(ParameterNode p, ReturnKind kind) { + parameterValueFlowCand(p, getAReturnNodeOfKind(kind)) } pragma[nomagic] - private predicate argumentValueFlowsThroughNoCtx0( + private predicate argumentValueFlowsThroughCand0( DataFlowCall call, ArgumentNode arg, ReturnKind kind ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowsThroughNoCtx(param, kind) + parameterValueFlowsThroughCand(param, kind) ) } @@ -69,8 +69,8 @@ private module ImplCommon { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. */ - private predicate argumentValueFlowsThroughNoCtx(ArgumentNode arg, OutNode out) { - exists(DataFlowCall call, ReturnKind kind | argumentValueFlowsThroughNoCtx0(call, arg, kind) | + private predicate argumentValueFlowsThroughCand(ArgumentNode arg, OutNode out) { + exists(DataFlowCall call, ReturnKind kind | argumentValueFlowsThroughCand0(call, arg, kind) | out = getAnOutNode(call, kind) and compatibleTypes(arg.getType(), out.getType()) ) @@ -85,7 +85,7 @@ private module ImplCommon { DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing ) { arg.argumentOf(call, i) and - argumentValueFlowsThroughNoCtx(arg, _) and + argumentValueFlowsThroughCand(arg, _) and enclosing = arg.getEnclosingCallable() } @@ -147,7 +147,7 @@ private module ImplCommon { */ private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { p = node and - parameterValueFlowsThroughNoCtx(p, _) and + parameterValueFlowsThroughCand(p, _) and cc = getAValidCallContextForParameter(p) or exists(Node mid | @@ -213,6 +213,16 @@ private module ImplCommon { argumentValueFlowsThrough(node1, node2, _) } + private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { + p = node + or + exists(Node mid | + parameterValueFlowNoCtx(p, mid) and + localValueStep(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + } + /* * Calculation of `predicate store(Node node1, Content f, Node node2)`: * There are four cases: From 142e1cb9fbbcf8c939c9728c722221c01c01b88d Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Fri, 6 Sep 2019 16:34:20 +0100 Subject: [PATCH 0231/1227] C++: Implement AggregateLiteral.mayBeImpure() --- cpp/ql/src/semmle/code/cpp/exprs/Literal.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll index f8d2b56190d..84a8e91b393 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll @@ -132,7 +132,6 @@ class HexLiteral extends Literal { * A C/C++ aggregate literal. */ class AggregateLiteral extends Expr, @aggregateliteral { - // if this is turned into a Literal we need to change mayBeImpure override string getCanonicalQLClass() { result = "AggregateLiteral" } /** @@ -145,6 +144,10 @@ class AggregateLiteral extends Expr, @aggregateliteral { result = this.(ClassAggregateLiteral).getFieldExpr(f) } + override predicate mayBeImpure() { this.getAChild().mayBeImpure() } + + override predicate mayBeGloballyImpure() { this.getAChild().mayBeGloballyImpure() } + /** Gets a textual representation of this aggregate literal. */ override string toString() { result = "{...}" } } From 5a198a39dfa9973c083407adac110973dd03dcf4 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 25 Sep 2019 11:52:19 +0200 Subject: [PATCH 0232/1227] C#: Autoformat --- csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql index a0d5d0870b1..4fef7c41256 100644 --- a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql +++ b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql @@ -94,8 +94,7 @@ predicate mayNotBeDiposed(LocalScopeDisposableCreation disposable) { exists(Conf conf, DataFlow::ExprNode e | e.getExpr() = disposable and conf.isSource(e) and - not exists(DataFlow::Node sink | - conf.hasFlow(DataFlow::exprNode(disposable), sink) | + not exists(DataFlow::Node sink | conf.hasFlow(DataFlow::exprNode(disposable), sink) | sink instanceof ReturnNode implies sink.getEnclosingCallable() = disposable.getEnclosingCallable() From 0b0f69fe2da1c6e4b2d539b303fd6f6dc61c8521 Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Wed, 25 Sep 2019 12:50:05 +0100 Subject: [PATCH 0233/1227] QL etudes: Tidy up alternative solns --- .../learn-ql/ql-etudes/river-crossing.rst | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.rst b/docs/language/learn-ql/ql-etudes/river-crossing.rst index 1b5b1883739..0ab2efceef8 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.rst +++ b/docs/language/learn-ql/ql-etudes/river-crossing.rst @@ -242,8 +242,18 @@ Alternative solutions Here are some more example QL queries that solve the river crossing puzzle: - - Solutions described in more detail: https://lgtm.com/query/4550752404102766320/ - - Solutions displayed in a more visual way: https://lgtm.com/query/5824364611285694673/ + #. This query uses a modified ``path`` variable to describe the resulting path in + more detail. -.. TODO: Add more examples + check that the queries are "tidied up" and clear. + ➤ `See solution in the query console `__ + #. This query models the man and the cargo items in a different way, using an + `abstract `__ + class and predicate. It also displays the resulting path in a more visual way. + + ➤ `See solution in the query console `__ + + #. This query introduces `algebraic datatypes `__ + to model the situation, instead of defining everything as a subclass of ``string``. + + ➤ `See solution in the query console `__ \ No newline at end of file From c810776413e5566e2cc35828d684891001bbe6f0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 25 Sep 2019 13:57:42 +0200 Subject: [PATCH 0234/1227] C#: Update reference conversion test --- .../conversion/reftype/RefType.cs | 6 ++++++ .../conversion/reftype/RefType.expected | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/csharp/ql/test/library-tests/conversion/reftype/RefType.cs b/csharp/ql/test/library-tests/conversion/reftype/RefType.cs index 9a291798bc5..04d74108387 100644 --- a/csharp/ql/test/library-tests/conversion/reftype/RefType.cs +++ b/csharp/ql/test/library-tests/conversion/reftype/RefType.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; interface I1 { } interface I2 { } interface I3 : I1, I2 { } +interface I4 where T3 : C1 { I4 M(I4 x); } class C1 { } @@ -86,4 +87,9 @@ class C2 : C1 } } +class C3 where T5 : C1 +{ + public I4 M(I4 x) => x; +} + // semmle-extractor-options: /r:System.Dynamic.Runtime.dll /r:System.Linq.Expressions.dll diff --git a/csharp/ql/test/library-tests/conversion/reftype/RefType.expected b/csharp/ql/test/library-tests/conversion/reftype/RefType.expected index 7e36270e6f7..227b057a7d5 100644 --- a/csharp/ql/test/library-tests/conversion/reftype/RefType.expected +++ b/csharp/ql/test/library-tests/conversion/reftype/RefType.expected @@ -21,6 +21,8 @@ | C2[] | Object | | C2[] | Object[] | | C2[] | dynamic | +| C3<,> | Object | +| C3<,> | dynamic | | Func> | Object | | Func> | dynamic | | Func | Func | @@ -70,6 +72,14 @@ | I3 | I2 | | I3 | Object | | I3 | dynamic | +| I4<,> | Object | +| I4<,> | dynamic | +| I4 | Object | +| I4 | dynamic | +| I4 | Object | +| I4 | dynamic | +| I4 | Object | +| I4 | dynamic | | ICollection | IEnumerable | | ICollection | Object | | ICollection | dynamic | @@ -180,6 +190,9 @@ | Object[] | dynamic | | SByte[] | Object | | SByte[] | dynamic | +| T3 | C1 | +| T3 | Object | +| T3 | dynamic | | T3[] | ICollection | | T3[] | IEnumerable | | T3[] | IList | @@ -203,6 +216,7 @@ | T4[] | Object | | T4[] | Object[] | | T4[] | dynamic | +| T5 | C1 | | T5 | Object | | T5 | dynamic | | UInt32[] | Object | @@ -215,6 +229,7 @@ | null | C1[] | | null | C2 | | null | C2[] | +| null | C3<,> | | null | Func> | | null | Func | | null | Func | @@ -233,6 +248,10 @@ | null | I3<,> | | null | I3 | | null | I3 | +| null | I4<,> | +| null | I4 | +| null | I4 | +| null | I4 | | null | ICollection | | null | ICollection | | null | ICollection | @@ -263,6 +282,7 @@ | null | Object | | null | Object[] | | null | SByte[] | +| null | T3 | | null | T3[] | | null | T4 | | null | T4[] | From 886b258385951dd705936df6c9ad06294ad1077d Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Wed, 25 Sep 2019 14:35:25 +0100 Subject: [PATCH 0235/1227] QL etudes: Update linked queries --- docs/language/learn-ql/ql-etudes/river-crossing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.rst b/docs/language/learn-ql/ql-etudes/river-crossing.rst index 0ab2efceef8..588ece6aaa6 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.rst +++ b/docs/language/learn-ql/ql-etudes/river-crossing.rst @@ -245,15 +245,15 @@ Here are some more example QL queries that solve the river crossing puzzle: #. This query uses a modified ``path`` variable to describe the resulting path in more detail. - ➤ `See solution in the query console `__ + ➤ `See solution in the query console `__ #. This query models the man and the cargo items in a different way, using an `abstract `__ class and predicate. It also displays the resulting path in a more visual way. - ➤ `See solution in the query console `__ + ➤ `See solution in the query console `__ #. This query introduces `algebraic datatypes `__ to model the situation, instead of defining everything as a subclass of ``string``. - ➤ `See solution in the query console `__ \ No newline at end of file + ➤ `See solution in the query console `__ \ No newline at end of file From 3da438bb841056c6f79f0877d5ebc9836e67ad69 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 25 Sep 2019 14:01:48 +0200 Subject: [PATCH 0236/1227] C#: Handle unbound types in conversion library A constructed type, `C`, where `T` is the type parameter of `C`, is represented in the database as the corresponding unbound generict type `C<>`. Consequently, the type conversion library, which only considers `ConstructedType`s, does not handle all implicit conversions. For example, in ``` interface I where T1 : C ``` there should be an implicit conversion from `I` to `I` (=`I<>`). --- .../ql/src/semmle/code/csharp/Conversion.qll | 142 +++++++++--------- .../conversion/reftype/RefType.expected | 2 + 2 files changed, 70 insertions(+), 74 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Conversion.qll b/csharp/ql/src/semmle/code/csharp/Conversion.qll index 4c38f9de164..617badac7d5 100644 --- a/csharp/ql/src/semmle/code/csharp/Conversion.qll +++ b/csharp/ql/src/semmle/code/csharp/Conversion.qll @@ -54,11 +54,28 @@ private predicate implicitConversionNonNull(Type fromType, Type toType) { fromType instanceof DynamicType // 6.1.8 } -private Type getTypeArgument(UnboundGenericType ugt, ConstructedType ct, int i, TypeParameter tp) { - ct.getUnboundGeneric() = ugt and +/** + * A generic type. This includes both constructed generic types and unbound + * generic types (which correspond to constructed generic types where the + * type arguments equal the type parameters). + */ +private class GenericType extends Generic, Type { + /** Gets the `i`th type argument. */ + Type getTypeArgument(int i) { result = this.getChild(i) } + + /** Gets the unbound generic type. */ + UnboundGenericType getUnboundGeneric() { + result = this.(ConstructedType).getUnboundGeneric() + or + result = this + } +} + +private Type getTypeArgument(UnboundGenericType ugt, GenericType gt, int i, TypeParameter tp) { + gt.getUnboundGeneric() = ugt and not ugt instanceof AnonymousClass and tp = ugt.getTypeParameter(i) and - result = ct.getTypeArgument(i) + result = gt.getTypeArgument(i) } /** A type that is an element type of an array type. */ @@ -68,7 +85,7 @@ private class ArrayElementType extends Type { /** A type that is an argument in a constructed type. */ private class TypeArgument extends Type { - TypeArgument() { this = any(ConstructedType ct).getATypeArgument() } + TypeArgument() { this = any(GenericType gt).getTypeArgument(_) } } /** @@ -95,8 +112,7 @@ private module Identity { private class IdentityConvertibleArrayType extends IdentityConvertibleType, ArrayType { } - private class IdentityConvertibleConstructedType extends IdentityConvertibleType, ConstructedType { - } + private class IdentityConvertibleGenericType extends IdentityConvertibleType, GenericType { } /** * A type is (strictly) identity convertible if it contains at least one `object` @@ -109,7 +125,7 @@ private module Identity { or isIdentityConvertible(t.(ArrayType).getElementType()) or - isIdentityConvertible(t.(ConstructedType).getATypeArgument()) + isIdentityConvertible(t.(GenericType).getTypeArgument(_)) } predicate convIdentityStrict(IdentityConvertibleType fromType, IdentityConvertibleType toType) { @@ -119,7 +135,7 @@ private module Identity { or convIdentityStrictArrayType(fromType, toType) or - convIdentityStrictConstructedType(fromType, toType) + convIdentityStrictGenericType(fromType, toType) } private predicate convIdentityObjectDynamic(ObjectType fromType, DynamicType toType) { any() } @@ -151,7 +167,7 @@ private module Identity { */ private int getTypeArgumentCount(UnboundGenericType ugt, int i) { result = strictcount(Type arg | - exists(IdentityConvertibleConstructedType ct | ct.getUnboundGeneric() = ugt | + exists(IdentityConvertibleGenericType ct | ct.getUnboundGeneric() = ugt | arg = ct.getTypeArgument(i) ) ) @@ -162,9 +178,7 @@ private module Identity { } /** Gets the 'i'th type argument, ranked by size, of constructed type `t`. */ - private Type getTypeArgumentRanked( - UnboundGenericType ugt, IdentityConvertibleConstructedType t, int i - ) { + private Type getTypeArgumentRanked(UnboundGenericType ugt, IdentityConvertibleGenericType t, int i) { result = getTypeArgument(ugt, t, rnk(ugt, i), _) } @@ -207,8 +221,8 @@ private module Identity { pragma[nomagic] private predicate convIdentitySingle0( - UnboundGenericType ugt, IdentityConvertibleConstructedType toType, - TypeArgument fromTypeArgument, TypeArgument toTypeArgument + UnboundGenericType ugt, IdentityConvertibleGenericType toType, TypeArgument fromTypeArgument, + TypeArgument toTypeArgument ) { convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, 0) and toTypeArgument = getTypeArgumentRanked(ugt, toType, 0) and @@ -220,8 +234,8 @@ private module Identity { * convertible, and the number of type arguments is 1. */ predicate convIdentitySingle( - UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, - IdentityConvertibleConstructedType toType + UnboundGenericType ugt, IdentityConvertibleGenericType fromType, + IdentityConvertibleGenericType toType ) { exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument | convIdentitySingle0(ugt, toType, fromTypeArgument, toTypeArgument) @@ -232,8 +246,8 @@ private module Identity { pragma[nomagic] private predicate convIdentityMultiple01Aux0( - UnboundGenericType ugt, IdentityConvertibleConstructedType toType, - TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument toTypeArgument1 + UnboundGenericType ugt, IdentityConvertibleGenericType toType, TypeArgument fromTypeArgument0, + TypeArgument toTypeArgument0, TypeArgument toTypeArgument1 ) { convTypeArgumentsSameUnbound(ugt, fromTypeArgument0, toTypeArgument0, 0) and toTypeArgument0 = getTypeArgumentRanked(ugt, toType, 0) and @@ -242,8 +256,8 @@ private module Identity { pragma[nomagic] private predicate convIdentityMultiple01Aux1( - UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, - TypeArgument fromTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1 + UnboundGenericType ugt, IdentityConvertibleGenericType fromType, TypeArgument fromTypeArgument0, + TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1 ) { convTypeArgumentsSameUnbound(ugt, fromTypeArgument1, toTypeArgument1, 1) and fromTypeArgument0 = getTypeArgumentRanked(ugt, fromType, 0) and @@ -255,8 +269,8 @@ private module Identity { * are identity convertible. */ private predicate convIdentityMultiple01( - UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, - IdentityConvertibleConstructedType toType + UnboundGenericType ugt, IdentityConvertibleGenericType fromType, + IdentityConvertibleGenericType toType ) { exists( Type fromTypeArgument0, Type toTypeArgument0, Type fromTypeArgument1, Type toTypeArgument1 @@ -270,7 +284,7 @@ private module Identity { pragma[nomagic] private predicate convIdentityMultiple2Aux( - UnboundGenericType ugt, IdentityConvertibleConstructedType toType, int i, + UnboundGenericType ugt, IdentityConvertibleGenericType toType, int i, TypeArgument fromTypeArgument, TypeArgument toTypeArgument ) { convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, i) and @@ -279,8 +293,8 @@ private module Identity { } private predicate convIdentityMultiple2( - UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, - IdentityConvertibleConstructedType toType, int i + UnboundGenericType ugt, IdentityConvertibleGenericType fromType, + IdentityConvertibleGenericType toType, int i ) { exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument | convIdentityMultiple2Aux(ugt, toType, i, fromTypeArgument, toTypeArgument) @@ -295,8 +309,8 @@ private module Identity { */ pragma[nomagic] predicate convIdentityMultiple( - UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, - IdentityConvertibleConstructedType toType, int i + UnboundGenericType ugt, IdentityConvertibleGenericType fromType, + IdentityConvertibleGenericType toType, int i ) { convIdentityMultiple01(ugt, fromType, toType) and i = 1 or @@ -304,8 +318,8 @@ private module Identity { convIdentityMultiple2(ugt, fromType, toType, i) } - private predicate convIdentityStrictConstructedType( - IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType + private predicate convIdentityStrictGenericType( + IdentityConvertibleGenericType fromType, IdentityConvertibleGenericType toType ) { // Semantically equivalent with // ``` @@ -730,7 +744,7 @@ predicate convConversionOperator(Type fromType, Type toType) { } /** 13.1.3.2: Variance conversion. */ -private predicate convVariance(ConstructedType fromType, ConstructedType toType) { +private predicate convVariance(GenericType fromType, GenericType toType) { // Semantically equivalent with // ``` // ugt = fromType.getUnboundGeneric() @@ -758,34 +772,14 @@ private predicate convVariance(ConstructedType fromType, ConstructedType toType) } private module Variance { - /** - * Holds if constructed type `ct` is potentially variance convertible to - * or from another constructed type, as a result of the `i`th type - * argument being potentially convertible. - */ - private predicate isVarianceConvertible(ConstructedType ct, int i) { - exists(TypeParameter tp, Type t | - tp = ct.getUnboundGeneric().getTypeParameter(i) and - t = ct.getTypeArgument(i) - | - // Anything that is not a type parameter is potentially convertible - // to/from another type; if the `i`th type parameter is invariant, - // `t` must be strictly identity convertible - not t instanceof TypeParameter and - (tp.isIn() or tp.isOut() or Identity::convIdentityStrict(t, _)) - or - exists(TypeParameter s | s = t | - // A type parameter with implicit reference conversion - exists(convTypeParameterBase(s)) and s.isRefType() and tp.isOut() + private class VarianceConvertibleGenericType extends GenericType { + VarianceConvertibleGenericType() { + exists(TypeParameter tp | tp = this.getUnboundGeneric().getATypeParameter() | + tp.isIn() or - // A type parameter convertible from another type parameter - exists(TypeParameter u | s = convTypeParameterBase(u) and u.isRefType() and tp.isIn()) + tp.isOut() ) - ) - } - - private class VarianceConvertibleConstructedType extends ConstructedType { - VarianceConvertibleConstructedType() { isVarianceConvertible(this, _) } + } } /** @@ -794,8 +788,8 @@ private module Variance { */ private int getTypeArgumentCount(UnboundGenericType ugt, int i) { result = strictcount(Type arg | - exists(VarianceConvertibleConstructedType ct | ct.getUnboundGeneric() = ugt | - arg = ct.getTypeArgument(i) + exists(VarianceConvertibleGenericType gt | gt.getUnboundGeneric() = ugt | + arg = gt.getTypeArgument(i) ) ) } @@ -806,7 +800,7 @@ private module Variance { /** Gets the 'i'th type argument, ranked by size, of constructed type `t`. */ private Type getTypeArgumentRanked( - UnboundGenericType ugt, VarianceConvertibleConstructedType t, int i, TypeParameter tp + UnboundGenericType ugt, VarianceConvertibleGenericType t, int i, TypeParameter tp ) { result = getTypeArgument(ugt, t, rnk(ugt, i), tp) } @@ -889,8 +883,8 @@ private module Variance { pragma[nomagic] private predicate convVarianceSingle0( - UnboundGenericType ugt, VarianceConvertibleConstructedType toType, - TypeArgument fromTypeArgument, TypeArgument toTypeArgument + UnboundGenericType ugt, VarianceConvertibleGenericType toType, TypeArgument fromTypeArgument, + TypeArgument toTypeArgument ) { convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, 0) and toTypeArgument = getTypeArgumentRanked(ugt, toType, 0, _) and @@ -902,8 +896,8 @@ private module Variance { * convertible, and the number of type arguments is 1. */ predicate convVarianceSingle( - UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, - VarianceConvertibleConstructedType toType + UnboundGenericType ugt, VarianceConvertibleGenericType fromType, + VarianceConvertibleGenericType toType ) { exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument | convVarianceSingle0(ugt, toType, fromTypeArgument, toTypeArgument) @@ -914,8 +908,8 @@ private module Variance { pragma[nomagic] private predicate convVarianceMultiple01Aux0( - UnboundGenericType ugt, VarianceConvertibleConstructedType toType, - TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument toTypeArgument1 + UnboundGenericType ugt, VarianceConvertibleGenericType toType, TypeArgument fromTypeArgument0, + TypeArgument toTypeArgument0, TypeArgument toTypeArgument1 ) { convTypeArgumentsSameUnbound(ugt, fromTypeArgument0, toTypeArgument0, 0) and toTypeArgument0 = getTypeArgumentRanked(ugt, toType, 0, _) and @@ -924,8 +918,8 @@ private module Variance { pragma[nomagic] private predicate convVarianceMultiple01Aux1( - UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, - TypeArgument fromTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1 + UnboundGenericType ugt, VarianceConvertibleGenericType fromType, TypeArgument fromTypeArgument0, + TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1 ) { convTypeArgumentsSameUnbound(ugt, fromTypeArgument1, toTypeArgument1, 1) and fromTypeArgument0 = getTypeArgumentRanked(ugt, fromType, 0, _) and @@ -937,8 +931,8 @@ private module Variance { * are variance convertible. */ private predicate convVarianceMultiple01( - UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, - VarianceConvertibleConstructedType toType + UnboundGenericType ugt, VarianceConvertibleGenericType fromType, + VarianceConvertibleGenericType toType ) { exists( TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument fromTypeArgument1, @@ -953,7 +947,7 @@ private module Variance { pragma[nomagic] private predicate convVarianceMultiple2Aux( - UnboundGenericType ugt, VarianceConvertibleConstructedType toType, int i, + UnboundGenericType ugt, VarianceConvertibleGenericType toType, int i, TypeArgument fromTypeArgument, TypeArgument toTypeArgument ) { convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, i) and @@ -962,8 +956,8 @@ private module Variance { } private predicate convVarianceMultiple2( - UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, - VarianceConvertibleConstructedType toType, int i + UnboundGenericType ugt, VarianceConvertibleGenericType fromType, + VarianceConvertibleGenericType toType, int i ) { exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument | convVarianceMultiple2Aux(ugt, toType, i, fromTypeArgument, toTypeArgument) @@ -978,8 +972,8 @@ private module Variance { */ pragma[nomagic] predicate convVarianceMultiple( - UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, - VarianceConvertibleConstructedType toType, int i + UnboundGenericType ugt, VarianceConvertibleGenericType fromType, + VarianceConvertibleGenericType toType, int i ) { convVarianceMultiple01(ugt, fromType, toType) and i = 1 or diff --git a/csharp/ql/test/library-tests/conversion/reftype/RefType.expected b/csharp/ql/test/library-tests/conversion/reftype/RefType.expected index 227b057a7d5..cdcfcf78f96 100644 --- a/csharp/ql/test/library-tests/conversion/reftype/RefType.expected +++ b/csharp/ql/test/library-tests/conversion/reftype/RefType.expected @@ -74,8 +74,10 @@ | I3 | dynamic | | I4<,> | Object | | I4<,> | dynamic | +| I4 | I4<,> | | I4 | Object | | I4 | dynamic | +| I4 | I4 | | I4 | Object | | I4 | dynamic | | I4 | Object | From c6c565bc373e1353830ea731823feea024b4c4c8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 25 Sep 2019 18:20:48 +0200 Subject: [PATCH 0237/1227] Learn QL: Fix query link in Python Points-to tutorial --- docs/language/learn-ql/python/pointsto-type-infer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/python/pointsto-type-infer.rst b/docs/language/learn-ql/python/pointsto-type-infer.rst index 6ca1bde67c8..bcbab520477 100644 --- a/docs/language/learn-ql/python/pointsto-type-infer.rst +++ b/docs/language/learn-ql/python/pointsto-type-infer.rst @@ -173,7 +173,7 @@ Many of the results shown will have ``cls`` as ``NoneType``. It is more informat not cls.hasAttribute("__iter__") select loop, cls, origin -➤ `See this in the query console `__. This reports the same results, but with a third column showing the source of the ``None`` values. +➤ `See this in the query console `__. This reports the same results, but with a third column showing the source of the ``None`` values. Finding calls using call-graph analysis ---------------------------------------------------- From 7f18f35f31273e667cc334480d1a3a9f524474c3 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 25 Sep 2019 21:20:45 +0200 Subject: [PATCH 0238/1227] C#: Update test --- .../ql/test/library-tests/comments/Generics.expected | 7 ++----- csharp/ql/test/library-tests/comments/Generics.ql | 12 +++--------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/csharp/ql/test/library-tests/comments/Generics.expected b/csharp/ql/test/library-tests/comments/Generics.expected index 2f55348f3cb..28e946fc8f5 100644 --- a/csharp/ql/test/library-tests/comments/Generics.expected +++ b/csharp/ql/test/library-tests/comments/Generics.expected @@ -1,5 +1,2 @@ -| comments2.cs:118:5:118:21 | // ... | comments2.cs:119:11:119:25 | GenericClass<> | NestedType | -| comments2.cs:118:5:118:21 | // ... | comments2.cs:119:11:119:25 | GenericClass<> | UnboundGenericClass | -| comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | CallableOrCFE | -| comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | InstanceCallable | -| comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | UnboundGenericMethod | +| comments2.cs:118:5:118:21 | // ... | comments2.cs:119:11:119:25 | GenericClass<> | +| comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | diff --git a/csharp/ql/test/library-tests/comments/Generics.ql b/csharp/ql/test/library-tests/comments/Generics.ql index cce6c2dc4f4..0e743aaada4 100644 --- a/csharp/ql/test/library-tests/comments/Generics.ql +++ b/csharp/ql/test/library-tests/comments/Generics.ql @@ -1,6 +1,6 @@ import csharp -from CommentBlock b, Element e, string s +from CommentBlock b, Element e where b.getElement() = e and ( @@ -8,11 +8,5 @@ where e instanceof ConstructedClass or e instanceof UnboundGenericClass or e instanceof UnboundGenericMethod - ) and - s = e.getAQlClass() and - not s = "SourceDeclarationType" and - not s = "SourceDeclarationCallable" and - not s = "SourceDeclarationMethod" and - not s = "NonConstructedMethod" and - not s = "RuntimeInstanceMethod" -select b, e, s + ) +select b, e From c47a4e0c44eba9f24ffb5490986188347e1372f5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 26 Sep 2019 11:16:24 +0200 Subject: [PATCH 0239/1227] Learn QL: Minor formatting fix in python/statements-expressions --- docs/language/learn-ql/python/statements-expressions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/python/statements-expressions.rst b/docs/language/learn-ql/python/statements-expressions.rst index 2d45abde73a..9f1a15a6d1a 100644 --- a/docs/language/learn-ql/python/statements-expressions.rst +++ b/docs/language/learn-ql/python/statements-expressions.rst @@ -72,7 +72,7 @@ An ``if`` statement where one branch is composed of just ``pass`` statements cou To find statements like this we can run the following query: -**Find ``if`` statements with empty branches** +**Find 'if' statements with empty branches** .. code-block:: ql From 8ca294ae4111efd3136bd74d6d7843ca5874948c Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 18 Sep 2019 11:04:12 +0100 Subject: [PATCH 0240/1227] JS: Merge TypeScript/CallSignatures test --- .../CallSignatures/CallSignatures.expected | 4 ---- .../TypeScript/CallSignatures/CallSignatures.ql | 5 ----- .../CallSignatures/IndexSignatures.expected | 2 -- .../CallSignatures/IndexSignatures.ql | 5 ----- .../CallSignatures/MethodDeclarations.expected | 3 --- .../CallSignatures/MethodDeclarations.ql | 4 ---- .../TypeScript/CallSignatures/test.expected | 12 ++++++++++++ .../TypeScript/CallSignatures/test.ql | 17 +++++++++++++++++ 8 files changed, 29 insertions(+), 23 deletions(-) delete mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatures/CallSignatures.expected delete mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatures/CallSignatures.ql delete mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatures/IndexSignatures.expected delete mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatures/IndexSignatures.ql delete mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatures/MethodDeclarations.expected delete mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatures/MethodDeclarations.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatures/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatures/test.ql diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/CallSignatures.expected b/javascript/ql/test/library-tests/TypeScript/CallSignatures/CallSignatures.expected deleted file mode 100644 index f97c1bcd416..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatures/CallSignatures.expected +++ /dev/null @@ -1,4 +0,0 @@ -| tst.ts:7:3:7:22 | (x: number): number; | interface I | tst.ts:7:3:7:22 | (x: number): number; | abstract | -| tst.ts:8:3:8:21 | new (x: number): C; | interface I | tst.ts:8:3:8:21 | new (x: number): C; | abstract | -| tst.ts:13:3:13:22 | (x: number): number; | anonymous interface | tst.ts:13:3:13:22 | (x: number): number; | abstract | -| tst.ts:14:3:14:21 | new (x: number): C; | anonymous interface | tst.ts:14:3:14:21 | new (x: number): C; | abstract | diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/CallSignatures.ql b/javascript/ql/test/library-tests/TypeScript/CallSignatures/CallSignatures.ql deleted file mode 100644 index 61d85786859..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatures/CallSignatures.ql +++ /dev/null @@ -1,5 +0,0 @@ -import javascript - -from CallSignature call, string abstractness -where if call.isAbstract() then abstractness = "abstract" else abstractness = "not abstract" -select call, call.getDeclaringType().describe(), call.getBody(), abstractness diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/IndexSignatures.expected b/javascript/ql/test/library-tests/TypeScript/CallSignatures/IndexSignatures.expected deleted file mode 100644 index 9f0791d5632..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatures/IndexSignatures.expected +++ /dev/null @@ -1,2 +0,0 @@ -| tst.ts:9:3:9:22 | [x: number]: string; | interface I | tst.ts:9:3:9:22 | [x: number]: string; | abstract | -| tst.ts:15:3:15:22 | [x: number]: string; | anonymous interface | tst.ts:15:3:15:22 | [x: number]: string; | abstract | diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/IndexSignatures.ql b/javascript/ql/test/library-tests/TypeScript/CallSignatures/IndexSignatures.ql deleted file mode 100644 index 31e7522f959..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatures/IndexSignatures.ql +++ /dev/null @@ -1,5 +0,0 @@ -import javascript - -from IndexSignature sig, string abstractness -where if sig.isAbstract() then abstractness = "abstract" else abstractness = "not abstract" -select sig, sig.getDeclaringType().describe(), sig.getBody(), abstractness diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/MethodDeclarations.expected b/javascript/ql/test/library-tests/TypeScript/CallSignatures/MethodDeclarations.expected deleted file mode 100644 index 86864857814..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatures/MethodDeclarations.expected +++ /dev/null @@ -1,3 +0,0 @@ -| tst.ts:1:18:1:17 | constructor() {} | Method constructor in class C | -| tst.ts:2:3:2:31 | abstrac ... number; | Method abstract in class C | -| tst.ts:3:3:3:30 | abstrac ... er): C; | Method new in class C | diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/MethodDeclarations.ql b/javascript/ql/test/library-tests/TypeScript/CallSignatures/MethodDeclarations.ql deleted file mode 100644 index 1f832c56e77..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatures/MethodDeclarations.ql +++ /dev/null @@ -1,4 +0,0 @@ -import javascript - -from MethodDeclaration method -select method, "Method " + method.getName() + " in " + method.getDeclaringType().describe() diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.expected b/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.expected new file mode 100644 index 00000000000..1d9aa880e89 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.expected @@ -0,0 +1,12 @@ +test_CallSignature +| tst.ts:7:3:7:22 | (x: number): number; | interface I | tst.ts:7:3:7:22 | (x: number): number; | abstract | +| tst.ts:8:3:8:21 | new (x: number): C; | interface I | tst.ts:8:3:8:21 | new (x: number): C; | abstract | +| tst.ts:13:3:13:22 | (x: number): number; | anonymous interface | tst.ts:13:3:13:22 | (x: number): number; | abstract | +| tst.ts:14:3:14:21 | new (x: number): C; | anonymous interface | tst.ts:14:3:14:21 | new (x: number): C; | abstract | +test_IndexSignature +| tst.ts:9:3:9:22 | [x: number]: string; | interface I | tst.ts:9:3:9:22 | [x: number]: string; | abstract | +| tst.ts:15:3:15:22 | [x: number]: string; | anonymous interface | tst.ts:15:3:15:22 | [x: number]: string; | abstract | +test_MethodDeclarations +| tst.ts:1:18:1:17 | constructor() {} | Method constructor in class C | +| tst.ts:2:3:2:31 | abstrac ... number; | Method abstract in class C | +| tst.ts:3:3:3:30 | abstrac ... er): C; | Method new in class C | diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.ql b/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.ql new file mode 100644 index 00000000000..174f163627f --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.ql @@ -0,0 +1,17 @@ +import javascript + +query predicate test_CallSignature(CallSignature call, string declType, ASTNode body, string abstractness) { + (if call.isAbstract() then abstractness = "abstract" else abstractness = "not abstract") and + declType = call.getDeclaringType().describe() and + body = call.getBody() +} + +query predicate test_IndexSignature(IndexSignature sig, string declType, ASTNode body, string abstractness) { + (if sig.isAbstract() then abstractness = "abstract" else abstractness = "not abstract") and + declType = sig.getDeclaringType().describe() and + body = sig.getBody() +} + +query predicate test_MethodDeclarations(MethodDeclaration method, string descr) { + descr = "Method " + method.getName() + " in " + method.getDeclaringType().describe() +} From 97494290deccaa147c2f98ed6e6655b18de64dd0 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 18 Sep 2019 11:34:11 +0100 Subject: [PATCH 0241/1227] JS: Add getOverloadIndex() --- .../ql/src/semmle/javascript/Classes.qll | 130 +++++++++++++++++- .../TypeScript/CallSignatures/test.expected | 54 ++++++++ .../TypeScript/CallSignatures/test.ql | 15 ++ .../TypeScript/CallSignatures/tst.ts | 38 +++++ 4 files changed, 234 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Classes.qll b/javascript/ql/src/semmle/javascript/Classes.qll index 1d314a6383d..05a27fd54e0 100644 --- a/javascript/ql/src/semmle/javascript/Classes.qll +++ b/javascript/ql/src/semmle/javascript/Classes.qll @@ -48,6 +48,9 @@ class ClassOrInterface extends @classorinterface, TypeParameterized { /** Gets a member declared in this class or interface. */ MemberDeclaration getAMember() { result.getDeclaringType() = this } + /** Gets the `i`th member declared in this class or interface. */ + MemberDeclaration getMemberByIndex(int i) { properties(result, this, i, _, _) } + /** Gets the member with the given name declared in this class or interface. */ MemberDeclaration getMember(string name) { result = getAMember() and @@ -57,9 +60,19 @@ class ClassOrInterface extends @classorinterface, TypeParameterized { /** Gets a method declared in this class or interface. */ MethodDeclaration getAMethod() { result = getAMember() } - /** Gets the method with the given name declared in this class or interface. */ + /** + * Gets the method with the given name declared in this class or interface. + * + * Note that for overloaded method signatures in TypeScript files, this returns every overload. + */ MethodDeclaration getMethod(string name) { result = getMember(name) } + /** Gets an overloaded version of the method with the given name declared in this class or interface. */ + MethodDeclaration getMethodOverload(string name, int overloadIndex) { + result = getMethod(name) and + overloadIndex = result.getOverloadIndex() + } + /** Gets a field declared in this class or interface. */ FieldDeclaration getAField() { result = getAMember() } @@ -523,6 +536,9 @@ class MemberDeclaration extends @property, Documentable { /** Gets the class this member belongs to, if any. */ ClassDefinition getDeclaringClass() { properties(this, result, _, _, _) } + /** Gets the index of this member within its enclosing type. */ + int getMemberIndex() { properties(this, _, result, _, _) } + /** Gets the nearest enclosing function or toplevel in which this member occurs. */ StmtContainer getContainer() { result = getDeclaringType().getContainer() } @@ -642,6 +658,80 @@ class MethodDeclaration extends MemberDeclaration { * Gets the body of this method. */ FunctionExpr getBody() { result = getChildExpr(1) } + + /** + * Holds if this method is overloaded, that is, there are multiple method + * signatures with its name declared in the enclosing type. + */ + predicate isOverloaded() { + not this instanceof ConstructorDeclaration and + hasOverloadedMethod(getDeclaringType(), getName()) + or + this instanceof ConstructorDeclaration and + hasOverloadedConstructor(getDeclaringClass()) + } + + /** + * Gets the index of this method declaration among all the method declarations + * with this name. + * + * In the rare case of a class containing multiple concrete methods with the same name, + * the overload index is defined as if only one of them was concrete. + */ + int getOverloadIndex() { + exists(ClassOrInterface type, string name | + this = rank[result + 1](MethodDeclaration method, int i | + methodDeclaredInType(type, name, i, method) + | + method order by i + ) + ) + or + exists(ClassDefinition type | + this = rank[result + 1](ConstructorDeclaration ctor, int i | + ctor = type.getMemberByIndex(i) + | + ctor order by i + ) + ) + } +} + +/** + * Holds if the `index`th member of `type` is `method`, which has the given `name`. + */ +private predicate methodDeclaredInType( + ClassOrInterface type, string name, int index, MethodDeclaration method +) { + not method instanceof ConstructorDeclaration and // distinguish methods named "constructor" from the constructor + type.getMemberByIndex(index) = method and + method.getName() = name +} + +/** + * Holds if `type` has an overloaded method named `name`. + */ +private predicate hasOverloadedMethod(ClassOrInterface type, string name) { + exists(MethodDeclaration method | + method = type.getMethod(name) and + not method instanceof ConstructorDeclaration and + method.getOverloadIndex() > 0 + ) +} + +/** Holds if `type` has an overloaded constructor declaration. */ +private predicate hasOverloadedConstructor(ClassDefinition type) { + type.getConstructor().getOverloadIndex() > 0 +} + +/** Holds if `type` has an overloaded function call signature. */ +private predicate hasOverloadedFunctionCallSignature(ClassOrInterface type) { + type.getACallSignature().(FunctionCallSignature).getOverloadIndex() > 0 +} + +/** Holds if `type` has an overloaded constructor call signature. */ +private predicate hasOverloadedConstructorCallSignature(ClassOrInterface type) { + type.getACallSignature().(ConstructorCallSignature).getOverloadIndex() > 0 } /** @@ -1048,7 +1138,24 @@ class CallSignature extends @call_signature, MemberSignature { * } * ``` */ -class FunctionCallSignature extends @function_call_signature, CallSignature { } +class FunctionCallSignature extends @function_call_signature, CallSignature { + /** Gets the index of this function call signature among the function call signatures in the enclosing type. */ + int getOverloadIndex() { + exists(ClassOrInterface type | type = getDeclaringType() | + this = rank[result + 1](FunctionCallSignature sig, int i | + sig = type.getMemberByIndex(i) + | + sig order by i + ) + ) + } + + /** + * Holds if this function call signature is overloaded, that is, there are multiple function call + * signatures declared in the enclosing type. + */ + predicate isOverloaded() { hasOverloadedFunctionCallSignature(getDeclaringType()) } +} /** * A constructor call signature declared in an interface. @@ -1061,7 +1168,24 @@ class FunctionCallSignature extends @function_call_signature, CallSignature { } * } * ``` */ -class ConstructorCallSignature extends @constructor_call_signature, CallSignature { } +class ConstructorCallSignature extends @constructor_call_signature, CallSignature { + /** Gets the index of this constructor call signature among the constructor call signatures in the enclosing type. */ + int getOverloadIndex() { + exists(ClassOrInterface type | type = getDeclaringType() | + this = rank[result + 1](ConstructorCallSignature sig, int i | + sig = type.getMemberByIndex(i) + | + sig order by i + ) + ) + } + + /** + * Holds if this constructor call signature is overloaded, that is, there are multiple constructor call + * signatures declared in the enclosing type. + */ + predicate isOverloaded() { hasOverloadedConstructorCallSignature(getDeclaringType()) } +} /** * An index signature declared in an interface. diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.expected b/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.expected index 1d9aa880e89..bfb6ff5e6af 100644 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.expected @@ -3,6 +3,12 @@ test_CallSignature | tst.ts:8:3:8:21 | new (x: number): C; | interface I | tst.ts:8:3:8:21 | new (x: number): C; | abstract | | tst.ts:13:3:13:22 | (x: number): number; | anonymous interface | tst.ts:13:3:13:22 | (x: number): number; | abstract | | tst.ts:14:3:14:21 | new (x: number): C; | anonymous interface | tst.ts:14:3:14:21 | new (x: number): C; | abstract | +| tst.ts:47:3:47:14 | (x: number); | interface ICallSigOverloads | tst.ts:47:3:47:14 | (x: number); | abstract | +| tst.ts:48:3:48:17 | new(x: number); | interface ICallSigOverloads | tst.ts:48:3:48:17 | new(x: number); | abstract | +| tst.ts:49:3:49:14 | (x: string); | interface ICallSigOverloads | tst.ts:49:3:49:14 | (x: string); | abstract | +| tst.ts:50:3:50:17 | new(x: string); | interface ICallSigOverloads | tst.ts:50:3:50:17 | new(x: string); | abstract | +| tst.ts:52:3:52:17 | new(x: number); | interface ICallSigOverloads | tst.ts:52:3:52:17 | new(x: number); | abstract | +| tst.ts:53:3:53:14 | (x: number); | interface ICallSigOverloads | tst.ts:53:3:53:14 | (x: number); | abstract | test_IndexSignature | tst.ts:9:3:9:22 | [x: number]: string; | interface I | tst.ts:9:3:9:22 | [x: number]: string; | abstract | | tst.ts:15:3:15:22 | [x: number]: string; | anonymous interface | tst.ts:15:3:15:22 | [x: number]: string; | abstract | @@ -10,3 +16,51 @@ test_MethodDeclarations | tst.ts:1:18:1:17 | constructor() {} | Method constructor in class C | | tst.ts:2:3:2:31 | abstrac ... number; | Method abstract in class C | | tst.ts:3:3:3:30 | abstrac ... er): C; | Method new in class C | +| tst.ts:19:3:19:17 | foo(x: number); | Method foo in interface IOverloads | +| tst.ts:20:3:20:17 | foo(x: string); | Method foo in interface IOverloads | +| tst.ts:21:3:21:8 | bar(); | Method bar in interface IOverloads | +| tst.ts:22:3:22:17 | foo(x: number); | Method foo in interface IOverloads | +| tst.ts:25:27:25:26 | constructor() {} | Method constructor in class COverloads | +| tst.ts:26:3:26:26 | abstrac ... umber); | Method foo in class COverloads | +| tst.ts:27:3:27:26 | abstrac ... tring); | Method foo in class COverloads | +| tst.ts:28:3:28:26 | abstrac ... umber); | Method foo in class COverloads | +| tst.ts:30:3:30:17 | bar(x: number); | Method bar in class COverloads | +| tst.ts:31:3:31:17 | bar(x: string); | Method bar in class COverloads | +| tst.ts:33:3:33:11 | bar(x) {} | Method bar in class COverloads | +| tst.ts:37:3:37:25 | constru ... umber); | Method constructor in class ConstructorOverloads | +| tst.ts:38:3:38:25 | constru ... tring); | Method constructor in class ConstructorOverloads | +| tst.ts:40:3:40:25 | constru ... umber); | Method constructor in class ConstructorOverloads | +| tst.ts:42:3:42:29 | ["const ... tring); | Method constructor in class ConstructorOverloads | +| tst.ts:43:3:43:29 | ["const ... umber); | Method constructor in class ConstructorOverloads | +test_MethodOverload +| tst.ts:1:18:1:17 | constructor() {} | 0 | false | +| tst.ts:2:3:2:31 | abstrac ... number; | 0 | false | +| tst.ts:3:3:3:30 | abstrac ... er): C; | 0 | false | +| tst.ts:19:3:19:17 | foo(x: number); | 0 | true | +| tst.ts:20:3:20:17 | foo(x: string); | 1 | true | +| tst.ts:21:3:21:8 | bar(); | 0 | false | +| tst.ts:22:3:22:17 | foo(x: number); | 2 | true | +| tst.ts:25:27:25:26 | constructor() {} | 0 | false | +| tst.ts:26:3:26:26 | abstrac ... umber); | 0 | true | +| tst.ts:27:3:27:26 | abstrac ... tring); | 1 | true | +| tst.ts:28:3:28:26 | abstrac ... umber); | 2 | true | +| tst.ts:30:3:30:17 | bar(x: number); | 0 | true | +| tst.ts:31:3:31:17 | bar(x: string); | 1 | true | +| tst.ts:33:3:33:11 | bar(x) {} | 2 | true | +| tst.ts:37:3:37:25 | constru ... umber); | 0 | true | +| tst.ts:38:3:38:25 | constru ... tring); | 1 | true | +| tst.ts:40:3:40:25 | constru ... umber); | 2 | true | +| tst.ts:42:3:42:29 | ["const ... tring); | 0 | true | +| tst.ts:43:3:43:29 | ["const ... umber); | 1 | true | +test_FunctionCallSigOverload +| tst.ts:7:3:7:22 | (x: number): number; | 0 | false | +| tst.ts:13:3:13:22 | (x: number): number; | 0 | false | +| tst.ts:47:3:47:14 | (x: number); | 0 | true | +| tst.ts:49:3:49:14 | (x: string); | 1 | true | +| tst.ts:53:3:53:14 | (x: number); | 2 | true | +test_ConstructorCallSigOverload +| tst.ts:8:3:8:21 | new (x: number): C; | 0 | false | +| tst.ts:14:3:14:21 | new (x: number): C; | 0 | false | +| tst.ts:48:3:48:17 | new(x: number); | 0 | true | +| tst.ts:50:3:50:17 | new(x: string); | 1 | true | +| tst.ts:52:3:52:17 | new(x: number); | 2 | true | diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.ql b/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.ql index 174f163627f..f3d79f91feb 100644 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.ql +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatures/test.ql @@ -15,3 +15,18 @@ query predicate test_IndexSignature(IndexSignature sig, string declType, ASTNode query predicate test_MethodDeclarations(MethodDeclaration method, string descr) { descr = "Method " + method.getName() + " in " + method.getDeclaringType().describe() } + +query predicate test_MethodOverload(MethodDeclaration method, int index, boolean overloaded) { + index = method.getOverloadIndex() and + if method.isOverloaded() then overloaded = true else overloaded = false +} + +query predicate test_FunctionCallSigOverload(FunctionCallSignature sig, int index, boolean overloaded) { + index = sig.getOverloadIndex() and + if sig.isOverloaded() then overloaded = true else overloaded = false +} + +query predicate test_ConstructorCallSigOverload(ConstructorCallSignature sig, int index, boolean overloaded) { + index = sig.getOverloadIndex() and + if sig.isOverloaded() then overloaded = true else overloaded = false +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatures/tst.ts b/javascript/ql/test/library-tests/TypeScript/CallSignatures/tst.ts index 0d93e8f6c9a..91ad9ff9fcc 100644 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatures/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatures/tst.ts @@ -14,3 +14,41 @@ var x : { new (x: number): C; [x: number]: string; } + +interface IOverloads { + foo(x: number); + foo(x: string); + bar(); + foo(x: number); +} + +abstract class COverloads { + abstract foo(x: number); + abstract foo(x: string); + abstract foo(x: number); + + bar(x: number); + bar(x: string); + x = 45; + bar(x) {}; +} + +declare class ConstructorOverloads { + constructor(x: number); + constructor(x: string); + x: number; + constructor(x: number); + + ["constructor"](x: string); + ["constructor"](x: number); +} + +interface ICallSigOverloads { + (x: number); + new(x: number); + (x: string); + new(x: string); + field: number; + new(x: number); + (x: number); +} From 405d43d53957f5a8a3554049c70f8f5ca246ba0e Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 18 Sep 2019 12:16:50 +0100 Subject: [PATCH 0242/1227] JS: Merge CallSignatureTypes test --- .../CallSignatureTypes/ExprSignatures.ql | 14 -------------- .../CallSignatureTypes/Signatures.expected | 7 ------- .../CallSignatureTypes/Signatures.ql | 4 ---- .../{ExprSignatures.expected => test.expected} | 9 +++++++++ .../TypeScript/CallSignatureTypes/test.ql | 18 ++++++++++++++++++ 5 files changed, 27 insertions(+), 25 deletions(-) delete mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/ExprSignatures.ql delete mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/Signatures.expected delete mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/Signatures.ql rename javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/{ExprSignatures.expected => test.expected} (74%) create mode 100644 javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.ql diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/ExprSignatures.ql b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/ExprSignatures.ql deleted file mode 100644 index affea425be8..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/ExprSignatures.ql +++ /dev/null @@ -1,14 +0,0 @@ -import javascript - -string getASignatureOrElseType(Type t) { - result = t.getASignature(_).toString() - or - not exists(t.getASignature(_)) and - result = t.toString() -} - -from Expr expr -where - not exists(MethodDeclaration decl | decl.getNameExpr() = expr) and - not exists(DotExpr dot | expr = dot.getPropertyNameExpr()) -select expr, getASignatureOrElseType(expr.getType()) diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/Signatures.expected b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/Signatures.expected deleted file mode 100644 index 35f91c7292a..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/Signatures.expected +++ /dev/null @@ -1,7 +0,0 @@ -| Callable | function | 0 | (x: number): string | -| Newable | constructor | 0 | new (x: number): any | -| OverloadedCallable | function | 0 | (x: number): number | -| OverloadedCallable | function | 1 | (x: string): string | -| OverloadedCallable | function | 2 | (x: any): any | -| OverloadedNewable | constructor | 0 | new (x: number): OverloadedNewable | -| OverloadedNewable | constructor | 1 | new (x: any): any | diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/Signatures.ql b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/Signatures.ql deleted file mode 100644 index 6f5032997da..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/Signatures.ql +++ /dev/null @@ -1,4 +0,0 @@ -import javascript - -from TypeReference type, SignatureKind kind, int n -select type, kind, n, type.getSignature(kind, n) diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/ExprSignatures.expected b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected similarity index 74% rename from javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/ExprSignatures.expected rename to javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected index bd521857919..ae9b5537990 100644 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/ExprSignatures.expected +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected @@ -1,3 +1,4 @@ +test_ExprSignature | tst.ts:2:4:2:4 | x | number | | tst.ts:6:4:6:4 | x | number | | tst.ts:7:4:7:4 | x | string | @@ -29,3 +30,11 @@ | tst.ts:41:10:41:17 | g.method | (x: string): string | | tst.ts:41:10:41:24 | g.method("foo") | string | | tst.ts:41:19:41:23 | "foo" | "foo" | +test_TypeReferenceSig +| Callable | function | 0 | (x: number): string | +| Newable | constructor | 0 | new (x: number): any | +| OverloadedCallable | function | 0 | (x: number): number | +| OverloadedCallable | function | 1 | (x: string): string | +| OverloadedCallable | function | 2 | (x: any): any | +| OverloadedNewable | constructor | 0 | new (x: number): OverloadedNewable | +| OverloadedNewable | constructor | 1 | new (x: any): any | diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.ql b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.ql new file mode 100644 index 00000000000..17988e38abc --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.ql @@ -0,0 +1,18 @@ +import javascript + +string getASignatureOrElseType(Type t) { + result = t.getASignature(_).toString() + or + not exists(t.getASignature(_)) and + result = t.toString() +} + +query predicate test_ExprSignature(Expr expr, string type) { + not exists(MethodDeclaration decl | decl.getNameExpr() = expr) and + not exists(DotExpr dot | expr = dot.getPropertyNameExpr()) and + type = getASignatureOrElseType(expr.getType()) +} + +query predicate test_TypeReferenceSig(TypeReference type, SignatureKind kind, int n, CallSignatureType sig) { + sig = type.getSignature(kind, n) +} From 999d10e1f070c4d917ac63627435e34f4f08c3a0 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 18 Sep 2019 12:29:51 +0100 Subject: [PATCH 0243/1227] JS: Use consistent indentation --- .../lib/typescript/src/ast_extractor.ts | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/javascript/extractor/lib/typescript/src/ast_extractor.ts b/javascript/extractor/lib/typescript/src/ast_extractor.ts index 182d8c98a50..6aa58507c85 100644 --- a/javascript/extractor/lib/typescript/src/ast_extractor.ts +++ b/javascript/extractor/lib/typescript/src/ast_extractor.ts @@ -295,54 +295,54 @@ function isNamedNodeWithSymbol(node: ts.Node): node is NamedNodeWithSymbol { */ function isTypedNode(node: ts.Node): boolean { switch (node.kind) { - case ts.SyntaxKind.ArrayLiteralExpression: - case ts.SyntaxKind.ArrowFunction: - case ts.SyntaxKind.AsExpression: - case ts.SyntaxKind.AwaitExpression: - case ts.SyntaxKind.BinaryExpression: - case ts.SyntaxKind.CallExpression: - case ts.SyntaxKind.ClassExpression: - case ts.SyntaxKind.CommaListExpression: - case ts.SyntaxKind.ConditionalExpression: - case ts.SyntaxKind.DeleteExpression: - case ts.SyntaxKind.ElementAccessExpression: - case ts.SyntaxKind.ExpressionStatement: - case ts.SyntaxKind.ExpressionWithTypeArguments: - case ts.SyntaxKind.FalseKeyword: - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.FunctionExpression: - case ts.SyntaxKind.Identifier: - case ts.SyntaxKind.JsxExpression: - case ts.SyntaxKind.LiteralType: - case ts.SyntaxKind.NewExpression: - case ts.SyntaxKind.NonNullExpression: - case ts.SyntaxKind.NoSubstitutionTemplateLiteral: - case ts.SyntaxKind.NumericLiteral: - case ts.SyntaxKind.ObjectKeyword: - case ts.SyntaxKind.ObjectLiteralExpression: - case ts.SyntaxKind.OmittedExpression: - case ts.SyntaxKind.ParenthesizedExpression: - case ts.SyntaxKind.PartiallyEmittedExpression: - case ts.SyntaxKind.PostfixUnaryExpression: - case ts.SyntaxKind.PrefixUnaryExpression: - case ts.SyntaxKind.PropertyAccessExpression: - case ts.SyntaxKind.RegularExpressionLiteral: - case ts.SyntaxKind.StringLiteral: - case ts.SyntaxKind.TaggedTemplateExpression: - case ts.SyntaxKind.TemplateExpression: - case ts.SyntaxKind.TemplateHead: - case ts.SyntaxKind.TemplateMiddle: - case ts.SyntaxKind.TemplateSpan: - case ts.SyntaxKind.TemplateTail: - case ts.SyntaxKind.TrueKeyword: - case ts.SyntaxKind.TypeAssertionExpression: - case ts.SyntaxKind.TypeLiteral: - case ts.SyntaxKind.TypeOfExpression: - case ts.SyntaxKind.VoidExpression: - case ts.SyntaxKind.YieldExpression: - return true; - default: - return ts.isTypeNode(node); + case ts.SyntaxKind.ArrayLiteralExpression: + case ts.SyntaxKind.ArrowFunction: + case ts.SyntaxKind.AsExpression: + case ts.SyntaxKind.AwaitExpression: + case ts.SyntaxKind.BinaryExpression: + case ts.SyntaxKind.CallExpression: + case ts.SyntaxKind.ClassExpression: + case ts.SyntaxKind.CommaListExpression: + case ts.SyntaxKind.ConditionalExpression: + case ts.SyntaxKind.DeleteExpression: + case ts.SyntaxKind.ElementAccessExpression: + case ts.SyntaxKind.ExpressionStatement: + case ts.SyntaxKind.ExpressionWithTypeArguments: + case ts.SyntaxKind.FalseKeyword: + case ts.SyntaxKind.FunctionDeclaration: + case ts.SyntaxKind.FunctionExpression: + case ts.SyntaxKind.Identifier: + case ts.SyntaxKind.JsxExpression: + case ts.SyntaxKind.LiteralType: + case ts.SyntaxKind.NewExpression: + case ts.SyntaxKind.NonNullExpression: + case ts.SyntaxKind.NoSubstitutionTemplateLiteral: + case ts.SyntaxKind.NumericLiteral: + case ts.SyntaxKind.ObjectKeyword: + case ts.SyntaxKind.ObjectLiteralExpression: + case ts.SyntaxKind.OmittedExpression: + case ts.SyntaxKind.ParenthesizedExpression: + case ts.SyntaxKind.PartiallyEmittedExpression: + case ts.SyntaxKind.PostfixUnaryExpression: + case ts.SyntaxKind.PrefixUnaryExpression: + case ts.SyntaxKind.PropertyAccessExpression: + case ts.SyntaxKind.RegularExpressionLiteral: + case ts.SyntaxKind.StringLiteral: + case ts.SyntaxKind.TaggedTemplateExpression: + case ts.SyntaxKind.TemplateExpression: + case ts.SyntaxKind.TemplateHead: + case ts.SyntaxKind.TemplateMiddle: + case ts.SyntaxKind.TemplateSpan: + case ts.SyntaxKind.TemplateTail: + case ts.SyntaxKind.TrueKeyword: + case ts.SyntaxKind.TypeAssertionExpression: + case ts.SyntaxKind.TypeLiteral: + case ts.SyntaxKind.TypeOfExpression: + case ts.SyntaxKind.VoidExpression: + case ts.SyntaxKind.YieldExpression: + return true; + default: + return ts.isTypeNode(node); } } From b4f67f20af5897a6690f204e2d03dee97b78a791 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 18 Sep 2019 14:49:21 +0100 Subject: [PATCH 0244/1227] JS: Extract types and signatures for functions --- .../lib/typescript/src/ast_extractor.ts | 19 +++++ .../semmle/js/ast/AFunctionExpression.java | 11 +++ .../semmle/js/ast/FunctionDeclaration.java | 22 ++++++ .../src/com/semmle/js/ast/IFunction.java | 14 +++- .../com/semmle/js/extractor/ASTExtractor.java | 7 ++ .../js/parser/TypeScriptASTConverter.java | 69 ++++++++++++------- .../ql/src/semmle/javascript/Functions.qll | 7 ++ .../ql/src/semmlecode.javascript.dbscheme | 5 ++ .../CallSignatureTypes/test.expected | 34 +++++++++ .../TypeScript/CallSignatureTypes/test.ql | 4 ++ .../TypeScript/CallSignatureTypes/tst.ts | 5 ++ 11 files changed, 172 insertions(+), 25 deletions(-) diff --git a/javascript/extractor/lib/typescript/src/ast_extractor.ts b/javascript/extractor/lib/typescript/src/ast_extractor.ts index 6aa58507c85..3aa40347f2c 100644 --- a/javascript/extractor/lib/typescript/src/ast_extractor.ts +++ b/javascript/extractor/lib/typescript/src/ast_extractor.ts @@ -22,6 +22,7 @@ export interface AugmentedNode extends ts.Node { $symbol?: number; $resolvedSignature?: number; $overloadIndex?: number; + $declaredSignature?: number; } export type AugmentedPos = number; @@ -263,6 +264,17 @@ export function augmentAst(ast: AugmentedSourceFile, code: string, project: Proj namePart.$symbol = typeTable.getSymbolId(symbol); } } + if (ts.isFunctionLike(node)) { + let signature = typeChecker.getSignatureFromDeclaration(node); + if (signature != null) { + let kind = ts.isConstructSignatureDeclaration(node) || ts.isConstructorDeclaration(node) + ? ts.SignatureKind.Construct : ts.SignatureKind.Call; + let id = typeTable.getSignatureId(kind, signature); + if (id != null) { + (node as AugmentedNode).$declaredSignature = id; + } + } + } } } } @@ -302,8 +314,10 @@ function isTypedNode(node: ts.Node): boolean { case ts.SyntaxKind.BinaryExpression: case ts.SyntaxKind.CallExpression: case ts.SyntaxKind.ClassExpression: + case ts.SyntaxKind.ClassDeclaration: case ts.SyntaxKind.CommaListExpression: case ts.SyntaxKind.ConditionalExpression: + case ts.SyntaxKind.Constructor: case ts.SyntaxKind.DeleteExpression: case ts.SyntaxKind.ElementAccessExpression: case ts.SyntaxKind.ExpressionStatement: @@ -311,9 +325,13 @@ function isTypedNode(node: ts.Node): boolean { case ts.SyntaxKind.FalseKeyword: case ts.SyntaxKind.FunctionDeclaration: case ts.SyntaxKind.FunctionExpression: + case ts.SyntaxKind.GetAccessor: case ts.SyntaxKind.Identifier: + case ts.SyntaxKind.IndexSignature: case ts.SyntaxKind.JsxExpression: case ts.SyntaxKind.LiteralType: + case ts.SyntaxKind.MethodDeclaration: + case ts.SyntaxKind.MethodSignature: case ts.SyntaxKind.NewExpression: case ts.SyntaxKind.NonNullExpression: case ts.SyntaxKind.NoSubstitutionTemplateLiteral: @@ -327,6 +345,7 @@ function isTypedNode(node: ts.Node): boolean { case ts.SyntaxKind.PrefixUnaryExpression: case ts.SyntaxKind.PropertyAccessExpression: case ts.SyntaxKind.RegularExpressionLiteral: + case ts.SyntaxKind.SetAccessor: case ts.SyntaxKind.StringLiteral: case ts.SyntaxKind.TaggedTemplateExpression: case ts.SyntaxKind.TemplateExpression: diff --git a/javascript/extractor/src/com/semmle/js/ast/AFunctionExpression.java b/javascript/extractor/src/com/semmle/js/ast/AFunctionExpression.java index 55782e3b150..a8ab11342f1 100644 --- a/javascript/extractor/src/com/semmle/js/ast/AFunctionExpression.java +++ b/javascript/extractor/src/com/semmle/js/ast/AFunctionExpression.java @@ -12,6 +12,7 @@ import java.util.List; public abstract class AFunctionExpression extends Expression implements IFunction { private final AFunction fn; private int symbol = -1; + private int declaredSignature = -1; public AFunctionExpression( String type, @@ -144,4 +145,14 @@ public abstract class AFunctionExpression extends Expression implements IFunctio public void setSymbol(int symbol) { this.symbol = symbol; } + + @Override + public int getDeclaredSignatureId() { + return declaredSignature; + } + + @Override + public void setDeclaredSignatureId(int id) { + declaredSignature = id; + } } diff --git a/javascript/extractor/src/com/semmle/js/ast/FunctionDeclaration.java b/javascript/extractor/src/com/semmle/js/ast/FunctionDeclaration.java index 78d45dd430c..86dfb50e3c4 100644 --- a/javascript/extractor/src/com/semmle/js/ast/FunctionDeclaration.java +++ b/javascript/extractor/src/com/semmle/js/ast/FunctionDeclaration.java @@ -19,6 +19,8 @@ public class FunctionDeclaration extends Statement implements IFunction { private final AFunction fn; private final boolean hasDeclareKeyword; private int symbol = -1; + private int staticType = -1; + private int declaredSignature = -1; public FunctionDeclaration( SourceLocation loc, @@ -185,4 +187,24 @@ public class FunctionDeclaration extends Statement implements IFunction { public void setSymbol(int symbol) { this.symbol = symbol; } + + @Override + public int getStaticTypeId() { + return staticType; + } + + @Override + public void setStaticTypeId(int id) { + staticType = id; + } + + @Override + public int getDeclaredSignatureId() { + return declaredSignature; + } + + @Override + public void setDeclaredSignatureId(int id) { + declaredSignature = id; + } } diff --git a/javascript/extractor/src/com/semmle/js/ast/IFunction.java b/javascript/extractor/src/com/semmle/js/ast/IFunction.java index 089e3718f10..0b20af60fc0 100644 --- a/javascript/extractor/src/com/semmle/js/ast/IFunction.java +++ b/javascript/extractor/src/com/semmle/js/ast/IFunction.java @@ -3,11 +3,12 @@ package com.semmle.js.ast; import com.semmle.ts.ast.DecoratorList; import com.semmle.ts.ast.INodeWithSymbol; import com.semmle.ts.ast.ITypeExpression; +import com.semmle.ts.ast.ITypedAstNode; import com.semmle.ts.ast.TypeParameter; import java.util.List; /** A function declaration or expression. */ -public interface IFunction extends IStatementContainer, INodeWithSymbol { +public interface IFunction extends IStatementContainer, INodeWithSymbol, ITypedAstNode { /** The function name; may be null for function expressions. */ public Identifier getId(); @@ -63,4 +64,15 @@ public interface IFunction extends IStatementContainer, INodeWithSymbol { public List getParameterDecorators(); public boolean hasDeclareKeyword(); + + /** + * Gets the type signature of this function as determined by the TypeScript compiler, or -1 if no + * call signature was extracted. + * + *

    The ID refers to a signature in a table that is extracted on a per-project basis, and the + * meaning of this type ID is not available at the AST level. + */ + public int getDeclaredSignatureId(); + + public void setDeclaredSignatureId(int id); } diff --git a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java index 52a0adc122b..2bf8460cd6c 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java @@ -762,6 +762,7 @@ public class ASTExtractor { trapwriter.addTuple("hasDeclareKeyword", key); } extractFunction(nd, key); + emitStaticType(nd, key); return key; } @@ -833,7 +834,13 @@ public class ASTExtractor { extractParameterDefaultsAndTypes(nd, key, i); extractFunctionAttributes(nd, key); + + // Extract associated symbol and signature emitNodeSymbol(nd, key); + if (nd.getDeclaredSignatureId() != -1) { + Label signatureKey = trapwriter.globalID("signature;" + nd.getDeclaredSignatureId()); + trapwriter.addTuple("declared_function_signature", key, signatureKey); + } boolean oldIsStrict = isStrict; isStrict = bodyIsStrict; diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index dc36d57bf30..de9042b6d36 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -42,6 +42,7 @@ import com.semmle.js.ast.ForOfStatement; import com.semmle.js.ast.ForStatement; import com.semmle.js.ast.FunctionDeclaration; import com.semmle.js.ast.FunctionExpression; +import com.semmle.js.ast.IFunction; import com.semmle.js.ast.INode; import com.semmle.js.ast.IPattern; import com.semmle.js.ast.Identifier; @@ -670,6 +671,13 @@ public class TypeScriptASTConverter { attachSymbolInformation(node, json); } + /** Attached the declared call signature to a function. */ + private void attachDeclaredSignature(IFunction node, JsonObject json) { + if (json.has("$declaredSignature")) { + node.setDeclaredSignatureId(json.get("$declaredSignature").getAsInt()); + } + } + /** * Convert the given array of TypeScript AST nodes into a list of JavaScript AST nodes, skipping * any {@code null} elements. @@ -786,15 +794,18 @@ public class TypeScriptASTConverter { } private Node convertArrowFunction(JsonObject node, SourceLocation loc) throws ParseError { - return new ArrowFunctionExpression( - loc, - convertParameters(node), - convertChild(node, "body"), - false, - hasModifier(node, "AsyncKeyword"), - convertChildrenNotNull(node, "typeParameters"), - convertParameterTypes(node), - convertChildAsType(node, "type")); + ArrowFunctionExpression function = + new ArrowFunctionExpression( + loc, + convertParameters(node), + convertChild(node, "body"), + false, + hasModifier(node, "AsyncKeyword"), + convertChildrenNotNull(node, "typeParameters"), + convertParameterTypes(node), + convertChildAsType(node, "type")); + attachDeclaredSignature(function, node); + return function; } private Node convertAwaitExpression(JsonObject node, SourceLocation loc) throws ParseError { @@ -1044,6 +1055,8 @@ public class TypeScriptASTConverter { null, null); attachSymbolInformation(value, node); + attachStaticType(value, node); + attachDeclaredSignature(value, node); List parameterFields = convertParameterFields(node); return new MethodDefinition(loc, flags, methodKind, key, value, parameterFields); } @@ -1234,6 +1247,8 @@ public class TypeScriptASTConverter { returnType, thisParam); attachSymbolInformation(function, node); + attachStaticType(function, node); + attachDeclaredSignature(function, node); return fixExports(loc, function); } @@ -1247,18 +1262,22 @@ public class TypeScriptASTConverter { List paramDecorators = convertParameterDecorators(node); ITypeExpression returnType = convertChildAsType(node, "type"); ITypeExpression thisParam = convertThisParameterType(node); - return new FunctionExpression( - loc, - fnId, - params, - fnbody, - generator, - async, - convertChildrenNotNull(node, "typeParameters"), - paramTypes, - paramDecorators, - returnType, - thisParam); + FunctionExpression function = + new FunctionExpression( + loc, + fnId, + params, + fnbody, + generator, + async, + convertChildrenNotNull(node, "typeParameters"), + paramTypes, + paramDecorators, + returnType, + thisParam); + attachStaticType(function, node); + attachDeclaredSignature(function, node); + return function; } private Node convertFunctionType(JsonObject node, SourceLocation loc) throws ParseError { @@ -1591,7 +1610,7 @@ public class TypeScriptASTConverter { List paramDecorators = convertParameterDecorators(node); List typeParameters = convertChildrenNotNull(node, "typeParameters"); ITypeExpression thisType = convertThisParameterType(node); - FunctionExpression method = + FunctionExpression function = new FunctionExpression( loc, null, @@ -1604,8 +1623,10 @@ public class TypeScriptASTConverter { paramDecorators, returnType, thisType); - attachSymbolInformation(method, node); - return method; + attachSymbolInformation(function, node); + attachStaticType(function, node); + attachDeclaredSignature(function, node); + return function; } private Node convertNamespaceDeclaration(JsonObject node, SourceLocation loc) throws ParseError { diff --git a/javascript/ql/src/semmle/javascript/Functions.qll b/javascript/ql/src/semmle/javascript/Functions.qll index be7eef0ed19..c8f41e76570 100644 --- a/javascript/ql/src/semmle/javascript/Functions.qll +++ b/javascript/ql/src/semmle/javascript/Functions.qll @@ -416,6 +416,13 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine * This predicate is only populated for files extracted with full TypeScript extraction. */ CanonicalFunctionName getCanonicalName() { ast_node_symbol(this, result) } + + /** + * Gets the call signature of this function, as determined by the TypeScript compiler, if any. + */ + CallSignatureType getCallSignature() { + declared_function_signature(this, result) + } } /** diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme b/javascript/ql/src/semmlecode.javascript.dbscheme index 56b74a6808d..ab0dab3b55b 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme +++ b/javascript/ql/src/semmlecode.javascript.dbscheme @@ -641,6 +641,11 @@ ast_node_type( unique int node: @typed_ast_node ref, int typ: @type ref); +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + invoke_expr_signature( unique int node: @invokeexpr ref, int sig: @signature_type ref diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected index ae9b5537990..22a187fbe8b 100644 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected @@ -6,9 +6,19 @@ test_ExprSignature | tst.ts:12:8:12:8 | x | number | | tst.ts:16:8:16:8 | x | number | | tst.ts:17:8:17:8 | x | any | +| tst.ts:21:3:21:28 | method( ... string; | (x: number): string | | tst.ts:21:10:21:10 | x | number | +| tst.ts:23:3:23:38 | overloa ... number; | (x: any): any | +| tst.ts:23:3:23:38 | overloa ... number; | (x: number): number | +| tst.ts:23:3:23:38 | overloa ... number; | (x: string): string | | tst.ts:23:20:23:20 | x | number | +| tst.ts:24:3:24:38 | overloa ... string; | (x: any): any | +| tst.ts:24:3:24:38 | overloa ... string; | (x: number): number | +| tst.ts:24:3:24:38 | overloa ... string; | (x: string): string | | tst.ts:24:20:24:20 | x | string | +| tst.ts:25:3:25:32 | overloa ... ): any; | (x: any): any | +| tst.ts:25:3:25:32 | overloa ... ): any; | (x: number): number | +| tst.ts:25:3:25:32 | overloa ... ): any; | (x: string): string | | tst.ts:25:20:25:20 | x | any | | tst.ts:28:5:28:5 | m | Method | | tst.ts:29:1:29:1 | m | Method | @@ -22,7 +32,9 @@ test_ExprSignature | tst.ts:30:1:30:25 | m.overl ... ("foo") | string | | tst.ts:30:20:30:24 | "foo" | "foo" | | tst.ts:33:3:33:10 | callback | (x: number): string | +| tst.ts:33:13:33:33 | (x: num ... string | (x: number): string | | tst.ts:33:14:33:14 | x | number | +| tst.ts:37:3:37:18 | method(x: T): T; | (x: T): T | | tst.ts:37:10:37:10 | x | T | | tst.ts:40:10:40:12 | foo | (g: Generic): string | | tst.ts:40:14:40:14 | g | Generic | @@ -30,6 +42,11 @@ test_ExprSignature | tst.ts:41:10:41:17 | g.method | (x: string): string | | tst.ts:41:10:41:24 | g.method("foo") | string | | tst.ts:41:19:41:23 | "foo" | "foo" | +| tst.ts:44:15:44:15 | C | C | +| tst.ts:45:3:45:25 | constru ... tring); | any | +| tst.ts:45:15:45:15 | x | string | +| tst.ts:46:3:46:25 | constru ... umber); | any | +| tst.ts:46:15:46:15 | x | number | test_TypeReferenceSig | Callable | function | 0 | (x: number): string | | Newable | constructor | 0 | new (x: number): any | @@ -38,3 +55,20 @@ test_TypeReferenceSig | OverloadedCallable | function | 2 | (x: any): any | | OverloadedNewable | constructor | 0 | new (x: number): OverloadedNewable | | OverloadedNewable | constructor | 1 | new (x: any): any | +test_FunctionCallSig +| tst.ts:2:3:2:22 | (x: number): string; | (x: number): string | +| tst.ts:6:3:6:22 | (x: number): number; | (x: number): number | +| tst.ts:7:3:7:22 | (x: string): string; | (x: string): string | +| tst.ts:8:3:8:16 | (x: any): any; | (x: any): any | +| tst.ts:12:3:12:23 | new (x: ... ): any; | new (x: number): any | +| tst.ts:16:3:16:37 | new (x: ... ewable; | new (x: number): OverloadedNewable | +| tst.ts:17:3:17:20 | new (x: any): any; | new (x: any): any | +| tst.ts:21:3:21:28 | method( ... string; | (x: number): string | +| tst.ts:23:3:23:38 | overloa ... number; | (x: number): number | +| tst.ts:24:3:24:38 | overloa ... string; | (x: string): string | +| tst.ts:25:3:25:32 | overloa ... ): any; | (x: any): any | +| tst.ts:33:13:33:33 | (x: num ... string | (x: number): string | +| tst.ts:37:3:37:18 | method(x: T): T; | (x: T): T | +| tst.ts:40:1:42:1 | functio ... oo");\\n} | (g: Generic): string | +| tst.ts:45:3:45:25 | constru ... tring); | new (x: string): C | +| tst.ts:46:3:46:25 | constru ... umber); | new (x: number): C | diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.ql b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.ql index 17988e38abc..7ac2ae2a5f8 100644 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.ql +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.ql @@ -16,3 +16,7 @@ query predicate test_ExprSignature(Expr expr, string type) { query predicate test_TypeReferenceSig(TypeReference type, SignatureKind kind, int n, CallSignatureType sig) { sig = type.getSignature(kind, n) } + +query predicate test_FunctionCallSig(Function f, CallSignatureType sig) { + sig = f.getCallSignature() +} diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/tst.ts b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/tst.ts index eaf73422da0..84d3b004ed7 100644 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/tst.ts @@ -40,3 +40,8 @@ interface Generic { function foo(g: Generic) { return g.method("foo"); } + +declare class C { + constructor(x: string); + constructor(x: number); +} From cafa9edf691ec223bbfb4d2f6eae140ddb6020ca Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 18 Sep 2019 15:42:42 +0100 Subject: [PATCH 0245/1227] JS: upgrade script, stats, version string --- .../src/com/semmle/js/extractor/Main.java | 17 +- .../src/semmlecode.javascript.dbscheme.stats | 63 + .../old.dbscheme | 1167 ++++++++++++++++ .../semmlecode.javascript.dbscheme | 1172 +++++++++++++++++ .../upgrade.properties | 2 + 5 files changed, 2413 insertions(+), 8 deletions(-) create mode 100644 javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/old.dbscheme create mode 100644 javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/semmlecode.javascript.dbscheme create mode 100644 javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/upgrade.properties diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 2b3d64228e0..466e93639eb 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -1,5 +1,13 @@ package com.semmle.js.extractor; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + import com.semmle.js.extractor.ExtractorConfig.HTMLHandling; import com.semmle.js.extractor.ExtractorConfig.Platform; import com.semmle.js.extractor.ExtractorConfig.SourceType; @@ -23,13 +31,6 @@ import com.semmle.util.language.LegacyLanguage; import com.semmle.util.process.ArgsParser; import com.semmle.util.process.ArgsParser.FileMode; import com.semmle.util.trap.TrapWriter; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; /** The main entry point of the JavaScript extractor. */ public class Main { @@ -37,7 +38,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2019-09-13"; + public static final String EXTRACTOR_VERSION = "2019-09-18"; public static final Pattern NEWLINE = Pattern.compile("\n"); diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme.stats b/javascript/ql/src/semmlecode.javascript.dbscheme.stats index 01026d1ec3e..5f638b48c37 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme.stats +++ b/javascript/ql/src/semmlecode.javascript.dbscheme.stats @@ -16715,6 +16715,69 @@ +declared_function_signature +62664 + + +node +62664 + + +sig +21731 + + + + +node +sig + + +12 + + +1 +2 +62664 + + + + + + +sig +node + + +12 + + +1 +2 +16826 + + +2 +3 +2358 + + +3 +6 +1683 + + +6 +10251 +864 + + + + + + + + invoke_expr_signature 140668 diff --git a/javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/old.dbscheme b/javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/old.dbscheme new file mode 100644 index 00000000000..56b74a6808d --- /dev/null +++ b/javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/old.dbscheme @@ -0,0 +1,1167 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +isExterns (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url; + +isModule (int tl: @toplevel ref); +isNodejs (int tl: @toplevel ref); +isES2015Module (int tl: @toplevel ref); +isClosureModule (int tl: @toplevel ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmtContainers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jumpTargets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmtparent = @stmt | @toplevel | @functionexpr | @arrowfunctionexpr; +@stmt_container = @toplevel | @function | @namespacedeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; + +case @stmt.kind of + 0 = @emptystmt +| 1 = @blockstmt +| 2 = @exprstmt +| 3 = @ifstmt +| 4 = @labeledstmt +| 5 = @breakstmt +| 6 = @continuestmt +| 7 = @withstmt +| 8 = @switchstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @trystmt +| 12 = @whilestmt +| 13 = @dowhilestmt +| 14 = @forstmt +| 15 = @forinstmt +| 16 = @debuggerstmt +| 17 = @functiondeclstmt +| 18 = @vardeclstmt +| 19 = @case +| 20 = @catchclause +| 21 = @forofstmt +| 22 = @constdeclstmt +| 23 = @letstmt +| 24 = @legacy_letstmt +| 25 = @foreachstmt +| 26 = @classdeclstmt +| 27 = @importdeclaration +| 28 = @exportalldeclaration +| 29 = @exportdefaultdeclaration +| 30 = @exportnameddeclaration +| 31 = @namespacedeclaration +| 32 = @importequalsdeclaration +| 33 = @exportassigndeclaration +| 34 = @interfacedeclaration +| 35 = @typealiasdeclaration +| 36 = @enumdeclaration +| 37 = @externalmoduledeclaration +| 38 = @exportasnamespacedeclaration +| 39 = @globalaugmentationdeclaration +; + +@declstmt = @vardeclstmt | @constdeclstmt | @letstmt | @legacy_letstmt; + +@exportdeclaration = @exportalldeclaration | @exportdefaultdeclaration | @exportnameddeclaration; + +@namespacedefinition = @namespacedeclaration | @enumdeclaration; +@typedefinition = @classdefinition | @interfacedeclaration | @enumdeclaration | @typealiasdeclaration | @enum_member; + +isInstantiated(unique int decl: @namespacedeclaration ref); + +@declarablestmt = @declstmt | @namespacedeclaration | @classdeclstmt | @functiondeclstmt | @enumdeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; +hasDeclareKeyword(unique int stmt: @declarablestmt ref); + +isForAwaitOf(unique int forof: @forofstmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @exprparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @exprortype ref); + +enclosingStmt (unique int expr: @exprortype ref, + int stmt: @stmt ref); + +exprContainers (unique int expr: @exprortype ref, + int container: @stmt_container ref); + +arraySize (unique int ae: @arraylike ref, + int sz: int ref); + +isDelegating (int yield: @yieldexpr ref); + +@exprorstmt = @expr | @stmt; +@exprortype = @expr | @typeexpr; +@exprparent = @exprorstmt | @property | @functiontypeexpr; +@arraylike = @arrayexpr | @arraypattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; + +case @expr.kind of + 0 = @label +| 1 = @nullliteral +| 2 = @booleanliteral +| 3 = @numberliteral +| 4 = @stringliteral +| 5 = @regexpliteral +| 6 = @thisexpr +| 7 = @arrayexpr +| 8 = @objexpr +| 9 = @functionexpr +| 10 = @seqexpr +| 11 = @conditionalexpr +| 12 = @newexpr +| 13 = @callexpr +| 14 = @dotexpr +| 15 = @indexexpr +| 16 = @negexpr +| 17 = @plusexpr +| 18 = @lognotexpr +| 19 = @bitnotexpr +| 20 = @typeofexpr +| 21 = @voidexpr +| 22 = @deleteexpr +| 23 = @eqexpr +| 24 = @neqexpr +| 25 = @eqqexpr +| 26 = @neqqexpr +| 27 = @ltexpr +| 28 = @leexpr +| 29 = @gtexpr +| 30 = @geexpr +| 31 = @lshiftexpr +| 32 = @rshiftexpr +| 33 = @urshiftexpr +| 34 = @addexpr +| 35 = @subexpr +| 36 = @mulexpr +| 37 = @divexpr +| 38 = @modexpr +| 39 = @bitorexpr +| 40 = @xorexpr +| 41 = @bitandexpr +| 42 = @inexpr +| 43 = @instanceofexpr +| 44 = @logandexpr +| 45 = @logorexpr +| 47 = @assignexpr +| 48 = @assignaddexpr +| 49 = @assignsubexpr +| 50 = @assignmulexpr +| 51 = @assigndivexpr +| 52 = @assignmodexpr +| 53 = @assignlshiftexpr +| 54 = @assignrshiftexpr +| 55 = @assignurshiftexpr +| 56 = @assignorexpr +| 57 = @assignxorexpr +| 58 = @assignandexpr +| 59 = @preincexpr +| 60 = @postincexpr +| 61 = @predecexpr +| 62 = @postdecexpr +| 63 = @parexpr +| 64 = @vardeclarator +| 65 = @arrowfunctionexpr +| 66 = @spreadelement +| 67 = @arraypattern +| 68 = @objectpattern +| 69 = @yieldexpr +| 70 = @taggedtemplateexpr +| 71 = @templateliteral +| 72 = @templateelement +| 73 = @arraycomprehensionexpr +| 74 = @generatorexpr +| 75 = @forincomprehensionblock +| 76 = @forofcomprehensionblock +| 77 = @legacy_letexpr +| 78 = @vardecl +| 79 = @proper_varaccess +| 80 = @classexpr +| 81 = @superexpr +| 82 = @newtargetexpr +| 83 = @namedimportspecifier +| 84 = @importdefaultspecifier +| 85 = @importnamespacespecifier +| 86 = @namedexportspecifier +| 87 = @expexpr +| 88 = @assignexpexpr +| 89 = @jsxelement +| 90 = @jsxqualifiedname +| 91 = @jsxemptyexpr +| 92 = @awaitexpr +| 93 = @functionsentexpr +| 94 = @decorator +| 95 = @exportdefaultspecifier +| 96 = @exportnamespacespecifier +| 97 = @bindexpr +| 98 = @externalmodulereference +| 99 = @dynamicimport +| 100 = @expressionwithtypearguments +| 101 = @prefixtypeassertion +| 102 = @astypeassertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigintliteral +| 107 = @nullishcoalescingexpr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @vardecl | @varaccess; + +@identifier = @label | @varref | @typeidentifier; + +@literal = @nullliteral | @booleanliteral | @numberliteral | @stringliteral | @regexpliteral | @bigintliteral; + +@propaccess = @dotexpr | @indexexpr; + +@invokeexpr = @newexpr | @callexpr; + +@unaryexpr = @negexpr | @plusexpr | @lognotexpr | @bitnotexpr | @typeofexpr | @voidexpr | @deleteexpr | @spreadelement; + +@equalitytest = @eqexpr | @neqexpr | @eqqexpr | @neqqexpr; + +@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr; + +@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; + +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr; + +@updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; + +@pattern = @varref | @arraypattern | @objectpattern; + +@comprehensionexpr = @arraycomprehensionexpr | @generatorexpr; + +@comprehensionblock = @forincomprehensionblock | @forofcomprehensionblock; + +@importspecifier = @namedimportspecifier | @importdefaultspecifier | @importnamespacespecifier; + +@exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; + +@typeassertion = @astypeassertion | @prefixtypeassertion; + +@classdefinition = @classdeclstmt | @classexpr; +@interfacedefinition = @interfacedeclaration | @interfacetypeexpr; +@classorinterface = @classdefinition | @interfacedefinition; + +@lexical_decl = @vardecl | @typedecl; +@lexical_access = @varaccess | @localtypeaccess | @localvartypeaccess | @localnamespaceaccess; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @globalscope +| 1 = @functionscope +| 2 = @catchscope +| 3 = @modulescope +| 4 = @blockscope +| 5 = @forscope +| 6 = @forinscope // for-of scopes work the same as for-in scopes +| 7 = @comprehensionblockscope +| 8 = @classexprscope +| 9 = @namespacescope +| 10 = @classdeclscope +| 11 = @interfacescope +| 12 = @typealiasscope +| 13 = @mappedtypescope +| 14 = @enumscope +| 15 = @externalmodulescope +| 16 = @conditionaltypescope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @functiondeclstmt | @functionexpr | @arrowfunctionexpr; + +@parameterized = @function | @catchclause; +@type_parameterized = @function | @classorinterface | @typealiasdeclaration | @mappedtypeexpr | @infertypeexpr; + +isGenerator (int fun: @function ref); +hasRestParameter (int fun: @function ref); +isAsync (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +isArgumentsObject (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @localvartypeaccess; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @vardecl ref, + int decl: @variable ref); + +@typebind_id = @localtypeaccess | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @typedecl | @vardecl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @vardecl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @localnamespaceaccess | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @objexpr | @objectpattern | @classdefinition | @jsxelement | @interfacedefinition | @enumdeclaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @vardeclarator; + +isComputed (int id: @property ref); +isMethod (int id: @property ref); +isStatic (int id: @property ref); +isAbstractMember (int id: @property ref); +isConstEnum (int id: @enumdeclaration ref); +isAbstractClass (int id: @classdeclstmt ref); + +hasPublicKeyword (int id: @property ref); +hasPrivateKeyword (int id: @property ref); +hasProtectedKeyword (int id: @property ref); +hasReadonlyKeyword (int id: @property ref); +isOptionalMember (int id: @property ref); +hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @functionexpr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @localtypeaccess +| 1 = @typedecl +| 2 = @keywordtypeexpr +| 3 = @stringliteraltypeexpr +| 4 = @numberliteraltypeexpr +| 5 = @booleanliteraltypeexpr +| 6 = @arraytypeexpr +| 7 = @uniontypeexpr +| 8 = @indexedaccesstypeexpr +| 9 = @intersectiontypeexpr +| 10 = @parenthesizedtypeexpr +| 11 = @tupletypeexpr +| 12 = @keyoftypeexpr +| 13 = @qualifiedtypeaccess +| 14 = @generictypeexpr +| 15 = @typelabel +| 16 = @typeoftypeexpr +| 17 = @localvartypeaccess +| 18 = @qualifiedvartypeaccess +| 19 = @thisvartypeaccess +| 20 = @istypeexpr +| 21 = @interfacetypeexpr +| 22 = @typeparameter +| 23 = @plainfunctiontypeexpr +| 24 = @constructortypeexpr +| 25 = @localnamespaceaccess +| 26 = @qualifiednamespaceaccess +| 27 = @mappedtypeexpr +| 28 = @conditionaltypeexpr +| 29 = @infertypeexpr +| 30 = @importtypeaccess +| 31 = @importnamespaceaccess +| 32 = @importvartypeaccess +| 33 = @optionaltypeexpr +| 34 = @resttypeexpr +| 35 = @bigintliteraltypeexpr +| 36 = @readonlytypeexpr +; + +@typeref = @typeaccess | @typedecl; +@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literaltypeexpr = @stringliteraltypeexpr | @numberliteraltypeexpr | @booleanliteraltypeexpr | @bigintliteraltypeexpr; +@typeaccess = @localtypeaccess | @qualifiedtypeaccess | @importtypeaccess; +@vartypeaccess = @localvartypeaccess | @qualifiedvartypeaccess | @thisvartypeaccess | @importvartypeaccess; +@namespaceaccess = @localnamespaceaccess | @qualifiednamespaceaccess | @importnamespaceaccess; +@importtypeexpr = @importtypeaccess | @importnamespaceaccess | @importvartypeaccess; + +@functiontypeexpr = @plainfunctiontypeexpr | @constructortypeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @anytype +| 1 = @stringtype +| 2 = @numbertype +| 3 = @uniontype +| 4 = @truetype +| 5 = @falsetype +| 6 = @typereference +| 7 = @objecttype +| 8 = @canonicaltypevariabletype +| 9 = @typeoftype +| 10 = @voidtype +| 11 = @undefinedtype +| 12 = @nulltype +| 13 = @nevertype +| 14 = @plainsymboltype +| 15 = @uniquesymboltype +| 16 = @objectkeywordtype +| 17 = @intersectiontype +| 18 = @tupletype +| 19 = @lexicaltypevariabletype +| 20 = @thistype +| 21 = @numberliteraltype +| 22 = @stringliteraltype +| 23 = @unknowntype +| 24 = @biginttype +| 25 = @bigintliteraltype +; + +@booleanliteraltype = @truetype | @falsetype; +@symboltype = @plainsymboltype | @uniquesymboltype; +@unionorintersectiontype = @uniontype | @intersectiontype; +@typevariabletype = @canonicaltypevariabletype | @lexicaltypevariabletype; + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @typereference | @typevariabletype | @typeoftype | @uniquesymboltype; +@ast_node_with_symbol = @typedefinition | @namespacedefinition | @toplevel | @typeaccess | @namespaceaccess | @vardecl | @function | @invokeexpr; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +@literaltype = @stringliteraltype | @numberliteraltype | @booleanliteraltype | @bigintliteraltype; +@type_with_literal_value = @stringliteraltype | @numberliteraltype | @bigintliteraltype; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @typereference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment +| 2 = @doccomment +| 3 = @htmlcommentstart +| 4 = @htmlcommentend; + +@htmlcomment = @htmlcommentstart | @htmlcommentend; +@linecomment = @slashslashcomment | @htmlcomment; +@blockcomment = @slashstarcomment | @doccomment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +jsParseErrors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexpliteral; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_char +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexpParseErrors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_char | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; + +isGreedy (int id: @regexp_quantifier ref); +rangeQuantifierLowerBound (unique int id: @regexp_range ref, int lo: int ref); +rangeQuantifierUpperBound (unique int id: @regexp_range ref, int hi: int ref); +isCapture (unique int id: @regexp_group ref, int number: int ref); +isNamedCapture (unique int id: @regexp_group ref, string name: string ref); +isInverted (int id: @regexp_char_class ref); +regexpConstValue (unique int id: @regexp_constant ref, varchar(1) value: string ref); +charClassEscape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +namedBackref (unique int id: @regexp_backref ref, string name: string ref); +unicodePropertyEscapeName (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicodePropertyEscapeValue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @exprparent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property; + +@optionalchainable = @callexpr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) \ No newline at end of file diff --git a/javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/semmlecode.javascript.dbscheme b/javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/semmlecode.javascript.dbscheme new file mode 100644 index 00000000000..ab0dab3b55b --- /dev/null +++ b/javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/semmlecode.javascript.dbscheme @@ -0,0 +1,1172 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +isExterns (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url; + +isModule (int tl: @toplevel ref); +isNodejs (int tl: @toplevel ref); +isES2015Module (int tl: @toplevel ref); +isClosureModule (int tl: @toplevel ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmtContainers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jumpTargets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmtparent = @stmt | @toplevel | @functionexpr | @arrowfunctionexpr; +@stmt_container = @toplevel | @function | @namespacedeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; + +case @stmt.kind of + 0 = @emptystmt +| 1 = @blockstmt +| 2 = @exprstmt +| 3 = @ifstmt +| 4 = @labeledstmt +| 5 = @breakstmt +| 6 = @continuestmt +| 7 = @withstmt +| 8 = @switchstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @trystmt +| 12 = @whilestmt +| 13 = @dowhilestmt +| 14 = @forstmt +| 15 = @forinstmt +| 16 = @debuggerstmt +| 17 = @functiondeclstmt +| 18 = @vardeclstmt +| 19 = @case +| 20 = @catchclause +| 21 = @forofstmt +| 22 = @constdeclstmt +| 23 = @letstmt +| 24 = @legacy_letstmt +| 25 = @foreachstmt +| 26 = @classdeclstmt +| 27 = @importdeclaration +| 28 = @exportalldeclaration +| 29 = @exportdefaultdeclaration +| 30 = @exportnameddeclaration +| 31 = @namespacedeclaration +| 32 = @importequalsdeclaration +| 33 = @exportassigndeclaration +| 34 = @interfacedeclaration +| 35 = @typealiasdeclaration +| 36 = @enumdeclaration +| 37 = @externalmoduledeclaration +| 38 = @exportasnamespacedeclaration +| 39 = @globalaugmentationdeclaration +; + +@declstmt = @vardeclstmt | @constdeclstmt | @letstmt | @legacy_letstmt; + +@exportdeclaration = @exportalldeclaration | @exportdefaultdeclaration | @exportnameddeclaration; + +@namespacedefinition = @namespacedeclaration | @enumdeclaration; +@typedefinition = @classdefinition | @interfacedeclaration | @enumdeclaration | @typealiasdeclaration | @enum_member; + +isInstantiated(unique int decl: @namespacedeclaration ref); + +@declarablestmt = @declstmt | @namespacedeclaration | @classdeclstmt | @functiondeclstmt | @enumdeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; +hasDeclareKeyword(unique int stmt: @declarablestmt ref); + +isForAwaitOf(unique int forof: @forofstmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @exprparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @exprortype ref); + +enclosingStmt (unique int expr: @exprortype ref, + int stmt: @stmt ref); + +exprContainers (unique int expr: @exprortype ref, + int container: @stmt_container ref); + +arraySize (unique int ae: @arraylike ref, + int sz: int ref); + +isDelegating (int yield: @yieldexpr ref); + +@exprorstmt = @expr | @stmt; +@exprortype = @expr | @typeexpr; +@exprparent = @exprorstmt | @property | @functiontypeexpr; +@arraylike = @arrayexpr | @arraypattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; + +case @expr.kind of + 0 = @label +| 1 = @nullliteral +| 2 = @booleanliteral +| 3 = @numberliteral +| 4 = @stringliteral +| 5 = @regexpliteral +| 6 = @thisexpr +| 7 = @arrayexpr +| 8 = @objexpr +| 9 = @functionexpr +| 10 = @seqexpr +| 11 = @conditionalexpr +| 12 = @newexpr +| 13 = @callexpr +| 14 = @dotexpr +| 15 = @indexexpr +| 16 = @negexpr +| 17 = @plusexpr +| 18 = @lognotexpr +| 19 = @bitnotexpr +| 20 = @typeofexpr +| 21 = @voidexpr +| 22 = @deleteexpr +| 23 = @eqexpr +| 24 = @neqexpr +| 25 = @eqqexpr +| 26 = @neqqexpr +| 27 = @ltexpr +| 28 = @leexpr +| 29 = @gtexpr +| 30 = @geexpr +| 31 = @lshiftexpr +| 32 = @rshiftexpr +| 33 = @urshiftexpr +| 34 = @addexpr +| 35 = @subexpr +| 36 = @mulexpr +| 37 = @divexpr +| 38 = @modexpr +| 39 = @bitorexpr +| 40 = @xorexpr +| 41 = @bitandexpr +| 42 = @inexpr +| 43 = @instanceofexpr +| 44 = @logandexpr +| 45 = @logorexpr +| 47 = @assignexpr +| 48 = @assignaddexpr +| 49 = @assignsubexpr +| 50 = @assignmulexpr +| 51 = @assigndivexpr +| 52 = @assignmodexpr +| 53 = @assignlshiftexpr +| 54 = @assignrshiftexpr +| 55 = @assignurshiftexpr +| 56 = @assignorexpr +| 57 = @assignxorexpr +| 58 = @assignandexpr +| 59 = @preincexpr +| 60 = @postincexpr +| 61 = @predecexpr +| 62 = @postdecexpr +| 63 = @parexpr +| 64 = @vardeclarator +| 65 = @arrowfunctionexpr +| 66 = @spreadelement +| 67 = @arraypattern +| 68 = @objectpattern +| 69 = @yieldexpr +| 70 = @taggedtemplateexpr +| 71 = @templateliteral +| 72 = @templateelement +| 73 = @arraycomprehensionexpr +| 74 = @generatorexpr +| 75 = @forincomprehensionblock +| 76 = @forofcomprehensionblock +| 77 = @legacy_letexpr +| 78 = @vardecl +| 79 = @proper_varaccess +| 80 = @classexpr +| 81 = @superexpr +| 82 = @newtargetexpr +| 83 = @namedimportspecifier +| 84 = @importdefaultspecifier +| 85 = @importnamespacespecifier +| 86 = @namedexportspecifier +| 87 = @expexpr +| 88 = @assignexpexpr +| 89 = @jsxelement +| 90 = @jsxqualifiedname +| 91 = @jsxemptyexpr +| 92 = @awaitexpr +| 93 = @functionsentexpr +| 94 = @decorator +| 95 = @exportdefaultspecifier +| 96 = @exportnamespacespecifier +| 97 = @bindexpr +| 98 = @externalmodulereference +| 99 = @dynamicimport +| 100 = @expressionwithtypearguments +| 101 = @prefixtypeassertion +| 102 = @astypeassertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigintliteral +| 107 = @nullishcoalescingexpr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @vardecl | @varaccess; + +@identifier = @label | @varref | @typeidentifier; + +@literal = @nullliteral | @booleanliteral | @numberliteral | @stringliteral | @regexpliteral | @bigintliteral; + +@propaccess = @dotexpr | @indexexpr; + +@invokeexpr = @newexpr | @callexpr; + +@unaryexpr = @negexpr | @plusexpr | @lognotexpr | @bitnotexpr | @typeofexpr | @voidexpr | @deleteexpr | @spreadelement; + +@equalitytest = @eqexpr | @neqexpr | @eqqexpr | @neqqexpr; + +@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr; + +@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; + +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr; + +@updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; + +@pattern = @varref | @arraypattern | @objectpattern; + +@comprehensionexpr = @arraycomprehensionexpr | @generatorexpr; + +@comprehensionblock = @forincomprehensionblock | @forofcomprehensionblock; + +@importspecifier = @namedimportspecifier | @importdefaultspecifier | @importnamespacespecifier; + +@exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; + +@typeassertion = @astypeassertion | @prefixtypeassertion; + +@classdefinition = @classdeclstmt | @classexpr; +@interfacedefinition = @interfacedeclaration | @interfacetypeexpr; +@classorinterface = @classdefinition | @interfacedefinition; + +@lexical_decl = @vardecl | @typedecl; +@lexical_access = @varaccess | @localtypeaccess | @localvartypeaccess | @localnamespaceaccess; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @globalscope +| 1 = @functionscope +| 2 = @catchscope +| 3 = @modulescope +| 4 = @blockscope +| 5 = @forscope +| 6 = @forinscope // for-of scopes work the same as for-in scopes +| 7 = @comprehensionblockscope +| 8 = @classexprscope +| 9 = @namespacescope +| 10 = @classdeclscope +| 11 = @interfacescope +| 12 = @typealiasscope +| 13 = @mappedtypescope +| 14 = @enumscope +| 15 = @externalmodulescope +| 16 = @conditionaltypescope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @functiondeclstmt | @functionexpr | @arrowfunctionexpr; + +@parameterized = @function | @catchclause; +@type_parameterized = @function | @classorinterface | @typealiasdeclaration | @mappedtypeexpr | @infertypeexpr; + +isGenerator (int fun: @function ref); +hasRestParameter (int fun: @function ref); +isAsync (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +isArgumentsObject (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @localvartypeaccess; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @vardecl ref, + int decl: @variable ref); + +@typebind_id = @localtypeaccess | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @typedecl | @vardecl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @vardecl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @localnamespaceaccess | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @objexpr | @objectpattern | @classdefinition | @jsxelement | @interfacedefinition | @enumdeclaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @vardeclarator; + +isComputed (int id: @property ref); +isMethod (int id: @property ref); +isStatic (int id: @property ref); +isAbstractMember (int id: @property ref); +isConstEnum (int id: @enumdeclaration ref); +isAbstractClass (int id: @classdeclstmt ref); + +hasPublicKeyword (int id: @property ref); +hasPrivateKeyword (int id: @property ref); +hasProtectedKeyword (int id: @property ref); +hasReadonlyKeyword (int id: @property ref); +isOptionalMember (int id: @property ref); +hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @functionexpr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @localtypeaccess +| 1 = @typedecl +| 2 = @keywordtypeexpr +| 3 = @stringliteraltypeexpr +| 4 = @numberliteraltypeexpr +| 5 = @booleanliteraltypeexpr +| 6 = @arraytypeexpr +| 7 = @uniontypeexpr +| 8 = @indexedaccesstypeexpr +| 9 = @intersectiontypeexpr +| 10 = @parenthesizedtypeexpr +| 11 = @tupletypeexpr +| 12 = @keyoftypeexpr +| 13 = @qualifiedtypeaccess +| 14 = @generictypeexpr +| 15 = @typelabel +| 16 = @typeoftypeexpr +| 17 = @localvartypeaccess +| 18 = @qualifiedvartypeaccess +| 19 = @thisvartypeaccess +| 20 = @istypeexpr +| 21 = @interfacetypeexpr +| 22 = @typeparameter +| 23 = @plainfunctiontypeexpr +| 24 = @constructortypeexpr +| 25 = @localnamespaceaccess +| 26 = @qualifiednamespaceaccess +| 27 = @mappedtypeexpr +| 28 = @conditionaltypeexpr +| 29 = @infertypeexpr +| 30 = @importtypeaccess +| 31 = @importnamespaceaccess +| 32 = @importvartypeaccess +| 33 = @optionaltypeexpr +| 34 = @resttypeexpr +| 35 = @bigintliteraltypeexpr +| 36 = @readonlytypeexpr +; + +@typeref = @typeaccess | @typedecl; +@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literaltypeexpr = @stringliteraltypeexpr | @numberliteraltypeexpr | @booleanliteraltypeexpr | @bigintliteraltypeexpr; +@typeaccess = @localtypeaccess | @qualifiedtypeaccess | @importtypeaccess; +@vartypeaccess = @localvartypeaccess | @qualifiedvartypeaccess | @thisvartypeaccess | @importvartypeaccess; +@namespaceaccess = @localnamespaceaccess | @qualifiednamespaceaccess | @importnamespaceaccess; +@importtypeexpr = @importtypeaccess | @importnamespaceaccess | @importvartypeaccess; + +@functiontypeexpr = @plainfunctiontypeexpr | @constructortypeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @anytype +| 1 = @stringtype +| 2 = @numbertype +| 3 = @uniontype +| 4 = @truetype +| 5 = @falsetype +| 6 = @typereference +| 7 = @objecttype +| 8 = @canonicaltypevariabletype +| 9 = @typeoftype +| 10 = @voidtype +| 11 = @undefinedtype +| 12 = @nulltype +| 13 = @nevertype +| 14 = @plainsymboltype +| 15 = @uniquesymboltype +| 16 = @objectkeywordtype +| 17 = @intersectiontype +| 18 = @tupletype +| 19 = @lexicaltypevariabletype +| 20 = @thistype +| 21 = @numberliteraltype +| 22 = @stringliteraltype +| 23 = @unknowntype +| 24 = @biginttype +| 25 = @bigintliteraltype +; + +@booleanliteraltype = @truetype | @falsetype; +@symboltype = @plainsymboltype | @uniquesymboltype; +@unionorintersectiontype = @uniontype | @intersectiontype; +@typevariabletype = @canonicaltypevariabletype | @lexicaltypevariabletype; + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @typereference | @typevariabletype | @typeoftype | @uniquesymboltype; +@ast_node_with_symbol = @typedefinition | @namespacedefinition | @toplevel | @typeaccess | @namespaceaccess | @vardecl | @function | @invokeexpr; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +@literaltype = @stringliteraltype | @numberliteraltype | @booleanliteraltype | @bigintliteraltype; +@type_with_literal_value = @stringliteraltype | @numberliteraltype | @bigintliteraltype; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @typereference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment +| 2 = @doccomment +| 3 = @htmlcommentstart +| 4 = @htmlcommentend; + +@htmlcomment = @htmlcommentstart | @htmlcommentend; +@linecomment = @slashslashcomment | @htmlcomment; +@blockcomment = @slashstarcomment | @doccomment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +jsParseErrors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexpliteral; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_char +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexpParseErrors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_char | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; + +isGreedy (int id: @regexp_quantifier ref); +rangeQuantifierLowerBound (unique int id: @regexp_range ref, int lo: int ref); +rangeQuantifierUpperBound (unique int id: @regexp_range ref, int hi: int ref); +isCapture (unique int id: @regexp_group ref, int number: int ref); +isNamedCapture (unique int id: @regexp_group ref, string name: string ref); +isInverted (int id: @regexp_char_class ref); +regexpConstValue (unique int id: @regexp_constant ref, varchar(1) value: string ref); +charClassEscape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +namedBackref (unique int id: @regexp_backref ref, string name: string ref); +unicodePropertyEscapeName (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicodePropertyEscapeValue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @exprparent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property; + +@optionalchainable = @callexpr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) \ No newline at end of file diff --git a/javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/upgrade.properties b/javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/upgrade.properties new file mode 100644 index 00000000000..2dc97a2bab6 --- /dev/null +++ b/javascript/upgrades/56b74a6808d3fe01835d454c25ea8dc3da1a8fdf/upgrade.properties @@ -0,0 +1,2 @@ +description: add declared function signatures to database +compatibility: backwards From c2f6855a7b908905d1504a24cc920e29e76f02a6 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 20 Sep 2019 16:02:59 +0100 Subject: [PATCH 0246/1227] JS: Update tests --- .../TypeVariableTypes/SignatureTypeParameters.expected | 1 + .../ql/test/library-tests/TypeScript/Types/GetExprType.expected | 2 ++ 2 files changed, 3 insertions(+) diff --git a/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/SignatureTypeParameters.expected b/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/SignatureTypeParameters.expected index 36d84b19f3a..3b6ee6a25b6 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/SignatureTypeParameters.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/SignatureTypeParameters.expected @@ -1,5 +1,6 @@ | (x: D): D | 1 | 0 | D | no bound | | (x: () => E): E | 1 | 0 | E | no bound | +| (x: E[] \| (() => E)): E | 1 | 0 | E | no bound | | (x: E[]): E | 1 | 0 | E | no bound | | (callbackfn: (value: E, index: number, array: E[]) => va... | 1 | 0 | S | no bound | | (callbackfn: (value: T \| S, index: number, array: (T... | 1 | 0 | S | no bound | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected b/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected index fe1bcace0c4..371cdb05b21 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected @@ -64,10 +64,12 @@ | tst.ts:22:29:22:29 | 2 | 2 | | tst.ts:24:5:24:9 | array | number[] | | tst.ts:26:5:26:12 | voidType | () => void | +| tst.ts:26:15:26:24 | () => void | () => void | | tst.ts:27:5:27:17 | undefinedType | undefined | | tst.ts:28:5:28:12 | nullType | null | | tst.ts:28:22:28:25 | null | null | | tst.ts:29:5:29:13 | neverType | () => never | +| tst.ts:29:16:29:26 | () => never | () => never | | tst.ts:30:5:30:14 | symbolType | symbol | | tst.ts:31:7:31:22 | uniqueSymbolType | typeof uniqueSymbolType | | tst.ts:31:41:31:44 | null | null | From 9511465f04ef80c6f1b0afe914e54d6b625bdc97 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 26 Sep 2019 11:16:24 +0200 Subject: [PATCH 0247/1227] Learn QL: Minor formatting fix in python/statements-expressions (cherry picked from commit c47a4e0c44eba9f24ffb5490986188347e1372f5) --- docs/language/learn-ql/python/statements-expressions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/python/statements-expressions.rst b/docs/language/learn-ql/python/statements-expressions.rst index 2d45abde73a..9f1a15a6d1a 100644 --- a/docs/language/learn-ql/python/statements-expressions.rst +++ b/docs/language/learn-ql/python/statements-expressions.rst @@ -72,7 +72,7 @@ An ``if`` statement where one branch is composed of just ``pass`` statements cou To find statements like this we can run the following query: -**Find ``if`` statements with empty branches** +**Find 'if' statements with empty branches** .. code-block:: ql From 94d876e8a3664c4fba6f48f7f10f937885900759 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 25 Sep 2019 18:20:48 +0200 Subject: [PATCH 0248/1227] Learn QL: Fix query link in Python Points-to tutorial (cherry picked from commit c6c565bc373e1353830ea731823feea024b4c4c8) --- docs/language/learn-ql/python/pointsto-type-infer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/python/pointsto-type-infer.rst b/docs/language/learn-ql/python/pointsto-type-infer.rst index 6ca1bde67c8..bcbab520477 100644 --- a/docs/language/learn-ql/python/pointsto-type-infer.rst +++ b/docs/language/learn-ql/python/pointsto-type-infer.rst @@ -173,7 +173,7 @@ Many of the results shown will have ``cls`` as ``NoneType``. It is more informat not cls.hasAttribute("__iter__") select loop, cls, origin -➤ `See this in the query console `__. This reports the same results, but with a third column showing the source of the ``None`` values. +➤ `See this in the query console `__. This reports the same results, but with a third column showing the source of the ``None`` values. Finding calls using call-graph analysis ---------------------------------------------------- From 16d8d2efa18749d58f71e893219162f9bb2238fa Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Tue, 24 Sep 2019 15:28:42 +0100 Subject: [PATCH 0249/1227] Remove useless translation --- .../raw/internal/TranslatedExpr.qll | 98 ------------------- 1 file changed, 98 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 2f0be8366c0..0daf51dc41f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1893,104 +1893,6 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { } } -/** - * The IR translation of a lambda expression. This initializes a temporary variable whose type is that of the lambda, - * using the initializer list that represents the captures of the lambda. - */ -class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationContext { - override LambdaExpr expr; - - final override Instruction getFirstInstruction() { - result = this.getInstruction(InitializerVariableAddressTag()) - } - - final override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() } - - override Instruction getResult() { result = this.getInstruction(LoadTag()) } - - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { - tag = InitializerVariableAddressTag() and - kind instanceof GotoEdge and - result = this.getInstruction(InitializerStoreTag()) - or - tag = InitializerStoreTag() and - kind instanceof GotoEdge and - ( - result = this.getInitialization().getFirstInstruction() - or - not this.hasInitializer() and result = this.getInstruction(LoadTag()) - ) - or - tag = LoadTag() and - kind instanceof GotoEdge and - result = this.getParent().getChildSuccessor(this) - } - - override Instruction getChildSuccessor(TranslatedElement child) { - child = getInitialization() and - result = this.getInstruction(LoadTag()) - } - - override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue - ) { - tag = InitializerVariableAddressTag() and - opcode instanceof Opcode::VariableAddress and - resultType = this.getResultType() and - isLValue = true - or - tag = InitializerStoreTag() and - opcode instanceof Opcode::Uninitialized and - resultType = this.getResultType() and - isLValue = false - or - tag = LoadTag() and - opcode instanceof Opcode::Load and - resultType = this.getResultType() and - isLValue = false - } - - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = InitializerStoreTag() and - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - or - tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) - } - - override IRVariable getInstructionVariable(InstructionTag tag) { - ( - tag = InitializerVariableAddressTag() or - tag = InitializerStoreTag() - ) and - result = this.getTempVariable(LambdaTempVar()) - } - - override predicate hasTempVariable(TempVariableTag tag, Type type) { - tag = LambdaTempVar() and - type = this.getResultType() - } - - final override Instruction getTargetAddress() { - result = this.getInstruction(InitializerVariableAddressTag()) - } - - final override Type getTargetType() { result = this.getResultType() } - - private predicate hasInitializer() { exists(this.getInitialization()) } - - private TranslatedInitialization getInitialization() { - result = getTranslatedInitialization(expr.getChild(0)) - } -} - /** * The translation of a `DelegateCall`. Since this type of call needs * desugaring, we treat it as a special case. The AST node of the From 3a5140c0f53c5ecf75ffc48403460ff96a868a4c Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Tue, 24 Sep 2019 16:19:26 +0100 Subject: [PATCH 0250/1227] Indexers and events Added test for indexers. Added support for event accesses and added test. --- .../raw/internal/TranslatedElement.qll | 6 + .../raw/internal/TranslatedExpr.qll | 39 +++++ csharp/ql/test/library-tests/ir/ir/events.cs | 19 +++ .../ql/test/library-tests/ir/ir/indexers.cs | 26 ++++ .../test/library-tests/ir/ir/raw_ir.expected | 146 ++++++++++++++++++ 5 files changed, 236 insertions(+) create mode 100644 csharp/ql/test/library-tests/ir/ir/events.cs create mode 100644 csharp/ql/test/library-tests/ir/ir/indexers.cs diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll index 879ac4d1384..2a83bdfe429 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll @@ -99,6 +99,12 @@ private predicate ignoreExprOnly(Expr expr) { // Ignore the expression (that is not a declaration) // that appears in a using block expr.getParent().(UsingBlockStmt).getExpr() = expr + or + // Ignore the `ThisAccess` when it is used as the qualifier for + // a callable access (e.g. when a member callable is passed as a + // parameter for a delegate creation expression) + expr instanceof ThisAccess and + expr.getParent() instanceof CallableAccess } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 0daf51dc41f..ac74c49f148 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1382,6 +1382,11 @@ class TranslatedAssignExpr extends TranslatedAssignment { class TranslatedAssignOperation extends TranslatedAssignment { override AssignOperation expr; + TranslatedAssignOperation() { + // Assignments to events is handled differently + not expr.getLValue() instanceof EventAccess + } + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { kind instanceof GotoEdge and ( @@ -2057,3 +2062,37 @@ class TranslatedDelegateCreation extends TranslatedCreation { override predicate needsLoad() { none() } } + +/** + * Represents the IR translation of an assign operation where the lhs is an event access. + */ +class TranslatedEventAccess extends TranslatedNonConstantExpr { + override AssignOperation expr; + + TranslatedEventAccess() { expr.getLValue() instanceof EventAccess } + + // We only translate the lhs, since the rhs is translated as part of the + // accessor call. + override TranslatedElement getChild(int id) { id = 0 and result = this.getLValue() } + + override predicate hasInstruction( + Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + ) { + none() + } + + final override Instruction getFirstInstruction() { + result = this.getLValue().getFirstInstruction() + } + + override Instruction getResult() { none() } + + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } + + override Instruction getChildSuccessor(TranslatedElement child) { + child = this.getLValue() and + result = this.getParent().getChildSuccessor(this) + } + + private TranslatedExpr getLValue() { result = getTranslatedExpr(expr.getLValue()) } +} diff --git a/csharp/ql/test/library-tests/ir/ir/events.cs b/csharp/ql/test/library-tests/ir/ir/events.cs new file mode 100644 index 00000000000..ea49280c699 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/ir/events.cs @@ -0,0 +1,19 @@ +class Events +{ + public delegate string MyDel(string str); + + event MyDel MyEvent; + + public Events() { + this.MyEvent += new MyDel(this.WelcomeUser); + } + + public string WelcomeUser(string username) { + return "Welcome " + username; + } + + static void Main(string[] args) { + Events obj1 = new Events(); + string result = obj1.MyEvent("Tutorials Point"); + } +} diff --git a/csharp/ql/test/library-tests/ir/ir/indexers.cs b/csharp/ql/test/library-tests/ir/ir/indexers.cs new file mode 100644 index 00000000000..7c336cd1db0 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/ir/indexers.cs @@ -0,0 +1,26 @@ +class Indexers +{ + public class Contact + { + private string[] address = new string[3]; + public string this[int index] + { + get + { + return address[index]; + } + set + { + address[index] = value; + } + } + } + + public static void Main() + { + Contact contact = new Contact(); + contact[0] = "Begumpet"; + contact[1] = "Hyderabad"; + contact[2] = "Telengana"; + } +} diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index 16d15ff3aa8..bf7ca0c5d06 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -480,6 +480,70 @@ delegates.cs: # 11| v0_17(Void) = UnmodeledUse : mu* # 11| v0_18(Void) = ExitFunction : +events.cs: +# 7| System.Void Events..ctor() +# 7| Block 0 +# 7| v0_0(Void) = EnterFunction : +# 7| mu0_1(null) = AliasedDefinition : +# 7| mu0_2(null) = UnmodeledDefinition : +# 7| r0_3(glval) = InitializeThis : +# 8| r0_4(Events) = CopyValue : r0_3 +# 8| r0_5(glval) = FunctionAddress[add_MyEvent] : +# 8| r0_6(MyDel) = NewObj : +# 8| r0_7(glval) = FunctionAddress[MyDel] : +# 8| r0_8(glval) = FunctionAddress[WelcomeUser] : +# 8| v0_9(Void) = Call : func:r0_7, this:r0_6, 0:r0_8 +# 8| mu0_10(null) = ^CallSideEffect : ~mu0_2 +# 8| v0_11(Void) = Call : func:r0_5, this:r0_4, 0:r0_6 +# 8| mu0_12(null) = ^CallSideEffect : ~mu0_2 +# 7| v0_13(Void) = ReturnVoid : +# 7| v0_14(Void) = UnmodeledUse : mu* +# 7| v0_15(Void) = ExitFunction : + +# 11| System.String Events.WelcomeUser(System.String) +# 11| Block 0 +# 11| v0_0(Void) = EnterFunction : +# 11| mu0_1(null) = AliasedDefinition : +# 11| mu0_2(null) = UnmodeledDefinition : +# 11| r0_3(glval) = InitializeThis : +# 11| r0_4(glval) = VariableAddress[username] : +# 11| mu0_5(String) = InitializeParameter[username] : &:r0_4 +# 12| r0_6(glval) = VariableAddress[#return] : +# 12| r0_7(String) = StringConstant["Welcome "] : +# 12| r0_8(glval) = VariableAddress[username] : +# 12| r0_9(String) = Load : &:r0_8, ~mu0_2 +# 12| r0_10(String) = Add : r0_7, r0_9 +# 12| mu0_11(String) = Store : &:r0_6, r0_10 +# 11| r0_12(glval) = VariableAddress[#return] : +# 11| v0_13(Void) = ReturnValue : &:r0_12, ~mu0_2 +# 11| v0_14(Void) = UnmodeledUse : mu* +# 11| v0_15(Void) = ExitFunction : + +# 15| System.Void Events.Main(System.String[]) +# 15| Block 0 +# 15| v0_0(Void) = EnterFunction : +# 15| mu0_1(null) = AliasedDefinition : +# 15| mu0_2(null) = UnmodeledDefinition : +# 15| r0_3(glval) = VariableAddress[args] : +# 15| mu0_4(String[]) = InitializeParameter[args] : &:r0_3 +# 16| r0_5(glval) = VariableAddress[obj1] : +# 16| r0_6(Events) = NewObj : +# 16| r0_7(glval) = FunctionAddress[Events] : +# 16| v0_8(Void) = Call : func:r0_7, this:r0_6 +# 16| mu0_9(null) = ^CallSideEffect : ~mu0_2 +# 16| mu0_10(Events) = Store : &:r0_5, r0_6 +# 17| r0_11(glval) = VariableAddress[result] : +# 17| r0_12(glval) = VariableAddress[obj1] : +# 17| r0_13(Events) = Load : &:r0_12, ~mu0_2 +# 17| r0_14(glval) = FunctionAddress[Invoke] : +# 17| r0_15(String) = StringConstant["Tutorials Point"] : +# 17| v0_16(Void) = Call : func:r0_14, this:r0_13, 0:r0_15 +# 17| mu0_17(null) = ^CallSideEffect : ~mu0_2 +# 17| mu0_18(String) = Store : &:r0_11, v0_16 +# 15| v0_19(Void) = ReturnVoid : +# 15| v0_20(Void) = UnmodeledUse : mu* +# 15| v0_21(Void) = ExitFunction : + foreach.cs: # 4| System.Void ForEach.Main() # 4| Block 0 @@ -598,6 +662,88 @@ func_with_param_call.cs: # 10| v0_12(Void) = UnmodeledUse : mu* # 10| v0_13(Void) = ExitFunction : +indexers.cs: +# 8| System.String Indexers.Contact.get_Item(System.Int32) +# 8| Block 0 +# 8| v0_0(Void) = EnterFunction : +# 8| mu0_1(null) = AliasedDefinition : +# 8| mu0_2(null) = UnmodeledDefinition : +# 8| r0_3(glval) = InitializeThis : +# 6| r0_4(glval) = VariableAddress[index] : +# 6| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 +# 10| r0_6(glval) = VariableAddress[#return] : +# 10| r0_7(Contact) = CopyValue : r0_3 +# 10| r0_8(glval) = FieldAddress[address] : r0_7 +# 10| r0_9(String[]) = ElementsAddress : r0_8 +# 10| r0_10(glval) = VariableAddress[index] : +# 10| r0_11(Int32) = Load : &:r0_10, ~mu0_2 +# 10| r0_12(String[]) = PointerAdd[4] : r0_9, r0_11 +# 10| r0_13(String) = Load : &:r0_12, ~mu0_2 +# 10| mu0_14(String) = Store : &:r0_6, r0_13 +# 8| r0_15(glval) = VariableAddress[#return] : +# 8| v0_16(Void) = ReturnValue : &:r0_15, ~mu0_2 +# 8| v0_17(Void) = UnmodeledUse : mu* +# 8| v0_18(Void) = ExitFunction : + +# 12| System.Void Indexers.Contact.set_Item(System.Int32,System.String) +# 12| Block 0 +# 12| v0_0(Void) = EnterFunction : +# 12| mu0_1(null) = AliasedDefinition : +# 12| mu0_2(null) = UnmodeledDefinition : +# 12| r0_3(glval) = InitializeThis : +# 6| r0_4(glval) = VariableAddress[index] : +# 6| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 +# 12| r0_6(glval) = VariableAddress[value] : +# 12| mu0_7(String) = InitializeParameter[value] : &:r0_6 +# 14| r0_8(glval) = VariableAddress[value] : +# 14| r0_9(String) = Load : &:r0_8, ~mu0_2 +# 14| r0_10(Contact) = CopyValue : r0_3 +# 14| r0_11(glval) = FieldAddress[address] : r0_10 +# 14| r0_12(String[]) = ElementsAddress : r0_11 +# 14| r0_13(glval) = VariableAddress[index] : +# 14| r0_14(Int32) = Load : &:r0_13, ~mu0_2 +# 14| r0_15(String[]) = PointerAdd[4] : r0_12, r0_14 +# 14| mu0_16(String) = Store : &:r0_15, r0_9 +# 12| v0_17(Void) = ReturnVoid : +# 12| v0_18(Void) = UnmodeledUse : mu* +# 12| v0_19(Void) = ExitFunction : + +# 19| System.Void Indexers.Main() +# 19| Block 0 +# 19| v0_0(Void) = EnterFunction : +# 19| mu0_1(null) = AliasedDefinition : +# 19| mu0_2(null) = UnmodeledDefinition : +# 21| r0_3(glval) = VariableAddress[contact] : +# 21| r0_4(Contact) = NewObj : +# 21| r0_5(glval) = FunctionAddress[Contact] : +# 21| v0_6(Void) = Call : func:r0_5, this:r0_4 +# 21| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 21| mu0_8(Contact) = Store : &:r0_3, r0_4 +# 22| r0_9(glval) = VariableAddress[contact] : +# 22| r0_10(Contact) = Load : &:r0_9, ~mu0_2 +# 22| r0_11(glval) = FunctionAddress[set_Item] : +# 22| r0_12(Int32) = Constant[0] : +# 22| r0_13(String) = StringConstant["Begumpet"] : +# 22| v0_14(Void) = Call : func:r0_11, this:r0_10, 0:r0_12, 1:r0_13 +# 22| mu0_15(null) = ^CallSideEffect : ~mu0_2 +# 23| r0_16(glval) = VariableAddress[contact] : +# 23| r0_17(Contact) = Load : &:r0_16, ~mu0_2 +# 23| r0_18(glval) = FunctionAddress[set_Item] : +# 23| r0_19(Int32) = Constant[1] : +# 23| r0_20(String) = StringConstant["Hyderabad"] : +# 23| v0_21(Void) = Call : func:r0_18, this:r0_17, 0:r0_19, 1:r0_20 +# 23| mu0_22(null) = ^CallSideEffect : ~mu0_2 +# 24| r0_23(glval) = VariableAddress[contact] : +# 24| r0_24(Contact) = Load : &:r0_23, ~mu0_2 +# 24| r0_25(glval) = FunctionAddress[set_Item] : +# 24| r0_26(Int32) = Constant[2] : +# 24| r0_27(String) = StringConstant["Telengana"] : +# 24| v0_28(Void) = Call : func:r0_25, this:r0_24, 0:r0_26, 1:r0_27 +# 24| mu0_29(null) = ^CallSideEffect : ~mu0_2 +# 19| v0_30(Void) = ReturnVoid : +# 19| v0_31(Void) = UnmodeledUse : mu* +# 19| v0_32(Void) = ExitFunction : + inheritance_polymorphism.cs: # 3| System.Int32 A.function() # 3| Block 0 From 0999780d82195f19cf563fae325b24112ae8a222 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Wed, 25 Sep 2019 15:08:44 +0100 Subject: [PATCH 0251/1227] Address PR comments --- .../raw/internal/TranslatedElement.qll | 4 + csharp/ql/test/library-tests/ir/ir/events.cs | 30 +- .../ql/test/library-tests/ir/ir/indexers.cs | 16 +- .../test/library-tests/ir/ir/raw_ir.expected | 331 ++++++++++-------- 4 files changed, 231 insertions(+), 150 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll index 2a83bdfe429..f98527e084f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll @@ -205,6 +205,10 @@ private predicate ignoreLoad(Expr expr) { // to get the address of the first element in an array expr = any(ArrayAccess aa).getQualifier() or + // Indexer calls returns a reference or a value, + // no need to load it + expr instanceof IndexerCall + or // No load is needed for the lvalue in an assignment such as: // Eg. `Object obj = oldObj`; expr = any(Assignment a).getLValue() and diff --git a/csharp/ql/test/library-tests/ir/ir/events.cs b/csharp/ql/test/library-tests/ir/ir/events.cs index ea49280c699..7364b0069f9 100644 --- a/csharp/ql/test/library-tests/ir/ir/events.cs +++ b/csharp/ql/test/library-tests/ir/ir/events.cs @@ -1,19 +1,35 @@ class Events { public delegate string MyDel(string str); + public MyDel Inst; event MyDel MyEvent; - public Events() { - this.MyEvent += new MyDel(this.WelcomeUser); + public Events() + { + this.Inst = new MyDel(this.Fun); } - public string WelcomeUser(string username) { - return "Welcome " + username; + public void AddEvent() + { + this.MyEvent += this.Inst; + } + + public void RemoveEvent() + { + this.MyEvent -= this.Inst; + } + + public string Fun(string str) + { + return str; } - static void Main(string[] args) { - Events obj1 = new Events(); - string result = obj1.MyEvent("Tutorials Point"); + static void Main(string[] args) + { + Events obj = new Events(); + obj.AddEvent(); + string result = obj.MyEvent("string"); + obj.RemoveEvent(); } } diff --git a/csharp/ql/test/library-tests/ir/ir/indexers.cs b/csharp/ql/test/library-tests/ir/ir/indexers.cs index 7c336cd1db0..c11e3b7ad62 100644 --- a/csharp/ql/test/library-tests/ir/ir/indexers.cs +++ b/csharp/ql/test/library-tests/ir/ir/indexers.cs @@ -1,8 +1,12 @@ class Indexers { - public class Contact + public class MyClass { - private string[] address = new string[3]; + public MyClass() + { + } + + private string[] address = new string[2]; public string this[int index] { get @@ -18,9 +22,9 @@ class Indexers public static void Main() { - Contact contact = new Contact(); - contact[0] = "Begumpet"; - contact[1] = "Hyderabad"; - contact[2] = "Telengana"; + MyClass inst = new MyClass(); + inst[0] = "str1"; + inst[1] = "str1"; + inst[1] = inst[0]; } } diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index bf7ca0c5d06..116e3e77f33 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -481,68 +481,109 @@ delegates.cs: # 11| v0_18(Void) = ExitFunction : events.cs: -# 7| System.Void Events..ctor() -# 7| Block 0 -# 7| v0_0(Void) = EnterFunction : -# 7| mu0_1(null) = AliasedDefinition : -# 7| mu0_2(null) = UnmodeledDefinition : -# 7| r0_3(glval) = InitializeThis : -# 8| r0_4(Events) = CopyValue : r0_3 -# 8| r0_5(glval) = FunctionAddress[add_MyEvent] : -# 8| r0_6(MyDel) = NewObj : -# 8| r0_7(glval) = FunctionAddress[MyDel] : -# 8| r0_8(glval) = FunctionAddress[WelcomeUser] : -# 8| v0_9(Void) = Call : func:r0_7, this:r0_6, 0:r0_8 -# 8| mu0_10(null) = ^CallSideEffect : ~mu0_2 -# 8| v0_11(Void) = Call : func:r0_5, this:r0_4, 0:r0_6 -# 8| mu0_12(null) = ^CallSideEffect : ~mu0_2 -# 7| v0_13(Void) = ReturnVoid : -# 7| v0_14(Void) = UnmodeledUse : mu* -# 7| v0_15(Void) = ExitFunction : +# 8| System.Void Events..ctor() +# 8| Block 0 +# 8| v0_0(Void) = EnterFunction : +# 8| mu0_1(null) = AliasedDefinition : +# 8| mu0_2(null) = UnmodeledDefinition : +# 8| r0_3(glval) = InitializeThis : +# 10| r0_4(MyDel) = NewObj : +# 10| r0_5(glval) = FunctionAddress[MyDel] : +# 10| r0_6(glval) = FunctionAddress[Fun] : +# 10| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6 +# 10| mu0_8(null) = ^CallSideEffect : ~mu0_2 +# 10| r0_9(Events) = CopyValue : r0_3 +# 10| r0_10(glval) = FieldAddress[Inst] : r0_9 +# 10| mu0_11(MyDel) = Store : &:r0_10, r0_4 +# 8| v0_12(Void) = ReturnVoid : +# 8| v0_13(Void) = UnmodeledUse : mu* +# 8| v0_14(Void) = ExitFunction : -# 11| System.String Events.WelcomeUser(System.String) -# 11| Block 0 -# 11| v0_0(Void) = EnterFunction : -# 11| mu0_1(null) = AliasedDefinition : -# 11| mu0_2(null) = UnmodeledDefinition : -# 11| r0_3(glval) = InitializeThis : -# 11| r0_4(glval) = VariableAddress[username] : -# 11| mu0_5(String) = InitializeParameter[username] : &:r0_4 -# 12| r0_6(glval) = VariableAddress[#return] : -# 12| r0_7(String) = StringConstant["Welcome "] : -# 12| r0_8(glval) = VariableAddress[username] : -# 12| r0_9(String) = Load : &:r0_8, ~mu0_2 -# 12| r0_10(String) = Add : r0_7, r0_9 -# 12| mu0_11(String) = Store : &:r0_6, r0_10 -# 11| r0_12(glval) = VariableAddress[#return] : -# 11| v0_13(Void) = ReturnValue : &:r0_12, ~mu0_2 -# 11| v0_14(Void) = UnmodeledUse : mu* -# 11| v0_15(Void) = ExitFunction : +# 13| System.Void Events.AddEvent() +# 13| Block 0 +# 13| v0_0(Void) = EnterFunction : +# 13| mu0_1(null) = AliasedDefinition : +# 13| mu0_2(null) = UnmodeledDefinition : +# 13| r0_3(glval) = InitializeThis : +# 15| r0_4(Events) = CopyValue : r0_3 +# 15| r0_5(glval) = FunctionAddress[add_MyEvent] : +# 15| r0_6(Events) = CopyValue : r0_3 +# 15| r0_7(glval) = FieldAddress[Inst] : r0_6 +# 15| r0_8(MyDel) = Load : &:r0_7, ~mu0_2 +# 15| v0_9(Void) = Call : func:r0_5, this:r0_4, 0:r0_8 +# 15| mu0_10(null) = ^CallSideEffect : ~mu0_2 +# 13| v0_11(Void) = ReturnVoid : +# 13| v0_12(Void) = UnmodeledUse : mu* +# 13| v0_13(Void) = ExitFunction : -# 15| System.Void Events.Main(System.String[]) -# 15| Block 0 -# 15| v0_0(Void) = EnterFunction : -# 15| mu0_1(null) = AliasedDefinition : -# 15| mu0_2(null) = UnmodeledDefinition : -# 15| r0_3(glval) = VariableAddress[args] : -# 15| mu0_4(String[]) = InitializeParameter[args] : &:r0_3 -# 16| r0_5(glval) = VariableAddress[obj1] : -# 16| r0_6(Events) = NewObj : -# 16| r0_7(glval) = FunctionAddress[Events] : -# 16| v0_8(Void) = Call : func:r0_7, this:r0_6 -# 16| mu0_9(null) = ^CallSideEffect : ~mu0_2 -# 16| mu0_10(Events) = Store : &:r0_5, r0_6 -# 17| r0_11(glval) = VariableAddress[result] : -# 17| r0_12(glval) = VariableAddress[obj1] : -# 17| r0_13(Events) = Load : &:r0_12, ~mu0_2 -# 17| r0_14(glval) = FunctionAddress[Invoke] : -# 17| r0_15(String) = StringConstant["Tutorials Point"] : -# 17| v0_16(Void) = Call : func:r0_14, this:r0_13, 0:r0_15 -# 17| mu0_17(null) = ^CallSideEffect : ~mu0_2 -# 17| mu0_18(String) = Store : &:r0_11, v0_16 -# 15| v0_19(Void) = ReturnVoid : -# 15| v0_20(Void) = UnmodeledUse : mu* -# 15| v0_21(Void) = ExitFunction : +# 18| System.Void Events.RemoveEvent() +# 18| Block 0 +# 18| v0_0(Void) = EnterFunction : +# 18| mu0_1(null) = AliasedDefinition : +# 18| mu0_2(null) = UnmodeledDefinition : +# 18| r0_3(glval) = InitializeThis : +# 20| r0_4(Events) = CopyValue : r0_3 +# 20| r0_5(glval) = FunctionAddress[remove_MyEvent] : +# 20| r0_6(Events) = CopyValue : r0_3 +# 20| r0_7(glval) = FieldAddress[Inst] : r0_6 +# 20| r0_8(MyDel) = Load : &:r0_7, ~mu0_2 +# 20| v0_9(Void) = Call : func:r0_5, this:r0_4, 0:r0_8 +# 20| mu0_10(null) = ^CallSideEffect : ~mu0_2 +# 18| v0_11(Void) = ReturnVoid : +# 18| v0_12(Void) = UnmodeledUse : mu* +# 18| v0_13(Void) = ExitFunction : + +# 23| System.String Events.Fun(System.String) +# 23| Block 0 +# 23| v0_0(Void) = EnterFunction : +# 23| mu0_1(null) = AliasedDefinition : +# 23| mu0_2(null) = UnmodeledDefinition : +# 23| r0_3(glval) = InitializeThis : +# 23| r0_4(glval) = VariableAddress[str] : +# 23| mu0_5(String) = InitializeParameter[str] : &:r0_4 +# 25| r0_6(glval) = VariableAddress[#return] : +# 25| r0_7(glval) = VariableAddress[str] : +# 25| r0_8(String) = Load : &:r0_7, ~mu0_2 +# 25| mu0_9(String) = Store : &:r0_6, r0_8 +# 23| r0_10(glval) = VariableAddress[#return] : +# 23| v0_11(Void) = ReturnValue : &:r0_10, ~mu0_2 +# 23| v0_12(Void) = UnmodeledUse : mu* +# 23| v0_13(Void) = ExitFunction : + +# 28| System.Void Events.Main(System.String[]) +# 28| Block 0 +# 28| v0_0(Void) = EnterFunction : +# 28| mu0_1(null) = AliasedDefinition : +# 28| mu0_2(null) = UnmodeledDefinition : +# 28| r0_3(glval) = VariableAddress[args] : +# 28| mu0_4(String[]) = InitializeParameter[args] : &:r0_3 +# 30| r0_5(glval) = VariableAddress[obj] : +# 30| r0_6(Events) = NewObj : +# 30| r0_7(glval) = FunctionAddress[Events] : +# 30| v0_8(Void) = Call : func:r0_7, this:r0_6 +# 30| mu0_9(null) = ^CallSideEffect : ~mu0_2 +# 30| mu0_10(Events) = Store : &:r0_5, r0_6 +# 31| r0_11(glval) = VariableAddress[obj] : +# 31| r0_12(Events) = Load : &:r0_11, ~mu0_2 +# 31| r0_13(glval) = FunctionAddress[AddEvent] : +# 31| v0_14(Void) = Call : func:r0_13, this:r0_12 +# 31| mu0_15(null) = ^CallSideEffect : ~mu0_2 +# 32| r0_16(glval) = VariableAddress[result] : +# 32| r0_17(glval) = VariableAddress[obj] : +# 32| r0_18(Events) = Load : &:r0_17, ~mu0_2 +# 32| r0_19(glval) = FunctionAddress[Invoke] : +# 32| r0_20(String) = StringConstant["string"] : +# 32| v0_21(Void) = Call : func:r0_19, this:r0_18, 0:r0_20 +# 32| mu0_22(null) = ^CallSideEffect : ~mu0_2 +# 32| mu0_23(String) = Store : &:r0_16, v0_21 +# 33| r0_24(glval) = VariableAddress[obj] : +# 33| r0_25(Events) = Load : &:r0_24, ~mu0_2 +# 33| r0_26(glval) = FunctionAddress[RemoveEvent] : +# 33| v0_27(Void) = Call : func:r0_26, this:r0_25 +# 33| mu0_28(null) = ^CallSideEffect : ~mu0_2 +# 28| v0_29(Void) = ReturnVoid : +# 28| v0_30(Void) = UnmodeledUse : mu* +# 28| v0_31(Void) = ExitFunction : foreach.cs: # 4| System.Void ForEach.Main() @@ -663,86 +704,102 @@ func_with_param_call.cs: # 10| v0_13(Void) = ExitFunction : indexers.cs: -# 8| System.String Indexers.Contact.get_Item(System.Int32) -# 8| Block 0 -# 8| v0_0(Void) = EnterFunction : -# 8| mu0_1(null) = AliasedDefinition : -# 8| mu0_2(null) = UnmodeledDefinition : -# 8| r0_3(glval) = InitializeThis : -# 6| r0_4(glval) = VariableAddress[index] : -# 6| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 -# 10| r0_6(glval) = VariableAddress[#return] : -# 10| r0_7(Contact) = CopyValue : r0_3 -# 10| r0_8(glval) = FieldAddress[address] : r0_7 -# 10| r0_9(String[]) = ElementsAddress : r0_8 -# 10| r0_10(glval) = VariableAddress[index] : -# 10| r0_11(Int32) = Load : &:r0_10, ~mu0_2 -# 10| r0_12(String[]) = PointerAdd[4] : r0_9, r0_11 -# 10| r0_13(String) = Load : &:r0_12, ~mu0_2 -# 10| mu0_14(String) = Store : &:r0_6, r0_13 -# 8| r0_15(glval) = VariableAddress[#return] : -# 8| v0_16(Void) = ReturnValue : &:r0_15, ~mu0_2 -# 8| v0_17(Void) = UnmodeledUse : mu* -# 8| v0_18(Void) = ExitFunction : +# 5| System.Void Indexers.MyClass..ctor() +# 5| Block 0 +# 5| v0_0(Void) = EnterFunction : +# 5| mu0_1(null) = AliasedDefinition : +# 5| mu0_2(null) = UnmodeledDefinition : +# 5| r0_3(glval) = InitializeThis : +# 6| v0_4(Void) = NoOp : +# 5| v0_5(Void) = ReturnVoid : +# 5| v0_6(Void) = UnmodeledUse : mu* +# 5| v0_7(Void) = ExitFunction : -# 12| System.Void Indexers.Contact.set_Item(System.Int32,System.String) +# 12| System.String Indexers.MyClass.get_Item(System.Int32) # 12| Block 0 -# 12| v0_0(Void) = EnterFunction : -# 12| mu0_1(null) = AliasedDefinition : -# 12| mu0_2(null) = UnmodeledDefinition : -# 12| r0_3(glval) = InitializeThis : -# 6| r0_4(glval) = VariableAddress[index] : -# 6| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 -# 12| r0_6(glval) = VariableAddress[value] : -# 12| mu0_7(String) = InitializeParameter[value] : &:r0_6 -# 14| r0_8(glval) = VariableAddress[value] : -# 14| r0_9(String) = Load : &:r0_8, ~mu0_2 -# 14| r0_10(Contact) = CopyValue : r0_3 -# 14| r0_11(glval) = FieldAddress[address] : r0_10 -# 14| r0_12(String[]) = ElementsAddress : r0_11 -# 14| r0_13(glval) = VariableAddress[index] : -# 14| r0_14(Int32) = Load : &:r0_13, ~mu0_2 -# 14| r0_15(String[]) = PointerAdd[4] : r0_12, r0_14 -# 14| mu0_16(String) = Store : &:r0_15, r0_9 -# 12| v0_17(Void) = ReturnVoid : -# 12| v0_18(Void) = UnmodeledUse : mu* -# 12| v0_19(Void) = ExitFunction : +# 12| v0_0(Void) = EnterFunction : +# 12| mu0_1(null) = AliasedDefinition : +# 12| mu0_2(null) = UnmodeledDefinition : +# 12| r0_3(glval) = InitializeThis : +# 10| r0_4(glval) = VariableAddress[index] : +# 10| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 +# 14| r0_6(glval) = VariableAddress[#return] : +# 14| r0_7(MyClass) = CopyValue : r0_3 +# 14| r0_8(glval) = FieldAddress[address] : r0_7 +# 14| r0_9(String[]) = ElementsAddress : r0_8 +# 14| r0_10(glval) = VariableAddress[index] : +# 14| r0_11(Int32) = Load : &:r0_10, ~mu0_2 +# 14| r0_12(String[]) = PointerAdd[8] : r0_9, r0_11 +# 14| r0_13(String) = Load : &:r0_12, ~mu0_2 +# 14| mu0_14(String) = Store : &:r0_6, r0_13 +# 12| r0_15(glval) = VariableAddress[#return] : +# 12| v0_16(Void) = ReturnValue : &:r0_15, ~mu0_2 +# 12| v0_17(Void) = UnmodeledUse : mu* +# 12| v0_18(Void) = ExitFunction : -# 19| System.Void Indexers.Main() -# 19| Block 0 -# 19| v0_0(Void) = EnterFunction : -# 19| mu0_1(null) = AliasedDefinition : -# 19| mu0_2(null) = UnmodeledDefinition : -# 21| r0_3(glval) = VariableAddress[contact] : -# 21| r0_4(Contact) = NewObj : -# 21| r0_5(glval) = FunctionAddress[Contact] : -# 21| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 21| mu0_7(null) = ^CallSideEffect : ~mu0_2 -# 21| mu0_8(Contact) = Store : &:r0_3, r0_4 -# 22| r0_9(glval) = VariableAddress[contact] : -# 22| r0_10(Contact) = Load : &:r0_9, ~mu0_2 -# 22| r0_11(glval) = FunctionAddress[set_Item] : -# 22| r0_12(Int32) = Constant[0] : -# 22| r0_13(String) = StringConstant["Begumpet"] : -# 22| v0_14(Void) = Call : func:r0_11, this:r0_10, 0:r0_12, 1:r0_13 -# 22| mu0_15(null) = ^CallSideEffect : ~mu0_2 -# 23| r0_16(glval) = VariableAddress[contact] : -# 23| r0_17(Contact) = Load : &:r0_16, ~mu0_2 -# 23| r0_18(glval) = FunctionAddress[set_Item] : -# 23| r0_19(Int32) = Constant[1] : -# 23| r0_20(String) = StringConstant["Hyderabad"] : -# 23| v0_21(Void) = Call : func:r0_18, this:r0_17, 0:r0_19, 1:r0_20 -# 23| mu0_22(null) = ^CallSideEffect : ~mu0_2 -# 24| r0_23(glval) = VariableAddress[contact] : -# 24| r0_24(Contact) = Load : &:r0_23, ~mu0_2 -# 24| r0_25(glval) = FunctionAddress[set_Item] : -# 24| r0_26(Int32) = Constant[2] : -# 24| r0_27(String) = StringConstant["Telengana"] : -# 24| v0_28(Void) = Call : func:r0_25, this:r0_24, 0:r0_26, 1:r0_27 -# 24| mu0_29(null) = ^CallSideEffect : ~mu0_2 -# 19| v0_30(Void) = ReturnVoid : -# 19| v0_31(Void) = UnmodeledUse : mu* -# 19| v0_32(Void) = ExitFunction : +# 16| System.Void Indexers.MyClass.set_Item(System.Int32,System.String) +# 16| Block 0 +# 16| v0_0(Void) = EnterFunction : +# 16| mu0_1(null) = AliasedDefinition : +# 16| mu0_2(null) = UnmodeledDefinition : +# 16| r0_3(glval) = InitializeThis : +# 10| r0_4(glval) = VariableAddress[index] : +# 10| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 +# 16| r0_6(glval) = VariableAddress[value] : +# 16| mu0_7(String) = InitializeParameter[value] : &:r0_6 +# 18| r0_8(glval) = VariableAddress[value] : +# 18| r0_9(String) = Load : &:r0_8, ~mu0_2 +# 18| r0_10(MyClass) = CopyValue : r0_3 +# 18| r0_11(glval) = FieldAddress[address] : r0_10 +# 18| r0_12(String[]) = ElementsAddress : r0_11 +# 18| r0_13(glval) = VariableAddress[index] : +# 18| r0_14(Int32) = Load : &:r0_13, ~mu0_2 +# 18| r0_15(String[]) = PointerAdd[8] : r0_12, r0_14 +# 18| mu0_16(String) = Store : &:r0_15, r0_9 +# 16| v0_17(Void) = ReturnVoid : +# 16| v0_18(Void) = UnmodeledUse : mu* +# 16| v0_19(Void) = ExitFunction : + +# 23| System.Void Indexers.Main() +# 23| Block 0 +# 23| v0_0(Void) = EnterFunction : +# 23| mu0_1(null) = AliasedDefinition : +# 23| mu0_2(null) = UnmodeledDefinition : +# 25| r0_3(glval) = VariableAddress[inst] : +# 25| r0_4(MyClass) = NewObj : +# 25| r0_5(glval) = FunctionAddress[MyClass] : +# 25| v0_6(Void) = Call : func:r0_5, this:r0_4 +# 25| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 25| mu0_8(MyClass) = Store : &:r0_3, r0_4 +# 26| r0_9(glval) = VariableAddress[inst] : +# 26| r0_10(MyClass) = Load : &:r0_9, ~mu0_2 +# 26| r0_11(glval) = FunctionAddress[set_Item] : +# 26| r0_12(Int32) = Constant[0] : +# 26| r0_13(String) = StringConstant["str1"] : +# 26| v0_14(Void) = Call : func:r0_11, this:r0_10, 0:r0_12, 1:r0_13 +# 26| mu0_15(null) = ^CallSideEffect : ~mu0_2 +# 27| r0_16(glval) = VariableAddress[inst] : +# 27| r0_17(MyClass) = Load : &:r0_16, ~mu0_2 +# 27| r0_18(glval) = FunctionAddress[set_Item] : +# 27| r0_19(Int32) = Constant[1] : +# 27| r0_20(String) = StringConstant["str1"] : +# 27| v0_21(Void) = Call : func:r0_18, this:r0_17, 0:r0_19, 1:r0_20 +# 27| mu0_22(null) = ^CallSideEffect : ~mu0_2 +# 28| r0_23(glval) = VariableAddress[inst] : +# 28| r0_24(MyClass) = Load : &:r0_23, ~mu0_2 +# 28| r0_25(glval) = FunctionAddress[set_Item] : +# 28| r0_26(Int32) = Constant[1] : +# 28| r0_27(glval) = VariableAddress[inst] : +# 28| r0_28(MyClass) = Load : &:r0_27, ~mu0_2 +# 28| r0_29(glval) = FunctionAddress[get_Item] : +# 28| r0_30(Int32) = Constant[0] : +# 28| r0_31(String) = Call : func:r0_29, this:r0_28, 0:r0_30 +# 28| mu0_32(null) = ^CallSideEffect : ~mu0_2 +# 28| v0_33(Void) = Call : func:r0_25, this:r0_24, 0:r0_26, 1:r0_31 +# 28| mu0_34(null) = ^CallSideEffect : ~mu0_2 +# 23| v0_35(Void) = ReturnVoid : +# 23| v0_36(Void) = UnmodeledUse : mu* +# 23| v0_37(Void) = ExitFunction : inheritance_polymorphism.cs: # 3| System.Int32 A.function() From 69365ccd031b839fcc2ff32b3cb5d1365f18785c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 25 Sep 2019 13:34:18 +0200 Subject: [PATCH 0252/1227] remove false positive in missingSpaceInAppend by requring the presence of a word-like fragment --- change-notes/1.22/analysis-javascript.md | 1 + .../src/Expressions/MissingSpaceInAppend.ql | 52 ++++++++++++++++--- .../MissingSpaceInAppend.expected | 1 + .../MissingSpaceInAppend/missing.js | 2 + .../Expressions/MissingSpaceInAppend/ok.js | 5 +- 5 files changed, 54 insertions(+), 7 deletions(-) diff --git a/change-notes/1.22/analysis-javascript.md b/change-notes/1.22/analysis-javascript.md index fd211197157..fd09522fc25 100644 --- a/change-notes/1.22/analysis-javascript.md +++ b/change-notes/1.22/analysis-javascript.md @@ -36,6 +36,7 @@ | Shift out of range (`js/shift-out-of-range`| Fewer false positive results | This rule now correctly handles BigInt shift operands. | | Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer false-positive results. | This rule no longer flags calls to placeholder functions that trivially throw an exception. | | Undocumented parameter (`js/jsdoc/missing-parameter`) | No changes to results | This rule is now run on LGTM, although its results are still not shown by default. | +| Missing space in string concatenation (`js/missing-space-in-concatenation`) | Fewer false positive results | The rule now requires a word-like part exists in the string concatenation. | ## Changes to QL libraries diff --git a/javascript/ql/src/Expressions/MissingSpaceInAppend.ql b/javascript/ql/src/Expressions/MissingSpaceInAppend.ql index 4870927fd51..bd744109675 100644 --- a/javascript/ql/src/Expressions/MissingSpaceInAppend.ql +++ b/javascript/ql/src/Expressions/MissingSpaceInAppend.ql @@ -22,14 +22,51 @@ Expr leftChild(Expr e) { result = e.(AddExpr).getLeftOperand() } -class LiteralOrTemplate extends Expr { - LiteralOrTemplate() { - this instanceof TemplateLiteral or - this instanceof Literal +predicate isInConcat(Expr e) { + exists(ParExpr par | par.getExpression() = e) + or + exists(AddExpr a | a.getAnOperand() = e) +} + +class ConcatenationLiteral extends Expr { + ConcatenationLiteral() { + ( + this instanceof TemplateLiteral + or + this instanceof Literal + ) + and isInConcat(this) } } -from AddExpr e, LiteralOrTemplate l, LiteralOrTemplate r, string word +Expr getConcatChild(Expr e) { + result = rightChild(e) or + result = leftChild(e) +} + +Expr getConcatParent(Expr e) { + e = getConcatChild(result) +} + +predicate isWordLike(ConcatenationLiteral lit) { + lit.getStringValue().regexpMatch("(?i).*[a-z]{3,}.*") +} + +class ConcatRoot extends AddExpr { + ConcatRoot() { + not isInConcat(this) + } +} + +ConcatRoot getAddRoot(AddExpr e) { + result = getConcatParent*(e) +} + +predicate hasWordLikeFragment(AddExpr e) { + isWordLike(getConcatChild*(getAddRoot(e))) +} + +from AddExpr e, ConcatenationLiteral l, ConcatenationLiteral r, string word where // l and r are appended together l = rightChild*(e.getLeftOperand()) and @@ -41,5 +78,8 @@ where // needed, and intra-identifier punctuation in, for example, a qualified name. word = l.getStringValue().regexpCapture(".* (([-A-Za-z/'\\.:,]*[a-zA-Z]|[0-9]+)[\\.:,!?']*)", 1) and r.getStringValue().regexpMatch("[a-zA-Z].*") and - not word.regexpMatch(".*[,\\.:].*[a-zA-Z].*[^a-zA-Z]") + not word.regexpMatch(".*[,\\.:].*[a-zA-Z].*[^a-zA-Z]") and + + // There must be a constant-string in the concatenation that looks like a word. + hasWordLikeFragment(e) select l, "This string appears to be missing a space after '" + word + "'." diff --git a/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/MissingSpaceInAppend.expected b/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/MissingSpaceInAppend.expected index 5be6f307c43..20e61738e7b 100644 --- a/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/MissingSpaceInAppend.expected +++ b/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/MissingSpaceInAppend.expected @@ -11,3 +11,4 @@ | missing.js:24:5:24:21 | `missing a space` | This string appears to be missing a space after 'space'. | | missing.js:26:5:26:21 | "missing a space" | This string appears to be missing a space after 'space'. | | missing.js:28:5:28:21 | `missing a space` | This string appears to be missing a space after 'space'. | +| missing.js:31:7:31:12 | "h. 0" | This string appears to be missing a space after '0'. | diff --git a/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/missing.js b/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/missing.js index 58b72d2da51..c97f6be724e 100644 --- a/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/missing.js +++ b/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/missing.js @@ -27,3 +27,5 @@ s = "missing a space" + `here`; s = `missing a space` + `here`; + +s = (("h. 0" + "h")) + "word" diff --git a/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/ok.js b/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/ok.js index b4791701528..f0adfd8254a 100644 --- a/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/ok.js +++ b/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/ok.js @@ -8,4 +8,7 @@ s = "the class java.util." + s = "some data: a,b,c," + "d,e,f"; s = "overflow: scroll;" + - "position: absolute;"; \ No newline at end of file + "position: absolute;"; + +s = "h. 0" + "h" +s = ((("h. 0"))) + (("h")) + ("h") \ No newline at end of file From 3f974fbc14c758298540415e4eb563897e43271b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 26 Sep 2019 12:57:08 +0200 Subject: [PATCH 0253/1227] Python: Modernise the `py/not-named-cls` query. --- python/ql/src/Functions/NonCls.ql | 4 ++-- python/ql/src/semmle/python/objects/ObjectAPI.qll | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/python/ql/src/Functions/NonCls.ql b/python/ql/src/Functions/NonCls.ql index 015263df19f..34bfbe9ea80 100644 --- a/python/ql/src/Functions/NonCls.ql +++ b/python/ql/src/Functions/NonCls.ql @@ -23,13 +23,13 @@ predicate first_arg_cls(Function f) { } predicate is_type_method(Function f) { - exists(ClassObject c | c.getPyClass() = f.getScope() and c.getASuperType() = theTypeType()) + exists(ClassValue c | c.getScope() = f.getScope() and c.getASuperType() = ClassValue::type()) } predicate classmethod_decorators_only(Function f) { forall(Expr decorator | decorator = f.getADecorator() | - ((Name) decorator).getId() = "classmethod") + decorator.(Name).getId() = "classmethod") } from Function f, string message diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 35392f456df..7d3526edf76 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -560,6 +560,11 @@ module ClassValue { result = TBuiltinClassObject(Builtin::special("FunctionType")) } + /** Get the `ClassValue` for the `type` class. */ + ClassValue type() { + result = TType() + } + /** Get the `ClassValue` for the class of builtin functions. */ ClassValue builtinFunction() { result = Value::named("len").getClass() From c6d9eb9254eeb5ed24ca7f2bd58b2fc3202530c7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 23 Sep 2019 15:28:43 +0200 Subject: [PATCH 0254/1227] Python: Move more tests for argument names into own file Plus fixup of expected output from unrelated tests --- ...odificationOfParameterWithDefault.expected | 16 ++++----- .../Functions/general/argument_names.py | 36 +++++++++++++++++++ .../Functions/general/functions_test.py | 34 ------------------ 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected b/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected index bc4b1153499..9b7af6df8b7 100644 --- a/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected +++ b/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected @@ -1,14 +1,14 @@ edges | functions_test.py:39:9:39:9 | empty mutable value | functions_test.py:40:5:40:5 | empty mutable value | | functions_test.py:133:15:133:15 | empty mutable value | functions_test.py:134:5:134:5 | empty mutable value | -| functions_test.py:185:25:185:25 | empty mutable value | functions_test.py:186:5:186:5 | empty mutable value | -| functions_test.py:188:21:188:21 | empty mutable value | functions_test.py:189:5:189:5 | empty mutable value | -| functions_test.py:191:27:191:27 | empty mutable value | functions_test.py:192:25:192:25 | empty mutable value | -| functions_test.py:191:27:191:27 | empty mutable value | functions_test.py:193:21:193:21 | empty mutable value | -| functions_test.py:192:25:192:25 | empty mutable value | functions_test.py:185:25:185:25 | empty mutable value | -| functions_test.py:193:21:193:21 | empty mutable value | functions_test.py:188:21:188:21 | empty mutable value | +| functions_test.py:151:25:151:25 | empty mutable value | functions_test.py:152:5:152:5 | empty mutable value | +| functions_test.py:154:21:154:21 | empty mutable value | functions_test.py:155:5:155:5 | empty mutable value | +| functions_test.py:157:27:157:27 | empty mutable value | functions_test.py:158:25:158:25 | empty mutable value | +| functions_test.py:157:27:157:27 | empty mutable value | functions_test.py:159:21:159:21 | empty mutable value | +| functions_test.py:158:25:158:25 | empty mutable value | functions_test.py:151:25:151:25 | empty mutable value | +| functions_test.py:159:21:159:21 | empty mutable value | functions_test.py:154:21:154:21 | empty mutable value | #select | functions_test.py:40:5:40:5 | x | functions_test.py:39:9:39:9 | empty mutable value | functions_test.py:40:5:40:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:39:9:39:9 | x | Default value | | functions_test.py:134:5:134:5 | x | functions_test.py:133:15:133:15 | empty mutable value | functions_test.py:134:5:134:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:133:15:133:15 | x | Default value | -| functions_test.py:186:5:186:5 | x | functions_test.py:191:27:191:27 | empty mutable value | functions_test.py:186:5:186:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:191:27:191:27 | y | Default value | -| functions_test.py:189:5:189:5 | x | functions_test.py:191:27:191:27 | empty mutable value | functions_test.py:189:5:189:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:191:27:191:27 | y | Default value | +| functions_test.py:152:5:152:5 | x | functions_test.py:157:27:157:27 | empty mutable value | functions_test.py:152:5:152:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:157:27:157:27 | y | Default value | +| functions_test.py:155:5:155:5 | x | functions_test.py:157:27:157:27 | empty mutable value | functions_test.py:155:5:155:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:157:27:157:27 | y | Default value | diff --git a/python/ql/test/query-tests/Functions/general/argument_names.py b/python/ql/test/query-tests/Functions/general/argument_names.py index f245bdf3d74..ebd90f17670 100644 --- a/python/ql/test/query-tests/Functions/general/argument_names.py +++ b/python/ql/test/query-tests/Functions/general/argument_names.py @@ -66,3 +66,39 @@ class NonSelf(object): def s_cmethod2(cls): pass s_cmethod2 = classmethod(s_cmethod2) + +#Possible FPs for non-self. ODASA-2439 + +class C(object): + def _func(f): + return f + + _func(x) + + #or + @_func + def meth(self): + pass + + +def dont_care(arg): + pass + +class C(object): + + meth = dont_care + +class Meta(type): + + #__new__ is an implicit class method, so the first arg is the metaclass + def __new__(metacls, name, bases, cls_dict): + return super(Meta, metacls).__new__(metacls, name, bases, cls_dict) + +#ODASA-6062 +import zope.interface +class Z(zope.interface.Interface): + + def meth(arg): + pass + +Z().meth(0) diff --git a/python/ql/test/query-tests/Functions/general/functions_test.py b/python/ql/test/query-tests/Functions/general/functions_test.py index 104371d2ac4..271539792e7 100644 --- a/python/ql/test/query-tests/Functions/general/functions_test.py +++ b/python/ql/test/query-tests/Functions/general/functions_test.py @@ -134,33 +134,6 @@ def augassign(x = []): x += ["x"] -#Possible FPs for non-self. ODASA-2439 - -class C(object): - def _func(f): - return f - - _func(x) - - #or - @_func - def meth(self): - pass - - -def dont_care(arg): - pass - -class C(object): - - meth = dont_care - -class Meta(type): - - #__new__ is an implicit class method, so the first arg is the metaclass - def __new__(metacls, name, bases, cls_dict): - return super(Meta, metacls).__new__(metacls, name, bases, cls_dict) - #ODASA 3658 from sys import exit #Consistent returns @@ -172,14 +145,7 @@ def ok5(): print(e) exit(EXIT_ERROR) -#ODASA-6062 -import zope.interface -class Z(zope.interface.Interface): - def meth(arg): - pass - -Z().meth(0) # indirect modification of parameter with default def aug_assign_argument(x): From a81bf720f5370eadb1e74e4cccae53fdbcf858c8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 25 Sep 2019 15:54:21 +0200 Subject: [PATCH 0255/1227] Python: Modernise the `py/not-named-self` query. --- python/ql/src/Functions/NonSelf.ql | 36 +++++++++---------- .../ql/src/semmle/python/libraries/Zope.qll | 21 ++++++++++- .../types/functions/Zope.expected | 2 +- .../library-tests/types/functions/Zope.ql | 2 +- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/python/ql/src/Functions/NonSelf.ql b/python/ql/src/Functions/NonSelf.ql index 37b7ee0ef06..22e23ba5c01 100644 --- a/python/ql/src/Functions/NonSelf.ql +++ b/python/ql/src/Functions/NonSelf.ql @@ -16,39 +16,37 @@ import python import semmle.python.libraries.Zope -predicate first_arg_self(Function f) { - f.getArgName(0) = "self" +predicate is_type_method(FunctionValue fv) { + exists(ClassValue c | c.declaredAttribute(_) = fv and c.getASuperType() = ClassValue::type()) } -predicate is_type_method(FunctionObject f) { - exists(ClassObject c | c.lookupAttribute(_) = f and c.getASuperType() = theTypeType()) -} - -predicate used_in_defining_scope(FunctionObject f) { - exists(Call c | - c.getScope() = f.getFunction().getScope() and - c.getFunc().refersTo(f) +predicate used_in_defining_scope(FunctionValue fv) { + exists(Call c | + c.getScope() = fv.getScope().getScope() and c.getFunc().pointsTo(fv) ) } -from Function f, PyFunctionObject func, string message +from Function f, FunctionValue fv, string message where -exists(ClassObject cls, string name | - cls.declaredAttribute(name) = func and cls.isNewStyle() and +exists(ClassValue cls, string name | + cls.declaredAttribute(name) = fv and cls.isNewStyle() and not name = "__new__" and not name = "__metaclass__" and /* declared in scope */ - f.getScope() = cls.getPyClass() + f.getScope() = cls.getScope() ) and -not first_arg_self(f) and not is_type_method(func) and -func.getFunction() = f and not f.getName() = "lambda" and -not used_in_defining_scope(func) and +not f.getArgName(0) = "self" and +not is_type_method(fv) and +fv.getScope() = f and +not f.getName() = "lambda" and +not used_in_defining_scope(fv) and ( if exists(f.getArgName(0)) then message = "Normal methods should have 'self', rather than '" + f.getArgName(0) + "', as their first parameter." else - message = "Normal methods should have at least one parameter (the first of which should be 'self')." and not f.hasVarArg() + message = "Normal methods should have at least one parameter (the first of which should be 'self')." and + not f.hasVarArg() ) and -not func instanceof ZopeInterfaceMethod +not fv instanceof ZopeInterfaceMethodValue select f, message diff --git a/python/ql/src/semmle/python/libraries/Zope.qll b/python/ql/src/semmle/python/libraries/Zope.qll index b58adcaf7fc..7199cbcfbe0 100644 --- a/python/ql/src/semmle/python/libraries/Zope.qll +++ b/python/ql/src/semmle/python/libraries/Zope.qll @@ -2,8 +2,10 @@ import python +private import semmle.python.pointsto.PointsTo + /** A method that to a sub-class of `zope.interface.Interface` */ -class ZopeInterfaceMethod extends PyFunctionObject { +deprecated class ZopeInterfaceMethod extends PyFunctionObject { /** Holds if this method belongs to a class that sub-classes `zope.interface.Interface` */ ZopeInterfaceMethod() { @@ -26,3 +28,20 @@ class ZopeInterfaceMethod extends PyFunctionObject { } } + +/** A method that belongs to a sub-class of `zope.interface.Interface` */ +class ZopeInterfaceMethodValue extends PythonFunctionValue { + + /** Holds if this method belongs to a class that sub-classes `zope.interface.Interface` */ + ZopeInterfaceMethodValue() { + exists(Value interface, ClassValue owner | + interface = Module::named("zope.interface").attr("Interface") and + owner.declaredAttribute(_) = this and + // `zope.interface.Interface` will be recognized as a Value by the pointsTo analysis, + // because it is the result of instantiating a "meta" class. getASuperType only returns + // ClassValues, so we do this little trick to make things work + Types::getBase(owner.getASuperType(), _) = interface + ) + } + +} diff --git a/python/ql/test/library-tests/types/functions/Zope.expected b/python/ql/test/library-tests/types/functions/Zope.expected index 339baf4798a..ef743dd8589 100644 --- a/python/ql/test/library-tests/types/functions/Zope.expected +++ b/python/ql/test/library-tests/types/functions/Zope.expected @@ -1 +1 @@ -| Function yes | +| Function Z.yes | diff --git a/python/ql/test/library-tests/types/functions/Zope.ql b/python/ql/test/library-tests/types/functions/Zope.ql index d3143778b2b..91b828b2ff2 100644 --- a/python/ql/test/library-tests/types/functions/Zope.ql +++ b/python/ql/test/library-tests/types/functions/Zope.ql @@ -2,5 +2,5 @@ import python import semmle.python.libraries.Zope -from ZopeInterfaceMethod f +from ZopeInterfaceMethodValue f select f.toString() From 5271d6a06374a03156c55c0a9b3955bf9325d592 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 25 Sep 2019 15:22:18 +0200 Subject: [PATCH 0256/1227] Python: Add min/max #parameters to FunctionValue So we don't loose this information on the newly migrated/modernise zope interface --- .../ql/src/semmle/python/libraries/Zope.qll | 11 ++++++ .../src/semmle/python/objects/ObjectAPI.qll | 37 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/python/ql/src/semmle/python/libraries/Zope.qll b/python/ql/src/semmle/python/libraries/Zope.qll index 7199cbcfbe0..8f69c792b5d 100644 --- a/python/ql/src/semmle/python/libraries/Zope.qll +++ b/python/ql/src/semmle/python/libraries/Zope.qll @@ -44,4 +44,15 @@ class ZopeInterfaceMethodValue extends PythonFunctionValue { ) } + override int minParameters() { + result = super.minParameters() + 1 + } + + override int maxParameters() { + if exists(this.getScope().getVararg()) then + result = super.maxParameters() + else + result = super.maxParameters() + 1 + } + } diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 7d3526edf76..9eac5c073af 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -434,6 +434,11 @@ abstract class FunctionValue extends CallableValue { abstract string getQualifiedName(); + /** Gets the minimum number of parameters that can be correctly passed to this function */ + abstract int minParameters(); + + /** Gets the maximum number of parameters that can be correctly passed to this function */ + abstract int maxParameters(); } /** Class representing Python functions */ @@ -447,6 +452,23 @@ class PythonFunctionValue extends FunctionValue { result = this.(PythonFunctionObjectInternal).getScope().getQualifiedName() } + override int minParameters() { + exists(Function f | + f = this.getScope() and + result = count(f.getAnArg()) - count(f.getDefinition().getArgs().getADefault()) + ) + } + + override int maxParameters() { + exists(Function f | + f = this.getScope() and + if exists(f.getVararg()) then + result = 2147483647 // INT_MAX + else + result = count(f.getAnArg()) + ) + } + } /** Class representing builtin functions, such as `len` or `print` */ @@ -460,6 +482,13 @@ class BuiltinFunctionValue extends FunctionValue { result = this.(BuiltinFunctionObjectInternal).getName() } + override int minParameters() { + none() + } + + override int maxParameters() { + none() + } } /** Class representing builtin methods, such as `list.append` or `set.add` */ @@ -477,6 +506,14 @@ class BuiltinMethodValue extends FunctionValue { ) } + override int minParameters() { + none() + } + + override int maxParameters() { + none() + } + } /** A class representing sequence objects with a length and tracked items. From 546405a379b54f43b437476d8b3dc947abee178b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 24 Sep 2019 16:03:19 +0200 Subject: [PATCH 0257/1227] Python: Add more tests for cls/self argument names --- .../Functions/general/NonCls.expected | 3 ++- .../Functions/general/NonSelf.expected | 5 ++-- .../Functions/general/argument_names.py | 27 ++++++++++++++----- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/python/ql/test/query-tests/Functions/general/NonCls.expected b/python/ql/test/query-tests/Functions/general/NonCls.expected index 59e2d12ceda..0ca17babe3e 100644 --- a/python/ql/test/query-tests/Functions/general/NonCls.expected +++ b/python/ql/test/query-tests/Functions/general/NonCls.expected @@ -1,2 +1,3 @@ | argument_names.py:17:5:17:24 | Function n_cmethod | Class methods or methods of a type deriving from type should have 'cls', rather than 'self', as their first argument. | -| argument_names.py:32:5:32:20 | Function c_method | Class methods or methods of a type deriving from type should have 'cls', rather than 'y', as their first argument. | +| argument_names.py:22:5:22:21 | Function n_cmethod2 | Class methods or methods of a type deriving from type should have 'cls' as their first argument. | +| argument_names.py:37:5:37:20 | Function c_method | Class methods or methods of a type deriving from type should have 'cls', rather than 'y', as their first argument. | diff --git a/python/ql/test/query-tests/Functions/general/NonSelf.expected b/python/ql/test/query-tests/Functions/general/NonSelf.expected index d35e282cb55..ff2959353fc 100644 --- a/python/ql/test/query-tests/Functions/general/NonSelf.expected +++ b/python/ql/test/query-tests/Functions/general/NonSelf.expected @@ -1,3 +1,4 @@ -| argument_names.py:45:5:45:20 | Function __init__ | Normal methods should have 'self', rather than 'x', as their first parameter. | -| argument_names.py:48:5:48:20 | Function s_method | Normal methods should have 'self', rather than 'y', as their first parameter. | +| argument_names.py:50:5:50:20 | Function __init__ | Normal methods should have 'self', rather than 'x', as their first parameter. | +| argument_names.py:53:5:53:20 | Function s_method | Normal methods should have 'self', rather than 'y', as their first parameter. | +| argument_names.py:56:5:56:20 | Function s_method2 | Normal methods should have at least one parameter (the first of which should be 'self'). | | om_test.py:71:5:71:19 | Function __repr__ | Normal methods should have at least one parameter (the first of which should be 'self'). | diff --git a/python/ql/test/query-tests/Functions/general/argument_names.py b/python/ql/test/query-tests/Functions/general/argument_names.py index ebd90f17670..e4e446dd4d4 100644 --- a/python/ql/test/query-tests/Functions/general/argument_names.py +++ b/python/ql/test/query-tests/Functions/general/argument_names.py @@ -17,6 +17,11 @@ class Normal(object): def n_cmethod(self): pass + # not ok + @classmethod + def n_cmethod2(): + pass + # this is allowed because it has a decorator other than @classmethod @classmethod @id @@ -48,6 +53,9 @@ class NonSelf(object): def s_method(y): pass + def s_method2(): + pass + def s_ok(self): pass @@ -69,25 +77,32 @@ class NonSelf(object): #Possible FPs for non-self. ODASA-2439 -class C(object): +class Acceptable1(object): + def _func(f): + return f + _func(x) + +class Acceptable2(object): def _func(f): return f - _func(x) - - #or @_func def meth(self): pass - +# Handling methods defined in a different scope than the class it belongs to, +# gets problmematic since we need to show the full-path from method definition +# to actually adding it to the class. We tried to enable warnings for these in +# September 2019, but ended up sticking to the decision from ODASA-2439 (where +# results are both obvious and useful to the end-user). def dont_care(arg): pass -class C(object): +class Acceptable3(object): meth = dont_care +# OK class Meta(type): #__new__ is an implicit class method, so the first arg is the metaclass From 12c49031e8d4681028782571422f298ac562354e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 26 Sep 2019 15:03:47 +0200 Subject: [PATCH 0258/1227] Python: Modernise bottle library --- python/ql/src/semmle/python/web/bottle/General.qll | 10 +++++----- python/ql/src/semmle/python/web/bottle/Redirect.qll | 2 +- python/ql/src/semmle/python/web/bottle/Request.qll | 4 ++-- python/ql/src/semmle/python/web/bottle/Response.qll | 4 ++-- .../ql/test/library-tests/web/bottle/Sources.expected | 2 -- python/ql/test/library-tests/web/bottle/Taint.expected | 2 -- python/ql/test/query-tests/Security/lib/bottle.py | 1 - 7 files changed, 10 insertions(+), 15 deletions(-) diff --git a/python/ql/src/semmle/python/web/bottle/General.qll b/python/ql/src/semmle/python/web/bottle/General.qll index e7751ac5d15..436982ad073 100644 --- a/python/ql/src/semmle/python/web/bottle/General.qll +++ b/python/ql/src/semmle/python/web/bottle/General.qll @@ -3,12 +3,12 @@ import semmle.python.web.Http import semmle.python.types.Extensions /** The bottle module */ -ModuleObject theBottleModule() { - result = ModuleObject::named("bottle") +ModuleValue theBottleModule() { + result = Module::named("bottle") } /** The bottle.Bottle class */ -ClassObject theBottleClass() { +ClassValue theBottleClass() { result = theBottleModule().attr("Bottle") } @@ -17,8 +17,8 @@ ClassObject theBottleClass() { */ predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func) { exists(CallNode decorator_call, string name | - route_call.getFunction().(AttrNode).getObject(name).refersTo(_, theBottleClass(), _) or - route_call.getFunction().refersTo(theBottleModule().attr(name)) + route_call.getFunction().(AttrNode).getObject(name).pointsTo().getClass() = theBottleClass() or + route_call.getFunction().pointsTo(theBottleModule().attr(name)) | (name = "route" or name = httpVerbLower()) and decorator_call.getFunction() = route_call and diff --git a/python/ql/src/semmle/python/web/bottle/Redirect.qll b/python/ql/src/semmle/python/web/bottle/Redirect.qll index 666d4038f3c..a02166be8b7 100644 --- a/python/ql/src/semmle/python/web/bottle/Redirect.qll +++ b/python/ql/src/semmle/python/web/bottle/Redirect.qll @@ -8,7 +8,7 @@ import semmle.python.security.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.bottle.General -FunctionObject bottle_redirect() { +FunctionValue bottle_redirect() { result = theBottleModule().attr("redirect") } diff --git a/python/ql/src/semmle/python/web/bottle/Request.qll b/python/ql/src/semmle/python/web/bottle/Request.qll index d54318dae59..80b307fb63e 100644 --- a/python/ql/src/semmle/python/web/bottle/Request.qll +++ b/python/ql/src/semmle/python/web/bottle/Request.qll @@ -6,7 +6,7 @@ import semmle.python.security.strings.Untrusted import semmle.python.web.Http import semmle.python.web.bottle.General -private Object theBottleRequestObject() { +private Value theBottleRequestObject() { result = theBottleModule().attr("request") } @@ -32,7 +32,7 @@ class BottleRequestKind extends TaintKind { private class RequestSource extends TaintSource { RequestSource() { - this.(ControlFlowNode).refersTo(theBottleRequestObject()) + this.(ControlFlowNode).pointsTo(theBottleRequestObject()) } override predicate isSourceOf(TaintKind kind) { diff --git a/python/ql/src/semmle/python/web/bottle/Response.qll b/python/ql/src/semmle/python/web/bottle/Response.qll index e2b94cc46a8..b90aea152cf 100644 --- a/python/ql/src/semmle/python/web/bottle/Response.qll +++ b/python/ql/src/semmle/python/web/bottle/Response.qll @@ -18,7 +18,7 @@ class BottleResponse extends TaintKind { } -private Object theBottleResponseObject() { +private Value theBottleResponseObject() { result = theBottleModule().attr("response") } @@ -27,7 +27,7 @@ class BottleResponseBodyAssignment extends HttpResponseTaintSink { BottleResponseBodyAssignment() { exists(DefinitionNode lhs | lhs.getValue() = this and - lhs.(AttrNode).getObject("body").refersTo(theBottleResponseObject()) + lhs.(AttrNode).getObject("body").pointsTo(theBottleResponseObject()) ) } diff --git a/python/ql/test/library-tests/web/bottle/Sources.expected b/python/ql/test/library-tests/web/bottle/Sources.expected index ae780564c37..46c419efb95 100644 --- a/python/ql/test/library-tests/web/bottle/Sources.expected +++ b/python/ql/test/library-tests/web/bottle/Sources.expected @@ -1,7 +1,5 @@ | ../../../query-tests/Security/lib/bottle.py:64 | LocalRequest() | bottle.request | -| ../../../query-tests/Security/lib/bottle.py:64 | request | bottle.request | | test.py:3 | ImportMember | bottle.request | -| test.py:3 | request | bottle.request | | test.py:8 | name | externally controlled string | | test.py:12 | name | externally controlled string | | test.py:18 | request | bottle.request | diff --git a/python/ql/test/library-tests/web/bottle/Taint.expected b/python/ql/test/library-tests/web/bottle/Taint.expected index ea97dab3473..451b1ee3e00 100644 --- a/python/ql/test/library-tests/web/bottle/Taint.expected +++ b/python/ql/test/library-tests/web/bottle/Taint.expected @@ -1,8 +1,6 @@ | ../../../query-tests/Security/lib/bottle.py:64 | LocalRequest() | bottle.request | -| ../../../query-tests/Security/lib/bottle.py:64 | request | bottle.request | | ../../../query-tests/Security/lib/bottle.py:68 | url | externally controlled string | | test.py:3 | ImportMember | bottle.request | -| test.py:3 | request | bottle.request | | test.py:8 | name | externally controlled string | | test.py:9 | BinaryExpr | externally controlled string | | test.py:9 | name | externally controlled string | diff --git a/python/ql/test/query-tests/Security/lib/bottle.py b/python/ql/test/query-tests/Security/lib/bottle.py index bd2d736c192..fe42507852c 100644 --- a/python/ql/test/query-tests/Security/lib/bottle.py +++ b/python/ql/test/query-tests/Security/lib/bottle.py @@ -67,4 +67,3 @@ response = LocalResponse() def redirect(url, code=None): pass - From 41f16aaf7ab942de092cc5ee4630dc496fe8b341 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 26 Sep 2019 15:05:51 +0200 Subject: [PATCH 0259/1227] Python: Autoformat (4 spaces) bottle library --- .../src/semmle/python/web/bottle/General.qll | 24 +++----- .../src/semmle/python/web/bottle/Redirect.qll | 19 ++----- .../src/semmle/python/web/bottle/Request.qll | 57 ++++--------------- .../src/semmle/python/web/bottle/Response.qll | 34 +++-------- 4 files changed, 31 insertions(+), 103 deletions(-) diff --git a/python/ql/src/semmle/python/web/bottle/General.qll b/python/ql/src/semmle/python/web/bottle/General.qll index 436982ad073..765b4cb1add 100644 --- a/python/ql/src/semmle/python/web/bottle/General.qll +++ b/python/ql/src/semmle/python/web/bottle/General.qll @@ -3,23 +3,20 @@ import semmle.python.web.Http import semmle.python.types.Extensions /** The bottle module */ -ModuleValue theBottleModule() { - result = Module::named("bottle") -} +ModuleValue theBottleModule() { result = Module::named("bottle") } /** The bottle.Bottle class */ -ClassValue theBottleClass() { - result = theBottleModule().attr("Bottle") -} +ClassValue theBottleClass() { result = theBottleModule().attr("Bottle") } -/** Holds if `route` is routed to `func` +/** + * Holds if `route` is routed to `func` * by decorating `func` with `app.route(route)` or `route(route)` */ predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func) { exists(CallNode decorator_call, string name | route_call.getFunction().(AttrNode).getObject(name).pointsTo().getClass() = theBottleClass() or route_call.getFunction().pointsTo(theBottleModule().attr(name)) - | + | (name = "route" or name = httpVerbLower()) and decorator_call.getFunction() = route_call and route_call.getArg(0) = route and @@ -28,10 +25,7 @@ predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func } class BottleRoute extends ControlFlowNode { - - BottleRoute() { - bottle_route(this, _, _) - } + BottleRoute() { bottle_route(this, _, _) } string getUrl() { exists(StrConst url | @@ -40,9 +34,7 @@ class BottleRoute extends ControlFlowNode { ) } - Function getFunction() { - bottle_route(this, _, result) - } + Function getFunction() { bottle_route(this, _, result) } Parameter getNamedArgument() { exists(string name, Function func | @@ -52,5 +44,3 @@ class BottleRoute extends ControlFlowNode { ) } } - - diff --git a/python/ql/src/semmle/python/web/bottle/Redirect.qll b/python/ql/src/semmle/python/web/bottle/Redirect.qll index a02166be8b7..187839f30e8 100644 --- a/python/ql/src/semmle/python/web/bottle/Redirect.qll +++ b/python/ql/src/semmle/python/web/bottle/Redirect.qll @@ -1,25 +1,21 @@ -/** Provides class representing the `bottle.redirect` function. +/** + * Provides class representing the `bottle.redirect` function. * This module is intended to be imported into a taint-tracking query * to extend `TaintSink`. */ -import python +import python import semmle.python.security.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.bottle.General -FunctionValue bottle_redirect() { - result = theBottleModule().attr("redirect") -} +FunctionValue bottle_redirect() { result = theBottleModule().attr("redirect") } /** * Represents an argument to the `bottle.redirect` function. */ class BottleRedirect extends TaintSink { - - override string toString() { - result = "bottle.redirect" - } + override string toString() { result = "bottle.redirect" } BottleRedirect() { exists(CallNode call | @@ -28,8 +24,5 @@ class BottleRedirect extends TaintSink { ) } - override predicate sinks(TaintKind kind) { - kind instanceof StringKind - } - + override predicate sinks(TaintKind kind) { kind instanceof StringKind } } diff --git a/python/ql/src/semmle/python/web/bottle/Request.qll b/python/ql/src/semmle/python/web/bottle/Request.qll index 80b307fb63e..767b3d0d25b 100644 --- a/python/ql/src/semmle/python/web/bottle/Request.qll +++ b/python/ql/src/semmle/python/web/bottle/Request.qll @@ -1,20 +1,13 @@ import python - - import semmle.python.security.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.web.Http import semmle.python.web.bottle.General -private Value theBottleRequestObject() { - result = theBottleModule().attr("request") -} +private Value theBottleRequestObject() { result = theBottleModule().attr("request") } class BottleRequestKind extends TaintKind { - - BottleRequestKind() { - this = "bottle.request" - } + BottleRequestKind() { this = "bottle.request" } override TaintKind getTaintOfAttribute(string name) { result instanceof BottleFormsDict and @@ -26,34 +19,23 @@ class BottleRequestKind extends TaintKind { result.(DictKind).getValue() instanceof FileUpload and name = "files" } - } private class RequestSource extends TaintSource { + RequestSource() { this.(ControlFlowNode).pointsTo(theBottleRequestObject()) } - RequestSource() { - this.(ControlFlowNode).pointsTo(theBottleRequestObject()) - } - - override predicate isSourceOf(TaintKind kind) { - kind instanceof BottleRequestKind - } - + override predicate isSourceOf(TaintKind kind) { kind instanceof BottleRequestKind } } - class BottleFormsDict extends TaintKind { - - BottleFormsDict() { - this = "bottle.FormsDict" - } + BottleFormsDict() { this = "bottle.FormsDict" } override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { /* Cannot use `getTaintOfAttribute(name)` as it wouldn't bind `name` */ exists(string name | - fromnode = tonode.(AttrNode).getObject(name) and + fromnode = tonode.(AttrNode).getObject(name) and result instanceof UntrustedStringKind - | + | name != "get" and name != "getunicode" and name != "getall" ) } @@ -67,10 +49,7 @@ class BottleFormsDict extends TaintKind { } class FileUpload extends TaintKind { - - FileUpload() { - this = "bottle.FileUpload" - } + FileUpload() { this = "bottle.FileUpload" } override TaintKind getTaintOfAttribute(string name) { name = "filename" and result instanceof UntrustedStringKind @@ -79,37 +58,23 @@ class FileUpload extends TaintKind { or name = "file" and result instanceof UntrustedFile } - } class UntrustedFile extends TaintKind { - UntrustedFile() { this = "Untrusted file" } - } // // TO DO.. File uploads -- Should check about file uploads for other frameworks as well. // Move UntrustedFile to shared location // - - /** Parameter to a bottle request handler function */ class BottleRequestParameter extends TaintSource { - BottleRequestParameter() { - exists(BottleRoute route | - route.getNamedArgument() = this.(ControlFlowNode).getNode() - ) + exists(BottleRoute route | route.getNamedArgument() = this.(ControlFlowNode).getNode()) } - override predicate isSourceOf(TaintKind kind) { - kind instanceof UntrustedStringKind - } - - override string toString() { - result = "bottle handler function argument" - } + override predicate isSourceOf(TaintKind kind) { kind instanceof UntrustedStringKind } + override string toString() { result = "bottle handler function argument" } } - diff --git a/python/ql/src/semmle/python/web/bottle/Response.qll b/python/ql/src/semmle/python/web/bottle/Response.qll index b90aea152cf..4ad8fbe5e94 100644 --- a/python/ql/src/semmle/python/web/bottle/Response.qll +++ b/python/ql/src/semmle/python/web/bottle/Response.qll @@ -1,29 +1,21 @@ import python - import semmle.python.security.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.web.Http import semmle.python.web.bottle.General - -/** A bottle.Response object +/** + * A bottle.Response object * This isn't really a "taint", but we use the value tracking machinery to * track the flow of response objects. */ class BottleResponse extends TaintKind { - - BottleResponse() { - this = "bottle.response" - } - + BottleResponse() { this = "bottle.response" } } -private Value theBottleResponseObject() { - result = theBottleModule().attr("response") -} +private Value theBottleResponseObject() { result = theBottleModule().attr("response") } class BottleResponseBodyAssignment extends HttpResponseTaintSink { - BottleResponseBodyAssignment() { exists(DefinitionNode lhs | lhs.getValue() = this and @@ -31,14 +23,10 @@ class BottleResponseBodyAssignment extends HttpResponseTaintSink { ) } - override predicate sinks(TaintKind kind) { - kind instanceof StringKind - } - + override predicate sinks(TaintKind kind) { kind instanceof StringKind } } class BottleHandlerFunctionResult extends HttpResponseTaintSink { - BottleHandlerFunctionResult() { exists(BottleRoute route, Return ret | ret.getScope() = route.getFunction() and @@ -46,18 +34,12 @@ class BottleHandlerFunctionResult extends HttpResponseTaintSink { ) } - override predicate sinks(TaintKind kind) { - kind instanceof StringKind - } - - override string toString() { - result = "bottle handler function result" - } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override string toString() { result = "bottle handler function result" } } class BottleCookieSet extends CookieSet, CallNode { - BottleCookieSet() { any(BottleResponse r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) } @@ -67,6 +49,4 @@ class BottleCookieSet extends CookieSet, CallNode { override ControlFlowNode getKey() { result = this.getArg(0) } override ControlFlowNode getValue() { result = this.getArg(1) } - } - From 4221639155d5a667d6af2e219d656b0a5038d621 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 26 Sep 2019 16:25:15 +0200 Subject: [PATCH 0260/1227] Java: Improve taint/value distinction for flow through with fields. --- .../java/dataflow/internal/DataFlowImpl.qll | 2 +- .../java/dataflow/internal/DataFlowImpl2.qll | 2 +- .../java/dataflow/internal/DataFlowImpl3.qll | 2 +- .../java/dataflow/internal/DataFlowImpl4.qll | 2 +- .../java/dataflow/internal/DataFlowImpl5.qll | 2 +- .../dataflow/internal/DataFlowImplCommon.qll | 1116 ++++++++++------- 6 files changed, 665 insertions(+), 461 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 6fa04737e33..e0ca469bf78 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index d0be8824f98..29036c8c51d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index d0be8824f98..29036c8c51d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index d0be8824f98..29036c8c51d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index d0be8824f98..29036c8c51d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 49d592a0e8a..6463600846f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -3,481 +3,685 @@ import DataFlowImplSpecific::Public private ReturnNode getAReturnNodeOfKind(ReturnKind kind) { result.getKind() = kind } -cached +module Public { + import ImplCommon + import FlowThrough_v2 +} + private module ImplCommon { - /** - * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. - * The instance parameter is considered to have index `-1`. - */ - pragma[nomagic] - private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { - p.isParameterOf(viableCallable(call), i) - } + import Cached - /** - * Holds if `arg` is a possible argument to `p` in `call`, taking virtual - * dispatch into account. - */ cached - predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { - exists(int i | - viableParam(call, i, p) and - arg.argumentOf(call, i) - ) - } + private module Cached { + /** + * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. + * The instance parameter is considered to have index `-1`. + */ + pragma[nomagic] + private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallable(call), i) + } - /** - * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. - */ - private predicate parameterValueFlowCand(ParameterNode p, Node node) { - p = node - or - exists(Node mid | - parameterValueFlowCand(p, mid) and - simpleLocalFlowStep(mid, node) and - compatibleTypes(p.getType(), node.getType()) - ) - or - // flow through a callable - exists(Node arg | - parameterValueFlowCand(p, arg) and - argumentValueFlowsThroughCand(arg, node) and - compatibleTypes(p.getType(), node.getType()) - ) - } - - /** - * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps, not taking call contexts - * into account. - */ - private predicate parameterValueFlowsThroughCand(ParameterNode p, ReturnKind kind) { - parameterValueFlowCand(p, getAReturnNodeOfKind(kind)) - } - - pragma[nomagic] - private predicate argumentValueFlowsThroughCand0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind - ) { - exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowsThroughCand(param, kind) - ) - } - - /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. - */ - private predicate argumentValueFlowsThroughCand(ArgumentNode arg, OutNode out) { - exists(DataFlowCall call, ReturnKind kind | argumentValueFlowsThroughCand0(call, arg, kind) | - out = getAnOutNode(call, kind) and - compatibleTypes(arg.getType(), out.getType()) - ) - } - - /** - * Holds if `arg` is the `i`th argument of `call` inside the callable - * `enclosing`, and `arg` may flow through `call`. - */ - pragma[noinline] - private predicate argumentOf( - DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing - ) { - arg.argumentOf(call, i) and - argumentValueFlowsThroughCand(arg, _) and - enclosing = arg.getEnclosingCallable() - } - - pragma[noinline] - private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } - - pragma[noinline] - private predicate viableParamArg0(int i, ArgumentNode arg, CallContext outercc, DataFlowCall call) { - exists(DataFlowCallable c | argumentOf(call, i, arg, c) | - outercc = TAnyCallContext() - or - outercc = TSomeCall(getAParameter(c), _) - or - exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | - reducedViableImplInCallContext(_, c, other) + /** + * Holds if `arg` is a possible argument to `p` in `call`, taking virtual + * dispatch into account. + */ + cached + predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParam(call, i, p) and + arg.argumentOf(call, i) ) - ) - } + } - pragma[noinline] - private predicate viableParamArg1( - ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, - DataFlowCall call - ) { - viableParamArg0(i, arg, outercc, call) and - callable = resolveCall(call, outercc) and - p.isParameterOf(callable, any(int j | j <= i and j >= i)) - } + private module FlowThrough_v1 { + private predicate step = simpleLocalFlowStep/2; - /** - * Holds if `arg` is a possible argument to `p`, in the call `call`, and - * `arg` may flow through `call`. The possible contexts before and after - * entering the callable are `outercc` and `innercc`, respectively. - */ - private predicate viableParamArg( - DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, - CallContextCall innercc - ) { - exists(int i, DataFlowCallable callable | viableParamArg1(p, callable, i, arg, outercc, call) | - if reducedViableImplInCallContext(_, callable, call) - then innercc = TSpecificCall(call, i, true) - else innercc = TSomeCall(p, true) - ) - } - - private CallContextCall getAValidCallContextForParameter(ParameterNode p) { - result = TSomeCall(p, _) - or - exists(DataFlowCall call, int i, DataFlowCallable callable | - result = TSpecificCall(call, i, _) and - p.isParameterOf(callable, i) and - reducedViableImplInCallContext(_, callable, call) - ) - } - - /** - * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, in call context `cc`. - */ - private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { - p = node and - parameterValueFlowsThroughCand(p, _) and - cc = getAValidCallContextForParameter(p) - or - exists(Node mid | - parameterValueFlow(p, mid, cc) and - simpleLocalFlowStep(mid, node) and - compatibleTypes(p.getType(), node.getType()) - ) - or - // flow through a callable - exists(Node arg | - parameterValueFlow(p, arg, cc) and - argumentValueFlowsThrough(arg, node, cc) and - compatibleTypes(p.getType(), node.getType()) - ) - } - - /** - * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps, in call context `cc`. - */ - cached - predicate parameterValueFlowsThrough(ParameterNode p, ReturnKind kind, CallContextCall cc) { - parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) - } - - pragma[nomagic] - private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc - ) { - exists(ParameterNode param, CallContext innercc | - viableParamArg(call, param, arg, cc, innercc) and - parameterValueFlowsThrough(param, kind, innercc) - ) - } - - /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * in call context cc. - */ - cached - predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { - exists(DataFlowCall call, ReturnKind kind | argumentValueFlowsThrough0(call, arg, kind, cc) | - out = getAnOutNode(call, kind) and - compatibleTypes(arg.getType(), out.getType()) - ) - } - - /** - * Holds if `p` can flow to the pre-update node of `n` in the same callable - * using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlowNoCtx(p, n.getPreUpdateNode()) - } - - /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a value-preserving method. - */ - private predicate localValueStep(Node node1, Node node2) { - simpleLocalFlowStep(node1, node2) or - argumentValueFlowsThrough(node1, node2, _) - } - - private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { - p = node - or - exists(Node mid | - parameterValueFlowNoCtx(p, mid) and - localValueStep(mid, node) and - compatibleTypes(p.getType(), node.getType()) - ) - } - - /* - * Calculation of `predicate store(Node node1, Content f, Node node2)`: - * There are four cases: - * - The base case: A direct local assignment given by `storeStep`. - * - A call to a method or constructor with two arguments, `arg1` and `arg2`, - * such that the call has the side-effect `arg2.f = arg1`. - * - A call to a method that returns an object in which an argument has been - * stored. - * - A reverse step through a read when the result of the read has been - * stored into. This handles cases like `x.f1.f2 = y`. - * `storeViaSideEffect` covers the first two cases, and `storeReturn` covers - * the third case. - */ - - /** - * Holds if data can flow from `node1` to `node2` via a direct assignment to - * `f` or via a call that acts as a setter. - */ - cached - predicate store(Node node1, Content f, Node node2) { - storeViaSideEffect(node1, f, node2) or - storeReturn(node1, f, node2) or - read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode()) - } - - private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(DataFlowCall call, int i1, int i2 | - setterCall(call, i1, i2, f) and - node1.(ArgumentNode).argumentOf(call, i1) and - node2.getPreUpdateNode().(ArgumentNode).argumentOf(call, i2) and - compatibleTypes(node1.getTypeBound(), f.getType()) and - compatibleTypes(node2.getTypeBound(), f.getContainerType()) - ) - } - - pragma[nomagic] - private predicate setterInParam(ParameterNode p1, Content f, ParameterNode p2) { - exists(Node n1, PostUpdateNode n2 | - parameterValueFlowNoCtx(p1, n1) and - storeViaSideEffect(n1, f, n2) and - parameterValueFlowNoCtx(p2, n2.getPreUpdateNode()) and - p1 != p2 - ) - } - - pragma[nomagic] - private predicate setterCall(DataFlowCall call, int i1, int i2, Content f) { - exists(DataFlowCallable callable, ParameterNode p1, ParameterNode p2 | - setterInParam(p1, f, p2) and - callable = viableCallable(call) and - p1.isParameterOf(callable, i1) and - p2.isParameterOf(callable, i2) - ) - } - - pragma[noinline] - private predicate storeReturn0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { - exists(ParameterNode p | - viableParamArg(call, p, arg) and - setterReturn(p, f, kind) - ) - } - - private predicate storeReturn(Node node1, Content f, Node node2) { - exists(DataFlowCall call, ReturnKind kind | - storeReturn0(call, kind, node1, f) and - node2 = getAnOutNode(call, kind) and - compatibleTypes(node1.getTypeBound(), f.getType()) and - compatibleTypes(node2.getTypeBound(), f.getContainerType()) - ) - } - - private predicate setterReturn(ParameterNode p, Content f, ReturnKind kind) { - exists(Node n1, Node n2 | - parameterValueFlowNoCtx(p, n1) and - store(n1, f, n2) and - localValueStep*(n2, getAReturnNodeOfKind(kind)) - ) - } - - pragma[noinline] - private predicate read0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { - exists(ParameterNode p | - viableParamArg(call, p, arg) and - getter(p, f, kind) - ) - } - - /** - * Holds if data can flow from `node1` to `node2` via a direct read of `f` or - * via a getter. - */ - cached - predicate read(Node node1, Content f, Node node2) { - readStep(node1, f, node2) and storeStep(_, f, _) - or - exists(DataFlowCall call, ReturnKind kind | - read0(call, kind, node1, f) and - node2 = getAnOutNode(call, kind) and - compatibleTypes(node1.getTypeBound(), f.getContainerType()) and - compatibleTypes(node2.getTypeBound(), f.getType()) - ) - } - - private predicate getter(ParameterNode p, Content f, ReturnKind kind) { - exists(Node n1, Node n2 | - parameterValueFlowNoCtx(p, n1) and - read(n1, f, n2) and - localValueStep*(n2, getAReturnNodeOfKind(kind)) - ) - } - - cached - predicate localStoreReadStep(Node node1, Node node2) { - exists(Node mid1, Node mid2, Content f | - store(node1, f, mid1) and - localValueStep*(mid1, mid2) and - read(mid2, f, node2) and - compatibleTypes(node1.getTypeBound(), node2.getTypeBound()) - ) - } - - /** - * Holds if `call` passes an implicit or explicit instance argument, i.e., an - * expression that reaches a `this` parameter. - */ - private predicate callHasInstanceArgument(DataFlowCall call) { - exists(ArgumentNode arg | arg.argumentOf(call, -1)) - } - - cached - newtype TCallContext = - TAnyCallContext() or - TSpecificCall(DataFlowCall call, int i, boolean emptyAp) { - reducedViableImplInCallContext(_, _, call) and - (emptyAp = true or emptyAp = false) and - ( - exists(call.getArgument(i)) + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, not taking call contexts into account. + */ + private predicate parameterValueFlowCand(ParameterNode p, Node node) { + p = node or - i = -1 and callHasInstanceArgument(call) + exists(Node mid | + parameterValueFlowCand(p, mid) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlowCand(p, arg) and + argumentValueFlowsThroughCand(arg, node) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, not taking call contexts + * into account. + */ + private predicate parameterValueFlowsThroughCand(ParameterNode p, ReturnKind kind) { + parameterValueFlowCand(p, getAReturnNodeOfKind(kind)) + } + + pragma[nomagic] + private predicate argumentValueFlowsThroughCand0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind + ) { + exists(ParameterNode param | viableParamArg(call, param, arg) | + parameterValueFlowsThroughCand(param, kind) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + */ + private predicate argumentValueFlowsThroughCand(ArgumentNode arg, OutNode out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + + /** + * Holds if `arg` is the `i`th argument of `call` inside the callable + * `enclosing`, and `arg` may flow through `call`. + */ + pragma[noinline] + private predicate argumentOf( + DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing + ) { + arg.argumentOf(call, i) and + argumentValueFlowsThroughCand(arg, _) and + enclosing = arg.getEnclosingCallable() + } + + pragma[noinline] + private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } + + pragma[noinline] + private predicate viableParamArg0( + int i, ArgumentNode arg, CallContext outercc, DataFlowCall call + ) { + exists(DataFlowCallable c | argumentOf(call, i, arg, c) | + outercc = TAnyCallContext() + or + outercc = TSomeCall(getAParameter(c), _) + or + exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | + reducedViableImplInCallContext(_, c, other) + ) + ) + } + + pragma[noinline] + private predicate viableParamArg1( + ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, + DataFlowCall call + ) { + viableParamArg0(i, arg, outercc, call) and + callable = resolveCall(call, outercc) and + p.isParameterOf(callable, any(int j | j <= i and j >= i)) + } + + /** + * Holds if `arg` is a possible argument to `p`, in the call `call`, and + * `arg` may flow through `call`. The possible contexts before and after + * entering the callable are `outercc` and `innercc`, respectively. + */ + private predicate viableParamArg( + DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, + CallContextCall innercc + ) { + exists(int i, DataFlowCallable callable | + viableParamArg1(p, callable, i, arg, outercc, call) + | + if reducedViableImplInCallContext(_, callable, call) + then innercc = TSpecificCall(call, i, true) + else innercc = TSomeCall(p, true) + ) + } + + private CallContextCall getAValidCallContextForParameter(ParameterNode p) { + result = TSomeCall(p, _) + or + exists(DataFlowCall call, int i, DataFlowCallable callable | + result = TSpecificCall(call, i, _) and + p.isParameterOf(callable, i) and + reducedViableImplInCallContext(_, callable, call) + ) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { + p = node and + parameterValueFlowsThroughCand(p, _) and + cc = getAValidCallContextForParameter(p) + or + exists(Node mid | + parameterValueFlow(p, mid, cc) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlow(p, arg, cc) and + argumentValueFlowsThrough(arg, node, cc) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlowsThrough( + ParameterNode p, ReturnKind kind, CallContextCall cc + ) { + parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) + } + + pragma[nomagic] + private predicate argumentValueFlowsThrough0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc + ) { + exists(ParameterNode param, CallContext innercc | + viableParamArg(call, param, arg, cc, innercc) and + parameterValueFlowsThrough(param, kind, innercc) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * in call context cc. + */ + predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, cc) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + } + + /** + * Holds if `p` can flow to the pre-update node of `n` in the same callable + * using only value-preserving steps. + */ + cached + predicate parameterValueFlowsToUpdate(ParameterNode p, PostUpdateNode n) { + parameterValueFlowNoCtx(p, n.getPreUpdateNode()) + } + + /** + * Holds if data can flow from `node1` to `node2` in one local step or a step + * through a value-preserving method. + */ + private predicate localValueStep(Node node1, Node node2) { + simpleLocalFlowStep(node1, node2) or + FlowThrough_v1::argumentValueFlowsThrough(node1, node2, _) + } + + private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { + p = node + or + exists(Node mid | + parameterValueFlowNoCtx(p, mid) and + localValueStep(mid, node) and + compatibleTypes(p.getType(), node.getType()) ) - } or - TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or - TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) } + } - cached - newtype TReturnPosition = - TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) } -} + /* + * Calculation of `predicate store(Node node1, Content f, Node node2)`: + * There are four cases: + * - The base case: A direct local assignment given by `storeStep`. + * - A call to a method or constructor with two arguments, `arg1` and `arg2`, + * such that the call has the side-effect `arg2.f = arg1`. + * - A call to a method that returns an object in which an argument has been + * stored. + * - A reverse step through a read when the result of the read has been + * stored into. This handles cases like `x.f1.f2 = y`. + * `storeViaSideEffect` covers the first two cases, and `storeReturn` covers + * the third case. + */ -import ImplCommon + /** + * Holds if data can flow from `node1` to `node2` via a direct assignment to + * `f` or via a call that acts as a setter. + */ + cached + predicate store(Node node1, Content f, Node node2) { + storeViaSideEffect(node1, f, node2) or + storeReturn(node1, f, node2) or + read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode()) + } -pragma[noinline] -private predicate returnPosition(ReturnNode ret, DataFlowCallable c, ReturnKind kind) { - c = returnNodeGetEnclosingCallable(ret) and - kind = ret.getKind() -} + private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) { + storeStep(node1, f, node2) and readStep(_, f, _) + or + exists(DataFlowCall call, int i1, int i2 | + setterCall(call, i1, i2, f) and + node1.(ArgumentNode).argumentOf(call, i1) and + node2.getPreUpdateNode().(ArgumentNode).argumentOf(call, i2) and + compatibleTypes(node1.getTypeBound(), f.getType()) and + compatibleTypes(node2.getTypeBound(), f.getContainerType()) + ) + } -/** - * A call context to restrict the targets of virtual dispatch and match the - * call sites of flow into a method with flow out of a method. - * - * There are four cases: - * - `TAnyCallContext()` : No restrictions on method flow. - * - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th - * parameter at the given `call`. This call improves the set of viable - * dispatch targets for at least one method call in the current callable. - * - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The - * originating call does not improve the set of dispatch targets for any - * method call in the current callable and was therefore not recorded. - * - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and - * this dispatch target of `call` implies a reduced set of dispatch origins - * to which data may flow if it should reach a `return` statement. - */ -abstract class CallContext extends TCallContext { - abstract string toString(); -} + pragma[nomagic] + private predicate setterInParam(ParameterNode p1, Content f, ParameterNode p2) { + exists(Node n1, PostUpdateNode n2 | + parameterValueFlowNoCtx(p1, n1) and + storeViaSideEffect(n1, f, n2) and + parameterValueFlowNoCtx(p2, n2.getPreUpdateNode()) and + p1 != p2 + ) + } -class CallContextAny extends CallContext, TAnyCallContext { - override string toString() { result = "CcAny" } -} + pragma[nomagic] + private predicate setterCall(DataFlowCall call, int i1, int i2, Content f) { + exists(DataFlowCallable callable, ParameterNode p1, ParameterNode p2 | + setterInParam(p1, f, p2) and + callable = viableCallable(call) and + p1.isParameterOf(callable, i1) and + p2.isParameterOf(callable, i2) + ) + } -abstract class CallContextCall extends CallContext { } + pragma[noinline] + private predicate storeReturn0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { + exists(ParameterNode p | + viableParamArg(call, p, arg) and + setterReturn(p, f, kind) + ) + } -class CallContextSpecificCall extends CallContextCall, TSpecificCall { - override string toString() { - exists(DataFlowCall call, int i | this = TSpecificCall(call, i, _) | - result = "CcCall(" + call + ", " + i + ")" + private predicate storeReturn(Node node1, Content f, Node node2) { + exists(DataFlowCall call, ReturnKind kind | + storeReturn0(call, kind, node1, f) and + node2 = getAnOutNode(call, kind) and + compatibleTypes(node1.getTypeBound(), f.getType()) and + compatibleTypes(node2.getTypeBound(), f.getContainerType()) + ) + } + + private predicate setterReturn(ParameterNode p, Content f, ReturnKind kind) { + exists(Node n1, Node n2 | + parameterValueFlowNoCtx(p, n1) and + store(n1, f, n2) and + localValueStep*(n2, getAReturnNodeOfKind(kind)) + ) + } + + pragma[noinline] + private predicate read0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { + exists(ParameterNode p | + viableParamArg(call, p, arg) and + getter(p, f, kind) + ) + } + + /** + * Holds if data can flow from `node1` to `node2` via a direct read of `f` or + * via a getter. + */ + cached + predicate read(Node node1, Content f, Node node2) { + readStep(node1, f, node2) and storeStep(_, f, _) + or + exists(DataFlowCall call, ReturnKind kind | + read0(call, kind, node1, f) and + node2 = getAnOutNode(call, kind) and + compatibleTypes(node1.getTypeBound(), f.getContainerType()) and + compatibleTypes(node2.getTypeBound(), f.getType()) + ) + } + + private predicate getter(ParameterNode p, Content f, ReturnKind kind) { + exists(Node n1, Node n2 | + parameterValueFlowNoCtx(p, n1) and + read(n1, f, n2) and + localValueStep*(n2, getAReturnNodeOfKind(kind)) + ) + } + + cached + predicate localStoreReadStep(Node node1, Node node2) { + exists(Node mid1, Node mid2, Content f | + store(node1, f, mid1) and + localValueStep*(mid1, mid2) and + read(mid2, f, node2) and + compatibleTypes(node1.getTypeBound(), node2.getTypeBound()) + ) + } + + cached + module FlowThrough_v2 { + private predicate step(Node node1, Node node2) { + simpleLocalFlowStep(node1, node2) or + localStoreReadStep(node1, node2) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, not taking call contexts into account. + */ + private predicate parameterValueFlowCand(ParameterNode p, Node node) { + p = node + or + exists(Node mid | + parameterValueFlowCand(p, mid) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlowCand(p, arg) and + argumentValueFlowsThroughCand(arg, node) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, not taking call contexts + * into account. + */ + private predicate parameterValueFlowsThroughCand(ParameterNode p, ReturnKind kind) { + parameterValueFlowCand(p, getAReturnNodeOfKind(kind)) + } + + pragma[nomagic] + private predicate argumentValueFlowsThroughCand0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind + ) { + exists(ParameterNode param | viableParamArg(call, param, arg) | + parameterValueFlowsThroughCand(param, kind) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + */ + private predicate argumentValueFlowsThroughCand(ArgumentNode arg, OutNode out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + + /** + * Holds if `arg` is the `i`th argument of `call` inside the callable + * `enclosing`, and `arg` may flow through `call`. + */ + pragma[noinline] + private predicate argumentOf( + DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing + ) { + arg.argumentOf(call, i) and + argumentValueFlowsThroughCand(arg, _) and + enclosing = arg.getEnclosingCallable() + } + + pragma[noinline] + private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } + + pragma[noinline] + private predicate viableParamArg0( + int i, ArgumentNode arg, CallContext outercc, DataFlowCall call + ) { + exists(DataFlowCallable c | argumentOf(call, i, arg, c) | + outercc = TAnyCallContext() + or + outercc = TSomeCall(getAParameter(c), _) + or + exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | + reducedViableImplInCallContext(_, c, other) + ) + ) + } + + pragma[noinline] + private predicate viableParamArg1( + ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, + DataFlowCall call + ) { + viableParamArg0(i, arg, outercc, call) and + callable = resolveCall(call, outercc) and + p.isParameterOf(callable, any(int j | j <= i and j >= i)) + } + + /** + * Holds if `arg` is a possible argument to `p`, in the call `call`, and + * `arg` may flow through `call`. The possible contexts before and after + * entering the callable are `outercc` and `innercc`, respectively. + */ + private predicate viableParamArg( + DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, + CallContextCall innercc + ) { + exists(int i, DataFlowCallable callable | + viableParamArg1(p, callable, i, arg, outercc, call) + | + if reducedViableImplInCallContext(_, callable, call) + then innercc = TSpecificCall(call, i, true) + else innercc = TSomeCall(p, true) + ) + } + + private CallContextCall getAValidCallContextForParameter(ParameterNode p) { + result = TSomeCall(p, _) + or + exists(DataFlowCall call, int i, DataFlowCallable callable | + result = TSpecificCall(call, i, _) and + p.isParameterOf(callable, i) and + reducedViableImplInCallContext(_, callable, call) + ) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { + p = node and + parameterValueFlowsThroughCand(p, _) and + cc = getAValidCallContextForParameter(p) + or + exists(Node mid | + parameterValueFlow(p, mid, cc) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlow(p, arg, cc) and + argumentValueFlowsThrough(arg, node, cc) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, in call context `cc`. + */ + cached + predicate parameterValueFlowsThrough(ParameterNode p, ReturnKind kind, CallContextCall cc) { + parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) + } + + pragma[nomagic] + private predicate argumentValueFlowsThrough0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc + ) { + exists(ParameterNode param, CallContext innercc | + viableParamArg(call, param, arg, cc, innercc) and + parameterValueFlowsThrough(param, kind, innercc) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * in call context cc. + */ + cached + predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, cc) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + } + + /** + * Holds if `call` passes an implicit or explicit instance argument, i.e., an + * expression that reaches a `this` parameter. + */ + private predicate callHasInstanceArgument(DataFlowCall call) { + exists(ArgumentNode arg | arg.argumentOf(call, -1)) + } + + cached + newtype TCallContext = + TAnyCallContext() or + TSpecificCall(DataFlowCall call, int i, boolean emptyAp) { + reducedViableImplInCallContext(_, _, call) and + (emptyAp = true or emptyAp = false) and + ( + exists(call.getArgument(i)) + or + i = -1 and callHasInstanceArgument(call) + ) + } or + TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or + TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) } + + cached + newtype TReturnPosition = + TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) } + } + + pragma[noinline] + private predicate returnPosition(ReturnNode ret, DataFlowCallable c, ReturnKind kind) { + c = returnNodeGetEnclosingCallable(ret) and + kind = ret.getKind() + } + + /** + * A call context to restrict the targets of virtual dispatch and match the + * call sites of flow into a method with flow out of a method. + * + * There are four cases: + * - `TAnyCallContext()` : No restrictions on method flow. + * - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th + * parameter at the given `call`. This call improves the set of viable + * dispatch targets for at least one method call in the current callable. + * - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The + * originating call does not improve the set of dispatch targets for any + * method call in the current callable and was therefore not recorded. + * - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and + * this dispatch target of `call` implies a reduced set of dispatch origins + * to which data may flow if it should reach a `return` statement. + */ + abstract class CallContext extends TCallContext { + abstract string toString(); + } + + class CallContextAny extends CallContext, TAnyCallContext { + override string toString() { result = "CcAny" } + } + + abstract class CallContextCall extends CallContext { } + + class CallContextSpecificCall extends CallContextCall, TSpecificCall { + override string toString() { + exists(DataFlowCall call, int i | this = TSpecificCall(call, i, _) | + result = "CcCall(" + call + ", " + i + ")" + ) + } + } + + class CallContextSomeCall extends CallContextCall, TSomeCall { + override string toString() { result = "CcSomeCall" } + } + + class CallContextReturn extends CallContext, TReturn { + override string toString() { + exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") + } + } + + /** A callable tagged with a relevant return kind. */ + class ReturnPosition extends TReturnPosition0 { + private DataFlowCallable c; + private ReturnKind kind; + + ReturnPosition() { this = TReturnPosition0(c, kind) } + + /** Gets the callable. */ + DataFlowCallable getCallable() { result = c } + + /** Gets the return kind. */ + ReturnKind getKind() { result = kind } + + /** Gets a textual representation of this return position. */ + string toString() { result = "[" + kind + "] " + c } + } + + pragma[noinline] + DataFlowCallable returnNodeGetEnclosingCallable(ReturnNode ret) { + result = ret.getEnclosingCallable() + } + + pragma[noinline] + ReturnPosition getReturnPosition(ReturnNode ret) { + exists(DataFlowCallable c, ReturnKind k | returnPosition(ret, c, k) | + result = TReturnPosition0(c, k) ) } -} -class CallContextSomeCall extends CallContextCall, TSomeCall { - override string toString() { result = "CcSomeCall" } -} + bindingset[cc, callable] + predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { + cc instanceof CallContextAny and callable = viableCallable(call) + or + exists(DataFlowCallable c0, DataFlowCall call0 | + call0.getEnclosingCallable() = callable and + cc = TReturn(c0, call0) and + c0 = prunedViableImplInCallContextReverse(call0, call) + ) + } -class CallContextReturn extends CallContext, TReturn { - override string toString() { - exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") + bindingset[call, cc] + DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { + exists(DataFlowCall ctx | cc = TSpecificCall(ctx, _, _) | + if reducedViableImplInCallContext(call, _, ctx) + then result = prunedViableImplInCallContext(call, ctx) + else result = viableCallable(call) + ) + or + result = viableCallable(call) and cc instanceof CallContextSomeCall + or + result = viableCallable(call) and cc instanceof CallContextAny + or + result = viableCallable(call) and cc instanceof CallContextReturn } } - -/** A callable tagged with a relevant return kind. */ -class ReturnPosition extends TReturnPosition0 { - private DataFlowCallable c; - private ReturnKind kind; - - ReturnPosition() { this = TReturnPosition0(c, kind) } - - /** Gets the callable. */ - DataFlowCallable getCallable() { result = c } - - /** Gets the return kind. */ - ReturnKind getKind() { result = kind } - - /** Gets a textual representation of this return position. */ - string toString() { result = "[" + kind + "] " + c } -} - -pragma[noinline] -DataFlowCallable returnNodeGetEnclosingCallable(ReturnNode ret) { - result = ret.getEnclosingCallable() -} - -pragma[noinline] -ReturnPosition getReturnPosition(ReturnNode ret) { - exists(DataFlowCallable c, ReturnKind k | returnPosition(ret, c, k) | - result = TReturnPosition0(c, k) - ) -} - -bindingset[cc, callable] -predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { - cc instanceof CallContextAny and callable = viableCallable(call) - or - exists(DataFlowCallable c0, DataFlowCall call0 | - call0.getEnclosingCallable() = callable and - cc = TReturn(c0, call0) and - c0 = prunedViableImplInCallContextReverse(call0, call) - ) -} - -bindingset[call, cc] -DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { - exists(DataFlowCall ctx | cc = TSpecificCall(ctx, _, _) | - if reducedViableImplInCallContext(call, _, ctx) - then result = prunedViableImplInCallContext(call, ctx) - else result = viableCallable(call) - ) - or - result = viableCallable(call) and cc instanceof CallContextSomeCall - or - result = viableCallable(call) and cc instanceof CallContextAny - or - result = viableCallable(call) and cc instanceof CallContextReturn -} From 0afea80d538d50a139a1a7f7116041cddaebe374 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 26 Sep 2019 16:29:13 +0200 Subject: [PATCH 0261/1227] Java: Improve guards for equal ssa variables. --- .../semmle/code/java/controlflow/Guards.qll | 10 +++ .../java/controlflow/internal/GuardsLogic.qll | 73 ++++++++++++------- java/ql/test/query-tests/Nullness/B.java | 2 +- .../query-tests/Nullness/NullMaybe.expected | 1 - 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/java/ql/src/semmle/code/java/controlflow/Guards.qll b/java/ql/src/semmle/code/java/controlflow/Guards.qll index ac7d4cb8150..c382e7963cc 100644 --- a/java/ql/src/semmle/code/java/controlflow/Guards.qll +++ b/java/ql/src/semmle/code/java/controlflow/Guards.qll @@ -97,6 +97,16 @@ class Guard extends ExprParent { result = this.(SwitchCase).getSwitchExpr().getEnclosingStmt() } + /** + * Gets the basic block containing this guard or the basic block containing + * the switch expression if the guard is a switch case. + */ + BasicBlock getBasicBlock() { + result = this.(Expr).getBasicBlock() or + result = this.(SwitchCase).getSwitch().getExpr().getProperExpr().getBasicBlock() or + result = this.(SwitchCase).getSwitchExpr().getExpr().getProperExpr().getBasicBlock() + } + /** * Holds if this guard is an equality test between `e1` and `e2`. The test * can be either `==`, `!=`, `.equals`, or a switch case. If the test is diff --git a/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll b/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll index b80c470bbc9..6fd8d08a658 100644 --- a/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll +++ b/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll @@ -107,7 +107,7 @@ predicate implies_v2(Guard g1, boolean b1, Guard g2, boolean b2) { uniqueValue(v, e, k) and guardImpliesEqual(g1, b1, v, k) and g2.directlyControls(e.getBasicBlock(), b2) and - not g2.directlyControls(getBasicBlockOfGuard(g1), b2) + not g2.directlyControls(g1.getBasicBlock(), b2) ) } @@ -271,16 +271,24 @@ private predicate uniqueValue(SsaVariable v, Expr e, AbstractValue k) { ) } +/** + * Holds if `v1` and `v2` have the same value in `bb`. + */ +private predicate equalVarsInBlock(BasicBlock bb, SsaVariable v1, SsaVariable v2) { + exists(Guard guard, boolean branch | + guard.isEquality(v1.getAUse(), v2.getAUse(), branch) and + guardControls_v1(guard, bb, branch) + ) +} + /** * Holds if `guard` evaluating to `branch` implies that `v` equals `k`. */ private predicate guardImpliesEqual(Guard guard, boolean branch, SsaVariable v, AbstractValue k) { - guard.isEquality(v.getAUse(), k.getExpr(), branch) -} - -private BasicBlock getBasicBlockOfGuard(Guard g) { - result = g.(Expr).getControlFlowNode().getBasicBlock() or - result = g.(SwitchCase).getSwitch().getExpr().getProperExpr().getControlFlowNode().getBasicBlock() + exists(SsaVariable v0 | + guard.isEquality(v0.getAUse(), k.getExpr(), branch) and + (v = v0 or equalVarsInBlock(guard.getBasicBlock(), v0, v)) + ) } private ControlFlowNode getAGuardBranchSuccessor(Guard g, boolean branch) { @@ -299,7 +307,7 @@ private predicate guardControlsPhiBranch( guard.directlyControls(upd.getBasicBlock(), branch) and upd.getDefiningExpr().(VariableAssign).getSource().getProperExpr() = e and upd = phi.getAPhiInput() and - getBasicBlockOfGuard(guard).bbStrictlyDominates(phi.getBasicBlock()) + guard.getBasicBlock().bbStrictlyDominates(phi.getBasicBlock()) } /** @@ -326,7 +334,7 @@ private predicate conditionalAssign(SsaVariable v, Guard guard, boolean branch, forall(SsaVariable other | other != upd and other = phi.getAPhiInput() | guard.directlyControls(other.getBasicBlock(), branch.booleanNot()) or - other.getBasicBlock().bbDominates(getBasicBlockOfGuard(guard)) and + other.getBasicBlock().bbDominates(guard.getBasicBlock()) and not other.isLiveAtEndOfBlock(getAGuardBranchSuccessor(guard, branch)) ) ) @@ -341,6 +349,11 @@ private predicate conditionalAssignVal(SsaVariable v, Guard guard, boolean branc private predicate relevantEq(SsaVariable v, AbstractValue val) { conditionalAssignVal(v, _, _, val) + or + exists(SsaVariable v0 | + conditionalAssignVal(v0, _, _, val) and + equalVarsInBlock(_, v0, v) + ) } /** @@ -349,16 +362,19 @@ private predicate relevantEq(SsaVariable v, AbstractValue val) { private predicate guardImpliesNotEqual1( Guard guard, boolean branch, SsaVariable v, AbstractValue val ) { - relevantEq(v, val) and - ( - guard.isEquality(v.getAUse(), val.getExpr(), branch.booleanNot()) - or - exists(AbstractValue val2 | - guard.isEquality(v.getAUse(), val2.getExpr(), branch) and - val != val2 - ) - or - guard.(InstanceOfExpr).getExpr() = sameValue(v, _) and branch = true and val = TAbsValNull() + exists(SsaVariable v0 | + relevantEq(v0, val) and + ( + guard.isEquality(v0.getAUse(), val.getExpr(), branch.booleanNot()) + or + exists(AbstractValue val2 | + guard.isEquality(v0.getAUse(), val2.getExpr(), branch) and + val != val2 + ) + or + guard.(InstanceOfExpr).getExpr() = sameValue(v0, _) and branch = true and val = TAbsValNull() + ) and + (v = v0 or equalVarsInBlock(guard.getBasicBlock(), v0, v)) ) } @@ -368,13 +384,16 @@ private predicate guardImpliesNotEqual1( private predicate guardImpliesNotEqual2( Guard guard, boolean branch, SsaVariable v, AbstractValue val ) { - relevantEq(v, val) and - ( - guard = directNullGuard(v, branch, false) and val = TAbsValNull() - or - exists(int k | - guard = integerGuard(v.getAUse(), branch, k, false) and - val = TAbsValInt(k) - ) + exists(SsaVariable v0 | + relevantEq(v0, val) and + ( + guard = directNullGuard(v0, branch, false) and val = TAbsValNull() + or + exists(int k | + guard = integerGuard(v0.getAUse(), branch, k, false) and + val = TAbsValInt(k) + ) + ) and + (v = v0 or equalVarsInBlock(guard.getBasicBlock(), v0, v)) ) } diff --git a/java/ql/test/query-tests/Nullness/B.java b/java/ql/test/query-tests/Nullness/B.java index bd71f2cceb1..6605a9c84e3 100644 --- a/java/ql/test/query-tests/Nullness/B.java +++ b/java/ql/test/query-tests/Nullness/B.java @@ -101,7 +101,7 @@ public class B { if (alen == blen) { for(int i = 0; i < alen; i++) { sum += a[i]; // OK - sum += b[i]; // NPE - false positive + sum += b[i]; // OK } } int alen2; diff --git a/java/ql/test/query-tests/Nullness/NullMaybe.expected b/java/ql/test/query-tests/Nullness/NullMaybe.expected index 475ff3a5717..4a21a3f2f66 100644 --- a/java/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/java/ql/test/query-tests/Nullness/NullMaybe.expected @@ -12,7 +12,6 @@ | B.java:72:15:72:16 | xs | Variable $@ may be null here because of $@ assignment. | B.java:68:5:68:41 | int[] xs | xs | B.java:68:11:68:40 | xs | this | | B.java:75:20:75:21 | xs | Variable $@ may be null here because of $@ assignment. | B.java:68:5:68:41 | int[] xs | xs | B.java:68:11:68:40 | xs | this | | B.java:78:20:78:21 | xs | Variable $@ may be null here because of $@ assignment. | B.java:68:5:68:41 | int[] xs | xs | B.java:68:11:68:40 | xs | this | -| B.java:104:16:104:16 | b | Variable $@ may be null here as suggested by $@ null guard. | B.java:97:36:97:42 | b | b | B.java:99:16:99:24 | ... == ... | this | | B.java:118:5:118:7 | obj | Variable $@ may be null here as suggested by $@ null guard. | B.java:117:27:117:36 | obj | obj | B.java:119:13:119:23 | ... != ... | this | | B.java:133:5:133:7 | obj | Variable $@ may be null here because of $@ assignment. | B.java:128:5:128:22 | Object obj | obj | B.java:128:12:128:21 | obj | this | | B.java:190:7:190:7 | o | Variable $@ may be null here because of $@ assignment. | B.java:178:5:178:20 | Object o | o | B.java:186:5:186:12 | ...=... | this | From 457794e0306b55fd023826b50f1e4945d99560f3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 26 Sep 2019 13:03:52 +0200 Subject: [PATCH 0262/1227] Python: Consistenly use parameter instead of argument in docs The Python 3 FAQ states that this is the right thing [0] It sadly doesn't align 100% with PEP8, which calls them for "arguments" [1], but after discussion with Taus, we decided to go with "parameter" everywhere to be consistent. [0] https://docs.python.org/3/faq/programming.html#faq-argument-vs-parameter [1] https://www.python.org/dev/peps/pep-0008/#function-and-method-arguments --- python/ql/src/Functions/NonCls.qhelp | 6 +++--- python/ql/src/Functions/NonCls.ql | 10 +++++----- python/ql/src/Functions/NonSelf.py | 6 +++--- python/ql/src/Functions/NonSelf.ql | 6 +++--- .../test/query-tests/Functions/general/NonCls.expected | 6 +++--- .../query-tests/Functions/general/NonSelf.expected | 6 +++--- .../general/{argument_names.py => parameter_names.py} | 6 +++--- 7 files changed, 23 insertions(+), 23 deletions(-) rename python/ql/test/query-tests/Functions/general/{argument_names.py => parameter_names.py} (90%) diff --git a/python/ql/src/Functions/NonCls.qhelp b/python/ql/src/Functions/NonCls.qhelp index 0e658e7a6b9..6ac9170a991 100644 --- a/python/ql/src/Functions/NonCls.qhelp +++ b/python/ql/src/Functions/NonCls.qhelp @@ -5,14 +5,14 @@ -

    The first argument of a class method, a new method or any metaclass method -should be called cls. This makes the purpose of the argument clear to other developers. +

    The first parameter of a class method, a new method or any metaclass method +should be called cls. This makes the purpose of the parameter clear to other developers.

    -

    Change the name of the first argument to cls as recommended by the style guidelines +

    Change the name of the first parameter to cls as recommended by the style guidelines in PEP 8.

    diff --git a/python/ql/src/Functions/NonCls.ql b/python/ql/src/Functions/NonCls.ql index 34bfbe9ea80..54258ffb4cb 100644 --- a/python/ql/src/Functions/NonCls.ql +++ b/python/ql/src/Functions/NonCls.ql @@ -1,7 +1,7 @@ /** * @name First parameter of a class method is not named 'cls' - * @description Using an alternative name for the first argument of a class method makes code more - * difficult to read; PEP8 states that the first argument to class methods should be 'cls'. + * @description Using an alternative name for the first parameter of a class method makes code more + * difficult to read; PEP8 states that the first parameter to class methods should be 'cls'. * @kind problem * @tags maintainability * readability @@ -38,10 +38,10 @@ not first_arg_cls(f) and classmethod_decorators_only(f) and not f.getName() = "__new__" and ( if exists(f.getArgName(0)) then - message = "Class methods or methods of a type deriving from type should have 'cls', rather than '" + - f.getArgName(0) + "', as their first argument." + message = "Class methods or methods of a type deriving from type should have 'cls', rather than '" + + f.getArgName(0) + "', as their first parameter." else - message = "Class methods or methods of a type deriving from type should have 'cls' as their first argument." + message = "Class methods or methods of a type deriving from type should have 'cls' as their first parameter." ) select f, message diff --git a/python/ql/src/Functions/NonSelf.py b/python/ql/src/Functions/NonSelf.py index 845172717e4..00d3c2ff6f5 100644 --- a/python/ql/src/Functions/NonSelf.py +++ b/python/ql/src/Functions/NonSelf.py @@ -1,9 +1,9 @@ class Point: - def __init__(val, x, y): # first argument is mis-named 'val' + def __init__(val, x, y): # first parameter is mis-named 'val' val._x = x val._y = y - + class Point2: - def __init__(self, x, y): # first argument is correctly named 'self' + def __init__(self, x, y): # first parameter is correctly named 'self' self._x = x self._y = y \ No newline at end of file diff --git a/python/ql/src/Functions/NonSelf.ql b/python/ql/src/Functions/NonSelf.ql index 22e23ba5c01..04a84ea15ad 100644 --- a/python/ql/src/Functions/NonSelf.ql +++ b/python/ql/src/Functions/NonSelf.ql @@ -1,7 +1,7 @@ /** - * @name First argument of a method is not named 'self' - * @description Using an alternative name for the first argument of an instance method makes - * code more difficult to read; PEP8 states that the first argument to instance + * @name First parameter of a method is not named 'self' + * @description Using an alternative name for the first parameter of an instance method makes + * code more difficult to read; PEP8 states that the first parameter to instance * methods should be 'self'. * @kind problem * @tags maintainability diff --git a/python/ql/test/query-tests/Functions/general/NonCls.expected b/python/ql/test/query-tests/Functions/general/NonCls.expected index 0ca17babe3e..991c344c9d7 100644 --- a/python/ql/test/query-tests/Functions/general/NonCls.expected +++ b/python/ql/test/query-tests/Functions/general/NonCls.expected @@ -1,3 +1,3 @@ -| argument_names.py:17:5:17:24 | Function n_cmethod | Class methods or methods of a type deriving from type should have 'cls', rather than 'self', as their first argument. | -| argument_names.py:22:5:22:21 | Function n_cmethod2 | Class methods or methods of a type deriving from type should have 'cls' as their first argument. | -| argument_names.py:37:5:37:20 | Function c_method | Class methods or methods of a type deriving from type should have 'cls', rather than 'y', as their first argument. | +| parameter_names.py:17:5:17:24 | Function n_cmethod | Class methods or methods of a type deriving from type should have 'cls', rather than 'self', as their first parameter. | +| parameter_names.py:22:5:22:21 | Function n_cmethod2 | Class methods or methods of a type deriving from type should have 'cls' as their first parameter. | +| parameter_names.py:37:5:37:20 | Function c_method | Class methods or methods of a type deriving from type should have 'cls', rather than 'y', as their first parameter. | diff --git a/python/ql/test/query-tests/Functions/general/NonSelf.expected b/python/ql/test/query-tests/Functions/general/NonSelf.expected index ff2959353fc..17d5f9818dd 100644 --- a/python/ql/test/query-tests/Functions/general/NonSelf.expected +++ b/python/ql/test/query-tests/Functions/general/NonSelf.expected @@ -1,4 +1,4 @@ -| argument_names.py:50:5:50:20 | Function __init__ | Normal methods should have 'self', rather than 'x', as their first parameter. | -| argument_names.py:53:5:53:20 | Function s_method | Normal methods should have 'self', rather than 'y', as their first parameter. | -| argument_names.py:56:5:56:20 | Function s_method2 | Normal methods should have at least one parameter (the first of which should be 'self'). | | om_test.py:71:5:71:19 | Function __repr__ | Normal methods should have at least one parameter (the first of which should be 'self'). | +| parameter_names.py:50:5:50:20 | Function __init__ | Normal methods should have 'self', rather than 'x', as their first parameter. | +| parameter_names.py:53:5:53:20 | Function s_method | Normal methods should have 'self', rather than 'y', as their first parameter. | +| parameter_names.py:56:5:56:20 | Function s_method2 | Normal methods should have at least one parameter (the first of which should be 'self'). | diff --git a/python/ql/test/query-tests/Functions/general/argument_names.py b/python/ql/test/query-tests/Functions/general/parameter_names.py similarity index 90% rename from python/ql/test/query-tests/Functions/general/argument_names.py rename to python/ql/test/query-tests/Functions/general/parameter_names.py index e4e446dd4d4..33e6229d6ec 100644 --- a/python/ql/test/query-tests/Functions/general/argument_names.py +++ b/python/ql/test/query-tests/Functions/general/parameter_names.py @@ -1,6 +1,6 @@ -# Using name other than 'self' for first argument in methods. -# This shouldn't apply to classmethods (first argument should be 'cls' or similar) -# or static methods (first argument can be anything) +# Using name other than 'self' for first parameter in methods. +# This shouldn't apply to classmethods (first parameter should be 'cls' or similar) +# or static methods (first parameter can be anything) class Normal(object): From 4a5aae0db8592978165175f16accfa18b6ff8131 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 26 Sep 2019 13:20:58 +0200 Subject: [PATCH 0263/1227] Python: autoformat (4 spaces) NonCls.ql NonSelf.ql --- python/ql/src/Functions/NonCls.ql | 31 +++++++++--------- python/ql/src/Functions/NonSelf.ql | 50 ++++++++++++++++-------------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/python/ql/src/Functions/NonCls.ql b/python/ql/src/Functions/NonCls.ql index 54258ffb4cb..983a5c75b30 100644 --- a/python/ql/src/Functions/NonCls.ql +++ b/python/ql/src/Functions/NonCls.ql @@ -16,7 +16,8 @@ import python predicate first_arg_cls(Function f) { exists(string argname | argname = f.getArgName(0) | - argname = "cls" or + argname = "cls" + or /* Not PEP8, but relatively common */ argname = "mcls" ) @@ -27,21 +28,21 @@ predicate is_type_method(Function f) { } predicate classmethod_decorators_only(Function f) { - forall(Expr decorator | - decorator = f.getADecorator() | - decorator.(Name).getId() = "classmethod") + forall(Expr decorator | decorator = f.getADecorator() | decorator.(Name).getId() = "classmethod") } from Function f, string message -where (f.getADecorator().(Name).getId() = "classmethod" or is_type_method(f)) and -not first_arg_cls(f) and classmethod_decorators_only(f) and -not f.getName() = "__new__" and -( - if exists(f.getArgName(0)) then - message = "Class methods or methods of a type deriving from type should have 'cls', rather than '" + - f.getArgName(0) + "', as their first parameter." - else - message = "Class methods or methods of a type deriving from type should have 'cls' as their first parameter." -) - +where + (f.getADecorator().(Name).getId() = "classmethod" or is_type_method(f)) and + not first_arg_cls(f) and + classmethod_decorators_only(f) and + not f.getName() = "__new__" and + ( + if exists(f.getArgName(0)) + then + message = "Class methods or methods of a type deriving from type should have 'cls', rather than '" + + f.getArgName(0) + "', as their first parameter." + else + message = "Class methods or methods of a type deriving from type should have 'cls' as their first parameter." + ) select f, message diff --git a/python/ql/src/Functions/NonSelf.ql b/python/ql/src/Functions/NonSelf.ql index 04a84ea15ad..f1e139f90ad 100644 --- a/python/ql/src/Functions/NonSelf.ql +++ b/python/ql/src/Functions/NonSelf.ql @@ -21,32 +21,34 @@ predicate is_type_method(FunctionValue fv) { } predicate used_in_defining_scope(FunctionValue fv) { - exists(Call c | - c.getScope() = fv.getScope().getScope() and c.getFunc().pointsTo(fv) - ) + exists(Call c | c.getScope() = fv.getScope().getScope() and c.getFunc().pointsTo(fv)) } from Function f, FunctionValue fv, string message where -exists(ClassValue cls, string name | - cls.declaredAttribute(name) = fv and cls.isNewStyle() and - not name = "__new__" and - not name = "__metaclass__" and - /* declared in scope */ - f.getScope() = cls.getScope() -) and -not f.getArgName(0) = "self" and -not is_type_method(fv) and -fv.getScope() = f and -not f.getName() = "lambda" and -not used_in_defining_scope(fv) and -( - if exists(f.getArgName(0)) then - message = "Normal methods should have 'self', rather than '" + f.getArgName(0) + "', as their first parameter." - else - message = "Normal methods should have at least one parameter (the first of which should be 'self')." and - not f.hasVarArg() -) and -not fv instanceof ZopeInterfaceMethodValue - + exists(ClassValue cls, string name | + cls.declaredAttribute(name) = fv and + cls.isNewStyle() and + not name = "__new__" and + not name = "__metaclass__" and + /* declared in scope */ + f.getScope() = cls.getScope() + ) and + not f.getArgName(0) = "self" and + not is_type_method(fv) and + fv.getScope() = f and + not f.getName() = "lambda" and + not used_in_defining_scope(fv) and + ( + ( + if exists(f.getArgName(0)) + then + message = "Normal methods should have 'self', rather than '" + f.getArgName(0) + + "', as their first parameter." + else + message = "Normal methods should have at least one parameter (the first of which should be 'self')." + ) and + not f.hasVarArg() + ) and + not fv instanceof ZopeInterfaceMethodValue select f, message From 7fb8f8453d9452f2dec623976d2da0b6d3dcc09b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 26 Sep 2019 16:35:38 +0200 Subject: [PATCH 0264/1227] fix for when the concatenation root is in parentheses --- javascript/ql/src/Expressions/MissingSpaceInAppend.ql | 2 +- .../MissingSpaceInAppend/MissingSpaceInAppend.expected | 3 ++- .../query-tests/Expressions/MissingSpaceInAppend/missing.js | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Expressions/MissingSpaceInAppend.ql b/javascript/ql/src/Expressions/MissingSpaceInAppend.ql index bd744109675..2df7940646c 100644 --- a/javascript/ql/src/Expressions/MissingSpaceInAppend.ql +++ b/javascript/ql/src/Expressions/MissingSpaceInAppend.ql @@ -23,7 +23,7 @@ Expr leftChild(Expr e) { } predicate isInConcat(Expr e) { - exists(ParExpr par | par.getExpression() = e) + exists(ParExpr par | isInConcat(par) and par.getExpression() = e) or exists(AddExpr a | a.getAnOperand() = e) } diff --git a/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/MissingSpaceInAppend.expected b/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/MissingSpaceInAppend.expected index 20e61738e7b..7fd4130341f 100644 --- a/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/MissingSpaceInAppend.expected +++ b/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/MissingSpaceInAppend.expected @@ -11,4 +11,5 @@ | missing.js:24:5:24:21 | `missing a space` | This string appears to be missing a space after 'space'. | | missing.js:26:5:26:21 | "missing a space" | This string appears to be missing a space after 'space'. | | missing.js:28:5:28:21 | `missing a space` | This string appears to be missing a space after 'space'. | -| missing.js:31:7:31:12 | "h. 0" | This string appears to be missing a space after '0'. | +| missing.js:30:7:30:21 | "missing space" | This string appears to be missing a space after 'space'. | +| missing.js:32:7:32:12 | "h. 0" | This string appears to be missing a space after '0'. | diff --git a/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/missing.js b/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/missing.js index c97f6be724e..bdb85cc5bb1 100644 --- a/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/missing.js +++ b/javascript/ql/test/query-tests/Expressions/MissingSpaceInAppend/missing.js @@ -27,5 +27,6 @@ s = "missing a space" + `here`; s = `missing a space` + `here`; +s = (("missing space") + "here") s = (("h. 0" + "h")) + "word" From 3a4cef646de30c263d4fdc86c34b377cbe8129db Mon Sep 17 00:00:00 2001 From: james Date: Thu, 26 Sep 2019 16:04:01 +0100 Subject: [PATCH 0265/1227] docs: fix some formatting issues --- .../learn-ql/cpp/conversions-classes.rst | 2 +- docs/language/learn-ql/cpp/function-classes.rst | 4 ++++ .../learn-ql/cpp/introduce-libraries-cpp.rst | 4 ++++ .../learn-ql/cpp/zero-space-terminator.rst | 4 ++++ docs/language/learn-ql/csharp/ql-for-csharp.rst | 15 --------------- docs/language/learn-ql/java/call-graph.rst | 2 ++ .../learn-ql/java/expressions-statements.rst | 2 ++ .../learn-ql/java/introduce-libraries-java.rst | 10 +++++++++- .../learn-ql/java/types-class-hierarchy.rst | 2 ++ .../javascript/introduce-libraries-js.rst | 2 +- docs/language/learn-ql/python/functions.rst | 2 ++ .../python/introduce-libraries-python.rst | 16 ++++++++-------- .../learn-ql/python/pointsto-type-infer.rst | 9 +++++---- .../learn-ql/python/statements-expressions.rst | 8 ++++---- 14 files changed, 48 insertions(+), 34 deletions(-) diff --git a/docs/language/learn-ql/cpp/conversions-classes.rst b/docs/language/learn-ql/cpp/conversions-classes.rst index 512d967a53f..28032a932d2 100644 --- a/docs/language/learn-ql/cpp/conversions-classes.rst +++ b/docs/language/learn-ql/cpp/conversions-classes.rst @@ -128,7 +128,7 @@ Unlike the earlier versions of the query, this query would return each side of t Note - In general, QL predicates named ``getAXxx`` exploit the ability to return multiple results (multiple instances of ``Xxx``) whereas plain ``getXxx`` predicates usually return at most one specific instance of ``Xxx``. + In general, QL predicates named ``getAXxx`` exploit the ability to return multiple results (multiple instances of ``Xxx``) whereas plain ``getXxx`` predicates usually return at most one specific instance of ``Xxx``. Classes ------- diff --git a/docs/language/learn-ql/cpp/function-classes.rst b/docs/language/learn-ql/cpp/function-classes.rst index 5dde2546995..4b9db11351b 100644 --- a/docs/language/learn-ql/cpp/function-classes.rst +++ b/docs/language/learn-ql/cpp/function-classes.rst @@ -60,6 +60,10 @@ This query returns fewer results. However, if you examine the results then you c For example, there is a more complicated LGTM `query `__ that finds unused static functions. To see the QL code for this query, click **Open in query console** at the top of the page. +.. pull-quote:: + + Tip + You can explore the definition of an element in the standard QL libraries and see what predicates are available. Use the keyboard **F3** button to open the definition of any element. Alternatively, hover over the element and click **Jump to definition** in the tooltip displayed. The library file is opened in a new tab with the definition highlighted. Finding a specific function diff --git a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst index 01f8b244684..5c287bd7115 100644 --- a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst +++ b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst @@ -12,6 +12,10 @@ There is an extensive QL library for analyzing C/C++ code. The QL classes in thi The rest of this topic briefly summarizes the most important QL classes and predicates provided by this library. +.. pull-quote:: + + Tip + You can find related classes and features using the query console's auto-complete feature. You can also press **F3** to jump to the definition of any element (QL library files are opened in new tabs in the console). Summary of the library classes diff --git a/docs/language/learn-ql/cpp/zero-space-terminator.rst b/docs/language/learn-ql/cpp/zero-space-terminator.rst index f2d0ae36dbd..c5c578633e1 100644 --- a/docs/language/learn-ql/cpp/zero-space-terminator.rst +++ b/docs/language/learn-ql/cpp/zero-space-terminator.rst @@ -87,6 +87,10 @@ Now we can write a query using these classes: Note that there is no need to check whether anything is added to the ``strlen`` expression, as it would be in the corrected C code ``malloc(strlen(string) + 1)``. This is because the corrected code would in fact be an ``AddExpr`` containing a ``StrlenCall``, not an instance of ``StrlenCall`` itself. A side-effect of this approach is that we omit certain unlikely patterns such as ``malloc(strlen(string) + 0``). In practice we can always come back and extend our query to cover this pattern if it is a concern. +.. pull-quote:: + + Tip + For some projects, this query may not return any results. Possibly the project you are querying does not have any problems of this kind, but it is also important to make sure the query itself is working properly. One solution is to set up a test project with examples of correct and incorrect code to run the query against (the C code at the very top of this page makes a good starting point). Another approach is to test each part of the query individually to make sure everything is working. When you have defined the basic query then you can refine the query to include further coding patterns or to exclude false positives: diff --git a/docs/language/learn-ql/csharp/ql-for-csharp.rst b/docs/language/learn-ql/csharp/ql-for-csharp.rst index 56d8f7ef017..879d8c15107 100644 --- a/docs/language/learn-ql/csharp/ql-for-csharp.rst +++ b/docs/language/learn-ql/csharp/ql-for-csharp.rst @@ -14,23 +14,8 @@ These topics provide an overview of the QL C# libraries and show examples of how - :doc:`Introducing the C# libraries ` introduces the standard libraries used to write queries for C# code. -.. raw:: html - - - - :doc:`Tutorial: Analyzing data flow in C# ` demonstrates how to write queries using the standard QL for C# data flow and taint tracking libraries. -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - Other resources --------------- diff --git a/docs/language/learn-ql/java/call-graph.rst b/docs/language/learn-ql/java/call-graph.rst index b0c721b1fd7..3cea5294c0e 100644 --- a/docs/language/learn-ql/java/call-graph.rst +++ b/docs/language/learn-ql/java/call-graph.rst @@ -78,6 +78,8 @@ Given this API, we can easily write a query that finds methods that are not call ➤ `See this in the query console `__. This simple query typically returns a large number of results. +.. pull-quote:: + Note We have to use ``polyCalls`` instead of ``calls`` here: we want to be reasonably sure that ``callee`` is not called, either directly or via overriding. diff --git a/docs/language/learn-ql/java/expressions-statements.rst b/docs/language/learn-ql/java/expressions-statements.rst index c8882c41792..0034868f01a 100644 --- a/docs/language/learn-ql/java/expressions-statements.rst +++ b/docs/language/learn-ql/java/expressions-statements.rst @@ -18,6 +18,8 @@ Specifically, consider the following code snippet: If ``l`` is bigger than 2\ :sup:`31`\ - 1 (the largest positive value of type ``int``), then this loop will never terminate: ``i`` will start at zero, being incremented all the way up to 2\ :sup:`31`\ - 1, which is still smaller than ``l``. When it is incremented once more, an arithmetic overflow occurs, and ``i`` becomes -2\ :sup:`31`\, which also is smaller than ``l``! Eventually, ``i`` will reach zero again, and the cycle repeats. +.. pull-quote:: + More about overflow All primitive numeric types have a maximum value, beyond which they will wrap around to their lowest possible value (called an "overflow"). For ``int``, this maximum value is 2\ :sup:`31`\ - 1. Type ``long`` can accommodate larger values up to a maximum of 2\ :sup:`63`\ - 1. In this example, this means that ``l`` can take on a value that is higher than the maximum for type ``int``; ``i`` will never be able to reach this value, instead overflowing and returning to a low value. diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index 32863b099e0..ef20dd47ccf 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -14,6 +14,10 @@ The library is implemented as a set of QL modules, that is, files with the exten The rest of this topic briefly summarizes the most important QL classes and predicates provided by this library. +.. pull-quote:: + + Note + The example queries in this topic illustrate the types of results returned by different library classes. The results themselves are not interesting but can be used as the basis for developing a more complex query. The tutorial topics show how you can take a simple query and fine-tune it to find precisely the results you're interested in. Summary of the library classes @@ -315,7 +319,11 @@ Class ``Javadoc`` represents an entire Javadoc comment as a tree of ``JavadocEle ➤ `See this in the query console `__. None of the LGTM.com demo projects uses the ``@author`` tag on private fields. - Note that on line 5 we used ``getParent+`` to capture tags that are nested at any depth within the Javadoc comment. +.. pull-quote:: + + Note + + On line 5 we used ``getParent+`` to capture tags that are nested at any depth within the Javadoc comment. For more information on working with Javadoc, see the :doc:`tutorial on Javadoc `. diff --git a/docs/language/learn-ql/java/types-class-hierarchy.rst b/docs/language/learn-ql/java/types-class-hierarchy.rst index df50e600cf9..9855a0391b2 100644 --- a/docs/language/learn-ql/java/types-class-hierarchy.rst +++ b/docs/language/learn-ql/java/types-class-hierarchy.rst @@ -32,6 +32,8 @@ To determine ancestor types (including immediate super types, and also *their* s ➤ `See this in the query console `__. If this query were run on the example snippet above, the query would return ``A``, ``I``, and ``java.lang.Object``. +.. pull-quote:: + Tip If you want to see the location of ``B`` as well as ``A``, you can replace ``B.getASupertype+()`` with ``B.getASupertype*()`` and re-run the query. diff --git a/docs/language/learn-ql/javascript/introduce-libraries-js.rst b/docs/language/learn-ql/javascript/introduce-libraries-js.rst index 0e3a7e5acdd..0858cbb5f8d 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-js.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-js.rst @@ -224,7 +224,7 @@ The `TopLevel `__, `Class `__ and `Function `__ which are all subclasses of ``Scope``. +A Python program is a group of modules. Technically a module is just a list of statements, but we often think of it as composed of classes and functions. These top-level entities, the module, class and function are represented by the three classes `Module `__, `Class `__ and `Function `__, which are all subclasses of ``Scope``. - ``Scope`` @@ -110,12 +110,12 @@ Examples Each syntactic element in Python source is recorded in the snapshot. These can be queried via the corresponding class. Let us start with a couple of simple examples. -1. Finding all finally blocks -''''''''''''''''''''''''''''' +1. Finding all ``finally`` blocks +''''''''''''''''''''''''''''''''' For our first example, we can find all ``finally`` blocks by using the ``Try`` class: -**Find all ``finally`` blocks** +**Find all** ``finally`` **blocks** .. code-block:: ql @@ -126,8 +126,8 @@ For our first example, we can find all ``finally`` blocks by using the ``Try`` c ➤ `See this in the query console `__. Many projects include examples of this pattern. -2. Finding 'except' blocks that do nothing -'''''''''''''''''''''''''''''''''''''''''' +2. Finding ``except`` blocks that do nothing +'''''''''''''''''''''''''''''''''''''''''''' For our second example, we can use a simplified version of a query from the standard query set. We look for all ``except`` blocks that do nothing. @@ -137,7 +137,7 @@ A block that does nothing is one that contains no statements except ``pass`` sta not exists(Stmt s | s = ex.getAStmt() | not s instanceof Pass) -where ``ex`` is an ``ExceptStmt`` and ``Pass`` is the class representing ``pass`` statements. Instead of using the double negative, **"no**\ *statements that are*\ **not**\ *pass statements"*, this can also be expressed positively, "all statements must be pass statements." The positive form is expressed in QL using the ``forall`` quantifier: +where ``ex`` is an ``ExceptStmt`` and ``Pass`` is the class representing ``pass`` statements. Instead of using the double negative, *no statements that are not pass statements*, this can also be expressed positively, *all statements must be pass statements*. The positive form is expressed in QL using the ``forall`` quantifier: .. code-block:: ql @@ -145,7 +145,7 @@ where ``ex`` is an ``ExceptStmt`` and ``Pass`` is the class representing ``pass` Both forms are equivalent. Using the positive QL expression, the whole query looks like this: -**Find pass-only ``except`` blocks** +**Find pass-only** ``except`` **blocks** .. code-block:: ql diff --git a/docs/language/learn-ql/python/pointsto-type-infer.rst b/docs/language/learn-ql/python/pointsto-type-infer.rst index bcbab520477..1b5817f8534 100644 --- a/docs/language/learn-ql/python/pointsto-type-infer.rst +++ b/docs/language/learn-ql/python/pointsto-type-infer.rst @@ -37,7 +37,8 @@ The predicate ``ControlFlowNode.pointsTo(...)`` shows which object a control flo predicate pointsTo(Context context, Value object, ControlFlowNode origin) ``object`` is an object that the control flow node refers to, and ``origin`` is where the object comes from, which is useful for displaying meaningful results. - The third form includes the ``context`` in which the control flow node refers to the ``object``. This form can usually be ignored. + +The third form includes the ``context`` in which the control flow node refers to the ``object``. This form can usually be ignored. .. pull-quote:: @@ -62,7 +63,7 @@ We want to find ``except`` blocks in a ``try`` statement that are in the wrong o First we can write a query to find ordered pairs of ``except`` blocks for a ``try`` statement. -**Ordered except blocks in same ``try`` statement** +**Ordered except blocks in same** ``try`` **statement** .. code-block:: ql @@ -81,7 +82,7 @@ Here ``ex1`` and ``ex2`` are both ``except`` handlers in the ``try`` statement ` The results of this query need to be filtered to return only results where ``ex1`` is more general than ``ex2``. We can use the fact that an ``except`` block is more general than another block if the class it handles is a superclass of the other. -**More general ``except`` block** +**More general** ``except`` **block** .. code-block:: ql @@ -102,7 +103,7 @@ ensures that ``cls1`` is a ``ClassValue`` that the ``except`` block would handle Combining the parts of the query we get this: -**More general ``except`` block precedes more specific** +**More general** ``except`` **block precedes more specific** .. code-block:: ql diff --git a/docs/language/learn-ql/python/statements-expressions.rst b/docs/language/learn-ql/python/statements-expressions.rst index 9f1a15a6d1a..622733ceb1b 100644 --- a/docs/language/learn-ql/python/statements-expressions.rst +++ b/docs/language/learn-ql/python/statements-expressions.rst @@ -143,7 +143,7 @@ Python implementations commonly cache small integers and single character string We can check for these as follows: -**Find comparisons to integer or string literals using ``is``** +**Find comparisons to integer or string literals using** ``is`` .. code-block:: ql @@ -158,6 +158,8 @@ We can check for these as follows: The clause ``cmp.getOp(0) instanceof Is and cmp.getComparator(0) = literal`` checks that the first comparison operator is "is" and that the first comparator is a literal. +.. pull-quote:: + Tip We have to use ``cmp.getOp(0)`` and ``cmp.getComparator(0)``\ as there is no ``cmp.getOp()`` or ``cmp.getComparator()``. The reason for this is that a ``Compare`` expression can have multiple operators. For example, the expression ``3 < x < 7`` has two operators and two comparators. You use ``cmp.getComparator(0)`` to get the first comparator (in this example the ``3``) and ``cmp.getComparator(1)`` to get the second comparator (in this example the ``7``). @@ -253,9 +255,7 @@ checks that the value of the attribute (the expression to the left of the dot in Class and function definitions ------------------------------ -As Python is a dynamically typed language, class, and function definitions are executable statements. This means that a class statement is both a statement and a scope containing statements. To represent this cleanly the class definition is broken into a number of parts. At runtime, when a class definition is executed a class object is created and then assigned to a variable of the same name in the scope enclosing the class. This class is created from a code-object representing the source code for the body of the class. To represent this the ``ClassDef`` class (which represents a ``class`` statement) subclasses ``Assign``. The ``Class`` class, which represents the body of the class, can be accessed via the ``ClassDef.getDefinedClass()`` - -``FunctionDef``, ``Function`` are handled similarly. +As Python is a dynamically typed language, class, and function definitions are executable statements. This means that a class statement is both a statement and a scope containing statements. To represent this cleanly the class definition is broken into a number of parts. At runtime, when a class definition is executed a class object is created and then assigned to a variable of the same name in the scope enclosing the class. This class is created from a code-object representing the source code for the body of the class. To represent this the ``ClassDef`` class (which represents a ``class`` statement) subclasses ``Assign``. The ``Class`` class, which represents the body of the class, can be accessed via the ``ClassDef.getDefinedClass()``. ``FunctionDef`` and ``Function`` are handled similarly. Here is the relevant part of the class hierarchy: From f97958296d53193de3fc0ad24e14387174eb1e7f Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 26 Sep 2019 17:12:08 +0200 Subject: [PATCH 0266/1227] Java/C++/C#: Sync. --- .../cpp/dataflow/internal/DataFlowImpl.qll | 11 +- .../cpp/dataflow/internal/DataFlowImpl2.qll | 11 +- .../cpp/dataflow/internal/DataFlowImpl3.qll | 11 +- .../cpp/dataflow/internal/DataFlowImpl4.qll | 11 +- .../dataflow/internal/DataFlowImplCommon.qll | 1105 ++++++++++------- .../dataflow/internal/DataFlowImplLocal.qll | 11 +- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 11 +- .../ir/dataflow/internal/DataFlowImpl2.qll | 11 +- .../ir/dataflow/internal/DataFlowImpl3.qll | 11 +- .../ir/dataflow/internal/DataFlowImpl4.qll | 11 +- .../dataflow/internal/DataFlowImplCommon.qll | 1105 ++++++++++------- .../csharp/dataflow/internal/DataFlowImpl.qll | 11 +- .../dataflow/internal/DataFlowImpl2.qll | 11 +- .../dataflow/internal/DataFlowImpl3.qll | 11 +- .../dataflow/internal/DataFlowImpl4.qll | 11 +- .../dataflow/internal/DataFlowImpl5.qll | 11 +- .../dataflow/internal/DataFlowImplCommon.qll | 1105 ++++++++++------- .../java/dataflow/internal/DataFlowImpl2.qll | 9 +- .../java/dataflow/internal/DataFlowImpl3.qll | 9 +- .../java/dataflow/internal/DataFlowImpl4.qll | 9 +- .../java/dataflow/internal/DataFlowImpl5.qll | 9 +- 21 files changed, 2084 insertions(+), 1421 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index d0be8824f98..e0ca469bf78 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index d0be8824f98..e0ca469bf78 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index d0be8824f98..e0ca469bf78 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index d0be8824f98..e0ca469bf78 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 97052e80004..6463600846f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -3,470 +3,685 @@ import DataFlowImplSpecific::Public private ReturnNode getAReturnNodeOfKind(ReturnKind kind) { result.getKind() = kind } -cached +module Public { + import ImplCommon + import FlowThrough_v2 +} + private module ImplCommon { - /** - * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. - * The instance parameter is considered to have index `-1`. - */ - pragma[nomagic] - private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { - p.isParameterOf(viableCallable(call), i) - } + import Cached - /** - * Holds if `arg` is a possible argument to `p` in `call`, taking virtual - * dispatch into account. - */ cached - predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { - exists(int i | - viableParam(call, i, p) and - arg.argumentOf(call, i) - ) - } + private module Cached { + /** + * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. + * The instance parameter is considered to have index `-1`. + */ + pragma[nomagic] + private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallable(call), i) + } - /** - * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. - */ - private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { - p = node - or - exists(Node mid | - parameterValueFlowNoCtx(p, mid) and - simpleLocalFlowStep(mid, node) and - compatibleTypes(p.getType(), node.getType()) - ) - or - // flow through a callable - exists(Node arg | - parameterValueFlowNoCtx(p, arg) and - argumentValueFlowsThroughNoCtx(arg, node) and - compatibleTypes(p.getType(), node.getType()) - ) - } - - /** - * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps, not taking call contexts - * into account. - */ - private predicate parameterValueFlowsThroughNoCtx(ParameterNode p, ReturnKind kind) { - parameterValueFlowNoCtx(p, getAReturnNodeOfKind(kind)) - } - - pragma[nomagic] - private predicate argumentValueFlowsThroughNoCtx0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind - ) { - exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowsThroughNoCtx(param, kind) - ) - } - - /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. - */ - private predicate argumentValueFlowsThroughNoCtx(ArgumentNode arg, OutNode out) { - exists(DataFlowCall call, ReturnKind kind | argumentValueFlowsThroughNoCtx0(call, arg, kind) | - out = getAnOutNode(call, kind) and - compatibleTypes(arg.getType(), out.getType()) - ) - } - - /** - * Holds if `arg` is the `i`th argument of `call` inside the callable - * `enclosing`, and `arg` may flow through `call`. - */ - pragma[noinline] - private predicate argumentOf( - DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing - ) { - arg.argumentOf(call, i) and - argumentValueFlowsThroughNoCtx(arg, _) and - enclosing = arg.getEnclosingCallable() - } - - pragma[noinline] - private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } - - pragma[noinline] - private predicate viableParamArg0(int i, ArgumentNode arg, CallContext outercc, DataFlowCall call) { - exists(DataFlowCallable c | argumentOf(call, i, arg, c) | - outercc = TAnyCallContext() - or - outercc = TSomeCall(getAParameter(c), _) - or - exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | - reducedViableImplInCallContext(_, c, other) + /** + * Holds if `arg` is a possible argument to `p` in `call`, taking virtual + * dispatch into account. + */ + cached + predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParam(call, i, p) and + arg.argumentOf(call, i) ) - ) - } + } - pragma[noinline] - private predicate viableParamArg1( - ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, - DataFlowCall call - ) { - viableParamArg0(i, arg, outercc, call) and - callable = resolveCall(call, outercc) and - p.isParameterOf(callable, any(int j | j <= i and j >= i)) - } + private module FlowThrough_v1 { + private predicate step = simpleLocalFlowStep/2; - /** - * Holds if `arg` is a possible argument to `p`, in the call `call`, and - * `arg` may flow through `call`. The possible contexts before and after - * entering the callable are `outercc` and `innercc`, respectively. - */ - private predicate viableParamArg( - DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, - CallContextCall innercc - ) { - exists(int i, DataFlowCallable callable | viableParamArg1(p, callable, i, arg, outercc, call) | - if reducedViableImplInCallContext(_, callable, call) - then innercc = TSpecificCall(call, i, true) - else innercc = TSomeCall(p, true) - ) - } - - private CallContextCall getAValidCallContextForParameter(ParameterNode p) { - result = TSomeCall(p, _) - or - exists(DataFlowCall call, int i, DataFlowCallable callable | - result = TSpecificCall(call, i, _) and - p.isParameterOf(callable, i) and - reducedViableImplInCallContext(_, callable, call) - ) - } - - /** - * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, in call context `cc`. - */ - private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { - p = node and - parameterValueFlowsThroughNoCtx(p, _) and - cc = getAValidCallContextForParameter(p) - or - exists(Node mid | - parameterValueFlow(p, mid, cc) and - simpleLocalFlowStep(mid, node) and - compatibleTypes(p.getType(), node.getType()) - ) - or - // flow through a callable - exists(Node arg | - parameterValueFlow(p, arg, cc) and - argumentValueFlowsThrough(arg, node, cc) and - compatibleTypes(p.getType(), node.getType()) - ) - } - - /** - * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps, in call context `cc`. - */ - cached - predicate parameterValueFlowsThrough(ParameterNode p, ReturnKind kind, CallContextCall cc) { - parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) - } - - pragma[nomagic] - private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc - ) { - exists(ParameterNode param, CallContext innercc | - viableParamArg(call, param, arg, cc, innercc) and - parameterValueFlowsThrough(param, kind, innercc) - ) - } - - /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * in call context cc. - */ - cached - predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { - exists(DataFlowCall call, ReturnKind kind | argumentValueFlowsThrough0(call, arg, kind, cc) | - out = getAnOutNode(call, kind) and - compatibleTypes(arg.getType(), out.getType()) - ) - } - - /** - * Holds if `p` can flow to the pre-update node of `n` in the same callable - * using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlowNoCtx(p, n.getPreUpdateNode()) - } - - /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a value-preserving method. - */ - private predicate localValueStep(Node node1, Node node2) { - simpleLocalFlowStep(node1, node2) or - argumentValueFlowsThrough(node1, node2, _) - } - - /* - * Calculation of `predicate store(Node node1, Content f, Node node2)`: - * There are four cases: - * - The base case: A direct local assignment given by `storeStep`. - * - A call to a method or constructor with two arguments, `arg1` and `arg2`, - * such that the call has the side-effect `arg2.f = arg1`. - * - A call to a method that returns an object in which an argument has been - * stored. - * - A reverse step through a read when the result of the read has been - * stored into. This handles cases like `x.f1.f2 = y`. - * `storeViaSideEffect` covers the first two cases, and `storeReturn` covers - * the third case. - */ - - /** - * Holds if data can flow from `node1` to `node2` via a direct assignment to - * `f` or via a call that acts as a setter. - */ - cached - predicate store(Node node1, Content f, Node node2) { - storeViaSideEffect(node1, f, node2) or - storeReturn(node1, f, node2) or - read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode()) - } - - private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(DataFlowCall call, int i1, int i2 | - setterCall(call, i1, i2, f) and - node1.(ArgumentNode).argumentOf(call, i1) and - node2.getPreUpdateNode().(ArgumentNode).argumentOf(call, i2) and - compatibleTypes(node1.getTypeBound(), f.getType()) and - compatibleTypes(node2.getTypeBound(), f.getContainerType()) - ) - } - - pragma[nomagic] - private predicate setterInParam(ParameterNode p1, Content f, ParameterNode p2) { - exists(Node n1, PostUpdateNode n2 | - parameterValueFlowNoCtx(p1, n1) and - storeViaSideEffect(n1, f, n2) and - parameterValueFlowNoCtx(p2, n2.getPreUpdateNode()) and - p1 != p2 - ) - } - - pragma[nomagic] - private predicate setterCall(DataFlowCall call, int i1, int i2, Content f) { - exists(DataFlowCallable callable, ParameterNode p1, ParameterNode p2 | - setterInParam(p1, f, p2) and - callable = viableCallable(call) and - p1.isParameterOf(callable, i1) and - p2.isParameterOf(callable, i2) - ) - } - - pragma[noinline] - private predicate storeReturn0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { - exists(ParameterNode p | - viableParamArg(call, p, arg) and - setterReturn(p, f, kind) - ) - } - - private predicate storeReturn(Node node1, Content f, Node node2) { - exists(DataFlowCall call, ReturnKind kind | - storeReturn0(call, kind, node1, f) and - node2 = getAnOutNode(call, kind) and - compatibleTypes(node1.getTypeBound(), f.getType()) and - compatibleTypes(node2.getTypeBound(), f.getContainerType()) - ) - } - - private predicate setterReturn(ParameterNode p, Content f, ReturnKind kind) { - exists(Node n1, Node n2 | - parameterValueFlowNoCtx(p, n1) and - store(n1, f, n2) and - localValueStep*(n2, getAReturnNodeOfKind(kind)) - ) - } - - pragma[noinline] - private predicate read0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { - exists(ParameterNode p | - viableParamArg(call, p, arg) and - getter(p, f, kind) - ) - } - - /** - * Holds if data can flow from `node1` to `node2` via a direct read of `f` or - * via a getter. - */ - cached - predicate read(Node node1, Content f, Node node2) { - readStep(node1, f, node2) and storeStep(_, f, _) - or - exists(DataFlowCall call, ReturnKind kind | - read0(call, kind, node1, f) and - node2 = getAnOutNode(call, kind) and - compatibleTypes(node1.getTypeBound(), f.getContainerType()) and - compatibleTypes(node2.getTypeBound(), f.getType()) - ) - } - - private predicate getter(ParameterNode p, Content f, ReturnKind kind) { - exists(Node n1, Node n2 | - parameterValueFlowNoCtx(p, n1) and - read(n1, f, n2) and - localValueStep*(n2, getAReturnNodeOfKind(kind)) - ) - } - - cached - predicate localStoreReadStep(Node node1, Node node2) { - exists(Node mid1, Node mid2, Content f | - store(node1, f, mid1) and - localValueStep*(mid1, mid2) and - read(mid2, f, node2) - ) - } - - /** - * Holds if `call` passes an implicit or explicit instance argument, i.e., an - * expression that reaches a `this` parameter. - */ - private predicate callHasInstanceArgument(DataFlowCall call) { - exists(ArgumentNode arg | arg.argumentOf(call, -1)) - } - - cached - newtype TCallContext = - TAnyCallContext() or - TSpecificCall(DataFlowCall call, int i, boolean emptyAp) { - reducedViableImplInCallContext(_, _, call) and - (emptyAp = true or emptyAp = false) and - ( - exists(call.getArgument(i)) + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, not taking call contexts into account. + */ + private predicate parameterValueFlowCand(ParameterNode p, Node node) { + p = node or - i = -1 and callHasInstanceArgument(call) + exists(Node mid | + parameterValueFlowCand(p, mid) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlowCand(p, arg) and + argumentValueFlowsThroughCand(arg, node) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, not taking call contexts + * into account. + */ + private predicate parameterValueFlowsThroughCand(ParameterNode p, ReturnKind kind) { + parameterValueFlowCand(p, getAReturnNodeOfKind(kind)) + } + + pragma[nomagic] + private predicate argumentValueFlowsThroughCand0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind + ) { + exists(ParameterNode param | viableParamArg(call, param, arg) | + parameterValueFlowsThroughCand(param, kind) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + */ + private predicate argumentValueFlowsThroughCand(ArgumentNode arg, OutNode out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + + /** + * Holds if `arg` is the `i`th argument of `call` inside the callable + * `enclosing`, and `arg` may flow through `call`. + */ + pragma[noinline] + private predicate argumentOf( + DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing + ) { + arg.argumentOf(call, i) and + argumentValueFlowsThroughCand(arg, _) and + enclosing = arg.getEnclosingCallable() + } + + pragma[noinline] + private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } + + pragma[noinline] + private predicate viableParamArg0( + int i, ArgumentNode arg, CallContext outercc, DataFlowCall call + ) { + exists(DataFlowCallable c | argumentOf(call, i, arg, c) | + outercc = TAnyCallContext() + or + outercc = TSomeCall(getAParameter(c), _) + or + exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | + reducedViableImplInCallContext(_, c, other) + ) + ) + } + + pragma[noinline] + private predicate viableParamArg1( + ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, + DataFlowCall call + ) { + viableParamArg0(i, arg, outercc, call) and + callable = resolveCall(call, outercc) and + p.isParameterOf(callable, any(int j | j <= i and j >= i)) + } + + /** + * Holds if `arg` is a possible argument to `p`, in the call `call`, and + * `arg` may flow through `call`. The possible contexts before and after + * entering the callable are `outercc` and `innercc`, respectively. + */ + private predicate viableParamArg( + DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, + CallContextCall innercc + ) { + exists(int i, DataFlowCallable callable | + viableParamArg1(p, callable, i, arg, outercc, call) + | + if reducedViableImplInCallContext(_, callable, call) + then innercc = TSpecificCall(call, i, true) + else innercc = TSomeCall(p, true) + ) + } + + private CallContextCall getAValidCallContextForParameter(ParameterNode p) { + result = TSomeCall(p, _) + or + exists(DataFlowCall call, int i, DataFlowCallable callable | + result = TSpecificCall(call, i, _) and + p.isParameterOf(callable, i) and + reducedViableImplInCallContext(_, callable, call) + ) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { + p = node and + parameterValueFlowsThroughCand(p, _) and + cc = getAValidCallContextForParameter(p) + or + exists(Node mid | + parameterValueFlow(p, mid, cc) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlow(p, arg, cc) and + argumentValueFlowsThrough(arg, node, cc) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlowsThrough( + ParameterNode p, ReturnKind kind, CallContextCall cc + ) { + parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) + } + + pragma[nomagic] + private predicate argumentValueFlowsThrough0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc + ) { + exists(ParameterNode param, CallContext innercc | + viableParamArg(call, param, arg, cc, innercc) and + parameterValueFlowsThrough(param, kind, innercc) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * in call context cc. + */ + predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, cc) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + } + + /** + * Holds if `p` can flow to the pre-update node of `n` in the same callable + * using only value-preserving steps. + */ + cached + predicate parameterValueFlowsToUpdate(ParameterNode p, PostUpdateNode n) { + parameterValueFlowNoCtx(p, n.getPreUpdateNode()) + } + + /** + * Holds if data can flow from `node1` to `node2` in one local step or a step + * through a value-preserving method. + */ + private predicate localValueStep(Node node1, Node node2) { + simpleLocalFlowStep(node1, node2) or + FlowThrough_v1::argumentValueFlowsThrough(node1, node2, _) + } + + private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { + p = node + or + exists(Node mid | + parameterValueFlowNoCtx(p, mid) and + localValueStep(mid, node) and + compatibleTypes(p.getType(), node.getType()) ) - } or - TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or - TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) } + } - cached - newtype TReturnPosition = - TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) } -} + /* + * Calculation of `predicate store(Node node1, Content f, Node node2)`: + * There are four cases: + * - The base case: A direct local assignment given by `storeStep`. + * - A call to a method or constructor with two arguments, `arg1` and `arg2`, + * such that the call has the side-effect `arg2.f = arg1`. + * - A call to a method that returns an object in which an argument has been + * stored. + * - A reverse step through a read when the result of the read has been + * stored into. This handles cases like `x.f1.f2 = y`. + * `storeViaSideEffect` covers the first two cases, and `storeReturn` covers + * the third case. + */ -import ImplCommon + /** + * Holds if data can flow from `node1` to `node2` via a direct assignment to + * `f` or via a call that acts as a setter. + */ + cached + predicate store(Node node1, Content f, Node node2) { + storeViaSideEffect(node1, f, node2) or + storeReturn(node1, f, node2) or + read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode()) + } -pragma[noinline] -private predicate returnPosition(ReturnNode ret, DataFlowCallable c, ReturnKind kind) { - c = returnNodeGetEnclosingCallable(ret) and - kind = ret.getKind() -} + private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) { + storeStep(node1, f, node2) and readStep(_, f, _) + or + exists(DataFlowCall call, int i1, int i2 | + setterCall(call, i1, i2, f) and + node1.(ArgumentNode).argumentOf(call, i1) and + node2.getPreUpdateNode().(ArgumentNode).argumentOf(call, i2) and + compatibleTypes(node1.getTypeBound(), f.getType()) and + compatibleTypes(node2.getTypeBound(), f.getContainerType()) + ) + } -/** - * A call context to restrict the targets of virtual dispatch and match the - * call sites of flow into a method with flow out of a method. - * - * There are four cases: - * - `TAnyCallContext()` : No restrictions on method flow. - * - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th - * parameter at the given `call`. This call improves the set of viable - * dispatch targets for at least one method call in the current callable. - * - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The - * originating call does not improve the set of dispatch targets for any - * method call in the current callable and was therefore not recorded. - * - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and - * this dispatch target of `call` implies a reduced set of dispatch origins - * to which data may flow if it should reach a `return` statement. - */ -abstract class CallContext extends TCallContext { - abstract string toString(); -} + pragma[nomagic] + private predicate setterInParam(ParameterNode p1, Content f, ParameterNode p2) { + exists(Node n1, PostUpdateNode n2 | + parameterValueFlowNoCtx(p1, n1) and + storeViaSideEffect(n1, f, n2) and + parameterValueFlowNoCtx(p2, n2.getPreUpdateNode()) and + p1 != p2 + ) + } -class CallContextAny extends CallContext, TAnyCallContext { - override string toString() { result = "CcAny" } -} + pragma[nomagic] + private predicate setterCall(DataFlowCall call, int i1, int i2, Content f) { + exists(DataFlowCallable callable, ParameterNode p1, ParameterNode p2 | + setterInParam(p1, f, p2) and + callable = viableCallable(call) and + p1.isParameterOf(callable, i1) and + p2.isParameterOf(callable, i2) + ) + } -abstract class CallContextCall extends CallContext { } + pragma[noinline] + private predicate storeReturn0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { + exists(ParameterNode p | + viableParamArg(call, p, arg) and + setterReturn(p, f, kind) + ) + } -class CallContextSpecificCall extends CallContextCall, TSpecificCall { - override string toString() { - exists(DataFlowCall call, int i | this = TSpecificCall(call, i, _) | - result = "CcCall(" + call + ", " + i + ")" + private predicate storeReturn(Node node1, Content f, Node node2) { + exists(DataFlowCall call, ReturnKind kind | + storeReturn0(call, kind, node1, f) and + node2 = getAnOutNode(call, kind) and + compatibleTypes(node1.getTypeBound(), f.getType()) and + compatibleTypes(node2.getTypeBound(), f.getContainerType()) + ) + } + + private predicate setterReturn(ParameterNode p, Content f, ReturnKind kind) { + exists(Node n1, Node n2 | + parameterValueFlowNoCtx(p, n1) and + store(n1, f, n2) and + localValueStep*(n2, getAReturnNodeOfKind(kind)) + ) + } + + pragma[noinline] + private predicate read0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { + exists(ParameterNode p | + viableParamArg(call, p, arg) and + getter(p, f, kind) + ) + } + + /** + * Holds if data can flow from `node1` to `node2` via a direct read of `f` or + * via a getter. + */ + cached + predicate read(Node node1, Content f, Node node2) { + readStep(node1, f, node2) and storeStep(_, f, _) + or + exists(DataFlowCall call, ReturnKind kind | + read0(call, kind, node1, f) and + node2 = getAnOutNode(call, kind) and + compatibleTypes(node1.getTypeBound(), f.getContainerType()) and + compatibleTypes(node2.getTypeBound(), f.getType()) + ) + } + + private predicate getter(ParameterNode p, Content f, ReturnKind kind) { + exists(Node n1, Node n2 | + parameterValueFlowNoCtx(p, n1) and + read(n1, f, n2) and + localValueStep*(n2, getAReturnNodeOfKind(kind)) + ) + } + + cached + predicate localStoreReadStep(Node node1, Node node2) { + exists(Node mid1, Node mid2, Content f | + store(node1, f, mid1) and + localValueStep*(mid1, mid2) and + read(mid2, f, node2) and + compatibleTypes(node1.getTypeBound(), node2.getTypeBound()) + ) + } + + cached + module FlowThrough_v2 { + private predicate step(Node node1, Node node2) { + simpleLocalFlowStep(node1, node2) or + localStoreReadStep(node1, node2) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, not taking call contexts into account. + */ + private predicate parameterValueFlowCand(ParameterNode p, Node node) { + p = node + or + exists(Node mid | + parameterValueFlowCand(p, mid) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlowCand(p, arg) and + argumentValueFlowsThroughCand(arg, node) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, not taking call contexts + * into account. + */ + private predicate parameterValueFlowsThroughCand(ParameterNode p, ReturnKind kind) { + parameterValueFlowCand(p, getAReturnNodeOfKind(kind)) + } + + pragma[nomagic] + private predicate argumentValueFlowsThroughCand0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind + ) { + exists(ParameterNode param | viableParamArg(call, param, arg) | + parameterValueFlowsThroughCand(param, kind) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + */ + private predicate argumentValueFlowsThroughCand(ArgumentNode arg, OutNode out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + + /** + * Holds if `arg` is the `i`th argument of `call` inside the callable + * `enclosing`, and `arg` may flow through `call`. + */ + pragma[noinline] + private predicate argumentOf( + DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing + ) { + arg.argumentOf(call, i) and + argumentValueFlowsThroughCand(arg, _) and + enclosing = arg.getEnclosingCallable() + } + + pragma[noinline] + private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } + + pragma[noinline] + private predicate viableParamArg0( + int i, ArgumentNode arg, CallContext outercc, DataFlowCall call + ) { + exists(DataFlowCallable c | argumentOf(call, i, arg, c) | + outercc = TAnyCallContext() + or + outercc = TSomeCall(getAParameter(c), _) + or + exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | + reducedViableImplInCallContext(_, c, other) + ) + ) + } + + pragma[noinline] + private predicate viableParamArg1( + ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, + DataFlowCall call + ) { + viableParamArg0(i, arg, outercc, call) and + callable = resolveCall(call, outercc) and + p.isParameterOf(callable, any(int j | j <= i and j >= i)) + } + + /** + * Holds if `arg` is a possible argument to `p`, in the call `call`, and + * `arg` may flow through `call`. The possible contexts before and after + * entering the callable are `outercc` and `innercc`, respectively. + */ + private predicate viableParamArg( + DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, + CallContextCall innercc + ) { + exists(int i, DataFlowCallable callable | + viableParamArg1(p, callable, i, arg, outercc, call) + | + if reducedViableImplInCallContext(_, callable, call) + then innercc = TSpecificCall(call, i, true) + else innercc = TSomeCall(p, true) + ) + } + + private CallContextCall getAValidCallContextForParameter(ParameterNode p) { + result = TSomeCall(p, _) + or + exists(DataFlowCall call, int i, DataFlowCallable callable | + result = TSpecificCall(call, i, _) and + p.isParameterOf(callable, i) and + reducedViableImplInCallContext(_, callable, call) + ) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { + p = node and + parameterValueFlowsThroughCand(p, _) and + cc = getAValidCallContextForParameter(p) + or + exists(Node mid | + parameterValueFlow(p, mid, cc) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlow(p, arg, cc) and + argumentValueFlowsThrough(arg, node, cc) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, in call context `cc`. + */ + cached + predicate parameterValueFlowsThrough(ParameterNode p, ReturnKind kind, CallContextCall cc) { + parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) + } + + pragma[nomagic] + private predicate argumentValueFlowsThrough0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc + ) { + exists(ParameterNode param, CallContext innercc | + viableParamArg(call, param, arg, cc, innercc) and + parameterValueFlowsThrough(param, kind, innercc) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * in call context cc. + */ + cached + predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, cc) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + } + + /** + * Holds if `call` passes an implicit or explicit instance argument, i.e., an + * expression that reaches a `this` parameter. + */ + private predicate callHasInstanceArgument(DataFlowCall call) { + exists(ArgumentNode arg | arg.argumentOf(call, -1)) + } + + cached + newtype TCallContext = + TAnyCallContext() or + TSpecificCall(DataFlowCall call, int i, boolean emptyAp) { + reducedViableImplInCallContext(_, _, call) and + (emptyAp = true or emptyAp = false) and + ( + exists(call.getArgument(i)) + or + i = -1 and callHasInstanceArgument(call) + ) + } or + TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or + TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) } + + cached + newtype TReturnPosition = + TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) } + } + + pragma[noinline] + private predicate returnPosition(ReturnNode ret, DataFlowCallable c, ReturnKind kind) { + c = returnNodeGetEnclosingCallable(ret) and + kind = ret.getKind() + } + + /** + * A call context to restrict the targets of virtual dispatch and match the + * call sites of flow into a method with flow out of a method. + * + * There are four cases: + * - `TAnyCallContext()` : No restrictions on method flow. + * - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th + * parameter at the given `call`. This call improves the set of viable + * dispatch targets for at least one method call in the current callable. + * - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The + * originating call does not improve the set of dispatch targets for any + * method call in the current callable and was therefore not recorded. + * - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and + * this dispatch target of `call` implies a reduced set of dispatch origins + * to which data may flow if it should reach a `return` statement. + */ + abstract class CallContext extends TCallContext { + abstract string toString(); + } + + class CallContextAny extends CallContext, TAnyCallContext { + override string toString() { result = "CcAny" } + } + + abstract class CallContextCall extends CallContext { } + + class CallContextSpecificCall extends CallContextCall, TSpecificCall { + override string toString() { + exists(DataFlowCall call, int i | this = TSpecificCall(call, i, _) | + result = "CcCall(" + call + ", " + i + ")" + ) + } + } + + class CallContextSomeCall extends CallContextCall, TSomeCall { + override string toString() { result = "CcSomeCall" } + } + + class CallContextReturn extends CallContext, TReturn { + override string toString() { + exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") + } + } + + /** A callable tagged with a relevant return kind. */ + class ReturnPosition extends TReturnPosition0 { + private DataFlowCallable c; + private ReturnKind kind; + + ReturnPosition() { this = TReturnPosition0(c, kind) } + + /** Gets the callable. */ + DataFlowCallable getCallable() { result = c } + + /** Gets the return kind. */ + ReturnKind getKind() { result = kind } + + /** Gets a textual representation of this return position. */ + string toString() { result = "[" + kind + "] " + c } + } + + pragma[noinline] + DataFlowCallable returnNodeGetEnclosingCallable(ReturnNode ret) { + result = ret.getEnclosingCallable() + } + + pragma[noinline] + ReturnPosition getReturnPosition(ReturnNode ret) { + exists(DataFlowCallable c, ReturnKind k | returnPosition(ret, c, k) | + result = TReturnPosition0(c, k) ) } -} -class CallContextSomeCall extends CallContextCall, TSomeCall { - override string toString() { result = "CcSomeCall" } -} + bindingset[cc, callable] + predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { + cc instanceof CallContextAny and callable = viableCallable(call) + or + exists(DataFlowCallable c0, DataFlowCall call0 | + call0.getEnclosingCallable() = callable and + cc = TReturn(c0, call0) and + c0 = prunedViableImplInCallContextReverse(call0, call) + ) + } -class CallContextReturn extends CallContext, TReturn { - override string toString() { - exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") + bindingset[call, cc] + DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { + exists(DataFlowCall ctx | cc = TSpecificCall(ctx, _, _) | + if reducedViableImplInCallContext(call, _, ctx) + then result = prunedViableImplInCallContext(call, ctx) + else result = viableCallable(call) + ) + or + result = viableCallable(call) and cc instanceof CallContextSomeCall + or + result = viableCallable(call) and cc instanceof CallContextAny + or + result = viableCallable(call) and cc instanceof CallContextReturn } } - -/** A callable tagged with a relevant return kind. */ -class ReturnPosition extends TReturnPosition0 { - private DataFlowCallable c; - private ReturnKind kind; - - ReturnPosition() { this = TReturnPosition0(c, kind) } - - /** Gets the callable. */ - DataFlowCallable getCallable() { result = c } - - /** Gets the return kind. */ - ReturnKind getKind() { result = kind } - - /** Gets a textual representation of this return position. */ - string toString() { result = "[" + kind + "] " + c } -} - -pragma[noinline] -DataFlowCallable returnNodeGetEnclosingCallable(ReturnNode ret) { - result = ret.getEnclosingCallable() -} - -pragma[noinline] -ReturnPosition getReturnPosition(ReturnNode ret) { - exists(DataFlowCallable c, ReturnKind k | returnPosition(ret, c, k) | - result = TReturnPosition0(c, k) - ) -} - -bindingset[cc, callable] -predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { - cc instanceof CallContextAny and callable = viableCallable(call) - or - exists(DataFlowCallable c0, DataFlowCall call0 | - call0.getEnclosingCallable() = callable and - cc = TReturn(c0, call0) and - c0 = prunedViableImplInCallContextReverse(call0, call) - ) -} - -bindingset[call, cc] -DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { - exists(DataFlowCall ctx | cc = TSpecificCall(ctx, _, _) | - if reducedViableImplInCallContext(call, _, ctx) - then result = prunedViableImplInCallContext(call, ctx) - else result = viableCallable(call) - ) - or - result = viableCallable(call) and cc instanceof CallContextSomeCall - or - result = viableCallable(call) and cc instanceof CallContextAny - or - result = viableCallable(call) and cc instanceof CallContextReturn -} diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index d0be8824f98..e0ca469bf78 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index d0be8824f98..e0ca469bf78 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index d0be8824f98..e0ca469bf78 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index d0be8824f98..e0ca469bf78 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index d0be8824f98..e0ca469bf78 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 97052e80004..6463600846f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -3,470 +3,685 @@ import DataFlowImplSpecific::Public private ReturnNode getAReturnNodeOfKind(ReturnKind kind) { result.getKind() = kind } -cached +module Public { + import ImplCommon + import FlowThrough_v2 +} + private module ImplCommon { - /** - * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. - * The instance parameter is considered to have index `-1`. - */ - pragma[nomagic] - private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { - p.isParameterOf(viableCallable(call), i) - } + import Cached - /** - * Holds if `arg` is a possible argument to `p` in `call`, taking virtual - * dispatch into account. - */ cached - predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { - exists(int i | - viableParam(call, i, p) and - arg.argumentOf(call, i) - ) - } + private module Cached { + /** + * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. + * The instance parameter is considered to have index `-1`. + */ + pragma[nomagic] + private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallable(call), i) + } - /** - * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. - */ - private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { - p = node - or - exists(Node mid | - parameterValueFlowNoCtx(p, mid) and - simpleLocalFlowStep(mid, node) and - compatibleTypes(p.getType(), node.getType()) - ) - or - // flow through a callable - exists(Node arg | - parameterValueFlowNoCtx(p, arg) and - argumentValueFlowsThroughNoCtx(arg, node) and - compatibleTypes(p.getType(), node.getType()) - ) - } - - /** - * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps, not taking call contexts - * into account. - */ - private predicate parameterValueFlowsThroughNoCtx(ParameterNode p, ReturnKind kind) { - parameterValueFlowNoCtx(p, getAReturnNodeOfKind(kind)) - } - - pragma[nomagic] - private predicate argumentValueFlowsThroughNoCtx0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind - ) { - exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowsThroughNoCtx(param, kind) - ) - } - - /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. - */ - private predicate argumentValueFlowsThroughNoCtx(ArgumentNode arg, OutNode out) { - exists(DataFlowCall call, ReturnKind kind | argumentValueFlowsThroughNoCtx0(call, arg, kind) | - out = getAnOutNode(call, kind) and - compatibleTypes(arg.getType(), out.getType()) - ) - } - - /** - * Holds if `arg` is the `i`th argument of `call` inside the callable - * `enclosing`, and `arg` may flow through `call`. - */ - pragma[noinline] - private predicate argumentOf( - DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing - ) { - arg.argumentOf(call, i) and - argumentValueFlowsThroughNoCtx(arg, _) and - enclosing = arg.getEnclosingCallable() - } - - pragma[noinline] - private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } - - pragma[noinline] - private predicate viableParamArg0(int i, ArgumentNode arg, CallContext outercc, DataFlowCall call) { - exists(DataFlowCallable c | argumentOf(call, i, arg, c) | - outercc = TAnyCallContext() - or - outercc = TSomeCall(getAParameter(c), _) - or - exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | - reducedViableImplInCallContext(_, c, other) + /** + * Holds if `arg` is a possible argument to `p` in `call`, taking virtual + * dispatch into account. + */ + cached + predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParam(call, i, p) and + arg.argumentOf(call, i) ) - ) - } + } - pragma[noinline] - private predicate viableParamArg1( - ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, - DataFlowCall call - ) { - viableParamArg0(i, arg, outercc, call) and - callable = resolveCall(call, outercc) and - p.isParameterOf(callable, any(int j | j <= i and j >= i)) - } + private module FlowThrough_v1 { + private predicate step = simpleLocalFlowStep/2; - /** - * Holds if `arg` is a possible argument to `p`, in the call `call`, and - * `arg` may flow through `call`. The possible contexts before and after - * entering the callable are `outercc` and `innercc`, respectively. - */ - private predicate viableParamArg( - DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, - CallContextCall innercc - ) { - exists(int i, DataFlowCallable callable | viableParamArg1(p, callable, i, arg, outercc, call) | - if reducedViableImplInCallContext(_, callable, call) - then innercc = TSpecificCall(call, i, true) - else innercc = TSomeCall(p, true) - ) - } - - private CallContextCall getAValidCallContextForParameter(ParameterNode p) { - result = TSomeCall(p, _) - or - exists(DataFlowCall call, int i, DataFlowCallable callable | - result = TSpecificCall(call, i, _) and - p.isParameterOf(callable, i) and - reducedViableImplInCallContext(_, callable, call) - ) - } - - /** - * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, in call context `cc`. - */ - private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { - p = node and - parameterValueFlowsThroughNoCtx(p, _) and - cc = getAValidCallContextForParameter(p) - or - exists(Node mid | - parameterValueFlow(p, mid, cc) and - simpleLocalFlowStep(mid, node) and - compatibleTypes(p.getType(), node.getType()) - ) - or - // flow through a callable - exists(Node arg | - parameterValueFlow(p, arg, cc) and - argumentValueFlowsThrough(arg, node, cc) and - compatibleTypes(p.getType(), node.getType()) - ) - } - - /** - * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps, in call context `cc`. - */ - cached - predicate parameterValueFlowsThrough(ParameterNode p, ReturnKind kind, CallContextCall cc) { - parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) - } - - pragma[nomagic] - private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc - ) { - exists(ParameterNode param, CallContext innercc | - viableParamArg(call, param, arg, cc, innercc) and - parameterValueFlowsThrough(param, kind, innercc) - ) - } - - /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * in call context cc. - */ - cached - predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { - exists(DataFlowCall call, ReturnKind kind | argumentValueFlowsThrough0(call, arg, kind, cc) | - out = getAnOutNode(call, kind) and - compatibleTypes(arg.getType(), out.getType()) - ) - } - - /** - * Holds if `p` can flow to the pre-update node of `n` in the same callable - * using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlowNoCtx(p, n.getPreUpdateNode()) - } - - /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a value-preserving method. - */ - private predicate localValueStep(Node node1, Node node2) { - simpleLocalFlowStep(node1, node2) or - argumentValueFlowsThrough(node1, node2, _) - } - - /* - * Calculation of `predicate store(Node node1, Content f, Node node2)`: - * There are four cases: - * - The base case: A direct local assignment given by `storeStep`. - * - A call to a method or constructor with two arguments, `arg1` and `arg2`, - * such that the call has the side-effect `arg2.f = arg1`. - * - A call to a method that returns an object in which an argument has been - * stored. - * - A reverse step through a read when the result of the read has been - * stored into. This handles cases like `x.f1.f2 = y`. - * `storeViaSideEffect` covers the first two cases, and `storeReturn` covers - * the third case. - */ - - /** - * Holds if data can flow from `node1` to `node2` via a direct assignment to - * `f` or via a call that acts as a setter. - */ - cached - predicate store(Node node1, Content f, Node node2) { - storeViaSideEffect(node1, f, node2) or - storeReturn(node1, f, node2) or - read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode()) - } - - private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(DataFlowCall call, int i1, int i2 | - setterCall(call, i1, i2, f) and - node1.(ArgumentNode).argumentOf(call, i1) and - node2.getPreUpdateNode().(ArgumentNode).argumentOf(call, i2) and - compatibleTypes(node1.getTypeBound(), f.getType()) and - compatibleTypes(node2.getTypeBound(), f.getContainerType()) - ) - } - - pragma[nomagic] - private predicate setterInParam(ParameterNode p1, Content f, ParameterNode p2) { - exists(Node n1, PostUpdateNode n2 | - parameterValueFlowNoCtx(p1, n1) and - storeViaSideEffect(n1, f, n2) and - parameterValueFlowNoCtx(p2, n2.getPreUpdateNode()) and - p1 != p2 - ) - } - - pragma[nomagic] - private predicate setterCall(DataFlowCall call, int i1, int i2, Content f) { - exists(DataFlowCallable callable, ParameterNode p1, ParameterNode p2 | - setterInParam(p1, f, p2) and - callable = viableCallable(call) and - p1.isParameterOf(callable, i1) and - p2.isParameterOf(callable, i2) - ) - } - - pragma[noinline] - private predicate storeReturn0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { - exists(ParameterNode p | - viableParamArg(call, p, arg) and - setterReturn(p, f, kind) - ) - } - - private predicate storeReturn(Node node1, Content f, Node node2) { - exists(DataFlowCall call, ReturnKind kind | - storeReturn0(call, kind, node1, f) and - node2 = getAnOutNode(call, kind) and - compatibleTypes(node1.getTypeBound(), f.getType()) and - compatibleTypes(node2.getTypeBound(), f.getContainerType()) - ) - } - - private predicate setterReturn(ParameterNode p, Content f, ReturnKind kind) { - exists(Node n1, Node n2 | - parameterValueFlowNoCtx(p, n1) and - store(n1, f, n2) and - localValueStep*(n2, getAReturnNodeOfKind(kind)) - ) - } - - pragma[noinline] - private predicate read0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { - exists(ParameterNode p | - viableParamArg(call, p, arg) and - getter(p, f, kind) - ) - } - - /** - * Holds if data can flow from `node1` to `node2` via a direct read of `f` or - * via a getter. - */ - cached - predicate read(Node node1, Content f, Node node2) { - readStep(node1, f, node2) and storeStep(_, f, _) - or - exists(DataFlowCall call, ReturnKind kind | - read0(call, kind, node1, f) and - node2 = getAnOutNode(call, kind) and - compatibleTypes(node1.getTypeBound(), f.getContainerType()) and - compatibleTypes(node2.getTypeBound(), f.getType()) - ) - } - - private predicate getter(ParameterNode p, Content f, ReturnKind kind) { - exists(Node n1, Node n2 | - parameterValueFlowNoCtx(p, n1) and - read(n1, f, n2) and - localValueStep*(n2, getAReturnNodeOfKind(kind)) - ) - } - - cached - predicate localStoreReadStep(Node node1, Node node2) { - exists(Node mid1, Node mid2, Content f | - store(node1, f, mid1) and - localValueStep*(mid1, mid2) and - read(mid2, f, node2) - ) - } - - /** - * Holds if `call` passes an implicit or explicit instance argument, i.e., an - * expression that reaches a `this` parameter. - */ - private predicate callHasInstanceArgument(DataFlowCall call) { - exists(ArgumentNode arg | arg.argumentOf(call, -1)) - } - - cached - newtype TCallContext = - TAnyCallContext() or - TSpecificCall(DataFlowCall call, int i, boolean emptyAp) { - reducedViableImplInCallContext(_, _, call) and - (emptyAp = true or emptyAp = false) and - ( - exists(call.getArgument(i)) + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, not taking call contexts into account. + */ + private predicate parameterValueFlowCand(ParameterNode p, Node node) { + p = node or - i = -1 and callHasInstanceArgument(call) + exists(Node mid | + parameterValueFlowCand(p, mid) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlowCand(p, arg) and + argumentValueFlowsThroughCand(arg, node) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, not taking call contexts + * into account. + */ + private predicate parameterValueFlowsThroughCand(ParameterNode p, ReturnKind kind) { + parameterValueFlowCand(p, getAReturnNodeOfKind(kind)) + } + + pragma[nomagic] + private predicate argumentValueFlowsThroughCand0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind + ) { + exists(ParameterNode param | viableParamArg(call, param, arg) | + parameterValueFlowsThroughCand(param, kind) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + */ + private predicate argumentValueFlowsThroughCand(ArgumentNode arg, OutNode out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + + /** + * Holds if `arg` is the `i`th argument of `call` inside the callable + * `enclosing`, and `arg` may flow through `call`. + */ + pragma[noinline] + private predicate argumentOf( + DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing + ) { + arg.argumentOf(call, i) and + argumentValueFlowsThroughCand(arg, _) and + enclosing = arg.getEnclosingCallable() + } + + pragma[noinline] + private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } + + pragma[noinline] + private predicate viableParamArg0( + int i, ArgumentNode arg, CallContext outercc, DataFlowCall call + ) { + exists(DataFlowCallable c | argumentOf(call, i, arg, c) | + outercc = TAnyCallContext() + or + outercc = TSomeCall(getAParameter(c), _) + or + exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | + reducedViableImplInCallContext(_, c, other) + ) + ) + } + + pragma[noinline] + private predicate viableParamArg1( + ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, + DataFlowCall call + ) { + viableParamArg0(i, arg, outercc, call) and + callable = resolveCall(call, outercc) and + p.isParameterOf(callable, any(int j | j <= i and j >= i)) + } + + /** + * Holds if `arg` is a possible argument to `p`, in the call `call`, and + * `arg` may flow through `call`. The possible contexts before and after + * entering the callable are `outercc` and `innercc`, respectively. + */ + private predicate viableParamArg( + DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, + CallContextCall innercc + ) { + exists(int i, DataFlowCallable callable | + viableParamArg1(p, callable, i, arg, outercc, call) + | + if reducedViableImplInCallContext(_, callable, call) + then innercc = TSpecificCall(call, i, true) + else innercc = TSomeCall(p, true) + ) + } + + private CallContextCall getAValidCallContextForParameter(ParameterNode p) { + result = TSomeCall(p, _) + or + exists(DataFlowCall call, int i, DataFlowCallable callable | + result = TSpecificCall(call, i, _) and + p.isParameterOf(callable, i) and + reducedViableImplInCallContext(_, callable, call) + ) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { + p = node and + parameterValueFlowsThroughCand(p, _) and + cc = getAValidCallContextForParameter(p) + or + exists(Node mid | + parameterValueFlow(p, mid, cc) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlow(p, arg, cc) and + argumentValueFlowsThrough(arg, node, cc) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlowsThrough( + ParameterNode p, ReturnKind kind, CallContextCall cc + ) { + parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) + } + + pragma[nomagic] + private predicate argumentValueFlowsThrough0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc + ) { + exists(ParameterNode param, CallContext innercc | + viableParamArg(call, param, arg, cc, innercc) and + parameterValueFlowsThrough(param, kind, innercc) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * in call context cc. + */ + predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, cc) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + } + + /** + * Holds if `p` can flow to the pre-update node of `n` in the same callable + * using only value-preserving steps. + */ + cached + predicate parameterValueFlowsToUpdate(ParameterNode p, PostUpdateNode n) { + parameterValueFlowNoCtx(p, n.getPreUpdateNode()) + } + + /** + * Holds if data can flow from `node1` to `node2` in one local step or a step + * through a value-preserving method. + */ + private predicate localValueStep(Node node1, Node node2) { + simpleLocalFlowStep(node1, node2) or + FlowThrough_v1::argumentValueFlowsThrough(node1, node2, _) + } + + private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { + p = node + or + exists(Node mid | + parameterValueFlowNoCtx(p, mid) and + localValueStep(mid, node) and + compatibleTypes(p.getType(), node.getType()) ) - } or - TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or - TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) } + } - cached - newtype TReturnPosition = - TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) } -} + /* + * Calculation of `predicate store(Node node1, Content f, Node node2)`: + * There are four cases: + * - The base case: A direct local assignment given by `storeStep`. + * - A call to a method or constructor with two arguments, `arg1` and `arg2`, + * such that the call has the side-effect `arg2.f = arg1`. + * - A call to a method that returns an object in which an argument has been + * stored. + * - A reverse step through a read when the result of the read has been + * stored into. This handles cases like `x.f1.f2 = y`. + * `storeViaSideEffect` covers the first two cases, and `storeReturn` covers + * the third case. + */ -import ImplCommon + /** + * Holds if data can flow from `node1` to `node2` via a direct assignment to + * `f` or via a call that acts as a setter. + */ + cached + predicate store(Node node1, Content f, Node node2) { + storeViaSideEffect(node1, f, node2) or + storeReturn(node1, f, node2) or + read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode()) + } -pragma[noinline] -private predicate returnPosition(ReturnNode ret, DataFlowCallable c, ReturnKind kind) { - c = returnNodeGetEnclosingCallable(ret) and - kind = ret.getKind() -} + private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) { + storeStep(node1, f, node2) and readStep(_, f, _) + or + exists(DataFlowCall call, int i1, int i2 | + setterCall(call, i1, i2, f) and + node1.(ArgumentNode).argumentOf(call, i1) and + node2.getPreUpdateNode().(ArgumentNode).argumentOf(call, i2) and + compatibleTypes(node1.getTypeBound(), f.getType()) and + compatibleTypes(node2.getTypeBound(), f.getContainerType()) + ) + } -/** - * A call context to restrict the targets of virtual dispatch and match the - * call sites of flow into a method with flow out of a method. - * - * There are four cases: - * - `TAnyCallContext()` : No restrictions on method flow. - * - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th - * parameter at the given `call`. This call improves the set of viable - * dispatch targets for at least one method call in the current callable. - * - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The - * originating call does not improve the set of dispatch targets for any - * method call in the current callable and was therefore not recorded. - * - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and - * this dispatch target of `call` implies a reduced set of dispatch origins - * to which data may flow if it should reach a `return` statement. - */ -abstract class CallContext extends TCallContext { - abstract string toString(); -} + pragma[nomagic] + private predicate setterInParam(ParameterNode p1, Content f, ParameterNode p2) { + exists(Node n1, PostUpdateNode n2 | + parameterValueFlowNoCtx(p1, n1) and + storeViaSideEffect(n1, f, n2) and + parameterValueFlowNoCtx(p2, n2.getPreUpdateNode()) and + p1 != p2 + ) + } -class CallContextAny extends CallContext, TAnyCallContext { - override string toString() { result = "CcAny" } -} + pragma[nomagic] + private predicate setterCall(DataFlowCall call, int i1, int i2, Content f) { + exists(DataFlowCallable callable, ParameterNode p1, ParameterNode p2 | + setterInParam(p1, f, p2) and + callable = viableCallable(call) and + p1.isParameterOf(callable, i1) and + p2.isParameterOf(callable, i2) + ) + } -abstract class CallContextCall extends CallContext { } + pragma[noinline] + private predicate storeReturn0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { + exists(ParameterNode p | + viableParamArg(call, p, arg) and + setterReturn(p, f, kind) + ) + } -class CallContextSpecificCall extends CallContextCall, TSpecificCall { - override string toString() { - exists(DataFlowCall call, int i | this = TSpecificCall(call, i, _) | - result = "CcCall(" + call + ", " + i + ")" + private predicate storeReturn(Node node1, Content f, Node node2) { + exists(DataFlowCall call, ReturnKind kind | + storeReturn0(call, kind, node1, f) and + node2 = getAnOutNode(call, kind) and + compatibleTypes(node1.getTypeBound(), f.getType()) and + compatibleTypes(node2.getTypeBound(), f.getContainerType()) + ) + } + + private predicate setterReturn(ParameterNode p, Content f, ReturnKind kind) { + exists(Node n1, Node n2 | + parameterValueFlowNoCtx(p, n1) and + store(n1, f, n2) and + localValueStep*(n2, getAReturnNodeOfKind(kind)) + ) + } + + pragma[noinline] + private predicate read0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { + exists(ParameterNode p | + viableParamArg(call, p, arg) and + getter(p, f, kind) + ) + } + + /** + * Holds if data can flow from `node1` to `node2` via a direct read of `f` or + * via a getter. + */ + cached + predicate read(Node node1, Content f, Node node2) { + readStep(node1, f, node2) and storeStep(_, f, _) + or + exists(DataFlowCall call, ReturnKind kind | + read0(call, kind, node1, f) and + node2 = getAnOutNode(call, kind) and + compatibleTypes(node1.getTypeBound(), f.getContainerType()) and + compatibleTypes(node2.getTypeBound(), f.getType()) + ) + } + + private predicate getter(ParameterNode p, Content f, ReturnKind kind) { + exists(Node n1, Node n2 | + parameterValueFlowNoCtx(p, n1) and + read(n1, f, n2) and + localValueStep*(n2, getAReturnNodeOfKind(kind)) + ) + } + + cached + predicate localStoreReadStep(Node node1, Node node2) { + exists(Node mid1, Node mid2, Content f | + store(node1, f, mid1) and + localValueStep*(mid1, mid2) and + read(mid2, f, node2) and + compatibleTypes(node1.getTypeBound(), node2.getTypeBound()) + ) + } + + cached + module FlowThrough_v2 { + private predicate step(Node node1, Node node2) { + simpleLocalFlowStep(node1, node2) or + localStoreReadStep(node1, node2) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, not taking call contexts into account. + */ + private predicate parameterValueFlowCand(ParameterNode p, Node node) { + p = node + or + exists(Node mid | + parameterValueFlowCand(p, mid) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlowCand(p, arg) and + argumentValueFlowsThroughCand(arg, node) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, not taking call contexts + * into account. + */ + private predicate parameterValueFlowsThroughCand(ParameterNode p, ReturnKind kind) { + parameterValueFlowCand(p, getAReturnNodeOfKind(kind)) + } + + pragma[nomagic] + private predicate argumentValueFlowsThroughCand0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind + ) { + exists(ParameterNode param | viableParamArg(call, param, arg) | + parameterValueFlowsThroughCand(param, kind) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + */ + private predicate argumentValueFlowsThroughCand(ArgumentNode arg, OutNode out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + + /** + * Holds if `arg` is the `i`th argument of `call` inside the callable + * `enclosing`, and `arg` may flow through `call`. + */ + pragma[noinline] + private predicate argumentOf( + DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing + ) { + arg.argumentOf(call, i) and + argumentValueFlowsThroughCand(arg, _) and + enclosing = arg.getEnclosingCallable() + } + + pragma[noinline] + private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } + + pragma[noinline] + private predicate viableParamArg0( + int i, ArgumentNode arg, CallContext outercc, DataFlowCall call + ) { + exists(DataFlowCallable c | argumentOf(call, i, arg, c) | + outercc = TAnyCallContext() + or + outercc = TSomeCall(getAParameter(c), _) + or + exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | + reducedViableImplInCallContext(_, c, other) + ) + ) + } + + pragma[noinline] + private predicate viableParamArg1( + ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, + DataFlowCall call + ) { + viableParamArg0(i, arg, outercc, call) and + callable = resolveCall(call, outercc) and + p.isParameterOf(callable, any(int j | j <= i and j >= i)) + } + + /** + * Holds if `arg` is a possible argument to `p`, in the call `call`, and + * `arg` may flow through `call`. The possible contexts before and after + * entering the callable are `outercc` and `innercc`, respectively. + */ + private predicate viableParamArg( + DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, + CallContextCall innercc + ) { + exists(int i, DataFlowCallable callable | + viableParamArg1(p, callable, i, arg, outercc, call) + | + if reducedViableImplInCallContext(_, callable, call) + then innercc = TSpecificCall(call, i, true) + else innercc = TSomeCall(p, true) + ) + } + + private CallContextCall getAValidCallContextForParameter(ParameterNode p) { + result = TSomeCall(p, _) + or + exists(DataFlowCall call, int i, DataFlowCallable callable | + result = TSpecificCall(call, i, _) and + p.isParameterOf(callable, i) and + reducedViableImplInCallContext(_, callable, call) + ) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { + p = node and + parameterValueFlowsThroughCand(p, _) and + cc = getAValidCallContextForParameter(p) + or + exists(Node mid | + parameterValueFlow(p, mid, cc) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlow(p, arg, cc) and + argumentValueFlowsThrough(arg, node, cc) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, in call context `cc`. + */ + cached + predicate parameterValueFlowsThrough(ParameterNode p, ReturnKind kind, CallContextCall cc) { + parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) + } + + pragma[nomagic] + private predicate argumentValueFlowsThrough0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc + ) { + exists(ParameterNode param, CallContext innercc | + viableParamArg(call, param, arg, cc, innercc) and + parameterValueFlowsThrough(param, kind, innercc) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * in call context cc. + */ + cached + predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, cc) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + } + + /** + * Holds if `call` passes an implicit or explicit instance argument, i.e., an + * expression that reaches a `this` parameter. + */ + private predicate callHasInstanceArgument(DataFlowCall call) { + exists(ArgumentNode arg | arg.argumentOf(call, -1)) + } + + cached + newtype TCallContext = + TAnyCallContext() or + TSpecificCall(DataFlowCall call, int i, boolean emptyAp) { + reducedViableImplInCallContext(_, _, call) and + (emptyAp = true or emptyAp = false) and + ( + exists(call.getArgument(i)) + or + i = -1 and callHasInstanceArgument(call) + ) + } or + TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or + TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) } + + cached + newtype TReturnPosition = + TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) } + } + + pragma[noinline] + private predicate returnPosition(ReturnNode ret, DataFlowCallable c, ReturnKind kind) { + c = returnNodeGetEnclosingCallable(ret) and + kind = ret.getKind() + } + + /** + * A call context to restrict the targets of virtual dispatch and match the + * call sites of flow into a method with flow out of a method. + * + * There are four cases: + * - `TAnyCallContext()` : No restrictions on method flow. + * - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th + * parameter at the given `call`. This call improves the set of viable + * dispatch targets for at least one method call in the current callable. + * - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The + * originating call does not improve the set of dispatch targets for any + * method call in the current callable and was therefore not recorded. + * - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and + * this dispatch target of `call` implies a reduced set of dispatch origins + * to which data may flow if it should reach a `return` statement. + */ + abstract class CallContext extends TCallContext { + abstract string toString(); + } + + class CallContextAny extends CallContext, TAnyCallContext { + override string toString() { result = "CcAny" } + } + + abstract class CallContextCall extends CallContext { } + + class CallContextSpecificCall extends CallContextCall, TSpecificCall { + override string toString() { + exists(DataFlowCall call, int i | this = TSpecificCall(call, i, _) | + result = "CcCall(" + call + ", " + i + ")" + ) + } + } + + class CallContextSomeCall extends CallContextCall, TSomeCall { + override string toString() { result = "CcSomeCall" } + } + + class CallContextReturn extends CallContext, TReturn { + override string toString() { + exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") + } + } + + /** A callable tagged with a relevant return kind. */ + class ReturnPosition extends TReturnPosition0 { + private DataFlowCallable c; + private ReturnKind kind; + + ReturnPosition() { this = TReturnPosition0(c, kind) } + + /** Gets the callable. */ + DataFlowCallable getCallable() { result = c } + + /** Gets the return kind. */ + ReturnKind getKind() { result = kind } + + /** Gets a textual representation of this return position. */ + string toString() { result = "[" + kind + "] " + c } + } + + pragma[noinline] + DataFlowCallable returnNodeGetEnclosingCallable(ReturnNode ret) { + result = ret.getEnclosingCallable() + } + + pragma[noinline] + ReturnPosition getReturnPosition(ReturnNode ret) { + exists(DataFlowCallable c, ReturnKind k | returnPosition(ret, c, k) | + result = TReturnPosition0(c, k) ) } -} -class CallContextSomeCall extends CallContextCall, TSomeCall { - override string toString() { result = "CcSomeCall" } -} + bindingset[cc, callable] + predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { + cc instanceof CallContextAny and callable = viableCallable(call) + or + exists(DataFlowCallable c0, DataFlowCall call0 | + call0.getEnclosingCallable() = callable and + cc = TReturn(c0, call0) and + c0 = prunedViableImplInCallContextReverse(call0, call) + ) + } -class CallContextReturn extends CallContext, TReturn { - override string toString() { - exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") + bindingset[call, cc] + DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { + exists(DataFlowCall ctx | cc = TSpecificCall(ctx, _, _) | + if reducedViableImplInCallContext(call, _, ctx) + then result = prunedViableImplInCallContext(call, ctx) + else result = viableCallable(call) + ) + or + result = viableCallable(call) and cc instanceof CallContextSomeCall + or + result = viableCallable(call) and cc instanceof CallContextAny + or + result = viableCallable(call) and cc instanceof CallContextReturn } } - -/** A callable tagged with a relevant return kind. */ -class ReturnPosition extends TReturnPosition0 { - private DataFlowCallable c; - private ReturnKind kind; - - ReturnPosition() { this = TReturnPosition0(c, kind) } - - /** Gets the callable. */ - DataFlowCallable getCallable() { result = c } - - /** Gets the return kind. */ - ReturnKind getKind() { result = kind } - - /** Gets a textual representation of this return position. */ - string toString() { result = "[" + kind + "] " + c } -} - -pragma[noinline] -DataFlowCallable returnNodeGetEnclosingCallable(ReturnNode ret) { - result = ret.getEnclosingCallable() -} - -pragma[noinline] -ReturnPosition getReturnPosition(ReturnNode ret) { - exists(DataFlowCallable c, ReturnKind k | returnPosition(ret, c, k) | - result = TReturnPosition0(c, k) - ) -} - -bindingset[cc, callable] -predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { - cc instanceof CallContextAny and callable = viableCallable(call) - or - exists(DataFlowCallable c0, DataFlowCall call0 | - call0.getEnclosingCallable() = callable and - cc = TReturn(c0, call0) and - c0 = prunedViableImplInCallContextReverse(call0, call) - ) -} - -bindingset[call, cc] -DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { - exists(DataFlowCall ctx | cc = TSpecificCall(ctx, _, _) | - if reducedViableImplInCallContext(call, _, ctx) - then result = prunedViableImplInCallContext(call, ctx) - else result = viableCallable(call) - ) - or - result = viableCallable(call) and cc instanceof CallContextSomeCall - or - result = viableCallable(call) and cc instanceof CallContextAny - or - result = viableCallable(call) and cc instanceof CallContextReturn -} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index d0be8824f98..e0ca469bf78 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index d0be8824f98..e0ca469bf78 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index d0be8824f98..e0ca469bf78 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index d0be8824f98..e0ca469bf78 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index d0be8824f98..e0ca469bf78 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -7,7 +7,7 @@ * on each other without introducing mutual recursion among those configurations. */ -private import DataFlowImplCommon +private import DataFlowImplCommon::Public private import DataFlowImplSpecific::Private import DataFlowImplSpecific::Public @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 97052e80004..6463600846f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -3,470 +3,685 @@ import DataFlowImplSpecific::Public private ReturnNode getAReturnNodeOfKind(ReturnKind kind) { result.getKind() = kind } -cached +module Public { + import ImplCommon + import FlowThrough_v2 +} + private module ImplCommon { - /** - * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. - * The instance parameter is considered to have index `-1`. - */ - pragma[nomagic] - private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { - p.isParameterOf(viableCallable(call), i) - } + import Cached - /** - * Holds if `arg` is a possible argument to `p` in `call`, taking virtual - * dispatch into account. - */ cached - predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { - exists(int i | - viableParam(call, i, p) and - arg.argumentOf(call, i) - ) - } + private module Cached { + /** + * Holds if `p` is the `i`th parameter of a viable dispatch target of `call`. + * The instance parameter is considered to have index `-1`. + */ + pragma[nomagic] + private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { + p.isParameterOf(viableCallable(call), i) + } - /** - * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. - */ - private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { - p = node - or - exists(Node mid | - parameterValueFlowNoCtx(p, mid) and - simpleLocalFlowStep(mid, node) and - compatibleTypes(p.getType(), node.getType()) - ) - or - // flow through a callable - exists(Node arg | - parameterValueFlowNoCtx(p, arg) and - argumentValueFlowsThroughNoCtx(arg, node) and - compatibleTypes(p.getType(), node.getType()) - ) - } - - /** - * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps, not taking call contexts - * into account. - */ - private predicate parameterValueFlowsThroughNoCtx(ParameterNode p, ReturnKind kind) { - parameterValueFlowNoCtx(p, getAReturnNodeOfKind(kind)) - } - - pragma[nomagic] - private predicate argumentValueFlowsThroughNoCtx0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind - ) { - exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowsThroughNoCtx(param, kind) - ) - } - - /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. - */ - private predicate argumentValueFlowsThroughNoCtx(ArgumentNode arg, OutNode out) { - exists(DataFlowCall call, ReturnKind kind | argumentValueFlowsThroughNoCtx0(call, arg, kind) | - out = getAnOutNode(call, kind) and - compatibleTypes(arg.getType(), out.getType()) - ) - } - - /** - * Holds if `arg` is the `i`th argument of `call` inside the callable - * `enclosing`, and `arg` may flow through `call`. - */ - pragma[noinline] - private predicate argumentOf( - DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing - ) { - arg.argumentOf(call, i) and - argumentValueFlowsThroughNoCtx(arg, _) and - enclosing = arg.getEnclosingCallable() - } - - pragma[noinline] - private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } - - pragma[noinline] - private predicate viableParamArg0(int i, ArgumentNode arg, CallContext outercc, DataFlowCall call) { - exists(DataFlowCallable c | argumentOf(call, i, arg, c) | - outercc = TAnyCallContext() - or - outercc = TSomeCall(getAParameter(c), _) - or - exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | - reducedViableImplInCallContext(_, c, other) + /** + * Holds if `arg` is a possible argument to `p` in `call`, taking virtual + * dispatch into account. + */ + cached + predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParam(call, i, p) and + arg.argumentOf(call, i) ) - ) - } + } - pragma[noinline] - private predicate viableParamArg1( - ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, - DataFlowCall call - ) { - viableParamArg0(i, arg, outercc, call) and - callable = resolveCall(call, outercc) and - p.isParameterOf(callable, any(int j | j <= i and j >= i)) - } + private module FlowThrough_v1 { + private predicate step = simpleLocalFlowStep/2; - /** - * Holds if `arg` is a possible argument to `p`, in the call `call`, and - * `arg` may flow through `call`. The possible contexts before and after - * entering the callable are `outercc` and `innercc`, respectively. - */ - private predicate viableParamArg( - DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, - CallContextCall innercc - ) { - exists(int i, DataFlowCallable callable | viableParamArg1(p, callable, i, arg, outercc, call) | - if reducedViableImplInCallContext(_, callable, call) - then innercc = TSpecificCall(call, i, true) - else innercc = TSomeCall(p, true) - ) - } - - private CallContextCall getAValidCallContextForParameter(ParameterNode p) { - result = TSomeCall(p, _) - or - exists(DataFlowCall call, int i, DataFlowCallable callable | - result = TSpecificCall(call, i, _) and - p.isParameterOf(callable, i) and - reducedViableImplInCallContext(_, callable, call) - ) - } - - /** - * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, in call context `cc`. - */ - private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { - p = node and - parameterValueFlowsThroughNoCtx(p, _) and - cc = getAValidCallContextForParameter(p) - or - exists(Node mid | - parameterValueFlow(p, mid, cc) and - simpleLocalFlowStep(mid, node) and - compatibleTypes(p.getType(), node.getType()) - ) - or - // flow through a callable - exists(Node arg | - parameterValueFlow(p, arg, cc) and - argumentValueFlowsThrough(arg, node, cc) and - compatibleTypes(p.getType(), node.getType()) - ) - } - - /** - * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps, in call context `cc`. - */ - cached - predicate parameterValueFlowsThrough(ParameterNode p, ReturnKind kind, CallContextCall cc) { - parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) - } - - pragma[nomagic] - private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc - ) { - exists(ParameterNode param, CallContext innercc | - viableParamArg(call, param, arg, cc, innercc) and - parameterValueFlowsThrough(param, kind, innercc) - ) - } - - /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * in call context cc. - */ - cached - predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { - exists(DataFlowCall call, ReturnKind kind | argumentValueFlowsThrough0(call, arg, kind, cc) | - out = getAnOutNode(call, kind) and - compatibleTypes(arg.getType(), out.getType()) - ) - } - - /** - * Holds if `p` can flow to the pre-update node of `n` in the same callable - * using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlowNoCtx(p, n.getPreUpdateNode()) - } - - /** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a value-preserving method. - */ - private predicate localValueStep(Node node1, Node node2) { - simpleLocalFlowStep(node1, node2) or - argumentValueFlowsThrough(node1, node2, _) - } - - /* - * Calculation of `predicate store(Node node1, Content f, Node node2)`: - * There are four cases: - * - The base case: A direct local assignment given by `storeStep`. - * - A call to a method or constructor with two arguments, `arg1` and `arg2`, - * such that the call has the side-effect `arg2.f = arg1`. - * - A call to a method that returns an object in which an argument has been - * stored. - * - A reverse step through a read when the result of the read has been - * stored into. This handles cases like `x.f1.f2 = y`. - * `storeViaSideEffect` covers the first two cases, and `storeReturn` covers - * the third case. - */ - - /** - * Holds if data can flow from `node1` to `node2` via a direct assignment to - * `f` or via a call that acts as a setter. - */ - cached - predicate store(Node node1, Content f, Node node2) { - storeViaSideEffect(node1, f, node2) or - storeReturn(node1, f, node2) or - read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode()) - } - - private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(DataFlowCall call, int i1, int i2 | - setterCall(call, i1, i2, f) and - node1.(ArgumentNode).argumentOf(call, i1) and - node2.getPreUpdateNode().(ArgumentNode).argumentOf(call, i2) and - compatibleTypes(node1.getTypeBound(), f.getType()) and - compatibleTypes(node2.getTypeBound(), f.getContainerType()) - ) - } - - pragma[nomagic] - private predicate setterInParam(ParameterNode p1, Content f, ParameterNode p2) { - exists(Node n1, PostUpdateNode n2 | - parameterValueFlowNoCtx(p1, n1) and - storeViaSideEffect(n1, f, n2) and - parameterValueFlowNoCtx(p2, n2.getPreUpdateNode()) and - p1 != p2 - ) - } - - pragma[nomagic] - private predicate setterCall(DataFlowCall call, int i1, int i2, Content f) { - exists(DataFlowCallable callable, ParameterNode p1, ParameterNode p2 | - setterInParam(p1, f, p2) and - callable = viableCallable(call) and - p1.isParameterOf(callable, i1) and - p2.isParameterOf(callable, i2) - ) - } - - pragma[noinline] - private predicate storeReturn0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { - exists(ParameterNode p | - viableParamArg(call, p, arg) and - setterReturn(p, f, kind) - ) - } - - private predicate storeReturn(Node node1, Content f, Node node2) { - exists(DataFlowCall call, ReturnKind kind | - storeReturn0(call, kind, node1, f) and - node2 = getAnOutNode(call, kind) and - compatibleTypes(node1.getTypeBound(), f.getType()) and - compatibleTypes(node2.getTypeBound(), f.getContainerType()) - ) - } - - private predicate setterReturn(ParameterNode p, Content f, ReturnKind kind) { - exists(Node n1, Node n2 | - parameterValueFlowNoCtx(p, n1) and - store(n1, f, n2) and - localValueStep*(n2, getAReturnNodeOfKind(kind)) - ) - } - - pragma[noinline] - private predicate read0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { - exists(ParameterNode p | - viableParamArg(call, p, arg) and - getter(p, f, kind) - ) - } - - /** - * Holds if data can flow from `node1` to `node2` via a direct read of `f` or - * via a getter. - */ - cached - predicate read(Node node1, Content f, Node node2) { - readStep(node1, f, node2) and storeStep(_, f, _) - or - exists(DataFlowCall call, ReturnKind kind | - read0(call, kind, node1, f) and - node2 = getAnOutNode(call, kind) and - compatibleTypes(node1.getTypeBound(), f.getContainerType()) and - compatibleTypes(node2.getTypeBound(), f.getType()) - ) - } - - private predicate getter(ParameterNode p, Content f, ReturnKind kind) { - exists(Node n1, Node n2 | - parameterValueFlowNoCtx(p, n1) and - read(n1, f, n2) and - localValueStep*(n2, getAReturnNodeOfKind(kind)) - ) - } - - cached - predicate localStoreReadStep(Node node1, Node node2) { - exists(Node mid1, Node mid2, Content f | - store(node1, f, mid1) and - localValueStep*(mid1, mid2) and - read(mid2, f, node2) - ) - } - - /** - * Holds if `call` passes an implicit or explicit instance argument, i.e., an - * expression that reaches a `this` parameter. - */ - private predicate callHasInstanceArgument(DataFlowCall call) { - exists(ArgumentNode arg | arg.argumentOf(call, -1)) - } - - cached - newtype TCallContext = - TAnyCallContext() or - TSpecificCall(DataFlowCall call, int i, boolean emptyAp) { - reducedViableImplInCallContext(_, _, call) and - (emptyAp = true or emptyAp = false) and - ( - exists(call.getArgument(i)) + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, not taking call contexts into account. + */ + private predicate parameterValueFlowCand(ParameterNode p, Node node) { + p = node or - i = -1 and callHasInstanceArgument(call) + exists(Node mid | + parameterValueFlowCand(p, mid) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlowCand(p, arg) and + argumentValueFlowsThroughCand(arg, node) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, not taking call contexts + * into account. + */ + private predicate parameterValueFlowsThroughCand(ParameterNode p, ReturnKind kind) { + parameterValueFlowCand(p, getAReturnNodeOfKind(kind)) + } + + pragma[nomagic] + private predicate argumentValueFlowsThroughCand0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind + ) { + exists(ParameterNode param | viableParamArg(call, param, arg) | + parameterValueFlowsThroughCand(param, kind) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + */ + private predicate argumentValueFlowsThroughCand(ArgumentNode arg, OutNode out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + + /** + * Holds if `arg` is the `i`th argument of `call` inside the callable + * `enclosing`, and `arg` may flow through `call`. + */ + pragma[noinline] + private predicate argumentOf( + DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing + ) { + arg.argumentOf(call, i) and + argumentValueFlowsThroughCand(arg, _) and + enclosing = arg.getEnclosingCallable() + } + + pragma[noinline] + private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } + + pragma[noinline] + private predicate viableParamArg0( + int i, ArgumentNode arg, CallContext outercc, DataFlowCall call + ) { + exists(DataFlowCallable c | argumentOf(call, i, arg, c) | + outercc = TAnyCallContext() + or + outercc = TSomeCall(getAParameter(c), _) + or + exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | + reducedViableImplInCallContext(_, c, other) + ) + ) + } + + pragma[noinline] + private predicate viableParamArg1( + ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, + DataFlowCall call + ) { + viableParamArg0(i, arg, outercc, call) and + callable = resolveCall(call, outercc) and + p.isParameterOf(callable, any(int j | j <= i and j >= i)) + } + + /** + * Holds if `arg` is a possible argument to `p`, in the call `call`, and + * `arg` may flow through `call`. The possible contexts before and after + * entering the callable are `outercc` and `innercc`, respectively. + */ + private predicate viableParamArg( + DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, + CallContextCall innercc + ) { + exists(int i, DataFlowCallable callable | + viableParamArg1(p, callable, i, arg, outercc, call) + | + if reducedViableImplInCallContext(_, callable, call) + then innercc = TSpecificCall(call, i, true) + else innercc = TSomeCall(p, true) + ) + } + + private CallContextCall getAValidCallContextForParameter(ParameterNode p) { + result = TSomeCall(p, _) + or + exists(DataFlowCall call, int i, DataFlowCallable callable | + result = TSpecificCall(call, i, _) and + p.isParameterOf(callable, i) and + reducedViableImplInCallContext(_, callable, call) + ) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { + p = node and + parameterValueFlowsThroughCand(p, _) and + cc = getAValidCallContextForParameter(p) + or + exists(Node mid | + parameterValueFlow(p, mid, cc) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlow(p, arg, cc) and + argumentValueFlowsThrough(arg, node, cc) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlowsThrough( + ParameterNode p, ReturnKind kind, CallContextCall cc + ) { + parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) + } + + pragma[nomagic] + private predicate argumentValueFlowsThrough0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc + ) { + exists(ParameterNode param, CallContext innercc | + viableParamArg(call, param, arg, cc, innercc) and + parameterValueFlowsThrough(param, kind, innercc) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * in call context cc. + */ + predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, cc) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + } + + /** + * Holds if `p` can flow to the pre-update node of `n` in the same callable + * using only value-preserving steps. + */ + cached + predicate parameterValueFlowsToUpdate(ParameterNode p, PostUpdateNode n) { + parameterValueFlowNoCtx(p, n.getPreUpdateNode()) + } + + /** + * Holds if data can flow from `node1` to `node2` in one local step or a step + * through a value-preserving method. + */ + private predicate localValueStep(Node node1, Node node2) { + simpleLocalFlowStep(node1, node2) or + FlowThrough_v1::argumentValueFlowsThrough(node1, node2, _) + } + + private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { + p = node + or + exists(Node mid | + parameterValueFlowNoCtx(p, mid) and + localValueStep(mid, node) and + compatibleTypes(p.getType(), node.getType()) ) - } or - TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or - TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) } + } - cached - newtype TReturnPosition = - TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) } -} + /* + * Calculation of `predicate store(Node node1, Content f, Node node2)`: + * There are four cases: + * - The base case: A direct local assignment given by `storeStep`. + * - A call to a method or constructor with two arguments, `arg1` and `arg2`, + * such that the call has the side-effect `arg2.f = arg1`. + * - A call to a method that returns an object in which an argument has been + * stored. + * - A reverse step through a read when the result of the read has been + * stored into. This handles cases like `x.f1.f2 = y`. + * `storeViaSideEffect` covers the first two cases, and `storeReturn` covers + * the third case. + */ -import ImplCommon + /** + * Holds if data can flow from `node1` to `node2` via a direct assignment to + * `f` or via a call that acts as a setter. + */ + cached + predicate store(Node node1, Content f, Node node2) { + storeViaSideEffect(node1, f, node2) or + storeReturn(node1, f, node2) or + read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode()) + } -pragma[noinline] -private predicate returnPosition(ReturnNode ret, DataFlowCallable c, ReturnKind kind) { - c = returnNodeGetEnclosingCallable(ret) and - kind = ret.getKind() -} + private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) { + storeStep(node1, f, node2) and readStep(_, f, _) + or + exists(DataFlowCall call, int i1, int i2 | + setterCall(call, i1, i2, f) and + node1.(ArgumentNode).argumentOf(call, i1) and + node2.getPreUpdateNode().(ArgumentNode).argumentOf(call, i2) and + compatibleTypes(node1.getTypeBound(), f.getType()) and + compatibleTypes(node2.getTypeBound(), f.getContainerType()) + ) + } -/** - * A call context to restrict the targets of virtual dispatch and match the - * call sites of flow into a method with flow out of a method. - * - * There are four cases: - * - `TAnyCallContext()` : No restrictions on method flow. - * - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th - * parameter at the given `call`. This call improves the set of viable - * dispatch targets for at least one method call in the current callable. - * - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The - * originating call does not improve the set of dispatch targets for any - * method call in the current callable and was therefore not recorded. - * - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and - * this dispatch target of `call` implies a reduced set of dispatch origins - * to which data may flow if it should reach a `return` statement. - */ -abstract class CallContext extends TCallContext { - abstract string toString(); -} + pragma[nomagic] + private predicate setterInParam(ParameterNode p1, Content f, ParameterNode p2) { + exists(Node n1, PostUpdateNode n2 | + parameterValueFlowNoCtx(p1, n1) and + storeViaSideEffect(n1, f, n2) and + parameterValueFlowNoCtx(p2, n2.getPreUpdateNode()) and + p1 != p2 + ) + } -class CallContextAny extends CallContext, TAnyCallContext { - override string toString() { result = "CcAny" } -} + pragma[nomagic] + private predicate setterCall(DataFlowCall call, int i1, int i2, Content f) { + exists(DataFlowCallable callable, ParameterNode p1, ParameterNode p2 | + setterInParam(p1, f, p2) and + callable = viableCallable(call) and + p1.isParameterOf(callable, i1) and + p2.isParameterOf(callable, i2) + ) + } -abstract class CallContextCall extends CallContext { } + pragma[noinline] + private predicate storeReturn0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { + exists(ParameterNode p | + viableParamArg(call, p, arg) and + setterReturn(p, f, kind) + ) + } -class CallContextSpecificCall extends CallContextCall, TSpecificCall { - override string toString() { - exists(DataFlowCall call, int i | this = TSpecificCall(call, i, _) | - result = "CcCall(" + call + ", " + i + ")" + private predicate storeReturn(Node node1, Content f, Node node2) { + exists(DataFlowCall call, ReturnKind kind | + storeReturn0(call, kind, node1, f) and + node2 = getAnOutNode(call, kind) and + compatibleTypes(node1.getTypeBound(), f.getType()) and + compatibleTypes(node2.getTypeBound(), f.getContainerType()) + ) + } + + private predicate setterReturn(ParameterNode p, Content f, ReturnKind kind) { + exists(Node n1, Node n2 | + parameterValueFlowNoCtx(p, n1) and + store(n1, f, n2) and + localValueStep*(n2, getAReturnNodeOfKind(kind)) + ) + } + + pragma[noinline] + private predicate read0(DataFlowCall call, ReturnKind kind, ArgumentNode arg, Content f) { + exists(ParameterNode p | + viableParamArg(call, p, arg) and + getter(p, f, kind) + ) + } + + /** + * Holds if data can flow from `node1` to `node2` via a direct read of `f` or + * via a getter. + */ + cached + predicate read(Node node1, Content f, Node node2) { + readStep(node1, f, node2) and storeStep(_, f, _) + or + exists(DataFlowCall call, ReturnKind kind | + read0(call, kind, node1, f) and + node2 = getAnOutNode(call, kind) and + compatibleTypes(node1.getTypeBound(), f.getContainerType()) and + compatibleTypes(node2.getTypeBound(), f.getType()) + ) + } + + private predicate getter(ParameterNode p, Content f, ReturnKind kind) { + exists(Node n1, Node n2 | + parameterValueFlowNoCtx(p, n1) and + read(n1, f, n2) and + localValueStep*(n2, getAReturnNodeOfKind(kind)) + ) + } + + cached + predicate localStoreReadStep(Node node1, Node node2) { + exists(Node mid1, Node mid2, Content f | + store(node1, f, mid1) and + localValueStep*(mid1, mid2) and + read(mid2, f, node2) and + compatibleTypes(node1.getTypeBound(), node2.getTypeBound()) + ) + } + + cached + module FlowThrough_v2 { + private predicate step(Node node1, Node node2) { + simpleLocalFlowStep(node1, node2) or + localStoreReadStep(node1, node2) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, not taking call contexts into account. + */ + private predicate parameterValueFlowCand(ParameterNode p, Node node) { + p = node + or + exists(Node mid | + parameterValueFlowCand(p, mid) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlowCand(p, arg) and + argumentValueFlowsThroughCand(arg, node) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, not taking call contexts + * into account. + */ + private predicate parameterValueFlowsThroughCand(ParameterNode p, ReturnKind kind) { + parameterValueFlowCand(p, getAReturnNodeOfKind(kind)) + } + + pragma[nomagic] + private predicate argumentValueFlowsThroughCand0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind + ) { + exists(ParameterNode param | viableParamArg(call, param, arg) | + parameterValueFlowsThroughCand(param, kind) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + */ + private predicate argumentValueFlowsThroughCand(ArgumentNode arg, OutNode out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + + /** + * Holds if `arg` is the `i`th argument of `call` inside the callable + * `enclosing`, and `arg` may flow through `call`. + */ + pragma[noinline] + private predicate argumentOf( + DataFlowCall call, int i, ArgumentNode arg, DataFlowCallable enclosing + ) { + arg.argumentOf(call, i) and + argumentValueFlowsThroughCand(arg, _) and + enclosing = arg.getEnclosingCallable() + } + + pragma[noinline] + private ParameterNode getAParameter(DataFlowCallable c) { result.getEnclosingCallable() = c } + + pragma[noinline] + private predicate viableParamArg0( + int i, ArgumentNode arg, CallContext outercc, DataFlowCall call + ) { + exists(DataFlowCallable c | argumentOf(call, i, arg, c) | + outercc = TAnyCallContext() + or + outercc = TSomeCall(getAParameter(c), _) + or + exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) | + reducedViableImplInCallContext(_, c, other) + ) + ) + } + + pragma[noinline] + private predicate viableParamArg1( + ParameterNode p, DataFlowCallable callable, int i, ArgumentNode arg, CallContext outercc, + DataFlowCall call + ) { + viableParamArg0(i, arg, outercc, call) and + callable = resolveCall(call, outercc) and + p.isParameterOf(callable, any(int j | j <= i and j >= i)) + } + + /** + * Holds if `arg` is a possible argument to `p`, in the call `call`, and + * `arg` may flow through `call`. The possible contexts before and after + * entering the callable are `outercc` and `innercc`, respectively. + */ + private predicate viableParamArg( + DataFlowCall call, ParameterNode p, ArgumentNode arg, CallContext outercc, + CallContextCall innercc + ) { + exists(int i, DataFlowCallable callable | + viableParamArg1(p, callable, i, arg, outercc, call) + | + if reducedViableImplInCallContext(_, callable, call) + then innercc = TSpecificCall(call, i, true) + else innercc = TSomeCall(p, true) + ) + } + + private CallContextCall getAValidCallContextForParameter(ParameterNode p) { + result = TSomeCall(p, _) + or + exists(DataFlowCall call, int i, DataFlowCallable callable | + result = TSpecificCall(call, i, _) and + p.isParameterOf(callable, i) and + reducedViableImplInCallContext(_, callable, call) + ) + } + + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, in call context `cc`. + */ + private predicate parameterValueFlow(ParameterNode p, Node node, CallContextCall cc) { + p = node and + parameterValueFlowsThroughCand(p, _) and + cc = getAValidCallContextForParameter(p) + or + exists(Node mid | + parameterValueFlow(p, mid, cc) and + step(mid, node) and + compatibleTypes(p.getType(), node.getType()) + ) + or + // flow through a callable + exists(Node arg | + parameterValueFlow(p, arg, cc) and + argumentValueFlowsThrough(arg, node, cc) and + compatibleTypes(p.getType(), node.getType()) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, in call context `cc`. + */ + cached + predicate parameterValueFlowsThrough(ParameterNode p, ReturnKind kind, CallContextCall cc) { + parameterValueFlow(p, getAReturnNodeOfKind(kind), cc) + } + + pragma[nomagic] + private predicate argumentValueFlowsThrough0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind, CallContext cc + ) { + exists(ParameterNode param, CallContext innercc | + viableParamArg(call, param, arg, cc, innercc) and + parameterValueFlowsThrough(param, kind, innercc) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * in call context cc. + */ + cached + predicate argumentValueFlowsThrough(ArgumentNode arg, OutNode out, CallContext cc) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, cc) + | + out = getAnOutNode(call, kind) and + compatibleTypes(arg.getType(), out.getType()) + ) + } + } + + /** + * Holds if `call` passes an implicit or explicit instance argument, i.e., an + * expression that reaches a `this` parameter. + */ + private predicate callHasInstanceArgument(DataFlowCall call) { + exists(ArgumentNode arg | arg.argumentOf(call, -1)) + } + + cached + newtype TCallContext = + TAnyCallContext() or + TSpecificCall(DataFlowCall call, int i, boolean emptyAp) { + reducedViableImplInCallContext(_, _, call) and + (emptyAp = true or emptyAp = false) and + ( + exists(call.getArgument(i)) + or + i = -1 and callHasInstanceArgument(call) + ) + } or + TSomeCall(ParameterNode p, boolean emptyAp) { emptyAp = true or emptyAp = false } or + TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) } + + cached + newtype TReturnPosition = + TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) } + } + + pragma[noinline] + private predicate returnPosition(ReturnNode ret, DataFlowCallable c, ReturnKind kind) { + c = returnNodeGetEnclosingCallable(ret) and + kind = ret.getKind() + } + + /** + * A call context to restrict the targets of virtual dispatch and match the + * call sites of flow into a method with flow out of a method. + * + * There are four cases: + * - `TAnyCallContext()` : No restrictions on method flow. + * - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th + * parameter at the given `call`. This call improves the set of viable + * dispatch targets for at least one method call in the current callable. + * - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The + * originating call does not improve the set of dispatch targets for any + * method call in the current callable and was therefore not recorded. + * - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and + * this dispatch target of `call` implies a reduced set of dispatch origins + * to which data may flow if it should reach a `return` statement. + */ + abstract class CallContext extends TCallContext { + abstract string toString(); + } + + class CallContextAny extends CallContext, TAnyCallContext { + override string toString() { result = "CcAny" } + } + + abstract class CallContextCall extends CallContext { } + + class CallContextSpecificCall extends CallContextCall, TSpecificCall { + override string toString() { + exists(DataFlowCall call, int i | this = TSpecificCall(call, i, _) | + result = "CcCall(" + call + ", " + i + ")" + ) + } + } + + class CallContextSomeCall extends CallContextCall, TSomeCall { + override string toString() { result = "CcSomeCall" } + } + + class CallContextReturn extends CallContext, TReturn { + override string toString() { + exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") + } + } + + /** A callable tagged with a relevant return kind. */ + class ReturnPosition extends TReturnPosition0 { + private DataFlowCallable c; + private ReturnKind kind; + + ReturnPosition() { this = TReturnPosition0(c, kind) } + + /** Gets the callable. */ + DataFlowCallable getCallable() { result = c } + + /** Gets the return kind. */ + ReturnKind getKind() { result = kind } + + /** Gets a textual representation of this return position. */ + string toString() { result = "[" + kind + "] " + c } + } + + pragma[noinline] + DataFlowCallable returnNodeGetEnclosingCallable(ReturnNode ret) { + result = ret.getEnclosingCallable() + } + + pragma[noinline] + ReturnPosition getReturnPosition(ReturnNode ret) { + exists(DataFlowCallable c, ReturnKind k | returnPosition(ret, c, k) | + result = TReturnPosition0(c, k) ) } -} -class CallContextSomeCall extends CallContextCall, TSomeCall { - override string toString() { result = "CcSomeCall" } -} + bindingset[cc, callable] + predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { + cc instanceof CallContextAny and callable = viableCallable(call) + or + exists(DataFlowCallable c0, DataFlowCall call0 | + call0.getEnclosingCallable() = callable and + cc = TReturn(c0, call0) and + c0 = prunedViableImplInCallContextReverse(call0, call) + ) + } -class CallContextReturn extends CallContext, TReturn { - override string toString() { - exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") + bindingset[call, cc] + DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { + exists(DataFlowCall ctx | cc = TSpecificCall(ctx, _, _) | + if reducedViableImplInCallContext(call, _, ctx) + then result = prunedViableImplInCallContext(call, ctx) + else result = viableCallable(call) + ) + or + result = viableCallable(call) and cc instanceof CallContextSomeCall + or + result = viableCallable(call) and cc instanceof CallContextAny + or + result = viableCallable(call) and cc instanceof CallContextReturn } } - -/** A callable tagged with a relevant return kind. */ -class ReturnPosition extends TReturnPosition0 { - private DataFlowCallable c; - private ReturnKind kind; - - ReturnPosition() { this = TReturnPosition0(c, kind) } - - /** Gets the callable. */ - DataFlowCallable getCallable() { result = c } - - /** Gets the return kind. */ - ReturnKind getKind() { result = kind } - - /** Gets a textual representation of this return position. */ - string toString() { result = "[" + kind + "] " + c } -} - -pragma[noinline] -DataFlowCallable returnNodeGetEnclosingCallable(ReturnNode ret) { - result = ret.getEnclosingCallable() -} - -pragma[noinline] -ReturnPosition getReturnPosition(ReturnNode ret) { - exists(DataFlowCallable c, ReturnKind k | returnPosition(ret, c, k) | - result = TReturnPosition0(c, k) - ) -} - -bindingset[cc, callable] -predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { - cc instanceof CallContextAny and callable = viableCallable(call) - or - exists(DataFlowCallable c0, DataFlowCall call0 | - call0.getEnclosingCallable() = callable and - cc = TReturn(c0, call0) and - c0 = prunedViableImplInCallContextReverse(call0, call) - ) -} - -bindingset[call, cc] -DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { - exists(DataFlowCall ctx | cc = TSpecificCall(ctx, _, _) | - if reducedViableImplInCallContext(call, _, ctx) - then result = prunedViableImplInCallContext(call, ctx) - else result = viableCallable(call) - ) - or - result = viableCallable(call) and cc instanceof CallContextSomeCall - or - result = viableCallable(call) and cc instanceof CallContextAny - or - result = viableCallable(call) and cc instanceof CallContextReturn -} diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 29036c8c51d..e0ca469bf78 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 29036c8c51d..e0ca469bf78 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 29036c8c51d..e0ca469bf78 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 29036c8c51d..e0ca469bf78 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -1075,6 +1075,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, flowCandFwd(mid, fromArg, _, config) and store(mid, f, node) and nodeCand(node, unbind(config)) and + readStoreCand(f, unbind(config)) and apf.headUsesContent(f) ) or @@ -1175,12 +1176,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co exists(Content f, AccessPathFront apf0 | flowCandStore(node, f, toReturn, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, unbind(config)) + consCand(f, apf, config) ) or exists(Content f, AccessPathFront apf0 | flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, unbind(config)) and + consCandFwd(f, apf0, config) and apf.headUsesContent(f) ) } @@ -1221,8 +1222,8 @@ private newtype TAccessPath = TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first - * element of the list and its length are tracked. If data flows from a source to + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the * tracked object. The final type indicates the type of the tracked object. From a7a5eaa23f7c87cc7327870968a4053916293a79 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Thu, 26 Sep 2019 16:43:27 +0100 Subject: [PATCH 0267/1227] Address PR comments --- .../csharp/ir/rangeanalysis/RangeAnalysis.qll | 18 ++-- .../csharp/ir/rangeanalysis/RangeUtils.qll | 12 ++- .../ir/offbyone/OffByOneRA.expected | 12 ++- .../library-tests/ir/offbyone/OffByOneRA.ql | 26 ++---- .../ql/test/library-tests/ir/offbyone/test.cs | 33 +++---- .../ir/rangeanalysis/RangeAnalysis.expected | 36 ++++---- .../library-tests/ir/rangeanalysis/test.cs | 85 ++++++++++--------- 7 files changed, 116 insertions(+), 106 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll index 35cb6900c1c..e3403728633 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll @@ -233,19 +233,25 @@ private class SafeCastInstruction extends ConvertInstruction { * Holds if `typ` is a small integral type with the given lower and upper bounds. */ private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { - typ instanceof SignedIntegralType and typ.getSize() = 1 and lowerbound = -128 and upperbound = 127 + typ instanceof SignedIntegralType and + typ.getSize() = 1 and + lowerbound = typ.minValue() and + upperbound = typ.maxValue() or - typ instanceof UnsignedIntegralType and typ.getSize() = 1 and lowerbound = 0 and upperbound = 255 + typ instanceof UnsignedIntegralType and + typ.getSize() = 1 and + lowerbound = typ.minValue() and + upperbound = typ.maxValue() or typ instanceof SignedIntegralType and typ.getSize() = 2 and - lowerbound = -32768 and - upperbound = 32767 + lowerbound = typ.minValue() and + upperbound = typ.maxValue() or typ instanceof UnsignedIntegralType and typ.getSize() = 2 and - lowerbound = 0 and - upperbound = 65535 + lowerbound = typ.minValue() and + upperbound = typ.maxValue() } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll index b2f912dabfd..77a87b0b458 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll @@ -40,10 +40,20 @@ IntValue getConstantValue(Instruction instr) { ) } +/** + * Gets the dimension of the array (either the declared size, or the + * size of the initializer); if no size is declared and no initializer used, + * the predicate does not hold. + */ IntValue getArrayDim(Variable arr) { exists(ArrayCreation ac | arr.getInitializer() = ac and - result = ac.getInitializer().getNumberOfElements() + if exists(ac.getLengthArgument(0)) + then result = ac.getLengthArgument(0).getValue().toInt() + else + if exists(ac.getInitializer()) + then result = ac.getInitializer().getNumberOfElements() + else none() ) } diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected index 9b8d568e64d..0c16c9ff134 100644 --- a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected +++ b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected @@ -1,7 +1,5 @@ -| test.cs:10:17:10:21 | test1 | test.cs:17:41:17:51 | access to array element | This array access is ok, the index is at most the lenth of the array + -1 | -| test.cs:21:17:21:21 | test2 | test.cs:33:41:33:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | -| test.cs:37:17:37:21 | test3 | test.cs:50:41:50:51 | access to array element | This array access is ok, the index is at most the lenth of the array + -1 | -| test.cs:54:17:54:21 | test4 | test.cs:64:41:64:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | -| test.cs:68:17:68:21 | test5 | test.cs:74:22:74:27 | access to indexer | This array access might be out of bounds, as the index might be equal to the array length | -| test.cs:78:17:78:21 | test6 | test.cs:87:41:87:55 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | -| test.cs:91:17:91:21 | test7 | test.cs:101:41:101:50 | access to array element | This array access might be out of bounds, as the index might be equal to the array length + 1 | +| test.cs:21:17:21:21 | Test2 | test.cs:34:41:34:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | +| test.cs:56:17:56:21 | Test4 | test.cs:67:41:67:51 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | +| test.cs:71:17:71:21 | Test5 | test.cs:77:22:77:27 | access to indexer | This array access might be out of bounds, as the index might be equal to the array length | +| test.cs:81:17:81:21 | Test6 | test.cs:90:41:90:55 | access to array element | This array access might be out of bounds, as the index might be equal to the array length | +| test.cs:94:17:94:21 | Test7 | test.cs:104:41:104:50 | access to array element | This array access might be out of bounds, as the index might be equal to the array length + 1 | diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql index 7271996557a..2e74079769f 100644 --- a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql +++ b/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql @@ -1,6 +1,7 @@ import csharp import semmle.code.csharp.ir.IR import semmle.code.csharp.ir.rangeanalysis.RangeAnalysis +import semmle.code.csharp.ir.rangeanalysis.RangeUtils /** * Holds if the index expression of `aa` is less than or equal to the array length plus `k`. @@ -27,19 +28,8 @@ predicate boundedArrayAccess(ElementAccess aa, int k) { .getTarget() ) or - exists(ArrayCreation ac | - ac.getParent().(LocalVariableDeclExpr).getVariable() = aa - .getQualifier() - .(VariableAccess) - .getTarget() and - b instanceof ZeroBound and - if exists(ac.getLengthArgument(0)) - then k = delta - ac.getLengthArgument(0).getValue().toInt() - else - if exists(ac.getInitializer()) - then k = delta - ac.getInitializer().getNumberOfElements() - else none() - ) + b instanceof ZeroBound and + k = delta - getArrayDim(aa.getQualifier().(VariableAccess).getTarget()) ) } @@ -54,12 +44,8 @@ predicate bestArrayAccessBound(ElementAccess aa, int k) { from ElementAccess aa, int k, string msg, string add where bestArrayAccessBound(aa, k) and + k >= 0 and (if k = 0 then add = "" else add = " + " + k) and - ( - if k >= 0 - then - msg = "This array access might be out of bounds, as the index might be equal to the array length" - + add - else msg = "This array access is ok, the index is at most the lenth of the array " + add - ) + msg = "This array access might be out of bounds, as the index might be equal to the array length" + + add select aa.getEnclosingCallable(), aa, msg diff --git a/csharp/ql/test/library-tests/ir/offbyone/test.cs b/csharp/ql/test/library-tests/ir/offbyone/test.cs index 7315a84820f..74bf155420f 100644 --- a/csharp/ql/test/library-tests/ir/offbyone/test.cs +++ b/csharp/ql/test/library-tests/ir/offbyone/test.cs @@ -3,22 +3,23 @@ class ContainerLengthOffByOne public int[] arr; public string str; - public static void fun(int elem) + public static void Fun(int elem) { } - public void test1() + public void Test1() { int len1 = this.arr.Length; int len2 = len1 + 1; // OK for(int i = 0; i < len2 - 1; i++) { - ContainerLengthOffByOne.fun(this.arr[i]); + ContainerLengthOffByOne.Fun(this.arr[i]); } } - public void test2() { + public void Test2() + { int len1 = this.arr.Length; int len2; @@ -30,11 +31,12 @@ class ContainerLengthOffByOne // exceeds the size of the array. for(int i = 0; i < len2; i++) { - ContainerLengthOffByOne.fun(this.arr[i]); + ContainerLengthOffByOne.Fun(this.arr[i]); } } - public void test3() { + public void Test3() + { int len1 = this.arr.Length; int len2 = len1 - 1; @@ -47,11 +49,12 @@ class ContainerLengthOffByOne // we don't get an off by one error. for(int i = 0; i < len3; i++) { - ContainerLengthOffByOne.fun(this.arr[i]); + ContainerLengthOffByOne.Fun(this.arr[i]); } } - public void test4() { + public void Test4() + { int len1 = this.arr.Length; int len2 = len1 + 1; @@ -61,11 +64,11 @@ class ContainerLengthOffByOne // Not OK, len5 is off by one. for(int i = 0; i < len5; i++) { - ContainerLengthOffByOne.fun(this.arr[i]); + ContainerLengthOffByOne.Fun(this.arr[i]); } } - public void test5() + public void Test5() { int len = this.str.Length; // Not OK; test for indexers @@ -75,20 +78,20 @@ class ContainerLengthOffByOne } } - public void test6() + public void Test6() { int len = this.arr.Length - 2; int len1 = len + 3; int len2 = len1 - 1; - // Not OK, of by one + // Not OK, off by one // The test shows that more complex expressions are treated correctly for (int i = 0; i < len2; i++) { - ContainerLengthOffByOne.fun(this.arr[i + 1]); + ContainerLengthOffByOne.Fun(this.arr[i + 1]); } } - public void test7() + public void Test7() { int[] arrInit = { 1, 2, 3 }; int len = (arrInit.Length * 2 + 2) / 2 * 2; @@ -98,7 +101,7 @@ class ContainerLengthOffByOne // are used in bounds for (int i = 0; i < len1; i++) { - ContainerLengthOffByOne.fun(arrInit[i]); + ContainerLengthOffByOne.Fun(arrInit[i]); } } } diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected index 36ffe7efbba..329bbd3bff0 100644 --- a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected +++ b/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected @@ -1,18 +1,18 @@ -| test.cs:19:12:19:12 | Store: access to parameter x | test.cs:15:24:15:24 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:19:12:19:12 | Store: access to parameter x | test.cs:15:31:15:31 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cs:16:9:16:13 | test.cs:16:9:16:13 | -| test.cs:19:12:19:12 | Store: access to parameter x | test.cs:15:31:15:31 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:29:12:29:12 | Store: access to parameter x | test.cs:23:24:23:24 | InitializeParameter: x | -2 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:29:12:29:12 | Store: access to parameter x | test.cs:23:31:23:31 | InitializeParameter: y | -2 | false | CompareLT: ... < ... | test.cs:24:9:24:13 | test.cs:24:9:24:13 | -| test.cs:36:12:36:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:36:12:36:12 | Load: access to local variable i | test.cs:33:25:33:25 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cs:35:20:35:24 | test.cs:35:20:35:24 | -| test.cs:39:12:39:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 1 | false | CompareGT: ... > ... | test.cs:38:20:38:24 | test.cs:38:20:38:24 | -| test.cs:39:12:39:12 | Load: access to local variable i | test.cs:33:25:33:25 | InitializeParameter: x | 0 | true | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:39:12:39:12 | Load: access to local variable i | test.cs:35:20:35:20 | Phi: access to local variable i | 0 | true | CompareLT: ... < ... | test.cs:35:20:35:24 | test.cs:35:20:35:24 | -| test.cs:42:12:42:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:42:12:42:12 | Load: access to local variable i | test.cs:33:25:33:25 | InitializeParameter: x | 1 | true | CompareLT: ... < ... | test.cs:41:20:41:28 | test.cs:41:20:41:28 | -| test.cs:42:12:42:12 | Load: access to local variable i | test.cs:35:20:35:20 | Phi: access to local variable i | 1 | true | CompareLT: ... < ... | test.cs:41:20:41:28 | test.cs:41:20:41:28 | -| test.cs:42:12:42:12 | Load: access to local variable i | test.cs:38:20:38:20 | Phi: access to local variable i | 0 | false | CompareGT: ... > ... | test.cs:38:20:38:24 | test.cs:38:20:38:24 | -| test.cs:49:13:49:17 | Load: access to parameter begin | test.cs:47:33:47:37 | InitializeParameter: begin | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | -| test.cs:58:14:58:14 | Load: access to parameter x | test.cs:55:32:55:32 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cs:57:11:57:15 | test.cs:57:11:57:15 | -| test.cs:58:14:58:14 | Load: access to parameter x | test.cs:55:39:55:39 | InitializeParameter: z | -2 | true | CompareLT: ... < ... | test.cs:57:11:57:15 | test.cs:57:11:57:15 | -| test.cs:63:14:63:14 | Load: access to parameter x | test.cs:55:32:55:32 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cs:61:9:61:13 | test.cs:61:9:61:13 | +| test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:24:16:24 | InitializeParameter: x | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:31:16:31 | InitializeParameter: y | 0 | false | CompareLT: ... < ... | test.cs:18:9:18:13 | test.cs:18:9:18:13 | +| test.cs:22:12:22:12 | Store: access to parameter x | test.cs:16:31:16:31 | InitializeParameter: y | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:36:12:36:12 | Store: access to parameter x | test.cs:26:24:26:24 | InitializeParameter: x | -2 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:36:12:36:12 | Store: access to parameter x | test.cs:26:31:26:31 | InitializeParameter: y | -2 | false | CompareLT: ... < ... | test.cs:28:9:28:13 | test.cs:28:9:28:13 | +| test.cs:45:12:45:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:45:12:45:12 | Load: access to local variable i | test.cs:40:25:40:25 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cs:43:20:43:24 | test.cs:43:20:43:24 | +| test.cs:49:12:49:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 1 | false | CompareGT: ... > ... | test.cs:47:20:47:24 | test.cs:47:20:47:24 | +| test.cs:49:12:49:12 | Load: access to local variable i | test.cs:40:25:40:25 | InitializeParameter: x | 0 | true | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:49:12:49:12 | Load: access to local variable i | test.cs:43:20:43:20 | Phi: access to local variable i | 0 | true | CompareLT: ... < ... | test.cs:43:20:43:24 | test.cs:43:20:43:24 | +| test.cs:53:12:53:12 | Load: access to local variable i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:53:12:53:12 | Load: access to local variable i | test.cs:40:25:40:25 | InitializeParameter: x | 1 | true | CompareLT: ... < ... | test.cs:51:20:51:28 | test.cs:51:20:51:28 | +| test.cs:53:12:53:12 | Load: access to local variable i | test.cs:43:20:43:20 | Phi: access to local variable i | 1 | true | CompareLT: ... < ... | test.cs:51:20:51:28 | test.cs:51:20:51:28 | +| test.cs:53:12:53:12 | Load: access to local variable i | test.cs:47:20:47:20 | Phi: access to local variable i | 0 | false | CompareGT: ... > ... | test.cs:47:20:47:24 | test.cs:47:20:47:24 | +| test.cs:62:13:62:17 | Load: access to parameter begin | test.cs:58:33:58:37 | InitializeParameter: begin | 0 | false | NoReason | file://:0:0:0:0 | :0:0:0:0 | +| test.cs:74:14:74:14 | Load: access to parameter x | test.cs:68:32:68:32 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cs:72:11:72:15 | test.cs:72:11:72:15 | +| test.cs:74:14:74:14 | Load: access to parameter x | test.cs:68:39:68:39 | InitializeParameter: z | -2 | true | CompareLT: ... < ... | test.cs:72:11:72:15 | test.cs:72:11:72:15 | +| test.cs:81:14:81:14 | Load: access to parameter x | test.cs:68:32:68:32 | InitializeParameter: y | -1 | true | CompareLT: ... < ... | test.cs:77:9:77:13 | test.cs:77:9:77:13 | diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/test.cs b/csharp/ql/test/library-tests/ir/rangeanalysis/test.cs index 221312b1449..018d7b76a59 100644 --- a/csharp/ql/test/library-tests/ir/rangeanalysis/test.cs +++ b/csharp/ql/test/library-tests/ir/rangeanalysis/test.cs @@ -1,78 +1,85 @@ class RangeAnalysis { - static void sink(int val) { - + static void Sink(int val) + { } - static unsafe void sinkp(int* p) { - + static unsafe void Sinkp(int* p) + { } - static int source() { + static int Source() + { return 0; } // Guards, inference, critical edges - static int test1(int x, int y) { - if (x < y) { + static int Test1(int x, int y) + { + if (x < y) + { x = y; } return x; } // Bounds mergers at phi nodes - static int test2(int x, int y) { - if (x < y) { + static int Test2(int x, int y) + { + if (x < y) + { x = y; - } else { - x = x-2; + } + else + { + x = x - 2; } return x; } // for loops - static void test3(int x) { + static void Test3(int x) + { int y = x; - for(int i = 0; i < x; i++) { - sink(i); + for(int i = 0; i < x; i++) + { + Sink(i); } - for(int i = y; i > 0; i--) { - sink(i); + for(int i = y; i > 0; i--) + { + Sink(i); } - for(int i = 0; i < y + 2; i++) { - sink(i); + for(int i = 0; i < y + 2; i++) + { + Sink(i); } } // pointer bounds - unsafe static void test4(int *begin, int *end) { - while (begin < end) { - sinkp(begin); + unsafe static void Test4(int *begin, int *end) + { + while (begin < end) + { + Sinkp(begin); begin++; } } // bound propagation through conditionals - static void test5(int x, int y, int z) { - if (y < z) { - if (x < y) { - sink(x); + static void Test5(int x, int y, int z) + { + if (y < z) + { + if (x < y) + { + Sink(x); } } - if (x < y) { - if (y < z) { - sink(x); // x < z is not inferred here + if (x < y) + { + if (y < z) + { + Sink(x); // x < z is not inferred here } } } - - unsafe static void addone(int[] arr) - { - int length = arr.Length; - fixed (int* b = arr) - { - int *p = b; - for(int i = 0; i <= length; i++) - *p++ += 1; - } - } } From 28aa7dcae2ef7946d2b3662c7560228278322629 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 26 Sep 2019 13:56:43 -0700 Subject: [PATCH 0268/1227] C++: Fix PR feedback --- change-notes/1.23/analysis-cpp.md | 4 + .../interfaces/FunctionInputsAndOutputs.qll | 267 +++++++++++------- 2 files changed, 165 insertions(+), 106 deletions(-) diff --git a/change-notes/1.23/analysis-cpp.md b/change-notes/1.23/analysis-cpp.md index ce317236f93..61e823eb7f3 100644 --- a/change-notes/1.23/analysis-cpp.md +++ b/change-notes/1.23/analysis-cpp.md @@ -35,3 +35,7 @@ The following changes in version 1.23 affect C/C++ analysis in all applications. * There is now a `DataFlow::localExprFlow` predicate and a `TaintTracking::localExprTaint` predicate to make it easy to use the most common case of local data flow and taint: from one `Expr` to another. +* The member predicates of the `FunctionInput` and `FunctionOutput` classes have been renamed for + clarity (e.g. `isOutReturnPointer()` to `isReturnValueDeref()`). The existing member predicates + have been deprecated, and will be removed in a future release. Code that uses the old member + predicates should be updated to use the corresponding new member predicate. 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 206812b8d94..cf934d0811c 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll @@ -29,28 +29,87 @@ private newtype TFunctionInput = class FunctionInput extends TFunctionInput { abstract string toString(); + /** + * Holds if this is the input value of the parameter with index `index`. + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * `isParameter(0)` holds for the `FunctionInput` that represents the value of `n` (with type + * `int`) on entry to the function. + * `isParameter(1)` holds for the `FunctionInput` that represents the value of `p` (with type + * `char*`) on entry to the function. + * `isParameter(2)` holds for the `FunctionInput` that represents the "value" of the reference `r` + * (with type `float&`) on entry to the function, _not_ the value of the referred-to `float`. + */ predicate isParameter(ParameterIndex index) { none() } + /** + * Holds if this is the input value of the parameter with index `index`. + * DEPRECATED: Use `isParameter(index)` instead. + */ + deprecated final predicate isInParameter(ParameterIndex index) { isParameter(index) } + + /** + * Holds if this is the input value pointed to by a pointer parameter to a function, or the input + * value referred to by a reference parameter to a function, where the parameter has index + * `index`. + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * `isParameterDeref(1)` holds for the `FunctionInput` that represents the value of `*p` (with + * type `char`) on entry to the function. + * `isParameterDeref(2)` holds for the `FunctionInput` that represents the value of `r` (with type + * `float`) on entry to the function. + * There is no `FunctionInput` for which `isParameterDeref(0)` holds, because `n` is neither a + * pointer nor a reference. + */ predicate isParameterDeref(ParameterIndex index) { none() } + /** + * Holds if this is the input value pointed to by a pointer parameter to a function, or the input + * value referred to by a reference parameter to a function, where the parameter has index + * `index`. + * DEPRECATED: Use `isParameterDeref(index)` instead. + */ + deprecated final predicate isInParameterPointer(ParameterIndex index) { isParameterDeref(index) } + + /** + * Holds if this is the input value pointed to by the `this` pointer of an instance member + * function. + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r) const; + * }; + * ``` + * `isQualifierObject()` holds for the `FunctionInput` that represents the value of `*this` (with + * type `C const`) on entry to the function. + */ predicate isQualifierObject() { none() } + /** + * Holds if this is the input value pointed to by the `this` pointer of an instance member + * function. + * DEPRECATED: Use `isQualifierObject()` instead. + */ + deprecated final predicate isInQualifier() { isQualifierObject() } + + /** + * Holds if this is the input value of the `this` pointer of an instance member function. + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r) const; + * }; + * ``` + * `isQualifierAddress()` holds for the `FunctionInput` that represents the value of `this` (with + * type `C const *`) on entry to the function. + */ predicate isQualifierAddress() { none() } } -/** - * The input value of a parameter to a function. - * Example: - * ```cpp - * void func(int n, char* p, float& r); - * ``` - * The `InParameter` with `getIndex() = 0` represents the value of `n` (with type `int`) on entry to - * the function. - * The `InParameter` with `getIndex() = 1` represents the value of `p` (with type `char*`) on entry - * to the function. - * The `InParameter` with `getIndex() = 2` represents the "value" of the reference `r` (with type - * `float&`) on entry to the function, _not_ the value of the referred-to `float`. - */ class InParameter extends FunctionInput, TInParameter { ParameterIndex index; @@ -64,20 +123,6 @@ class InParameter extends FunctionInput, TInParameter { override predicate isParameter(ParameterIndex i) { i = index } } -/** - * The input value pointed to by a pointer parameter to a function, or the input value referred to - * by a reference parameter to a function. - * Example: - * ```cpp - * void func(int n, char* p, float& r); - * ``` - * The `InParameterDeref` with `getIndex() = 1` represents the value of `*p` (with type `char`) on - * entry to the function. - * The `InParameterDeref` with `getIndex() = 2` represents the value of `r` (with type `float`) on - * entry to the function. - * There is no `InParameterDeref` with `getIndex() = 0`, because `n` is neither a pointer nor a - * reference. - */ class InParameterDeref extends FunctionInput, TInParameterDeref { ParameterIndex index; @@ -91,34 +136,12 @@ class InParameterDeref extends FunctionInput, TInParameterDeref { override predicate isParameterDeref(ParameterIndex i) { i = index } } -/** - * The input value pointed to by the `this` pointer of an instance member function. - * Example: - * ```cpp - * struct C { - * void mfunc(int n, char* p, float& r) const; - * }; - * ``` - * The `InQualifierObject` represents the value of `*this` (with type `C const`) on entry to the - * function. - */ class InQualifierObject extends FunctionInput, TInQualifierObject { override string toString() { result = "InQualifierObject" } override predicate isQualifierObject() { any() } } -/** - * The input value of the `this` pointer of an instance member function. - * Example: - * ```cpp - * struct C { - * void mfunc(int n, char* p, float& r) const; - * }; - * ``` - * The `InQualifierAddress` represents the value of `this` (with type `C const *`) on entry to the - * function. - */ class InQualifierAddress extends FunctionInput, TInQualifierAddress { override string toString() { result = "InQualifierAddress" } @@ -142,29 +165,104 @@ private newtype TFunctionOutput = class FunctionOutput extends TFunctionOutput { abstract string toString(); + /** + * Holds if this is the output value pointed to by a pointer parameter to a function, or the + * output value referred to by a reference parameter to a function, where the parameter has + * index `index`. + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * `isParameterDeref(1)` holds for the `FunctionOutput` that represents the value of `*p` (with + * type `char`) on return from the function. + * `isParameterDeref(2)` holds for the `FunctionOutput` that represents the value of `r` (with + * type `float`) on return from the function. + * There is no `FunctionOutput` for which `isParameterDeref(0)` holds, because `n` is neither a + * pointer nor a reference. + */ predicate isParameterDeref(ParameterIndex i) { none() } + /** + * Holds if this is the output value pointed to by a pointer parameter to a function, or the + * output value referred to by a reference parameter to a function, where the parameter has + * index `index`. + * DEPRECATED: Use `isParameterDeref(index)` instead. + */ + deprecated final predicate isOutParameterPointer(ParameterIndex index) { isParameterDeref(index) } + + /** + * Holds if this is the output value pointed to by the `this` pointer of an instance member + * function. + * ``` + * struct C { + * void mfunc(int n, char* p, float& r); + * }; + * ``` + * `isQualifierObject()` holds for the `FunctionOutput` that represents the value of `*this` (with + * type `C`) on return from the function. + */ predicate isQualifierObject() { none() } + /** + * Holds if this is the output value pointed to by the `this` pointer of an instance member + * function. + * DEPRECATED: Use `isQualifierObject()` instead. + */ + deprecated final predicate isOutQualifier() { isQualifierObject() } + + /** + * Holds if this is the value returned by a function. + * Example: + * ``` + * int getInt(); + * char* getPointer(); + * float& getReference(); + * ``` + * `isReturnValue()` holds for the `FunctionOutput` that represents the value returned by + * `getInt()` (with type `int`). + * `isReturnValue()` holds for the `FunctionOutput` that represents the value returned by + * `getPointer()` (with type `char*`). + * `isReturnValue()` holds for the `FunctionOutput` that represents the "value" of the reference + * returned by `getReference()` (with type `float&`), _not_ the value of the referred-to + * `float`. + */ predicate isReturnValue() { none() } + /** + * Holds if this is the value returned by a function. + * DEPRECATED: Use `isReturnValue()` instead. + */ + deprecated final predicate isOutReturnValue() { isReturnValue() } + + /** + * Holds if this is the output value pointed to by the return value of a function, if the function + * returns a pointer, or the output value referred to by the return value of a function, if the + * function returns a reference. + * Example: + * ``` + * char* getPointer(); + * float& getReference(); + * int getInt(); + * ``` + * `isReturnValueDeref()` holds for the `FunctionOutput` that represents the value of + * `*getPointer()` (with type `char`). + * `isReturnValueDeref()` holds for the `FunctionOutput` that represents the value of + * `getReference()` (with type `float`). + * There is no `FunctionOutput` of `getInt()` for which `isReturnValueDeref()` holds because the + * return type of `getInt()` is neither a pointer nor a reference. + */ predicate isReturnValueDeref() { none() } + + /* + * Holds if this is the output value pointed to by the return value of a function, if the function + * returns a pointer, or the output value referred to by the return value of a function, if the + * function returns a reference. + * DEPRECATED: Use `isReturnValueDeref()` instead. + */ + + deprecated final predicate isOutReturnPointer() { isReturnValueDeref() } } -/** - * The output value pointed to by a pointer parameter to a function, or the output value referred to - * by a reference parameter to a function. - * Example: - * ```cpp - * void func(int n, char* p, float& r); - * ``` - * The `OutParameterDeref` with `getIndex() = 1` represents the value of `*p` (with type `char`) on - * return from the function. - * The `OutParameterDeref` with `getIndex() = 2` represents the value of `r` (with type `float`) on - * return from the function. - * There is no `OutParameterDeref` with `getIndex() = 0`, because `n` is neither a pointer nor a - * reference. - */ class OutParameterDeref extends FunctionOutput, TOutParameterDeref { ParameterIndex index; @@ -177,61 +275,18 @@ class OutParameterDeref extends FunctionOutput, TOutParameterDeref { override predicate isParameterDeref(ParameterIndex i) { i = index } } -/** - * The output value pointed to by the `this` pointer of an instance member function. - * Example: - * ```cpp - * struct C { - * void mfunc(int n, char* p, float& r); - * }; - * ``` - * The `OutQualifierObject` represents the value of `*this` (with type `C`) on return from the - * function. - */ class OutQualifierObject extends FunctionOutput, TOutQualifierObject { override string toString() { result = "OutQualifier" } override predicate isQualifierObject() { any() } } -/** - * The value returned by a function. - * Example: - * ```cpp - * int getInt(); - * char* getPointer(); - * float& getReference(); - * ``` - * The `OutReturnValue` for `getInt()` represents the value returned by `getInt()` (with type - * `int`). - * The `OutReturnValue` for `getPointer()` represents the value returned by `getPointer()` (with - * type `char*`). - * The `OutReturnValue` for `getReference()` represents the "value" of the reference returned by - * `getReference()` (with type `float&`), _not_ the value of the referred-to `float`. - */ class OutReturnValue extends FunctionOutput, TOutReturnValue { override string toString() { result = "OutReturnValue" } override predicate isReturnValue() { any() } } -/** - * The output value pointed to by the return value of a function, if the function returns a pointer, - * or the output value referred to by the return value of a function, if the function returns a - * reference. - * Example: - * ```cpp - * char* getPointer(); - * float& getReference(); - * int getInt(); - * ``` - * The `OutReturnValueDeref` for `getPointer()` represents the value of `*getPointer()` (with type - * `char`). - * The `OutReturnValueDeref` for `getReference()` represents the value of `getReference()` (with - * type `float`). - * There is no `OutReturnValueDeref` for `getInt()`, because the return type of `getInt()` is - * neither a pointer nor a reference. - */ class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref { override string toString() { result = "OutReturnValueDeref" } From e30e163081ed570a85b1ee27acbc5d37045cf72a Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 26 Sep 2019 15:47:52 -0700 Subject: [PATCH 0269/1227] C#: Implement `IRType` This commit implements the language-neutral IR type system for C#. It mostly follows the same pattern as C++, modified to fit the C# type system. All object references, pointers, and lvalues are represented as `IRAddress` types. All structs and generic parameters are implemented as `IRBlobType`. Function addresses get a single `IRFunctionAddressType`. I had to fix a couple places in the original IR type system where I didn't realize I was still depending on language-specific types. As part of this, `CSharpType` and `CppType` now have a `hasUnspecifiedType()` predicate, which is equivalent to `hasType()`, except that it holds only for the unspecified version of the type. This predicate can go away once we remove the IR's references to the underlying `Type` objects. All C# IR tests pass without modification, but only because this commit continues to print the name of `IRUnknownType` as `null`, and `IRFunctionAddressType` as `glval`. These will be fixed separately in a subsequent commit in this PR. --- .../code/cpp/ir/implementation/IRType.qll | 4 +- .../aliased_ssa/Instruction.qll | 18 +- .../internal/InstructionImports.qll | 1 + .../cpp/ir/implementation/raw/Instruction.qll | 18 +- .../raw/internal/InstructionImports.qll | 1 + .../unaliased_ssa/Instruction.qll | 18 +- .../internal/InstructionImports.qll | 1 + .../semmle/code/cpp/ir/internal/CppType.qll | 19 +- .../ql/src/semmle/code/csharp/ir/PrintIR.ql | 2 +- .../code/csharp/ir/implementation/IRType.qll | 259 +++++++++++ .../internal/IRTypeInternal.qll | 1 + .../ir/implementation/raw/Instruction.qll | 18 +- .../raw/internal/IRConstruction.qll | 28 +- .../implementation/raw/internal/IRImports.qll | 1 + .../raw/internal/IRVariableImports.qll | 1 + .../raw/internal/InstructionImports.qll | 1 + .../raw/internal/OperandImports.qll | 1 + .../raw/internal/TranslatedCondition.qll | 5 +- .../raw/internal/TranslatedElement.qll | 20 +- .../raw/internal/TranslatedExpr.qll | 235 +++++----- .../raw/internal/TranslatedFunction.qll | 54 +-- .../raw/internal/TranslatedInitialization.qll | 24 +- .../raw/internal/TranslatedStmt.qll | 88 ++-- .../internal/common/TranslatedCallBase.qll | 20 +- .../common/TranslatedConditionBase.qll | 6 +- .../common/TranslatedDeclarationBase.qll | 9 +- .../raw/internal/desugar/Common.qll | 20 +- .../raw/internal/desugar/Foreach.qll | 19 +- .../raw/internal/desugar/Lock.qll | 25 +- ...TranslatedCompilerGeneratedDeclaration.qll | 8 +- .../code/csharp/ir/internal/CSharpType.qll | 424 ++++++++++++++++++ .../csharp/ir/internal/IRCSharpLanguage.qll | 30 +- .../code/csharp/ir/internal/IRUtilities.qll | 22 +- .../ir/ir/raw_ir_sanity.expected | 2 + 34 files changed, 1018 insertions(+), 385 deletions(-) create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll 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 19202f5d49c..053b018eaf5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -7,7 +7,9 @@ private import internal.IRTypeInternal newtype TIRType = TIRVoidType() or TIRUnknownType() or - TIRErrorType() or + TIRErrorType() { + Language::hasErrorType() + } or TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index f84871e227d..01e2d219652 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -5,6 +5,7 @@ import IRVariable import Operand private import internal.InstructionImports as Imports import Imports::EdgeKind +import Imports::IRType import Imports::MemoryAccessKind import Imports::Opcode private import Imports::OperandTag @@ -315,7 +316,7 @@ class Instruction extends Construction::TInstruction { } private string getResultPrefix() { - if getResultType() instanceof Language::VoidType + if getResultIRType() instanceof IRVoidType then result = "v" else if hasMemoryResult() @@ -440,6 +441,12 @@ class Instruction extends Construction::TInstruction { result = Construction::getInstructionResultType(this) } + /** + * Gets the type of the result produced by this instruction. If the instruction does not produce + * a result, its result type will be `IRVoidType`. + */ + final IRType getResultIRType() { result = getResultLanguageType().getIRType() } + /** * Gets the type of the result produced by this instruction. If the * instruction does not produce a result, its result type will be `VoidType`. @@ -448,13 +455,12 @@ class Instruction extends Construction::TInstruction { * thought of as "pointer to `getResultType()`". */ final Language::Type getResultType() { - exists(Language::LanguageType resultType, Language::Type langType | + exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasType(langType, _) or - not resultType.hasType(_, _) and result instanceof Language::UnknownType - ) and - result = langType.getUnspecifiedType() + resultType.hasUnspecifiedType(result, _) or + not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType + ) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/InstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/InstructionImports.qll index 0138af075dc..a75f70dbe2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/InstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/InstructionImports.qll @@ -1,4 +1,5 @@ import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.Opcode as Opcode import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index f84871e227d..01e2d219652 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -5,6 +5,7 @@ import IRVariable import Operand private import internal.InstructionImports as Imports import Imports::EdgeKind +import Imports::IRType import Imports::MemoryAccessKind import Imports::Opcode private import Imports::OperandTag @@ -315,7 +316,7 @@ class Instruction extends Construction::TInstruction { } private string getResultPrefix() { - if getResultType() instanceof Language::VoidType + if getResultIRType() instanceof IRVoidType then result = "v" else if hasMemoryResult() @@ -440,6 +441,12 @@ class Instruction extends Construction::TInstruction { result = Construction::getInstructionResultType(this) } + /** + * Gets the type of the result produced by this instruction. If the instruction does not produce + * a result, its result type will be `IRVoidType`. + */ + final IRType getResultIRType() { result = getResultLanguageType().getIRType() } + /** * Gets the type of the result produced by this instruction. If the * instruction does not produce a result, its result type will be `VoidType`. @@ -448,13 +455,12 @@ class Instruction extends Construction::TInstruction { * thought of as "pointer to `getResultType()`". */ final Language::Type getResultType() { - exists(Language::LanguageType resultType, Language::Type langType | + exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasType(langType, _) or - not resultType.hasType(_, _) and result instanceof Language::UnknownType - ) and - result = langType.getUnspecifiedType() + resultType.hasUnspecifiedType(result, _) or + not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType + ) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll index 0138af075dc..a75f70dbe2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll @@ -1,4 +1,5 @@ import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.Opcode as Opcode import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index f84871e227d..01e2d219652 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -5,6 +5,7 @@ import IRVariable import Operand private import internal.InstructionImports as Imports import Imports::EdgeKind +import Imports::IRType import Imports::MemoryAccessKind import Imports::Opcode private import Imports::OperandTag @@ -315,7 +316,7 @@ class Instruction extends Construction::TInstruction { } private string getResultPrefix() { - if getResultType() instanceof Language::VoidType + if getResultIRType() instanceof IRVoidType then result = "v" else if hasMemoryResult() @@ -440,6 +441,12 @@ class Instruction extends Construction::TInstruction { result = Construction::getInstructionResultType(this) } + /** + * Gets the type of the result produced by this instruction. If the instruction does not produce + * a result, its result type will be `IRVoidType`. + */ + final IRType getResultIRType() { result = getResultLanguageType().getIRType() } + /** * Gets the type of the result produced by this instruction. If the * instruction does not produce a result, its result type will be `VoidType`. @@ -448,13 +455,12 @@ class Instruction extends Construction::TInstruction { * thought of as "pointer to `getResultType()`". */ final Language::Type getResultType() { - exists(Language::LanguageType resultType, Language::Type langType | + exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasType(langType, _) or - not resultType.hasType(_, _) and result instanceof Language::UnknownType - ) and - result = langType.getUnspecifiedType() + resultType.hasUnspecifiedType(result, _) or + not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType + ) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll index 0138af075dc..a75f70dbe2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll @@ -1,4 +1,5 @@ import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.Opcode as Opcode import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll index 5af6b402ee3..9fa6ebe5018 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -31,6 +31,13 @@ private int getTypeSize(Type type) { else result = type.getSize() } +/** + * Holds if an `IRErrorType` should exist. + */ +predicate hasErrorType() { + exists(ErroneousType t) +} + /** * Holds if an `IRBooleanType` with the specified `byteSize` should exist. */ @@ -170,9 +177,7 @@ private newtype TCppType = * of a `VariableAddress` where the variable is of reference type) */ class CppType extends TCppType { - string toString() { - result = "" - } + abstract string toString(); /** Gets a string used in IR dumps */ string getDumpString() { result = toString() } @@ -191,6 +196,13 @@ class CppType extends TCppType { * it represents a glvalue of type `Type` (if `isGLValue` is `true`). */ abstract predicate hasType(Type type, boolean isGLValue); + + final predicate hasUnspecifiedType(Type type, boolean isGLValue) { + exists(Type specifiedType | + hasType(specifiedType, isGLValue) and + type = specifiedType.getUnspecifiedType() + ) + } } /** @@ -204,6 +216,7 @@ private class CppWrappedType extends CppType { this = TGLValueAddressType(ctype) } + abstract string toString(); abstract override IRType getIRType(); abstract override predicate hasType(Type type, boolean isGLValue); } diff --git a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql b/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql index be1474d7b1c..d2368e7bf4a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql +++ b/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql @@ -1,7 +1,7 @@ /** * @name Print IR * @description Outputs a representation of the IR graph - * @id charp/print-ir + * @id csharp/print-ir * @kind graph */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll new file mode 100644 index 00000000000..163d384c759 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll @@ -0,0 +1,259 @@ +/** + * Minimal, language-neutral type system for the IR. + */ + +private import internal.IRTypeInternal + +private newtype TIRType = + TIRVoidType() or + TIRUnknownType() or + TIRErrorType() { + Language::hasErrorType() + } or + TIRBooleanType(int byteSize) { + Language::hasBooleanType(byteSize) + } or + TIRSignedIntegerType(int byteSize) { + Language::hasSignedIntegerType(byteSize) + } or + TIRUnsignedIntegerType(int byteSize) { + Language::hasUnsignedIntegerType(byteSize) + } or + TIRFloatingPointType(int byteSize) { + Language::hasFloatingPointType(byteSize) + } or + TIRAddressType(int byteSize) { + Language::hasAddressType(byteSize) + } or + TIRFunctionAddressType(int byteSize) { + Language::hasFunctionAddressType(byteSize) + } or + TIRBlobType(Language::BlobTypeTag tag, int byteSize) { + Language::hasBlobType(tag, byteSize) + } + +/** + * The language-neutral type of an IR `Instruction`, `Operand`, or `IRVariable`. + * The interface to `IRType` and its subclasses is the same across all languages for which the IR + * is supported, so analyses that expect to be used for multiple languages should generally use + * `IRType` rather than a language-specific type. + * + * Many types from the language-specific type system will map to a single canonical `IRType`. Two + * types that map to the same `IRType` are considered equivalent by the IR. As an example, in C++, + * all pointer types map to the same instance of `IRAddressType`. + */ +class IRType extends TIRType { + abstract string toString(); + + /** + * Gets a string that uniquely identifies this `IRType`. This string is often the same as the + * result of `IRType.toString()`, but for some types it may be more verbose to ensure uniqueness. + */ + string getIdentityString() { + result = toString() + } + + /** + * Gets the size of the type, in bytes, if known. + * + * This will hold for all `IRType` objects except `IRUnknownType`. + */ + abstract int getByteSize(); + + /** + * Gets a single instance of `LanguageType` that maps to this `IRType`. + */ + abstract Language::LanguageType getCanonicalLanguageType(); +} + +/** + * An unknown type. Generally used to represent results and operands that access an unknown set of + * memory locations, such as the side effects of a function call. + */ +class IRUnknownType extends IRType, TIRUnknownType { + final override string toString() { result = "unknown" } + + final override int getByteSize() { none() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalUnknownType() + } +} + +/** + * A void type, which has no values. Used to represent the result type of an instruction that does + * not produce a result. + */ +class IRVoidType extends IRType, TIRVoidType { + final override string toString() { result = "void" } + + final override int getByteSize() { result = 0 } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalVoidType() + } +} + +/** + * An error type. Used when an error in the source code prevents the extractor from determining the + * proper type. + */ +class IRErrorType extends IRType, TIRErrorType { + final override string toString() { result = "error" } + + final override int getByteSize() { result = 0 } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalErrorType() + } +} + +private class IRSizedType extends IRType { + int byteSize; + + IRSizedType() { + this = TIRBooleanType(byteSize) or + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) or + this = TIRFloatingPointType(byteSize) or + this = TIRAddressType(byteSize) or + this = TIRFunctionAddressType(byteSize) or + this = TIRBlobType(_, byteSize) + } + + abstract override string toString(); + + final override int getByteSize() { result = byteSize } + + abstract override Language::LanguageType getCanonicalLanguageType(); +} + +/** + * A Boolean type, which can hold the values `true` (non-zero) or `false` (zero). + */ +class IRBooleanType extends IRSizedType, TIRBooleanType { + final override string toString() { result = "bool" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalBooleanType(byteSize) + } +} + +/** + * A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and + * `IRFloatingPointType`. + */ +class IRNumericType extends IRSizedType { + IRNumericType() { + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) or + this = TIRFloatingPointType(byteSize) + } + + abstract override string toString(); + + abstract override Language::LanguageType getCanonicalLanguageType(); +} + +/** + * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed + * integer, as well as character types whose representation is signed. + */ +class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { + final override string toString() { result = "int" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalSignedIntegerType(byteSize) + } +} + +/** + * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an + * unsigned integer, as well as character types whose representation is unsigned. + */ +class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { + final override string toString() { result = "uint" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalUnsignedIntegerType(byteSize) + } +} + +/** + * A floating-point type. + */ +class IRFloatingPointType extends IRNumericType, TIRFloatingPointType { + final override string toString() { result = "float" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalFloatingPointType(byteSize) + } +} + +/** + * An address type, representing the memory address of data. Used to represent pointers, references, + * and lvalues, include those that are garbage collected. + * + * The address of a function is represented by the separate `IRFunctionAddressType`. + */ +class IRAddressType extends IRSizedType, TIRAddressType { + final override string toString() { result = "addr" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalAddressType(byteSize) + } +} + +/** + * An address type, representing the memory address of code. Used to represent function pointers, + * function references, and the target of a direct function call. + */ +class IRFunctionAddressType extends IRSizedType, TIRFunctionAddressType { + final override string toString() { result = "func" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalFunctionAddressType(byteSize) + } +} + +/** + * A type with known size that does not fit any of the other kinds of type. Used to represent + * classes, structs, unions, fixed-size arrays, pointers-to-member, and more. + */ +class IRBlobType extends IRSizedType, TIRBlobType { + Language::BlobTypeTag tag; + + IRBlobType() { + this = TIRBlobType(tag, byteSize) + } + + final override string toString() { + result = "blob" + byteSize.toString() + "{" + tag.toString() + "}" + } + + final override string getIdentityString() { + result = "blob" + byteSize.toString() + "{" + Language::getBlobTagIdentityString(tag) + "}" + } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalBlobType(tag, byteSize) + } + + /** + * Gets the "tag" that differentiates this type from other incompatible blob types that have the + * same size. + */ + final Language::BlobTypeTag getTag() { result = tag } +} + +module IRTypeSanity { + query predicate missingCanonicalLanguageType(IRType type, string message) { + not exists(type.getCanonicalLanguageType()) and + message = "Type does not have a canonical `LanguageType`" + } + + query predicate multipleCanonicalLanguageTypes(IRType type, string message) { + strictcount(type.getCanonicalLanguageType()) > 1 and + message = "Type has multiple canonical `LanguageType`s: " + concat(type.getCanonicalLanguageType().toString(), ", ") + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll new file mode 100644 index 00000000000..0ee01a30ac3 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll @@ -0,0 +1 @@ +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index f84871e227d..01e2d219652 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -5,6 +5,7 @@ import IRVariable import Operand private import internal.InstructionImports as Imports import Imports::EdgeKind +import Imports::IRType import Imports::MemoryAccessKind import Imports::Opcode private import Imports::OperandTag @@ -315,7 +316,7 @@ class Instruction extends Construction::TInstruction { } private string getResultPrefix() { - if getResultType() instanceof Language::VoidType + if getResultIRType() instanceof IRVoidType then result = "v" else if hasMemoryResult() @@ -440,6 +441,12 @@ class Instruction extends Construction::TInstruction { result = Construction::getInstructionResultType(this) } + /** + * Gets the type of the result produced by this instruction. If the instruction does not produce + * a result, its result type will be `IRVoidType`. + */ + final IRType getResultIRType() { result = getResultLanguageType().getIRType() } + /** * Gets the type of the result produced by this instruction. If the * instruction does not produce a result, its result type will be `VoidType`. @@ -448,13 +455,12 @@ class Instruction extends Construction::TInstruction { * thought of as "pointer to `getResultType()`". */ final Language::Type getResultType() { - exists(Language::LanguageType resultType, Language::Type langType | + exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasType(langType, _) or - not resultType.hasType(_, _) and result instanceof Language::UnknownType - ) and - result = langType.getUnspecifiedType() + resultType.hasUnspecifiedType(result, _) or + not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType + ) ) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll index 372f5383db0..b26327d9248 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll @@ -1,6 +1,8 @@ import csharp import semmle.code.csharp.ir.implementation.raw.IR private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType +private import semmle.code.csharp.ir.internal.Overlap private import semmle.code.csharp.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition @@ -31,16 +33,18 @@ private module Cached { cached newtype TInstruction = MkInstruction(TranslatedElement element, InstructionTag tag) { - element.hasInstruction(_, tag, _, _) + element.hasInstruction(_, tag, _) } cached - predicate hasUserVariable(Callable callable, Variable var, Type type) { + predicate hasUserVariable(Callable callable, Variable var, CSharpType type) { getTranslatedFunction(callable).hasUserVariable(var, type) } cached - predicate hasTempVariable(Callable callable, Language::AST ast, TempVariableTag tag, Type type) { + predicate hasTempVariable( + Callable callable, Language::AST ast, TempVariableTag tag, CSharpType type + ) { exists(TranslatedElement element | element.getAST() = ast and callable = element.getFunction() and @@ -83,22 +87,16 @@ private module Cached { } cached - Type getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { + CSharpType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as // the result type of the load. if instruction instanceof LoadInstruction - then result = instruction.(LoadInstruction).getResultType() + then result = instruction.(LoadInstruction).getResultLanguageType() else result = getInstructionTranslatedElement(instruction) .getInstructionOperandType(getInstructionTag(instruction), tag) } - cached - int getInstructionOperandSize(Instruction instruction, SideEffectOperandTag tag) { - result = getInstructionTranslatedElement(instruction) - .getInstructionOperandSize(getInstructionTag(instruction), tag) - } - cached Instruction getPhiOperandDefinition( PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap @@ -216,15 +214,15 @@ private module Cached { } cached - predicate instructionHasType(Instruction instruction, Type type, boolean isLValue) { + CSharpType getInstructionResultType(Instruction instruction) { getInstructionTranslatedElement(instruction) - .hasInstruction(_, getInstructionTag(instruction), type, isLValue) + .hasInstruction(_, getInstructionTag(instruction), result) } cached Opcode getInstructionOpcode(Instruction instruction) { getInstructionTranslatedElement(instruction) - .hasInstruction(result, getInstructionTag(instruction), _, _) + .hasInstruction(result, getInstructionTag(instruction), _) } cached @@ -271,7 +269,7 @@ private module Cached { } cached - Type getInstructionExceptionType(Instruction instruction) { + CSharpType getInstructionExceptionType(Instruction instruction) { result = getInstructionTranslatedElement(instruction) .getInstructionExceptionType(getInstructionTag(instruction)) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll index b5abc1049f3..3b716c201ac 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll @@ -1,2 +1,3 @@ import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll index 20c299416ef..9ab8de41259 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll @@ -1,3 +1,4 @@ +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll index da9b8e6e877..8628f5be373 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll @@ -1,4 +1,5 @@ import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.csharp.ir.implementation.Opcode as Opcode import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll index 13667df7276..19e753f8a4a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll @@ -1,3 +1,4 @@ +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.csharp.ir.internal.Overlap as Overlap import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll index 93e8e67200a..85106cfbf27 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll @@ -1,6 +1,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr @@ -34,7 +35,7 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -100,7 +101,7 @@ abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeConditio } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll index 879ac4d1384..85af08a411f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll @@ -3,6 +3,7 @@ import semmle.code.csharp.ir.implementation.raw.IR private import semmle.code.csharp.ir.IRConfiguration private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition @@ -15,11 +16,6 @@ private import desugar.Foreach private import desugar.Delegate private import desugar.Lock -/** - * Gets the built-in `int` type. - */ -IntType getIntType() { any() } - ArrayType getArrayOfDim(int dim, Type type) { result.getRank() = dim and result.getElementType() = type @@ -411,7 +407,7 @@ abstract class TranslatedElement extends TTranslatedElement { * `VoidType`. */ abstract predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ); /** @@ -452,7 +448,7 @@ abstract class TranslatedElement extends TTranslatedElement { * `tag` must be unique for each variable generated from the same AST node * (not just from the same `TranslatedElement`). */ - predicate hasTempVariable(TempVariableTag tag, Type type) { none() } + predicate hasTempVariable(TempVariableTag tag, CSharpType type) { none() } /** * If the instruction specified by `tag` is a `FunctionInstruction`, gets the @@ -507,7 +503,7 @@ abstract class TranslatedElement extends TTranslatedElement { * If the instruction specified by `tag` is a `CatchByTypeInstruction`, * gets the type of the exception to be caught. */ - Type getInstructionExceptionType(InstructionTag tag) { none() } + CSharpType getInstructionExceptionType(InstructionTag tag) { none() } /** * If the instruction specified by `tag` is an `InheritanceConversionInstruction`, @@ -526,13 +522,7 @@ abstract class TranslatedElement extends TTranslatedElement { /** * Gets the type of the memory operand specified by `operandTag` on the the instruction specified by `tag`. */ - Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } - - /** - * Gets the size of the memory operand specified by `operandTag` on the the instruction specified by `tag`. - * Only holds for operands whose type is `UnknownType`. - */ - int getInstructionOperandSize(InstructionTag tag, SideEffectOperandTag operandTag) { none() } + CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } /** * Gets the instruction generated by this element with tag `tag`. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 8e83de3e027..4cea9e9f8f2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -2,6 +2,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag private import semmle.code.csharp.ir.internal.TempVariableTag +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRUtilities private import InstructionTag private import TranslatedCondition @@ -96,6 +97,12 @@ abstract class TranslatedCoreExpr extends TranslatedExpr { not needsLoad(expr) } + final CSharpType getResultCSharpType() { + if isResultLValue() = true + then result = getTypeForGLValue(expr.getType()) + else result = getTypeForPRValue(expr.getType()) + } + /** * Returns `true` if the result of this `TranslatedExpr` is a lvalue, or * `false` if the result is a rvalue. @@ -118,7 +125,7 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { ( tag = ConditionValueTrueTempAddressTag() or @@ -126,29 +133,25 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, tag = ConditionValueResultTempAddressTag() ) and opcode instanceof Opcode::VariableAddress and - resultType = this.getResultType() and - isLValue = true + resultType = getTypeForGLValue(expr.getType()) or ( tag = ConditionValueTrueConstantTag() or tag = ConditionValueFalseConstantTag() ) and opcode instanceof Opcode::Constant and - resultType = this.getResultType() and - isLValue = this.isResultLValue() + resultType = getResultCSharpType() or ( tag = ConditionValueTrueStoreTag() or tag = ConditionValueFalseStoreTag() ) and opcode instanceof Opcode::Store and - resultType = this.getResultType() and - isLValue = this.isResultLValue() + resultType = getResultCSharpType() or tag = ConditionValueResultLoadTag() and opcode instanceof Opcode::Load and - resultType = this.getResultType() and - isLValue = this.isResultLValue() + resultType = getResultCSharpType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -209,9 +212,9 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, ) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ConditionValueTempVar() and - type = this.getResultType() + type = this.getResultCSharpType() } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -260,12 +263,13 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad { override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = expr.getType() and - if not this.producesExprResult() then isLValue = true else isLValue = false + if producesExprResult() + then resultType = getTypeForPRValue(expr.getType()) + else resultType = getTypeForGLValue(expr.getType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -326,32 +330,29 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { or resultType instanceof FloatingPointType and result = this.getResultType() or - resultType instanceof PointerType and result = getIntType() + resultType instanceof PointerType and result = any(IntType t) ) ) } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { - isLValue = false and - ( - tag = CrementLoadTag() and - opcode instanceof Opcode::Load and - resultType = this.getResultType() - or - tag = CrementConstantTag() and - opcode instanceof Opcode::Constant and - resultType = this.getConstantType() - or - tag = CrementOpTag() and - opcode = this.getOpcode() and - resultType = this.getResultType() - or - tag = CrementStoreTag() and - opcode instanceof Opcode::Store and - resultType = this.getResultType() - ) + tag = CrementLoadTag() and + opcode instanceof Opcode::Load and + resultType = getTypeForPRValue(expr.getType()) + or + tag = CrementConstantTag() and + opcode instanceof Opcode::Constant and + resultType = getTypeForPRValue(this.getConstantType()) + or + tag = CrementOpTag() and + opcode = this.getOpcode() and + resultType = getTypeForPRValue(expr.getType()) + or + tag = CrementStoreTag() and + opcode instanceof Opcode::Store and + resultType = getTypeForPRValue(expr.getType()) } final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -467,7 +468,7 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -506,7 +507,7 @@ class TranslatedCollectionInitializer extends TranslatedNonConstantExpr, Initial override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -609,22 +610,20 @@ class TranslatedArrayAccess extends TranslatedNonConstantExpr { override Instruction getResult() { result = this.getInstruction(PointerAddTag(getRank() - 1)) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { exists(int index | inBounds(index) and tag = PointerAddTag(index) and opcode instanceof Opcode::PointerAdd and - resultType = this.getInstruction(ElementsAddressTag(index)).getResultType() and - isLValue = false + resultType = getTypeForPRValue(getArrayOfDim(getRank() - index, expr.getType())) ) or exists(int index | inBounds(index) and tag = ElementsAddressTag(index) and opcode instanceof Opcode::ElementsAddress and - resultType = getArrayOfDim(getRank() - index, expr.getType()) and - isLValue = false + resultType = getTypeForPRValue(getArrayOfDim(getRank() - index, expr.getType())) ) } @@ -694,7 +693,7 @@ abstract class TranslatedPointerOps extends TranslatedNonConstantExpr { } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -726,12 +725,11 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr { final override TranslatedElement getChild(int id) { none() } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode instanceof Opcode::CopyValue and - resultType = expr.getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } @@ -778,13 +776,12 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { this.needsExtraLoad() and tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -856,14 +853,13 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { - TranslatedVariableAccess.super.hasInstruction(opcode, tag, resultType, isLValue) + TranslatedVariableAccess.super.hasInstruction(opcode, tag, resultType) or tag = AddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = this.getResultType() and - isLValue = true + resultType = getTypeForGLValue(this.getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -902,12 +898,11 @@ class TranslatedFieldAccess extends TranslatedVariableAccess { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = AddressTag() and opcode instanceof Opcode::FieldAddress and - resultType = this.getResultType() and - isLValue = true + resultType = getTypeForGLValue(expr.getType()) } override Field getInstructionField(InstructionTag tag) { @@ -932,12 +927,11 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode instanceof Opcode::FunctionAddress and - resultType = expr.getType() and - isLValue = true + resultType = getTypeForGLValue(expr.getType()) } override Callable getInstructionFunction(InstructionTag tag) { @@ -982,12 +976,11 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedVal } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode = this.getOpcode() and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -1034,12 +1027,11 @@ abstract class TranslatedSingleInstructionExpr extends TranslatedNonConstantExpr abstract Opcode getOpcode(); final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { opcode = getOpcode() and tag = OnlyInstructionTag() and - resultType = this.getResultType() and - isLValue = this.isResultLValue() + resultType = getResultCSharpType() } final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) } @@ -1112,13 +1104,12 @@ class TranslatedCast extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { ( tag = ConvertTag() and opcode = this.getOpcode() and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) ) } @@ -1289,7 +1280,7 @@ abstract class TranslatedAssignment extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { ( this.needsConversion() and @@ -1298,8 +1289,7 @@ abstract class TranslatedAssignment extends TranslatedNonConstantExpr { // crudely represent conversions. Could // be useful to represent the whole chain of conversions opcode instanceof Opcode::Convert and - resultType = expr.getLValue().getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getLValue().getType()) ) } @@ -1347,14 +1337,13 @@ class TranslatedAssignExpr extends TranslatedAssignment { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { - TranslatedAssignment.super.hasInstruction(opcode, tag, resultType, isLValue) + TranslatedAssignment.super.hasInstruction(opcode, tag, resultType) or tag = AssignmentStoreTag() and opcode instanceof Opcode::Store and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -1472,31 +1461,28 @@ class TranslatedAssignOperation extends TranslatedAssignment { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { - isLValue = false and + tag = AssignOperationLoadTag() and + opcode instanceof Opcode::Load and + resultType = getTypeForPRValue(this.getLeftOperand().getResultType()) + or + tag = AssignOperationOpTag() and + opcode = getOpcode() and + resultType = getTypeForPRValue(this.getConvertedLeftOperandType()) + or + tag = AssignmentStoreTag() and + opcode instanceof Opcode::Store and + resultType = getTypeForPRValue(expr.getType()) + or + this.leftOperandNeedsConversion() and + opcode instanceof Opcode::Convert and ( - tag = AssignOperationLoadTag() and - opcode instanceof Opcode::Load and - resultType = this.getLeftOperand().getResultType() + tag = AssignOperationConvertLeftTag() and + resultType = getTypeForPRValue(this.getConvertedLeftOperandType()) or - tag = AssignOperationOpTag() and - opcode = getOpcode() and - resultType = this.getConvertedLeftOperandType() - or - tag = AssignmentStoreTag() and - opcode instanceof Opcode::Store and - resultType = this.getResultType() - or - this.leftOperandNeedsConversion() and - opcode instanceof Opcode::Convert and - ( - tag = AssignOperationConvertLeftTag() and - resultType = this.getConvertedLeftOperandType() - or - tag = AssignOperationConvertResultTag() and - resultType = this.getLeftOperand().getResultType() - ) + tag = AssignOperationConvertResultTag() and + resultType = getTypeForPRValue(this.getLeftOperand().getResultType()) ) } @@ -1583,7 +1569,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont override Instruction getFirstInstruction() { result = this.getCondition().getFirstInstruction() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { not this.resultIsVoid() and ( @@ -1595,8 +1581,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont tag = ConditionValueResultTempAddressTag() ) and opcode instanceof Opcode::VariableAddress and - resultType = this.getResultType() and - isLValue = true + resultType = getTypeForGLValue(this.getResultType()) or ( not this.thenIsVoid() and tag = ConditionValueTrueStoreTag() @@ -1604,13 +1589,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont not this.elseIsVoid() and tag = ConditionValueFalseStoreTag() ) and opcode instanceof Opcode::Store and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(this.getResultType()) or tag = ConditionValueResultLoadTag() and opcode instanceof Opcode::Load and - resultType = this.getResultType() and - isLValue = this.isResultLValue() + resultType = this.getResultCSharpType() ) } @@ -1678,10 +1661,10 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont ) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { not this.resultIsVoid() and tag = ConditionValueTempVar() and - type = this.getResultType() + type = getTypeForPRValue(this.getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -1816,34 +1799,29 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { this.hasVar() and tag = InitializerStoreTag() and opcode instanceof Opcode::Store and - resultType = expr.getPattern().getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getPattern().getType()) or tag = ConvertTag() and opcode instanceof Opcode::CheckedConvertOrNull and - resultType = expr.getPattern().getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getPattern().getType()) or tag = GeneratedNEQTag() and opcode instanceof Opcode::CompareNE and - resultType = expr.getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) or tag = GeneratedConstantTag() and opcode instanceof Opcode::Constant and - resultType = expr.getPattern().getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getPattern().getType()) or this.hasVar() and tag = GeneratedBranchTag() and opcode instanceof Opcode::ConditionalBranch and - resultType = expr.getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } override string getInstructionConstantValue(InstructionTag tag) { @@ -1932,22 +1910,19 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = this.getResultType() and - isLValue = true + resultType = getTypeForGLValue(expr.getType()) or tag = InitializerStoreTag() and opcode instanceof Opcode::Uninitialized and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) or tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = this.getResultType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -1973,9 +1948,9 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont result = this.getTempVariable(LambdaTempVar()) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LambdaTempVar() and - type = this.getResultType() + type = getTypeForPRValue(this.getResultType()) } final override Instruction getTargetAddress() { @@ -2015,7 +1990,7 @@ class TranslatedDelegateCall extends TranslatedNonConstantExpr { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -2044,20 +2019,18 @@ abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreatio } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { // Instruction that allocated space for a new object, // and returns its address tag = NewObjTag() and opcode instanceof Opcode::NewObj and - resultType = expr.getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) or this.needsLoad() and tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = expr.getType() and - isLValue = false + resultType = getTypeForPRValue(expr.getType()) } final override Instruction getFirstInstruction() { result = this.getInstruction(NewObjTag()) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll index 41f88e25766..00fb956f30c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -1,6 +1,7 @@ import csharp import semmle.code.csharp.ir.implementation.raw.IR private import semmle.code.csharp.ir.implementation.Opcode +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRUtilities private import semmle.code.csharp.ir.implementation.internal.OperandTag private import semmle.code.csharp.ir.internal.TempVariableTag @@ -121,39 +122,33 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { ( tag = EnterFunctionTag() and opcode instanceof Opcode::EnterFunction and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() or tag = UnmodeledDefinitionTag() and opcode instanceof Opcode::UnmodeledDefinition and - resultType instanceof Language::UnknownType and - isLValue = false + resultType = getUnknownType() or tag = AliasedDefinitionTag() and opcode instanceof Opcode::AliasedDefinition and - resultType instanceof Language::UnknownType and - isLValue = false + resultType = getUnknownType() or tag = InitializeThisTag() and opcode instanceof Opcode::InitializeThis and - resultType = getThisType() and - isLValue = true + resultType = getTypeForGLValue(getThisType()) or tag = ReturnValueAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = this.getReturnType() and - not resultType instanceof VoidType and - isLValue = true + not getReturnType() instanceof VoidType and + resultType = getTypeForGLValue(getReturnType()) or ( tag = ReturnTag() and - resultType instanceof VoidType and - isLValue = false and + resultType = getVoidType() and if this.getReturnType() instanceof VoidType then opcode instanceof Opcode::ReturnVoid else opcode instanceof Opcode::ReturnValue @@ -161,8 +156,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or tag = UnwindTag() and opcode instanceof Opcode::Unwind and - resultType instanceof VoidType and - isLValue = false and + resultType = getVoidType() and ( // Only generate the `Unwind` instruction if there is any exception // handling present in the function (compiler generated or not). @@ -172,13 +166,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or tag = UnmodeledUseTag() and opcode instanceof Opcode::UnmodeledUse and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() or tag = ExitFunctionTag() and opcode instanceof Opcode::ExitFunction and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() ) } @@ -207,11 +199,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { ) } - final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { tag = ReturnTag() and not this.getReturnType() instanceof VoidType and operandTag instanceof LoadOperandTag and - result = this.getReturnType() + result = getTypeForPRValue(this.getReturnType()) } final override IRVariable getInstructionVariable(InstructionTag tag) { @@ -219,10 +211,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = this.getReturnVariable() } - final override predicate hasTempVariable(TempVariableTag tag, Type type) { + final override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ReturnValueTempVar() and - type = this.getReturnType() and - not type instanceof VoidType + type = getTypeForPRValue(this.getReturnType()) and + not getReturnType() instanceof VoidType } /** @@ -278,7 +270,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { * parameters and local variables, plus any static fields that are directly accessed by the * function. */ - final predicate hasUserVariable(Variable var, Type type) { + final predicate hasUserVariable(Variable var, CSharpType type) { ( var.(Member).isStatic() and exists(VariableAccess access | @@ -288,7 +280,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { or var.(LocalScopeVariable).getCallable() = callable ) and - type = getVariableType(var) + type = getTypeForPRValue(getVariableType(var)) } final private Type getReturnType() { result = callable.getReturnType() } @@ -334,17 +326,15 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter { final override Instruction getChildSuccessor(TranslatedElement child) { none() } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getVariableType(param) and - isLValue = true + resultType = getTypeForGLValue(param.getType()) or tag = InitializerStoreTag() and opcode instanceof Opcode::InitializeParameter and - resultType = getVariableType(param) and - isLValue = false + resultType = getTypeForPRValue(param.getType()) } final override IRVariable getInstructionVariable(InstructionTag tag) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll index d0d98a4918a..35dea9ab94b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -6,6 +6,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr @@ -88,7 +89,7 @@ abstract class TranslatedListInitialization extends TranslatedInitialization, In } final override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -135,12 +136,11 @@ class TranslatedDirectInitialization extends TranslatedInitialization { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = InitializerStoreTag() and opcode instanceof Opcode::Store and - resultType = this.getContext().getTargetType() and - isLValue = false + resultType = getTypeForPRValue(this.getContext().getTargetType()) or needsConversion() and tag = AssignmentConvertRightTag() and @@ -148,8 +148,7 @@ class TranslatedDirectInitialization extends TranslatedInitialization { // crudely represent conversions. Could // be useful to represent the whole chain of conversions opcode instanceof Opcode::Convert and - resultType = this.getContext().getTargetType() and - isLValue = false + resultType = getTypeForPRValue(this.getContext().getTargetType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -219,17 +218,15 @@ abstract class TranslatedElementInitialization extends TranslatedElement { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = getElementIndexTag() and opcode instanceof Opcode::Constant and - resultType = getIntType() and - isLValue = false + resultType = getIntType() or tag = getElementAddressTag() and opcode instanceof Opcode::PointerAdd and - resultType = getElementType() and - isLValue = true + resultType = getTypeForGLValue(getElementType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -354,13 +351,12 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { this.needsConversion() and tag = OnlyInstructionTag() and opcode instanceof Opcode::Convert and - resultType = call.getTarget().getDeclaringType() and - isLValue = true + resultType = getTypeForGLValue(call.getTarget().getDeclaringType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll index 3e4934987a3..20590c133b0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -1,4 +1,5 @@ import csharp +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.TempVariableTag private import semmle.code.csharp.ir.implementation.internal.OperandTag private import InstructionTag @@ -40,12 +41,11 @@ class TranslatedEmptyStmt extends TranslatedStmt { override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode instanceof Opcode::NoOp and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -63,7 +63,7 @@ class TranslatedDeclStmt extends TranslatedStmt { override TranslatedElement getChild(int id) { result = this.getLocalDeclaration(id) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -98,7 +98,7 @@ class TranslatedExprStmt extends TranslatedStmt { override TranslatedElement getChild(int id) { id = 0 and result = this.getExpr() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -162,12 +162,11 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationCont } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = this.getEnclosingFunction().getReturnVariable().getType() and - isLValue = true + resultType = getTypeForGLValue(this.getEnclosingFunction().getFunction().getReturnType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -207,12 +206,11 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt { override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode instanceof Opcode::NoOp and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -241,7 +239,7 @@ class TranslatedTryStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -290,13 +288,12 @@ class TranslatedBlock extends TranslatedStmt { override TranslatedElement getChild(int id) { result = this.getStmt(id) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { isEmpty() and opcode instanceof Opcode::NoOp and tag = OnlyInstructionTag() and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getFirstInstruction() { @@ -358,12 +355,11 @@ class TranslatedCatchByTypeClause extends TranslatedClause { TranslatedCatchByTypeClause() { stmt instanceof SpecificCatchClause } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = CatchTag() and opcode instanceof Opcode::CatchByType and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override TranslatedElement getChild(int id) { @@ -389,9 +385,9 @@ class TranslatedCatchByTypeClause extends TranslatedClause { ) } - override Type getInstructionExceptionType(InstructionTag tag) { + override CSharpType getInstructionExceptionType(InstructionTag tag) { tag = CatchTag() and - result = stmt.(SpecificCatchClause).getVariable().getType() + result = getTypeForPRValue(stmt.(SpecificCatchClause).getVariable().getType()) } private TranslatedLocalDeclaration getParameter() { @@ -406,12 +402,11 @@ class TranslatedGeneralCatchClause extends TranslatedClause { TranslatedGeneralCatchClause() { stmt instanceof GeneralCatchClause } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = CatchTag() and opcode instanceof Opcode::CatchAny and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -440,17 +435,15 @@ class TranslatedThrowExceptionStmt extends TranslatedStmt, InitializationContext } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = ThrowTag() and opcode instanceof Opcode::ThrowValue and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() or tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = this.getExceptionType() and - isLValue = true + resultType = getTypeForGLValue(this.getExceptionType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -473,9 +466,9 @@ class TranslatedThrowExceptionStmt extends TranslatedStmt, InitializationContext result = getIRTempVariable(stmt, ThrowTempVar()) } - final override predicate hasTempVariable(TempVariableTag tag, Type type) { + final override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ThrowTempVar() and - type = this.getExceptionType() + type = getTypeForPRValue(this.getExceptionType()) } final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -490,10 +483,10 @@ class TranslatedThrowExceptionStmt extends TranslatedStmt, InitializationContext ) } - final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { tag = ThrowTag() and operandTag instanceof LoadOperandTag and - result = this.getExceptionType() + result = getTypeForPRValue(this.getExceptionType()) } override Instruction getTargetAddress() { @@ -523,12 +516,11 @@ class TranslatedEmptyThrowStmt extends TranslatedStmt { override Instruction getFirstInstruction() { result = this.getInstruction(ThrowTag()) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = ThrowTag() and opcode instanceof Opcode::ReThrow and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -583,7 +575,7 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -611,7 +603,7 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -725,12 +717,11 @@ abstract class TranslatedSpecificJump extends TranslatedStmt { override TranslatedElement getChild(int id) { none() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = OnlyInstructionTag() and opcode instanceof Opcode::NoOp and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -853,12 +844,11 @@ class TranslatedSwitchStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = SwitchBranchTag() and opcode instanceof Opcode::Switch and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { @@ -936,7 +926,7 @@ class TranslatedUnsafeStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -972,7 +962,7 @@ class TranslatedFixedStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -1013,7 +1003,7 @@ class TranslatedLockStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -1047,7 +1037,7 @@ class TranslatedCheckedUncheckedStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -1090,7 +1080,7 @@ class TranslatedUsingBlockStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -1126,7 +1116,7 @@ class TranslatedUsingDeclStmt extends TranslatedStmt { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll index b6f708d04d9..9a0edd85456 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll @@ -10,6 +10,7 @@ private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr private import semmle.code.csharp.ir.Util +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language private import TranslatedExprBase @@ -33,12 +34,11 @@ abstract class TranslatedCallBase extends TranslatedElement { } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = CallTag() and opcode instanceof Opcode::Call and - resultType = getCallResultType() and - isLValue = false + resultType = getTypeForPRValue(getCallResultType()) or hasSideEffect() and tag = CallSideEffectTag() and @@ -46,20 +46,18 @@ abstract class TranslatedCallBase extends TranslatedElement { if hasWriteSideEffect() then ( opcode instanceof Opcode::CallSideEffect and - resultType instanceof Language::UnknownType + resultType = getUnknownType() ) else ( opcode instanceof Opcode::CallReadSideEffect and - resultType instanceof Language::UnknownType + resultType = getUnknownType() ) - ) and - isLValue = false + ) or tag = CallTargetTag() and opcode instanceof Opcode::FunctionAddress and // Since the DB does not have a function type, // we just use the UnknownType - resultType instanceof Language::UnknownType and - isLValue = true + resultType = getFunctionAddressType() } override Instruction getChildSuccessor(TranslatedElement child) { @@ -115,11 +113,11 @@ abstract class TranslatedCallBase extends TranslatedElement { result = getUnmodeledDefinitionInstruction() } - final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { tag = CallSideEffectTag() and hasSideEffect() and operandTag instanceof SideEffectOperandTag and - result instanceof Language::UnknownType + result = getUnknownType() } Instruction getResult() { result = getInstruction(CallTag()) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll index 7503e3b41e2..5252cdac863 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll @@ -9,6 +9,7 @@ private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language /** @@ -39,12 +40,11 @@ abstract class ValueConditionBase extends ConditionBase { override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = ValueConditionConditionalBranchTag() and opcode instanceof Opcode::ConditionalBranch and - resultType instanceof VoidType and - isLValue = false + resultType = getVoidType() } override Instruction getChildSuccessor(TranslatedElement child) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll index fbf5db28ec8..88a8961bf66 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll @@ -11,6 +11,7 @@ private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language abstract class LocalVariableDeclarationBase extends TranslatedElement { @@ -19,18 +20,16 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement { override Instruction getFirstInstruction() { result = getVarAddress() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = InitializerVariableAddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getVarType() and - isLValue = true + resultType = getTypeForGLValue(getVarType()) or hasUninitializedInstruction() and tag = InitializerStoreTag() and opcode instanceof Opcode::Uninitialized and - resultType = getVarType() and - isLValue = false + resultType = getTypeForPRValue(getVarType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll index 1b29ac7c543..33697848155 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll @@ -8,6 +8,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.TempVariableTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction @@ -31,7 +32,7 @@ abstract class TranslatedCompilerGeneratedTry extends TranslatedCompilerGenerate override Stmt generatedBy; override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -73,12 +74,11 @@ abstract class TranslatedCompilerGeneratedTry extends TranslatedCompilerGenerate */ abstract class TranslatedCompilerGeneratedConstant extends TranslatedCompilerGeneratedExpr { override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { opcode instanceof Opcode::Constant and tag = OnlyInstructionTag() and - resultType = getResultType() and - isLValue = false + resultType = getTypeForPRValue(getResultType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -118,7 +118,7 @@ abstract class TranslatedCompilerGeneratedBlock extends TranslatedCompilerGenera } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -171,7 +171,7 @@ abstract class TranslatedCompilerGeneratedIfStmt extends TranslatedCompilerGener } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -191,18 +191,16 @@ abstract class TranslatedCompilerGeneratedVariableAccess extends TranslatedCompi override Instruction getChildSuccessor(TranslatedElement child) { none() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { tag = AddressTag() and opcode instanceof Opcode::VariableAddress and - resultType = getResultType() and - isLValue = true + resultType = getTypeForGLValue(getResultType()) or needsLoad() and tag = LoadTag() and opcode instanceof Opcode::Load and - resultType = getResultType() and - isLValue = false + resultType = getTypeForPRValue(getResultType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll index 06a001e8912..a7b1881e92b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll @@ -36,6 +36,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.TempVariableTag private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr @@ -113,7 +114,7 @@ class TranslatedForeachWhile extends TranslatedCompilerGeneratedStmt, ConditionC TranslatedForeachWhile() { this = TTranslatedCompilerGeneratedElement(generatedBy, 2) } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } @@ -329,9 +330,9 @@ private class TranslatedForeachEnumerator extends TranslatedCompilerGeneratedDec TranslatedForeachEnumerator() { this = TTranslatedCompilerGeneratedElement(generatedBy, 8) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ForeachEnumTempVar() and - type = getInitialization().getCallResultType() + type = getTypeForPRValue(getInitialization().getCallResultType()) } override IRTempVariable getIRVariable() { @@ -388,9 +389,9 @@ private class TranslatedMoveNextEnumAcc extends TTranslatedCompilerGeneratedElem override Type getResultType() { result instanceof BoolType } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ForeachEnumTempVar() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -413,9 +414,9 @@ private class TranslatedForeachCurrentEnumAcc extends TTranslatedCompilerGenerat override Type getResultType() { result instanceof BoolType } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ForeachEnumTempVar() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -438,9 +439,9 @@ private class TranslatedForeachDisposeEnumAcc extends TTranslatedCompilerGenerat override Type getResultType() { result instanceof BoolType } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = ForeachEnumTempVar() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll index 1fb0167b4cc..7a0ec9d5cbc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll @@ -21,6 +21,7 @@ import csharp private import semmle.code.csharp.ir.implementation.Opcode private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.TempVariableTag private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement @@ -259,9 +260,9 @@ private class TranslatedLockWasTakenDecl extends TranslatedCompilerGeneratedDecl TranslatedLockWasTakenDecl() { this = TTranslatedCompilerGeneratedElement(generatedBy, 8) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockWasTakenTemp() and - type instanceof BoolType + type = getBoolType() } override IRTempVariable getIRVariable() { @@ -290,9 +291,9 @@ private class TranslatedLockedVarDecl extends TranslatedCompilerGeneratedDeclara TranslatedLockedVarDecl() { this = TTranslatedCompilerGeneratedElement(generatedBy, 9) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockedVarTemp() and - type = generatedBy.getExpr().getType() + type = getTypeForPRValue(generatedBy.getExpr().getType()) } override IRTempVariable getIRVariable() { @@ -321,9 +322,9 @@ private class TranslatedMonitorEnterVarAcc extends TTranslatedCompilerGeneratedE override Type getResultType() { result = generatedBy.getExpr().getType() } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockedVarTemp() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -352,9 +353,9 @@ private class TranslatedMonitorExitVarAcc extends TTranslatedCompilerGeneratedEl result = getTempVariable(LockedVarTemp()) } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockedVarTemp() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override predicate needsLoad() { any() } @@ -372,9 +373,9 @@ private class TranslatedLockWasTakenCondVarAcc extends TTranslatedCompilerGenera override Type getResultType() { result instanceof BoolType } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockWasTakenTemp() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -397,9 +398,9 @@ private class TranslatedLockWasTakenRefArg extends TTranslatedCompilerGeneratedE override Type getResultType() { result instanceof BoolType } - override predicate hasTempVariable(TempVariableTag tag, Type type) { + override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { tag = LockWasTakenTemp() and - type = getResultType() + type = getTypeForPRValue(getResultType()) } override IRVariable getInstructionVariable(InstructionTag tag) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll index 5820a8b8309..2fac4b38999 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll @@ -12,6 +12,7 @@ private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedEleme private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedDeclarationBase private import TranslatedCompilerGeneratedElement +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDeclarationBase, @@ -29,17 +30,16 @@ abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDecla } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { - LocalVariableDeclarationBase.super.hasInstruction(opcode, tag, resultType, isLValue) + LocalVariableDeclarationBase.super.hasInstruction(opcode, tag, resultType) or // we can reuse the initializer store tag // since compiler generated declarations // do not have the `Uninitialized` instruction tag = InitializerStoreTag() and opcode instanceof Opcode::Store and - resultType = getVarType() and - isLValue = false + resultType = getTypeForPRValue(getVarType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll new file mode 100644 index 00000000000..cf0ae13a426 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll @@ -0,0 +1,424 @@ +private import csharp +private import semmle.code.csharp.ir.implementation.IRType +private import IRCSharpLanguage as Language + +int getTypeSize(Type type) { + // REVIEW: Is this complete? + result = type.(SimpleType).getSize() + or + result = getTypeSize(type.(Enum).getUnderlyingType()) + or + // TODO: Generate a reasonable size + type instanceof Struct and result = 16 + or + type instanceof RefType and result = getPointerSize() + or + type instanceof PointerType and result = getPointerSize() + or + result = getTypeSize(type.(TupleType).getUnderlyingType()) + or + // TODO: Add room for extra field + result = getTypeSize(type.(NullableType).getUnderlyingType()) + or + type instanceof VoidType and result = 0 +} + +int getPointerSize() { + result = 8 +} + +/** + * Holds if an `IRErrorType` should exist. + */ +predicate hasErrorType() { + exists(UnknownType t) +} + +/** + * Holds if an `IRBooleanType` with the specified `byteSize` should exist. + */ +predicate hasBooleanType(int byteSize) { + byteSize = getTypeSize(any(BoolType type)) +} + +private predicate isSignedIntegerType(ValueType type) { + type instanceof SignedIntegralType or + type.(Enum).getUnderlyingType() instanceof SignedIntegralType +} + +private predicate isUnsignedIntegerType(ValueType type) { + type instanceof UnsignedIntegralType or + type instanceof CharType or + type.(Enum).getUnderlyingType() instanceof UnsignedIntegralType +} + +/** + * Holds if an `IRSignedIntegerType` with the specified `byteSize` should exist. + */ +predicate hasSignedIntegerType(int byteSize) { + byteSize = getTypeSize(any(ValueType type | isSignedIntegerType(type))) +} + +/** + * Holds if an `IRUnsignedIntegerType` with the specified `byteSize` should exist. + */ +predicate hasUnsignedIntegerType(int byteSize) { + byteSize = getTypeSize(any(ValueType type | isUnsignedIntegerType(type))) +} + +/** + * Holds if an `IRFloatingPointType` with the specified `byteSize` should exist. + */ +predicate hasFloatingPointType(int byteSize) { + byteSize = any(FloatingPointType type).getSize() +} + +private predicate isPointerIshType(Type type) { + type instanceof PointerType or + type instanceof RefType +} + +/** + * Holds if an `IRAddressType` with the specified `byteSize` should exist. + */ +predicate hasAddressType(int byteSize) { + // This covers all pointers, all references, and because it also looks at `NullType`, it + // should always return a result that makes sense for arbitrary glvalues as well. + byteSize = getTypeSize(any(Type type | isPointerIshType(type))) +} + +/** + * Holds if an `IRFunctionAddressType` with the specified `byteSize` should exist. + */ +predicate hasFunctionAddressType(int byteSize) { + byteSize = getTypeSize(any(NullType type)) +} + +private int getBaseClassSize(ValueOrRefType type) { + if exists(type.getBaseClass()) + then result = getContentSize(type.getBaseClass()) + else result = 0 +} + +private int getContentSize(ValueOrRefType type) { + result = getBaseClassSize(type) + + sum(Field field | + not field.isStatic() | + getTypeSize(field.getType()) + ) +} + +private predicate isBlobType(ValueOrRefType type) { + type instanceof Struct or + type instanceof NullableType or + type instanceof DecimalType +} + +/** + * Holds if an `IRBlobType` with the specified `tag` and `byteSize` should exist. + */ +predicate hasBlobType(Type tag, int byteSize) { + isBlobType(tag) and byteSize = getTypeSize(tag) +} + +private Type getRepresentationType(Type type) { + result = type.(Enum).getUnderlyingType() + or + result = type.(TupleType).getUnderlyingType() + or + not type instanceof Enum and not type instanceof TupleType and result = type +} + +/** + * Gets the `IRType` that represents a prvalue of the specified `Type`. + */ +private IRType getIRTypeForPRValue(Type type) { + exists(Type repType | + repType = getRepresentationType(type) | + exists(IRBlobType blobType | + blobType = result | + blobType.getByteSize() = getTypeSize(repType) and + blobType.getTag() = repType + ) + or + result.(IRBooleanType).getByteSize() = repType.(BoolType).getSize() + or + isSignedIntegerType(repType) and + result.(IRSignedIntegerType).getByteSize() = getTypeSize(repType) + or + isUnsignedIntegerType(repType) and + result.(IRUnsignedIntegerType).getByteSize() = getTypeSize(repType) + or + result.(IRFloatingPointType).getByteSize() = repType.(FloatingPointType).getSize() + or + isPointerIshType(repType) and result.(IRAddressType).getByteSize() = getTypeSize(repType) + or + repType instanceof VoidType and result instanceof IRVoidType + or + repType instanceof UnknownType and result instanceof IRErrorType + ) +} + +string getBlobTagIdentityString(Type tag) { + result = tag.getQualifiedName() +} + +private newtype TCSharpType = + TPRValueType(Type type) { + exists(getIRTypeForPRValue(type)) + } or + TGLValueAddressType(Type type) { + any() + } or + TFunctionAddressType() or + TUnknownType() + +class CSharpType extends TCSharpType { + abstract string toString(); + + /** Gets a string used in IR dumps */ + string getDumpString() { result = toString() } + + /** Gets the size of the type in bytes, if known. */ + final int getByteSize() { result = getIRType().getByteSize() } + + /** + * Gets the `IRType` that represents this `CSharpType`. Many different `CSharpType`s can map to a + * single `IRType`. + */ + abstract IRType getIRType(); + + /** + * Holds if the `CSharpType` represents a prvalue of type `Type` (if `isGLValue` is `false`), or + * if it represents a glvalue of type `Type` (if `isGLValue` is `true`). + */ + abstract predicate hasType(Type type, boolean isGLValue); + + final predicate hasUnspecifiedType(Type type, boolean isGLValue) { + hasType(type, isGLValue) + } +} + +/** + * A `CSharpType` that wraps an existing `Type` (either as a prvalue or a glvalue). + */ +private class CSharpWrappedType extends CSharpType { + Type cstype; + + CSharpWrappedType() { + this = TPRValueType(cstype) or + this = TGLValueAddressType(cstype) + } + + abstract override string toString(); + abstract override IRType getIRType(); + abstract override predicate hasType(Type type, boolean isGLValue); +} + +/** + * A `CSharpType` that represents a prvalue of an existing `Type`. + */ +private class CSharpPRValueType extends CSharpWrappedType, TPRValueType { + override final string toString() { result = cstype.toString() } + + override final IRType getIRType() { result = getIRTypeForPRValue(cstype) } + + override final predicate hasType(Type type, boolean isGLValue) { + type = cstype and + isGLValue = false + } +} + +/** + * A `CSharpType` that represents a glvalue of an existing `Type`. + */ +private class CSharpGLValueAddressType extends CSharpWrappedType, TGLValueAddressType { + override final string toString() { + result = "glval<" + cstype.toString() + ">" + } + + override final IRAddressType getIRType() { + result.getByteSize() = getPointerSize() + } + + override final predicate hasType(Type type, boolean isGLValue) { + type = cstype and + isGLValue = true + } +} + +/** + * A `CSharpType` that represents a function address. + */ +private class CSharpFunctionAddressType extends CSharpType, TFunctionAddressType { + override final string toString() { +// result = "" // FIXME + result = "glval" + } + + override final IRFunctionAddressType getIRType() { + result.getByteSize() = getPointerSize() + } + + override final predicate hasType(Type type, boolean isGLValue) { + type instanceof VoidType and isGLValue = true + } +} + +/** + * A `CSharpType` that represents an unknown type. + */ +private class CSharpUnknownType extends CSharpType, TUnknownType { + override final string toString() { +// result = "" // FIXME + result = "null" + } + + override final IRUnknownType getIRType() { + any() + } + + override final predicate hasType(Type type, boolean isGLValue) { + type instanceof VoidType and isGLValue = false + } +} + +/** + * Gets the single instance of `CSharpUnknownType`. + */ +CSharpUnknownType getUnknownType() { + any() +} + +/** + * Gets the `CSharpType` that represents a prvalue of type `void`. + */ +CSharpPRValueType getVoidType() { + exists(VoidType voidType | + result.hasType(voidType, false) + ) +} + +/** + * Gets the `CSharpType` that represents a prvalue of type `type`. + */ +CSharpPRValueType getTypeForPRValue(Type type) { + result.hasType(type, false) +} + +/** + * Gets the `CSharpType` that represents a glvalue of type `type`. + */ +CSharpGLValueAddressType getTypeForGLValue(Type type) { + result.hasType(type, true) +} + +/** + * Gets the `CSharpType` that represents a prvalue of type `int`. + */ +CSharpPRValueType getIntType() { + result.hasType(any(IntType t), false) +} + +/** + * Gets the `CSharpType` that represents a prvalue of type `bool`. + */ +CSharpPRValueType getBoolType() { + result.hasType(any(BoolType t), false) +} + +/** + * Gets the `CSharpType` that represents a prvalue of `NullType`. + */ +CSharpPRValueType getNullType() { + result.hasType(any(NullType t), false) +} + +/** + * Gets the `CSharpType` that represents a function address. + */ +CSharpFunctionAddressType getFunctionAddressType() { + any() +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRBooleanType` with the specified + * `byteSize`. + */ +CSharpPRValueType getCanonicalBooleanType(int byteSize) { + exists(BoolType type | + result = TPRValueType(type) and byteSize = type.getSize() + ) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRSignedIntegerType` with the specified + * `byteSize`. + */ +CSharpPRValueType getCanonicalSignedIntegerType(int byteSize) { + result = TPRValueType(any(SignedIntegralType t | t.getSize() = byteSize)) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRUnsignedIntegerType` with the specified + * `byteSize`. + */ +CSharpPRValueType getCanonicalUnsignedIntegerType(int byteSize) { + result = TPRValueType(any(UnsignedIntegralType t | t.getSize() = byteSize)) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRFloatingPointType` with the specified + * `byteSize`. + */ +CSharpPRValueType getCanonicalFloatingPointType(int byteSize) { + result = TPRValueType(any(FloatingPointType type | type.getSize() = byteSize)) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRAddressType` with the specified + * `byteSize`. + */ +CSharpPRValueType getCanonicalAddressType(int byteSize) { + // We just use `NullType`, since it should be unique. + result = TPRValueType(any(NullType type | getTypeSize(type) = byteSize)) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRFunctionAddressType` with the specified + * `byteSize`. + */ +CSharpFunctionAddressType getCanonicalFunctionAddressType(int byteSize) { + result.getByteSize() = byteSize +} + +/** + * Gets the `CSharpType` that is the canonical type for `IRErrorType`. + */ +CSharpPRValueType getCanonicalErrorType() { + result = TPRValueType(any(UnknownType type)) +} + +/** + * Gets the `CSharpType` that is the canonical type for `IRUnknownType`. + */ +CSharpUnknownType getCanonicalUnknownType() { + any() +} + +/** + * Gets the `CSharpType` that is the canonical type for `IRVoidType`. + */ +CSharpPRValueType getCanonicalVoidType() { + result = TPRValueType(any(VoidType type)) +} + +/** + * Gets the `CSharpType` that is the canonical type for an `IRBlobType` with the specified `tag` and + * `byteSize`. + */ +CSharpPRValueType getCanonicalBlobType(Type tag, int byteSize) { + isBlobType(tag) and + result = TPRValueType(tag) and + getTypeSize(tag) = byteSize +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll index c359879c87f..5ff50b8f825 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll @@ -1,5 +1,9 @@ private import csharp as CSharp private import IRUtilities +import CSharpType + +class LanguageType = CSharpType; +class BlobTypeTag = CSharp::ValueOrRefType; class Function = CSharp::Callable; @@ -81,32 +85,6 @@ predicate hasPositionalArgIndex(int argIndex) { predicate hasAsmOperandIndex(int operandIndex) { none() } -int getTypeSize(Type type) { - // REVIEW: Is this complete? - result = type.(CSharp::SimpleType).getSize() - or - result = getTypeSize(type.(CSharp::Enum).getUnderlyingType()) - or - // TODO: Generate a reasonable size - type instanceof CSharp::Struct and result = 16 - or - type instanceof CSharp::RefType and result = getPointerSize() - or - type instanceof CSharp::PointerType and result = getPointerSize() - or - result = getTypeSize(type.(CSharp::TupleType).getUnderlyingType()) - or - // TODO: Add room for extra field - result = getTypeSize(type.(CSharp::NullableType).getUnderlyingType()) - or - type instanceof CSharp::VoidType and result = 0 -} - -int getPointerSize() { - // TODO: Deal with sizes in general - result = 8 -} - predicate isVariableAutomatic(Variable var) { var instanceof CSharp::LocalScopeVariable } string getStringLiteralText(StringLiteral s) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll index c14e361aa01..1aeace91377 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll @@ -1,25 +1,13 @@ private import csharp /** - * Get the actual type of the specified variable, as opposed to the declared type. - * This returns the type of the variable after any pointer decay is applied, and - * after any unsized array type has its size inferred from the initializer. + * Get the actual type of the specified variable, as opposed to the declared + * type. */ Type getVariableType(Variable v) { - exists(Type declaredType | - declaredType = v.getType() and - if v instanceof Parameter - then result = declaredType - else - if declaredType instanceof ArrayType - then - // TODO: Arrays have a declared dimension in C#, so this should not be needed - // and not declaredType.(ArrayType).hasArraySize() - result = v.getInitializer().getType() - or - not exists(v.getInitializer()) and result = declaredType - else result = declaredType - ) + // C# doesn't seem to have any cases where the variable's actual type differs + // from its declared type. + result = v.getType() } predicate hasCaseEdge(CaseStmt caseStmt, string minValue, string maxValue) { diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected index ae680785ce6..28d42be0d96 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected @@ -13,3 +13,5 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +missingCanonicalLanguageType +multipleCanonicalLanguageTypes From c8d154e9cc56f1670dce0ab714a67e3664588599 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 26 Sep 2019 15:54:09 -0700 Subject: [PATCH 0270/1227] C#: Fix dump of IR types --- .../code/csharp/ir/internal/CSharpType.qll | 6 +- .../test/library-tests/ir/ir/raw_ir.expected | 528 +++++++++--------- 2 files changed, 266 insertions(+), 268 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll index cf0ae13a426..9b9e33aa355 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll @@ -252,8 +252,7 @@ private class CSharpGLValueAddressType extends CSharpWrappedType, TGLValueAddres */ private class CSharpFunctionAddressType extends CSharpType, TFunctionAddressType { override final string toString() { -// result = "" // FIXME - result = "glval" + result = "" } override final IRFunctionAddressType getIRType() { @@ -270,8 +269,7 @@ private class CSharpFunctionAddressType extends CSharpType, TFunctionAddressType */ private class CSharpUnknownType extends CSharpType, TUnknownType { override final string toString() { -// result = "" // FIXME - result = "null" + result = "" } override final IRUnknownType getIRType() { diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index 5a3ade51b6b..ef1344ec3e5 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -2,8 +2,8 @@ array.cs: # 2| System.Void ArrayTest.one_dim_init_acc() # 2| Block 0 # 2| v0_0(Void) = EnterFunction : -# 2| mu0_1(null) = AliasedDefinition : -# 2| mu0_2(null) = UnmodeledDefinition : +# 2| mu0_1() = AliasedDefinition : +# 2| mu0_2() = UnmodeledDefinition : # 2| r0_3(glval) = InitializeThis : # 4| r0_4(glval) = VariableAddress[one_dim] : # 4| mu0_5(Int32[]) = Uninitialized[one_dim] : &:r0_4 @@ -58,8 +58,8 @@ array.cs: # 13| System.Void ArrayTest.twod_and_init_acc() # 13| Block 0 # 13| v0_0(Void) = EnterFunction : -# 13| mu0_1(null) = AliasedDefinition : -# 13| mu0_2(null) = UnmodeledDefinition : +# 13| mu0_1() = AliasedDefinition : +# 13| mu0_2() = UnmodeledDefinition : # 13| r0_3(glval) = InitializeThis : # 15| r0_4(glval) = VariableAddress[a] : # 15| mu0_5(Int32[,]) = Uninitialized[a] : &:r0_4 @@ -150,8 +150,8 @@ assignop.cs: # 4| System.Void AssignOp.Main() # 4| Block 0 # 4| v0_0(Void) = EnterFunction : -# 4| mu0_1(null) = AliasedDefinition : -# 4| mu0_2(null) = UnmodeledDefinition : +# 4| mu0_1() = AliasedDefinition : +# 4| mu0_2() = UnmodeledDefinition : # 5| r0_3(glval) = VariableAddress[a] : # 5| r0_4(Int32) = Constant[1] : # 5| mu0_5(Int32) = Store : &:r0_3, r0_4 @@ -221,13 +221,13 @@ casts.cs: # 11| System.Void Casts.Main() # 11| Block 0 # 11| v0_0(Void) = EnterFunction : -# 11| mu0_1(null) = AliasedDefinition : -# 11| mu0_2(null) = UnmodeledDefinition : +# 11| mu0_1() = AliasedDefinition : +# 11| mu0_2() = UnmodeledDefinition : # 13| r0_3(glval) = VariableAddress[Aobj] : # 13| r0_4(Casts_A) = NewObj : -# 13| r0_5(glval) = FunctionAddress[Casts_A] : +# 13| r0_5() = FunctionAddress[Casts_A] : # 13| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 13| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 13| mu0_7() = ^CallSideEffect : ~mu0_2 # 13| mu0_8(Casts_A) = Store : &:r0_3, r0_4 # 14| r0_9(glval) = VariableAddress[bobjCE] : # 14| r0_10(glval) = VariableAddress[Aobj] : @@ -247,19 +247,19 @@ collections.cs: # 11| System.Void Collections.Main() # 11| Block 0 # 11| v0_0(Void) = EnterFunction : -# 11| mu0_1(null) = AliasedDefinition : -# 11| mu0_2(null) = UnmodeledDefinition : +# 11| mu0_1() = AliasedDefinition : +# 11| mu0_2() = UnmodeledDefinition : # 13| r0_3(glval>) = VariableAddress[dict] : # 13| r0_4(Dictionary) = NewObj : -# 13| r0_5(glval) = FunctionAddress[Dictionary] : +# 13| r0_5() = FunctionAddress[Dictionary] : # 13| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 13| mu0_7(null) = ^CallSideEffect : ~mu0_2 -# 15| r0_8(glval) = FunctionAddress[Add] : +# 13| mu0_7() = ^CallSideEffect : ~mu0_2 +# 15| r0_8() = FunctionAddress[Add] : # 15| r0_9(Int32) = Constant[0] : # 15| r0_10(MyClass) = NewObj : -# 15| r0_11(glval) = FunctionAddress[MyClass] : +# 15| r0_11() = FunctionAddress[MyClass] : # 15| v0_12(Void) = Call : func:r0_11, this:r0_10 -# 15| mu0_13(null) = ^CallSideEffect : ~mu0_2 +# 15| mu0_13() = ^CallSideEffect : ~mu0_2 # 15| r0_14(String) = StringConstant["Hello"] : # 15| r0_15(glval) = FieldAddress[a] : r0_10 # 15| mu0_16(String) = Store : &:r0_15, r0_14 @@ -267,13 +267,13 @@ collections.cs: # 15| r0_18(glval) = FieldAddress[b] : r0_10 # 15| mu0_19(String) = Store : &:r0_18, r0_17 # 15| v0_20(Void) = Call : func:r0_8, this:r0_4, 0:r0_9, 1:r0_10 -# 15| mu0_21(null) = ^CallSideEffect : ~mu0_2 -# 16| r0_22(glval) = FunctionAddress[Add] : +# 15| mu0_21() = ^CallSideEffect : ~mu0_2 +# 16| r0_22() = FunctionAddress[Add] : # 16| r0_23(Int32) = Constant[1] : # 16| r0_24(MyClass) = NewObj : -# 16| r0_25(glval) = FunctionAddress[MyClass] : +# 16| r0_25() = FunctionAddress[MyClass] : # 16| v0_26(Void) = Call : func:r0_25, this:r0_24 -# 16| mu0_27(null) = ^CallSideEffect : ~mu0_2 +# 16| mu0_27() = ^CallSideEffect : ~mu0_2 # 16| r0_28(String) = StringConstant["Foo"] : # 16| r0_29(glval) = FieldAddress[a] : r0_24 # 16| mu0_30(String) = Store : &:r0_29, r0_28 @@ -281,7 +281,7 @@ collections.cs: # 16| r0_32(glval) = FieldAddress[b] : r0_24 # 16| mu0_33(String) = Store : &:r0_32, r0_31 # 16| v0_34(Void) = Call : func:r0_22, this:r0_4, 0:r0_23, 1:r0_24 -# 16| mu0_35(null) = ^CallSideEffect : ~mu0_2 +# 16| mu0_35() = ^CallSideEffect : ~mu0_2 # 13| mu0_36(Dictionary) = Store : &:r0_3, r0_4 # 11| v0_37(Void) = ReturnVoid : # 11| v0_38(Void) = UnmodeledUse : mu* @@ -291,8 +291,8 @@ constructor_init.cs: # 5| System.Void BaseClass..ctor() # 5| Block 0 # 5| v0_0(Void) = EnterFunction : -# 5| mu0_1(null) = AliasedDefinition : -# 5| mu0_2(null) = UnmodeledDefinition : +# 5| mu0_1() = AliasedDefinition : +# 5| mu0_2() = UnmodeledDefinition : # 5| r0_3(glval) = InitializeThis : # 6| v0_4(Void) = NoOp : # 5| v0_5(Void) = ReturnVoid : @@ -302,8 +302,8 @@ constructor_init.cs: # 9| System.Void BaseClass..ctor(System.Int32) # 9| Block 0 # 9| v0_0(Void) = EnterFunction : -# 9| mu0_1(null) = AliasedDefinition : -# 9| mu0_2(null) = UnmodeledDefinition : +# 9| mu0_1() = AliasedDefinition : +# 9| mu0_2() = UnmodeledDefinition : # 9| r0_3(glval) = InitializeThis : # 9| r0_4(glval) = VariableAddress[i] : # 9| mu0_5(Int32) = InitializeParameter[i] : &:r0_4 @@ -319,13 +319,13 @@ constructor_init.cs: # 17| System.Void DerivedClass..ctor() # 17| Block 0 # 17| v0_0(Void) = EnterFunction : -# 17| mu0_1(null) = AliasedDefinition : -# 17| mu0_2(null) = UnmodeledDefinition : +# 17| mu0_1() = AliasedDefinition : +# 17| mu0_2() = UnmodeledDefinition : # 17| r0_3(glval) = InitializeThis : # 17| r0_4(glval) = Convert[DerivedClass : BaseClass] : r0_3 -# 17| r0_5(glval) = FunctionAddress[BaseClass] : +# 17| r0_5() = FunctionAddress[BaseClass] : # 17| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 17| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 17| mu0_7() = ^CallSideEffect : ~mu0_2 # 18| v0_8(Void) = NoOp : # 17| v0_9(Void) = ReturnVoid : # 17| v0_10(Void) = UnmodeledUse : mu* @@ -334,17 +334,17 @@ constructor_init.cs: # 21| System.Void DerivedClass..ctor(System.Int32) # 21| Block 0 # 21| v0_0(Void) = EnterFunction : -# 21| mu0_1(null) = AliasedDefinition : -# 21| mu0_2(null) = UnmodeledDefinition : +# 21| mu0_1() = AliasedDefinition : +# 21| mu0_2() = UnmodeledDefinition : # 21| r0_3(glval) = InitializeThis : # 21| r0_4(glval) = VariableAddress[i] : # 21| mu0_5(Int32) = InitializeParameter[i] : &:r0_4 # 21| r0_6(glval) = Convert[DerivedClass : BaseClass] : r0_3 -# 21| r0_7(glval) = FunctionAddress[BaseClass] : +# 21| r0_7() = FunctionAddress[BaseClass] : # 21| r0_8(glval) = VariableAddress[i] : # 21| r0_9(Int32) = Load : &:r0_8, ~mu0_2 # 21| v0_10(Void) = Call : func:r0_7, this:r0_6, 0:r0_9 -# 21| mu0_11(null) = ^CallSideEffect : ~mu0_2 +# 21| mu0_11() = ^CallSideEffect : ~mu0_2 # 22| v0_12(Void) = NoOp : # 21| v0_13(Void) = ReturnVoid : # 21| v0_14(Void) = UnmodeledUse : mu* @@ -353,18 +353,18 @@ constructor_init.cs: # 25| System.Void DerivedClass..ctor(System.Int32,System.Int32) # 25| Block 0 # 25| v0_0(Void) = EnterFunction : -# 25| mu0_1(null) = AliasedDefinition : -# 25| mu0_2(null) = UnmodeledDefinition : +# 25| mu0_1() = AliasedDefinition : +# 25| mu0_2() = UnmodeledDefinition : # 25| r0_3(glval) = InitializeThis : # 25| r0_4(glval) = VariableAddress[i] : # 25| mu0_5(Int32) = InitializeParameter[i] : &:r0_4 # 25| r0_6(glval) = VariableAddress[j] : # 25| mu0_7(Int32) = InitializeParameter[j] : &:r0_6 -# 25| r0_8(glval) = FunctionAddress[DerivedClass] : +# 25| r0_8() = FunctionAddress[DerivedClass] : # 25| r0_9(glval) = VariableAddress[i] : # 25| r0_10(Int32) = Load : &:r0_9, ~mu0_2 # 25| v0_11(Void) = Call : func:r0_8, this:r0_3, 0:r0_10 -# 25| mu0_12(null) = ^CallSideEffect : ~mu0_2 +# 25| mu0_12() = ^CallSideEffect : ~mu0_2 # 26| v0_13(Void) = NoOp : # 25| v0_14(Void) = ReturnVoid : # 25| v0_15(Void) = UnmodeledUse : mu* @@ -373,28 +373,28 @@ constructor_init.cs: # 29| System.Void DerivedClass.Main() # 29| Block 0 # 29| v0_0(Void) = EnterFunction : -# 29| mu0_1(null) = AliasedDefinition : -# 29| mu0_2(null) = UnmodeledDefinition : +# 29| mu0_1() = AliasedDefinition : +# 29| mu0_2() = UnmodeledDefinition : # 31| r0_3(glval) = VariableAddress[obj1] : # 31| r0_4(DerivedClass) = NewObj : -# 31| r0_5(glval) = FunctionAddress[DerivedClass] : +# 31| r0_5() = FunctionAddress[DerivedClass] : # 31| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 31| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 31| mu0_7() = ^CallSideEffect : ~mu0_2 # 31| mu0_8(DerivedClass) = Store : &:r0_3, r0_4 # 32| r0_9(glval) = VariableAddress[obj2] : # 32| r0_10(DerivedClass) = NewObj : -# 32| r0_11(glval) = FunctionAddress[DerivedClass] : +# 32| r0_11() = FunctionAddress[DerivedClass] : # 32| r0_12(Int32) = Constant[1] : # 32| v0_13(Void) = Call : func:r0_11, this:r0_10, 0:r0_12 -# 32| mu0_14(null) = ^CallSideEffect : ~mu0_2 +# 32| mu0_14() = ^CallSideEffect : ~mu0_2 # 32| mu0_15(DerivedClass) = Store : &:r0_9, r0_10 # 33| r0_16(glval) = VariableAddress[obj3] : # 33| r0_17(DerivedClass) = NewObj : -# 33| r0_18(glval) = FunctionAddress[DerivedClass] : +# 33| r0_18() = FunctionAddress[DerivedClass] : # 33| r0_19(Int32) = Constant[1] : # 33| r0_20(Int32) = Constant[2] : # 33| v0_21(Void) = Call : func:r0_18, this:r0_17, 0:r0_19, 1:r0_20 -# 33| mu0_22(null) = ^CallSideEffect : ~mu0_2 +# 33| mu0_22() = ^CallSideEffect : ~mu0_2 # 33| mu0_23(DerivedClass) = Store : &:r0_16, r0_17 # 29| v0_24(Void) = ReturnVoid : # 29| v0_25(Void) = UnmodeledUse : mu* @@ -404,8 +404,8 @@ crement.cs: # 3| System.Void CrementOpsTest.Main() # 3| Block 0 # 3| v0_0(Void) = EnterFunction : -# 3| mu0_1(null) = AliasedDefinition : -# 3| mu0_2(null) = UnmodeledDefinition : +# 3| mu0_1() = AliasedDefinition : +# 3| mu0_2() = UnmodeledDefinition : # 5| r0_3(glval) = VariableAddress[x] : # 5| r0_4(Int32) = Constant[10] : # 5| mu0_5(Int32) = Store : &:r0_3, r0_4 @@ -445,8 +445,8 @@ delegates.cs: # 6| System.Int32 Delegates.returns(System.Int32) # 6| Block 0 # 6| v0_0(Void) = EnterFunction : -# 6| mu0_1(null) = AliasedDefinition : -# 6| mu0_2(null) = UnmodeledDefinition : +# 6| mu0_1() = AliasedDefinition : +# 6| mu0_2() = UnmodeledDefinition : # 6| r0_3(glval) = VariableAddress[ret] : # 6| mu0_4(Int32) = InitializeParameter[ret] : &:r0_3 # 8| r0_5(glval) = VariableAddress[#return] : @@ -460,32 +460,32 @@ delegates.cs: # 11| System.Void Delegates.Main() # 11| Block 0 -# 11| v0_0(Void) = EnterFunction : -# 11| mu0_1(null) = AliasedDefinition : -# 11| mu0_2(null) = UnmodeledDefinition : -# 12| r0_3(glval) = VariableAddress[del1] : -# 12| r0_4(Del) = NewObj : -# 12| r0_5(glval) = FunctionAddress[Del] : -# 12| r0_6(glval) = FunctionAddress[returns] : -# 12| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6 -# 12| mu0_8(null) = ^CallSideEffect : ~mu0_2 -# 12| mu0_9(Del) = Store : &:r0_3, r0_4 -# 13| r0_10(glval) = VariableAddress[del1] : -# 13| r0_11(Del) = Load : &:r0_10, ~mu0_2 -# 13| r0_12(glval) = FunctionAddress[Invoke] : -# 13| r0_13(Int32) = Constant[5] : -# 13| v0_14(Void) = Call : func:r0_12, this:r0_11, 0:r0_13 -# 13| mu0_15(null) = ^CallSideEffect : ~mu0_2 -# 11| v0_16(Void) = ReturnVoid : -# 11| v0_17(Void) = UnmodeledUse : mu* -# 11| v0_18(Void) = ExitFunction : +# 11| v0_0(Void) = EnterFunction : +# 11| mu0_1() = AliasedDefinition : +# 11| mu0_2() = UnmodeledDefinition : +# 12| r0_3(glval) = VariableAddress[del1] : +# 12| r0_4(Del) = NewObj : +# 12| r0_5() = FunctionAddress[Del] : +# 12| r0_6(glval) = FunctionAddress[returns] : +# 12| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6 +# 12| mu0_8() = ^CallSideEffect : ~mu0_2 +# 12| mu0_9(Del) = Store : &:r0_3, r0_4 +# 13| r0_10(glval) = VariableAddress[del1] : +# 13| r0_11(Del) = Load : &:r0_10, ~mu0_2 +# 13| r0_12() = FunctionAddress[Invoke] : +# 13| r0_13(Int32) = Constant[5] : +# 13| v0_14(Void) = Call : func:r0_12, this:r0_11, 0:r0_13 +# 13| mu0_15() = ^CallSideEffect : ~mu0_2 +# 11| v0_16(Void) = ReturnVoid : +# 11| v0_17(Void) = UnmodeledUse : mu* +# 11| v0_18(Void) = ExitFunction : foreach.cs: # 4| System.Void ForEach.Main() # 4| Block 0 # 4| v0_0(Void) = EnterFunction : -# 4| mu0_1(null) = AliasedDefinition : -# 4| mu0_2(null) = UnmodeledDefinition : +# 4| mu0_1() = AliasedDefinition : +# 4| mu0_2() = UnmodeledDefinition : # 5| r0_3(glval) = VariableAddress[a_array] : # 5| mu0_4(Int32[]) = Uninitialized[a_array] : &:r0_3 # 5| r0_5(Int32) = Constant[0] : @@ -519,18 +519,18 @@ foreach.cs: # 7| r0_33(glval) = VariableAddress[#temp7:9] : # 7| r0_34(glval) = VariableAddress[a_array] : # 7| r0_35(Int32[]) = Load : &:r0_34, ~mu0_2 -# 7| r0_36(glval) = FunctionAddress[GetEnumerator] : +# 7| r0_36() = FunctionAddress[GetEnumerator] : # 7| r0_37(IEnumerator) = Call : func:r0_36, this:r0_35 -# 7| mu0_38(null) = ^CallSideEffect : ~mu0_2 +# 7| mu0_38() = ^CallSideEffect : ~mu0_2 # 7| mu0_39(IEnumerator) = Store : &:r0_33, r0_37 #-----| Goto -> Block 1 # 7| Block 1 # 7| r1_0(glval) = VariableAddress[#temp7:9] : # 7| r1_1(Boolean) = Load : &:r1_0, ~mu0_2 -# 7| r1_2(glval) = FunctionAddress[MoveNext] : +# 7| r1_2() = FunctionAddress[MoveNext] : # 7| r1_3(Boolean) = Call : func:r1_2, this:r1_1 -# 7| mu1_4(null) = ^CallSideEffect : ~mu0_2 +# 7| mu1_4() = ^CallSideEffect : ~mu0_2 # 7| v1_5(Void) = ConditionalBranch : r1_3 #-----| False -> Block 3 #-----| True -> Block 2 @@ -539,9 +539,9 @@ foreach.cs: # 7| r2_0(glval) = VariableAddress[items] : # 7| r2_1(glval) = VariableAddress[#temp7:9] : # 7| r2_2(Boolean) = Load : &:r2_1, ~mu0_2 -# 7| r2_3(glval) = FunctionAddress[get_Current] : +# 7| r2_3() = FunctionAddress[get_Current] : # 7| r2_4(Int32) = Call : func:r2_3, this:r2_2 -# 7| mu2_5(null) = ^CallSideEffect : ~mu0_2 +# 7| mu2_5() = ^CallSideEffect : ~mu0_2 # 7| mu2_6(Int32) = Store : &:r2_0, r2_4 # 9| r2_7(glval) = VariableAddress[x] : # 9| r2_8(glval) = VariableAddress[items] : @@ -552,9 +552,9 @@ foreach.cs: # 7| Block 3 # 7| r3_0(glval) = VariableAddress[#temp7:9] : # 7| r3_1(Boolean) = Load : &:r3_0, ~mu0_2 -# 7| r3_2(glval) = FunctionAddress[Dispose] : +# 7| r3_2() = FunctionAddress[Dispose] : # 7| v3_3(Void) = Call : func:r3_2, this:r3_1 -# 7| mu3_4(null) = ^CallSideEffect : ~mu0_2 +# 7| mu3_4() = ^CallSideEffect : ~mu0_2 # 4| v3_5(Void) = ReturnVoid : # 4| v3_6(Void) = UnmodeledUse : mu* # 4| v3_7(Void) = ExitFunction : @@ -563,8 +563,8 @@ func_with_param_call.cs: # 5| System.Int32 test_call_with_param.f(System.Int32,System.Int32) # 5| Block 0 # 5| v0_0(Void) = EnterFunction : -# 5| mu0_1(null) = AliasedDefinition : -# 5| mu0_2(null) = UnmodeledDefinition : +# 5| mu0_1() = AliasedDefinition : +# 5| mu0_2() = UnmodeledDefinition : # 5| r0_3(glval) = VariableAddress[x] : # 5| mu0_4(Int32) = InitializeParameter[x] : &:r0_3 # 5| r0_5(glval) = VariableAddress[y] : @@ -584,14 +584,14 @@ func_with_param_call.cs: # 10| System.Int32 test_call_with_param.g() # 10| Block 0 # 10| v0_0(Void) = EnterFunction : -# 10| mu0_1(null) = AliasedDefinition : -# 10| mu0_2(null) = UnmodeledDefinition : +# 10| mu0_1() = AliasedDefinition : +# 10| mu0_2() = UnmodeledDefinition : # 12| r0_3(glval) = VariableAddress[#return] : -# 12| r0_4(glval) = FunctionAddress[f] : +# 12| r0_4() = FunctionAddress[f] : # 12| r0_5(Int32) = Constant[2] : # 12| r0_6(Int32) = Constant[3] : # 12| r0_7(Int32) = Call : func:r0_4, 0:r0_5, 1:r0_6 -# 12| mu0_8(null) = ^CallSideEffect : ~mu0_2 +# 12| mu0_8() = ^CallSideEffect : ~mu0_2 # 12| mu0_9(Int32) = Store : &:r0_3, r0_7 # 10| r0_10(glval) = VariableAddress[#return] : # 10| v0_11(Void) = ReturnValue : &:r0_10, ~mu0_2 @@ -602,8 +602,8 @@ inheritance_polymorphism.cs: # 3| System.Int32 A.function() # 3| Block 0 # 3| v0_0(Void) = EnterFunction : -# 3| mu0_1(null) = AliasedDefinition : -# 3| mu0_2(null) = UnmodeledDefinition : +# 3| mu0_1() = AliasedDefinition : +# 3| mu0_2() = UnmodeledDefinition : # 3| r0_3(glval) = InitializeThis : # 5| r0_4(glval) = VariableAddress[#return] : # 5| r0_5(Int32) = Constant[0] : @@ -616,8 +616,8 @@ inheritance_polymorphism.cs: # 15| System.Int32 C.function() # 15| Block 0 # 15| v0_0(Void) = EnterFunction : -# 15| mu0_1(null) = AliasedDefinition : -# 15| mu0_2(null) = UnmodeledDefinition : +# 15| mu0_1() = AliasedDefinition : +# 15| mu0_2() = UnmodeledDefinition : # 15| r0_3(glval) = InitializeThis : # 17| r0_4(glval) = VariableAddress[#return] : # 17| r0_5(Int32) = Constant[1] : @@ -629,54 +629,54 @@ inheritance_polymorphism.cs: # 23| System.Void Program.Main() # 23| Block 0 -# 23| v0_0(Void) = EnterFunction : -# 23| mu0_1(null) = AliasedDefinition : -# 23| mu0_2(null) = UnmodeledDefinition : -# 25| r0_3(glval) = VariableAddress[objB] : -# 25| r0_4(B) = NewObj : -# 25| r0_5(glval) = FunctionAddress[B] : -# 25| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 25| mu0_7(null) = ^CallSideEffect : ~mu0_2 -# 25| mu0_8(B) = Store : &:r0_3, r0_4 -# 26| r0_9(glval) = VariableAddress[objB] : -# 26| r0_10(B) = Load : &:r0_9, ~mu0_2 -# 26| r0_11(glval) = FunctionAddress[function] : -# 26| r0_12(Int32) = Call : func:r0_11, this:r0_10 -# 26| mu0_13(null) = ^CallSideEffect : ~mu0_2 -# 29| r0_14(glval) = VariableAddress[objA] : -# 29| mu0_15(A) = Uninitialized[objA] : &:r0_14 -# 30| r0_16(glval) = VariableAddress[objB] : -# 30| r0_17(B) = Load : &:r0_16, ~mu0_2 -# 30| r0_18(A) = Convert : r0_17 -# 30| r0_19(glval) = VariableAddress[objA] : -# 30| mu0_20(A) = Store : &:r0_19, r0_18 -# 31| r0_21(glval) = VariableAddress[objA] : -# 31| r0_22(A) = Load : &:r0_21, ~mu0_2 -# 31| r0_23(glval) = FunctionAddress[function] : -# 31| r0_24(Int32) = Call : func:r0_23, this:r0_22 -# 31| mu0_25(null) = ^CallSideEffect : ~mu0_2 -# 33| r0_26(glval) = VariableAddress[objC] : -# 33| r0_27(C) = NewObj : -# 33| r0_28(glval) = FunctionAddress[C] : -# 33| v0_29(Void) = Call : func:r0_28, this:r0_27 -# 33| mu0_30(null) = ^CallSideEffect : ~mu0_2 -# 33| r0_31(A) = Convert : r0_27 -# 33| mu0_32(A) = Store : &:r0_26, r0_27 -# 34| r0_33(glval) = VariableAddress[objC] : -# 34| r0_34(A) = Load : &:r0_33, ~mu0_2 -# 34| r0_35(glval) = FunctionAddress[function] : -# 34| r0_36(Int32) = Call : func:r0_35, this:r0_34 -# 34| mu0_37(null) = ^CallSideEffect : ~mu0_2 -# 23| v0_38(Void) = ReturnVoid : -# 23| v0_39(Void) = UnmodeledUse : mu* -# 23| v0_40(Void) = ExitFunction : +# 23| v0_0(Void) = EnterFunction : +# 23| mu0_1() = AliasedDefinition : +# 23| mu0_2() = UnmodeledDefinition : +# 25| r0_3(glval) = VariableAddress[objB] : +# 25| r0_4(B) = NewObj : +# 25| r0_5() = FunctionAddress[B] : +# 25| v0_6(Void) = Call : func:r0_5, this:r0_4 +# 25| mu0_7() = ^CallSideEffect : ~mu0_2 +# 25| mu0_8(B) = Store : &:r0_3, r0_4 +# 26| r0_9(glval) = VariableAddress[objB] : +# 26| r0_10(B) = Load : &:r0_9, ~mu0_2 +# 26| r0_11() = FunctionAddress[function] : +# 26| r0_12(Int32) = Call : func:r0_11, this:r0_10 +# 26| mu0_13() = ^CallSideEffect : ~mu0_2 +# 29| r0_14(glval) = VariableAddress[objA] : +# 29| mu0_15(A) = Uninitialized[objA] : &:r0_14 +# 30| r0_16(glval) = VariableAddress[objB] : +# 30| r0_17(B) = Load : &:r0_16, ~mu0_2 +# 30| r0_18(A) = Convert : r0_17 +# 30| r0_19(glval) = VariableAddress[objA] : +# 30| mu0_20(A) = Store : &:r0_19, r0_18 +# 31| r0_21(glval) = VariableAddress[objA] : +# 31| r0_22(A) = Load : &:r0_21, ~mu0_2 +# 31| r0_23() = FunctionAddress[function] : +# 31| r0_24(Int32) = Call : func:r0_23, this:r0_22 +# 31| mu0_25() = ^CallSideEffect : ~mu0_2 +# 33| r0_26(glval) = VariableAddress[objC] : +# 33| r0_27(C) = NewObj : +# 33| r0_28() = FunctionAddress[C] : +# 33| v0_29(Void) = Call : func:r0_28, this:r0_27 +# 33| mu0_30() = ^CallSideEffect : ~mu0_2 +# 33| r0_31(A) = Convert : r0_27 +# 33| mu0_32(A) = Store : &:r0_26, r0_27 +# 34| r0_33(glval) = VariableAddress[objC] : +# 34| r0_34(A) = Load : &:r0_33, ~mu0_2 +# 34| r0_35() = FunctionAddress[function] : +# 34| r0_36(Int32) = Call : func:r0_35, this:r0_34 +# 34| mu0_37() = ^CallSideEffect : ~mu0_2 +# 23| v0_38(Void) = ReturnVoid : +# 23| v0_39(Void) = UnmodeledUse : mu* +# 23| v0_40(Void) = ExitFunction : inoutref.cs: # 11| System.Void InOutRef.set(MyClass,MyClass) # 11| Block 0 # 11| v0_0(Void) = EnterFunction : -# 11| mu0_1(null) = AliasedDefinition : -# 11| mu0_2(null) = UnmodeledDefinition : +# 11| mu0_1() = AliasedDefinition : +# 11| mu0_2() = UnmodeledDefinition : # 11| r0_3(glval) = VariableAddress[o1] : # 11| mu0_4(MyClass) = InitializeParameter[o1] : &:r0_3 # 11| r0_5(glval) = VariableAddress[o2] : @@ -693,8 +693,8 @@ inoutref.cs: # 16| System.Void InOutRef.F(System.Int32,MyStruct,MyStruct,MyClass,MyClass) # 16| Block 0 # 16| v0_0(Void) = EnterFunction : -# 16| mu0_1(null) = AliasedDefinition : -# 16| mu0_2(null) = UnmodeledDefinition : +# 16| mu0_1() = AliasedDefinition : +# 16| mu0_2() = UnmodeledDefinition : # 16| r0_3(glval) = VariableAddress[a] : # 16| mu0_4(Int32) = InitializeParameter[a] : &:r0_3 # 16| r0_5(glval) = VariableAddress[b] : @@ -737,14 +737,14 @@ inoutref.cs: # 24| r0_42(glval) = VariableAddress[b] : # 24| r0_43(MyStruct) = Load : &:r0_42, ~mu0_2 # 24| mu0_44(MyStruct) = Store : &:r0_43, r0_41 -# 26| r0_45(glval) = FunctionAddress[set] : +# 26| r0_45() = FunctionAddress[set] : # 26| r0_46(glval) = VariableAddress[c] : # 26| r0_47(MyClass) = Load : &:r0_46, ~mu0_2 # 26| r0_48(glval) = VariableAddress[c1] : # 26| r0_49(MyClass) = Load : &:r0_48, ~mu0_2 # 26| r0_50(MyClass) = Load : &:r0_49, ~mu0_2 # 26| v0_51(Void) = Call : func:r0_45, 0:r0_47, 1:r0_50 -# 26| mu0_52(null) = ^CallSideEffect : ~mu0_2 +# 26| mu0_52() = ^CallSideEffect : ~mu0_2 # 16| v0_53(Void) = ReturnVoid : # 16| v0_54(Void) = UnmodeledUse : mu* # 16| v0_55(Void) = ExitFunction : @@ -752,32 +752,32 @@ inoutref.cs: # 29| System.Void InOutRef.Main() # 29| Block 0 # 29| v0_0(Void) = EnterFunction : -# 29| mu0_1(null) = AliasedDefinition : -# 29| mu0_2(null) = UnmodeledDefinition : +# 29| mu0_1() = AliasedDefinition : +# 29| mu0_2() = UnmodeledDefinition : # 31| r0_3(glval) = VariableAddress[a] : # 31| r0_4(Int32) = Constant[0] : # 31| mu0_5(Int32) = Store : &:r0_3, r0_4 # 32| r0_6(glval) = VariableAddress[b] : # 32| r0_7(MyStruct) = NewObj : -# 32| r0_8(glval) = FunctionAddress[MyStruct] : +# 32| r0_8() = FunctionAddress[MyStruct] : # 32| v0_9(Void) = Call : func:r0_8, this:r0_7 -# 32| mu0_10(null) = ^CallSideEffect : ~mu0_2 +# 32| mu0_10() = ^CallSideEffect : ~mu0_2 # 32| r0_11(MyStruct) = Load : &:r0_7, ~mu0_2 # 32| mu0_12(MyStruct) = Store : &:r0_6, r0_11 # 33| r0_13(glval) = VariableAddress[c] : # 33| r0_14(MyClass) = NewObj : -# 33| r0_15(glval) = FunctionAddress[MyClass] : +# 33| r0_15() = FunctionAddress[MyClass] : # 33| v0_16(Void) = Call : func:r0_15, this:r0_14 -# 33| mu0_17(null) = ^CallSideEffect : ~mu0_2 +# 33| mu0_17() = ^CallSideEffect : ~mu0_2 # 33| mu0_18(MyClass) = Store : &:r0_13, r0_14 -# 34| r0_19(glval) = FunctionAddress[F] : +# 34| r0_19() = FunctionAddress[F] : # 34| r0_20(glval) = VariableAddress[a] : # 34| r0_21(glval) = VariableAddress[b] : # 34| r0_22(glval) = VariableAddress[b] : # 34| r0_23(glval) = VariableAddress[c] : # 34| r0_24(glval) = VariableAddress[c] : # 34| v0_25(Void) = Call : func:r0_19, 0:r0_20, 1:r0_21, 2:r0_22, 3:r0_23, 4:r0_24 -# 34| mu0_26(null) = ^CallSideEffect : ~mu0_2 +# 34| mu0_26() = ^CallSideEffect : ~mu0_2 # 36| r0_27(glval) = VariableAddress[x] : # 36| r0_28(glval) = VariableAddress[b] : # 36| r0_29(glval) = FieldAddress[fld] : r0_28 @@ -791,8 +791,8 @@ isexpr.cs: # 8| System.Void IsExpr.Main() # 8| Block 0 # 8| v0_0(Void) = EnterFunction : -# 8| mu0_1(null) = AliasedDefinition : -# 8| mu0_2(null) = UnmodeledDefinition : +# 8| mu0_1() = AliasedDefinition : +# 8| mu0_2() = UnmodeledDefinition : # 10| r0_3(glval) = VariableAddress[obj] : # 10| r0_4(null) = Constant[null] : # 10| r0_5(Is_A) = Convert : r0_4 @@ -853,8 +853,8 @@ jumps.cs: # 5| System.Void Jumps.Main() # 5| Block 0 # 5| v0_0(Void) = EnterFunction : -# 5| mu0_1(null) = AliasedDefinition : -# 5| mu0_2(null) = UnmodeledDefinition : +# 5| mu0_1() = AliasedDefinition : +# 5| mu0_2() = UnmodeledDefinition : # 7| r0_3(glval) = VariableAddress[i] : # 7| r0_4(Int32) = Constant[1] : # 7| mu0_5(Int32) = Store : &:r0_3, r0_4 @@ -896,10 +896,10 @@ jumps.cs: #-----| Goto -> Block 7 # 13| Block 6 -# 13| r6_0(glval) = FunctionAddress[WriteLine] : -# 13| r6_1(String) = StringConstant["BreakAndContinue"] : -# 13| v6_2(Void) = Call : func:r6_0, 0:r6_1 -# 13| mu6_3(null) = ^CallSideEffect : ~mu0_2 +# 13| r6_0() = FunctionAddress[WriteLine] : +# 13| r6_1(String) = StringConstant["BreakAndContinue"] : +# 13| v6_2(Void) = Call : func:r6_0, 0:r6_1 +# 13| mu6_3() = ^CallSideEffect : ~mu0_2 #-----| Goto -> Block 19 # 16| Block 7 @@ -1014,26 +1014,26 @@ jumps.cs: #-----| Goto -> Block 22 # 37| Block 22 -# 37| v22_0(Void) = NoOp : -# 38| r22_1(glval) = FunctionAddress[WriteLine] : -# 38| r22_2(String) = StringConstant["Done"] : -# 38| v22_3(Void) = Call : func:r22_1, 0:r22_2 -# 38| mu22_4(null) = ^CallSideEffect : ~mu0_2 -# 5| v22_5(Void) = ReturnVoid : -# 5| v22_6(Void) = UnmodeledUse : mu* -# 5| v22_7(Void) = ExitFunction : +# 37| v22_0(Void) = NoOp : +# 38| r22_1() = FunctionAddress[WriteLine] : +# 38| r22_2(String) = StringConstant["Done"] : +# 38| v22_3(Void) = Call : func:r22_1, 0:r22_2 +# 38| mu22_4() = ^CallSideEffect : ~mu0_2 +# 5| v22_5(Void) = ReturnVoid : +# 5| v22_6(Void) = UnmodeledUse : mu* +# 5| v22_7(Void) = ExitFunction : lock.cs: # 5| System.Void LockTest.A() # 5| Block 0 # 5| v0_0(Void) = EnterFunction : -# 5| mu0_1(null) = AliasedDefinition : -# 5| mu0_2(null) = UnmodeledDefinition : +# 5| mu0_1() = AliasedDefinition : +# 5| mu0_2() = UnmodeledDefinition : # 7| r0_3(glval) = VariableAddress[object] : # 7| r0_4(Object) = NewObj : -# 7| r0_5(glval) = FunctionAddress[Object] : +# 7| r0_5() = FunctionAddress[Object] : # 7| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 7| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 7| mu0_7() = ^CallSideEffect : ~mu0_2 # 7| mu0_8(Object) = Store : &:r0_3, r0_4 # 8| r0_9(glval) = VariableAddress[#temp8:9] : # 8| r0_10(glval) = VariableAddress[object] : @@ -1042,20 +1042,20 @@ lock.cs: # 8| r0_13(glval) = VariableAddress[#temp8:9] : # 8| r0_14(Boolean) = Constant[false] : # 8| mu0_15(Boolean) = Store : &:r0_13, r0_14 -# 8| r0_16(glval) = FunctionAddress[Enter] : +# 8| r0_16() = FunctionAddress[Enter] : # 8| r0_17(glval) = VariableAddress[#temp8:9] : # 8| r0_18(Object) = Load : &:r0_17, ~mu0_2 # 8| r0_19(glval) = VariableAddress[#temp8:9] : # 8| v0_20(Void) = Call : func:r0_16, 0:r0_18, 1:r0_19 -# 8| mu0_21(null) = ^CallSideEffect : ~mu0_2 -# 10| r0_22(glval) = FunctionAddress[WriteLine] : +# 8| mu0_21() = ^CallSideEffect : ~mu0_2 +# 10| r0_22() = FunctionAddress[WriteLine] : # 10| r0_23(glval) = VariableAddress[object] : # 10| r0_24(Object) = Load : &:r0_23, ~mu0_2 -# 10| r0_25(glval) = FunctionAddress[ToString] : +# 10| r0_25() = FunctionAddress[ToString] : # 10| r0_26(String) = Call : func:r0_25, this:r0_24 -# 10| mu0_27(null) = ^CallSideEffect : ~mu0_2 +# 10| mu0_27() = ^CallSideEffect : ~mu0_2 # 10| v0_28(Void) = Call : func:r0_22, 0:r0_26 -# 10| mu0_29(null) = ^CallSideEffect : ~mu0_2 +# 10| mu0_29() = ^CallSideEffect : ~mu0_2 # 8| r0_30(glval) = VariableAddress[#temp8:9] : # 8| r0_31(Boolean) = Load : &:r0_30, ~mu0_2 # 8| v0_32(Void) = ConditionalBranch : r0_31 @@ -1068,19 +1068,19 @@ lock.cs: # 5| v1_2(Void) = ExitFunction : # 8| Block 2 -# 8| r2_0(glval) = FunctionAddress[Exit] : +# 8| r2_0() = FunctionAddress[Exit] : # 8| r2_1(glval) = VariableAddress[#temp8:9] : # 8| r2_2(Object) = Load : &:r2_1, ~mu0_2 # 8| v2_3(Void) = Call : func:r2_0, 0:r2_2 -# 8| mu2_4(null) = ^CallSideEffect : ~mu0_2 +# 8| mu2_4() = ^CallSideEffect : ~mu0_2 #-----| Goto -> Block 1 obj_creation.cs: # 7| System.Void ObjCreation.MyClass..ctor() # 7| Block 0 # 7| v0_0(Void) = EnterFunction : -# 7| mu0_1(null) = AliasedDefinition : -# 7| mu0_2(null) = UnmodeledDefinition : +# 7| mu0_1() = AliasedDefinition : +# 7| mu0_2() = UnmodeledDefinition : # 7| r0_3(glval) = InitializeThis : # 8| v0_4(Void) = NoOp : # 7| v0_5(Void) = ReturnVoid : @@ -1090,8 +1090,8 @@ obj_creation.cs: # 11| System.Void ObjCreation.MyClass..ctor(System.Int32) # 11| Block 0 # 11| v0_0(Void) = EnterFunction : -# 11| mu0_1(null) = AliasedDefinition : -# 11| mu0_2(null) = UnmodeledDefinition : +# 11| mu0_1() = AliasedDefinition : +# 11| mu0_2() = UnmodeledDefinition : # 11| r0_3(glval) = InitializeThis : # 11| r0_4(glval) = VariableAddress[_x] : # 11| mu0_5(Int32) = InitializeParameter[_x] : &:r0_4 @@ -1107,8 +1107,8 @@ obj_creation.cs: # 17| System.Void ObjCreation.SomeFun(ObjCreation.MyClass) # 17| Block 0 # 17| v0_0(Void) = EnterFunction : -# 17| mu0_1(null) = AliasedDefinition : -# 17| mu0_2(null) = UnmodeledDefinition : +# 17| mu0_1() = AliasedDefinition : +# 17| mu0_2() = UnmodeledDefinition : # 17| r0_3(glval) = VariableAddress[x] : # 17| mu0_4(MyClass) = InitializeParameter[x] : &:r0_3 # 18| v0_5(Void) = NoOp : @@ -1119,20 +1119,20 @@ obj_creation.cs: # 21| System.Void ObjCreation.Main() # 21| Block 0 # 21| v0_0(Void) = EnterFunction : -# 21| mu0_1(null) = AliasedDefinition : -# 21| mu0_2(null) = UnmodeledDefinition : +# 21| mu0_1() = AliasedDefinition : +# 21| mu0_2() = UnmodeledDefinition : # 23| r0_3(glval) = VariableAddress[obj] : # 23| r0_4(MyClass) = NewObj : -# 23| r0_5(glval) = FunctionAddress[MyClass] : +# 23| r0_5() = FunctionAddress[MyClass] : # 23| r0_6(Int32) = Constant[100] : # 23| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6 -# 23| mu0_8(null) = ^CallSideEffect : ~mu0_2 +# 23| mu0_8() = ^CallSideEffect : ~mu0_2 # 23| mu0_9(MyClass) = Store : &:r0_3, r0_4 # 24| r0_10(glval) = VariableAddress[obj_initlist] : # 24| r0_11(MyClass) = NewObj : -# 24| r0_12(glval) = FunctionAddress[MyClass] : +# 24| r0_12() = FunctionAddress[MyClass] : # 24| v0_13(Void) = Call : func:r0_12, this:r0_11 -# 24| mu0_14(null) = ^CallSideEffect : ~mu0_2 +# 24| mu0_14() = ^CallSideEffect : ~mu0_2 # 24| r0_15(Int32) = Constant[101] : # 24| r0_16(glval) = FieldAddress[x] : r0_11 # 24| mu0_17(Int32) = Store : &:r0_16, r0_15 @@ -1143,14 +1143,14 @@ obj_creation.cs: # 25| r0_22(glval) = FieldAddress[x] : r0_21 # 25| r0_23(Int32) = Load : &:r0_22, ~mu0_2 # 25| mu0_24(Int32) = Store : &:r0_19, r0_23 -# 27| r0_25(glval) = FunctionAddress[SomeFun] : +# 27| r0_25() = FunctionAddress[SomeFun] : # 27| r0_26(MyClass) = NewObj : -# 27| r0_27(glval) = FunctionAddress[MyClass] : +# 27| r0_27() = FunctionAddress[MyClass] : # 27| r0_28(Int32) = Constant[100] : # 27| v0_29(Void) = Call : func:r0_27, this:r0_26, 0:r0_28 -# 27| mu0_30(null) = ^CallSideEffect : ~mu0_2 +# 27| mu0_30() = ^CallSideEffect : ~mu0_2 # 27| v0_31(Void) = Call : func:r0_25, 0:r0_26 -# 27| mu0_32(null) = ^CallSideEffect : ~mu0_2 +# 27| mu0_32() = ^CallSideEffect : ~mu0_2 # 21| v0_33(Void) = ReturnVoid : # 21| v0_34(Void) = UnmodeledUse : mu* # 21| v0_35(Void) = ExitFunction : @@ -1159,16 +1159,16 @@ pointers.cs: # 3| System.Void Pointers.addone(System.Int32[]) # 3| Block 0 # 3| v0_0(Void) = EnterFunction : -# 3| mu0_1(null) = AliasedDefinition : -# 3| mu0_2(null) = UnmodeledDefinition : +# 3| mu0_1() = AliasedDefinition : +# 3| mu0_2() = UnmodeledDefinition : # 3| r0_3(glval) = VariableAddress[arr] : # 3| mu0_4(Int32[]) = InitializeParameter[arr] : &:r0_3 # 5| r0_5(glval) = VariableAddress[length] : # 5| r0_6(glval) = VariableAddress[arr] : # 5| r0_7(Int32[]) = Load : &:r0_6, ~mu0_2 -# 5| r0_8(glval) = FunctionAddress[get_Length] : +# 5| r0_8() = FunctionAddress[get_Length] : # 5| r0_9(Int32) = Call : func:r0_8, this:r0_7 -# 5| mu0_10(null) = ^CallSideEffect : ~mu0_2 +# 5| mu0_10() = ^CallSideEffect : ~mu0_2 # 5| mu0_11(Int32) = Store : &:r0_5, r0_9 # 6| r0_12(glval) = VariableAddress[b] : # 6| r0_13(glval) = VariableAddress[arr] : @@ -1219,19 +1219,19 @@ pointers.cs: # 25| System.Void Pointers.Main() # 25| Block 0 # 25| v0_0(Void) = EnterFunction : -# 25| mu0_1(null) = AliasedDefinition : -# 25| mu0_2(null) = UnmodeledDefinition : +# 25| mu0_1() = AliasedDefinition : +# 25| mu0_2() = UnmodeledDefinition : # 26| r0_3(glval) = VariableAddress[o] : # 26| r0_4(MyClass) = NewObj : -# 26| r0_5(glval) = FunctionAddress[MyClass] : +# 26| r0_5() = FunctionAddress[MyClass] : # 26| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 26| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 26| mu0_7() = ^CallSideEffect : ~mu0_2 # 26| mu0_8(MyClass) = Store : &:r0_3, r0_4 # 27| r0_9(glval) = VariableAddress[s] : # 27| r0_10(MyStruct) = NewObj : -# 27| r0_11(glval) = FunctionAddress[MyStruct] : +# 27| r0_11() = FunctionAddress[MyStruct] : # 27| v0_12(Void) = Call : func:r0_11, this:r0_10 -# 27| mu0_13(null) = ^CallSideEffect : ~mu0_2 +# 27| mu0_13() = ^CallSideEffect : ~mu0_2 # 27| r0_14(MyStruct) = Load : &:r0_10, ~mu0_2 # 27| mu0_15(MyStruct) = Store : &:r0_9, r0_14 # 30| r0_16(glval) = VariableAddress[p] : @@ -1275,11 +1275,11 @@ pointers.cs: # 39| r0_54(glval) = PointerAdd[4] : r0_43, r0_53 # 39| r0_55(Int32) = Constant[3] : # 39| mu0_56(Int32) = Store : &:r0_54, r0_55 -# 40| r0_57(glval) = FunctionAddress[addone] : +# 40| r0_57() = FunctionAddress[addone] : # 40| r0_58(glval) = VariableAddress[arr] : # 40| r0_59(Int32[]) = Load : &:r0_58, ~mu0_2 # 40| v0_60(Void) = Call : func:r0_57, 0:r0_59 -# 40| mu0_61(null) = ^CallSideEffect : ~mu0_2 +# 40| mu0_61() = ^CallSideEffect : ~mu0_2 # 25| v0_62(Void) = ReturnVoid : # 25| v0_63(Void) = UnmodeledUse : mu* # 25| v0_64(Void) = ExitFunction : @@ -1288,14 +1288,14 @@ prop.cs: # 7| System.Int32 PropClass.get_Prop() # 7| Block 0 # 7| v0_0(Void) = EnterFunction : -# 7| mu0_1(null) = AliasedDefinition : -# 7| mu0_2(null) = UnmodeledDefinition : +# 7| mu0_1() = AliasedDefinition : +# 7| mu0_2() = UnmodeledDefinition : # 7| r0_3(glval) = InitializeThis : # 9| r0_4(glval) = VariableAddress[#return] : # 9| r0_5(PropClass) = CopyValue : r0_3 -# 9| r0_6(glval) = FunctionAddress[func] : +# 9| r0_6() = FunctionAddress[func] : # 9| r0_7(Int32) = Call : func:r0_6, this:r0_5 -# 9| mu0_8(null) = ^CallSideEffect : ~mu0_2 +# 9| mu0_8() = ^CallSideEffect : ~mu0_2 # 9| mu0_9(Int32) = Store : &:r0_4, r0_7 # 7| r0_10(glval) = VariableAddress[#return] : # 7| v0_11(Void) = ReturnValue : &:r0_10, ~mu0_2 @@ -1305,8 +1305,8 @@ prop.cs: # 12| System.Void PropClass.set_Prop(System.Int32) # 12| Block 0 # 12| v0_0(Void) = EnterFunction : -# 12| mu0_1(null) = AliasedDefinition : -# 12| mu0_2(null) = UnmodeledDefinition : +# 12| mu0_1() = AliasedDefinition : +# 12| mu0_2() = UnmodeledDefinition : # 12| r0_3(glval) = InitializeThis : # 12| r0_4(glval) = VariableAddress[value] : # 12| mu0_5(Int32) = InitializeParameter[value] : &:r0_4 @@ -1322,8 +1322,8 @@ prop.cs: # 18| System.Int32 PropClass.func() # 18| Block 0 # 18| v0_0(Void) = EnterFunction : -# 18| mu0_1(null) = AliasedDefinition : -# 18| mu0_2(null) = UnmodeledDefinition : +# 18| mu0_1() = AliasedDefinition : +# 18| mu0_2() = UnmodeledDefinition : # 18| r0_3(glval) = InitializeThis : # 20| r0_4(glval) = VariableAddress[#return] : # 20| r0_5(Int32) = Constant[0] : @@ -1336,26 +1336,26 @@ prop.cs: # 26| System.Void Prog.Main() # 26| Block 0 # 26| v0_0(Void) = EnterFunction : -# 26| mu0_1(null) = AliasedDefinition : -# 26| mu0_2(null) = UnmodeledDefinition : +# 26| mu0_1() = AliasedDefinition : +# 26| mu0_2() = UnmodeledDefinition : # 28| r0_3(glval) = VariableAddress[obj] : # 28| r0_4(PropClass) = NewObj : -# 28| r0_5(glval) = FunctionAddress[PropClass] : +# 28| r0_5() = FunctionAddress[PropClass] : # 28| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 28| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 28| mu0_7() = ^CallSideEffect : ~mu0_2 # 28| mu0_8(PropClass) = Store : &:r0_3, r0_4 # 29| r0_9(glval) = VariableAddress[obj] : # 29| r0_10(PropClass) = Load : &:r0_9, ~mu0_2 -# 29| r0_11(glval) = FunctionAddress[set_Prop] : +# 29| r0_11() = FunctionAddress[set_Prop] : # 29| r0_12(Int32) = Constant[5] : # 29| v0_13(Void) = Call : func:r0_11, this:r0_10, 0:r0_12 -# 29| mu0_14(null) = ^CallSideEffect : ~mu0_2 +# 29| mu0_14() = ^CallSideEffect : ~mu0_2 # 30| r0_15(glval) = VariableAddress[x] : # 30| r0_16(glval) = VariableAddress[obj] : # 30| r0_17(PropClass) = Load : &:r0_16, ~mu0_2 -# 30| r0_18(glval) = FunctionAddress[get_Prop] : +# 30| r0_18() = FunctionAddress[get_Prop] : # 30| r0_19(Int32) = Call : func:r0_18, this:r0_17 -# 30| mu0_20(null) = ^CallSideEffect : ~mu0_2 +# 30| mu0_20() = ^CallSideEffect : ~mu0_2 # 30| mu0_21(Int32) = Store : &:r0_15, r0_19 # 26| v0_22(Void) = ReturnVoid : # 26| v0_23(Void) = UnmodeledUse : mu* @@ -1365,8 +1365,8 @@ simple_call.cs: # 5| System.Int32 test_simple_call.f() # 5| Block 0 # 5| v0_0(Void) = EnterFunction : -# 5| mu0_1(null) = AliasedDefinition : -# 5| mu0_2(null) = UnmodeledDefinition : +# 5| mu0_1() = AliasedDefinition : +# 5| mu0_2() = UnmodeledDefinition : # 7| r0_3(glval) = VariableAddress[#return] : # 7| r0_4(Int32) = Constant[0] : # 7| mu0_5(Int32) = Store : &:r0_3, r0_4 @@ -1378,13 +1378,13 @@ simple_call.cs: # 10| System.Int32 test_simple_call.g() # 10| Block 0 # 10| v0_0(Void) = EnterFunction : -# 10| mu0_1(null) = AliasedDefinition : -# 10| mu0_2(null) = UnmodeledDefinition : +# 10| mu0_1() = AliasedDefinition : +# 10| mu0_2() = UnmodeledDefinition : # 10| r0_3(glval) = InitializeThis : # 12| r0_4(glval) = VariableAddress[#return] : -# 12| r0_5(glval) = FunctionAddress[f] : +# 12| r0_5() = FunctionAddress[f] : # 12| r0_6(Int32) = Call : func:r0_5 -# 12| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 12| mu0_7() = ^CallSideEffect : ~mu0_2 # 12| mu0_8(Int32) = Store : &:r0_4, r0_6 # 10| r0_9(glval) = VariableAddress[#return] : # 10| v0_10(Void) = ReturnValue : &:r0_9, ~mu0_2 @@ -1395,8 +1395,8 @@ simple_function.cs: # 5| System.Int32 test_simple_function.f() # 5| Block 0 # 5| v0_0(Void) = EnterFunction : -# 5| mu0_1(null) = AliasedDefinition : -# 5| mu0_2(null) = UnmodeledDefinition : +# 5| mu0_1() = AliasedDefinition : +# 5| mu0_2() = UnmodeledDefinition : # 7| r0_3(glval) = VariableAddress[#return] : # 7| r0_4(Int32) = Constant[0] : # 7| mu0_5(Int32) = Store : &:r0_3, r0_4 @@ -1409,8 +1409,8 @@ stmts.cs: # 5| System.Int32 test_stmts.ifStmt(System.Int32) # 5| Block 0 # 5| v0_0(Void) = EnterFunction : -# 5| mu0_1(null) = AliasedDefinition : -# 5| mu0_2(null) = UnmodeledDefinition : +# 5| mu0_1() = AliasedDefinition : +# 5| mu0_2() = UnmodeledDefinition : # 5| r0_3(glval) = VariableAddress[x] : # 5| mu0_4(Int32) = InitializeParameter[x] : &:r0_3 # 7| r0_5(glval) = VariableAddress[x] : @@ -1442,8 +1442,8 @@ stmts.cs: # 13| System.Void test_stmts.whileStmt(System.Int32) # 13| Block 0 # 13| v0_0(Void) = EnterFunction : -# 13| mu0_1(null) = AliasedDefinition : -# 13| mu0_2(null) = UnmodeledDefinition : +# 13| mu0_1() = AliasedDefinition : +# 13| mu0_2() = UnmodeledDefinition : # 13| r0_3(glval) = VariableAddress[x] : # 13| mu0_4(Int32) = InitializeParameter[x] : &:r0_3 # 15| r0_5(glval) = VariableAddress[i] : @@ -1477,13 +1477,13 @@ stmts.cs: # 22| System.Int32 test_stmts.switchStmt() # 22| Block 0 # 22| v0_0(Void) = EnterFunction : -# 22| mu0_1(null) = AliasedDefinition : -# 22| mu0_2(null) = UnmodeledDefinition : +# 22| mu0_1() = AliasedDefinition : +# 22| mu0_2() = UnmodeledDefinition : # 24| r0_3(glval) = VariableAddress[caseSwitch] : # 24| r0_4(Object) = NewObj : -# 24| r0_5(glval) = FunctionAddress[Object] : +# 24| r0_5() = FunctionAddress[Object] : # 24| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 24| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 24| mu0_7() = ^CallSideEffect : ~mu0_2 # 24| mu0_8(Object) = Store : &:r0_3, r0_4 # 25| r0_9(glval) = VariableAddress[select] : # 25| r0_10(Int32) = Constant[0] : @@ -1543,8 +1543,8 @@ stmts.cs: # 46| System.Void test_stmts.tryCatchFinally() # 46| Block 0 # 46| v0_0(Void) = EnterFunction : -# 46| mu0_1(null) = AliasedDefinition : -# 46| mu0_2(null) = UnmodeledDefinition : +# 46| mu0_1() = AliasedDefinition : +# 46| mu0_2() = UnmodeledDefinition : # 48| r0_3(glval) = VariableAddress[x] : # 48| r0_4(Int32) = Constant[5] : # 48| mu0_5(Int32) = Store : &:r0_3, r0_4 @@ -1567,9 +1567,9 @@ stmts.cs: # 52| Block 3 # 52| r3_0(glval) = VariableAddress[#throw52:17] : # 52| r3_1(Exception) = NewObj : -# 52| r3_2(glval) = FunctionAddress[Exception] : +# 52| r3_2() = FunctionAddress[Exception] : # 52| v3_3(Void) = Call : func:r3_2, this:r3_1 -# 52| mu3_4(null) = ^CallSideEffect : ~mu0_2 +# 52| mu3_4() = ^CallSideEffect : ~mu0_2 # 52| mu3_5(Exception) = Store : &:r3_0, r3_1 # 52| v3_6(Void) = ThrowValue : &:r3_0, ~mu0_2 #-----| Exception -> Block 6 @@ -1608,8 +1608,8 @@ stmts.cs: # 69| System.Void test_stmts.forStmt() # 69| Block 0 # 69| v0_0(Void) = EnterFunction : -# 69| mu0_1(null) = AliasedDefinition : -# 69| mu0_2(null) = UnmodeledDefinition : +# 69| mu0_1() = AliasedDefinition : +# 69| mu0_2() = UnmodeledDefinition : # 71| r0_3(glval) = VariableAddress[x] : # 71| r0_4(Int32) = Constant[0] : # 71| mu0_5(Int32) = Store : &:r0_3, r0_4 @@ -1691,8 +1691,8 @@ stmts.cs: # 89| System.Void test_stmts.doWhile() # 89| Block 0 # 89| v0_0(Void) = EnterFunction : -# 89| mu0_1(null) = AliasedDefinition : -# 89| mu0_2(null) = UnmodeledDefinition : +# 89| mu0_1() = AliasedDefinition : +# 89| mu0_2() = UnmodeledDefinition : # 91| r0_3(glval) = VariableAddress[x] : # 91| r0_4(Int32) = Constant[0] : # 91| mu0_5(Int32) = Store : &:r0_3, r0_4 @@ -1721,8 +1721,8 @@ stmts.cs: # 99| System.Void test_stmts.checkedUnchecked() # 99| Block 0 # 99| v0_0(Void) = EnterFunction : -# 99| mu0_1(null) = AliasedDefinition : -# 99| mu0_2(null) = UnmodeledDefinition : +# 99| mu0_1() = AliasedDefinition : +# 99| mu0_2() = UnmodeledDefinition : # 101| r0_3(glval) = VariableAddress[num] : # 101| r0_4(Int32) = Constant[2147483647] : # 101| r0_5(Int32) = Load : &:r0_4, ~mu0_2 @@ -1747,8 +1747,8 @@ using.cs: # 7| System.Void UsingStmt.MyDisposable..ctor() # 7| Block 0 # 7| v0_0(Void) = EnterFunction : -# 7| mu0_1(null) = AliasedDefinition : -# 7| mu0_2(null) = UnmodeledDefinition : +# 7| mu0_1() = AliasedDefinition : +# 7| mu0_2() = UnmodeledDefinition : # 7| r0_3(glval) = InitializeThis : # 7| v0_4(Void) = NoOp : # 7| v0_5(Void) = ReturnVoid : @@ -1758,8 +1758,8 @@ using.cs: # 8| System.Void UsingStmt.MyDisposable.DoSomething() # 8| Block 0 # 8| v0_0(Void) = EnterFunction : -# 8| mu0_1(null) = AliasedDefinition : -# 8| mu0_2(null) = UnmodeledDefinition : +# 8| mu0_1() = AliasedDefinition : +# 8| mu0_2() = UnmodeledDefinition : # 8| r0_3(glval) = InitializeThis : # 8| v0_4(Void) = NoOp : # 8| v0_5(Void) = ReturnVoid : @@ -1769,8 +1769,8 @@ using.cs: # 9| System.Void UsingStmt.MyDisposable.Dispose() # 9| Block 0 # 9| v0_0(Void) = EnterFunction : -# 9| mu0_1(null) = AliasedDefinition : -# 9| mu0_2(null) = UnmodeledDefinition : +# 9| mu0_1() = AliasedDefinition : +# 9| mu0_2() = UnmodeledDefinition : # 9| r0_3(glval) = InitializeThis : # 9| v0_4(Void) = NoOp : # 9| v0_5(Void) = ReturnVoid : @@ -1780,41 +1780,41 @@ using.cs: # 12| System.Void UsingStmt.Main() # 12| Block 0 # 12| v0_0(Void) = EnterFunction : -# 12| mu0_1(null) = AliasedDefinition : -# 12| mu0_2(null) = UnmodeledDefinition : +# 12| mu0_1() = AliasedDefinition : +# 12| mu0_2() = UnmodeledDefinition : # 14| r0_3(glval) = VariableAddress[o1] : # 14| r0_4(MyDisposable) = NewObj : -# 14| r0_5(glval) = FunctionAddress[MyDisposable] : +# 14| r0_5() = FunctionAddress[MyDisposable] : # 14| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 14| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 14| mu0_7() = ^CallSideEffect : ~mu0_2 # 14| mu0_8(MyDisposable) = Store : &:r0_3, r0_4 # 16| r0_9(glval) = VariableAddress[o1] : # 16| r0_10(MyDisposable) = Load : &:r0_9, ~mu0_2 -# 16| r0_11(glval) = FunctionAddress[DoSomething] : +# 16| r0_11() = FunctionAddress[DoSomething] : # 16| v0_12(Void) = Call : func:r0_11, this:r0_10 -# 16| mu0_13(null) = ^CallSideEffect : ~mu0_2 +# 16| mu0_13() = ^CallSideEffect : ~mu0_2 # 19| r0_14(glval) = VariableAddress[o2] : # 19| r0_15(MyDisposable) = NewObj : -# 19| r0_16(glval) = FunctionAddress[MyDisposable] : +# 19| r0_16() = FunctionAddress[MyDisposable] : # 19| v0_17(Void) = Call : func:r0_16, this:r0_15 -# 19| mu0_18(null) = ^CallSideEffect : ~mu0_2 +# 19| mu0_18() = ^CallSideEffect : ~mu0_2 # 19| mu0_19(MyDisposable) = Store : &:r0_14, r0_15 # 22| r0_20(glval) = VariableAddress[o2] : # 22| r0_21(MyDisposable) = Load : &:r0_20, ~mu0_2 -# 22| r0_22(glval) = FunctionAddress[DoSomething] : +# 22| r0_22() = FunctionAddress[DoSomething] : # 22| v0_23(Void) = Call : func:r0_22, this:r0_21 -# 22| mu0_24(null) = ^CallSideEffect : ~mu0_2 +# 22| mu0_24() = ^CallSideEffect : ~mu0_2 # 25| r0_25(glval) = VariableAddress[o3] : # 25| r0_26(MyDisposable) = NewObj : -# 25| r0_27(glval) = FunctionAddress[MyDisposable] : +# 25| r0_27() = FunctionAddress[MyDisposable] : # 25| v0_28(Void) = Call : func:r0_27, this:r0_26 -# 25| mu0_29(null) = ^CallSideEffect : ~mu0_2 +# 25| mu0_29() = ^CallSideEffect : ~mu0_2 # 25| mu0_30(MyDisposable) = Store : &:r0_25, r0_26 # 26| r0_31(glval) = VariableAddress[o3] : # 26| r0_32(MyDisposable) = Load : &:r0_31, ~mu0_2 -# 26| r0_33(glval) = FunctionAddress[DoSomething] : +# 26| r0_33() = FunctionAddress[DoSomething] : # 26| v0_34(Void) = Call : func:r0_33, this:r0_32 -# 26| mu0_35(null) = ^CallSideEffect : ~mu0_2 +# 26| mu0_35() = ^CallSideEffect : ~mu0_2 # 12| v0_36(Void) = ReturnVoid : # 12| v0_37(Void) = UnmodeledUse : mu* # 12| v0_38(Void) = ExitFunction : @@ -1823,8 +1823,8 @@ variables.cs: # 5| System.Void test_variables.f() # 5| Block 0 # 5| v0_0(Void) = EnterFunction : -# 5| mu0_1(null) = AliasedDefinition : -# 5| mu0_2(null) = UnmodeledDefinition : +# 5| mu0_1() = AliasedDefinition : +# 5| mu0_2() = UnmodeledDefinition : # 7| r0_3(glval) = VariableAddress[x] : # 7| mu0_4(Int32) = Uninitialized[x] : &:r0_3 # 7| r0_5(glval) = VariableAddress[y] : From c38943292297aafb339c223fabee235f9a38a9be Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 26 Sep 2019 22:11:24 -0700 Subject: [PATCH 0271/1227] C++, C#: Sync `IRType.qll` between languages --- config/identical-files.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/identical-files.json b/config/identical-files.json index 6a216ac256d..2c19f84ea23 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -73,6 +73,10 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll" ], + "IR IRType": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll" + ], "IR Operand Tag": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll" From ff28b3f1b4e24a678bc6bdf37d1d27d046ea1a59 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 27 Sep 2019 11:02:22 +0200 Subject: [PATCH 0272/1227] Python: Modernise cherrypy library --- python/ql/src/semmle/python/web/cherrypy/General.qll | 12 ++++++------ python/ql/src/semmle/python/web/cherrypy/Request.qll | 2 +- .../test/library-tests/web/cherrypy/Sources.expected | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/python/ql/src/semmle/python/web/cherrypy/General.qll b/python/ql/src/semmle/python/web/cherrypy/General.qll index 4b7e3ecf8ea..bccfd56d7b3 100644 --- a/python/ql/src/semmle/python/web/cherrypy/General.qll +++ b/python/ql/src/semmle/python/web/cherrypy/General.qll @@ -3,8 +3,8 @@ import semmle.python.web.Http module CherryPy { - FunctionObject expose() { - result = ModuleObject::named("cherrypy").attr("expose") + FunctionValue expose() { + result = Value::named("cherrypy.expose") } } @@ -12,9 +12,9 @@ module CherryPy { class CherryPyExposedFunction extends Function { CherryPyExposedFunction() { - this.getADecorator().refersTo(CherryPy::expose()) + this.getADecorator().pointsTo(CherryPy::expose()) or - this.getADecorator().(Call).getFunc().refersTo(CherryPy::expose()) + this.getADecorator().(Call).getFunc().pointsTo(CherryPy::expose()) } } @@ -23,10 +23,10 @@ class CherryPyRoute extends CallNode { CherryPyRoute() { /* cherrypy.quickstart(root, script_name, config) */ - ModuleObject::named("cherrypy").attr("quickstart").(FunctionObject).getACall() = this + Value::named("cherrypy.quickstart").(FunctionValue).getACall() = this or /* cherrypy.tree.mount(root, script_name, config) */ - this.getFunction().(AttrNode).getObject("mount").refersTo(ModuleObject::named("cherrypy").attr("tree")) + this.getFunction().(AttrNode).getObject("mount").pointsTo(Value::named("cherrypy.tree")) } ClassObject getAppClass() { diff --git a/python/ql/src/semmle/python/web/cherrypy/Request.qll b/python/ql/src/semmle/python/web/cherrypy/Request.qll index 71976fa0a26..cf274742112 100644 --- a/python/ql/src/semmle/python/web/cherrypy/Request.qll +++ b/python/ql/src/semmle/python/web/cherrypy/Request.qll @@ -54,7 +54,7 @@ class CherryPyExposedFunctionParameter extends TaintSource { class CherryPyRequestSource extends TaintSource { CherryPyRequestSource() { - this.(ControlFlowNode).refersTo(ModuleObject::named("cherrypy").attr("request")) + this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) } override predicate isSourceOf(TaintKind kind) { diff --git a/python/ql/test/library-tests/web/cherrypy/Sources.expected b/python/ql/test/library-tests/web/cherrypy/Sources.expected index 73fdf0f2d68..b2a4d2e7c3e 100644 --- a/python/ql/test/library-tests/web/cherrypy/Sources.expected +++ b/python/ql/test/library-tests/web/cherrypy/Sources.expected @@ -1,4 +1,3 @@ | ../../../query-tests/Security/lib/cherrypy/__init__.py:10 | _ThreadLocalProxy() | cherrypy.request | -| ../../../query-tests/Security/lib/cherrypy/__init__.py:10 | request | cherrypy.request | | test.py:10 | arg | externally controlled string | | test.py:16 | arg | externally controlled string | From 25985e901bf5020f0fb6d9e7857d6c081d47e1fe Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 26 Sep 2019 17:53:10 +0200 Subject: [PATCH 0273/1227] Python: Remove a few false positives from `py/unused-import`. --- python/ql/src/Imports/UnusedImport.ql | 25 ++++++++++++++++--- .../Imports/unused/imports_test.py | 14 +++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/python/ql/src/Imports/UnusedImport.ql b/python/ql/src/Imports/UnusedImport.ql index 6d927550c0c..d87b0efd254 100644 --- a/python/ql/src/Imports/UnusedImport.ql +++ b/python/ql/src/Imports/UnusedImport.ql @@ -58,16 +58,28 @@ predicate imported_module_used_in_doctest(Import imp) { } predicate imported_module_used_in_typehint(Import imp) { - exists(string modname | - imp.getAName().getAsname().(Name).getId() = modname - and + exists(string modname, Location loc | + imp.getAName().getAsname().(Name).getId() = modname and + loc.getFile() = imp.getScope().(Module).getFile() + | /* Look for typehints containing the patterns: * # type: …name… */ exists(Comment typehint | - typehint.getLocation().getFile() = imp.getScope().(Module).getFile() and + loc = typehint.getLocation() and typehint.getText().regexpMatch("# type:.*" + modname + ".*") ) + or + // Type hint is inside a string annotation, as needed for forward references + exists(string typehint, Expr annotation | + annotation = any(Arguments a).getAnAnnotation() + or + annotation = any(AnnAssign a).getAnnotation() + | + annotation.pointsTo(Value::forString(typehint)) and + loc = annotation.getLocation() and + typehint.regexpMatch(".*\\b" + modname + "\\b.*") + ) ) } @@ -100,6 +112,11 @@ predicate unused_import(Import imp, Variable name) { not imported_module_used_in_doctest(imp) and not imported_module_used_in_typehint(imp) + and + /* Only consider import statements that actually point-to something (possibly an unknown module). + * If this is not the case, it's likely that the import statement never gets executed. + */ + imp.getAName().getValue().pointsTo(_) } diff --git a/python/ql/test/query-tests/Imports/unused/imports_test.py b/python/ql/test/query-tests/Imports/unused/imports_test.py index a1b457f0422..cf2024ac183 100644 --- a/python/ql/test/query-tests/Imports/unused/imports_test.py +++ b/python/ql/test/query-tests/Imports/unused/imports_test.py @@ -76,3 +76,17 @@ import typing foo = None # type: typing.Optional[int] + +# OK since the import statement is never executed +if False: + import never_imported + +# OK since the imported module is used in a forward-referenced type annotation. +import only_used_in_parameter_annotation + +def func(x: 'Optional[only_used_in_parameter_annotation]'): + pass + +import only_used_in_annotated_assignment + +var : 'Optional[only_used_in_annotated_assignment]' = 5 From c10ed5e11421acab794a736e199554cb0af50f78 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Mon, 23 Sep 2019 12:51:17 +0100 Subject: [PATCH 0274/1227] C++: Update results for vector_size atrr changes --- .../library-tests/ir/ir/PrintAST.expected | 4 +-- .../test/library-tests/ir/ir/raw_ir.expected | 34 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index d675fa95d21..eb6e4d3d0b6 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -8015,7 +8015,7 @@ ir.cpp: # 1154| Type = [SpecifiedType] __attribute((vector_size(16UL))) int # 1154| init: [Initializer] initializer for vi4 # 1154| expr: [VectorAggregateLiteral] {...} -# 1154| Type = [GNUVectorType] __attribute((vector_size(16))) int +# 1154| Type = [GNUVectorType] __attribute((vector_size(16UL))) int # 1154| ValueCategory = prvalue # 1154| 0: [Literal] 0 # 1154| Type = [IntType] int @@ -8107,7 +8107,7 @@ ir.cpp: # 1158| Type = [SpecifiedType] __attribute((vector_size(16UL))) int # 1158| ValueCategory = lvalue # 1158| 1: [AddExpr] ... + ... -# 1158| Type = [GNUVectorType] __attribute((vector_size(16))) int +# 1158| Type = [GNUVectorType] __attribute((vector_size(16UL))) int # 1158| ValueCategory = prvalue # 1158| 0: [VariableAccess] vi4 # 1158| Type = [SpecifiedType] __attribute((vector_size(16UL))) int diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 20f15e4f772..a9efc78468d 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -5277,8 +5277,8 @@ ir.cpp: # 1153| mu0_2(unknown) = UnmodeledDefinition : # 1153| r0_3(glval) = VariableAddress[i] : # 1153| mu0_4(int) = InitializeParameter[i] : &:r0_3 -# 1154| r0_5(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : -# 1154| mu0_6(__attribute((vector_size(16))) int) = Uninitialized[vi4] : &:r0_5 +# 1154| r0_5(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : +# 1154| mu0_6(__attribute((vector_size(16UL))) int) = Uninitialized[vi4] : &:r0_5 # 1154| r0_7(int) = Constant[0] : # 1154| r0_8(glval) = PointerAdd[4] : r0_5, r0_7 # 1154| r0_9(int) = Constant[0] : @@ -5296,7 +5296,7 @@ ir.cpp: # 1154| r0_21(int) = Constant[3] : # 1154| mu0_22(int) = Store : &:r0_20, r0_21 # 1155| r0_23(glval) = VariableAddress[x] : -# 1155| r0_24(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : +# 1155| r0_24(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1155| r0_25(glval) = VariableAddress[i] : # 1155| r0_26(int) = Load : &:r0_25, ~mu0_2 # 1155| r0_27(glval) = PointerAdd[4] : r0_24, r0_26 @@ -5304,29 +5304,29 @@ ir.cpp: # 1155| mu0_29(int) = Store : &:r0_23, r0_28 # 1156| r0_30(glval) = VariableAddress[x] : # 1156| r0_31(int) = Load : &:r0_30, ~mu0_2 -# 1156| r0_32(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : +# 1156| r0_32(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1156| r0_33(glval) = VariableAddress[i] : # 1156| r0_34(int) = Load : &:r0_33, ~mu0_2 # 1156| r0_35(glval) = PointerAdd[4] : r0_32, r0_34 # 1156| mu0_36(int) = Store : &:r0_35, r0_31 -# 1157| r0_37(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4_shuffle] : -# 1157| r0_38(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : -# 1157| r0_39(__attribute((vector_size(16))) int) = Load : &:r0_38, ~mu0_2 -# 1157| r0_40(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : -# 1157| r0_41(__attribute((vector_size(16))) int) = Load : &:r0_40, ~mu0_2 +# 1157| r0_37(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4_shuffle] : +# 1157| r0_38(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : +# 1157| r0_39(__attribute((vector_size(16UL))) int) = Load : &:r0_38, ~mu0_2 +# 1157| r0_40(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : +# 1157| r0_41(__attribute((vector_size(16UL))) int) = Load : &:r0_40, ~mu0_2 #-----| r0_42(int) = Constant[3] : # 1157| r0_43(int) = Constant[2] : # 1157| r0_44(int) = Constant[1] : # 1157| r0_45(int) = Constant[0] : # 1157| r0_46(__attribute((vector_size(16))) int) = BuiltIn[__builtin_shufflevector] : 0:r0_39, 1:r0_41, 2:r0_42, 3:r0_43, 4:r0_44, 5:r0_45 -# 1157| mu0_47(__attribute((vector_size(16))) int) = Store : &:r0_37, r0_46 -# 1158| r0_48(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : -# 1158| r0_49(__attribute((vector_size(16))) int) = Load : &:r0_48, ~mu0_2 -# 1158| r0_50(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4_shuffle] : -# 1158| r0_51(__attribute((vector_size(16))) int) = Load : &:r0_50, ~mu0_2 -# 1158| r0_52(__attribute((vector_size(16))) int) = Add : r0_49, r0_51 -# 1158| r0_53(glval<__attribute((vector_size(16))) int>) = VariableAddress[vi4] : -# 1158| mu0_54(__attribute((vector_size(16))) int) = Store : &:r0_53, r0_52 +# 1157| mu0_47(__attribute((vector_size(16UL))) int) = Store : &:r0_37, r0_46 +# 1158| r0_48(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : +# 1158| r0_49(__attribute((vector_size(16UL))) int) = Load : &:r0_48, ~mu0_2 +# 1158| r0_50(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4_shuffle] : +# 1158| r0_51(__attribute((vector_size(16UL))) int) = Load : &:r0_50, ~mu0_2 +# 1158| r0_52(__attribute((vector_size(16UL))) int) = Add : r0_49, r0_51 +# 1158| r0_53(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : +# 1158| mu0_54(__attribute((vector_size(16UL))) int) = Store : &:r0_53, r0_52 # 1159| v0_55(void) = NoOp : # 1153| v0_56(void) = ReturnVoid : # 1153| v0_57(void) = UnmodeledUse : mu* From cc016d583d2d2764d850b2440866048ff3f63dd9 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Mon, 23 Sep 2019 12:52:19 +0100 Subject: [PATCH 0275/1227] C++: Add further vector_size attribute tests --- cpp/ql/test/library-tests/vector_sizes/code.c | 6 ++++++ cpp/ql/test/library-tests/vector_sizes/test.expected | 3 +++ cpp/ql/test/library-tests/vector_sizes/test.ql | 4 ++++ 3 files changed, 13 insertions(+) create mode 100644 cpp/ql/test/library-tests/vector_sizes/code.c create mode 100644 cpp/ql/test/library-tests/vector_sizes/test.expected create mode 100644 cpp/ql/test/library-tests/vector_sizes/test.ql diff --git a/cpp/ql/test/library-tests/vector_sizes/code.c b/cpp/ql/test/library-tests/vector_sizes/code.c new file mode 100644 index 00000000000..517e77d14d9 --- /dev/null +++ b/cpp/ql/test/library-tests/vector_sizes/code.c @@ -0,0 +1,6 @@ +// semmle-extractor-options: --clang +void builtin(void) { + __attribute__((vector_size(16U))) int vec2 = { 0, 1, 2, 3 }; + __attribute__((vector_size(16UL))) int vec = { 0, 1, 2, 3 }; + __builtin_shufflevector(vec, vec, 3, 2, 1, 0); +} diff --git a/cpp/ql/test/library-tests/vector_sizes/test.expected b/cpp/ql/test/library-tests/vector_sizes/test.expected new file mode 100644 index 00000000000..150e6aeb04e --- /dev/null +++ b/cpp/ql/test/library-tests/vector_sizes/test.expected @@ -0,0 +1,3 @@ +| file://:0:0:0:0 | __attribute((vector_size(16))) int | 4 | +| file://:0:0:0:0 | __attribute((vector_size(16U))) int | 4 | +| file://:0:0:0:0 | __attribute((vector_size(16UL))) int | 4 | diff --git a/cpp/ql/test/library-tests/vector_sizes/test.ql b/cpp/ql/test/library-tests/vector_sizes/test.ql new file mode 100644 index 00000000000..c0e336c49ae --- /dev/null +++ b/cpp/ql/test/library-tests/vector_sizes/test.ql @@ -0,0 +1,4 @@ +import cpp + +from GNUVectorType gvt +select gvt, gvt.getNumElements() From 4341e88fc4dbeeb24aae204c0288693d3e87bd04 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 27 Sep 2019 13:03:27 +0200 Subject: [PATCH 0276/1227] Python: Clean up comments in preparation for autoformat. --- python/ql/src/Imports/UnusedImport.ql | 29 ++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/python/ql/src/Imports/UnusedImport.ql b/python/ql/src/Imports/UnusedImport.ql index d87b0efd254..951e7f87513 100644 --- a/python/ql/src/Imports/UnusedImport.ql +++ b/python/ql/src/Imports/UnusedImport.ql @@ -20,7 +20,7 @@ predicate global_name_used(Module m, Variable name) { u.getEnclosingModule() = m ) or - /* A use of an undefined class local variable, will use the global variable */ + // A use of an undefined class local variable, will use the global variable exists(Name u, LocalVariable v | u.uses(v) and v.getId() = name.getId() and @@ -33,10 +33,10 @@ predicate global_name_used(Module m, Variable name) { predicate all_not_understood(Module m) { exists(GlobalVariable a | a.getId() = "__all__" and a.getScope() = m | - /* __all__ is not defined as a simple list */ + // `__all__` is not defined as a simple list not m.declaredInAll(_) or - /* __all__ is modified */ + // `__all__` is modified exists(Call c | c.getFunc().(Attribute).getObject() = a.getALoad()) ) } @@ -45,10 +45,9 @@ predicate imported_module_used_in_doctest(Import imp) { exists(string modname | imp.getAName().getAsname().(Name).getId() = modname and - /* Look for doctests containing the patterns: - * >>> …name… - * ... …name… - */ + // Look for doctests containing the patterns: + // >>> …name… + // ... …name… exists(StrConst doc | doc.getEnclosingModule() = imp.getScope() and doc.isDocString() and @@ -62,9 +61,8 @@ predicate imported_module_used_in_typehint(Import imp) { imp.getAName().getAsname().(Name).getId() = modname and loc.getFile() = imp.getScope().(Module).getFile() | - /* Look for typehints containing the patterns: - * # type: …name… - */ + // Look for type hints containing the patterns: + // # type: …name… exists(Comment typehint | loc = typehint.getLocation() and typehint.getText().regexpMatch("# type:.*" + modname + ".*") @@ -95,10 +93,10 @@ predicate unused_import(Import imp, Variable name) { and not global_name_used(imp.getScope(), name) and - /* Imports in __init__.py are used to force module loading */ + // Imports in `__init__.py` are used to force module loading not imp.getEnclosingModule().isPackageInit() and - /* Name may be imported for use in epytext documentation */ + // Name may be imported for use in epytext documentation not exists(Comment cmt | cmt.getText().matches("%L{" + name.getId() + "}%") | cmt.getLocation().getFile() = imp.getLocation().getFile() @@ -106,16 +104,15 @@ predicate unused_import(Import imp, Variable name) { and not name_acceptable_for_unused_variable(name) and - /* Assume that opaque `__all__` includes imported module */ + // Assume that opaque `__all__` includes imported module not all_not_understood(imp.getEnclosingModule()) and not imported_module_used_in_doctest(imp) and not imported_module_used_in_typehint(imp) and - /* Only consider import statements that actually point-to something (possibly an unknown module). - * If this is not the case, it's likely that the import statement never gets executed. - */ + // Only consider import statements that actually point-to something (possibly an unknown module). + // If this is not the case, it's likely that the import statement never gets executed. imp.getAName().getValue().pointsTo(_) } From 9878e4fe263f54120fe282810274377a06f9cc01 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 27 Sep 2019 13:04:17 +0200 Subject: [PATCH 0277/1227] Python: Apply four-space autoformat. --- python/ql/src/Imports/UnusedImport.ql | 53 +++++++++------------------ 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/python/ql/src/Imports/UnusedImport.ql b/python/ql/src/Imports/UnusedImport.ql index 951e7f87513..3ac04e2e4d2 100644 --- a/python/ql/src/Imports/UnusedImport.ql +++ b/python/ql/src/Imports/UnusedImport.ql @@ -14,7 +14,7 @@ import python import Variables.Definition predicate global_name_used(Module m, Variable name) { - exists (Name u, GlobalVariable v | + exists(Name u, GlobalVariable v | u.uses(v) and v.getId() = name.getId() and u.getEnclosingModule() = m @@ -31,8 +31,7 @@ predicate global_name_used(Module m, Variable name) { /** Holds if a module has `__all__` but we don't understand it */ predicate all_not_understood(Module m) { - exists(GlobalVariable a | - a.getId() = "__all__" and a.getScope() = m | + exists(GlobalVariable a | a.getId() = "__all__" and a.getScope() = m | // `__all__` is not defined as a simple list not m.declaredInAll(_) or @@ -43,8 +42,7 @@ predicate all_not_understood(Module m) { predicate imported_module_used_in_doctest(Import imp) { exists(string modname | - imp.getAName().getAsname().(Name).getId() = modname - and + imp.getAName().getAsname().(Name).getId() = modname and // Look for doctests containing the patterns: // >>> …name… // ... …name… @@ -60,7 +58,7 @@ predicate imported_module_used_in_typehint(Import imp) { exists(string modname, Location loc | imp.getAName().getAsname().(Name).getId() = modname and loc.getFile() = imp.getScope().(Module).getFile() - | + | // Look for type hints containing the patterns: // # type: …name… exists(Comment typehint | @@ -73,7 +71,7 @@ predicate imported_module_used_in_typehint(Import imp) { annotation = any(Arguments a).getAnAnnotation() or annotation = any(AnnAssign a).getAnnotation() - | + | annotation.pointsTo(Value::forString(typehint)) and loc = annotation.getLocation() and typehint.regexpMatch(".*\\b" + modname + "\\b.*") @@ -81,43 +79,28 @@ predicate imported_module_used_in_typehint(Import imp) { ) } - predicate unused_import(Import imp, Variable name) { - ((Name)imp.getAName().getAsname()).getVariable() = name - and - not imp.getAnImportedModuleName() = "__future__" - and - not imp.getEnclosingModule().declaredInAll(name.getId()) - and - imp.getScope() = imp.getEnclosingModule() - and - not global_name_used(imp.getScope(), name) - and + imp.getAName().getAsname().(Name).getVariable() = name and + not imp.getAnImportedModuleName() = "__future__" and + not imp.getEnclosingModule().declaredInAll(name.getId()) and + imp.getScope() = imp.getEnclosingModule() and + not global_name_used(imp.getScope(), name) and // Imports in `__init__.py` are used to force module loading - not imp.getEnclosingModule().isPackageInit() - and + not imp.getEnclosingModule().isPackageInit() and // Name may be imported for use in epytext documentation - not exists(Comment cmt | - cmt.getText().matches("%L{" + name.getId() + "}%") | + not exists(Comment cmt | cmt.getText().matches("%L{" + name.getId() + "}%") | cmt.getLocation().getFile() = imp.getLocation().getFile() - ) - and - not name_acceptable_for_unused_variable(name) - and + ) and + not name_acceptable_for_unused_variable(name) and // Assume that opaque `__all__` includes imported module - not all_not_understood(imp.getEnclosingModule()) - and - not imported_module_used_in_doctest(imp) - and - not imported_module_used_in_typehint(imp) - and - // Only consider import statements that actually point-to something (possibly an unknown module). + not all_not_understood(imp.getEnclosingModule()) and + not imported_module_used_in_doctest(imp) and + not imported_module_used_in_typehint(imp) and + // Only consider import statements that actually point-to something (possibly an unknown module). // If this is not the case, it's likely that the import statement never gets executed. imp.getAName().getValue().pointsTo(_) } - from Stmt s, Variable name where unused_import(s, name) select s, "Import of '" + name.getId() + "' is not used." - From bc8e4d2005b8c3d16d9948f1be242b0213c83459 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 27 Sep 2019 13:06:09 +0200 Subject: [PATCH 0278/1227] Python: Autoformat (4 spaces) cherrypy library --- .../semmle/python/web/cherrypy/General.qll | 16 +------ .../semmle/python/web/cherrypy/Request.qll | 47 +++++-------------- .../semmle/python/web/cherrypy/Response.qll | 14 +----- 3 files changed, 16 insertions(+), 61 deletions(-) diff --git a/python/ql/src/semmle/python/web/cherrypy/General.qll b/python/ql/src/semmle/python/web/cherrypy/General.qll index bccfd56d7b3..0f1560b33b4 100644 --- a/python/ql/src/semmle/python/web/cherrypy/General.qll +++ b/python/ql/src/semmle/python/web/cherrypy/General.qll @@ -2,25 +2,18 @@ import python import semmle.python.web.Http module CherryPy { - - FunctionValue expose() { - result = Value::named("cherrypy.expose") - } - + FunctionValue expose() { result = Value::named("cherrypy.expose") } } class CherryPyExposedFunction extends Function { - CherryPyExposedFunction() { this.getADecorator().pointsTo(CherryPy::expose()) or this.getADecorator().(Call).getFunc().pointsTo(CherryPy::expose()) } - } class CherryPyRoute extends CallNode { - CherryPyRoute() { /* cherrypy.quickstart(root, script_name, config) */ Value::named("cherrypy.quickstart").(FunctionValue).getACall() = this @@ -36,9 +29,7 @@ class CherryPyRoute extends CallNode { } string getPath() { - exists(StringObject path | - result = path.getText() - | + exists(StringObject path | result = path.getText() | this.getArg(1).refersTo(path) or this.getArgByName("script_name").refersTo(path) @@ -50,7 +41,4 @@ class CherryPyRoute extends CallNode { or this.getArgByName("config").refersTo(_, result, _) } - } - - diff --git a/python/ql/src/semmle/python/web/cherrypy/Request.qll b/python/ql/src/semmle/python/web/cherrypy/Request.qll index cf274742112..2ae897a7f29 100644 --- a/python/ql/src/semmle/python/web/cherrypy/Request.qll +++ b/python/ql/src/semmle/python/web/cherrypy/Request.qll @@ -1,5 +1,4 @@ import python - import semmle.python.security.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http @@ -7,10 +6,7 @@ import semmle.python.web.cherrypy.General /** The cherrypy.request local-proxy object */ class CherryPyRequest extends TaintKind { - - CherryPyRequest() { - this = "cherrypy.request" - } + CherryPyRequest() { this = "cherrypy.request" } override TaintKind getTaintOfAttribute(string name) { name = "params" and result instanceof ExternalStringDictKind @@ -19,20 +15,17 @@ class CherryPyRequest extends TaintKind { } override TaintKind getTaintOfMethodResult(string name) { - ( - name = "getHeader" or - name = "getCookie" or - name = "getUser" or - name = "getPassword" - ) and - result instanceof ExternalStringKind + ( + name = "getHeader" or + name = "getCookie" or + name = "getUser" or + name = "getPassword" + ) and + result instanceof ExternalStringKind } - } - class CherryPyExposedFunctionParameter extends TaintSource { - CherryPyExposedFunctionParameter() { exists(Parameter p | p = any(CherryPyExposedFunction f).getAnArg() and @@ -41,29 +34,13 @@ class CherryPyExposedFunctionParameter extends TaintSource { ) } - override string toString() { - result = "CherryPy handler function parameter" - } - - override predicate isSourceOf(TaintKind kind) { - kind instanceof ExternalStringKind - } + override string toString() { result = "CherryPy handler function parameter" } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } } class CherryPyRequestSource extends TaintSource { + CherryPyRequestSource() { this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) } - CherryPyRequestSource() { - this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) - } - - override predicate isSourceOf(TaintKind kind) { - kind instanceof CherryPyRequest - } - + override predicate isSourceOf(TaintKind kind) { kind instanceof CherryPyRequest } } - - - - - diff --git a/python/ql/src/semmle/python/web/cherrypy/Response.qll b/python/ql/src/semmle/python/web/cherrypy/Response.qll index c194ededaac..7702b8ce500 100644 --- a/python/ql/src/semmle/python/web/cherrypy/Response.qll +++ b/python/ql/src/semmle/python/web/cherrypy/Response.qll @@ -1,14 +1,10 @@ import python - import semmle.python.security.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.web.Http import semmle.python.web.cherrypy.General - - class CherryPyExposedFunctionResult extends HttpResponseTaintSink { - CherryPyExposedFunctionResult() { exists(Return ret | ret.getScope() instanceof CherryPyExposedFunction and @@ -16,13 +12,7 @@ class CherryPyExposedFunctionResult extends HttpResponseTaintSink { ) } - override predicate sinks(TaintKind kind) { - kind instanceof StringKind - } - - override string toString() { - result = "cherrypy handler function result" - } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override string toString() { result = "cherrypy handler function result" } } - From f4e0abd4c416a4ba7e05593c11ffd4fe4a551f01 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 27 Sep 2019 13:14:52 +0200 Subject: [PATCH 0279/1227] Python: Modernise django library --- python/ql/src/semmle/python/web/django/Db.qll | 10 +++---- .../ql/src/semmle/python/web/django/Model.qll | 13 ++++----- .../src/semmle/python/web/django/Request.qll | 27 ++++++++++--------- .../src/semmle/python/web/django/Response.qll | 14 +++++----- .../src/semmle/python/web/django/Shared.qll | 9 ++++--- 5 files changed, 36 insertions(+), 37 deletions(-) diff --git a/python/ql/src/semmle/python/web/django/Db.qll b/python/ql/src/semmle/python/web/django/Db.qll index c5314cc298e..56db32849cc 100644 --- a/python/ql/src/semmle/python/web/django/Db.qll +++ b/python/ql/src/semmle/python/web/django/Db.qll @@ -11,8 +11,8 @@ class DjangoDbCursor extends DbCursor { } -private Object theDjangoConnectionObject() { - ModuleObject::named("django.db").attr("connection") = result +private Value theDjangoConnectionObject() { + result = Value::named("django.db.connection") } /** A kind of taint source representing sources of django cursor objects. @@ -22,7 +22,7 @@ class DjangoDbCursorSource extends DbConnectionSource { DjangoDbCursorSource() { exists(AttrNode cursor | this.(CallNode).getFunction()= cursor and - cursor.getObject("cursor").refersTo(theDjangoConnectionObject()) + cursor.getObject("cursor").pointsTo(theDjangoConnectionObject()) ) } @@ -37,8 +37,8 @@ class DjangoDbCursorSource extends DbConnectionSource { } -ClassObject theDjangoRawSqlClass() { - result = ModuleObject::named("django.db.models.expressions").attr("RawSQL") +ClassValue theDjangoRawSqlClass() { + result = Value::named("django.db.models.expressions.RawSQL") } /** diff --git a/python/ql/src/semmle/python/web/django/Model.qll b/python/ql/src/semmle/python/web/django/Model.qll index 2c845dad361..15bbe3e68c0 100644 --- a/python/ql/src/semmle/python/web/django/Model.qll +++ b/python/ql/src/semmle/python/web/django/Model.qll @@ -6,10 +6,10 @@ import semmle.python.web.Http import semmle.python.security.injection.Sql /** A django model class */ -class DjangoModel extends ClassObject { +class DjangoModel extends ClassValue { DjangoModel() { - ModuleObject::named("django.db.models").attr("Model") = this.getAnImproperSuperType() + Value::named("django.db.models.Model") = this.getASuperType() } } @@ -55,7 +55,7 @@ class DjangoDbTableObjects extends TaintKind { class DjangoModelObjects extends TaintSource { DjangoModelObjects() { - this.(AttrNode).isLoad() and this.(AttrNode).getObject("objects").refersTo(any(DjangoModel m)) + this.(AttrNode).isLoad() and this.(AttrNode).getObject("objects").pointsTo(any(DjangoModel m)) } override predicate isSourceOf(TaintKind kind) { @@ -73,7 +73,7 @@ class DjangoModelFieldWrite extends SqlInjectionSink { DjangoModelFieldWrite() { exists(AttrNode attr, DjangoModel model | - this = attr and attr.isStore() and attr.getObject(_).refersTo(model) + this = attr and attr.isStore() and attr.getObject(_).pointsTo(model) ) } @@ -87,7 +87,7 @@ class DjangoModelFieldWrite extends SqlInjectionSink { } -/** A direct reference to a django model object, which is a vulnerable to external data. */ +/** A direct reference to a django model object, which is vulnerable to external data. */ class DjangoModelDirectObjectReference extends TaintSink { DjangoModelDirectObjectReference() { @@ -111,7 +111,6 @@ class DjangoModelDirectObjectReference extends TaintSink { * A call to the `raw` method on a django model. This allows a raw SQL query * to be sent to the database, which is a security risk. */ - class DjangoModelRawCall extends SqlInjectionSink { DjangoModelRawCall() { @@ -135,8 +134,6 @@ class DjangoModelRawCall extends SqlInjectionSink { * A call to the `extra` method on a django model. This allows a raw SQL query * to be sent to the database, which is a security risk. */ - - class DjangoModelExtraCall extends SqlInjectionSink { DjangoModelExtraCall() { diff --git a/python/ql/src/semmle/python/web/django/Request.qll b/python/ql/src/semmle/python/web/django/Request.qll index bdd461ae6b7..7716118ab1f 100644 --- a/python/ql/src/semmle/python/web/django/Request.qll +++ b/python/ql/src/semmle/python/web/django/Request.qll @@ -67,9 +67,9 @@ abstract class DjangoRequestSource extends HttpRequestTaintSource { private class DjangoFunctionBasedViewRequestArgument extends DjangoRequestSource { DjangoFunctionBasedViewRequestArgument() { - exists(FunctionObject view | + exists(FunctionValue view | url_dispatch(_, _, view) and - this = view.getFunction().getArg(0).asName().getAFlowNode() + this = view.getScope().getArg(0).asName().getAFlowNode() ) } @@ -79,23 +79,24 @@ private class DjangoFunctionBasedViewRequestArgument extends DjangoRequestSource * https://docs.djangoproject.com/en/1.11/topics/class-based-views/ * */ -private class DjangoView extends ClassObject { +private class DjangoView extends ClassValue { DjangoView() { - ModuleObject::named("django.views.generic").attr("View") = this.getAnImproperSuperType() + Value::named("django.views.generic.View") = this.getASuperType() } + } -private FunctionObject djangoViewHttpMethod() { +private FunctionValue djangoViewHttpMethod() { exists(DjangoView view | - view.lookupAttribute(httpVerbLower()) = result + view.attr(httpVerbLower()) = result ) } class DjangoClassBasedViewRequestArgument extends DjangoRequestSource { DjangoClassBasedViewRequestArgument() { - this = djangoViewHttpMethod().getFunction().getArg(1).asName().getAFlowNode() + this = djangoViewHttpMethod().getScope().getArg(1).asName().getAFlowNode() } } @@ -107,11 +108,11 @@ class DjangoClassBasedViewRequestArgument extends DjangoRequestSource { /* Function based views */ -predicate url_dispatch(CallNode call, ControlFlowNode regex, FunctionObject view) { - exists(FunctionObject url | - ModuleObject::named("django.conf.urls").attr("url") = url and +predicate url_dispatch(CallNode call, ControlFlowNode regex, FunctionValue view) { + exists(FunctionValue url | + Value::named("django.conf.urls.url") = url and url.getArgumentForCall(call, 0) = regex and - url.getArgumentForCall(call, 1).refersTo(view) + url.getArgumentForCall(call, 1).pointsTo(view) ) } @@ -130,7 +131,7 @@ class UrlRouting extends CallNode { url_dispatch(this, _, _) } - FunctionObject getViewFunction() { + FunctionValue getViewFunction() { url_dispatch(this, _, result) } @@ -149,7 +150,7 @@ class HttpRequestParameter extends HttpRequestTaintSource { HttpRequestParameter() { exists(UrlRouting url | this.(ControlFlowNode).getNode() = - url.getViewFunction().getFunction().getArgByName(url.getNamedArgument()) + url.getViewFunction().getScope().getArgByName(url.getNamedArgument()) ) } diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index 45c5d50b336..7b1b483ea22 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -17,8 +17,8 @@ class DjangoResponse extends TaintKind { } -private ClassObject theDjangoHttpResponseClass() { - result = ModuleObject::named("django.http.response").attr("HttpResponse") and +private ClassValue theDjangoHttpResponseClass() { + result = Value::named("django.http.response.HttpResponse") and not result = theDjangoHttpRedirectClass() } @@ -26,8 +26,8 @@ private ClassObject theDjangoHttpResponseClass() { class DjangoResponseSource extends TaintSource { DjangoResponseSource() { - exists(ClassObject cls | - cls.getAnImproperSuperType() = theDjangoHttpResponseClass() and + exists(ClassValue cls | + cls.getASuperType() = theDjangoHttpResponseClass() and cls.getACall() = this ) } @@ -64,9 +64,9 @@ class DjangoResponseWrite extends HttpResponseTaintSink { class DjangoResponseContent extends HttpResponseTaintSink { DjangoResponseContent() { - exists(CallNode call, ClassObject cls | - cls.getAnImproperSuperType() = theDjangoHttpResponseClass() and - call.getFunction().refersTo(cls) | + exists(CallNode call, ClassValue cls | + cls.getASuperType() = theDjangoHttpResponseClass() and + call.getFunction().pointsTo(cls) | call.getArg(0) = this or call.getArgByName("content") = this diff --git a/python/ql/src/semmle/python/web/django/Shared.qll b/python/ql/src/semmle/python/web/django/Shared.qll index 86f802e15d6..b216d9de44c 100644 --- a/python/ql/src/semmle/python/web/django/Shared.qll +++ b/python/ql/src/semmle/python/web/django/Shared.qll @@ -1,9 +1,10 @@ import python -FunctionObject redirect() { - result = ModuleObject::named("django.shortcuts").attr("redirect") +/** django.shortcuts.redirect */ +FunctionValue redirect() { + result = Value::named("django.shortcuts.redirect") } -ClassObject theDjangoHttpRedirectClass() { - result = ModuleObject::named("django.http.response").attr("HttpResponseRedirectBase") +ClassValue theDjangoHttpRedirectClass() { + result = Value::named("django.http.response.HttpResponseRedirectBase") } From fc59b10ba4d62da5011fdff8ff5e65f5ce99bef9 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 27 Sep 2019 13:15:28 +0200 Subject: [PATCH 0280/1227] Python: Autoformat (4 spaces) django library --- python/ql/src/semmle/python/web/django/Db.qll | 43 +++------- .../ql/src/semmle/python/web/django/Model.qll | 72 ++++------------ .../src/semmle/python/web/django/Redirect.qll | 14 ++- .../src/semmle/python/web/django/Request.qll | 85 +++++-------------- .../src/semmle/python/web/django/Response.qll | 40 +++------ .../semmle/python/web/django/Sanitizers.qll | 5 +- .../src/semmle/python/web/django/Shared.qll | 4 +- 7 files changed, 67 insertions(+), 196 deletions(-) diff --git a/python/ql/src/semmle/python/web/django/Db.qll b/python/ql/src/semmle/python/web/django/Db.qll index 56db32849cc..00a36f5ba76 100644 --- a/python/ql/src/semmle/python/web/django/Db.qll +++ b/python/ql/src/semmle/python/web/django/Db.qll @@ -1,51 +1,37 @@ import python import semmle.python.security.injection.Sql -/** A taint kind representing a django cursor object. +/** + * A taint kind representing a django cursor object. */ class DjangoDbCursor extends DbCursor { - - DjangoDbCursor() { - this = "django.db.connection.cursor" - } - + DjangoDbCursor() { this = "django.db.connection.cursor" } } -private Value theDjangoConnectionObject() { - result = Value::named("django.db.connection") -} +private Value theDjangoConnectionObject() { result = Value::named("django.db.connection") } -/** A kind of taint source representing sources of django cursor objects. +/** + * A kind of taint source representing sources of django cursor objects. */ class DjangoDbCursorSource extends DbConnectionSource { - DjangoDbCursorSource() { exists(AttrNode cursor | - this.(CallNode).getFunction()= cursor and + this.(CallNode).getFunction() = cursor and cursor.getObject("cursor").pointsTo(theDjangoConnectionObject()) ) } - override string toString() { - result = "django.db.connection.cursor" - } - - override predicate isSourceOf(TaintKind kind) { - kind instanceof DjangoDbCursor - } + override string toString() { result = "django.db.connection.cursor" } + override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbCursor } } - -ClassValue theDjangoRawSqlClass() { - result = Value::named("django.db.models.expressions.RawSQL") -} +ClassValue theDjangoRawSqlClass() { result = Value::named("django.db.models.expressions.RawSQL") } /** * A sink of taint on calls to `django.db.models.expressions.RawSQL`. This * allows arbitrary SQL statements to be executed, which is a security risk. */ - class DjangoRawSqlSink extends SqlInjectionSink { DjangoRawSqlSink() { exists(CallNode call | @@ -54,12 +40,7 @@ class DjangoRawSqlSink extends SqlInjectionSink { ) } - override predicate sinks(TaintKind kind) { - kind instanceof ExternalStringKind - } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { - result = "django.db.models.expressions.RawSQL(sink,...)" - } + override string toString() { result = "django.db.models.expressions.RawSQL(sink,...)" } } - diff --git a/python/ql/src/semmle/python/web/django/Model.qll b/python/ql/src/semmle/python/web/django/Model.qll index 15bbe3e68c0..34cf5856802 100644 --- a/python/ql/src/semmle/python/web/django/Model.qll +++ b/python/ql/src/semmle/python/web/django/Model.qll @@ -1,5 +1,4 @@ import python - import semmle.python.security.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http @@ -7,19 +6,12 @@ import semmle.python.security.injection.Sql /** A django model class */ class DjangoModel extends ClassValue { - - DjangoModel() { - Value::named("django.db.models.Model") = this.getASuperType() - } - + DjangoModel() { Value::named("django.db.models.Model") = this.getASuperType() } } /** A "taint" for django database tables */ class DjangoDbTableObjects extends TaintKind { - - DjangoDbTableObjects() { - this = "django.db.models.Model.objects" - } + DjangoDbTableObjects() { this = "django.db.models.Model.objects" } override TaintKind getTaintOfMethodResult(string name) { result = this and @@ -53,102 +45,72 @@ class DjangoDbTableObjects extends TaintKind { /** Django model objects, which are sources of django database table "taint" */ class DjangoModelObjects extends TaintSource { - DjangoModelObjects() { this.(AttrNode).isLoad() and this.(AttrNode).getObject("objects").pointsTo(any(DjangoModel m)) } - override predicate isSourceOf(TaintKind kind) { - kind instanceof DjangoDbTableObjects - } - - override string toString() { - result = "django.db.models.Model.objects" - } + override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbTableObjects } + override string toString() { result = "django.db.models.Model.objects" } } /** A write to a field of a django model, which is a vulnerable to external data. */ class DjangoModelFieldWrite extends SqlInjectionSink { - DjangoModelFieldWrite() { exists(AttrNode attr, DjangoModel model | this = attr and attr.isStore() and attr.getObject(_).pointsTo(model) ) } - override predicate sinks(TaintKind kind) { - kind instanceof ExternalStringKind - } - - override string toString() { - result = "django model field write" - } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override string toString() { result = "django model field write" } } /** A direct reference to a django model object, which is vulnerable to external data. */ class DjangoModelDirectObjectReference extends TaintSink { - DjangoModelDirectObjectReference() { - exists(CallNode objects_get_call, ControlFlowNode objects | - this = objects_get_call.getAnArg() | + exists(CallNode objects_get_call, ControlFlowNode objects | this = objects_get_call.getAnArg() | objects_get_call.getFunction().(AttrNode).getObject("get") = objects and any(DjangoDbTableObjects objs).taints(objects) ) } - override predicate sinks(TaintKind kind) { - kind instanceof ExternalStringKind - } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { - result = "django model object reference" - } + override string toString() { result = "django model object reference" } } /** - * A call to the `raw` method on a django model. This allows a raw SQL query + * A call to the `raw` method on a django model. This allows a raw SQL query * to be sent to the database, which is a security risk. */ class DjangoModelRawCall extends SqlInjectionSink { - DjangoModelRawCall() { - exists(CallNode raw_call, ControlFlowNode queryset | - this = raw_call.getArg(0) | + exists(CallNode raw_call, ControlFlowNode queryset | this = raw_call.getArg(0) | raw_call.getFunction().(AttrNode).getObject("raw") = queryset and any(DjangoDbTableObjects objs).taints(queryset) ) } - override predicate sinks(TaintKind kind) { - kind instanceof ExternalStringKind - } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { - result = "django.models.QuerySet.raw(sink,...)" - } + override string toString() { result = "django.models.QuerySet.raw(sink,...)" } } /** - * A call to the `extra` method on a django model. This allows a raw SQL query + * A call to the `extra` method on a django model. This allows a raw SQL query * to be sent to the database, which is a security risk. */ class DjangoModelExtraCall extends SqlInjectionSink { - DjangoModelExtraCall() { - exists(CallNode extra_call, ControlFlowNode queryset | - this = extra_call.getArg(0) | + exists(CallNode extra_call, ControlFlowNode queryset | this = extra_call.getArg(0) | extra_call.getFunction().(AttrNode).getObject("extra") = queryset and any(DjangoDbTableObjects objs).taints(queryset) ) } - override predicate sinks(TaintKind kind) { - kind instanceof ExternalStringKind - } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { - result = "django.models.QuerySet.extra(sink,...)" - } + override string toString() { result = "django.models.QuerySet.extra(sink,...)" } } diff --git a/python/ql/src/semmle/python/web/django/Redirect.qll b/python/ql/src/semmle/python/web/django/Redirect.qll index 866a4b21383..87f0d81ec91 100644 --- a/python/ql/src/semmle/python/web/django/Redirect.qll +++ b/python/ql/src/semmle/python/web/django/Redirect.qll @@ -1,29 +1,25 @@ -/** Provides class representing the `django.redirect` function. +/** + * Provides class representing the `django.redirect` function. * This module is intended to be imported into a taint-tracking query * to extend `TaintSink`. */ -import python +import python import semmle.python.security.TaintTracking import semmle.python.security.strings.Basic private import semmle.python.web.django.Shared private import semmle.python.web.Http - /** * Represents an argument to the `django.redirect` function. */ class DjangoRedirect extends HttpRedirectTaintSink { - - override string toString() { - result = "django.redirect" - } + override string toString() { result = "django.redirect" } DjangoRedirect() { exists(CallNode call | redirect().getACall() = call and - this = call.getAnArg() + this = call.getAnArg() ) } - } diff --git a/python/ql/src/semmle/python/web/django/Request.qll b/python/ql/src/semmle/python/web/django/Request.qll index 7716118ab1f..d2ad2ff30d3 100644 --- a/python/ql/src/semmle/python/web/django/Request.qll +++ b/python/ql/src/semmle/python/web/django/Request.qll @@ -1,16 +1,11 @@ import python import semmle.python.regex - import semmle.python.security.TaintTracking import semmle.python.web.Http - /** A django.request.HttpRequest object */ class DjangoRequest extends TaintKind { - - DjangoRequest() { - this = "django.request.HttpRequest" - } + DjangoRequest() { this = "django.request.HttpRequest" } override TaintKind getTaintOfAttribute(string name) { (name = "GET" or name = "POST") and @@ -18,14 +13,13 @@ class DjangoRequest extends TaintKind { } override TaintKind getTaintOfMethodResult(string name) { - (name = "body" or name = "path") and result instanceof ExternalStringKind } } /* Helper for getTaintForStep() */ -pragma [noinline] +pragma[noinline] private predicate subscript_taint(SubscriptNode sub, ControlFlowNode obj, TaintKind kind) { sub.getValue() = obj and kind instanceof ExternalStringKind @@ -33,10 +27,7 @@ private predicate subscript_taint(SubscriptNode sub, ControlFlowNode obj, TaintK /** A django.request.QueryDict object */ class DjangoQueryDict extends TaintKind { - - DjangoQueryDict() { - this = "django.http.request.QueryDict" - } + DjangoQueryDict() { this = "django.http.request.QueryDict" } override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { this.taints(fromnode) and @@ -46,67 +37,46 @@ class DjangoQueryDict extends TaintKind { override TaintKind getTaintOfMethodResult(string name) { name = "get" and result instanceof ExternalStringKind } - } abstract class DjangoRequestSource extends HttpRequestTaintSource { + override string toString() { result = "Django request source" } - override string toString() { - result = "Django request source" - } - - override predicate isSourceOf(TaintKind kind) { - kind instanceof DjangoRequest - } - + override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoRequest } } -/** Function based views +/** + * Function based views * https://docs.djangoproject.com/en/1.11/topics/http/views/ */ private class DjangoFunctionBasedViewRequestArgument extends DjangoRequestSource { - DjangoFunctionBasedViewRequestArgument() { exists(FunctionValue view | url_dispatch(_, _, view) and this = view.getScope().getArg(0).asName().getAFlowNode() ) } - } -/** Class based views +/** + * Class based views * https://docs.djangoproject.com/en/1.11/topics/class-based-views/ - * */ private class DjangoView extends ClassValue { - - DjangoView() { - Value::named("django.views.generic.View") = this.getASuperType() - } - + DjangoView() { Value::named("django.views.generic.View") = this.getASuperType() } } private FunctionValue djangoViewHttpMethod() { - exists(DjangoView view | - view.attr(httpVerbLower()) = result - ) + exists(DjangoView view | view.attr(httpVerbLower()) = result) } class DjangoClassBasedViewRequestArgument extends DjangoRequestSource { - DjangoClassBasedViewRequestArgument() { this = djangoViewHttpMethod().getScope().getArg(1).asName().getAFlowNode() } - } - - - /* *********** Routing ********* */ - - /* Function based views */ predicate url_dispatch(CallNode call, ControlFlowNode regex, FunctionValue view) { exists(FunctionValue url | @@ -116,24 +86,14 @@ predicate url_dispatch(CallNode call, ControlFlowNode regex, FunctionValue view) ) } - class UrlRegex extends RegexString { - - UrlRegex() { - url_dispatch(_, this.getAFlowNode(), _) - } - + UrlRegex() { url_dispatch(_, this.getAFlowNode(), _) } } class UrlRouting extends CallNode { + UrlRouting() { url_dispatch(this, _, _) } - UrlRouting() { - url_dispatch(this, _, _) - } - - FunctionValue getViewFunction() { - url_dispatch(this, _, result) - } + FunctionValue getViewFunction() { url_dispatch(this, _, result) } string getNamedArgument() { exists(UrlRegex regex | @@ -141,25 +101,20 @@ class UrlRouting extends CallNode { regex.getGroupName(_, _) = result ) } - } /** An argument specified in a url routing table */ class HttpRequestParameter extends HttpRequestTaintSource { - HttpRequestParameter() { exists(UrlRouting url | - this.(ControlFlowNode).getNode() = - url.getViewFunction().getScope().getArgByName(url.getNamedArgument()) + this.(ControlFlowNode).getNode() = url + .getViewFunction() + .getScope() + .getArgByName(url.getNamedArgument()) ) } - override predicate isSourceOf(TaintKind kind) { - kind instanceof ExternalStringKind - } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { - result = "django.http.request.parameter" - } + override string toString() { result = "django.http.request.parameter" } } - diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index 7b1b483ea22..596ecd39c13 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -4,17 +4,13 @@ import semmle.python.security.strings.Basic private import semmle.python.web.django.Shared private import semmle.python.web.Http - -/** A django.http.response.Response object +/** + * A django.http.response.Response object * This isn't really a "taint", but we use the value tracking machinery to * track the flow of response objects. */ class DjangoResponse extends TaintKind { - - DjangoResponse() { - this = "django.response.HttpResponse" - } - + DjangoResponse() { this = "django.response.HttpResponse" } } private ClassValue theDjangoHttpResponseClass() { @@ -24,7 +20,6 @@ private ClassValue theDjangoHttpResponseClass() { /** Instantiation of a django response. */ class DjangoResponseSource extends TaintSource { - DjangoResponseSource() { exists(ClassValue cls | cls.getASuperType() = theDjangoHttpResponseClass() and @@ -34,14 +29,11 @@ class DjangoResponseSource extends TaintSource { override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponse } - override string toString() { - result = "django.http.response.HttpResponse" - } + override string toString() { result = "django.http.response.HttpResponse" } } /** A write to a django response, which is vulnerable to external data (xss) */ class DjangoResponseWrite extends HttpResponseTaintSink { - DjangoResponseWrite() { exists(AttrNode meth, CallNode call | call.getFunction() = meth and @@ -50,41 +42,30 @@ class DjangoResponseWrite extends HttpResponseTaintSink { ) } - override predicate sinks(TaintKind kind) { - kind instanceof StringKind - } - - override string toString() { - result = "django.Response.write(...)" - } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override string toString() { result = "django.Response.write(...)" } } /** An argument to initialization of a django response, which is vulnerable to external data (xss) */ class DjangoResponseContent extends HttpResponseTaintSink { - DjangoResponseContent() { exists(CallNode call, ClassValue cls | cls.getASuperType() = theDjangoHttpResponseClass() and - call.getFunction().pointsTo(cls) | + call.getFunction().pointsTo(cls) + | call.getArg(0) = this or call.getArgByName("content") = this ) } - override predicate sinks(TaintKind kind) { - kind instanceof StringKind - } - - override string toString() { - result = "django.Response(...)" - } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override string toString() { result = "django.Response(...)" } } class DjangoCookieSet extends CookieSet, CallNode { - DjangoCookieSet() { any(DjangoResponse r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) } @@ -94,5 +75,4 @@ class DjangoCookieSet extends CookieSet, CallNode { override ControlFlowNode getKey() { result = this.getArg(0) } override ControlFlowNode getValue() { result = this.getArg(1) } - } diff --git a/python/ql/src/semmle/python/web/django/Sanitizers.qll b/python/ql/src/semmle/python/web/django/Sanitizers.qll index db7f8aff8f8..e1694a1c481 100644 --- a/python/ql/src/semmle/python/web/django/Sanitizers.qll +++ b/python/ql/src/semmle/python/web/django/Sanitizers.qll @@ -1,7 +1,6 @@ import python - - -/* Sanitizers +/* + * Sanitizers * No django sanitizers implemented yet. */ diff --git a/python/ql/src/semmle/python/web/django/Shared.qll b/python/ql/src/semmle/python/web/django/Shared.qll index b216d9de44c..93161b3bc32 100644 --- a/python/ql/src/semmle/python/web/django/Shared.qll +++ b/python/ql/src/semmle/python/web/django/Shared.qll @@ -1,9 +1,7 @@ import python /** django.shortcuts.redirect */ -FunctionValue redirect() { - result = Value::named("django.shortcuts.redirect") -} +FunctionValue redirect() { result = Value::named("django.shortcuts.redirect") } ClassValue theDjangoHttpRedirectClass() { result = Value::named("django.http.response.HttpResponseRedirectBase") From 21513102f752ecd20c47c5d16fa1e722d2e6d0eb Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Fri, 27 Sep 2019 11:55:09 +0100 Subject: [PATCH 0281/1227] Compiler generated constructor Fixed a problem when the translating the compiler generated constructors that caused some sanity errors (since they have no body, when translating the constructor block fragmentation happened). Fixed this by skipping the translation of the body, if it does not exist (when translating a function). --- .../raw/internal/TranslatedFunction.qll | 14 +- .../ql/test/library-tests/ir/ir/indexers.cs | 4 - .../test/library-tests/ir/ir/raw_ir.expected | 175 ++++++++---------- 3 files changed, 92 insertions(+), 101 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll index 41f88e25766..1673e69ccab 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -75,7 +75,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { else if exists(getParameter(0)) then result = this.getParameter(0).getFirstInstruction() - else result = this.getBody().getFirstInstruction() + else result = this.getBodyOrReturn() ) or ( @@ -85,7 +85,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { else if exists(getConstructorInitializer()) then result = this.getConstructorInitializer().getFirstInstruction() - else result = this.getBody().getFirstInstruction() + else result = this.getBodyOrReturn() ) or tag = ReturnValueAddressTag() and @@ -110,16 +110,22 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { else if exists(getConstructorInitializer()) then result = this.getConstructorInitializer().getFirstInstruction() - else result = this.getBody().getFirstInstruction() + else result = this.getBodyOrReturn() ) or child = this.getConstructorInitializer() and - result = this.getBody().getFirstInstruction() + result = this.getBodyOrReturn() or child = this.getBody() and result = this.getReturnSuccessorInstruction() } + private Instruction getBodyOrReturn() { + if exists(this.getBody()) + then result = this.getBody().getFirstInstruction() + else result = this.getReturnSuccessorInstruction() + } + final override predicate hasInstruction( Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue ) { diff --git a/csharp/ql/test/library-tests/ir/ir/indexers.cs b/csharp/ql/test/library-tests/ir/ir/indexers.cs index c11e3b7ad62..dfe9c5fa21e 100644 --- a/csharp/ql/test/library-tests/ir/ir/indexers.cs +++ b/csharp/ql/test/library-tests/ir/ir/indexers.cs @@ -2,10 +2,6 @@ class Indexers { public class MyClass { - public MyClass() - { - } - private string[] address = new string[2]; public string this[int index] { diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index 116e3e77f33..4089b69f646 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -704,102 +704,91 @@ func_with_param_call.cs: # 10| v0_13(Void) = ExitFunction : indexers.cs: -# 5| System.Void Indexers.MyClass..ctor() -# 5| Block 0 -# 5| v0_0(Void) = EnterFunction : -# 5| mu0_1(null) = AliasedDefinition : -# 5| mu0_2(null) = UnmodeledDefinition : -# 5| r0_3(glval) = InitializeThis : -# 6| v0_4(Void) = NoOp : -# 5| v0_5(Void) = ReturnVoid : -# 5| v0_6(Void) = UnmodeledUse : mu* -# 5| v0_7(Void) = ExitFunction : +# 8| System.String Indexers.MyClass.get_Item(System.Int32) +# 8| Block 0 +# 8| v0_0(Void) = EnterFunction : +# 8| mu0_1(null) = AliasedDefinition : +# 8| mu0_2(null) = UnmodeledDefinition : +# 8| r0_3(glval) = InitializeThis : +# 6| r0_4(glval) = VariableAddress[index] : +# 6| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 +# 10| r0_6(glval) = VariableAddress[#return] : +# 10| r0_7(MyClass) = CopyValue : r0_3 +# 10| r0_8(glval) = FieldAddress[address] : r0_7 +# 10| r0_9(String[]) = ElementsAddress : r0_8 +# 10| r0_10(glval) = VariableAddress[index] : +# 10| r0_11(Int32) = Load : &:r0_10, ~mu0_2 +# 10| r0_12(String[]) = PointerAdd[8] : r0_9, r0_11 +# 10| r0_13(String) = Load : &:r0_12, ~mu0_2 +# 10| mu0_14(String) = Store : &:r0_6, r0_13 +# 8| r0_15(glval) = VariableAddress[#return] : +# 8| v0_16(Void) = ReturnValue : &:r0_15, ~mu0_2 +# 8| v0_17(Void) = UnmodeledUse : mu* +# 8| v0_18(Void) = ExitFunction : -# 12| System.String Indexers.MyClass.get_Item(System.Int32) +# 12| System.Void Indexers.MyClass.set_Item(System.Int32,System.String) # 12| Block 0 -# 12| v0_0(Void) = EnterFunction : -# 12| mu0_1(null) = AliasedDefinition : -# 12| mu0_2(null) = UnmodeledDefinition : -# 12| r0_3(glval) = InitializeThis : -# 10| r0_4(glval) = VariableAddress[index] : -# 10| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 -# 14| r0_6(glval) = VariableAddress[#return] : -# 14| r0_7(MyClass) = CopyValue : r0_3 -# 14| r0_8(glval) = FieldAddress[address] : r0_7 -# 14| r0_9(String[]) = ElementsAddress : r0_8 -# 14| r0_10(glval) = VariableAddress[index] : -# 14| r0_11(Int32) = Load : &:r0_10, ~mu0_2 -# 14| r0_12(String[]) = PointerAdd[8] : r0_9, r0_11 -# 14| r0_13(String) = Load : &:r0_12, ~mu0_2 -# 14| mu0_14(String) = Store : &:r0_6, r0_13 -# 12| r0_15(glval) = VariableAddress[#return] : -# 12| v0_16(Void) = ReturnValue : &:r0_15, ~mu0_2 -# 12| v0_17(Void) = UnmodeledUse : mu* -# 12| v0_18(Void) = ExitFunction : +# 12| v0_0(Void) = EnterFunction : +# 12| mu0_1(null) = AliasedDefinition : +# 12| mu0_2(null) = UnmodeledDefinition : +# 12| r0_3(glval) = InitializeThis : +# 6| r0_4(glval) = VariableAddress[index] : +# 6| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 +# 12| r0_6(glval) = VariableAddress[value] : +# 12| mu0_7(String) = InitializeParameter[value] : &:r0_6 +# 14| r0_8(glval) = VariableAddress[value] : +# 14| r0_9(String) = Load : &:r0_8, ~mu0_2 +# 14| r0_10(MyClass) = CopyValue : r0_3 +# 14| r0_11(glval) = FieldAddress[address] : r0_10 +# 14| r0_12(String[]) = ElementsAddress : r0_11 +# 14| r0_13(glval) = VariableAddress[index] : +# 14| r0_14(Int32) = Load : &:r0_13, ~mu0_2 +# 14| r0_15(String[]) = PointerAdd[8] : r0_12, r0_14 +# 14| mu0_16(String) = Store : &:r0_15, r0_9 +# 12| v0_17(Void) = ReturnVoid : +# 12| v0_18(Void) = UnmodeledUse : mu* +# 12| v0_19(Void) = ExitFunction : -# 16| System.Void Indexers.MyClass.set_Item(System.Int32,System.String) -# 16| Block 0 -# 16| v0_0(Void) = EnterFunction : -# 16| mu0_1(null) = AliasedDefinition : -# 16| mu0_2(null) = UnmodeledDefinition : -# 16| r0_3(glval) = InitializeThis : -# 10| r0_4(glval) = VariableAddress[index] : -# 10| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 -# 16| r0_6(glval) = VariableAddress[value] : -# 16| mu0_7(String) = InitializeParameter[value] : &:r0_6 -# 18| r0_8(glval) = VariableAddress[value] : -# 18| r0_9(String) = Load : &:r0_8, ~mu0_2 -# 18| r0_10(MyClass) = CopyValue : r0_3 -# 18| r0_11(glval) = FieldAddress[address] : r0_10 -# 18| r0_12(String[]) = ElementsAddress : r0_11 -# 18| r0_13(glval) = VariableAddress[index] : -# 18| r0_14(Int32) = Load : &:r0_13, ~mu0_2 -# 18| r0_15(String[]) = PointerAdd[8] : r0_12, r0_14 -# 18| mu0_16(String) = Store : &:r0_15, r0_9 -# 16| v0_17(Void) = ReturnVoid : -# 16| v0_18(Void) = UnmodeledUse : mu* -# 16| v0_19(Void) = ExitFunction : - -# 23| System.Void Indexers.Main() -# 23| Block 0 -# 23| v0_0(Void) = EnterFunction : -# 23| mu0_1(null) = AliasedDefinition : -# 23| mu0_2(null) = UnmodeledDefinition : -# 25| r0_3(glval) = VariableAddress[inst] : -# 25| r0_4(MyClass) = NewObj : -# 25| r0_5(glval) = FunctionAddress[MyClass] : -# 25| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 25| mu0_7(null) = ^CallSideEffect : ~mu0_2 -# 25| mu0_8(MyClass) = Store : &:r0_3, r0_4 -# 26| r0_9(glval) = VariableAddress[inst] : -# 26| r0_10(MyClass) = Load : &:r0_9, ~mu0_2 -# 26| r0_11(glval) = FunctionAddress[set_Item] : -# 26| r0_12(Int32) = Constant[0] : -# 26| r0_13(String) = StringConstant["str1"] : -# 26| v0_14(Void) = Call : func:r0_11, this:r0_10, 0:r0_12, 1:r0_13 -# 26| mu0_15(null) = ^CallSideEffect : ~mu0_2 -# 27| r0_16(glval) = VariableAddress[inst] : -# 27| r0_17(MyClass) = Load : &:r0_16, ~mu0_2 -# 27| r0_18(glval) = FunctionAddress[set_Item] : -# 27| r0_19(Int32) = Constant[1] : -# 27| r0_20(String) = StringConstant["str1"] : -# 27| v0_21(Void) = Call : func:r0_18, this:r0_17, 0:r0_19, 1:r0_20 -# 27| mu0_22(null) = ^CallSideEffect : ~mu0_2 -# 28| r0_23(glval) = VariableAddress[inst] : -# 28| r0_24(MyClass) = Load : &:r0_23, ~mu0_2 -# 28| r0_25(glval) = FunctionAddress[set_Item] : -# 28| r0_26(Int32) = Constant[1] : -# 28| r0_27(glval) = VariableAddress[inst] : -# 28| r0_28(MyClass) = Load : &:r0_27, ~mu0_2 -# 28| r0_29(glval) = FunctionAddress[get_Item] : -# 28| r0_30(Int32) = Constant[0] : -# 28| r0_31(String) = Call : func:r0_29, this:r0_28, 0:r0_30 -# 28| mu0_32(null) = ^CallSideEffect : ~mu0_2 -# 28| v0_33(Void) = Call : func:r0_25, this:r0_24, 0:r0_26, 1:r0_31 -# 28| mu0_34(null) = ^CallSideEffect : ~mu0_2 -# 23| v0_35(Void) = ReturnVoid : -# 23| v0_36(Void) = UnmodeledUse : mu* -# 23| v0_37(Void) = ExitFunction : +# 19| System.Void Indexers.Main() +# 19| Block 0 +# 19| v0_0(Void) = EnterFunction : +# 19| mu0_1(null) = AliasedDefinition : +# 19| mu0_2(null) = UnmodeledDefinition : +# 21| r0_3(glval) = VariableAddress[inst] : +# 21| r0_4(MyClass) = NewObj : +# 21| r0_5(glval) = FunctionAddress[MyClass] : +# 21| v0_6(Void) = Call : func:r0_5, this:r0_4 +# 21| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 21| mu0_8(MyClass) = Store : &:r0_3, r0_4 +# 22| r0_9(glval) = VariableAddress[inst] : +# 22| r0_10(MyClass) = Load : &:r0_9, ~mu0_2 +# 22| r0_11(glval) = FunctionAddress[set_Item] : +# 22| r0_12(Int32) = Constant[0] : +# 22| r0_13(String) = StringConstant["str1"] : +# 22| v0_14(Void) = Call : func:r0_11, this:r0_10, 0:r0_12, 1:r0_13 +# 22| mu0_15(null) = ^CallSideEffect : ~mu0_2 +# 23| r0_16(glval) = VariableAddress[inst] : +# 23| r0_17(MyClass) = Load : &:r0_16, ~mu0_2 +# 23| r0_18(glval) = FunctionAddress[set_Item] : +# 23| r0_19(Int32) = Constant[1] : +# 23| r0_20(String) = StringConstant["str1"] : +# 23| v0_21(Void) = Call : func:r0_18, this:r0_17, 0:r0_19, 1:r0_20 +# 23| mu0_22(null) = ^CallSideEffect : ~mu0_2 +# 24| r0_23(glval) = VariableAddress[inst] : +# 24| r0_24(MyClass) = Load : &:r0_23, ~mu0_2 +# 24| r0_25(glval) = FunctionAddress[set_Item] : +# 24| r0_26(Int32) = Constant[1] : +# 24| r0_27(glval) = VariableAddress[inst] : +# 24| r0_28(MyClass) = Load : &:r0_27, ~mu0_2 +# 24| r0_29(glval) = FunctionAddress[get_Item] : +# 24| r0_30(Int32) = Constant[0] : +# 24| r0_31(String) = Call : func:r0_29, this:r0_28, 0:r0_30 +# 24| mu0_32(null) = ^CallSideEffect : ~mu0_2 +# 24| v0_33(Void) = Call : func:r0_25, this:r0_24, 0:r0_26, 1:r0_31 +# 24| mu0_34(null) = ^CallSideEffect : ~mu0_2 +# 19| v0_35(Void) = ReturnVoid : +# 19| v0_36(Void) = UnmodeledUse : mu* +# 19| v0_37(Void) = ExitFunction : inheritance_polymorphism.cs: # 3| System.Int32 A.function() From f5b31ae9f5ceed8ecfe0220c340c5e94497db2f0 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Fri, 27 Sep 2019 12:21:47 +0100 Subject: [PATCH 0282/1227] Static fields The translation of static fields now uses `VariableAddress` instead of `FieldAddress`. This fixes the logic as well as the "field address without qualifier address" sanity check. --- .../raw/internal/TranslatedExpr.qll | 26 +++++++++++++------ csharp/ql/test/library-tests/ir/ir/prop.cs | 2 +- .../test/library-tests/ir/ir/raw_ir.expected | 11 ++++---- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index ac74c49f148..343846e300f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -833,16 +833,21 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr { class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { TranslatedNonFieldVariableAccess() { - not expr instanceof FieldAccess and - // If the parent expression is a `LocalVariableDeclAndInitExpr`, - // then translate only the variables that are initializers (on the RHS) - // and not the LHS (the address of the LHS is generated during - // the translation of the initialization). ( - expr.getParent() instanceof LocalVariableDeclAndInitExpr - implies - expr = expr.getParent().(LocalVariableDeclAndInitExpr).getInitializer() + not expr instanceof FieldAccess and + // If the parent expression is a `LocalVariableDeclAndInitExpr`, + // then translate only the variables that are initializers (on the RHS) + // and not the LHS (the address of the LHS is generated during + // the translation of the initialization). + ( + expr.getParent() instanceof LocalVariableDeclAndInitExpr + implies + expr = expr.getParent().(LocalVariableDeclAndInitExpr).getInitializer() + ) ) + or + // Static field accesses should be modeled as `TranslatedNonFieldAccess` + expr.(FieldAccess).getTarget().isStatic() } override Instruction getFirstInstruction() { @@ -874,6 +879,11 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { class TranslatedFieldAccess extends TranslatedVariableAccess { override FieldAccess expr; + + TranslatedFieldAccess() { + // Static field accesses should be modeled as `TranslatedNonFieldAccess` + not expr.getTarget().isStatic() + } override Instruction getFirstInstruction() { // If there is a qualifier diff --git a/csharp/ql/test/library-tests/ir/ir/prop.cs b/csharp/ql/test/library-tests/ir/ir/prop.cs index 942fcab2809..a075703d875 100644 --- a/csharp/ql/test/library-tests/ir/ir/prop.cs +++ b/csharp/ql/test/library-tests/ir/ir/prop.cs @@ -1,6 +1,6 @@ class PropClass { - private int prop; + private static int prop; public int Prop { diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index 4089b69f646..acba7e50086 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -1505,12 +1505,11 @@ prop.cs: # 12| mu0_5(Int32) = InitializeParameter[value] : &:r0_4 # 14| r0_6(glval) = VariableAddress[value] : # 14| r0_7(Int32) = Load : &:r0_6, ~mu0_2 -# 14| r0_8(PropClass) = CopyValue : r0_3 -# 14| r0_9(glval) = FieldAddress[prop] : r0_8 -# 14| mu0_10(Int32) = Store : &:r0_9, r0_7 -# 12| v0_11(Void) = ReturnVoid : -# 12| v0_12(Void) = UnmodeledUse : mu* -# 12| v0_13(Void) = ExitFunction : +# 14| r0_8(glval) = VariableAddress[prop] : +# 14| mu0_9(Int32) = Store : &:r0_8, r0_7 +# 12| v0_10(Void) = ReturnVoid : +# 12| v0_11(Void) = UnmodeledUse : mu* +# 12| v0_12(Void) = ExitFunction : # 18| System.Int32 PropClass.func() # 18| Block 0 From 70eca91d28675005440104467c439a9b895a8e23 Mon Sep 17 00:00:00 2001 From: alexey Date: Fri, 27 Sep 2019 12:36:38 +0100 Subject: [PATCH 0283/1227] Add tags tag to a Python query --- python/ql/src/Variables/UndefinedPlaceHolder.ql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/ql/src/Variables/UndefinedPlaceHolder.ql b/python/ql/src/Variables/UndefinedPlaceHolder.ql index f3eb960045c..0e6e5f07078 100644 --- a/python/ql/src/Variables/UndefinedPlaceHolder.ql +++ b/python/ql/src/Variables/UndefinedPlaceHolder.ql @@ -2,6 +2,8 @@ * @name Use of an undefined placeholder variable * @description Using a variable before it is initialized causes an exception. * @kind problem + * @tags reliability + * correctness * @problem.severity error * @sub-severity low * @precision medium From 921371d544912d2eb13ed5583113c4e86f976429 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 27 Sep 2019 13:51:56 +0200 Subject: [PATCH 0284/1227] Python: Modernise the cyclic import queries. --- python/ql/src/Imports/Cyclic.qll | 32 +++++++++---------- python/ql/src/Imports/CyclicImport.ql | 4 +-- .../ql/src/Imports/ModuleLevelCyclicImport.ql | 2 +- .../src/semmle/python/objects/ObjectAPI.qll | 6 ++++ 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/python/ql/src/Imports/Cyclic.qll b/python/ql/src/Imports/Cyclic.qll index b16e3ae147c..5bf38dc8713 100644 --- a/python/ql/src/Imports/Cyclic.qll +++ b/python/ql/src/Imports/Cyclic.qll @@ -4,47 +4,47 @@ predicate is_import_time(Stmt s) { not s.getScope+() instanceof Function } -PythonModuleObject module_imported_by(PythonModuleObject m) { +ModuleValue module_imported_by(ModuleValue m) { exists(Stmt imp | result = stmt_imports(imp) and - imp.getEnclosingModule() = m.getModule() and + imp.getEnclosingModule() = m.getScope() and // Import must reach exit to be part of a cycle imp.getAnEntryNode().getBasicBlock().reachesExit() ) } /** Is there a circular import of 'm1' beginning with 'm2'? */ -predicate circular_import(PythonModuleObject m1, PythonModuleObject m2) { +predicate circular_import(ModuleValue m1, ModuleValue m2) { m1 != m2 and m2 = module_imported_by(m1) and m1 = module_imported_by+(m2) } -ModuleObject stmt_imports(ImportingStmt s) { +ModuleValue stmt_imports(ImportingStmt s) { exists(string name | result.importedAs(name) and not name = "__main__" | name = s.getAnImportedModuleName() ) } -predicate import_time_imported_module(PythonModuleObject m1, PythonModuleObject m2, Stmt imp) { - imp.getEnclosingModule() = m1.getModule() and +predicate import_time_imported_module(ModuleValue m1, ModuleValue m2, Stmt imp) { + imp.getEnclosingModule() = m1.getScope() and is_import_time(imp) and m2 = stmt_imports(imp) } /** Is there a cyclic import of 'm1' beginning with an import 'm2' at 'imp' where all the imports are top-level? */ -predicate import_time_circular_import(PythonModuleObject m1, PythonModuleObject m2, Stmt imp) { +predicate import_time_circular_import(ModuleValue m1, ModuleValue m2, Stmt imp) { m1 != m2 and - import_time_imported_module(m1, m2, imp) and + import_time_imported_module(m1, m2, imp) and import_time_transitive_import(m2, _, m1) } -predicate import_time_transitive_import(PythonModuleObject base, Stmt imp, PythonModuleObject last) { +predicate import_time_transitive_import(ModuleValue base, Stmt imp, ModuleValue last) { last != base and ( import_time_imported_module(base, last, imp) or - exists(PythonModuleObject mid | + exists(ModuleValue mid | import_time_transitive_import(base, imp, mid) and import_time_imported_module(mid, last, _) ) @@ -56,11 +56,11 @@ predicate import_time_transitive_import(PythonModuleObject base, Stmt imp, Pytho /** * Returns import-time usages of module 'm' in module 'enclosing' */ -predicate import_time_module_use(PythonModuleObject m, PythonModuleObject enclosing, Expr use, string attr) { +predicate import_time_module_use(ModuleValue m, ModuleValue enclosing, Expr use, string attr) { exists(Expr mod | - use.getEnclosingModule() = enclosing.getModule() and + use.getEnclosingModule() = enclosing.getScope() and not use.getScope+() instanceof Function - and mod.refersTo(m) + and mod.pointsTo(m) | // either 'M.foo' use.(Attribute).getObject() = mod and use.(Attribute).getName() = attr @@ -74,14 +74,14 @@ predicate import_time_module_use(PythonModuleObject m, PythonModuleObject enclos AttributeError at 'use' (in module 'other') caused by 'first.attr' not being defined as its definition can occur after the import 'other' in 'first'. */ -predicate failing_import_due_to_cycle(PythonModuleObject first, PythonModuleObject other, Stmt imp, +predicate failing_import_due_to_cycle(ModuleValue first, ModuleValue other, Stmt imp, ControlFlowNode defn, Expr use, string attr) { import_time_imported_module(other, first, _) and import_time_transitive_import(first, imp, other) and import_time_module_use(first, other, use, attr) and - exists(ImportTimeScope n, SsaVariable v | + exists(ImportTimeScope n, SsaVariable v | defn = v.getDefinition() and - n = first.getModule() and v.getVariable().getScope() = n and v.getId() = attr | + n = first.getScope() and v.getVariable().getScope() = n and v.getId() = attr | not defn.strictlyDominates(imp.getAnEntryNode()) ) and not exists(If i | i.isNameEqMain() and i.contains(use)) diff --git a/python/ql/src/Imports/CyclicImport.ql b/python/ql/src/Imports/CyclicImport.ql index 1e1586c2f93..1b67f7ba858 100644 --- a/python/ql/src/Imports/CyclicImport.ql +++ b/python/ql/src/Imports/CyclicImport.ql @@ -14,9 +14,9 @@ import python import Cyclic -from PythonModuleObject m1, PythonModuleObject m2, Stmt imp +from ModuleValue m1, ModuleValue m2, Stmt imp where - imp.getEnclosingModule() = m1.getModule() + imp.getEnclosingModule() = m1.getScope() and stmt_imports(imp) = m2 and circular_import(m1, m2) and m1 != m2 diff --git a/python/ql/src/Imports/ModuleLevelCyclicImport.ql b/python/ql/src/Imports/ModuleLevelCyclicImport.ql index c7dc84e1094..3aa4bd55e2a 100644 --- a/python/ql/src/Imports/ModuleLevelCyclicImport.ql +++ b/python/ql/src/Imports/ModuleLevelCyclicImport.ql @@ -22,7 +22,7 @@ import Cyclic // then if we import the 'used' module, we will reach the cyclic import, start importing the 'using' // module, hit the 'use', and then crash due to the imported symbol not having been defined yet -from PythonModuleObject m1, Stmt imp, PythonModuleObject m2, string attr, Expr use, ControlFlowNode defn +from ModuleValue m1, Stmt imp, ModuleValue m2, string attr, Expr use, ControlFlowNode defn where failing_import_due_to_cycle(m1, m2, imp, defn, use, attr) select use, "'" + attr + "' may not be defined if module $@ is imported before module $@, " + "as the $@ of " + attr + " occurs after the cyclic $@ of " + m2.getName() + ".", diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 5181675b445..be604e0c918 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -133,6 +133,12 @@ class ModuleValue extends Value { result = this.(PythonModuleObjectInternal).getSourceModule().getFile() } + /** Whether this module is imported by 'import name'. For example on a linux system, + * the module 'posixpath' is imported as 'os.path' or as 'posixpath' */ + predicate importedAs(string name) { + PointsToInternal::module_imported_as(this, name) + } + } module Module { From c5cd5f489fdf2310d24a233f5ba1b9aa08f8bca6 Mon Sep 17 00:00:00 2001 From: AndreiDiaconu1 Date: Fri, 27 Sep 2019 13:07:20 +0100 Subject: [PATCH 0285/1227] Autoformat --- .../raw/internal/TranslatedExpr.qll | 20 +++++++++---------- .../raw/internal/TranslatedFunction.qll | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 343846e300f..3476484e413 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -833,17 +833,15 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr { class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { TranslatedNonFieldVariableAccess() { + not expr instanceof FieldAccess and + // If the parent expression is a `LocalVariableDeclAndInitExpr`, + // then translate only the variables that are initializers (on the RHS) + // and not the LHS (the address of the LHS is generated during + // the translation of the initialization). ( - not expr instanceof FieldAccess and - // If the parent expression is a `LocalVariableDeclAndInitExpr`, - // then translate only the variables that are initializers (on the RHS) - // and not the LHS (the address of the LHS is generated during - // the translation of the initialization). - ( - expr.getParent() instanceof LocalVariableDeclAndInitExpr - implies - expr = expr.getParent().(LocalVariableDeclAndInitExpr).getInitializer() - ) + expr.getParent() instanceof LocalVariableDeclAndInitExpr + implies + expr = expr.getParent().(LocalVariableDeclAndInitExpr).getInitializer() ) or // Static field accesses should be modeled as `TranslatedNonFieldAccess` @@ -879,7 +877,7 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { class TranslatedFieldAccess extends TranslatedVariableAccess { override FieldAccess expr; - + TranslatedFieldAccess() { // Static field accesses should be modeled as `TranslatedNonFieldAccess` not expr.getTarget().isStatic() diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll index 1673e69ccab..ef0e5fb6a67 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -125,7 +125,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { then result = this.getBody().getFirstInstruction() else result = this.getReturnSuccessorInstruction() } - + final override predicate hasInstruction( Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue ) { From aa16d20d5a600867271cea09a0443bb2fd3b9347 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 27 Sep 2019 14:50:03 +0200 Subject: [PATCH 0286/1227] Python: Fix false positive for cyclic imports guarded by `if False:`. --- python/ql/src/Imports/Cyclic.qll | 3 ++- python/ql/test/query-tests/Imports/cyclic-module/module10.py | 4 ++++ python/ql/test/query-tests/Imports/cyclic-module/typing.py | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 python/ql/test/query-tests/Imports/cyclic-module/typing.py diff --git a/python/ql/src/Imports/Cyclic.qll b/python/ql/src/Imports/Cyclic.qll index 5bf38dc8713..3f592011b23 100644 --- a/python/ql/src/Imports/Cyclic.qll +++ b/python/ql/src/Imports/Cyclic.qll @@ -22,7 +22,8 @@ predicate circular_import(ModuleValue m1, ModuleValue m2) { ModuleValue stmt_imports(ImportingStmt s) { exists(string name | result.importedAs(name) and not name = "__main__" | - name = s.getAnImportedModuleName() + name = s.getAnImportedModuleName() and + s.getASubExpression().pointsTo(result) ) } diff --git a/python/ql/test/query-tests/Imports/cyclic-module/module10.py b/python/ql/test/query-tests/Imports/cyclic-module/module10.py index 68127cc21fd..49975a86c09 100644 --- a/python/ql/test/query-tests/Imports/cyclic-module/module10.py +++ b/python/ql/test/query-tests/Imports/cyclic-module/module10.py @@ -1,5 +1,9 @@ +from typing import TYPE_CHECKING if False: import module1 +if TYPE_CHECKING: + import module1 + x = 1 diff --git a/python/ql/test/query-tests/Imports/cyclic-module/typing.py b/python/ql/test/query-tests/Imports/cyclic-module/typing.py new file mode 100644 index 00000000000..db21969beca --- /dev/null +++ b/python/ql/test/query-tests/Imports/cyclic-module/typing.py @@ -0,0 +1,2 @@ +TYPE_CHECKING = False + From c5c84a11d8b30dda1938e3bee8c0d516f375c6af Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 27 Sep 2019 15:07:34 +0200 Subject: [PATCH 0287/1227] Python: Autoformat. --- python/ql/src/Imports/Cyclic.qll | 46 ++++++++++--------- python/ql/src/Imports/CyclicImport.ql | 17 ++++--- .../ql/src/Imports/ModuleLevelCyclicImport.ql | 11 ++--- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/python/ql/src/Imports/Cyclic.qll b/python/ql/src/Imports/Cyclic.qll index 3f592011b23..bcda354ed95 100644 --- a/python/ql/src/Imports/Cyclic.qll +++ b/python/ql/src/Imports/Cyclic.qll @@ -1,8 +1,6 @@ import python -predicate is_import_time(Stmt s) { - not s.getScope+() instanceof Function -} +predicate is_import_time(Stmt s) { not s.getScope+() instanceof Function } ModuleValue module_imported_by(ModuleValue m) { exists(Stmt imp | @@ -16,12 +14,12 @@ ModuleValue module_imported_by(ModuleValue m) { /** Is there a circular import of 'm1' beginning with 'm2'? */ predicate circular_import(ModuleValue m1, ModuleValue m2) { m1 != m2 and - m2 = module_imported_by(m1) and m1 = module_imported_by+(m2) + m2 = module_imported_by(m1) and + m1 = module_imported_by+(m2) } ModuleValue stmt_imports(ImportingStmt s) { - exists(string name | - result.importedAs(name) and not name = "__main__" | + exists(string name | result.importedAs(name) and not name = "__main__" | name = s.getAnImportedModuleName() and s.getASubExpression().pointsTo(result) ) @@ -45,8 +43,8 @@ predicate import_time_transitive_import(ModuleValue base, Stmt imp, ModuleValue ( import_time_imported_module(base, last, imp) or - exists(ModuleValue mid | - import_time_transitive_import(base, imp, mid) and + exists(ModuleValue mid | + import_time_transitive_import(base, imp, mid) and import_time_imported_module(mid, last, _) ) ) and @@ -58,11 +56,11 @@ predicate import_time_transitive_import(ModuleValue base, Stmt imp, ModuleValue * Returns import-time usages of module 'm' in module 'enclosing' */ predicate import_time_module_use(ModuleValue m, ModuleValue enclosing, Expr use, string attr) { - exists(Expr mod | + exists(Expr mod | use.getEnclosingModule() = enclosing.getScope() and - not use.getScope+() instanceof Function - and mod.pointsTo(m) - | + not use.getScope+() instanceof Function and + mod.pointsTo(m) + | // either 'M.foo' use.(Attribute).getObject() = mod and use.(Attribute).getName() = attr or @@ -71,20 +69,24 @@ predicate import_time_module_use(ModuleValue m, ModuleValue enclosing, Expr use, ) } -/** Whether importing module 'first' before importing module 'other' will fail at runtime, due to an - AttributeError at 'use' (in module 'other') caused by 'first.attr' not being defined as its definition can - occur after the import 'other' in 'first'. -*/ -predicate failing_import_due_to_cycle(ModuleValue first, ModuleValue other, Stmt imp, - ControlFlowNode defn, Expr use, string attr) { +/** + * Whether importing module 'first' before importing module 'other' will fail at runtime, due to an + * AttributeError at 'use' (in module 'other') caused by 'first.attr' not being defined as its definition can + * occur after the import 'other' in 'first'. + */ +predicate failing_import_due_to_cycle( + ModuleValue first, ModuleValue other, Stmt imp, ControlFlowNode defn, Expr use, string attr +) { import_time_imported_module(other, first, _) and import_time_transitive_import(first, imp, other) and import_time_module_use(first, other, use, attr) and exists(ImportTimeScope n, SsaVariable v | defn = v.getDefinition() and - n = first.getScope() and v.getVariable().getScope() = n and v.getId() = attr | + n = first.getScope() and + v.getVariable().getScope() = n and + v.getId() = attr + | not defn.strictlyDominates(imp.getAnEntryNode()) - ) - and not exists(If i | i.isNameEqMain() and i.contains(use)) + ) and + not exists(If i | i.isNameEqMain() and i.contains(use)) } - diff --git a/python/ql/src/Imports/CyclicImport.ql b/python/ql/src/Imports/CyclicImport.ql index 1b67f7ba858..e14b41acb8e 100644 --- a/python/ql/src/Imports/CyclicImport.ql +++ b/python/ql/src/Imports/CyclicImport.ql @@ -15,13 +15,12 @@ import python import Cyclic from ModuleValue m1, ModuleValue m2, Stmt imp -where - imp.getEnclosingModule() = m1.getScope() - and stmt_imports(imp) = m2 - and circular_import(m1, m2) - and m1 != m2 - // this query finds all cyclic imports that are *not* flagged by ModuleLevelCyclicImport - and not failing_import_due_to_cycle(m2, m1, _, _, _, _) - and not exists(If i | i.isNameEqMain() and i.contains(imp)) +where + imp.getEnclosingModule() = m1.getScope() and + stmt_imports(imp) = m2 and + circular_import(m1, m2) and + m1 != m2 and + // this query finds all cyclic imports that are *not* flagged by ModuleLevelCyclicImport + not failing_import_due_to_cycle(m2, m1, _, _, _, _) and + not exists(If i | i.isNameEqMain() and i.contains(imp)) select imp, "Import of module $@ begins an import cycle.", m2, m2.getName() - diff --git a/python/ql/src/Imports/ModuleLevelCyclicImport.ql b/python/ql/src/Imports/ModuleLevelCyclicImport.ql index 3aa4bd55e2a..8cdb25c4ca5 100644 --- a/python/ql/src/Imports/ModuleLevelCyclicImport.ql +++ b/python/ql/src/Imports/ModuleLevelCyclicImport.ql @@ -21,11 +21,10 @@ import Cyclic // 3. 'foo' is defined in M after the import in M which completes the cycle. // then if we import the 'used' module, we will reach the cyclic import, start importing the 'using' // module, hit the 'use', and then crash due to the imported symbol not having been defined yet - from ModuleValue m1, Stmt imp, ModuleValue m2, string attr, Expr use, ControlFlowNode defn where failing_import_due_to_cycle(m1, m2, imp, defn, use, attr) -select use, "'" + attr + "' may not be defined if module $@ is imported before module $@, " + -"as the $@ of " + attr + " occurs after the cyclic $@ of " + m2.getName() + ".", -m1, m1.getName(), m2, m2.getName(), defn, "definition", imp, "import" - - \ No newline at end of file +select use, + "'" + attr + "' may not be defined if module $@ is imported before module $@, as the $@ of " + + attr + " occurs after the cyclic $@ of " + m2.getName() + ".", + // Arguments for the placeholders in the above message: + m1, m1.getName(), m2, m2.getName(), defn, "definition", imp, "import" From 5585ccd5097d6ff595ab1c9a3cedb73eae055d6c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 27 Sep 2019 12:33:33 -0700 Subject: [PATCH 0288/1227] C#: Fix up after merge --- .../raw/internal/TranslatedExpr.qll | 2 +- .../test/library-tests/ir/ir/raw_ir.expected | 84 +++++++++---------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 5bb69a5c75d..589f42fc77d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -2147,7 +2147,7 @@ class TranslatedEventAccess extends TranslatedNonConstantExpr { override TranslatedElement getChild(int id) { id = 0 and result = this.getLValue() } override predicate hasInstruction( - Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue + Opcode opcode, InstructionTag tag, CSharpType resultType ) { none() } diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index f4dd0473597..acf84bbafb8 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -484,14 +484,14 @@ events.cs: # 8| System.Void Events..ctor() # 8| Block 0 # 8| v0_0(Void) = EnterFunction : -# 8| mu0_1(null) = AliasedDefinition : -# 8| mu0_2(null) = UnmodeledDefinition : +# 8| mu0_1() = AliasedDefinition : +# 8| mu0_2() = UnmodeledDefinition : # 8| r0_3(glval) = InitializeThis : # 10| r0_4(MyDel) = NewObj : -# 10| r0_5(glval) = FunctionAddress[MyDel] : +# 10| r0_5() = FunctionAddress[MyDel] : # 10| r0_6(glval) = FunctionAddress[Fun] : # 10| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6 -# 10| mu0_8(null) = ^CallSideEffect : ~mu0_2 +# 10| mu0_8() = ^CallSideEffect : ~mu0_2 # 10| r0_9(Events) = CopyValue : r0_3 # 10| r0_10(glval) = FieldAddress[Inst] : r0_9 # 10| mu0_11(MyDel) = Store : &:r0_10, r0_4 @@ -502,16 +502,16 @@ events.cs: # 13| System.Void Events.AddEvent() # 13| Block 0 # 13| v0_0(Void) = EnterFunction : -# 13| mu0_1(null) = AliasedDefinition : -# 13| mu0_2(null) = UnmodeledDefinition : +# 13| mu0_1() = AliasedDefinition : +# 13| mu0_2() = UnmodeledDefinition : # 13| r0_3(glval) = InitializeThis : # 15| r0_4(Events) = CopyValue : r0_3 -# 15| r0_5(glval) = FunctionAddress[add_MyEvent] : +# 15| r0_5() = FunctionAddress[add_MyEvent] : # 15| r0_6(Events) = CopyValue : r0_3 # 15| r0_7(glval) = FieldAddress[Inst] : r0_6 # 15| r0_8(MyDel) = Load : &:r0_7, ~mu0_2 # 15| v0_9(Void) = Call : func:r0_5, this:r0_4, 0:r0_8 -# 15| mu0_10(null) = ^CallSideEffect : ~mu0_2 +# 15| mu0_10() = ^CallSideEffect : ~mu0_2 # 13| v0_11(Void) = ReturnVoid : # 13| v0_12(Void) = UnmodeledUse : mu* # 13| v0_13(Void) = ExitFunction : @@ -519,16 +519,16 @@ events.cs: # 18| System.Void Events.RemoveEvent() # 18| Block 0 # 18| v0_0(Void) = EnterFunction : -# 18| mu0_1(null) = AliasedDefinition : -# 18| mu0_2(null) = UnmodeledDefinition : +# 18| mu0_1() = AliasedDefinition : +# 18| mu0_2() = UnmodeledDefinition : # 18| r0_3(glval) = InitializeThis : # 20| r0_4(Events) = CopyValue : r0_3 -# 20| r0_5(glval) = FunctionAddress[remove_MyEvent] : +# 20| r0_5() = FunctionAddress[remove_MyEvent] : # 20| r0_6(Events) = CopyValue : r0_3 # 20| r0_7(glval) = FieldAddress[Inst] : r0_6 # 20| r0_8(MyDel) = Load : &:r0_7, ~mu0_2 # 20| v0_9(Void) = Call : func:r0_5, this:r0_4, 0:r0_8 -# 20| mu0_10(null) = ^CallSideEffect : ~mu0_2 +# 20| mu0_10() = ^CallSideEffect : ~mu0_2 # 18| v0_11(Void) = ReturnVoid : # 18| v0_12(Void) = UnmodeledUse : mu* # 18| v0_13(Void) = ExitFunction : @@ -536,8 +536,8 @@ events.cs: # 23| System.String Events.Fun(System.String) # 23| Block 0 # 23| v0_0(Void) = EnterFunction : -# 23| mu0_1(null) = AliasedDefinition : -# 23| mu0_2(null) = UnmodeledDefinition : +# 23| mu0_1() = AliasedDefinition : +# 23| mu0_2() = UnmodeledDefinition : # 23| r0_3(glval) = InitializeThis : # 23| r0_4(glval) = VariableAddress[str] : # 23| mu0_5(String) = InitializeParameter[str] : &:r0_4 @@ -553,34 +553,34 @@ events.cs: # 28| System.Void Events.Main(System.String[]) # 28| Block 0 # 28| v0_0(Void) = EnterFunction : -# 28| mu0_1(null) = AliasedDefinition : -# 28| mu0_2(null) = UnmodeledDefinition : +# 28| mu0_1() = AliasedDefinition : +# 28| mu0_2() = UnmodeledDefinition : # 28| r0_3(glval) = VariableAddress[args] : # 28| mu0_4(String[]) = InitializeParameter[args] : &:r0_3 # 30| r0_5(glval) = VariableAddress[obj] : # 30| r0_6(Events) = NewObj : -# 30| r0_7(glval) = FunctionAddress[Events] : +# 30| r0_7() = FunctionAddress[Events] : # 30| v0_8(Void) = Call : func:r0_7, this:r0_6 -# 30| mu0_9(null) = ^CallSideEffect : ~mu0_2 +# 30| mu0_9() = ^CallSideEffect : ~mu0_2 # 30| mu0_10(Events) = Store : &:r0_5, r0_6 # 31| r0_11(glval) = VariableAddress[obj] : # 31| r0_12(Events) = Load : &:r0_11, ~mu0_2 -# 31| r0_13(glval) = FunctionAddress[AddEvent] : +# 31| r0_13() = FunctionAddress[AddEvent] : # 31| v0_14(Void) = Call : func:r0_13, this:r0_12 -# 31| mu0_15(null) = ^CallSideEffect : ~mu0_2 +# 31| mu0_15() = ^CallSideEffect : ~mu0_2 # 32| r0_16(glval) = VariableAddress[result] : # 32| r0_17(glval) = VariableAddress[obj] : # 32| r0_18(Events) = Load : &:r0_17, ~mu0_2 -# 32| r0_19(glval) = FunctionAddress[Invoke] : +# 32| r0_19() = FunctionAddress[Invoke] : # 32| r0_20(String) = StringConstant["string"] : # 32| v0_21(Void) = Call : func:r0_19, this:r0_18, 0:r0_20 -# 32| mu0_22(null) = ^CallSideEffect : ~mu0_2 +# 32| mu0_22() = ^CallSideEffect : ~mu0_2 # 32| mu0_23(String) = Store : &:r0_16, v0_21 # 33| r0_24(glval) = VariableAddress[obj] : # 33| r0_25(Events) = Load : &:r0_24, ~mu0_2 -# 33| r0_26(glval) = FunctionAddress[RemoveEvent] : +# 33| r0_26() = FunctionAddress[RemoveEvent] : # 33| v0_27(Void) = Call : func:r0_26, this:r0_25 -# 33| mu0_28(null) = ^CallSideEffect : ~mu0_2 +# 33| mu0_28() = ^CallSideEffect : ~mu0_2 # 28| v0_29(Void) = ReturnVoid : # 28| v0_30(Void) = UnmodeledUse : mu* # 28| v0_31(Void) = ExitFunction : @@ -707,8 +707,8 @@ indexers.cs: # 5| System.Void Indexers.MyClass..ctor() # 5| Block 0 # 5| v0_0(Void) = EnterFunction : -# 5| mu0_1(null) = AliasedDefinition : -# 5| mu0_2(null) = UnmodeledDefinition : +# 5| mu0_1() = AliasedDefinition : +# 5| mu0_2() = UnmodeledDefinition : # 5| r0_3(glval) = InitializeThis : # 6| v0_4(Void) = NoOp : # 5| v0_5(Void) = ReturnVoid : @@ -718,8 +718,8 @@ indexers.cs: # 12| System.String Indexers.MyClass.get_Item(System.Int32) # 12| Block 0 # 12| v0_0(Void) = EnterFunction : -# 12| mu0_1(null) = AliasedDefinition : -# 12| mu0_2(null) = UnmodeledDefinition : +# 12| mu0_1() = AliasedDefinition : +# 12| mu0_2() = UnmodeledDefinition : # 12| r0_3(glval) = InitializeThis : # 10| r0_4(glval) = VariableAddress[index] : # 10| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 @@ -740,8 +740,8 @@ indexers.cs: # 16| System.Void Indexers.MyClass.set_Item(System.Int32,System.String) # 16| Block 0 # 16| v0_0(Void) = EnterFunction : -# 16| mu0_1(null) = AliasedDefinition : -# 16| mu0_2(null) = UnmodeledDefinition : +# 16| mu0_1() = AliasedDefinition : +# 16| mu0_2() = UnmodeledDefinition : # 16| r0_3(glval) = InitializeThis : # 10| r0_4(glval) = VariableAddress[index] : # 10| mu0_5(Int32) = InitializeParameter[index] : &:r0_4 @@ -763,40 +763,40 @@ indexers.cs: # 23| System.Void Indexers.Main() # 23| Block 0 # 23| v0_0(Void) = EnterFunction : -# 23| mu0_1(null) = AliasedDefinition : -# 23| mu0_2(null) = UnmodeledDefinition : +# 23| mu0_1() = AliasedDefinition : +# 23| mu0_2() = UnmodeledDefinition : # 25| r0_3(glval) = VariableAddress[inst] : # 25| r0_4(MyClass) = NewObj : -# 25| r0_5(glval) = FunctionAddress[MyClass] : +# 25| r0_5() = FunctionAddress[MyClass] : # 25| v0_6(Void) = Call : func:r0_5, this:r0_4 -# 25| mu0_7(null) = ^CallSideEffect : ~mu0_2 +# 25| mu0_7() = ^CallSideEffect : ~mu0_2 # 25| mu0_8(MyClass) = Store : &:r0_3, r0_4 # 26| r0_9(glval) = VariableAddress[inst] : # 26| r0_10(MyClass) = Load : &:r0_9, ~mu0_2 -# 26| r0_11(glval) = FunctionAddress[set_Item] : +# 26| r0_11() = FunctionAddress[set_Item] : # 26| r0_12(Int32) = Constant[0] : # 26| r0_13(String) = StringConstant["str1"] : # 26| v0_14(Void) = Call : func:r0_11, this:r0_10, 0:r0_12, 1:r0_13 -# 26| mu0_15(null) = ^CallSideEffect : ~mu0_2 +# 26| mu0_15() = ^CallSideEffect : ~mu0_2 # 27| r0_16(glval) = VariableAddress[inst] : # 27| r0_17(MyClass) = Load : &:r0_16, ~mu0_2 -# 27| r0_18(glval) = FunctionAddress[set_Item] : +# 27| r0_18() = FunctionAddress[set_Item] : # 27| r0_19(Int32) = Constant[1] : # 27| r0_20(String) = StringConstant["str1"] : # 27| v0_21(Void) = Call : func:r0_18, this:r0_17, 0:r0_19, 1:r0_20 -# 27| mu0_22(null) = ^CallSideEffect : ~mu0_2 +# 27| mu0_22() = ^CallSideEffect : ~mu0_2 # 28| r0_23(glval) = VariableAddress[inst] : # 28| r0_24(MyClass) = Load : &:r0_23, ~mu0_2 -# 28| r0_25(glval) = FunctionAddress[set_Item] : +# 28| r0_25() = FunctionAddress[set_Item] : # 28| r0_26(Int32) = Constant[1] : # 28| r0_27(glval) = VariableAddress[inst] : # 28| r0_28(MyClass) = Load : &:r0_27, ~mu0_2 -# 28| r0_29(glval) = FunctionAddress[get_Item] : +# 28| r0_29() = FunctionAddress[get_Item] : # 28| r0_30(Int32) = Constant[0] : # 28| r0_31(String) = Call : func:r0_29, this:r0_28, 0:r0_30 -# 28| mu0_32(null) = ^CallSideEffect : ~mu0_2 +# 28| mu0_32() = ^CallSideEffect : ~mu0_2 # 28| v0_33(Void) = Call : func:r0_25, this:r0_24, 0:r0_26, 1:r0_31 -# 28| mu0_34(null) = ^CallSideEffect : ~mu0_2 +# 28| mu0_34() = ^CallSideEffect : ~mu0_2 # 23| v0_35(Void) = ReturnVoid : # 23| v0_36(Void) = UnmodeledUse : mu* # 23| v0_37(Void) = ExitFunction : From f76334c24acaebf08186190fdcb7b9b89a5c2e2c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 27 Sep 2019 13:46:42 -0700 Subject: [PATCH 0289/1227] C++, C#: Share unaliased SSA files between languages Most of the C# diffs are from bringing those files in sync with the latest C++ files. --- config/identical-files.json | 62 +++++++++++----- .../code/cpp/ir/implementation/IRType.qll | 2 +- .../aliased_ssa/internal/SSAConstruction.qll | 4 +- .../internal/SSAConstructionImports.qll | 3 + .../internal/SSAConstruction.qll | 4 +- .../internal/SSAConstructionImports.qll | 3 + .../unaliased_ssa/internal/SimpleSSA.qll | 6 +- .../internal/SimpleSSAImports.qll | 5 ++ .../raw/internal/OperandImports.qll | 2 +- .../ir/implementation/unaliased_ssa/IR.qll | 1 + .../implementation/unaliased_ssa/IRSanity.qll | 1 + .../unaliased_ssa/IRVariable.qll | 25 +++++-- .../unaliased_ssa/Instruction.qll | 70 ++++++++++--------- .../implementation/unaliased_ssa/Operand.qll | 48 +++++++------ .../unaliased_ssa/internal/IRImports.qll | 1 + .../internal/IRVariableImports.qll | 1 + .../internal/InstructionImports.qll | 1 + .../unaliased_ssa/internal/OperandImports.qll | 1 + .../unaliased_ssa/internal/PrintSSA.qll | 64 +++++++++++------ .../internal/SSAConstruction.qll | 51 ++++---------- .../internal/SSAConstructionImports.qll | 3 + .../internal/SSAConstructionInternal.qll | 1 + .../unaliased_ssa/internal/SimpleSSA.qll | 25 +++---- .../internal/SimpleSSAImports.qll | 5 ++ .../ir/ir/unaliased_ssa_sanity.expected | 2 + 25 files changed, 226 insertions(+), 165 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll diff --git a/config/identical-files.json b/config/identical-files.json index 2c19f84ea23..1eff7dc3229 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -47,31 +47,36 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll" ], "IR IRBlock": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll" ], "IR IRVariable": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll" ], "IR IRFunction": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll" ], "IR Operand": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll" ], "IR IRType": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll", @@ -89,19 +94,22 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll" ], "IR IRSanity": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll" ], "IR PrintIR": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll" ], "IR IntegerConstant": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll", @@ -165,17 +173,27 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintIRImports.qll" ], + "C++ SSA SSAConstructionImports": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll" + ], "C++ SSA AliasAnalysis": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll" ], - "C++ SSA SSAConstruction": [ - "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll" + "IR SSA SimpleSSA": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll" ], - "C++ SSA PrintSSA": [ + "IR SSA SSAConstruction": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll" + ], + "IR SSA PrintSSA": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll" + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll" ], "C++ IR ValueNumber": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll", @@ -209,21 +227,27 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll" ], "C# IR InstructionImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll" ], "C# IR IRImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll" ], "C# IR IRBlockImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll" ], "C# IR IRVariableImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll" ], "C# IR OperandImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll" ], "C# IR PrintIRImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll" ] } 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 053b018eaf5..163d384c759 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -4,7 +4,7 @@ private import internal.IRTypeInternal -newtype TIRType = +private newtype TIRType = TIRVoidType() or TIRUnknownType() or TIRErrorType() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 9c1b52ed4e5..148fd65d264 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -1,7 +1,5 @@ import SSAConstructionInternal -private import semmle.code.cpp.ir.implementation.Opcode -private import semmle.code.cpp.ir.implementation.internal.OperandTag -private import semmle.code.cpp.ir.internal.Overlap +private import SSAConstructionImports private import NewIR private class OldBlock = Reachability::ReachableBlock; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll new file mode 100644 index 00000000000..00f12020a29 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll @@ -0,0 +1,3 @@ +import semmle.code.cpp.ir.implementation.Opcode +import semmle.code.cpp.ir.implementation.internal.OperandTag +import semmle.code.cpp.ir.internal.Overlap diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 9c1b52ed4e5..148fd65d264 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,7 +1,5 @@ import SSAConstructionInternal -private import semmle.code.cpp.ir.implementation.Opcode -private import semmle.code.cpp.ir.implementation.internal.OperandTag -private import semmle.code.cpp.ir.internal.Overlap +private import SSAConstructionImports private import NewIR private class OldBlock = Reachability::ReachableBlock; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll new file mode 100644 index 00000000000..00f12020a29 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -0,0 +1,3 @@ +import semmle.code.cpp.ir.implementation.Opcode +import semmle.code.cpp.ir.implementation.internal.OperandTag +import semmle.code.cpp.ir.internal.Overlap diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index 5577799513c..e23f67b2d96 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -1,9 +1,5 @@ import AliasAnalysis -private import semmle.code.cpp.ir.implementation.raw.IR -private import semmle.code.cpp.ir.internal.IntegerConstant as Ints -private import semmle.code.cpp.ir.implementation.internal.OperandTag -private import semmle.code.cpp.ir.internal.IRCppLanguage as Language -private import semmle.code.cpp.ir.internal.Overlap +private import SimpleSSAImports private class IntValue = Ints::IntValue; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll new file mode 100644 index 00000000000..8f160f5a456 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll @@ -0,0 +1,5 @@ +import semmle.code.cpp.ir.implementation.raw.IR +import semmle.code.cpp.ir.internal.IntegerConstant as Ints +import semmle.code.cpp.ir.implementation.internal.OperandTag +import semmle.code.cpp.ir.internal.IRCppLanguage as Language +import semmle.code.cpp.ir.internal.Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll index 19e753f8a4a..997185fb9f7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll @@ -1,4 +1,4 @@ -import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.internal.Overlap as Overlap import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll index 278040f8ab8..badd48552a5 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll @@ -5,6 +5,7 @@ import IRVariable import Operand private import internal.IRImports as Imports import Imports::EdgeKind +import Imports::IRType import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll index 3921472dc8e..6ee2e687015 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll @@ -1,2 +1,3 @@ private import IR import InstructionSanity +import IRTypeSanity \ No newline at end of file diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll index a7ca4593ac4..d17b810785e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -5,6 +5,7 @@ import Imports::TempVariableTag private import Imports::IRUtilities private import Imports::TTempVariableTag private import Imports::TIRVariable +private import Imports::IRType IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { result.getVariable() = var and @@ -24,7 +25,21 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - abstract Language::Type getType(); + final Language::Type getType() { + getLanguageType().hasType(result, false) + } + + /** + * Gets the language-neutral type of the variable. + */ + final IRType getIRType() { + result = getLanguageType().getIRType() + } + + /** + * Gets the type of the variable. + */ + abstract Language::LanguageType getLanguageType(); /** * Gets the AST node that declared this variable, or that introduced this @@ -59,7 +74,7 @@ abstract class IRVariable extends TIRVariable { */ class IRUserVariable extends IRVariable, TIRUserVariable { Language::Variable var; - Language::Type type; + Language::LanguageType type; IRUserVariable() { this = TIRUserVariable(var, type, func) } @@ -71,7 +86,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable { result = getVariable().toString() + " " + getVariable().getLocation().toString() } - final override Language::Type getType() { result = type } + final override Language::LanguageType getLanguageType() { result = type } /** * Gets the original user-declared variable. @@ -110,11 +125,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { Language::AST ast; TempVariableTag tag; - Language::Type type; + Language::LanguageType type; IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - final override Language::Type getType() { result = type } + final override Language::LanguageType getLanguageType() { result = type } final override Language::AST getAST() { result = ast } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 43f9663d2cd..01e2d219652 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -5,6 +5,7 @@ import IRVariable import Operand private import internal.InstructionImports as Imports import Imports::EdgeKind +import Imports::IRType import Imports::MemoryAccessKind import Imports::Opcode private import Imports::OperandTag @@ -113,10 +114,13 @@ module InstructionSanity { } query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func | + exists(Language::Function func, Instruction use | not exists(operand.getType()) and - func = operand.getUse().getEnclosingFunction() and - message = "Operand missing type in function '" + Language::getIdentityString(func) + "'." + use = operand.getUse() and + func = use.getEnclosingFunction() and + message = "Operand '" + operand.toString() + "' of instruction '" + + use.getOpcode().toString() + "' missing type in function '" + + Language::getIdentityString(func) + "'." ) } @@ -312,7 +316,7 @@ class Instruction extends Construction::TInstruction { } private string getResultPrefix() { - if getResultType() instanceof Language::VoidType + if getResultIRType() instanceof IRVoidType then result = "v" else if hasMemoryResult() @@ -344,23 +348,6 @@ class Instruction extends Construction::TInstruction { ) } - bindingset[type] - private string getValueCategoryString(string type) { - if isGLValue() then result = "glval<" + type + ">" else result = type - } - - string getResultTypeString() { - exists(string valcat | - valcat = getValueCategoryString(getResultType().toString()) and - if - getResultType() instanceof Language::UnknownType and - not isGLValue() and - exists(getResultSize()) - then result = valcat + "[" + getResultSize().toString() + "]" - else result = valcat - ) - } - /** * Gets a human-readable string that uniquely identifies this instruction * within the function. This string is used to refer to this instruction when @@ -380,7 +367,9 @@ class Instruction extends Construction::TInstruction { * * Example: `r1_1(int*)` */ - final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" } + final string getResultString() { + result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")" + } /** * Gets a string describing the operands of this instruction, suitable for @@ -448,6 +437,16 @@ class Instruction extends Construction::TInstruction { result = Construction::getInstructionUnconvertedResultExpression(this) } + final Language::LanguageType getResultLanguageType() { + result = Construction::getInstructionResultType(this) + } + + /** + * Gets the type of the result produced by this instruction. If the instruction does not produce + * a result, its result type will be `IRVoidType`. + */ + final IRType getResultIRType() { result = getResultLanguageType().getIRType() } + /** * Gets the type of the result produced by this instruction. If the * instruction does not produce a result, its result type will be `VoidType`. @@ -455,7 +454,15 @@ class Instruction extends Construction::TInstruction { * If `isGLValue()` holds, then the result type of this instruction should be * thought of as "pointer to `getResultType()`". */ - final Language::Type getResultType() { Construction::instructionHasType(this, result, _) } + final Language::Type getResultType() { + exists(Language::LanguageType resultType | + resultType = getResultLanguageType() and + ( + resultType.hasUnspecifiedType(result, _) or + not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType + ) + ) + } /** * Holds if the result produced by this instruction is a glvalue. If this @@ -475,7 +482,9 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::instructionHasType(this, _, true) } + final predicate isGLValue() { + Construction::getInstructionResultType(this).hasType(_, true) + } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -485,14 +494,7 @@ class Instruction extends Construction::TInstruction { * `getResultSize()` will always be the size of a pointer. */ final int getResultSize() { - if isGLValue() - then - // a glvalue is always pointer-sized. - result = Language::getPointerSize() - else - if getResultType() instanceof Language::UnknownType - then result = Construction::getInstructionResultSize(this) - else result = Language::getTypeSize(getResultType()) + result = Construction::getInstructionResultType(this).getByteSize() } /** @@ -1300,7 +1302,7 @@ class CatchInstruction extends Instruction { * An instruction that catches an exception of a specific type. */ class CatchByTypeInstruction extends CatchInstruction { - Language::Type exceptionType; + Language::LanguageType exceptionType; CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and @@ -1312,7 +1314,7 @@ class CatchByTypeInstruction extends CatchInstruction { /** * Gets the type of exception to be caught. */ - final Language::Type getExceptionType() { result = exceptionType } + final Language::LanguageType getExceptionType() { result = exceptionType } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index 1ced8ef3282..e3485825064 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -1,9 +1,10 @@ private import internal.IRInternal -import Instruction -import IRBlock +private import Instruction +private import IRBlock private import internal.OperandImports as Imports -import Imports::MemoryAccessKind -import Imports::Overlap +private import Imports::MemoryAccessKind +private import Imports::IRType +private import Imports::Overlap private import Imports::OperandTag cached @@ -143,22 +144,40 @@ class Operand extends TOperand { * the definition type, such as in the case of a partial read or a read from a pointer that * has been cast to a different type. */ - Language::Type getType() { result = getAnyDef().getResultType() } + Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() } + + /** + * Gets the language-neutral type of the value consumed by this operand. This is usually the same + * as the result type of the definition instruction consumed by this operand. For register + * operands, this is always the case. For some memory operands, the operand type may be different + * from the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + final IRType getIRType() { result = getLanguageType().getIRType() } + + /** + * Gets the type of the value consumed by this operand. This is usually the same as the + * result type of the definition instruction consumed by this operand. For register operands, + * this is always the case. For some memory operands, the operand type may be different from + * the definition type, such as in the case of a partial read or a read from a pointer that + * has been cast to a different type. + */ + final Language::Type getType() { getLanguageType().hasType(result, _) } /** * Holds if the value consumed by this operand is a glvalue. If this * holds, the value of the operand represents the address of a location, * and the type of the location is given by `getType()`. If this does * not hold, the value of the operand represents a value whose type is - * given by `getResultType()`. + * given by `getType()`. */ - predicate isGLValue() { getAnyDef().isGLValue() } + final predicate isGLValue() { getLanguageType().hasType(_, true) } /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. */ - int getSize() { result = Language::getTypeSize(getType()) } + final int getSize() { result = getLanguageType().getByteSize() } } /** @@ -170,11 +189,6 @@ class MemoryOperand extends Operand { this = TPhiOperand(_, _, _, _) } - override predicate isGLValue() { - // A `MemoryOperand` can never be a glvalue - none() - } - /** * Gets the kind of memory access performed by the operand. */ @@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; - final override Language::Type getType() { + final override Language::LanguageType getLanguageType() { result = Construction::getInstructionOperandType(useInstr, tag) } } @@ -371,12 +385,6 @@ class PositionalArgumentOperand extends ArgumentOperand { class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - final override int getSize() { - if getType() instanceof Language::UnknownType - then result = Construction::getInstructionOperandSize(useInstr, tag) - else result = Language::getTypeSize(getType()) - } - override MemoryAccessKind getMemoryAccess() { useInstr instanceof CallSideEffectInstruction and result instanceof EscapedMayMemoryAccess diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll index b5abc1049f3..3b716c201ac 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll @@ -1,2 +1,3 @@ import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll index 20c299416ef..9ab8de41259 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll @@ -1,3 +1,4 @@ +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll index da9b8e6e877..8628f5be373 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll @@ -1,4 +1,5 @@ import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.csharp.ir.implementation.Opcode as Opcode import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll index 13667df7276..997185fb9f7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll @@ -1,3 +1,4 @@ import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import semmle.code.csharp.ir.implementation.IRType as IRType import semmle.code.csharp.ir.internal.Overlap as Overlap import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll index a5c09c6401b..c73826bd4c8 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll @@ -4,34 +4,52 @@ private import Alias private import SSAConstruction private import DebugSSA +bindingset[offset] +private string getKeySuffixForOffset(int offset) { + if offset % 2 = 0 then result = "" else result = "_Chi" +} + +bindingset[offset] +private int getIndexForOffset(int offset) { result = offset / 2 } + /** * Property provide that dumps the memory access of each result. Useful for debugging SSA * construction. */ class PropertyProvider extends IRPropertyProvider { override string getInstructionProperty(Instruction instruction, string key) { - exists(MemoryLocation location | - location = getResultMemoryLocation(instruction) and - ( - key = "ResultMemoryLocation" and result = location.toString() - or - key = "ResultVirtualVariable" and result = location.getVirtualVariable().toString() + key = "ResultMemoryLocation" and + result = strictconcat(MemoryLocation loc | + loc = getResultMemoryLocation(instruction) + | + loc.toString(), "," ) - ) or - exists(MemoryLocation location | - location = getOperandMemoryLocation(instruction.getAnOperand()) and - ( - key = "OperandMemoryAccess" and result = location.toString() - or - key = "OperandVirtualVariable" and result = location.getVirtualVariable().toString() + key = "ResultVirtualVariable" and + result = strictconcat(MemoryLocation loc | + loc = getResultMemoryLocation(instruction) + | + loc.getVirtualVariable().toString(), "," ) - ) or - exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | - hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and - defBlock.getInstruction(defIndex) = instruction and - key = "DefinitionRank[" + useLocation.toString() + "]" and + key = "OperandMemoryLocation" and + result = strictconcat(MemoryLocation loc | + loc = getOperandMemoryLocation(instruction.getAnOperand()) + | + loc.toString(), "," + ) + or + key = "OperandVirtualVariable" and + result = strictconcat(MemoryLocation loc | + loc = getOperandMemoryLocation(instruction.getAnOperand()) + | + loc.getVirtualVariable().toString(), "," + ) + or + exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset | + hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and + defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and + key = "DefinitionRank" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + "]" and result = defRank.toString() ) or @@ -41,10 +59,11 @@ class PropertyProvider extends IRPropertyProvider { result = useRank.toString() ) or - exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | - hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and - defBlock.getInstruction(defIndex) = instruction and - key = "DefinitionReachesUse[" + useLocation.toString() + "]" and + exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset | + hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and + defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and + key = "DefinitionReachesUse" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + + "]" and result = strictconcat(IRBlock useBlock, int useRank, int useIndex | exists(Instruction useInstruction | hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and @@ -124,3 +143,4 @@ class PropertyProvider extends IRPropertyProvider { ) } } + diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 8f2ed18f060..148fd65d264 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,9 +1,6 @@ import SSAConstructionInternal -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.Overlap +private import SSAConstructionImports private import NewIR -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language private class OldBlock = Reachability::ReachableBlock; @@ -51,13 +48,13 @@ private module Cached { cached predicate hasTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::Type type + Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type ) { exists(OldIR::IRTempVariable var | var.getEnclosingFunction() = func and var.getAST() = ast and var.getTag() = tag and - var.getType() = type + var.getLanguageType() = type ) } @@ -137,24 +134,12 @@ private module Cached { } cached - Language::Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) { + Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) { exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | oldInstruction = getOldInstruction(instr) and oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and - result = oldOperand.getType() - ) - } - - cached - int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) { - exists(OldInstruction oldInstruction, OldIR::SideEffectOperand oldOperand | - oldInstruction = getOldInstruction(instr) and - oldOperand = oldInstruction.getAnOperand() and - tag = oldOperand.getOperandTag() and - // Only return a result for operands that need an explicit result size. - oldOperand.getType() instanceof Language::UnknownType and - result = oldOperand.getSize() + result = oldOperand.getLanguageType() ) } @@ -273,29 +258,25 @@ private module Cached { } cached - predicate instructionHasType(Instruction instruction, Language::Type type, boolean isGLValue) { + Language::LanguageType getInstructionResultType(Instruction instruction) { exists(OldInstruction oldInstruction | instruction = WrappedInstruction(oldInstruction) and - type = oldInstruction.getResultType() and - if oldInstruction.isGLValue() then isGLValue = true else isGLValue = false + result = oldInstruction.getResultLanguageType() ) or exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | instruction = Chi(oldInstruction) and hasChiNode(vvar, oldInstruction) and - type = vvar.getType() and - isGLValue = false + result = vvar.getType() ) or exists(Alias::MemoryLocation location | instruction = Phi(_, location) and - type = location.getType() and - isGLValue = false + result = location.getType() ) or instruction = Unreached(_) and - type instanceof Language::VoidType and - isGLValue = false + result = Language::getVoidType() } cached @@ -368,7 +349,7 @@ private module Cached { } cached - Language::Type getInstructionExceptionType(Instruction instruction) { + Language::LanguageType getInstructionExceptionType(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() } @@ -377,13 +358,6 @@ private module Cached { result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() } - cached - int getInstructionResultSize(Instruction instruction) { - // Only return a result for instructions that needed an explicit result size. - instruction.getResultType() instanceof Language::UnknownType and - result = getOldInstruction(instruction).getResultSize() - } - cached predicate getInstructionInheritance( Instruction instruction, Language::Class baseClass, Language::Class derivedClass @@ -839,7 +813,7 @@ module DefUse { } /** - * Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the + * Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the * `DebugSSA` module, which is then imported by PrintSSA. */ module DebugSSA { @@ -884,3 +858,4 @@ private module CachedForDebugging { result.getTag() = var.getTag() } } + diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll new file mode 100644 index 00000000000..6ee403226bc --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -0,0 +1,3 @@ +import semmle.code.csharp.ir.implementation.Opcode +import semmle.code.csharp.ir.implementation.internal.OperandTag +import semmle.code.csharp.ir.internal.Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index a4ced8d6d7c..44ff1f110c1 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -2,4 +2,5 @@ import semmle.code.csharp.ir.implementation.raw.IR as OldIR import semmle.code.csharp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability import semmle.code.csharp.ir.implementation.raw.internal.reachability.Dominance as Dominance import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as NewIR +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language import SimpleSSA as Alias diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index 42f582f7df2..e23f67b2d96 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -1,24 +1,20 @@ import AliasAnalysis -private import csharp -private import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.internal.IntegerConstant as Ints -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.Overlap +private import SimpleSSAImports private class IntValue = Ints::IntValue; private predicate hasResultMemoryAccess( - Instruction instr, IRVariable var, Type type, IntValue bitOffset + Instruction instr, IRVariable var, Language::LanguageType type, IntValue bitOffset ) { resultPointsTo(instr.getResultAddressOperand().getAnyDef(), var, bitOffset) and - type = instr.getResultType() + type = instr.getResultLanguageType() } private predicate hasOperandMemoryAccess( - MemoryOperand operand, IRVariable var, Type type, IntValue bitOffset + MemoryOperand operand, IRVariable var, Language::LanguageType type, IntValue bitOffset ) { resultPointsTo(operand.getAddressOperand().getAnyDef(), var, bitOffset) and - type = operand.getType() + type = operand.getLanguageType() } /** @@ -30,17 +26,17 @@ private predicate isVariableModeled(IRVariable var) { not variableAddressEscapes(var) and // There's no need to check for the right size. An `IRVariable` never has an `UnknownType`, so the test for // `type = var.getType()` is sufficient. - forall(Instruction instr, Type type, IntValue bitOffset | + forall(Instruction instr, Language::LanguageType type, IntValue bitOffset | hasResultMemoryAccess(instr, var, type, bitOffset) | bitOffset = 0 and - type = var.getType() + type.getIRType() = var.getIRType() ) and - forall(MemoryOperand operand, Type type, IntValue bitOffset | + forall(MemoryOperand operand, Language::LanguageType type, IntValue bitOffset | hasOperandMemoryAccess(operand, var, type, bitOffset) | bitOffset = 0 and - type = var.getType() + type.getIRType() = var.getIRType() ) } @@ -59,7 +55,7 @@ class MemoryLocation extends TMemoryLocation { final VirtualVariable getVirtualVariable() { result = this } - final Type getType() { result = var.getType() } + final Language::LanguageType getType() { result = var.getLanguageType() } final string getUniqueId() { result = var.getUniqueId() } } @@ -85,3 +81,4 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { result = getMemoryLocation(var) ) } + diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll new file mode 100644 index 00000000000..b6f92fda444 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll @@ -0,0 +1,5 @@ +import semmle.code.csharp.ir.implementation.raw.IR +import semmle.code.csharp.ir.internal.IntegerConstant as Ints +import semmle.code.csharp.ir.implementation.internal.OperandTag +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import semmle.code.csharp.ir.internal.Overlap diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected index ae680785ce6..28d42be0d96 100644 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -13,3 +13,5 @@ containsLoopOfForwardEdges lostReachability backEdgeCountMismatch useNotDominatedByDefinition +missingCanonicalLanguageType +multipleCanonicalLanguageTypes From c1e5db0b9641d7b984d6c12b9b1c8951dec89cd6 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 27 Sep 2019 17:54:18 -0700 Subject: [PATCH 0290/1227] C++ More PR feedback --- .../interfaces/FunctionInputsAndOutputs.qll | 89 ++++++++++--------- 1 file changed, 49 insertions(+), 40 deletions(-) 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 cf934d0811c..f9b88f7a6bf 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll @@ -31,16 +31,18 @@ class FunctionInput extends TFunctionInput { /** * Holds if this is the input value of the parameter with index `index`. + * * Example: * ``` * void func(int n, char* p, float& r); * ``` - * `isParameter(0)` holds for the `FunctionInput` that represents the value of `n` (with type + * - `isParameter(0)` holds for the `FunctionInput` that represents the value of `n` (with type * `int`) on entry to the function. - * `isParameter(1)` holds for the `FunctionInput` that represents the value of `p` (with type + * - `isParameter(1)` holds for the `FunctionInput` that represents the value of `p` (with type * `char*`) on entry to the function. - * `isParameter(2)` holds for the `FunctionInput` that represents the "value" of the reference `r` - * (with type `float&`) on entry to the function, _not_ the value of the referred-to `float`. + * - `isParameter(2)` holds for the `FunctionInput` that represents the "value" of the reference + * `r` (with type `float&`) on entry to the function, _not_ the value of the referred-to + * `float`. */ predicate isParameter(ParameterIndex index) { none() } @@ -52,60 +54,63 @@ class FunctionInput extends TFunctionInput { /** * Holds if this is the input value pointed to by a pointer parameter to a function, or the input - * value referred to by a reference parameter to a function, where the parameter has index - * `index`. + * value referred to by a reference parameter to a function, where the parameter has index + * `index`. + * * Example: * ``` * void func(int n, char* p, float& r); * ``` - * `isParameterDeref(1)` holds for the `FunctionInput` that represents the value of `*p` (with + * - `isParameterDeref(1)` holds for the `FunctionInput` that represents the value of `*p` (with * type `char`) on entry to the function. - * `isParameterDeref(2)` holds for the `FunctionInput` that represents the value of `r` (with type + * - `isParameterDeref(2)` holds for the `FunctionInput` that represents the value of `r` (with type * `float`) on entry to the function. - * There is no `FunctionInput` for which `isParameterDeref(0)` holds, because `n` is neither a + * - There is no `FunctionInput` for which `isParameterDeref(0)` holds, because `n` is neither a * pointer nor a reference. */ predicate isParameterDeref(ParameterIndex index) { none() } /** * Holds if this is the input value pointed to by a pointer parameter to a function, or the input - * value referred to by a reference parameter to a function, where the parameter has index - * `index`. + * value referred to by a reference parameter to a function, where the parameter has index + * `index`. * DEPRECATED: Use `isParameterDeref(index)` instead. */ deprecated final predicate isInParameterPointer(ParameterIndex index) { isParameterDeref(index) } /** * Holds if this is the input value pointed to by the `this` pointer of an instance member - * function. + * function. + * * Example: * ``` * struct C { * void mfunc(int n, char* p, float& r) const; * }; * ``` - * `isQualifierObject()` holds for the `FunctionInput` that represents the value of `*this` (with - * type `C const`) on entry to the function. + * - `isQualifierObject()` holds for the `FunctionInput` that represents the value of `*this` + * (with type `C const`) on entry to the function. */ predicate isQualifierObject() { none() } /** * Holds if this is the input value pointed to by the `this` pointer of an instance member - * function. + * function. * DEPRECATED: Use `isQualifierObject()` instead. */ deprecated final predicate isInQualifier() { isQualifierObject() } /** * Holds if this is the input value of the `this` pointer of an instance member function. + * * Example: * ``` * struct C { * void mfunc(int n, char* p, float& r) const; * }; * ``` - * `isQualifierAddress()` holds for the `FunctionInput` that represents the value of `this` (with - * type `C const *`) on entry to the function. + * - `isQualifierAddress()` holds for the `FunctionInput` that represents the value of `this` + * (with type `C const *`) on entry to the function. */ predicate isQualifierAddress() { none() } } @@ -167,25 +172,26 @@ class FunctionOutput extends TFunctionOutput { /** * Holds if this is the output value pointed to by a pointer parameter to a function, or the - * output value referred to by a reference parameter to a function, where the parameter has - * index `index`. + * output value referred to by a reference parameter to a function, where the parameter has + * index `index`. + * * Example: * ``` * void func(int n, char* p, float& r); * ``` - * `isParameterDeref(1)` holds for the `FunctionOutput` that represents the value of `*p` (with + * - `isParameterDeref(1)` holds for the `FunctionOutput` that represents the value of `*p` (with * type `char`) on return from the function. - * `isParameterDeref(2)` holds for the `FunctionOutput` that represents the value of `r` (with + * - `isParameterDeref(2)` holds for the `FunctionOutput` that represents the value of `r` (with * type `float`) on return from the function. - * There is no `FunctionOutput` for which `isParameterDeref(0)` holds, because `n` is neither a + * - There is no `FunctionOutput` for which `isParameterDeref(0)` holds, because `n` is neither a * pointer nor a reference. */ predicate isParameterDeref(ParameterIndex i) { none() } /** * Holds if this is the output value pointed to by a pointer parameter to a function, or the - * output value referred to by a reference parameter to a function, where the parameter has - * index `index`. + * output value referred to by a reference parameter to a function, where the parameter has + * index `index`. * DEPRECATED: Use `isParameterDeref(index)` instead. */ deprecated final predicate isOutParameterPointer(ParameterIndex index) { isParameterDeref(index) } @@ -193,36 +199,39 @@ class FunctionOutput extends TFunctionOutput { /** * Holds if this is the output value pointed to by the `this` pointer of an instance member * function. + * + * Example: * ``` * struct C { * void mfunc(int n, char* p, float& r); * }; * ``` - * `isQualifierObject()` holds for the `FunctionOutput` that represents the value of `*this` (with - * type `C`) on return from the function. + * - `isQualifierObject()` holds for the `FunctionOutput` that represents the value of `*this` + * (with type `C`) on return from the function. */ predicate isQualifierObject() { none() } /** * Holds if this is the output value pointed to by the `this` pointer of an instance member - * function. + * function. * DEPRECATED: Use `isQualifierObject()` instead. */ deprecated final predicate isOutQualifier() { isQualifierObject() } /** * Holds if this is the value returned by a function. + * * Example: * ``` * int getInt(); * char* getPointer(); * float& getReference(); * ``` - * `isReturnValue()` holds for the `FunctionOutput` that represents the value returned by + * - `isReturnValue()` holds for the `FunctionOutput` that represents the value returned by * `getInt()` (with type `int`). - * `isReturnValue()` holds for the `FunctionOutput` that represents the value returned by + * - `isReturnValue()` holds for the `FunctionOutput` that represents the value returned by * `getPointer()` (with type `char*`). - * `isReturnValue()` holds for the `FunctionOutput` that represents the "value" of the reference + * - `isReturnValue()` holds for the `FunctionOutput` that represents the "value" of the reference * returned by `getReference()` (with type `float&`), _not_ the value of the referred-to * `float`. */ @@ -236,30 +245,30 @@ class FunctionOutput extends TFunctionOutput { /** * Holds if this is the output value pointed to by the return value of a function, if the function - * returns a pointer, or the output value referred to by the return value of a function, if the - * function returns a reference. + * returns a pointer, or the output value referred to by the return value of a function, if the + * function returns a reference. + * * Example: * ``` * char* getPointer(); * float& getReference(); * int getInt(); * ``` - * `isReturnValueDeref()` holds for the `FunctionOutput` that represents the value of + * - `isReturnValueDeref()` holds for the `FunctionOutput` that represents the value of * `*getPointer()` (with type `char`). - * `isReturnValueDeref()` holds for the `FunctionOutput` that represents the value of + * - `isReturnValueDeref()` holds for the `FunctionOutput` that represents the value of * `getReference()` (with type `float`). - * There is no `FunctionOutput` of `getInt()` for which `isReturnValueDeref()` holds because the + * - There is no `FunctionOutput` of `getInt()` for which `isReturnValueDeref()` holds because the * return type of `getInt()` is neither a pointer nor a reference. */ predicate isReturnValueDeref() { none() } - /* + /** * Holds if this is the output value pointed to by the return value of a function, if the function - * returns a pointer, or the output value referred to by the return value of a function, if the - * function returns a reference. + * returns a pointer, or the output value referred to by the return value of a function, if the + * function returns a reference. * DEPRECATED: Use `isReturnValueDeref()` instead. */ - deprecated final predicate isOutReturnPointer() { isReturnValueDeref() } } @@ -276,7 +285,7 @@ class OutParameterDeref extends FunctionOutput, TOutParameterDeref { } class OutQualifierObject extends FunctionOutput, TOutQualifierObject { - override string toString() { result = "OutQualifier" } + override string toString() { result = "OutQualifierObject" } override predicate isQualifierObject() { any() } } From 043e5f716b074bacce04461e821e291c5b2b6b75 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Sun, 29 Sep 2019 22:39:09 -0700 Subject: [PATCH 0291/1227] C++, C#: Autoformat --- .../ir/implementation/aliased_ssa/IRSanity.qll | 2 +- .../ir/implementation/aliased_ssa/IRVariable.qll | 8 ++------ .../implementation/aliased_ssa/Instruction.qll | 16 ++++++---------- .../aliased_ssa/gvn/ValueNumbering.qll | 15 +++++++++------ .../aliased_ssa/internal/PrintSSA.qll | 1 - .../aliased_ssa/internal/SSAConstruction.qll | 1 - .../code/cpp/ir/implementation/raw/IRSanity.qll | 2 +- .../cpp/ir/implementation/raw/IRVariable.qll | 8 ++------ .../cpp/ir/implementation/raw/Instruction.qll | 16 ++++++---------- .../ir/implementation/raw/gvn/ValueNumbering.qll | 15 +++++++++------ .../ir/implementation/unaliased_ssa/IRSanity.qll | 2 +- .../implementation/unaliased_ssa/IRVariable.qll | 8 ++------ .../implementation/unaliased_ssa/Instruction.qll | 16 ++++++---------- .../unaliased_ssa/gvn/ValueNumbering.qll | 15 +++++++++------ .../unaliased_ssa/internal/PrintSSA.qll | 1 - .../unaliased_ssa/internal/SSAConstruction.qll | 1 - .../unaliased_ssa/internal/SimpleSSA.qll | 1 - cpp/ql/test/library-tests/ir/ir/foo.ql | 4 ++++ .../csharp/ir/implementation/raw/IRSanity.qll | 2 +- .../csharp/ir/implementation/raw/IRVariable.qll | 8 ++------ .../csharp/ir/implementation/raw/Instruction.qll | 16 ++++++---------- .../ir/implementation/raw/gvn/ValueNumbering.qll | 15 +++++++++------ .../ir/implementation/unaliased_ssa/IRSanity.qll | 2 +- .../implementation/unaliased_ssa/IRVariable.qll | 8 ++------ .../implementation/unaliased_ssa/Instruction.qll | 16 ++++++---------- .../unaliased_ssa/gvn/ValueNumbering.qll | 15 +++++++++------ .../unaliased_ssa/internal/PrintSSA.qll | 1 - .../unaliased_ssa/internal/SSAConstruction.qll | 1 - .../unaliased_ssa/internal/SimpleSSA.qll | 1 - 29 files changed, 94 insertions(+), 123 deletions(-) create mode 100644 cpp/ql/test/library-tests/ir/ir/foo.ql diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll index 6ee2e687015..de66a3c99dc 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll @@ -1,3 +1,3 @@ private import IR import InstructionSanity -import IRTypeSanity \ No newline at end of file +import IRTypeSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index d17b810785e..1a607f82c29 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -25,16 +25,12 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - final Language::Type getType() { - getLanguageType().hasType(result, false) - } + final Language::Type getType() { getLanguageType().hasType(result, false) } /** * Gets the language-neutral type of the variable. */ - final IRType getIRType() { - result = getLanguageType().getIRType() - } + final IRType getIRType() { result = getLanguageType().getIRType() } /** * Gets the type of the variable. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 01e2d219652..841497e98a2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -118,9 +118,8 @@ module InstructionSanity { not exists(operand.getType()) and use = operand.getUse() and func = use.getEnclosingFunction() and - message = "Operand '" + operand.toString() + "' of instruction '" + - use.getOpcode().toString() + "' missing type in function '" + - Language::getIdentityString(func) + "'." + message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' missing type in function '" + Language::getIdentityString(func) + "'." ) } @@ -458,7 +457,8 @@ class Instruction extends Construction::TInstruction { exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasUnspecifiedType(result, _) or + resultType.hasUnspecifiedType(result, _) + or not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType ) ) @@ -482,9 +482,7 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { - Construction::getInstructionResultType(this).hasType(_, true) - } + final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -493,9 +491,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { - result = Construction::getInstructionResultType(this).getByteSize() - } + final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll index 63500993a50..9521dda18a9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll @@ -47,7 +47,8 @@ newtype TValueNumber = unaryValueNumber(_, irFunc, opcode, type, operand) } or TInheritanceConversionValueNumber( - IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand + IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, + ValueNumber operand ) { inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) } or @@ -186,8 +187,8 @@ private predicate binaryValueNumber( } private predicate pointerArithmeticValueNumber( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, int elementSize, - ValueNumber leftOperand, ValueNumber rightOperand + PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, + int elementSize, ValueNumber leftOperand, ValueNumber rightOperand ) { instr.getEnclosingIRFunction() = irFunc and instr.getOpcode() = opcode and @@ -294,14 +295,16 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) { result = TUnaryValueNumber(irFunc, opcode, type, operand) ) or - exists(Opcode opcode, Language::Class baseClass, Language::Class derivedClass, - ValueNumber operand | + exists( + Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand + | inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) ) or exists( - Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand + Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand, + ValueNumber rightOperand | pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, rightOperand) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll index c73826bd4c8..23121523a6b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll @@ -143,4 +143,3 @@ class PropertyProvider extends IRPropertyProvider { ) } } - diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 148fd65d264..29e456f9fe3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -858,4 +858,3 @@ private module CachedForDebugging { result.getTag() = var.getTag() } } - diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll index 6ee2e687015..de66a3c99dc 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll @@ -1,3 +1,3 @@ private import IR import InstructionSanity -import IRTypeSanity \ No newline at end of file +import IRTypeSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index d17b810785e..1a607f82c29 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -25,16 +25,12 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - final Language::Type getType() { - getLanguageType().hasType(result, false) - } + final Language::Type getType() { getLanguageType().hasType(result, false) } /** * Gets the language-neutral type of the variable. */ - final IRType getIRType() { - result = getLanguageType().getIRType() - } + final IRType getIRType() { result = getLanguageType().getIRType() } /** * Gets the type of the variable. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 01e2d219652..841497e98a2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -118,9 +118,8 @@ module InstructionSanity { not exists(operand.getType()) and use = operand.getUse() and func = use.getEnclosingFunction() and - message = "Operand '" + operand.toString() + "' of instruction '" + - use.getOpcode().toString() + "' missing type in function '" + - Language::getIdentityString(func) + "'." + message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' missing type in function '" + Language::getIdentityString(func) + "'." ) } @@ -458,7 +457,8 @@ class Instruction extends Construction::TInstruction { exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasUnspecifiedType(result, _) or + resultType.hasUnspecifiedType(result, _) + or not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType ) ) @@ -482,9 +482,7 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { - Construction::getInstructionResultType(this).hasType(_, true) - } + final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -493,9 +491,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { - result = Construction::getInstructionResultType(this).getByteSize() - } + final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll index 63500993a50..9521dda18a9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -47,7 +47,8 @@ newtype TValueNumber = unaryValueNumber(_, irFunc, opcode, type, operand) } or TInheritanceConversionValueNumber( - IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand + IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, + ValueNumber operand ) { inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) } or @@ -186,8 +187,8 @@ private predicate binaryValueNumber( } private predicate pointerArithmeticValueNumber( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, int elementSize, - ValueNumber leftOperand, ValueNumber rightOperand + PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, + int elementSize, ValueNumber leftOperand, ValueNumber rightOperand ) { instr.getEnclosingIRFunction() = irFunc and instr.getOpcode() = opcode and @@ -294,14 +295,16 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) { result = TUnaryValueNumber(irFunc, opcode, type, operand) ) or - exists(Opcode opcode, Language::Class baseClass, Language::Class derivedClass, - ValueNumber operand | + exists( + Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand + | inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) ) or exists( - Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand + Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand, + ValueNumber rightOperand | pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, rightOperand) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll index 6ee2e687015..de66a3c99dc 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll @@ -1,3 +1,3 @@ private import IR import InstructionSanity -import IRTypeSanity \ No newline at end of file +import IRTypeSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index d17b810785e..1a607f82c29 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -25,16 +25,12 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - final Language::Type getType() { - getLanguageType().hasType(result, false) - } + final Language::Type getType() { getLanguageType().hasType(result, false) } /** * Gets the language-neutral type of the variable. */ - final IRType getIRType() { - result = getLanguageType().getIRType() - } + final IRType getIRType() { result = getLanguageType().getIRType() } /** * Gets the type of the variable. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 01e2d219652..841497e98a2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -118,9 +118,8 @@ module InstructionSanity { not exists(operand.getType()) and use = operand.getUse() and func = use.getEnclosingFunction() and - message = "Operand '" + operand.toString() + "' of instruction '" + - use.getOpcode().toString() + "' missing type in function '" + - Language::getIdentityString(func) + "'." + message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' missing type in function '" + Language::getIdentityString(func) + "'." ) } @@ -458,7 +457,8 @@ class Instruction extends Construction::TInstruction { exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasUnspecifiedType(result, _) or + resultType.hasUnspecifiedType(result, _) + or not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType ) ) @@ -482,9 +482,7 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { - Construction::getInstructionResultType(this).hasType(_, true) - } + final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -493,9 +491,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { - result = Construction::getInstructionResultType(this).getByteSize() - } + final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 63500993a50..9521dda18a9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -47,7 +47,8 @@ newtype TValueNumber = unaryValueNumber(_, irFunc, opcode, type, operand) } or TInheritanceConversionValueNumber( - IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand + IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, + ValueNumber operand ) { inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) } or @@ -186,8 +187,8 @@ private predicate binaryValueNumber( } private predicate pointerArithmeticValueNumber( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, int elementSize, - ValueNumber leftOperand, ValueNumber rightOperand + PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, + int elementSize, ValueNumber leftOperand, ValueNumber rightOperand ) { instr.getEnclosingIRFunction() = irFunc and instr.getOpcode() = opcode and @@ -294,14 +295,16 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) { result = TUnaryValueNumber(irFunc, opcode, type, operand) ) or - exists(Opcode opcode, Language::Class baseClass, Language::Class derivedClass, - ValueNumber operand | + exists( + Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand + | inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) ) or exists( - Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand + Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand, + ValueNumber rightOperand | pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, rightOperand) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll index c73826bd4c8..23121523a6b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll @@ -143,4 +143,3 @@ class PropertyProvider extends IRPropertyProvider { ) } } - diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 148fd65d264..29e456f9fe3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -858,4 +858,3 @@ private module CachedForDebugging { result.getTag() = var.getTag() } } - diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index e23f67b2d96..5925631b67c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -81,4 +81,3 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { result = getMemoryLocation(var) ) } - diff --git a/cpp/ql/test/library-tests/ir/ir/foo.ql b/cpp/ql/test/library-tests/ir/ir/foo.ql new file mode 100644 index 00000000000..9a50d6a1a2a --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/foo.ql @@ -0,0 +1,4 @@ +import cpp + +from Function f +select f, "Message: $@ -- $@ + $@", f.getADeclaration(), "decl", f, "def" diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll index 6ee2e687015..de66a3c99dc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll @@ -1,3 +1,3 @@ private import IR import InstructionSanity -import IRTypeSanity \ No newline at end of file +import IRTypeSanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll index d17b810785e..1a607f82c29 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll @@ -25,16 +25,12 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - final Language::Type getType() { - getLanguageType().hasType(result, false) - } + final Language::Type getType() { getLanguageType().hasType(result, false) } /** * Gets the language-neutral type of the variable. */ - final IRType getIRType() { - result = getLanguageType().getIRType() - } + final IRType getIRType() { result = getLanguageType().getIRType() } /** * Gets the type of the variable. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 01e2d219652..841497e98a2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -118,9 +118,8 @@ module InstructionSanity { not exists(operand.getType()) and use = operand.getUse() and func = use.getEnclosingFunction() and - message = "Operand '" + operand.toString() + "' of instruction '" + - use.getOpcode().toString() + "' missing type in function '" + - Language::getIdentityString(func) + "'." + message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' missing type in function '" + Language::getIdentityString(func) + "'." ) } @@ -458,7 +457,8 @@ class Instruction extends Construction::TInstruction { exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasUnspecifiedType(result, _) or + resultType.hasUnspecifiedType(result, _) + or not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType ) ) @@ -482,9 +482,7 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { - Construction::getInstructionResultType(this).hasType(_, true) - } + final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -493,9 +491,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { - result = Construction::getInstructionResultType(this).getByteSize() - } + final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll index 63500993a50..9521dda18a9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -47,7 +47,8 @@ newtype TValueNumber = unaryValueNumber(_, irFunc, opcode, type, operand) } or TInheritanceConversionValueNumber( - IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand + IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, + ValueNumber operand ) { inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) } or @@ -186,8 +187,8 @@ private predicate binaryValueNumber( } private predicate pointerArithmeticValueNumber( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, int elementSize, - ValueNumber leftOperand, ValueNumber rightOperand + PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, + int elementSize, ValueNumber leftOperand, ValueNumber rightOperand ) { instr.getEnclosingIRFunction() = irFunc and instr.getOpcode() = opcode and @@ -294,14 +295,16 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) { result = TUnaryValueNumber(irFunc, opcode, type, operand) ) or - exists(Opcode opcode, Language::Class baseClass, Language::Class derivedClass, - ValueNumber operand | + exists( + Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand + | inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) ) or exists( - Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand + Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand, + ValueNumber rightOperand | pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, rightOperand) and diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll index 6ee2e687015..de66a3c99dc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll @@ -1,3 +1,3 @@ private import IR import InstructionSanity -import IRTypeSanity \ No newline at end of file +import IRTypeSanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll index d17b810785e..1a607f82c29 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -25,16 +25,12 @@ abstract class IRVariable extends TIRVariable { /** * Gets the type of the variable. */ - final Language::Type getType() { - getLanguageType().hasType(result, false) - } + final Language::Type getType() { getLanguageType().hasType(result, false) } /** * Gets the language-neutral type of the variable. */ - final IRType getIRType() { - result = getLanguageType().getIRType() - } + final IRType getIRType() { result = getLanguageType().getIRType() } /** * Gets the type of the variable. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 01e2d219652..841497e98a2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -118,9 +118,8 @@ module InstructionSanity { not exists(operand.getType()) and use = operand.getUse() and func = use.getEnclosingFunction() and - message = "Operand '" + operand.toString() + "' of instruction '" + - use.getOpcode().toString() + "' missing type in function '" + - Language::getIdentityString(func) + "'." + message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' missing type in function '" + Language::getIdentityString(func) + "'." ) } @@ -458,7 +457,8 @@ class Instruction extends Construction::TInstruction { exists(Language::LanguageType resultType | resultType = getResultLanguageType() and ( - resultType.hasUnspecifiedType(result, _) or + resultType.hasUnspecifiedType(result, _) + or not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType ) ) @@ -482,9 +482,7 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { - Construction::getInstructionResultType(this).hasType(_, true) - } + final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -493,9 +491,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { - result = Construction::getInstructionResultType(this).getByteSize() - } + final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 63500993a50..9521dda18a9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -47,7 +47,8 @@ newtype TValueNumber = unaryValueNumber(_, irFunc, opcode, type, operand) } or TInheritanceConversionValueNumber( - IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand + IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass, + ValueNumber operand ) { inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) } or @@ -186,8 +187,8 @@ private predicate binaryValueNumber( } private predicate pointerArithmeticValueNumber( - PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, int elementSize, - ValueNumber leftOperand, ValueNumber rightOperand + PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, + int elementSize, ValueNumber leftOperand, ValueNumber rightOperand ) { instr.getEnclosingIRFunction() = irFunc and instr.getOpcode() = opcode and @@ -294,14 +295,16 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) { result = TUnaryValueNumber(irFunc, opcode, type, operand) ) or - exists(Opcode opcode, Language::Class baseClass, Language::Class derivedClass, - ValueNumber operand | + exists( + Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand + | inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) ) or exists( - Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand + Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand, + ValueNumber rightOperand | pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, rightOperand) and diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll index c73826bd4c8..23121523a6b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll @@ -143,4 +143,3 @@ class PropertyProvider extends IRPropertyProvider { ) } } - diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 148fd65d264..29e456f9fe3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -858,4 +858,3 @@ private module CachedForDebugging { result.getTag() = var.getTag() } } - diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index e23f67b2d96..5925631b67c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -81,4 +81,3 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) { result = getMemoryLocation(var) ) } - From 420713204ae5b1111e791cdd360383bf0ec7efdf Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Sun, 29 Sep 2019 22:44:17 -0700 Subject: [PATCH 0292/1227] C++, C#: Fix typo --- .../semmle/code/cpp/ir/implementation/IRType.qll | 14 +++----------- .../code/csharp/ir/implementation/IRType.qll | 14 +++----------- 2 files changed, 6 insertions(+), 22 deletions(-) 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 163d384c759..a1c8a2ca9c9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -43,7 +43,7 @@ private newtype TIRType = * all pointer types map to the same instance of `IRAddressType`. */ class IRType extends TIRType { - abstract string toString(); + string toString() { none() } /** * Gets a string that uniquely identifies this `IRType`. This string is often the same as the @@ -58,12 +58,12 @@ class IRType extends TIRType { * * This will hold for all `IRType` objects except `IRUnknownType`. */ - abstract int getByteSize(); + int getByteSize() { none() } /** * Gets a single instance of `LanguageType` that maps to this `IRType`. */ - abstract Language::LanguageType getCanonicalLanguageType(); + Language::LanguageType getCanonicalLanguageType() { none() } } /** @@ -121,11 +121,7 @@ private class IRSizedType extends IRType { this = TIRBlobType(_, byteSize) } - abstract override string toString(); - final override int getByteSize() { result = byteSize } - - abstract override Language::LanguageType getCanonicalLanguageType(); } /** @@ -149,10 +145,6 @@ class IRNumericType extends IRSizedType { this = TIRUnsignedIntegerType(byteSize) or this = TIRFloatingPointType(byteSize) } - - abstract override string toString(); - - abstract override Language::LanguageType getCanonicalLanguageType(); } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll index 163d384c759..a1c8a2ca9c9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll @@ -43,7 +43,7 @@ private newtype TIRType = * all pointer types map to the same instance of `IRAddressType`. */ class IRType extends TIRType { - abstract string toString(); + string toString() { none() } /** * Gets a string that uniquely identifies this `IRType`. This string is often the same as the @@ -58,12 +58,12 @@ class IRType extends TIRType { * * This will hold for all `IRType` objects except `IRUnknownType`. */ - abstract int getByteSize(); + int getByteSize() { none() } /** * Gets a single instance of `LanguageType` that maps to this `IRType`. */ - abstract Language::LanguageType getCanonicalLanguageType(); + Language::LanguageType getCanonicalLanguageType() { none() } } /** @@ -121,11 +121,7 @@ private class IRSizedType extends IRType { this = TIRBlobType(_, byteSize) } - abstract override string toString(); - final override int getByteSize() { result = byteSize } - - abstract override Language::LanguageType getCanonicalLanguageType(); } /** @@ -149,10 +145,6 @@ class IRNumericType extends IRSizedType { this = TIRUnsignedIntegerType(byteSize) or this = TIRFloatingPointType(byteSize) } - - abstract override string toString(); - - abstract override Language::LanguageType getCanonicalLanguageType(); } /** From b7595ed60ea107708c66806ec2008f49137aeac8 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 30 Sep 2019 09:11:47 +0200 Subject: [PATCH 0293/1227] C#: Remove duplicated class --- .../csharp/dataflow/internal/DataFlowDispatch.qll | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index 77dfc82a3a6..1e1353279a1 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -172,21 +172,6 @@ private module Cached { result = viableImplInCallContext(call, ctx) and reducedViableImplInReturn(result, call) } - - /** A valid return type for a method that uses `yield return`. */ - private class YieldReturnType extends Type { - YieldReturnType() { - exists(Type t | t = this.getSourceDeclaration() | - t instanceof SystemCollectionsIEnumerableInterface - or - t instanceof SystemCollectionsIEnumeratorInterface - or - t instanceof SystemCollectionsGenericIEnumerableTInterface - or - t instanceof SystemCollectionsGenericIEnumeratorInterface - ) - } - } } import Cached From c18d0430def2924703023ebcb80cc84d67480e09 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 26 Sep 2019 14:11:31 +0200 Subject: [PATCH 0294/1227] C#: Cleanup more files after failed autobuilder attempt --- .../autobuilder/Semmle.Autobuild/Autobuilder.cs | 17 ++++++++++++++--- .../Semmle.Extraction.CSharp/Analyser.cs | 5 ++--- .../Semmle.Extraction.CSharp/Extractor.cs | 14 +++++++++++++- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs index 59e69d5301e..a5a463d01a3 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs @@ -262,12 +262,23 @@ namespace Semmle.Autobuild BuildScript.DeleteDirectory(Actions.GetEnvironmentVariable("TRAP_FOLDER")); var cleanSourceArchive = BuildScript.DeleteDirectory(Actions.GetEnvironmentVariable("SOURCE_ARCHIVE")); - var cleanExtractorLog = - BuildScript.DeleteFile(Extractor.GetCSharpLogPath()); + var tryCleanExtractorArgsLogs = + BuildScript.Create(actions => + { + foreach (var file in Extractor.GetCSharpArgsLogs()) + try + { + actions.FileDelete(file); + } + catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block] + { } + return 0; + }); var attemptExtractorCleanup = BuildScript.Try(cleanTrapFolder) & BuildScript.Try(cleanSourceArchive) & - BuildScript.Try(cleanExtractorLog); + tryCleanExtractorArgsLogs & + BuildScript.DeleteFile(Extractor.GetCSharpLogPath()); /// /// Execute script `s` and check that the C# extractor has been executed. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index 58a9beebb68..544a1819117 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -450,8 +450,7 @@ namespace Semmle.Extraction.CSharp LogExtractorInfo(extractorVersion); Logger.Log(Severity.Info, $" Arguments to Roslyn: {string.Join(' ', roslynArgs)}"); - var csharpLogDir = Extractor.GetCSharpLogDirectory(); - var tempFile = Path.Combine(csharpLogDir, $"csharp.{Path.GetRandomFileName()}.txt"); + var tempFile = Extractor.GetCSharpArgsLogPath(Path.GetRandomFileName()); bool argsWritten; using (var streamWriter = new StreamWriter(new FileStream(tempFile, FileMode.Append, FileAccess.Write))) @@ -461,7 +460,7 @@ namespace Semmle.Extraction.CSharp } var hash = FileUtils.ComputeFileHash(tempFile); - var argsFile = Path.Combine(csharpLogDir, $"csharp.{hash}.txt"); + var argsFile = Extractor.GetCSharpArgsLogPath(hash); if (argsWritten) Logger.Log(Severity.Info, $" Arguments have been written to {argsFile}"); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs index 3e9a841fb62..acabad9e349 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs @@ -391,7 +391,19 @@ namespace Semmle.Extraction.CSharp public static string GetCSharpLogPath() => Path.Combine(GetCSharpLogDirectory(), "csharp.log"); - public static string GetCSharpLogDirectory() + /// + /// Gets the path to a `csharp.{hash}.txt` file written to by the C# extractor. + /// + public static string GetCSharpArgsLogPath(string hash) => + Path.Combine(GetCSharpLogDirectory(), $"csharp.{hash}.txt"); + + /// + /// Gets a list of all `csharp.{hash}.txt` files currently written to the log directory. + /// + public static IEnumerable GetCSharpArgsLogs() => + Directory.EnumerateFiles(GetCSharpLogDirectory(), "csharp.*.txt"); + + static string GetCSharpLogDirectory() { string snapshot = Environment.GetEnvironmentVariable("ODASA_SNAPSHOT"); string buildErrorDir = Environment.GetEnvironmentVariable("ODASA_BUILD_ERROR_DIR"); From 0320f0f26b244cf1dccb9d7c60609e3370226e88 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 12 Sep 2019 15:13:56 +0100 Subject: [PATCH 0295/1227] add query for detecting suspisous method names in TypeScript --- change-notes/1.23/analysis-javascript.md | 1 + .../Declarations/SuspiciousMethodName.qhelp | 50 ++++++++++++ .../src/Declarations/SuspiciousMethodName.ql | 80 +++++++++++++++++++ .../examples/SuspiciousMethodName.ts | 6 ++ .../examples/SuspiciousMethodNameFixed.ts | 4 + .../SuspiciousMethodName.expected | 4 + .../SuspiciousMethodName.qlref | 1 + .../Declarations/SuspiciousMethodName/tst.js | 19 +++++ .../Declarations/SuspiciousMethodName/tst.ts | 52 ++++++++++++ 9 files changed, 217 insertions(+) create mode 100644 javascript/ql/src/Declarations/SuspiciousMethodName.qhelp create mode 100644 javascript/ql/src/Declarations/SuspiciousMethodName.ql create mode 100644 javascript/ql/src/Declarations/examples/SuspiciousMethodName.ts create mode 100644 javascript/ql/src/Declarations/examples/SuspiciousMethodNameFixed.ts create mode 100644 javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.expected create mode 100644 javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.qlref create mode 100644 javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.js create mode 100644 javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.ts diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md index 7ba8b0e7543..e26862392f4 100644 --- a/change-notes/1.23/analysis-javascript.md +++ b/change-notes/1.23/analysis-javascript.md @@ -16,6 +16,7 @@ |---------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Unused index variable (`js/unused-index-variable`) | correctness | Highlights loops that iterate over an array, but do not use the index variable to access array elements, indicating a possible typo or logic error. Results are shown on LGTM by default. | | Loop bound injection (`js/loop-bound-injection`) | security, external/cwe/cwe-834 | Highlights loops where a user-controlled object with an arbitrary .length value can trick the server to loop indefinitely. Results are not shown on LGTM by default. | +| Suspicious method name (`js/suspicious-method-name`) | correctness, typescript, methods | Highlights suspiciously named methods where the developer likely meant to write a constructor or function. Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/javascript/ql/src/Declarations/SuspiciousMethodName.qhelp b/javascript/ql/src/Declarations/SuspiciousMethodName.qhelp new file mode 100644 index 00000000000..6a2a46913d6 --- /dev/null +++ b/javascript/ql/src/Declarations/SuspiciousMethodName.qhelp @@ -0,0 +1,50 @@ + + + +

    +In TypeScript the keywords constructor and new are +used to declare constructors in classes and interfaces respectively. +However, by using the wrong keyword a programmer can accidentally declare e.g. +a method called constructor inside an interface. +Similarly the keyword function is used to declare functions in +some contexts, however, using the keyword function inside a class +or interface results in declaring a method called function. +

    + +
    + + +

    +Declare classes as classes and not as interfaces. +Use the keyword constructor to declare constructors in a class, +use the keyword new to declare constructors inside interfaces, +and don't use function when declaring an interface that is a +function. +

    + +
    + + +

    +The below example declares an interface Point with 2 fields +and a method called constructor. The interface does not declare +a class Point with a constructor, which was likely what the +developer meant to create. +

    + + +

    +The below example is a fixed version of the above, where the interface is +instead declared as a class, thereby describing the type the developer meant +in the first place. +

    + + + +
    + + + +
    diff --git a/javascript/ql/src/Declarations/SuspiciousMethodName.ql b/javascript/ql/src/Declarations/SuspiciousMethodName.ql new file mode 100644 index 00000000000..c65bb1448ac --- /dev/null +++ b/javascript/ql/src/Declarations/SuspiciousMethodName.ql @@ -0,0 +1,80 @@ +/** + * @name Suspicious method name + * @description A method having the name "function", "new", or "constructor" + * is usually caused by a programmer being confused about the TypeScript syntax. + * @kind problem + * @problem.severity warning + * @id js/suspicious-method-name + * @precision high + * @tags correctness + * typescript + * methods + */ + +import javascript + +/** + * Holds if the method name on the given container is likely to be a mistake. + */ +predicate isSuspisousMethodName(string name, ClassOrInterface container) { + name = "function" + or + // "constructor" is only suspicious outside a class. + name = "constructor" and not container instanceof ClassDefinition + or + // "new" is only suspicious inside a class. + name = "new" and container instanceof ClassDefinition +} + +/** + * Holds if the beginning of the location is before the end. + */ +predicate isRealLocation(Location l) { + l.getEndLine() > l.getStartLine() or + (l.getStartLine() = l.getEndLine() and l.getEndColumn() > l.getStartColumn()) +} + +from MethodDeclaration member, ClassOrInterface container, string suffixMsg +where + container.getLocation().getFile().getFileType().isTypeScript() and + container.getAMember() = member and + isSuspisousMethodName(member.getName(), container) and + + // Assume that a "new" method is intentional if the class has an explicit constructor. + not ( + member.getName() = "new" and + container instanceof ClassDefinition and + exists(MemberDeclaration constructor | + container.getAMember() = constructor and + constructor.getName() = "constructor" and + // Test that it is not an implicitly declared constructor. + isRealLocation(constructor.getLocation()) + ) + ) and + + // Explicitly declared static methods are fine. + not ( + container instanceof ClassDefinition and + member.isStatic() + ) and + + // Only looking for declared methods. Methods with a body are OK. + not exists(member.getBody().getBody()) and + + // The developer was not confused about "function" when there are other methods in the interface. + not ( + member.getName() = "function" and + exists(MethodDeclaration other | other = container.getMethod(_) | + other.getName() != "function" and + isRealLocation(other.getLocation()) + ) + ) and + + ( + member.getName() = "constructor" and suffixMsg = "Did you mean to write a class instead of an interface?" + or + member.getName() = "new" and suffixMsg = "Did you mean \"constructor\"?" + or + member.getName() = "function" and suffixMsg = "Did you mean to omit \"function\"?" + ) +select member, "Declares a suspiciously named method \"" + member.getName() + "\". " + suffixMsg diff --git a/javascript/ql/src/Declarations/examples/SuspiciousMethodName.ts b/javascript/ql/src/Declarations/examples/SuspiciousMethodName.ts new file mode 100644 index 00000000000..b7b925aa15a --- /dev/null +++ b/javascript/ql/src/Declarations/examples/SuspiciousMethodName.ts @@ -0,0 +1,6 @@ +declare class Point { + x: number; + y: number; + constructor(x : number, y: number); +} + diff --git a/javascript/ql/src/Declarations/examples/SuspiciousMethodNameFixed.ts b/javascript/ql/src/Declarations/examples/SuspiciousMethodNameFixed.ts new file mode 100644 index 00000000000..850038f4dbf --- /dev/null +++ b/javascript/ql/src/Declarations/examples/SuspiciousMethodNameFixed.ts @@ -0,0 +1,4 @@ +interface Point { + x: number; + y: number; +} diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.expected b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.expected new file mode 100644 index 00000000000..444715e8182 --- /dev/null +++ b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.expected @@ -0,0 +1,4 @@ +| tst.ts:7:3:7:24 | constru ... string; | Declares a suspiciously named method "constructor". Did you mean "new"? | +| tst.ts:16:3:16:21 | function(): number; | Declares a suspiciously named method "function". Did you mean to omit "function"? | +| tst.ts:37:3:37:21 | function(): number; | Declares a suspiciously named method "function". Did you mean to omit "function"? | +| tst.ts:48:3:48:13 | new(): Quz; | Declares a suspiciously named method "new". Did you mean "constructor"? | diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.qlref b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.qlref new file mode 100644 index 00000000000..7db43af7e2f --- /dev/null +++ b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.qlref @@ -0,0 +1 @@ +Declarations/SuspiciousMethodName.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.js b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.js new file mode 100644 index 00000000000..b11deb47fcc --- /dev/null +++ b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.js @@ -0,0 +1,19 @@ + // OK: don't report anything in .js files. +function getStuff(number) { + return { + "new": function() { + + }, + "constructor": 123, + "function": "this is a string!" + } +} + +class Foobar { + new() { + return 123; + } + function() { + return "string"; + } +} diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.ts b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.ts new file mode 100644 index 00000000000..daf9db3192c --- /dev/null +++ b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.ts @@ -0,0 +1,52 @@ +var foo: MyInterface = 123 as any; + +interface MyInterface { + function (): number; // OK. Highly unlikely that it is an accident when there are other named methods in the interface. + (): number; // OK: What was probaly meant above. + new:() => void; // OK! This is a property, not a method, we ignore those. + constructor(): string; // NOT OK! This a called "constructor" + new(): Date; // OK! This a constructor signature. + + myNumber: 123; +} + +var a : MyFunction = null as any; + +interface MyFunction { + function(): number; // NOT OK! +} + + +class Foo { + new(): number { // OK! Highly unlikely that a developer confuses "constructor" and "new" when both are present. + return 123; + } + constructor() { // OK! This is a constructor. + + } + myString = "foobar" + + myMethod(): boolean { + return Math.random() > 0.5; + } +} + +var b : FunctionClass = new FunctionClass(); + +declare class FunctionClass { + function(): number; // NOT OK: +} + +class Baz { + new(): Baz { // OK! When there is a method body I assume the developer knows what they are doing. + return null as any; + } +} + + +declare class Quz { + new(): Quz; // NOT OK! The developer likely meant to write constructor. +} + +var bla = new Foo(); +var blab = new Baz(); \ No newline at end of file From ff78feeeeaec99bdf779242c33e25f57c7bcab29 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 30 Sep 2019 11:51:17 +0100 Subject: [PATCH 0296/1227] docs: version number and small css tweaks --- .../slides-semmle-2/static/theme/css/default.css | 5 +++-- docs/language/ql-training/conf.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/language/ql-training/_static-training/slides-semmle-2/static/theme/css/default.css b/docs/language/ql-training/_static-training/slides-semmle-2/static/theme/css/default.css index 2c05ea5e93b..e3664d42e06 100644 --- a/docs/language/ql-training/_static-training/slides-semmle-2/static/theme/css/default.css +++ b/docs/language/ql-training/_static-training/slides-semmle-2/static/theme/css/default.css @@ -485,6 +485,7 @@ ul { margin-left: 2.2em; margin-bottom: 1em; position: relative; + width: 90%; } /* line 300, ../scss/default.scss */ ul li { @@ -1569,7 +1570,7 @@ p.first.admonition-title { text-align: left; font-size: 0.8em; width: 100%; - overflow: scroll; + overflow: auto; border: 1px solid black; } @@ -1608,7 +1609,7 @@ p.first.admonition-title { display: block; position: fixed; top: 0; - right: -1%; + right: 0; font-size: 1.2em; } diff --git a/docs/language/ql-training/conf.py b/docs/language/ql-training/conf.py index de712cd06a4..8f8a13569b5 100644 --- a/docs/language/ql-training/conf.py +++ b/docs/language/ql-training/conf.py @@ -86,9 +86,9 @@ htmlhelp_basename = 'QL training' # built documents. # # The short X.Y version. -version = u'1.21' +version = u'1.22' # The full version, including alpha/beta/rc tags. -release = u'1.21' +release = u'1.22' copyright = u'2019 Semmle Ltd' author = u'Semmle Ltd' From b76f66e83be4beeb359013cde6b7f44b7f7bb897 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Fri, 20 Sep 2019 14:20:25 +0100 Subject: [PATCH 0297/1227] C++: Add test cases for constant initializers Adds test cases for initialisation of constants which aren't simple zeros. Example: int x = int(); --- .../test/duplication-tests/constants/constants.cpp | 12 ++++++++++++ .../test/duplication-tests/constants/expr.expected | 4 ++++ cpp/ql/test/duplication-tests/constants/expr.ql | 4 ++++ 3 files changed, 20 insertions(+) create mode 100644 cpp/ql/test/duplication-tests/constants/constants.cpp create mode 100644 cpp/ql/test/duplication-tests/constants/expr.expected create mode 100644 cpp/ql/test/duplication-tests/constants/expr.ql diff --git a/cpp/ql/test/duplication-tests/constants/constants.cpp b/cpp/ql/test/duplication-tests/constants/constants.cpp new file mode 100644 index 00000000000..c42a5981387 --- /dev/null +++ b/cpp/ql/test/duplication-tests/constants/constants.cpp @@ -0,0 +1,12 @@ + +int x = int(); +float y = float(); +double z = double(); + +/* This produces a getValueText() of 0 for R() in line 9, which is debatable. */ +struct R {}; +struct S { + S() : S(R()) { } + S(R) { } +}; +S s; diff --git a/cpp/ql/test/duplication-tests/constants/expr.expected b/cpp/ql/test/duplication-tests/constants/expr.expected new file mode 100644 index 00000000000..e860f867a10 --- /dev/null +++ b/cpp/ql/test/duplication-tests/constants/expr.expected @@ -0,0 +1,4 @@ +| constants.cpp:2:9:2:13 | 0 | int() | +| constants.cpp:3:11:3:17 | 0.0 | float() | +| constants.cpp:4:12:4:19 | 0.0 | double() | +| constants.cpp:9:11:9:13 | 0 | 0 | diff --git a/cpp/ql/test/duplication-tests/constants/expr.ql b/cpp/ql/test/duplication-tests/constants/expr.ql new file mode 100644 index 00000000000..09d745df82e --- /dev/null +++ b/cpp/ql/test/duplication-tests/constants/expr.ql @@ -0,0 +1,4 @@ +import cpp + +from Expr e +select e, e.getValueText() From 4f2ca11d2c75a3a9e4b8e42d857eb73376b9ae8a Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 30 Sep 2019 19:26:02 +0200 Subject: [PATCH 0298/1227] C#: Suppress `cs/similar-file` alerts --- .../Semmle.Extraction.CSharp/Entities/Expressions/Await.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/Expressions/Default.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs index 446e6057942..4a0d8eac0dd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Syntax; // lgtm[cs/similar-file] using Semmle.Extraction.Kinds; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs index 66fcececefc..4988a3c469d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Syntax; // lgtm[cs/similar-file] using Semmle.Extraction.Kinds; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs index ba05576a6a8..460dd65d2d6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Syntax; // lgtm[cs/similar-file] using Semmle.Extraction.Kinds; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs index 5a9d73c65b0..bc8630609f0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs @@ -1,4 +1,4 @@ -using Semmle.Extraction.Kinds; +using Semmle.Extraction.Kinds; // lgtm[cs/similar-file] using Microsoft.CodeAnalysis.CSharp.Syntax; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs index da88fffca9b..e916259e772 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Syntax; // lgtm[cs/similar-file] using Semmle.Extraction.Kinds; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs index 321d83f0367..ed2049c27f9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs @@ -1,4 +1,4 @@ -using Semmle.Extraction.Kinds; +using Semmle.Extraction.Kinds; // lgtm[cs/similar-file] using Microsoft.CodeAnalysis.CSharp.Syntax; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs index 4ac169c0287..1e06cfa72e4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Syntax; // lgtm[cs/similar-file] using Semmle.Extraction.Kinds; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs index 71bd7d4d702..d64113cdad2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Syntax; // lgtm[cs/similar-file] using Semmle.Extraction.Kinds; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs index b29876b8264..d4f5e91fbea 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Syntax; // lgtm[cs/similar-file] using Semmle.Extraction.Kinds; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs index f0740fef9dd..c4a46a7d74d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Syntax; // lgtm[cs/similar-file] using Semmle.Extraction.Kinds; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs index a6830b18c18..6cabf07591d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Syntax; // lgtm[cs/similar-file] using Semmle.Extraction.CSharp.Entities.Expressions; using Semmle.Extraction.Kinds; using System.IO; From 144aacb09d45ca346f381b4a1720444e72268c27 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Wed, 25 Sep 2019 12:38:52 -0700 Subject: [PATCH 0299/1227] [zlaski/memset-model] New Memset.qll file. --- .../cpp/models/implementations/Memset.qll | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll new file mode 100644 index 00000000000..be44181b7ba --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -0,0 +1,28 @@ +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.Taint + +/** + * The standard function `memset` and its assorted variants + */ +class MemsetFunction extends ArrayFunction, DataFlowFunction, TaintFunction { + MemsetFunction() { + hasGlobalName("memset") or + hasGlobalName("bzero") or + hasGlobalName("__builtin_memset") or + hasQualifiedName("std", "memset") + } + + override predicate hasArrayOutput(int bufParam) { bufParam = 0 } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + input.isInParameter(0) and + output.isOutReturnValue() + } + + override predicate hasArrayWithVariableSize(int bufParam, int countParam) { + bufParam = 0 and + (if hasGlobalName("bzero") then countParam = 1 else countParam = 2) + } +} From aaa2a60b93cb82550c3668348fc2656fe59c95ce Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Thu, 26 Sep 2019 12:14:35 -0700 Subject: [PATCH 0300/1227] [zlaski/memset-model] Remove taint tracking from `Memset.qll`. Add `Memset.qll` to `Models.qll`. --- cpp/ql/src/semmle/code/cpp/models/Models.qll | 1 + .../src/semmle/code/cpp/models/implementations/Memset.qll | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index 0747b00c48d..c152a473259 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -1,6 +1,7 @@ private import implementations.IdentityFunction private import implementations.Inet private import implementations.Memcpy +private import implementations.Memset private import implementations.Printf private import implementations.Pure private import implementations.Strcat diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index be44181b7ba..75d1bee4c88 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -1,17 +1,19 @@ 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.Taint /** * The standard function `memset` and its assorted variants */ -class MemsetFunction extends ArrayFunction, DataFlowFunction, TaintFunction { +class MemsetFunction extends ArrayFunction, DataFlowFunction { MemsetFunction() { hasGlobalName("memset") or + hasGlobalName("wmemset") or hasGlobalName("bzero") or hasGlobalName("__builtin_memset") or - hasQualifiedName("std", "memset") + hasGlobalName("__builtin_memset_chk") or + hasQualifiedName("std", "memset") or + hasQualifiedName("std", "wmemset") } override predicate hasArrayOutput(int bufParam) { bufParam = 0 } From ae169e9c33ea7a73e57e7a30abc2c736d45fe9ce Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Thu, 26 Sep 2019 16:14:07 -0700 Subject: [PATCH 0301/1227] [zlaski/memset-model] Add `AliasFunction` as base class of `MemsetFunction`; override predicates `parameterNeverEscapes`, `parameterEscapesOnlyViaReturn` and `parameterIsAlwaysReturned`. --- .../code/cpp/models/implementations/Memset.qll | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index 75d1bee4c88..85a1cec95d7 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -1,11 +1,12 @@ 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 /** * The standard function `memset` and its assorted variants */ -class MemsetFunction extends ArrayFunction, DataFlowFunction { +class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction { MemsetFunction() { hasGlobalName("memset") or hasGlobalName("wmemset") or @@ -27,4 +28,16 @@ class MemsetFunction extends ArrayFunction, DataFlowFunction { bufParam = 0 and (if hasGlobalName("bzero") then countParam = 1 else countParam = 2) } + + override predicate parameterNeverEscapes(int index) { + hasGlobalName("bzero") and index = 0 + } + + override predicate parameterEscapesOnlyViaReturn(int index) { + not hasGlobalName("bzero") and index = 0 + } + + override predicate parameterIsAlwaysReturned(int index) { + not hasGlobalName("bzero") and index = 0 + } } From a0cbd87d1f6705f2e5e4c0b637c649c1f3635bd9 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 30 Sep 2019 10:47:59 -0700 Subject: [PATCH 0302/1227] [zlaski/memset-model] Rename predicate usage as per PR/1938. --- .../code/cpp/models/implementations/Memset.qll | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index 85a1cec95d7..ce710eddaa7 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -20,24 +20,22 @@ class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction { override predicate hasArrayOutput(int bufParam) { bufParam = 0 } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { - input.isInParameter(0) and - output.isOutReturnValue() + input.isParameter(0) and + output.isReturnValue() } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { bufParam = 0 and (if hasGlobalName("bzero") then countParam = 1 else countParam = 2) } - - override predicate parameterNeverEscapes(int index) { - hasGlobalName("bzero") and index = 0 - } - + + override predicate parameterNeverEscapes(int index) { hasGlobalName("bzero") and index = 0 } + override predicate parameterEscapesOnlyViaReturn(int index) { - not hasGlobalName("bzero") and index = 0 + not hasGlobalName("bzero") and index = 0 } - + override predicate parameterIsAlwaysReturned(int index) { - not hasGlobalName("bzero") and index = 0 + not hasGlobalName("bzero") and index = 0 } } From 3d562243e4b4d0bcbe05b8be467c14907e376c09 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 11 Sep 2019 14:27:57 -0700 Subject: [PATCH 0303/1227] C++: add side effects for outparams --- cpp/ql/src/semmle/code/cpp/Parameter.qll | 7 + .../code/cpp/ir/implementation/Opcode.qll | 24 +- .../aliased_ssa/Instruction.qll | 100 +- .../ir/implementation/aliased_ssa/Operand.qll | 4 +- .../aliased_ssa/internal/AliasAnalysis.qll | 2 +- .../cpp/ir/implementation/raw/Instruction.qll | 100 +- .../cpp/ir/implementation/raw/Operand.qll | 4 +- .../raw/internal/TranslatedCall.qll | 231 ++- .../raw/internal/TranslatedElement.qll | 40 +- .../raw/internal/TranslatedExpr.qll | 4 + .../unaliased_ssa/Instruction.qll | 100 +- .../implementation/unaliased_ssa/Operand.qll | 4 +- .../unaliased_ssa/internal/AliasAnalysis.qll | 2 +- .../implementations/IdentityFunction.qll | 5 +- .../cpp/models/implementations/Memcpy.qll | 16 +- .../code/cpp/models/implementations/Pure.qll | 9 +- .../interfaces/FunctionInputsAndOutputs.qll | 7 - .../code/cpp/models/interfaces/SideEffect.qll | 12 +- .../library-tests/ir/ir/PrintAST.expected | 53 + cpp/ql/test/library-tests/ir/ir/ir.cpp | 8 + .../test/library-tests/ir/ir/raw_ir.expected | 1841 +++++++++-------- .../ir/ssa/aliased_ssa_ir.expected | 199 +- cpp/ql/test/library-tests/ir/ssa/ssa.cpp | 11 +- .../ir/ssa/unaliased_ssa_ir.expected | 177 +- .../code/csharp/ir/implementation/Opcode.qll | 24 +- .../ir/implementation/raw/Instruction.qll | 100 +- .../csharp/ir/implementation/raw/Operand.qll | 4 +- 27 files changed, 1906 insertions(+), 1182 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Parameter.qll b/cpp/ql/src/semmle/code/cpp/Parameter.qll index 74326ada99c..8b391101c6c 100644 --- a/cpp/ql/src/semmle/code/cpp/Parameter.qll +++ b/cpp/ql/src/semmle/code/cpp/Parameter.qll @@ -158,3 +158,10 @@ class Parameter extends LocalScopeVariable, @parameter { ) } } + +/** + * An `int` that is a parameter index for some function. This is needed for binding in certain cases. + */ +class ParameterIndex extends int { + ParameterIndex() { exists(Parameter p | this = p.getIndex()) } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index a16b8eb88a0..dad156c93a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -66,10 +66,10 @@ private newtype TOpcode = TCallSideEffect() or TCallReadSideEffect() or TIndirectReadSideEffect() or - TIndirectWriteSideEffect() or + TIndirectMustWriteSideEffect() or TIndirectMayWriteSideEffect() or TBufferReadSideEffect() or - TBufferWriteSideEffect() or + TBufferMustWriteSideEffect() or TBufferMayWriteSideEffect() or TChi() or TInlineAsm() or @@ -135,11 +135,16 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } +/** + * An opcode that definitely writes to a set of memory locations as a side effect. + */ +abstract class MustWriteSideEffectOpcode extends WriteSideEffectOpcode { } + /** * An opcode that may overwrite some, all, or none of an existing set of memory locations. Modeled * as a read of the original contents, plus a "may" write of the new contents. */ -abstract class MayWriteSideEffectOpcode extends SideEffectOpcode { } +abstract class MayWriteSideEffectOpcode extends WriteSideEffectOpcode { } /** * An opcode that accesses a buffer via an `AddressOperand` and a `BufferSizeOperand`. @@ -416,9 +421,9 @@ module Opcode { final override string toString() { result = "IndirectReadSideEffect" } } - class IndirectWriteSideEffect extends WriteSideEffectOpcode, MemoryAccessOpcode, - TIndirectWriteSideEffect { - final override string toString() { result = "IndirectWriteSideEffect" } + class IndirectMustWriteSideEffect extends MustWriteSideEffectOpcode, MemoryAccessOpcode, + TIndirectMustWriteSideEffect { + final override string toString() { result = "IndirectMustWriteSideEffect" } } class IndirectMayWriteSideEffect extends MayWriteSideEffectOpcode, MemoryAccessOpcode, @@ -430,9 +435,9 @@ module Opcode { final override string toString() { result = "BufferReadSideEffect" } } - class BufferWriteSideEffect extends WriteSideEffectOpcode, BufferAccessOpcode, - TBufferWriteSideEffect { - final override string toString() { result = "BufferWriteSideEffect" } + class BufferMustWriteSideEffect extends MustWriteSideEffectOpcode, BufferAccessOpcode, + TBufferMustWriteSideEffect { + final override string toString() { result = "BufferMustWriteSideEffect" } } class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode, @@ -456,3 +461,4 @@ module Opcode { final override string toString() { result = "NewObj" } } } + diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 43f9663d2cd..0f06e47a3ea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -20,32 +20,23 @@ module InstructionSanity { exists(Opcode opcode | opcode = instr.getOpcode() and ( - opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag - or - opcode instanceof BinaryOpcode and + opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or ( - tag instanceof LeftOperandTag or - tag instanceof RightOperandTag - ) - or - opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag - or - opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand - or - opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag - or - opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag - or - opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag - or - opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag - or - opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag - or - opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag - or - opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag - or + opcode instanceof BinaryOpcode and + ( + tag instanceof LeftOperandTag or + tag instanceof RightOperandTag + ) + ) or + opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or + opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or + opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag or + opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag or + opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or + opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or + opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or + opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or + ( opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or @@ -609,7 +600,9 @@ class VariableInstruction extends Instruction { VariableInstruction() { var = Construction::getInstructionVariable(this) } - final override string getImmediateString() { result = var.toString() } + override string getImmediateString() { + result = var.toString() + } final IRVariable getVariable() { result = var } } @@ -655,9 +648,9 @@ class VariableAddressInstruction extends VariableInstruction { class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } - final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } - - final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } + override final MemoryAccessKind getResultMemoryAccess() { + result instanceof IndirectMemoryAccess + } } /** @@ -1174,21 +1167,48 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends SideEffectInstruction { - IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } + IndirectReadSideEffectInstruction() { + getOpcode() instanceof Opcode::IndirectReadSideEffect + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends SideEffectInstruction { - BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } + BufferReadSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferReadSideEffect + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } +} + +/** + * An instruction representing a side effect of a function call. + */ +class WriteSideEffectInstruction extends SideEffectInstruction { + WriteSideEffectInstruction() { + getOpcode() instanceof WriteSideEffectOpcode + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } } /** * An instruction representing the write of an indirect parameter within a function call. */ -class IndirectWriteSideEffectInstruction extends SideEffectInstruction { - IndirectWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectWriteSideEffect } +class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + IndirectMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::IndirectMustWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } } @@ -1197,8 +1217,10 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction { * An instruction representing the write of an indirect buffer parameter within a function call. The * entire buffer is overwritten. */ -class BufferWriteSideEffectInstruction extends SideEffectInstruction { - BufferWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferWriteSideEffect } +class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + BufferMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferMustWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } } @@ -1208,7 +1230,7 @@ class BufferWriteSideEffectInstruction extends SideEffectInstruction { * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ -class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { +class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectMayWriteSideEffect } @@ -1222,8 +1244,10 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { * An instruction representing the write of an indirect buffer parameter within a function call. * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ -class BufferMayWriteSideEffectInstruction extends SideEffectInstruction { - BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } +class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { + BufferMayWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferMayWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMayMemoryAccess diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 1ced8ef3282..2161fe1efa4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -390,10 +390,10 @@ class SideEffectOperand extends TypedOperand { useInstr instanceof BufferReadSideEffectInstruction and result instanceof BufferMemoryAccess or - useInstr instanceof IndirectWriteSideEffectInstruction and + useInstr instanceof IndirectMustWriteSideEffectInstruction and result instanceof IndirectMemoryAccess or - useInstr instanceof BufferWriteSideEffectInstruction and + useInstr instanceof BufferMustWriteSideEffectInstruction and result instanceof BufferMemoryAccess or useInstr instanceof IndirectMayWriteSideEffectInstruction and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index dc50ef01354..da381515cb9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -226,7 +226,7 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = f + init.(InitializeParameterInstruction).getVariable().getAST() = f .getParameter(operand.(PositionalArgumentOperand).getIndex()) or init instanceof InitializeThisInstruction and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 43f9663d2cd..0f06e47a3ea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -20,32 +20,23 @@ module InstructionSanity { exists(Opcode opcode | opcode = instr.getOpcode() and ( - opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag - or - opcode instanceof BinaryOpcode and + opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or ( - tag instanceof LeftOperandTag or - tag instanceof RightOperandTag - ) - or - opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag - or - opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand - or - opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag - or - opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag - or - opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag - or - opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag - or - opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag - or - opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag - or - opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag - or + opcode instanceof BinaryOpcode and + ( + tag instanceof LeftOperandTag or + tag instanceof RightOperandTag + ) + ) or + opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or + opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or + opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag or + opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag or + opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or + opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or + opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or + opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or + ( opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or @@ -609,7 +600,9 @@ class VariableInstruction extends Instruction { VariableInstruction() { var = Construction::getInstructionVariable(this) } - final override string getImmediateString() { result = var.toString() } + override string getImmediateString() { + result = var.toString() + } final IRVariable getVariable() { result = var } } @@ -655,9 +648,9 @@ class VariableAddressInstruction extends VariableInstruction { class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } - final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } - - final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } + override final MemoryAccessKind getResultMemoryAccess() { + result instanceof IndirectMemoryAccess + } } /** @@ -1174,21 +1167,48 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends SideEffectInstruction { - IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } + IndirectReadSideEffectInstruction() { + getOpcode() instanceof Opcode::IndirectReadSideEffect + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends SideEffectInstruction { - BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } + BufferReadSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferReadSideEffect + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } +} + +/** + * An instruction representing a side effect of a function call. + */ +class WriteSideEffectInstruction extends SideEffectInstruction { + WriteSideEffectInstruction() { + getOpcode() instanceof WriteSideEffectOpcode + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } } /** * An instruction representing the write of an indirect parameter within a function call. */ -class IndirectWriteSideEffectInstruction extends SideEffectInstruction { - IndirectWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectWriteSideEffect } +class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + IndirectMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::IndirectMustWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } } @@ -1197,8 +1217,10 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction { * An instruction representing the write of an indirect buffer parameter within a function call. The * entire buffer is overwritten. */ -class BufferWriteSideEffectInstruction extends SideEffectInstruction { - BufferWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferWriteSideEffect } +class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + BufferMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferMustWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } } @@ -1208,7 +1230,7 @@ class BufferWriteSideEffectInstruction extends SideEffectInstruction { * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ -class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { +class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectMayWriteSideEffect } @@ -1222,8 +1244,10 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { * An instruction representing the write of an indirect buffer parameter within a function call. * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ -class BufferMayWriteSideEffectInstruction extends SideEffectInstruction { - BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } +class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { + BufferMayWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferMayWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMayMemoryAccess diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 1ced8ef3282..2161fe1efa4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -390,10 +390,10 @@ class SideEffectOperand extends TypedOperand { useInstr instanceof BufferReadSideEffectInstruction and result instanceof BufferMemoryAccess or - useInstr instanceof IndirectWriteSideEffectInstruction and + useInstr instanceof IndirectMustWriteSideEffectInstruction and result instanceof IndirectMemoryAccess or - useInstr instanceof BufferWriteSideEffectInstruction and + useInstr instanceof BufferMustWriteSideEffectInstruction and result instanceof BufferMemoryAccess or useInstr instanceof IndirectMayWriteSideEffectInstruction and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 14168217d9b..c9d697470c1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -5,6 +5,7 @@ private import semmle.code.cpp.models.interfaces.SideEffect private import InstructionTag private import TranslatedElement private import TranslatedExpr +private import TranslatedFunction /** * The IR translation of a call to a function. The call may be from an actual @@ -22,6 +23,8 @@ abstract class TranslatedCall extends TranslatedExpr { id = -1 and result = getCallTarget() or result = getArgument(id) + or + id = getNumberOfArguments() and result = getSideEffects() } final override Instruction getFirstInstruction() { @@ -66,6 +69,9 @@ abstract class TranslatedCall extends TranslatedExpr { then result = getArgument(argIndex + 1).getFirstInstruction() else result = getInstruction(CallTag()) ) + or + child = getSideEffects() and + result = getParent().getChildSuccessor(this) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -75,6 +81,17 @@ abstract class TranslatedCall extends TranslatedExpr { tag = CallTag() and if hasSideEffect() then result = getInstruction(CallSideEffectTag()) + else + if hasPreciseSideEffect() + then result = getSideEffects().getFirstInstruction() + else result = getParent().getChildSuccessor(this) + ) + or + ( + hasSideEffect() and + tag = CallSideEffectTag() and + if hasPreciseSideEffect() + then result = getSideEffects().getFirstInstruction() else result = getParent().getChildSuccessor(this) ) or @@ -165,6 +182,8 @@ abstract class TranslatedCall extends TranslatedExpr { */ abstract TranslatedExpr getArgument(int index); + abstract int getNumberOfArguments(); + /** * If there are any arguments, gets the first instruction of the first * argument. Otherwise, returns the call instruction. @@ -191,6 +210,10 @@ abstract class TranslatedCall extends TranslatedExpr { tag = CallSideEffectTag() and result = getResult() } + + predicate hasPreciseSideEffect() { exists(getSideEffects()) } + + TranslatedSideEffects getSideEffects() { result.getCall() = expr } } /** @@ -245,6 +268,8 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedC final override TranslatedExpr getArgument(int index) { result = getTranslatedExpr(expr.getArgument(index).getFullyConverted()) } + + final override int getNumberOfArguments() { result = expr.getNumberOfArguments() } } /** @@ -269,11 +294,11 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall { } override predicate hasReadSideEffect() { - not expr.getTarget().(SideEffectFunction).neverReadsMemory() + not expr.getTarget().(SideEffectFunction).hasOnlySpecificReadSideEffects() } override predicate hasWriteSideEffect() { - not expr.getTarget().(SideEffectFunction).neverWritesMemory() + not expr.getTarget().(SideEffectFunction).hasOnlySpecificWriteSideEffects() } } @@ -295,3 +320,205 @@ class TranslatedStructorCall extends TranslatedFunctionCall { override predicate hasQualifier() { any() } } + +class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects { + Call expr; + + TranslatedSideEffects() { this = TTranslatedSideEffects(expr) } + + override string toString() { result = "(side effects for " + expr.toString() + ")" } + + override Locatable getAST() { result = expr } + + Call getCall() { result = expr } + + override TranslatedElement getChild(int i) { + result = rank[i + 1](TranslatedSideEffect tse, int isWrite, int index | + ( + tse.getCall() = getCall() and + tse.getArgumentIndex() = index and + if tse.isWrite() then isWrite = 1 else isWrite = 0 + ) + | + tse order by isWrite, index + ) + } + + override Instruction getChildSuccessor(TranslatedElement te) { + exists(int i | + getChild(i) = te and + if exists(getChild(i + 1)) + then result = getChild(i + 1).getFirstInstruction() + else result = getParent().getChildSuccessor(this) + ) + } + + override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type t, boolean isGLValue) { + none() + } + + override Instruction getFirstInstruction() { result = getChild(0).getFirstInstruction() } + + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } + + override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } + + override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } + + /** + * Gets the `TranslatedFunction` containing this expression. + */ + final TranslatedFunction getEnclosingFunction() { + result = getTranslatedFunction(expr.getEnclosingFunction()) + } + + /** + * Gets the `Function` containing this expression. + */ + override Function getFunction() { result = expr.getEnclosingFunction() } +} + +class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEffect { + Call call; + Expr arg; + int index; + boolean write; + + TranslatedSideEffect() { this = TTranslatedArgumentSideEffect(call, arg, index, write) } + + override Locatable getAST() { result = arg } + + Expr getExpr() { result = arg } + + Call getCall() { result = call } + + int getArgumentIndex() { result = index } + + predicate isWrite() { write = true } + + override string toString() { + write = true and + result = "(write side effect for " + arg.toString() + ")" + or + write = false and + result = "(read side effect for " + arg.toString() + ")" + } + + override TranslatedElement getChild(int n) { none() } + + override Instruction getChildSuccessor(TranslatedElement child) { none() } + + override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } + + override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type t, boolean isGLValue) { + isWrite() and + hasSpecificWriteSideEffect(opcode) and + tag = OnlyInstructionTag() and + ( + opcode instanceof BufferAccessOpcode and + t instanceof UnknownType + or + not opcode instanceof BufferAccessOpcode and + ( + t = arg.getUnspecifiedType().(DerivedType).getBaseType() and + not t instanceof VoidType + or + arg.getUnspecifiedType().(DerivedType).getBaseType() instanceof VoidType and + t instanceof UnknownType + ) + or + index = -1 and + not arg.getUnspecifiedType() instanceof DerivedType and + t = arg.getUnspecifiedType() + ) and + isGLValue = false + or + not isWrite() and + hasSpecificReadSideEffect(opcode) and + tag = OnlyInstructionTag() and + t instanceof VoidType and + isGLValue = false + } + + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { + result = getParent().getChildSuccessor(this) and + tag = OnlyInstructionTag() and + kind instanceof GotoEdge + } + + override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + tag instanceof OnlyInstructionTag and + operandTag instanceof AddressOperandTag and + result = getTranslatedExpr(arg).getResult() + or + tag instanceof OnlyInstructionTag and + operandTag instanceof SideEffectOperandTag and + not call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(index, _, true) and + result = getEnclosingFunction().getUnmodeledDefinitionInstruction() + or + tag instanceof OnlyInstructionTag and + operandTag instanceof SideEffectOperandTag and + call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(index, _) and + result = getEnclosingFunction().getUnmodeledDefinitionInstruction() + } + + override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + tag instanceof OnlyInstructionTag and + result = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and + operandTag instanceof SideEffectOperandTag + or + tag instanceof OnlyInstructionTag and + result = arg.getType().getUnspecifiedType() and + not result instanceof DerivedType and + operandTag instanceof SideEffectOperandTag + } + + predicate hasSpecificWriteSideEffect(Opcode op) { + exists(boolean buffer, boolean mustWrite | + call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(index, buffer, mustWrite) and + ( + buffer = true and mustWrite = false and op instanceof Opcode::BufferMayWriteSideEffect + or + buffer = false and mustWrite = false and op instanceof Opcode::IndirectMayWriteSideEffect + or + buffer = true and mustWrite = true and op instanceof Opcode::BufferMustWriteSideEffect + or + buffer = false and mustWrite = true and op instanceof Opcode::IndirectMustWriteSideEffect + ) + ) + or + not call.getTarget() instanceof SideEffectFunction and + getArgumentIndex() != -1 and + op instanceof Opcode::BufferMayWriteSideEffect + or + not call.getTarget() instanceof SideEffectFunction and + getArgumentIndex() = -1 and + op instanceof Opcode::IndirectMayWriteSideEffect + } + + predicate hasSpecificReadSideEffect(Opcode op) { + exists(boolean buffer | + call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(index, buffer) and + ( + buffer = true and op instanceof Opcode::BufferReadSideEffect + or + buffer = false and op instanceof Opcode::IndirectReadSideEffect + ) + ) + or + not call.getTarget() instanceof SideEffectFunction and + op instanceof Opcode::IndirectReadSideEffect + } + + /** + * Gets the `TranslatedFunction` containing this expression. + */ + final TranslatedFunction getEnclosingFunction() { + result = getTranslatedFunction(arg.getEnclosingFunction()) + } + + /** + * Gets the `Function` containing this expression. + */ + override Function getFunction() { result = arg.getEnclosingFunction() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 23d3036ca15..2304d85d7ad 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -9,6 +9,7 @@ private import TranslatedCondition private import TranslatedFunction private import TranslatedStmt private import IRConstruction +private import semmle.code.cpp.models.interfaces.SideEffect /** * Gets the built-in `int` type. @@ -369,7 +370,44 @@ newtype TTranslatedElement = // An allocation size for a `new` or `new[]` expression TTranslatedAllocationSize(NewOrNewArrayExpr newExpr) { not ignoreExpr(newExpr) } or // The declaration/initialization part of a `ConditionDeclExpr` - TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } + TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or + // The side effects of a `Call` { + TTranslatedSideEffects(Call expr) { exists(TTranslatedArgumentSideEffect(expr, _, _, _)) } or // A precise side effect of an argument to a `Call` { + TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) { + ( + expr = call.getArgument(n).getFullyConverted() + or + expr = call.getQualifier().getFullyConverted() and + n = -1 + ) and + ( + call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(n, _) and + isWrite = false + or + call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(n, _, _) and + isWrite = true + or + not call.getTarget() instanceof SideEffectFunction and + exists(Type t | t = expr.getUnspecifiedType() | + t instanceof ArrayType or + t instanceof PointerType or + t instanceof ReferenceType + ) and + ( + isWrite = true or + isWrite = false + ) + or + not call.getTarget() instanceof SideEffectFunction and + n = -1 and + ( + isWrite = true or + isWrite = false + ) + ) and + not ignoreExpr(expr) and + not ignoreExpr(call) + } /** * Gets the index of the first explicitly initialized element in `initList` diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index fa8eeb36adb..97c61c146ad 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1642,6 +1642,10 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect any() } + final override int getNumberOfArguments() { + result = expr.getAllocatorCall().getNumberOfArguments() + } + final override TranslatedExpr getArgument(int index) { // If the allocator is the default operator new(void*), there will be no // allocator call in the AST. Otherwise, there will be an allocator call diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 43f9663d2cd..0f06e47a3ea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -20,32 +20,23 @@ module InstructionSanity { exists(Opcode opcode | opcode = instr.getOpcode() and ( - opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag - or - opcode instanceof BinaryOpcode and + opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or ( - tag instanceof LeftOperandTag or - tag instanceof RightOperandTag - ) - or - opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag - or - opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand - or - opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag - or - opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag - or - opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag - or - opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag - or - opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag - or - opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag - or - opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag - or + opcode instanceof BinaryOpcode and + ( + tag instanceof LeftOperandTag or + tag instanceof RightOperandTag + ) + ) or + opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or + opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or + opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag or + opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag or + opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or + opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or + opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or + opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or + ( opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or @@ -609,7 +600,9 @@ class VariableInstruction extends Instruction { VariableInstruction() { var = Construction::getInstructionVariable(this) } - final override string getImmediateString() { result = var.toString() } + override string getImmediateString() { + result = var.toString() + } final IRVariable getVariable() { result = var } } @@ -655,9 +648,9 @@ class VariableAddressInstruction extends VariableInstruction { class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } - final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } - - final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } + override final MemoryAccessKind getResultMemoryAccess() { + result instanceof IndirectMemoryAccess + } } /** @@ -1174,21 +1167,48 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends SideEffectInstruction { - IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } + IndirectReadSideEffectInstruction() { + getOpcode() instanceof Opcode::IndirectReadSideEffect + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends SideEffectInstruction { - BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } + BufferReadSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferReadSideEffect + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } +} + +/** + * An instruction representing a side effect of a function call. + */ +class WriteSideEffectInstruction extends SideEffectInstruction { + WriteSideEffectInstruction() { + getOpcode() instanceof WriteSideEffectOpcode + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } } /** * An instruction representing the write of an indirect parameter within a function call. */ -class IndirectWriteSideEffectInstruction extends SideEffectInstruction { - IndirectWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectWriteSideEffect } +class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + IndirectMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::IndirectMustWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } } @@ -1197,8 +1217,10 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction { * An instruction representing the write of an indirect buffer parameter within a function call. The * entire buffer is overwritten. */ -class BufferWriteSideEffectInstruction extends SideEffectInstruction { - BufferWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferWriteSideEffect } +class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + BufferMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferMustWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } } @@ -1208,7 +1230,7 @@ class BufferWriteSideEffectInstruction extends SideEffectInstruction { * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ -class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { +class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectMayWriteSideEffect } @@ -1222,8 +1244,10 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { * An instruction representing the write of an indirect buffer parameter within a function call. * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ -class BufferMayWriteSideEffectInstruction extends SideEffectInstruction { - BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } +class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { + BufferMayWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferMayWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMayMemoryAccess diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 1ced8ef3282..2161fe1efa4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -390,10 +390,10 @@ class SideEffectOperand extends TypedOperand { useInstr instanceof BufferReadSideEffectInstruction and result instanceof BufferMemoryAccess or - useInstr instanceof IndirectWriteSideEffectInstruction and + useInstr instanceof IndirectMustWriteSideEffectInstruction and result instanceof IndirectMemoryAccess or - useInstr instanceof BufferWriteSideEffectInstruction and + useInstr instanceof BufferMustWriteSideEffectInstruction and result instanceof BufferMemoryAccess or useInstr instanceof IndirectMayWriteSideEffectInstruction and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index dc50ef01354..da381515cb9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -226,7 +226,7 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = f + init.(InitializeParameterInstruction).getVariable().getAST() = f .getParameter(operand.(PositionalArgumentOperand).getIndex()) or init instanceof InitializeThisInstruction and diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll index 470041585c8..3e7fa713bd8 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll @@ -16,9 +16,9 @@ class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFuncti ) } - override predicate neverReadsMemory() { any() } + override predicate hasOnlySpecificReadSideEffects() { any() } - override predicate neverWritesMemory() { any() } + override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate parameterNeverEscapes(int index) { none() } @@ -37,3 +37,4 @@ class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFuncti input.isParameter(0) and output.isReturnValue() } } + 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 8fb0a61ea95..71ad3317e2d 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll @@ -1,13 +1,14 @@ 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.SideEffect import semmle.code.cpp.models.interfaces.Taint /** * The standard functions `memcpy` and `memmove`, and the gcc variant * `__builtin___memcpy_chk` */ -class MemcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction { +class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction, TaintFunction { MemcpyFunction() { this.hasName("memcpy") or this.hasName("memmove") or @@ -44,4 +45,17 @@ class MemcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction { ) and countParam = 2 } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { any() } + + override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { + i = 0 and buffer = true and mustWrite = true + } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + i = 1 and buffer = true + } } + diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index 5a7bda6012f..d3d63870577 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -67,9 +67,9 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE override predicate parameterIsAlwaysReturned(int i) { none() } - override predicate neverReadsMemory() { none() } + override predicate hasOnlySpecificReadSideEffects() { none() } - override predicate neverWritesMemory() { any() } + override predicate hasOnlySpecificWriteSideEffects() { any() } } class PureFunction extends TaintFunction, SideEffectFunction { @@ -91,7 +91,8 @@ class PureFunction extends TaintFunction, SideEffectFunction { output.isReturnValue() } - override predicate neverReadsMemory() { any() } + override predicate hasOnlySpecificReadSideEffects() { any() } - override predicate neverWritesMemory() { any() } + override predicate hasOnlySpecificWriteSideEffects() { any() } } + 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 f9b88f7a6bf..d0fbb50ebfa 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll @@ -6,13 +6,6 @@ import semmle.code.cpp.Parameter -/** - * An `int` that is a parameter index for some function. This is needed for binding in certain cases. - */ -class ParameterIndex extends int { - ParameterIndex() { exists(Parameter p | this = p.getIndex()) } -} - private newtype TFunctionInput = TInParameter(ParameterIndex i) or TInParameterDeref(ParameterIndex i) or diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll index 0afd55501c6..156b57e4fdd 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll @@ -9,6 +9,7 @@ import semmle.code.cpp.Function import semmle.code.cpp.models.Models +import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs /** * Models the side effects of a library function. @@ -19,12 +20,19 @@ abstract class SideEffectFunction extends Function { * This memory could be from global variables, or from other memory that was reachable from a * pointer that was passed into the function. */ - abstract predicate neverReadsMemory(); + abstract predicate hasOnlySpecificReadSideEffects(); /** * Holds if the function never writes to memory that remains allocated after the function * returns. This memory could be from global variables, or from other memory that was reachable * from a pointer that was passed into the function. */ - abstract predicate neverWritesMemory(); + abstract predicate hasOnlySpecificWriteSideEffects(); + + predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { + none() + } + + predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { none() } } + diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index eb6e4d3d0b6..5de69a800bc 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -8116,6 +8116,59 @@ ir.cpp: # 1158| Type = [SpecifiedType] __attribute((vector_size(16UL))) int # 1158| ValueCategory = prvalue(load) # 1159| 5: [ReturnStmt] return ... +# 1161| [TopLevelFunction] void* memcpy(void*, void*, int) +# 1161| params: +# 1161| 0: [Parameter] dst +# 1161| Type = [VoidPointerType] void * +# 1161| 1: [Parameter] src +# 1161| Type = [VoidPointerType] void * +# 1161| 2: [Parameter] size +# 1161| Type = [IntType] int +# 1163| [TopLevelFunction] int ModeledCallTarget(int) +# 1163| params: +# 1163| 0: [Parameter] x +# 1163| Type = [IntType] int +# 1163| body: [Block] { ... } +# 1164| 0: [DeclStmt] declaration +# 1164| 0: [VariableDeclarationEntry] definition of y +# 1164| Type = [IntType] int +# 1165| 1: [ExprStmt] ExprStmt +# 1165| 0: [FunctionCall] call to memcpy +# 1165| Type = [VoidPointerType] void * +# 1165| ValueCategory = prvalue +# 1165| 0: [CStyleCast] (void *)... +# 1165| Conversion = [PointerConversion] pointer conversion +# 1165| Type = [VoidPointerType] void * +# 1165| ValueCategory = prvalue +# 1165| expr: [AddressOfExpr] & ... +# 1165| Type = [IntPointerType] int * +# 1165| ValueCategory = prvalue +# 1165| 0: [VariableAccess] y +# 1165| Type = [IntType] int +# 1165| ValueCategory = lvalue +# 1165| 1: [CStyleCast] (void *)... +# 1165| Conversion = [PointerConversion] pointer conversion +# 1165| Type = [VoidPointerType] void * +# 1165| ValueCategory = prvalue +# 1165| expr: [AddressOfExpr] & ... +# 1165| Type = [IntPointerType] int * +# 1165| ValueCategory = prvalue +# 1165| 0: [VariableAccess] x +# 1165| Type = [IntType] int +# 1165| ValueCategory = lvalue +# 1165| 2: [CStyleCast] (int)... +# 1165| Conversion = [IntegralConversion] integral conversion +# 1165| Type = [IntType] int +# 1165| Value = [CStyleCast] 4 +# 1165| ValueCategory = prvalue +# 1165| expr: [SizeofTypeOperator] sizeof(int) +# 1165| Type = [LongType] unsigned long +# 1165| Value = [SizeofTypeOperator] 4 +# 1165| ValueCategory = prvalue +# 1166| 2: [ReturnStmt] return ... +# 1166| 0: [VariableAccess] y +# 1166| Type = [IntType] int +# 1166| ValueCategory = prvalue(load) perf-regression.cpp: # 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&) # 4| params: diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index 672c8d1ab81..08748ecb8d2 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -1158,4 +1158,12 @@ void VectorTypes(int i) { vi4 = vi4 + vi4_shuffle; } +void *memcpy(void *dst, void *src, int size); + +int ModeledCallTarget(int x) { + int y; + memcpy(&y, &x, sizeof(int)); + return y; +} + // semmle-extractor-options: -std=c++17 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index a9efc78468d..84059acbea2 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -14,10 +14,12 @@ bad_asts.cpp: # 16| r0_10(int) = Constant[1] : # 16| r0_11(int) = Call : func:r0_9, this:r0_8, 0:r0_10 # 16| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 17| v0_13(void) = NoOp : -# 14| v0_14(void) = ReturnVoid : -# 14| v0_15(void) = UnmodeledUse : mu* -# 14| v0_16(void) = ExitFunction : +# 16| v0_13(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 +# 16| r0_14(S) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 +# 17| v0_15(void) = NoOp : +# 14| v0_16(void) = ReturnVoid : +# 14| v0_17(void) = UnmodeledUse : mu* +# 14| v0_18(void) = ExitFunction : # 22| void Bad::Point::Point() # 22| Block 0 @@ -2673,10 +2675,14 @@ ir.cpp: # 585| r0_8(char *) = Convert : r0_7 # 585| v0_9(void) = Call : func:r0_3, 0:r0_5, 1:r0_6, 2:r0_8 # 585| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 586| v0_11(void) = NoOp : -# 584| v0_12(void) = ReturnVoid : -# 584| v0_13(void) = UnmodeledUse : mu* -# 584| v0_14(void) = ExitFunction : +# 585| v0_11(void) = ^IndirectReadSideEffect[s] : &:r0_5, ~mu0_2 +# 585| v0_12(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 +# 585| mu0_13(unknown) = ^BufferMayWriteSideEffect[s] : &:r0_5, ~mu0_2 +# 585| r0_14(unknown) = ^BufferMayWriteSideEffect : &:r0_8, ~mu0_2 +# 586| v0_15(void) = NoOp : +# 584| v0_16(void) = ReturnVoid : +# 584| v0_17(void) = UnmodeledUse : mu* +# 584| v0_18(void) = ExitFunction : # 590| void SetFuncPtr() # 590| Block 0 @@ -2702,67 +2708,77 @@ ir.cpp: # 615| void DeclareObject() # 615| Block 0 -# 615| v0_0(void) = EnterFunction : -# 615| mu0_1(unknown) = AliasedDefinition : -# 615| mu0_2(unknown) = UnmodeledDefinition : -# 616| r0_3(glval) = VariableAddress[s1] : -# 616| r0_4(glval) = FunctionAddress[String] : -# 616| v0_5(void) = Call : func:r0_4, this:r0_3 -# 616| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 617| r0_7(glval) = VariableAddress[s2] : -# 617| r0_8(glval) = FunctionAddress[String] : -# 617| r0_9(glval) = StringConstant["hello"] : -# 617| r0_10(char *) = Convert : r0_9 -# 617| v0_11(void) = Call : func:r0_8, this:r0_7, 0:r0_10 -# 617| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 618| r0_13(glval) = VariableAddress[s3] : -# 618| r0_14(glval) = FunctionAddress[ReturnObject] : -# 618| r0_15(String) = Call : func:r0_14 -# 618| mu0_16(unknown) = ^CallSideEffect : ~mu0_2 -# 618| mu0_17(String) = Store : &:r0_13, r0_15 -# 619| r0_18(glval) = VariableAddress[s4] : -# 619| r0_19(glval) = FunctionAddress[String] : -# 619| r0_20(glval) = StringConstant["test"] : -# 619| r0_21(char *) = Convert : r0_20 -# 619| v0_22(void) = Call : func:r0_19, this:r0_18, 0:r0_21 -# 619| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 -# 620| v0_24(void) = NoOp : -# 615| v0_25(void) = ReturnVoid : -# 615| v0_26(void) = UnmodeledUse : mu* -# 615| v0_27(void) = ExitFunction : +# 615| v0_0(void) = EnterFunction : +# 615| mu0_1(unknown) = AliasedDefinition : +# 615| mu0_2(unknown) = UnmodeledDefinition : +# 616| r0_3(glval) = VariableAddress[s1] : +# 616| r0_4(glval) = FunctionAddress[String] : +# 616| v0_5(void) = Call : func:r0_4, this:r0_3 +# 616| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 +# 617| r0_7(glval) = VariableAddress[s2] : +# 617| r0_8(glval) = FunctionAddress[String] : +# 617| r0_9(glval) = StringConstant["hello"] : +# 617| r0_10(char *) = Convert : r0_9 +# 617| v0_11(void) = Call : func:r0_8, this:r0_7, 0:r0_10 +# 617| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 617| v0_13(void) = ^IndirectReadSideEffect[p#0] : &:r0_10, ~mu0_2 +# 617| mu0_14(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_10, ~mu0_2 +# 618| r0_15(glval) = VariableAddress[s3] : +# 618| r0_16(glval) = FunctionAddress[ReturnObject] : +# 618| r0_17(String) = Call : func:r0_16 +# 618| mu0_18(unknown) = ^CallSideEffect : ~mu0_2 +# 618| mu0_19(String) = Store : &:r0_15, r0_17 +# 619| r0_20(glval) = VariableAddress[s4] : +# 619| r0_21(glval) = FunctionAddress[String] : +# 619| r0_22(glval) = StringConstant["test"] : +# 619| r0_23(char *) = Convert : r0_22 +# 619| v0_24(void) = Call : func:r0_21, this:r0_20, 0:r0_23 +# 619| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +# 619| v0_26(void) = ^IndirectReadSideEffect[p#0] : &:r0_23, ~mu0_2 +# 619| mu0_27(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_23, ~mu0_2 +# 620| v0_28(void) = NoOp : +# 615| v0_29(void) = ReturnVoid : +# 615| v0_30(void) = UnmodeledUse : mu* +# 615| v0_31(void) = ExitFunction : # 622| void CallMethods(String&, String*, String) # 622| Block 0 -# 622| v0_0(void) = EnterFunction : -# 622| mu0_1(unknown) = AliasedDefinition : -# 622| mu0_2(unknown) = UnmodeledDefinition : -# 622| r0_3(glval) = VariableAddress[r] : -# 622| mu0_4(String &) = InitializeParameter[r] : &:r0_3 -# 622| r0_5(glval) = VariableAddress[p] : -# 622| mu0_6(String *) = InitializeParameter[p] : &:r0_5 -# 622| r0_7(glval) = VariableAddress[s] : -# 622| mu0_8(String) = InitializeParameter[s] : &:r0_7 -# 623| r0_9(glval) = VariableAddress[r] : -# 623| r0_10(String &) = Load : &:r0_9, ~mu0_2 -# 623| r0_11(glval) = Convert : r0_10 -# 623| r0_12(glval) = FunctionAddress[c_str] : -# 623| r0_13(char *) = Call : func:r0_12, this:r0_11 -# 623| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 -# 624| r0_15(glval) = VariableAddress[p] : -# 624| r0_16(String *) = Load : &:r0_15, ~mu0_2 -# 624| r0_17(String *) = Convert : r0_16 -# 624| r0_18(glval) = FunctionAddress[c_str] : -# 624| r0_19(char *) = Call : func:r0_18, this:r0_17 -# 624| mu0_20(unknown) = ^CallSideEffect : ~mu0_2 -# 625| r0_21(glval) = VariableAddress[s] : -# 625| r0_22(glval) = Convert : r0_21 -# 625| r0_23(glval) = FunctionAddress[c_str] : -# 625| r0_24(char *) = Call : func:r0_23, this:r0_22 -# 625| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 626| v0_26(void) = NoOp : -# 622| v0_27(void) = ReturnVoid : -# 622| v0_28(void) = UnmodeledUse : mu* -# 622| v0_29(void) = ExitFunction : +# 622| v0_0(void) = EnterFunction : +# 622| mu0_1(unknown) = AliasedDefinition : +# 622| mu0_2(unknown) = UnmodeledDefinition : +# 622| r0_3(glval) = VariableAddress[r] : +# 622| mu0_4(String &) = InitializeParameter[r] : &:r0_3 +# 622| r0_5(glval) = VariableAddress[p] : +# 622| mu0_6(String *) = InitializeParameter[p] : &:r0_5 +# 622| r0_7(glval) = VariableAddress[s] : +# 622| mu0_8(String) = InitializeParameter[s] : &:r0_7 +# 623| r0_9(glval) = VariableAddress[r] : +# 623| r0_10(String &) = Load : &:r0_9, ~mu0_2 +# 623| r0_11(glval) = Convert : r0_10 +# 623| r0_12(glval) = FunctionAddress[c_str] : +# 623| r0_13(char *) = Call : func:r0_12, this:r0_11 +# 623| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 +# 623| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 +# 623| r0_16(String) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 +# 624| r0_17(glval) = VariableAddress[p] : +# 624| r0_18(String *) = Load : &:r0_17, ~mu0_2 +# 624| r0_19(String *) = Convert : r0_18 +# 624| r0_20(glval) = FunctionAddress[c_str] : +# 624| r0_21(char *) = Call : func:r0_20, this:r0_19 +# 624| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 +# 624| v0_23(void) = ^IndirectReadSideEffect : &:r0_19, ~mu0_2 +# 624| r0_24(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 +# 625| r0_25(glval) = VariableAddress[s] : +# 625| r0_26(glval) = Convert : r0_25 +# 625| r0_27(glval) = FunctionAddress[c_str] : +# 625| r0_28(char *) = Call : func:r0_27, this:r0_26 +# 625| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 +# 625| v0_30(void) = ^IndirectReadSideEffect : &:r0_26, ~mu0_2 +# 625| r0_31(String) = ^IndirectMayWriteSideEffect : &:r0_26, ~mu0_2 +# 626| v0_32(void) = NoOp : +# 622| v0_33(void) = ReturnVoid : +# 622| v0_34(void) = UnmodeledUse : mu* +# 622| v0_35(void) = ExitFunction : # 630| int C::StaticMemberFunction(int) # 630| Block 0 @@ -2865,50 +2881,58 @@ ir.cpp: # 653| r0_6(int) = Constant[0] : # 653| r0_7(int) = Call : func:r0_5, this:r0_4, 0:r0_6 # 653| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 654| r0_9(C *) = CopyValue : r0_3 -# 654| r0_10(glval) = FunctionAddress[InstanceMemberFunction] : -# 654| r0_11(int) = Constant[1] : -# 654| r0_12(int) = Call : func:r0_10, this:r0_9, 0:r0_11 -# 654| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_14(C *) = CopyValue : r0_3 -# 655| r0_15(glval) = FunctionAddress[InstanceMemberFunction] : -# 655| r0_16(int) = Constant[2] : -# 655| r0_17(int) = Call : func:r0_15, this:r0_14, 0:r0_16 -# 655| mu0_18(unknown) = ^CallSideEffect : ~mu0_2 -# 656| v0_19(void) = NoOp : -# 652| v0_20(void) = ReturnVoid : -# 652| v0_21(void) = UnmodeledUse : mu* -# 652| v0_22(void) = ExitFunction : +# 653| v0_9(void) = ^IndirectReadSideEffect : &:r0_4, ~mu0_2 +# 653| r0_10(C) = ^IndirectMayWriteSideEffect : &:r0_4, ~mu0_2 +# 654| r0_11(C *) = CopyValue : r0_3 +# 654| r0_12(glval) = FunctionAddress[InstanceMemberFunction] : +# 654| r0_13(int) = Constant[1] : +# 654| r0_14(int) = Call : func:r0_12, this:r0_11, 0:r0_13 +# 654| mu0_15(unknown) = ^CallSideEffect : ~mu0_2 +# 654| v0_16(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 +# 654| r0_17(C) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 +#-----| r0_18(C *) = CopyValue : r0_3 +# 655| r0_19(glval) = FunctionAddress[InstanceMemberFunction] : +# 655| r0_20(int) = Constant[2] : +# 655| r0_21(int) = Call : func:r0_19, this:r0_18, 0:r0_20 +# 655| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_23(void) = ^IndirectReadSideEffect : &:r0_18, ~mu0_2 +#-----| r0_24(C) = ^IndirectMayWriteSideEffect : &:r0_18, ~mu0_2 +# 656| v0_25(void) = NoOp : +# 652| v0_26(void) = ReturnVoid : +# 652| v0_27(void) = UnmodeledUse : mu* +# 652| v0_28(void) = ExitFunction : # 658| void C::C() # 658| Block 0 -# 658| v0_0(void) = EnterFunction : -# 658| mu0_1(unknown) = AliasedDefinition : -# 658| mu0_2(unknown) = UnmodeledDefinition : -# 658| r0_3(glval) = InitializeThis : -# 659| r0_4(glval) = FieldAddress[m_a] : r0_3 -# 659| r0_5(int) = Constant[1] : -# 659| mu0_6(int) = Store : &:r0_4, r0_5 -# 663| r0_7(glval) = FieldAddress[m_b] : r0_3 -# 663| r0_8(glval) = FunctionAddress[String] : -# 663| v0_9(void) = Call : func:r0_8, this:r0_7 -# 663| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 660| r0_11(glval) = FieldAddress[m_c] : r0_3 -# 660| r0_12(char) = Constant[3] : -# 660| mu0_13(char) = Store : &:r0_11, r0_12 -# 661| r0_14(glval) = FieldAddress[m_e] : r0_3 -# 661| r0_15(void *) = Constant[0] : -# 661| mu0_16(void *) = Store : &:r0_14, r0_15 -# 662| r0_17(glval) = FieldAddress[m_f] : r0_3 -# 662| r0_18(glval) = FunctionAddress[String] : -# 662| r0_19(glval) = StringConstant["test"] : -# 662| r0_20(char *) = Convert : r0_19 -# 662| v0_21(void) = Call : func:r0_18, this:r0_17, 0:r0_20 -# 662| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -# 664| v0_23(void) = NoOp : -# 658| v0_24(void) = ReturnVoid : -# 658| v0_25(void) = UnmodeledUse : mu* -# 658| v0_26(void) = ExitFunction : +# 658| v0_0(void) = EnterFunction : +# 658| mu0_1(unknown) = AliasedDefinition : +# 658| mu0_2(unknown) = UnmodeledDefinition : +# 658| r0_3(glval) = InitializeThis : +# 659| r0_4(glval) = FieldAddress[m_a] : r0_3 +# 659| r0_5(int) = Constant[1] : +# 659| mu0_6(int) = Store : &:r0_4, r0_5 +# 663| r0_7(glval) = FieldAddress[m_b] : r0_3 +# 663| r0_8(glval) = FunctionAddress[String] : +# 663| v0_9(void) = Call : func:r0_8, this:r0_7 +# 663| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 +# 660| r0_11(glval) = FieldAddress[m_c] : r0_3 +# 660| r0_12(char) = Constant[3] : +# 660| mu0_13(char) = Store : &:r0_11, r0_12 +# 661| r0_14(glval) = FieldAddress[m_e] : r0_3 +# 661| r0_15(void *) = Constant[0] : +# 661| mu0_16(void *) = Store : &:r0_14, r0_15 +# 662| r0_17(glval) = FieldAddress[m_f] : r0_3 +# 662| r0_18(glval) = FunctionAddress[String] : +# 662| r0_19(glval) = StringConstant["test"] : +# 662| r0_20(char *) = Convert : r0_19 +# 662| v0_21(void) = Call : func:r0_18, this:r0_17, 0:r0_20 +# 662| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 +# 662| v0_23(void) = ^IndirectReadSideEffect[p#0] : &:r0_20, ~mu0_2 +# 662| mu0_24(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_20, ~mu0_2 +# 664| v0_25(void) = NoOp : +# 658| v0_26(void) = ReturnVoid : +# 658| v0_27(void) = UnmodeledUse : mu* +# 658| v0_28(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 @@ -3094,21 +3118,23 @@ ir.cpp: # 720| double CallNestedTemplateFunc() # 720| Block 0 -# 720| v0_0(void) = EnterFunction : -# 720| mu0_1(unknown) = AliasedDefinition : -# 720| mu0_2(unknown) = UnmodeledDefinition : -# 721| r0_3(glval) = VariableAddress[#return] : -# 721| r0_4(glval) = FunctionAddress[Func] : -# 721| r0_5(void *) = Constant[0] : -# 721| r0_6(char) = Constant[111] : -# 721| r0_7(long) = Call : func:r0_4, 0:r0_5, 1:r0_6 -# 721| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 721| r0_9(double) = Convert : r0_7 -# 721| mu0_10(double) = Store : &:r0_3, r0_9 -# 720| r0_11(glval) = VariableAddress[#return] : -# 720| v0_12(void) = ReturnValue : &:r0_11, ~mu0_2 -# 720| v0_13(void) = UnmodeledUse : mu* -# 720| v0_14(void) = ExitFunction : +# 720| v0_0(void) = EnterFunction : +# 720| mu0_1(unknown) = AliasedDefinition : +# 720| mu0_2(unknown) = UnmodeledDefinition : +# 721| r0_3(glval) = VariableAddress[#return] : +# 721| r0_4(glval) = FunctionAddress[Func] : +# 721| r0_5(void *) = Constant[0] : +# 721| r0_6(char) = Constant[111] : +# 721| r0_7(long) = Call : func:r0_4, 0:r0_5, 1:r0_6 +# 721| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 +# 721| v0_9(void) = ^IndirectReadSideEffect[x] : &:r0_5, ~mu0_2 +# 721| mu0_10(unknown) = ^BufferMayWriteSideEffect[x] : &:r0_5, ~mu0_2 +# 721| r0_11(double) = Convert : r0_7 +# 721| mu0_12(double) = Store : &:r0_3, r0_11 +# 720| r0_13(glval) = VariableAddress[#return] : +# 720| v0_14(void) = ReturnValue : &:r0_13, ~mu0_2 +# 720| v0_15(void) = UnmodeledUse : mu* +# 720| v0_16(void) = ExitFunction : # 724| void TryCatch(bool) # 724| Block 0 @@ -3175,7 +3201,9 @@ ir.cpp: # 731| r7_3(char *) = Convert : r7_2 # 731| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 731| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 731| v7_6(void) = ThrowValue : &:r7_0, ~mu0_2 +# 731| v7_6(void) = ^IndirectReadSideEffect[p#0] : &:r7_3, ~mu0_2 +# 731| mu7_7(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r7_3, ~mu0_2 +# 731| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 # 733| Block 8 @@ -3190,15 +3218,17 @@ ir.cpp: #-----| Goto -> Block 10 # 735| Block 10 -# 735| r10_0(glval) = VariableAddress[s] : -# 735| mu10_1(char *) = InitializeParameter[s] : &:r10_0 -# 736| r10_2(glval) = VariableAddress[#throw736:5] : -# 736| r10_3(glval) = FunctionAddress[String] : -# 736| r10_4(glval) = VariableAddress[s] : -# 736| r10_5(char *) = Load : &:r10_4, ~mu0_2 -# 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 -# 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 736| v10_8(void) = ThrowValue : &:r10_2, ~mu0_2 +# 735| r10_0(glval) = VariableAddress[s] : +# 735| mu10_1(char *) = InitializeParameter[s] : &:r10_0 +# 736| r10_2(glval) = VariableAddress[#throw736:5] : +# 736| r10_3(glval) = FunctionAddress[String] : +# 736| r10_4(glval) = VariableAddress[s] : +# 736| r10_5(char *) = Load : &:r10_4, ~mu0_2 +# 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 +# 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 +# 736| v10_8(void) = ^IndirectReadSideEffect[p#0] : &:r10_5, ~mu0_2 +# 736| mu10_9(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r10_5, ~mu0_2 +# 736| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 # 738| Block 11 @@ -3224,27 +3254,31 @@ ir.cpp: # 745| Base& Base::operator=(Base const&) # 745| Block 0 -# 745| v0_0(void) = EnterFunction : -# 745| mu0_1(unknown) = AliasedDefinition : -# 745| mu0_2(unknown) = UnmodeledDefinition : -# 745| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 -#-----| r0_6(Base *) = CopyValue : r0_3 -#-----| r0_7(glval) = FieldAddress[base_s] : r0_6 -# 745| r0_8(glval) = FunctionAddress[operator=] : -#-----| r0_9(glval) = VariableAddress[p#0] : -#-----| r0_10(Base &) = Load : &:r0_9, ~mu0_2 -#-----| r0_11(glval) = FieldAddress[base_s] : r0_10 -# 745| r0_12(String &) = Call : func:r0_8, this:r0_7, 0:r0_11 -# 745| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_14(glval) = VariableAddress[#return] : -#-----| r0_15(Base *) = CopyValue : r0_3 -#-----| mu0_16(Base &) = Store : &:r0_14, r0_15 -# 745| r0_17(glval) = VariableAddress[#return] : -# 745| v0_18(void) = ReturnValue : &:r0_17, ~mu0_2 -# 745| v0_19(void) = UnmodeledUse : mu* -# 745| v0_20(void) = ExitFunction : +# 745| v0_0(void) = EnterFunction : +# 745| mu0_1(unknown) = AliasedDefinition : +# 745| mu0_2(unknown) = UnmodeledDefinition : +# 745| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 +#-----| r0_6(Base *) = CopyValue : r0_3 +#-----| r0_7(glval) = FieldAddress[base_s] : r0_6 +# 745| r0_8(glval) = FunctionAddress[operator=] : +#-----| r0_9(glval) = VariableAddress[p#0] : +#-----| r0_10(Base &) = Load : &:r0_9, ~mu0_2 +#-----| r0_11(glval) = FieldAddress[base_s] : r0_10 +# 745| r0_12(String &) = Call : func:r0_8, this:r0_7, 0:r0_11 +# 745| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect[p#0] : &:r0_11, ~mu0_2 +#-----| r0_16(String) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_11, ~mu0_2 +#-----| r0_18(glval) = VariableAddress[#return] : +#-----| r0_19(Base *) = CopyValue : r0_3 +#-----| mu0_20(Base &) = Store : &:r0_18, r0_19 +# 745| r0_21(glval) = VariableAddress[#return] : +# 745| v0_22(void) = ReturnValue : &:r0_21, ~mu0_2 +# 745| v0_23(void) = UnmodeledUse : mu* +# 745| v0_24(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 @@ -3295,35 +3329,43 @@ ir.cpp: # 754| Middle& Middle::operator=(Middle const&) # 754| Block 0 -# 754| v0_0(void) = EnterFunction : -# 754| mu0_1(unknown) = AliasedDefinition : -# 754| mu0_2(unknown) = UnmodeledDefinition : -# 754| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(Middle &) = InitializeParameter[p#0] : &:r0_4 -#-----| r0_6(Middle *) = CopyValue : r0_3 -#-----| r0_7(Base *) = ConvertToBase[Middle : Base] : r0_6 -# 754| r0_8(glval) = FunctionAddress[operator=] : -#-----| r0_9(glval) = VariableAddress[p#0] : -#-----| r0_10(Middle &) = Load : &:r0_9, ~mu0_2 -#-----| r0_11(Base *) = ConvertToBase[Middle : Base] : r0_10 -# 754| r0_12(Base &) = Call : func:r0_8, this:r0_7, 0:r0_11 -# 754| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_14(Middle *) = CopyValue : r0_3 -#-----| r0_15(glval) = FieldAddress[middle_s] : r0_14 -# 754| r0_16(glval) = FunctionAddress[operator=] : -#-----| r0_17(glval) = VariableAddress[p#0] : -#-----| r0_18(Middle &) = Load : &:r0_17, ~mu0_2 -#-----| r0_19(glval) = FieldAddress[middle_s] : r0_18 -# 754| r0_20(String &) = Call : func:r0_16, this:r0_15, 0:r0_19 -# 754| mu0_21(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_22(glval) = VariableAddress[#return] : -#-----| r0_23(Middle *) = CopyValue : r0_3 -#-----| mu0_24(Middle &) = Store : &:r0_22, r0_23 -# 754| r0_25(glval) = VariableAddress[#return] : -# 754| v0_26(void) = ReturnValue : &:r0_25, ~mu0_2 -# 754| v0_27(void) = UnmodeledUse : mu* -# 754| v0_28(void) = ExitFunction : +# 754| v0_0(void) = EnterFunction : +# 754| mu0_1(unknown) = AliasedDefinition : +# 754| mu0_2(unknown) = UnmodeledDefinition : +# 754| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(Middle &) = InitializeParameter[p#0] : &:r0_4 +#-----| r0_6(Middle *) = CopyValue : r0_3 +#-----| r0_7(Base *) = ConvertToBase[Middle : Base] : r0_6 +# 754| r0_8(glval) = FunctionAddress[operator=] : +#-----| r0_9(glval) = VariableAddress[p#0] : +#-----| r0_10(Middle &) = Load : &:r0_9, ~mu0_2 +#-----| r0_11(Base *) = ConvertToBase[Middle : Base] : r0_10 +# 754| r0_12(Base &) = Call : func:r0_8, this:r0_7, 0:r0_11 +# 754| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect[p#0] : &:r0_11, ~mu0_2 +#-----| r0_16(Base) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_11, ~mu0_2 +#-----| r0_18(Middle *) = CopyValue : r0_3 +#-----| r0_19(glval) = FieldAddress[middle_s] : r0_18 +# 754| r0_20(glval) = FunctionAddress[operator=] : +#-----| r0_21(glval) = VariableAddress[p#0] : +#-----| r0_22(Middle &) = Load : &:r0_21, ~mu0_2 +#-----| r0_23(glval) = FieldAddress[middle_s] : r0_22 +# 754| r0_24(String &) = Call : func:r0_20, this:r0_19, 0:r0_23 +# 754| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_26(void) = ^IndirectReadSideEffect : &:r0_19, ~mu0_2 +#-----| v0_27(void) = ^IndirectReadSideEffect[p#0] : &:r0_23, ~mu0_2 +#-----| r0_28(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 +#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_23, ~mu0_2 +#-----| r0_30(glval) = VariableAddress[#return] : +#-----| r0_31(Middle *) = CopyValue : r0_3 +#-----| mu0_32(Middle &) = Store : &:r0_30, r0_31 +# 754| r0_33(glval) = VariableAddress[#return] : +# 754| v0_34(void) = ReturnValue : &:r0_33, ~mu0_2 +# 754| v0_35(void) = UnmodeledUse : mu* +# 754| v0_36(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 @@ -3379,21 +3421,29 @@ ir.cpp: #-----| r0_11(Middle *) = ConvertToBase[Derived : Middle] : r0_10 # 763| r0_12(Middle &) = Call : func:r0_8, this:r0_7, 0:r0_11 # 763| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_14(Derived *) = CopyValue : r0_3 -#-----| r0_15(glval) = FieldAddress[derived_s] : r0_14 -# 763| r0_16(glval) = FunctionAddress[operator=] : -#-----| r0_17(glval) = VariableAddress[p#0] : -#-----| r0_18(Derived &) = Load : &:r0_17, ~mu0_2 +#-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect[p#0] : &:r0_11, ~mu0_2 +#-----| r0_16(Middle) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_11, ~mu0_2 +#-----| r0_18(Derived *) = CopyValue : r0_3 #-----| r0_19(glval) = FieldAddress[derived_s] : r0_18 -# 763| r0_20(String &) = Call : func:r0_16, this:r0_15, 0:r0_19 -# 763| mu0_21(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_22(glval) = VariableAddress[#return] : -#-----| r0_23(Derived *) = CopyValue : r0_3 -#-----| mu0_24(Derived &) = Store : &:r0_22, r0_23 -# 763| r0_25(glval) = VariableAddress[#return] : -# 763| v0_26(void) = ReturnValue : &:r0_25, ~mu0_2 -# 763| v0_27(void) = UnmodeledUse : mu* -# 763| v0_28(void) = ExitFunction : +# 763| r0_20(glval) = FunctionAddress[operator=] : +#-----| r0_21(glval) = VariableAddress[p#0] : +#-----| r0_22(Derived &) = Load : &:r0_21, ~mu0_2 +#-----| r0_23(glval) = FieldAddress[derived_s] : r0_22 +# 763| r0_24(String &) = Call : func:r0_20, this:r0_19, 0:r0_23 +# 763| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_26(void) = ^IndirectReadSideEffect : &:r0_19, ~mu0_2 +#-----| v0_27(void) = ^IndirectReadSideEffect[p#0] : &:r0_23, ~mu0_2 +#-----| r0_28(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 +#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_23, ~mu0_2 +#-----| r0_30(glval) = VariableAddress[#return] : +#-----| r0_31(Derived *) = CopyValue : r0_3 +#-----| mu0_32(Derived &) = Store : &:r0_30, r0_31 +# 763| r0_33(glval) = VariableAddress[#return] : +# 763| v0_34(void) = ReturnValue : &:r0_33, ~mu0_2 +# 763| v0_35(void) = UnmodeledUse : mu* +# 763| v0_36(void) = ExitFunction : # 766| void Derived::Derived() # 766| Block 0 @@ -3595,180 +3645,228 @@ ir.cpp: # 808| r0_27(glval) = ConvertToBase[Middle : Base] : r0_26 # 808| r0_28(Base &) = Call : func:r0_25, this:r0_24, 0:r0_27 # 808| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 -# 809| r0_30(glval) = VariableAddress[b] : -# 809| r0_31(glval) = FunctionAddress[operator=] : -# 809| r0_32(glval) = FunctionAddress[Base] : -# 809| r0_33(glval) = VariableAddress[m] : -# 809| r0_34(glval) = ConvertToBase[Middle : Base] : r0_33 -# 809| v0_35(void) = Call : func:r0_32, 0:r0_34 -# 809| mu0_36(unknown) = ^CallSideEffect : ~mu0_2 -# 809| r0_37(glval) = Convert : v0_35 -# 809| r0_38(Base &) = Call : func:r0_31, this:r0_30, 0:r0_37 -# 809| mu0_39(unknown) = ^CallSideEffect : ~mu0_2 -# 810| r0_40(glval) = VariableAddress[b] : -# 810| r0_41(glval) = FunctionAddress[operator=] : -# 810| r0_42(glval) = FunctionAddress[Base] : -# 810| r0_43(glval) = VariableAddress[m] : -# 810| r0_44(glval) = ConvertToBase[Middle : Base] : r0_43 -# 810| v0_45(void) = Call : func:r0_42, 0:r0_44 -# 810| mu0_46(unknown) = ^CallSideEffect : ~mu0_2 -# 810| r0_47(glval) = Convert : v0_45 -# 810| r0_48(Base &) = Call : func:r0_41, this:r0_40, 0:r0_47 -# 810| mu0_49(unknown) = ^CallSideEffect : ~mu0_2 -# 811| r0_50(glval) = VariableAddress[pm] : -# 811| r0_51(Middle *) = Load : &:r0_50, ~mu0_2 -# 811| r0_52(Base *) = ConvertToBase[Middle : Base] : r0_51 -# 811| r0_53(glval) = VariableAddress[pb] : -# 811| mu0_54(Base *) = Store : &:r0_53, r0_52 -# 812| r0_55(glval) = VariableAddress[pm] : -# 812| r0_56(Middle *) = Load : &:r0_55, ~mu0_2 -# 812| r0_57(Base *) = ConvertToBase[Middle : Base] : r0_56 -# 812| r0_58(glval) = VariableAddress[pb] : -# 812| mu0_59(Base *) = Store : &:r0_58, r0_57 -# 813| r0_60(glval) = VariableAddress[pm] : -# 813| r0_61(Middle *) = Load : &:r0_60, ~mu0_2 -# 813| r0_62(Base *) = ConvertToBase[Middle : Base] : r0_61 -# 813| r0_63(glval) = VariableAddress[pb] : -# 813| mu0_64(Base *) = Store : &:r0_63, r0_62 -# 814| r0_65(glval) = VariableAddress[pm] : -# 814| r0_66(Middle *) = Load : &:r0_65, ~mu0_2 -# 814| r0_67(Base *) = Convert : r0_66 -# 814| r0_68(glval) = VariableAddress[pb] : -# 814| mu0_69(Base *) = Store : &:r0_68, r0_67 -# 816| r0_70(glval) = VariableAddress[m] : -# 816| r0_71(glval) = FunctionAddress[operator=] : -# 816| r0_72(glval) = VariableAddress[b] : -# 816| r0_73(glval) = ConvertToDerived[Middle : Base] : r0_72 -# 816| r0_74(glval) = Convert : r0_73 -# 816| r0_75(Middle &) = Call : func:r0_71, this:r0_70, 0:r0_74 -# 816| mu0_76(unknown) = ^CallSideEffect : ~mu0_2 -# 817| r0_77(glval) = VariableAddress[m] : -# 817| r0_78(glval) = FunctionAddress[operator=] : -# 817| r0_79(glval) = VariableAddress[b] : -# 817| r0_80(glval) = ConvertToDerived[Middle : Base] : r0_79 -# 817| r0_81(glval) = Convert : r0_80 -# 817| r0_82(Middle &) = Call : func:r0_78, this:r0_77, 0:r0_81 -# 817| mu0_83(unknown) = ^CallSideEffect : ~mu0_2 -# 818| r0_84(glval) = VariableAddress[pb] : -# 818| r0_85(Base *) = Load : &:r0_84, ~mu0_2 -# 818| r0_86(Middle *) = ConvertToDerived[Middle : Base] : r0_85 -# 818| r0_87(glval) = VariableAddress[pm] : -# 818| mu0_88(Middle *) = Store : &:r0_87, r0_86 -# 819| r0_89(glval) = VariableAddress[pb] : -# 819| r0_90(Base *) = Load : &:r0_89, ~mu0_2 -# 819| r0_91(Middle *) = ConvertToDerived[Middle : Base] : r0_90 -# 819| r0_92(glval) = VariableAddress[pm] : -# 819| mu0_93(Middle *) = Store : &:r0_92, r0_91 -# 820| r0_94(glval) = VariableAddress[pb] : -# 820| r0_95(Base *) = Load : &:r0_94, ~mu0_2 -# 820| r0_96(Middle *) = Convert : r0_95 -# 820| r0_97(glval) = VariableAddress[pm] : -# 820| mu0_98(Middle *) = Store : &:r0_97, r0_96 -# 822| r0_99(glval) = VariableAddress[b] : -# 822| r0_100(glval) = FunctionAddress[operator=] : -# 822| r0_101(glval) = VariableAddress[d] : -# 822| r0_102(glval) = ConvertToBase[Derived : Middle] : r0_101 -# 822| r0_103(glval) = ConvertToBase[Middle : Base] : r0_102 -# 822| r0_104(Base &) = Call : func:r0_100, this:r0_99, 0:r0_103 -# 822| mu0_105(unknown) = ^CallSideEffect : ~mu0_2 -# 823| r0_106(glval) = VariableAddress[b] : -# 823| r0_107(glval) = FunctionAddress[operator=] : -# 823| r0_108(glval) = FunctionAddress[Base] : -# 823| r0_109(glval) = VariableAddress[d] : -# 823| r0_110(glval) = ConvertToBase[Derived : Middle] : r0_109 -# 823| r0_111(glval) = ConvertToBase[Middle : Base] : r0_110 -# 823| v0_112(void) = Call : func:r0_108, 0:r0_111 -# 823| mu0_113(unknown) = ^CallSideEffect : ~mu0_2 -# 823| r0_114(glval) = Convert : v0_112 -# 823| r0_115(Base &) = Call : func:r0_107, this:r0_106, 0:r0_114 -# 823| mu0_116(unknown) = ^CallSideEffect : ~mu0_2 -# 824| r0_117(glval) = VariableAddress[b] : -# 824| r0_118(glval) = FunctionAddress[operator=] : -# 824| r0_119(glval) = FunctionAddress[Base] : -# 824| r0_120(glval) = VariableAddress[d] : -# 824| r0_121(glval) = ConvertToBase[Derived : Middle] : r0_120 -# 824| r0_122(glval) = ConvertToBase[Middle : Base] : r0_121 -# 824| v0_123(void) = Call : func:r0_119, 0:r0_122 -# 824| mu0_124(unknown) = ^CallSideEffect : ~mu0_2 -# 824| r0_125(glval) = Convert : v0_123 -# 824| r0_126(Base &) = Call : func:r0_118, this:r0_117, 0:r0_125 -# 824| mu0_127(unknown) = ^CallSideEffect : ~mu0_2 -# 825| r0_128(glval) = VariableAddress[pd] : -# 825| r0_129(Derived *) = Load : &:r0_128, ~mu0_2 -# 825| r0_130(Middle *) = ConvertToBase[Derived : Middle] : r0_129 -# 825| r0_131(Base *) = ConvertToBase[Middle : Base] : r0_130 -# 825| r0_132(glval) = VariableAddress[pb] : -# 825| mu0_133(Base *) = Store : &:r0_132, r0_131 -# 826| r0_134(glval) = VariableAddress[pd] : -# 826| r0_135(Derived *) = Load : &:r0_134, ~mu0_2 -# 826| r0_136(Middle *) = ConvertToBase[Derived : Middle] : r0_135 -# 826| r0_137(Base *) = ConvertToBase[Middle : Base] : r0_136 -# 826| r0_138(glval) = VariableAddress[pb] : -# 826| mu0_139(Base *) = Store : &:r0_138, r0_137 -# 827| r0_140(glval) = VariableAddress[pd] : -# 827| r0_141(Derived *) = Load : &:r0_140, ~mu0_2 -# 827| r0_142(Middle *) = ConvertToBase[Derived : Middle] : r0_141 -# 827| r0_143(Base *) = ConvertToBase[Middle : Base] : r0_142 -# 827| r0_144(glval) = VariableAddress[pb] : -# 827| mu0_145(Base *) = Store : &:r0_144, r0_143 -# 828| r0_146(glval) = VariableAddress[pd] : -# 828| r0_147(Derived *) = Load : &:r0_146, ~mu0_2 -# 828| r0_148(Base *) = Convert : r0_147 -# 828| r0_149(glval) = VariableAddress[pb] : -# 828| mu0_150(Base *) = Store : &:r0_149, r0_148 -# 830| r0_151(glval) = VariableAddress[d] : -# 830| r0_152(glval) = FunctionAddress[operator=] : -# 830| r0_153(glval) = VariableAddress[b] : -# 830| r0_154(glval) = ConvertToDerived[Middle : Base] : r0_153 -# 830| r0_155(glval) = ConvertToDerived[Derived : Middle] : r0_154 -# 830| r0_156(glval) = Convert : r0_155 -# 830| r0_157(Derived &) = Call : func:r0_152, this:r0_151, 0:r0_156 -# 830| mu0_158(unknown) = ^CallSideEffect : ~mu0_2 -# 831| r0_159(glval) = VariableAddress[d] : -# 831| r0_160(glval) = FunctionAddress[operator=] : -# 831| r0_161(glval) = VariableAddress[b] : -# 831| r0_162(glval) = ConvertToDerived[Middle : Base] : r0_161 -# 831| r0_163(glval) = ConvertToDerived[Derived : Middle] : r0_162 -# 831| r0_164(glval) = Convert : r0_163 -# 831| r0_165(Derived &) = Call : func:r0_160, this:r0_159, 0:r0_164 -# 831| mu0_166(unknown) = ^CallSideEffect : ~mu0_2 -# 832| r0_167(glval) = VariableAddress[pb] : -# 832| r0_168(Base *) = Load : &:r0_167, ~mu0_2 -# 832| r0_169(Middle *) = ConvertToDerived[Middle : Base] : r0_168 -# 832| r0_170(Derived *) = ConvertToDerived[Derived : Middle] : r0_169 -# 832| r0_171(glval) = VariableAddress[pd] : -# 832| mu0_172(Derived *) = Store : &:r0_171, r0_170 -# 833| r0_173(glval) = VariableAddress[pb] : -# 833| r0_174(Base *) = Load : &:r0_173, ~mu0_2 -# 833| r0_175(Middle *) = ConvertToDerived[Middle : Base] : r0_174 -# 833| r0_176(Derived *) = ConvertToDerived[Derived : Middle] : r0_175 -# 833| r0_177(glval) = VariableAddress[pd] : -# 833| mu0_178(Derived *) = Store : &:r0_177, r0_176 -# 834| r0_179(glval) = VariableAddress[pb] : -# 834| r0_180(Base *) = Load : &:r0_179, ~mu0_2 -# 834| r0_181(Derived *) = Convert : r0_180 -# 834| r0_182(glval) = VariableAddress[pd] : -# 834| mu0_183(Derived *) = Store : &:r0_182, r0_181 -# 836| r0_184(glval) = VariableAddress[pmv] : -# 836| r0_185(MiddleVB1 *) = Constant[0] : -# 836| mu0_186(MiddleVB1 *) = Store : &:r0_184, r0_185 -# 837| r0_187(glval) = VariableAddress[pdv] : -# 837| r0_188(DerivedVB *) = Constant[0] : -# 837| mu0_189(DerivedVB *) = Store : &:r0_187, r0_188 -# 838| r0_190(glval) = VariableAddress[pmv] : -# 838| r0_191(MiddleVB1 *) = Load : &:r0_190, ~mu0_2 -# 838| r0_192(Base *) = ConvertToVirtualBase[MiddleVB1 : Base] : r0_191 -# 838| r0_193(glval) = VariableAddress[pb] : -# 838| mu0_194(Base *) = Store : &:r0_193, r0_192 -# 839| r0_195(glval) = VariableAddress[pdv] : -# 839| r0_196(DerivedVB *) = Load : &:r0_195, ~mu0_2 -# 839| r0_197(Base *) = ConvertToVirtualBase[DerivedVB : Base] : r0_196 -# 839| r0_198(glval) = VariableAddress[pb] : -# 839| mu0_199(Base *) = Store : &:r0_198, r0_197 -# 840| v0_200(void) = NoOp : -# 799| v0_201(void) = ReturnVoid : -# 799| v0_202(void) = UnmodeledUse : mu* -# 799| v0_203(void) = ExitFunction : +# 808| v0_30(void) = ^IndirectReadSideEffect : &:r0_24, ~mu0_2 +# 808| v0_31(void) = ^IndirectReadSideEffect[p#0] : &:r0_27, ~mu0_2 +# 808| r0_32(Base) = ^IndirectMayWriteSideEffect : &:r0_24, ~mu0_2 +# 808| mu0_33(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_27, ~mu0_2 +# 809| r0_34(glval) = VariableAddress[b] : +# 809| r0_35(glval) = FunctionAddress[operator=] : +# 809| r0_36(glval) = FunctionAddress[Base] : +# 809| r0_37(glval) = VariableAddress[m] : +# 809| r0_38(glval) = ConvertToBase[Middle : Base] : r0_37 +# 809| v0_39(void) = Call : func:r0_36, 0:r0_38 +# 809| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 +# 809| v0_41(void) = ^IndirectReadSideEffect[p#0] : &:r0_38, ~mu0_2 +# 809| mu0_42(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_38, ~mu0_2 +# 809| r0_43(glval) = Convert : v0_39 +# 809| r0_44(Base &) = Call : func:r0_35, this:r0_34, 0:r0_43 +# 809| mu0_45(unknown) = ^CallSideEffect : ~mu0_2 +# 809| v0_46(void) = ^IndirectReadSideEffect : &:r0_34, ~mu0_2 +# 809| v0_47(void) = ^IndirectReadSideEffect[p#0] : &:r0_43, ~mu0_2 +# 809| r0_48(Base) = ^IndirectMayWriteSideEffect : &:r0_34, ~mu0_2 +# 809| mu0_49(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_43, ~mu0_2 +# 810| r0_50(glval) = VariableAddress[b] : +# 810| r0_51(glval) = FunctionAddress[operator=] : +# 810| r0_52(glval) = FunctionAddress[Base] : +# 810| r0_53(glval) = VariableAddress[m] : +# 810| r0_54(glval) = ConvertToBase[Middle : Base] : r0_53 +# 810| v0_55(void) = Call : func:r0_52, 0:r0_54 +# 810| mu0_56(unknown) = ^CallSideEffect : ~mu0_2 +# 810| v0_57(void) = ^IndirectReadSideEffect[p#0] : &:r0_54, ~mu0_2 +# 810| mu0_58(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_54, ~mu0_2 +# 810| r0_59(glval) = Convert : v0_55 +# 810| r0_60(Base &) = Call : func:r0_51, this:r0_50, 0:r0_59 +# 810| mu0_61(unknown) = ^CallSideEffect : ~mu0_2 +# 810| v0_62(void) = ^IndirectReadSideEffect : &:r0_50, ~mu0_2 +# 810| v0_63(void) = ^IndirectReadSideEffect[p#0] : &:r0_59, ~mu0_2 +# 810| r0_64(Base) = ^IndirectMayWriteSideEffect : &:r0_50, ~mu0_2 +# 810| mu0_65(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_59, ~mu0_2 +# 811| r0_66(glval) = VariableAddress[pm] : +# 811| r0_67(Middle *) = Load : &:r0_66, ~mu0_2 +# 811| r0_68(Base *) = ConvertToBase[Middle : Base] : r0_67 +# 811| r0_69(glval) = VariableAddress[pb] : +# 811| mu0_70(Base *) = Store : &:r0_69, r0_68 +# 812| r0_71(glval) = VariableAddress[pm] : +# 812| r0_72(Middle *) = Load : &:r0_71, ~mu0_2 +# 812| r0_73(Base *) = ConvertToBase[Middle : Base] : r0_72 +# 812| r0_74(glval) = VariableAddress[pb] : +# 812| mu0_75(Base *) = Store : &:r0_74, r0_73 +# 813| r0_76(glval) = VariableAddress[pm] : +# 813| r0_77(Middle *) = Load : &:r0_76, ~mu0_2 +# 813| r0_78(Base *) = ConvertToBase[Middle : Base] : r0_77 +# 813| r0_79(glval) = VariableAddress[pb] : +# 813| mu0_80(Base *) = Store : &:r0_79, r0_78 +# 814| r0_81(glval) = VariableAddress[pm] : +# 814| r0_82(Middle *) = Load : &:r0_81, ~mu0_2 +# 814| r0_83(Base *) = Convert : r0_82 +# 814| r0_84(glval) = VariableAddress[pb] : +# 814| mu0_85(Base *) = Store : &:r0_84, r0_83 +# 816| r0_86(glval) = VariableAddress[m] : +# 816| r0_87(glval) = FunctionAddress[operator=] : +# 816| r0_88(glval) = VariableAddress[b] : +# 816| r0_89(glval) = ConvertToDerived[Middle : Base] : r0_88 +# 816| r0_90(glval) = Convert : r0_89 +# 816| r0_91(Middle &) = Call : func:r0_87, this:r0_86, 0:r0_90 +# 816| mu0_92(unknown) = ^CallSideEffect : ~mu0_2 +# 816| v0_93(void) = ^IndirectReadSideEffect : &:r0_86, ~mu0_2 +# 816| v0_94(void) = ^IndirectReadSideEffect[p#0] : &:r0_90, ~mu0_2 +# 816| r0_95(Middle) = ^IndirectMayWriteSideEffect : &:r0_86, ~mu0_2 +# 816| mu0_96(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_90, ~mu0_2 +# 817| r0_97(glval) = VariableAddress[m] : +# 817| r0_98(glval) = FunctionAddress[operator=] : +# 817| r0_99(glval) = VariableAddress[b] : +# 817| r0_100(glval) = ConvertToDerived[Middle : Base] : r0_99 +# 817| r0_101(glval) = Convert : r0_100 +# 817| r0_102(Middle &) = Call : func:r0_98, this:r0_97, 0:r0_101 +# 817| mu0_103(unknown) = ^CallSideEffect : ~mu0_2 +# 817| v0_104(void) = ^IndirectReadSideEffect : &:r0_97, ~mu0_2 +# 817| v0_105(void) = ^IndirectReadSideEffect[p#0] : &:r0_101, ~mu0_2 +# 817| r0_106(Middle) = ^IndirectMayWriteSideEffect : &:r0_97, ~mu0_2 +# 817| mu0_107(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_101, ~mu0_2 +# 818| r0_108(glval) = VariableAddress[pb] : +# 818| r0_109(Base *) = Load : &:r0_108, ~mu0_2 +# 818| r0_110(Middle *) = ConvertToDerived[Middle : Base] : r0_109 +# 818| r0_111(glval) = VariableAddress[pm] : +# 818| mu0_112(Middle *) = Store : &:r0_111, r0_110 +# 819| r0_113(glval) = VariableAddress[pb] : +# 819| r0_114(Base *) = Load : &:r0_113, ~mu0_2 +# 819| r0_115(Middle *) = ConvertToDerived[Middle : Base] : r0_114 +# 819| r0_116(glval) = VariableAddress[pm] : +# 819| mu0_117(Middle *) = Store : &:r0_116, r0_115 +# 820| r0_118(glval) = VariableAddress[pb] : +# 820| r0_119(Base *) = Load : &:r0_118, ~mu0_2 +# 820| r0_120(Middle *) = Convert : r0_119 +# 820| r0_121(glval) = VariableAddress[pm] : +# 820| mu0_122(Middle *) = Store : &:r0_121, r0_120 +# 822| r0_123(glval) = VariableAddress[b] : +# 822| r0_124(glval) = FunctionAddress[operator=] : +# 822| r0_125(glval) = VariableAddress[d] : +# 822| r0_126(glval) = ConvertToBase[Derived : Middle] : r0_125 +# 822| r0_127(glval) = ConvertToBase[Middle : Base] : r0_126 +# 822| r0_128(Base &) = Call : func:r0_124, this:r0_123, 0:r0_127 +# 822| mu0_129(unknown) = ^CallSideEffect : ~mu0_2 +# 822| v0_130(void) = ^IndirectReadSideEffect : &:r0_123, ~mu0_2 +# 822| v0_131(void) = ^IndirectReadSideEffect[p#0] : &:r0_127, ~mu0_2 +# 822| r0_132(Base) = ^IndirectMayWriteSideEffect : &:r0_123, ~mu0_2 +# 822| mu0_133(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_127, ~mu0_2 +# 823| r0_134(glval) = VariableAddress[b] : +# 823| r0_135(glval) = FunctionAddress[operator=] : +# 823| r0_136(glval) = FunctionAddress[Base] : +# 823| r0_137(glval) = VariableAddress[d] : +# 823| r0_138(glval) = ConvertToBase[Derived : Middle] : r0_137 +# 823| r0_139(glval) = ConvertToBase[Middle : Base] : r0_138 +# 823| v0_140(void) = Call : func:r0_136, 0:r0_139 +# 823| mu0_141(unknown) = ^CallSideEffect : ~mu0_2 +# 823| v0_142(void) = ^IndirectReadSideEffect[p#0] : &:r0_139, ~mu0_2 +# 823| mu0_143(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_139, ~mu0_2 +# 823| r0_144(glval) = Convert : v0_140 +# 823| r0_145(Base &) = Call : func:r0_135, this:r0_134, 0:r0_144 +# 823| mu0_146(unknown) = ^CallSideEffect : ~mu0_2 +# 823| v0_147(void) = ^IndirectReadSideEffect : &:r0_134, ~mu0_2 +# 823| v0_148(void) = ^IndirectReadSideEffect[p#0] : &:r0_144, ~mu0_2 +# 823| r0_149(Base) = ^IndirectMayWriteSideEffect : &:r0_134, ~mu0_2 +# 823| mu0_150(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_144, ~mu0_2 +# 824| r0_151(glval) = VariableAddress[b] : +# 824| r0_152(glval) = FunctionAddress[operator=] : +# 824| r0_153(glval) = FunctionAddress[Base] : +# 824| r0_154(glval) = VariableAddress[d] : +# 824| r0_155(glval) = ConvertToBase[Derived : Middle] : r0_154 +# 824| r0_156(glval) = ConvertToBase[Middle : Base] : r0_155 +# 824| v0_157(void) = Call : func:r0_153, 0:r0_156 +# 824| mu0_158(unknown) = ^CallSideEffect : ~mu0_2 +# 824| v0_159(void) = ^IndirectReadSideEffect[p#0] : &:r0_156, ~mu0_2 +# 824| mu0_160(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_156, ~mu0_2 +# 824| r0_161(glval) = Convert : v0_157 +# 824| r0_162(Base &) = Call : func:r0_152, this:r0_151, 0:r0_161 +# 824| mu0_163(unknown) = ^CallSideEffect : ~mu0_2 +# 824| v0_164(void) = ^IndirectReadSideEffect : &:r0_151, ~mu0_2 +# 824| v0_165(void) = ^IndirectReadSideEffect[p#0] : &:r0_161, ~mu0_2 +# 824| r0_166(Base) = ^IndirectMayWriteSideEffect : &:r0_151, ~mu0_2 +# 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_161, ~mu0_2 +# 825| r0_168(glval) = VariableAddress[pd] : +# 825| r0_169(Derived *) = Load : &:r0_168, ~mu0_2 +# 825| r0_170(Middle *) = ConvertToBase[Derived : Middle] : r0_169 +# 825| r0_171(Base *) = ConvertToBase[Middle : Base] : r0_170 +# 825| r0_172(glval) = VariableAddress[pb] : +# 825| mu0_173(Base *) = Store : &:r0_172, r0_171 +# 826| r0_174(glval) = VariableAddress[pd] : +# 826| r0_175(Derived *) = Load : &:r0_174, ~mu0_2 +# 826| r0_176(Middle *) = ConvertToBase[Derived : Middle] : r0_175 +# 826| r0_177(Base *) = ConvertToBase[Middle : Base] : r0_176 +# 826| r0_178(glval) = VariableAddress[pb] : +# 826| mu0_179(Base *) = Store : &:r0_178, r0_177 +# 827| r0_180(glval) = VariableAddress[pd] : +# 827| r0_181(Derived *) = Load : &:r0_180, ~mu0_2 +# 827| r0_182(Middle *) = ConvertToBase[Derived : Middle] : r0_181 +# 827| r0_183(Base *) = ConvertToBase[Middle : Base] : r0_182 +# 827| r0_184(glval) = VariableAddress[pb] : +# 827| mu0_185(Base *) = Store : &:r0_184, r0_183 +# 828| r0_186(glval) = VariableAddress[pd] : +# 828| r0_187(Derived *) = Load : &:r0_186, ~mu0_2 +# 828| r0_188(Base *) = Convert : r0_187 +# 828| r0_189(glval) = VariableAddress[pb] : +# 828| mu0_190(Base *) = Store : &:r0_189, r0_188 +# 830| r0_191(glval) = VariableAddress[d] : +# 830| r0_192(glval) = FunctionAddress[operator=] : +# 830| r0_193(glval) = VariableAddress[b] : +# 830| r0_194(glval) = ConvertToDerived[Middle : Base] : r0_193 +# 830| r0_195(glval) = ConvertToDerived[Derived : Middle] : r0_194 +# 830| r0_196(glval) = Convert : r0_195 +# 830| r0_197(Derived &) = Call : func:r0_192, this:r0_191, 0:r0_196 +# 830| mu0_198(unknown) = ^CallSideEffect : ~mu0_2 +# 830| v0_199(void) = ^IndirectReadSideEffect : &:r0_191, ~mu0_2 +# 830| v0_200(void) = ^IndirectReadSideEffect[p#0] : &:r0_196, ~mu0_2 +# 830| r0_201(Derived) = ^IndirectMayWriteSideEffect : &:r0_191, ~mu0_2 +# 830| mu0_202(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_196, ~mu0_2 +# 831| r0_203(glval) = VariableAddress[d] : +# 831| r0_204(glval) = FunctionAddress[operator=] : +# 831| r0_205(glval) = VariableAddress[b] : +# 831| r0_206(glval) = ConvertToDerived[Middle : Base] : r0_205 +# 831| r0_207(glval) = ConvertToDerived[Derived : Middle] : r0_206 +# 831| r0_208(glval) = Convert : r0_207 +# 831| r0_209(Derived &) = Call : func:r0_204, this:r0_203, 0:r0_208 +# 831| mu0_210(unknown) = ^CallSideEffect : ~mu0_2 +# 831| v0_211(void) = ^IndirectReadSideEffect : &:r0_203, ~mu0_2 +# 831| v0_212(void) = ^IndirectReadSideEffect[p#0] : &:r0_208, ~mu0_2 +# 831| r0_213(Derived) = ^IndirectMayWriteSideEffect : &:r0_203, ~mu0_2 +# 831| mu0_214(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_208, ~mu0_2 +# 832| r0_215(glval) = VariableAddress[pb] : +# 832| r0_216(Base *) = Load : &:r0_215, ~mu0_2 +# 832| r0_217(Middle *) = ConvertToDerived[Middle : Base] : r0_216 +# 832| r0_218(Derived *) = ConvertToDerived[Derived : Middle] : r0_217 +# 832| r0_219(glval) = VariableAddress[pd] : +# 832| mu0_220(Derived *) = Store : &:r0_219, r0_218 +# 833| r0_221(glval) = VariableAddress[pb] : +# 833| r0_222(Base *) = Load : &:r0_221, ~mu0_2 +# 833| r0_223(Middle *) = ConvertToDerived[Middle : Base] : r0_222 +# 833| r0_224(Derived *) = ConvertToDerived[Derived : Middle] : r0_223 +# 833| r0_225(glval) = VariableAddress[pd] : +# 833| mu0_226(Derived *) = Store : &:r0_225, r0_224 +# 834| r0_227(glval) = VariableAddress[pb] : +# 834| r0_228(Base *) = Load : &:r0_227, ~mu0_2 +# 834| r0_229(Derived *) = Convert : r0_228 +# 834| r0_230(glval) = VariableAddress[pd] : +# 834| mu0_231(Derived *) = Store : &:r0_230, r0_229 +# 836| r0_232(glval) = VariableAddress[pmv] : +# 836| r0_233(MiddleVB1 *) = Constant[0] : +# 836| mu0_234(MiddleVB1 *) = Store : &:r0_232, r0_233 +# 837| r0_235(glval) = VariableAddress[pdv] : +# 837| r0_236(DerivedVB *) = Constant[0] : +# 837| mu0_237(DerivedVB *) = Store : &:r0_235, r0_236 +# 838| r0_238(glval) = VariableAddress[pmv] : +# 838| r0_239(MiddleVB1 *) = Load : &:r0_238, ~mu0_2 +# 838| r0_240(Base *) = ConvertToVirtualBase[MiddleVB1 : Base] : r0_239 +# 838| r0_241(glval) = VariableAddress[pb] : +# 838| mu0_242(Base *) = Store : &:r0_241, r0_240 +# 839| r0_243(glval) = VariableAddress[pdv] : +# 839| r0_244(DerivedVB *) = Load : &:r0_243, ~mu0_2 +# 839| r0_245(Base *) = ConvertToVirtualBase[DerivedVB : Base] : r0_244 +# 839| r0_246(glval) = VariableAddress[pb] : +# 839| mu0_247(Base *) = Store : &:r0_246, r0_245 +# 840| v0_248(void) = NoOp : +# 799| v0_249(void) = ReturnVoid : +# 799| v0_250(void) = UnmodeledUse : mu* +# 799| v0_251(void) = ExitFunction : # 842| void PolymorphicBase::PolymorphicBase() # 842| Block 0 @@ -3865,19 +3963,21 @@ ir.cpp: # 867| void String::String() # 867| Block 0 -# 867| v0_0(void) = EnterFunction : -# 867| mu0_1(unknown) = AliasedDefinition : -# 867| mu0_2(unknown) = UnmodeledDefinition : -# 867| r0_3(glval) = InitializeThis : -# 868| r0_4(glval) = FunctionAddress[String] : -# 868| r0_5(glval) = StringConstant[""] : -# 868| r0_6(char *) = Convert : r0_5 -# 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 -# 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 869| v0_9(void) = NoOp : -# 867| v0_10(void) = ReturnVoid : -# 867| v0_11(void) = UnmodeledUse : mu* -# 867| v0_12(void) = ExitFunction : +# 867| v0_0(void) = EnterFunction : +# 867| mu0_1(unknown) = AliasedDefinition : +# 867| mu0_2(unknown) = UnmodeledDefinition : +# 867| r0_3(glval) = InitializeThis : +# 868| r0_4(glval) = FunctionAddress[String] : +# 868| r0_5(glval) = StringConstant[""] : +# 868| r0_6(char *) = Convert : r0_5 +# 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 +# 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 +# 868| v0_9(void) = ^IndirectReadSideEffect[p#0] : &:r0_6, ~mu0_2 +# 868| mu0_10(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_6, ~mu0_2 +# 869| v0_11(void) = NoOp : +# 867| v0_12(void) = ReturnVoid : +# 867| v0_13(void) = UnmodeledUse : mu* +# 867| v0_14(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 @@ -4049,65 +4149,67 @@ ir.cpp: # 940| void OperatorNew() # 940| Block 0 -# 940| v0_0(void) = EnterFunction : -# 940| mu0_1(unknown) = AliasedDefinition : -# 940| mu0_2(unknown) = UnmodeledDefinition : -# 941| r0_3(glval) = FunctionAddress[operator new] : -# 941| r0_4(unsigned long) = Constant[4] : -# 941| r0_5(void *) = Call : func:r0_3, 0:r0_4 -# 941| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 941| r0_7(int *) = Convert : r0_5 -# 942| r0_8(glval) = FunctionAddress[operator new] : -# 942| r0_9(unsigned long) = Constant[4] : -# 942| r0_10(float) = Constant[1.0] : -# 942| r0_11(void *) = Call : func:r0_8, 0:r0_9, 1:r0_10 -# 942| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 942| r0_13(int *) = Convert : r0_11 -# 943| r0_14(glval) = FunctionAddress[operator new] : -# 943| r0_15(unsigned long) = Constant[4] : -# 943| r0_16(void *) = Call : func:r0_14, 0:r0_15 -# 943| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 -# 943| r0_18(int *) = Convert : r0_16 -# 943| r0_19(int) = Constant[0] : -# 943| mu0_20(int) = Store : &:r0_18, r0_19 -# 944| r0_21(glval) = FunctionAddress[operator new] : -# 944| r0_22(unsigned long) = Constant[8] : -# 944| r0_23(void *) = Call : func:r0_21, 0:r0_22 -# 944| mu0_24(unknown) = ^CallSideEffect : ~mu0_2 -# 944| r0_25(String *) = Convert : r0_23 -# 944| r0_26(glval) = FunctionAddress[String] : -# 944| v0_27(void) = Call : func:r0_26, this:r0_25 -# 944| mu0_28(unknown) = ^CallSideEffect : ~mu0_2 -# 945| r0_29(glval) = FunctionAddress[operator new] : -# 945| r0_30(unsigned long) = Constant[8] : -# 945| r0_31(float) = Constant[1.0] : -# 945| r0_32(void *) = Call : func:r0_29, 0:r0_30, 1:r0_31 -# 945| mu0_33(unknown) = ^CallSideEffect : ~mu0_2 -# 945| r0_34(String *) = Convert : r0_32 -# 945| r0_35(glval) = FunctionAddress[String] : -# 945| r0_36(glval) = StringConstant["hello"] : -# 945| r0_37(char *) = Convert : r0_36 -# 945| v0_38(void) = Call : func:r0_35, this:r0_34, 0:r0_37 -# 945| mu0_39(unknown) = ^CallSideEffect : ~mu0_2 -# 946| r0_40(glval) = FunctionAddress[operator new] : -# 946| r0_41(unsigned long) = Constant[256] : -# 946| r0_42(align_val_t) = Constant[128] : -# 946| r0_43(void *) = Call : func:r0_40, 0:r0_41, 1:r0_42 -# 946| mu0_44(unknown) = ^CallSideEffect : ~mu0_2 -# 946| r0_45(Overaligned *) = Convert : r0_43 -# 947| r0_46(glval) = FunctionAddress[operator new] : -# 947| r0_47(unsigned long) = Constant[256] : -# 947| r0_48(align_val_t) = Constant[128] : -# 947| r0_49(float) = Constant[1.0] : -# 947| r0_50(void *) = Call : func:r0_46, 0:r0_47, 1:r0_48, 2:r0_49 -# 947| mu0_51(unknown) = ^CallSideEffect : ~mu0_2 -# 947| r0_52(Overaligned *) = Convert : r0_50 -# 947| r0_53(Overaligned) = Constant[0] : -# 947| mu0_54(Overaligned) = Store : &:r0_52, r0_53 -# 948| v0_55(void) = NoOp : -# 940| v0_56(void) = ReturnVoid : -# 940| v0_57(void) = UnmodeledUse : mu* -# 940| v0_58(void) = ExitFunction : +# 940| v0_0(void) = EnterFunction : +# 940| mu0_1(unknown) = AliasedDefinition : +# 940| mu0_2(unknown) = UnmodeledDefinition : +# 941| r0_3(glval) = FunctionAddress[operator new] : +# 941| r0_4(unsigned long) = Constant[4] : +# 941| r0_5(void *) = Call : func:r0_3, 0:r0_4 +# 941| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 +# 941| r0_7(int *) = Convert : r0_5 +# 942| r0_8(glval) = FunctionAddress[operator new] : +# 942| r0_9(unsigned long) = Constant[4] : +# 942| r0_10(float) = Constant[1.0] : +# 942| r0_11(void *) = Call : func:r0_8, 0:r0_9, 1:r0_10 +# 942| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 942| r0_13(int *) = Convert : r0_11 +# 943| r0_14(glval) = FunctionAddress[operator new] : +# 943| r0_15(unsigned long) = Constant[4] : +# 943| r0_16(void *) = Call : func:r0_14, 0:r0_15 +# 943| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 +# 943| r0_18(int *) = Convert : r0_16 +# 943| r0_19(int) = Constant[0] : +# 943| mu0_20(int) = Store : &:r0_18, r0_19 +# 944| r0_21(glval) = FunctionAddress[operator new] : +# 944| r0_22(unsigned long) = Constant[8] : +# 944| r0_23(void *) = Call : func:r0_21, 0:r0_22 +# 944| mu0_24(unknown) = ^CallSideEffect : ~mu0_2 +# 944| r0_25(String *) = Convert : r0_23 +# 944| r0_26(glval) = FunctionAddress[String] : +# 944| v0_27(void) = Call : func:r0_26, this:r0_25 +# 944| mu0_28(unknown) = ^CallSideEffect : ~mu0_2 +# 945| r0_29(glval) = FunctionAddress[operator new] : +# 945| r0_30(unsigned long) = Constant[8] : +# 945| r0_31(float) = Constant[1.0] : +# 945| r0_32(void *) = Call : func:r0_29, 0:r0_30, 1:r0_31 +# 945| mu0_33(unknown) = ^CallSideEffect : ~mu0_2 +# 945| r0_34(String *) = Convert : r0_32 +# 945| r0_35(glval) = FunctionAddress[String] : +# 945| r0_36(glval) = StringConstant["hello"] : +# 945| r0_37(char *) = Convert : r0_36 +# 945| v0_38(void) = Call : func:r0_35, this:r0_34, 0:r0_37 +# 945| mu0_39(unknown) = ^CallSideEffect : ~mu0_2 +# 945| v0_40(void) = ^IndirectReadSideEffect[p#0] : &:r0_37, ~mu0_2 +# 945| mu0_41(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_37, ~mu0_2 +# 946| r0_42(glval) = FunctionAddress[operator new] : +# 946| r0_43(unsigned long) = Constant[256] : +# 946| r0_44(align_val_t) = Constant[128] : +# 946| r0_45(void *) = Call : func:r0_42, 0:r0_43, 1:r0_44 +# 946| mu0_46(unknown) = ^CallSideEffect : ~mu0_2 +# 946| r0_47(Overaligned *) = Convert : r0_45 +# 947| r0_48(glval) = FunctionAddress[operator new] : +# 947| r0_49(unsigned long) = Constant[256] : +# 947| r0_50(align_val_t) = Constant[128] : +# 947| r0_51(float) = Constant[1.0] : +# 947| r0_52(void *) = Call : func:r0_48, 0:r0_49, 1:r0_50, 2:r0_51 +# 947| mu0_53(unknown) = ^CallSideEffect : ~mu0_2 +# 947| r0_54(Overaligned *) = Convert : r0_52 +# 947| r0_55(Overaligned) = Constant[0] : +# 947| mu0_56(Overaligned) = Store : &:r0_54, r0_55 +# 948| v0_57(void) = NoOp : +# 940| v0_58(void) = ReturnVoid : +# 940| v0_59(void) = UnmodeledUse : mu* +# 940| v0_60(void) = ExitFunction : # 950| void OperatorNewArray(int) # 950| Block 0 @@ -4575,116 +4677,132 @@ ir.cpp: # 1035| r0_28(float) = Constant[1.0] : # 1035| r0_29(char) = Call : func:r0_27, this:r0_26, 0:r0_28 # 1035| mu0_30(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| r0_31(glval) = VariableAddress[lambda_val] : -# 1036| r0_32(glval) = FunctionAddress[(constructor)] : -# 1036| r0_33(glval) = VariableAddress[#temp1036:21] : -# 1036| mu0_34(decltype([...](...){...})) = Uninitialized[#temp1036:21] : &:r0_33 -# 1036| r0_35(glval) = FieldAddress[s] : r0_33 -#-----| r0_36(glval) = FunctionAddress[String] : -#-----| v0_37(void) = Call : func:r0_36, this:r0_35 -#-----| mu0_38(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| r0_39(glval) = FieldAddress[x] : r0_33 -#-----| r0_40(glval) = VariableAddress[x] : -#-----| r0_41(int) = Load : &:r0_40, ~mu0_2 -#-----| mu0_42(int) = Store : &:r0_39, r0_41 -# 1036| r0_43(decltype([...](...){...})) = Load : &:r0_33, ~mu0_2 -# 1036| v0_44(void) = Call : func:r0_32, this:r0_31, 0:r0_43 -# 1036| mu0_45(unknown) = ^CallSideEffect : ~mu0_2 -# 1037| r0_46(glval) = VariableAddress[lambda_val] : -# 1037| r0_47(glval) = Convert : r0_46 -# 1037| r0_48(glval) = FunctionAddress[operator()] : -# 1037| r0_49(float) = Constant[2.0] : -# 1037| r0_50(char) = Call : func:r0_48, this:r0_47, 0:r0_49 -# 1037| mu0_51(unknown) = ^CallSideEffect : ~mu0_2 -# 1038| r0_52(glval) = VariableAddress[lambda_ref_explicit] : -# 1038| r0_53(glval) = VariableAddress[#temp1038:30] : -# 1038| mu0_54(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_53 -# 1038| r0_55(glval) = FieldAddress[s] : r0_53 -# 1038| r0_56(glval) = VariableAddress[s] : -# 1038| r0_57(String &) = Load : &:r0_56, ~mu0_2 -# 1038| mu0_58(String &) = Store : &:r0_55, r0_57 -# 1038| r0_59(decltype([...](...){...})) = Load : &:r0_53, ~mu0_2 -# 1038| mu0_60(decltype([...](...){...})) = Store : &:r0_52, r0_59 -# 1039| r0_61(glval) = VariableAddress[lambda_ref_explicit] : -# 1039| r0_62(glval) = Convert : r0_61 -# 1039| r0_63(glval) = FunctionAddress[operator()] : -# 1039| r0_64(float) = Constant[3.0] : -# 1039| r0_65(char) = Call : func:r0_63, this:r0_62, 0:r0_64 -# 1039| mu0_66(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| r0_67(glval) = VariableAddress[lambda_val_explicit] : -# 1040| r0_68(glval) = FunctionAddress[(constructor)] : -# 1040| r0_69(glval) = VariableAddress[#temp1040:30] : -# 1040| mu0_70(decltype([...](...){...})) = Uninitialized[#temp1040:30] : &:r0_69 -# 1040| r0_71(glval) = FieldAddress[s] : r0_69 -#-----| r0_72(glval) = FunctionAddress[String] : -#-----| v0_73(void) = Call : func:r0_72, this:r0_71 -#-----| mu0_74(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| r0_75(decltype([...](...){...})) = Load : &:r0_69, ~mu0_2 -# 1040| v0_76(void) = Call : func:r0_68, this:r0_67, 0:r0_75 -# 1040| mu0_77(unknown) = ^CallSideEffect : ~mu0_2 -# 1041| r0_78(glval) = VariableAddress[lambda_val_explicit] : -# 1041| r0_79(glval) = Convert : r0_78 -# 1041| r0_80(glval) = FunctionAddress[operator()] : -# 1041| r0_81(float) = Constant[4.0] : -# 1041| r0_82(char) = Call : func:r0_80, this:r0_79, 0:r0_81 -# 1041| mu0_83(unknown) = ^CallSideEffect : ~mu0_2 -# 1042| r0_84(glval) = VariableAddress[lambda_mixed_explicit] : -# 1042| r0_85(glval) = VariableAddress[#temp1042:32] : -# 1042| mu0_86(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_85 -# 1042| r0_87(glval) = FieldAddress[s] : r0_85 -# 1042| r0_88(glval) = VariableAddress[s] : -# 1042| r0_89(String &) = Load : &:r0_88, ~mu0_2 -# 1042| mu0_90(String &) = Store : &:r0_87, r0_89 -# 1042| r0_91(glval) = FieldAddress[x] : r0_85 -# 1042| r0_92(glval) = VariableAddress[x] : -# 1042| r0_93(int) = Load : &:r0_92, ~mu0_2 -# 1042| mu0_94(int) = Store : &:r0_91, r0_93 -# 1042| r0_95(decltype([...](...){...})) = Load : &:r0_85, ~mu0_2 -# 1042| mu0_96(decltype([...](...){...})) = Store : &:r0_84, r0_95 -# 1043| r0_97(glval) = VariableAddress[lambda_mixed_explicit] : -# 1043| r0_98(glval) = Convert : r0_97 -# 1043| r0_99(glval) = FunctionAddress[operator()] : -# 1043| r0_100(float) = Constant[5.0] : -# 1043| r0_101(char) = Call : func:r0_99, this:r0_98, 0:r0_100 -# 1043| mu0_102(unknown) = ^CallSideEffect : ~mu0_2 -# 1044| r0_103(glval) = VariableAddress[r] : -# 1044| r0_104(glval) = VariableAddress[x] : -# 1044| r0_105(int) = Load : &:r0_104, ~mu0_2 -# 1044| r0_106(int) = Constant[1] : -# 1044| r0_107(int) = Sub : r0_105, r0_106 -# 1044| mu0_108(int) = Store : &:r0_103, r0_107 -# 1045| r0_109(glval) = VariableAddress[lambda_inits] : -# 1045| r0_110(glval) = VariableAddress[#temp1045:23] : -# 1045| mu0_111(decltype([...](...){...})) = Uninitialized[#temp1045:23] : &:r0_110 -# 1045| r0_112(glval) = FieldAddress[s] : r0_110 -# 1045| r0_113(glval) = VariableAddress[s] : -# 1045| r0_114(String &) = Load : &:r0_113, ~mu0_2 -# 1045| mu0_115(String &) = Store : &:r0_112, r0_114 -# 1045| r0_116(glval) = FieldAddress[x] : r0_110 -# 1045| r0_117(glval) = VariableAddress[x] : -# 1045| r0_118(int) = Load : &:r0_117, ~mu0_2 -# 1045| mu0_119(int) = Store : &:r0_116, r0_118 -# 1045| r0_120(glval) = FieldAddress[i] : r0_110 -# 1045| r0_121(glval) = VariableAddress[x] : -# 1045| r0_122(int) = Load : &:r0_121, ~mu0_2 -# 1045| r0_123(int) = Constant[1] : -# 1045| r0_124(int) = Add : r0_122, r0_123 -# 1045| mu0_125(int) = Store : &:r0_120, r0_124 -# 1045| r0_126(glval) = FieldAddress[j] : r0_110 -# 1045| r0_127(glval) = VariableAddress[r] : -# 1045| mu0_128(int &) = Store : &:r0_126, r0_127 -# 1045| r0_129(decltype([...](...){...})) = Load : &:r0_110, ~mu0_2 -# 1045| mu0_130(decltype([...](...){...})) = Store : &:r0_109, r0_129 -# 1046| r0_131(glval) = VariableAddress[lambda_inits] : -# 1046| r0_132(glval) = Convert : r0_131 -# 1046| r0_133(glval) = FunctionAddress[operator()] : -# 1046| r0_134(float) = Constant[6.0] : -# 1046| r0_135(char) = Call : func:r0_133, this:r0_132, 0:r0_134 -# 1046| mu0_136(unknown) = ^CallSideEffect : ~mu0_2 -# 1047| v0_137(void) = NoOp : -# 1031| v0_138(void) = ReturnVoid : -# 1031| v0_139(void) = UnmodeledUse : mu* -# 1031| v0_140(void) = ExitFunction : +# 1035| v0_31(void) = ^IndirectReadSideEffect : &:r0_26, ~mu0_2 +# 1035| r0_32(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_26, ~mu0_2 +# 1036| r0_33(glval) = VariableAddress[lambda_val] : +# 1036| r0_34(glval) = FunctionAddress[(constructor)] : +# 1036| r0_35(glval) = VariableAddress[#temp1036:21] : +# 1036| mu0_36(decltype([...](...){...})) = Uninitialized[#temp1036:21] : &:r0_35 +# 1036| r0_37(glval) = FieldAddress[s] : r0_35 +#-----| r0_38(glval) = FunctionAddress[String] : +#-----| v0_39(void) = Call : func:r0_38, this:r0_37 +#-----| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 +# 1036| r0_41(glval) = FieldAddress[x] : r0_35 +#-----| r0_42(glval) = VariableAddress[x] : +#-----| r0_43(int) = Load : &:r0_42, ~mu0_2 +#-----| mu0_44(int) = Store : &:r0_41, r0_43 +# 1036| r0_45(decltype([...](...){...})) = Load : &:r0_35, ~mu0_2 +# 1036| v0_46(void) = Call : func:r0_34, this:r0_33, 0:r0_45 +# 1036| mu0_47(unknown) = ^CallSideEffect : ~mu0_2 +# 1036| v0_48(void) = ^IndirectReadSideEffect[p#0] : &:r0_45, ~mu0_2 +# 1036| mu0_49(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_45, ~mu0_2 +# 1037| r0_50(glval) = VariableAddress[lambda_val] : +# 1037| r0_51(glval) = Convert : r0_50 +# 1037| r0_52(glval) = FunctionAddress[operator()] : +# 1037| r0_53(float) = Constant[2.0] : +# 1037| r0_54(char) = Call : func:r0_52, this:r0_51, 0:r0_53 +# 1037| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 +# 1037| v0_56(void) = ^IndirectReadSideEffect : &:r0_51, ~mu0_2 +# 1037| r0_57(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_51, ~mu0_2 +# 1038| r0_58(glval) = VariableAddress[lambda_ref_explicit] : +# 1038| r0_59(glval) = VariableAddress[#temp1038:30] : +# 1038| mu0_60(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_59 +# 1038| r0_61(glval) = FieldAddress[s] : r0_59 +# 1038| r0_62(glval) = VariableAddress[s] : +# 1038| r0_63(String &) = Load : &:r0_62, ~mu0_2 +# 1038| mu0_64(String &) = Store : &:r0_61, r0_63 +# 1038| r0_65(decltype([...](...){...})) = Load : &:r0_59, ~mu0_2 +# 1038| mu0_66(decltype([...](...){...})) = Store : &:r0_58, r0_65 +# 1039| r0_67(glval) = VariableAddress[lambda_ref_explicit] : +# 1039| r0_68(glval) = Convert : r0_67 +# 1039| r0_69(glval) = FunctionAddress[operator()] : +# 1039| r0_70(float) = Constant[3.0] : +# 1039| r0_71(char) = Call : func:r0_69, this:r0_68, 0:r0_70 +# 1039| mu0_72(unknown) = ^CallSideEffect : ~mu0_2 +# 1039| v0_73(void) = ^IndirectReadSideEffect : &:r0_68, ~mu0_2 +# 1039| r0_74(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_68, ~mu0_2 +# 1040| r0_75(glval) = VariableAddress[lambda_val_explicit] : +# 1040| r0_76(glval) = FunctionAddress[(constructor)] : +# 1040| r0_77(glval) = VariableAddress[#temp1040:30] : +# 1040| mu0_78(decltype([...](...){...})) = Uninitialized[#temp1040:30] : &:r0_77 +# 1040| r0_79(glval) = FieldAddress[s] : r0_77 +#-----| r0_80(glval) = FunctionAddress[String] : +#-----| v0_81(void) = Call : func:r0_80, this:r0_79 +#-----| mu0_82(unknown) = ^CallSideEffect : ~mu0_2 +# 1040| r0_83(decltype([...](...){...})) = Load : &:r0_77, ~mu0_2 +# 1040| v0_84(void) = Call : func:r0_76, this:r0_75, 0:r0_83 +# 1040| mu0_85(unknown) = ^CallSideEffect : ~mu0_2 +# 1040| v0_86(void) = ^IndirectReadSideEffect[p#0] : &:r0_83, ~mu0_2 +# 1040| mu0_87(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_83, ~mu0_2 +# 1041| r0_88(glval) = VariableAddress[lambda_val_explicit] : +# 1041| r0_89(glval) = Convert : r0_88 +# 1041| r0_90(glval) = FunctionAddress[operator()] : +# 1041| r0_91(float) = Constant[4.0] : +# 1041| r0_92(char) = Call : func:r0_90, this:r0_89, 0:r0_91 +# 1041| mu0_93(unknown) = ^CallSideEffect : ~mu0_2 +# 1041| v0_94(void) = ^IndirectReadSideEffect : &:r0_89, ~mu0_2 +# 1041| r0_95(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_89, ~mu0_2 +# 1042| r0_96(glval) = VariableAddress[lambda_mixed_explicit] : +# 1042| r0_97(glval) = VariableAddress[#temp1042:32] : +# 1042| mu0_98(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_97 +# 1042| r0_99(glval) = FieldAddress[s] : r0_97 +# 1042| r0_100(glval) = VariableAddress[s] : +# 1042| r0_101(String &) = Load : &:r0_100, ~mu0_2 +# 1042| mu0_102(String &) = Store : &:r0_99, r0_101 +# 1042| r0_103(glval) = FieldAddress[x] : r0_97 +# 1042| r0_104(glval) = VariableAddress[x] : +# 1042| r0_105(int) = Load : &:r0_104, ~mu0_2 +# 1042| mu0_106(int) = Store : &:r0_103, r0_105 +# 1042| r0_107(decltype([...](...){...})) = Load : &:r0_97, ~mu0_2 +# 1042| mu0_108(decltype([...](...){...})) = Store : &:r0_96, r0_107 +# 1043| r0_109(glval) = VariableAddress[lambda_mixed_explicit] : +# 1043| r0_110(glval) = Convert : r0_109 +# 1043| r0_111(glval) = FunctionAddress[operator()] : +# 1043| r0_112(float) = Constant[5.0] : +# 1043| r0_113(char) = Call : func:r0_111, this:r0_110, 0:r0_112 +# 1043| mu0_114(unknown) = ^CallSideEffect : ~mu0_2 +# 1043| v0_115(void) = ^IndirectReadSideEffect : &:r0_110, ~mu0_2 +# 1043| r0_116(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_110, ~mu0_2 +# 1044| r0_117(glval) = VariableAddress[r] : +# 1044| r0_118(glval) = VariableAddress[x] : +# 1044| r0_119(int) = Load : &:r0_118, ~mu0_2 +# 1044| r0_120(int) = Constant[1] : +# 1044| r0_121(int) = Sub : r0_119, r0_120 +# 1044| mu0_122(int) = Store : &:r0_117, r0_121 +# 1045| r0_123(glval) = VariableAddress[lambda_inits] : +# 1045| r0_124(glval) = VariableAddress[#temp1045:23] : +# 1045| mu0_125(decltype([...](...){...})) = Uninitialized[#temp1045:23] : &:r0_124 +# 1045| r0_126(glval) = FieldAddress[s] : r0_124 +# 1045| r0_127(glval) = VariableAddress[s] : +# 1045| r0_128(String &) = Load : &:r0_127, ~mu0_2 +# 1045| mu0_129(String &) = Store : &:r0_126, r0_128 +# 1045| r0_130(glval) = FieldAddress[x] : r0_124 +# 1045| r0_131(glval) = VariableAddress[x] : +# 1045| r0_132(int) = Load : &:r0_131, ~mu0_2 +# 1045| mu0_133(int) = Store : &:r0_130, r0_132 +# 1045| r0_134(glval) = FieldAddress[i] : r0_124 +# 1045| r0_135(glval) = VariableAddress[x] : +# 1045| r0_136(int) = Load : &:r0_135, ~mu0_2 +# 1045| r0_137(int) = Constant[1] : +# 1045| r0_138(int) = Add : r0_136, r0_137 +# 1045| mu0_139(int) = Store : &:r0_134, r0_138 +# 1045| r0_140(glval) = FieldAddress[j] : r0_124 +# 1045| r0_141(glval) = VariableAddress[r] : +# 1045| mu0_142(int &) = Store : &:r0_140, r0_141 +# 1045| r0_143(decltype([...](...){...})) = Load : &:r0_124, ~mu0_2 +# 1045| mu0_144(decltype([...](...){...})) = Store : &:r0_123, r0_143 +# 1046| r0_145(glval) = VariableAddress[lambda_inits] : +# 1046| r0_146(glval) = Convert : r0_145 +# 1046| r0_147(glval) = FunctionAddress[operator()] : +# 1046| r0_148(float) = Constant[6.0] : +# 1046| r0_149(char) = Call : func:r0_147, this:r0_146, 0:r0_148 +# 1046| mu0_150(unknown) = ^CallSideEffect : ~mu0_2 +# 1046| v0_151(void) = ^IndirectReadSideEffect : &:r0_146, ~mu0_2 +# 1046| r0_152(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_146, ~mu0_2 +# 1047| v0_153(void) = NoOp : +# 1031| v0_154(void) = ReturnVoid : +# 1031| v0_155(void) = UnmodeledUse : mu* +# 1031| v0_156(void) = ExitFunction : # 1032| void (void Lambda(int, String const&))::(lambda [] type at line 1032, col. 23)::(constructor)((void Lambda(int, String const&))::(lambda [] type at line 1032, col. 23)&&) # 1032| Block 0 @@ -4731,30 +4849,32 @@ ir.cpp: # 1034| char (void Lambda(int, String const&))::(lambda [] type at line 1034, col. 21)::operator()(float) const # 1034| Block 0 -# 1034| v0_0(void) = EnterFunction : -# 1034| mu0_1(unknown) = AliasedDefinition : -# 1034| mu0_2(unknown) = UnmodeledDefinition : -# 1034| r0_3(glval) = InitializeThis : -# 1034| r0_4(glval) = VariableAddress[f] : -# 1034| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1034| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1034| r0_10(glval) = FunctionAddress[c_str] : -# 1034| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1034| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_13(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 -#-----| r0_14(glval) = FieldAddress[x] : r0_13 -#-----| r0_15(int &) = Load : &:r0_14, ~mu0_2 -# 1034| r0_16(int) = Load : &:r0_15, ~mu0_2 -# 1034| r0_17(glval) = PointerAdd[1] : r0_11, r0_16 -# 1034| r0_18(char) = Load : &:r0_17, ~mu0_2 -# 1034| mu0_19(char) = Store : &:r0_6, r0_18 -# 1034| r0_20(glval) = VariableAddress[#return] : -# 1034| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 -# 1034| v0_22(void) = UnmodeledUse : mu* -# 1034| v0_23(void) = ExitFunction : +# 1034| v0_0(void) = EnterFunction : +# 1034| mu0_1(unknown) = AliasedDefinition : +# 1034| mu0_2(unknown) = UnmodeledDefinition : +# 1034| r0_3(glval) = InitializeThis : +# 1034| r0_4(glval) = VariableAddress[f] : +# 1034| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1034| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 +# 1034| r0_10(glval) = FunctionAddress[c_str] : +# 1034| r0_11(char *) = Call : func:r0_10, this:r0_9 +# 1034| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 1034| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 +# 1034| r0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 +#-----| r0_15(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 +#-----| r0_16(glval) = FieldAddress[x] : r0_15 +#-----| r0_17(int &) = Load : &:r0_16, ~mu0_2 +# 1034| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 1034| r0_19(glval) = PointerAdd[1] : r0_11, r0_18 +# 1034| r0_20(char) = Load : &:r0_19, ~mu0_2 +# 1034| mu0_21(char) = Store : &:r0_6, r0_20 +# 1034| r0_22(glval) = VariableAddress[#return] : +# 1034| v0_23(void) = ReturnValue : &:r0_22, ~mu0_2 +# 1034| v0_24(void) = UnmodeledUse : mu* +# 1034| v0_25(void) = ExitFunction : # 1036| void (void Lambda(int, String const&))::(lambda [] type at line 1036, col. 21)::~() # 1036| Block 0 @@ -4773,52 +4893,56 @@ ir.cpp: # 1036| char (void Lambda(int, String const&))::(lambda [] type at line 1036, col. 21)::operator()(float) const # 1036| Block 0 -# 1036| v0_0(void) = EnterFunction : -# 1036| mu0_1(unknown) = AliasedDefinition : -# 1036| mu0_2(unknown) = UnmodeledDefinition : -# 1036| r0_3(glval) = InitializeThis : -# 1036| r0_4(glval) = VariableAddress[f] : -# 1036| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1036| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -# 1036| r0_9(glval) = FunctionAddress[c_str] : -# 1036| r0_10(char *) = Call : func:r0_9, this:r0_8 -# 1036| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_12(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 -#-----| r0_13(glval) = FieldAddress[x] : r0_12 -#-----| r0_14(int) = Load : &:r0_13, ~mu0_2 -# 1036| r0_15(glval) = PointerAdd[1] : r0_10, r0_14 -# 1036| r0_16(char) = Load : &:r0_15, ~mu0_2 -# 1036| mu0_17(char) = Store : &:r0_6, r0_16 -# 1036| r0_18(glval) = VariableAddress[#return] : -# 1036| v0_19(void) = ReturnValue : &:r0_18, ~mu0_2 -# 1036| v0_20(void) = UnmodeledUse : mu* -# 1036| v0_21(void) = ExitFunction : +# 1036| v0_0(void) = EnterFunction : +# 1036| mu0_1(unknown) = AliasedDefinition : +# 1036| mu0_2(unknown) = UnmodeledDefinition : +# 1036| r0_3(glval) = InitializeThis : +# 1036| r0_4(glval) = VariableAddress[f] : +# 1036| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1036| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +# 1036| r0_9(glval) = FunctionAddress[c_str] : +# 1036| r0_10(char *) = Call : func:r0_9, this:r0_8 +# 1036| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_12(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 +#-----| r0_13(String) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 +#-----| r0_14(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 +#-----| r0_15(glval) = FieldAddress[x] : r0_14 +#-----| r0_16(int) = Load : &:r0_15, ~mu0_2 +# 1036| r0_17(glval) = PointerAdd[1] : r0_10, r0_16 +# 1036| r0_18(char) = Load : &:r0_17, ~mu0_2 +# 1036| mu0_19(char) = Store : &:r0_6, r0_18 +# 1036| r0_20(glval) = VariableAddress[#return] : +# 1036| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 +# 1036| v0_22(void) = UnmodeledUse : mu* +# 1036| v0_23(void) = ExitFunction : # 1038| char (void Lambda(int, String const&))::(lambda [] type at line 1038, col. 30)::operator()(float) const # 1038| Block 0 -# 1038| v0_0(void) = EnterFunction : -# 1038| mu0_1(unknown) = AliasedDefinition : -# 1038| mu0_2(unknown) = UnmodeledDefinition : -# 1038| r0_3(glval) = InitializeThis : -# 1038| r0_4(glval) = VariableAddress[f] : -# 1038| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1038| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1038, col. 30 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1038| r0_10(glval) = FunctionAddress[c_str] : -# 1038| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1038| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 1038| r0_13(int) = Constant[0] : -# 1038| r0_14(glval) = PointerAdd[1] : r0_11, r0_13 -# 1038| r0_15(char) = Load : &:r0_14, ~mu0_2 -# 1038| mu0_16(char) = Store : &:r0_6, r0_15 -# 1038| r0_17(glval) = VariableAddress[#return] : -# 1038| v0_18(void) = ReturnValue : &:r0_17, ~mu0_2 -# 1038| v0_19(void) = UnmodeledUse : mu* -# 1038| v0_20(void) = ExitFunction : +# 1038| v0_0(void) = EnterFunction : +# 1038| mu0_1(unknown) = AliasedDefinition : +# 1038| mu0_2(unknown) = UnmodeledDefinition : +# 1038| r0_3(glval) = InitializeThis : +# 1038| r0_4(glval) = VariableAddress[f] : +# 1038| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1038| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1038, col. 30 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 +# 1038| r0_10(glval) = FunctionAddress[c_str] : +# 1038| r0_11(char *) = Call : func:r0_10, this:r0_9 +# 1038| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 1038| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 +# 1038| r0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 +# 1038| r0_15(int) = Constant[0] : +# 1038| r0_16(glval) = PointerAdd[1] : r0_11, r0_15 +# 1038| r0_17(char) = Load : &:r0_16, ~mu0_2 +# 1038| mu0_18(char) = Store : &:r0_6, r0_17 +# 1038| r0_19(glval) = VariableAddress[#return] : +# 1038| v0_20(void) = ReturnValue : &:r0_19, ~mu0_2 +# 1038| v0_21(void) = UnmodeledUse : mu* +# 1038| v0_22(void) = ExitFunction : # 1040| void (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::(constructor)((void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)&&) # 1040| Block 0 @@ -4854,224 +4978,250 @@ ir.cpp: # 1040| char (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::operator()(float) const # 1040| Block 0 -# 1040| v0_0(void) = EnterFunction : -# 1040| mu0_1(unknown) = AliasedDefinition : -# 1040| mu0_2(unknown) = UnmodeledDefinition : -# 1040| r0_3(glval) = InitializeThis : -# 1040| r0_4(glval) = VariableAddress[f] : -# 1040| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1040| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1040, col. 30 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -# 1040| r0_9(glval) = FunctionAddress[c_str] : -# 1040| r0_10(char *) = Call : func:r0_9, this:r0_8 -# 1040| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| r0_12(int) = Constant[0] : -# 1040| r0_13(glval) = PointerAdd[1] : r0_10, r0_12 -# 1040| r0_14(char) = Load : &:r0_13, ~mu0_2 -# 1040| mu0_15(char) = Store : &:r0_6, r0_14 -# 1040| r0_16(glval) = VariableAddress[#return] : -# 1040| v0_17(void) = ReturnValue : &:r0_16, ~mu0_2 -# 1040| v0_18(void) = UnmodeledUse : mu* -# 1040| v0_19(void) = ExitFunction : +# 1040| v0_0(void) = EnterFunction : +# 1040| mu0_1(unknown) = AliasedDefinition : +# 1040| mu0_2(unknown) = UnmodeledDefinition : +# 1040| r0_3(glval) = InitializeThis : +# 1040| r0_4(glval) = VariableAddress[f] : +# 1040| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1040| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1040, col. 30 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +# 1040| r0_9(glval) = FunctionAddress[c_str] : +# 1040| r0_10(char *) = Call : func:r0_9, this:r0_8 +# 1040| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_12(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 +#-----| r0_13(String) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 +# 1040| r0_14(int) = Constant[0] : +# 1040| r0_15(glval) = PointerAdd[1] : r0_10, r0_14 +# 1040| r0_16(char) = Load : &:r0_15, ~mu0_2 +# 1040| mu0_17(char) = Store : &:r0_6, r0_16 +# 1040| r0_18(glval) = VariableAddress[#return] : +# 1040| v0_19(void) = ReturnValue : &:r0_18, ~mu0_2 +# 1040| v0_20(void) = UnmodeledUse : mu* +# 1040| v0_21(void) = ExitFunction : # 1042| char (void Lambda(int, String const&))::(lambda [] type at line 1042, col. 32)::operator()(float) const # 1042| Block 0 -# 1042| v0_0(void) = EnterFunction : -# 1042| mu0_1(unknown) = AliasedDefinition : -# 1042| mu0_2(unknown) = UnmodeledDefinition : -# 1042| r0_3(glval) = InitializeThis : -# 1042| r0_4(glval) = VariableAddress[f] : -# 1042| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1042| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1042| r0_10(glval) = FunctionAddress[c_str] : -# 1042| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1042| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_13(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 -#-----| r0_14(glval) = FieldAddress[x] : r0_13 -#-----| r0_15(int) = Load : &:r0_14, ~mu0_2 -# 1042| r0_16(glval) = PointerAdd[1] : r0_11, r0_15 -# 1042| r0_17(char) = Load : &:r0_16, ~mu0_2 -# 1042| mu0_18(char) = Store : &:r0_6, r0_17 -# 1042| r0_19(glval) = VariableAddress[#return] : -# 1042| v0_20(void) = ReturnValue : &:r0_19, ~mu0_2 -# 1042| v0_21(void) = UnmodeledUse : mu* -# 1042| v0_22(void) = ExitFunction : +# 1042| v0_0(void) = EnterFunction : +# 1042| mu0_1(unknown) = AliasedDefinition : +# 1042| mu0_2(unknown) = UnmodeledDefinition : +# 1042| r0_3(glval) = InitializeThis : +# 1042| r0_4(glval) = VariableAddress[f] : +# 1042| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1042| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 +# 1042| r0_10(glval) = FunctionAddress[c_str] : +# 1042| r0_11(char *) = Call : func:r0_10, this:r0_9 +# 1042| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 1042| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 +# 1042| r0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 +#-----| r0_15(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 +#-----| r0_16(glval) = FieldAddress[x] : r0_15 +#-----| r0_17(int) = Load : &:r0_16, ~mu0_2 +# 1042| r0_18(glval) = PointerAdd[1] : r0_11, r0_17 +# 1042| r0_19(char) = Load : &:r0_18, ~mu0_2 +# 1042| mu0_20(char) = Store : &:r0_6, r0_19 +# 1042| r0_21(glval) = VariableAddress[#return] : +# 1042| v0_22(void) = ReturnValue : &:r0_21, ~mu0_2 +# 1042| v0_23(void) = UnmodeledUse : mu* +# 1042| v0_24(void) = ExitFunction : # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 23)::operator()(float) const # 1045| Block 0 -# 1045| v0_0(void) = EnterFunction : -# 1045| mu0_1(unknown) = AliasedDefinition : -# 1045| mu0_2(unknown) = UnmodeledDefinition : -# 1045| r0_3(glval) = InitializeThis : -# 1045| r0_4(glval) = VariableAddress[f] : -# 1045| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1045| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1045| r0_10(glval) = FunctionAddress[c_str] : -# 1045| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1045| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -#-----| r0_13(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -#-----| r0_14(glval) = FieldAddress[x] : r0_13 -#-----| r0_15(int) = Load : &:r0_14, ~mu0_2 -#-----| r0_16(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -# 1045| r0_17(glval) = FieldAddress[i] : r0_16 -# 1045| r0_18(int) = Load : &:r0_17, ~mu0_2 -# 1045| r0_19(int) = Add : r0_15, r0_18 -#-----| r0_20(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -# 1045| r0_21(glval) = FieldAddress[j] : r0_20 -# 1045| r0_22(int &) = Load : &:r0_21, ~mu0_2 -# 1045| r0_23(int) = Load : &:r0_22, ~mu0_2 -# 1045| r0_24(int) = Sub : r0_19, r0_23 -# 1045| r0_25(glval) = PointerAdd[1] : r0_11, r0_24 -# 1045| r0_26(char) = Load : &:r0_25, ~mu0_2 -# 1045| mu0_27(char) = Store : &:r0_6, r0_26 -# 1045| r0_28(glval) = VariableAddress[#return] : -# 1045| v0_29(void) = ReturnValue : &:r0_28, ~mu0_2 -# 1045| v0_30(void) = UnmodeledUse : mu* -# 1045| v0_31(void) = ExitFunction : +# 1045| v0_0(void) = EnterFunction : +# 1045| mu0_1(unknown) = AliasedDefinition : +# 1045| mu0_2(unknown) = UnmodeledDefinition : +# 1045| r0_3(glval) = InitializeThis : +# 1045| r0_4(glval) = VariableAddress[f] : +# 1045| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1045| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 +# 1045| r0_10(glval) = FunctionAddress[c_str] : +# 1045| r0_11(char *) = Call : func:r0_10, this:r0_9 +# 1045| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 1045| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 +# 1045| r0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 +#-----| r0_15(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +#-----| r0_16(glval) = FieldAddress[x] : r0_15 +#-----| r0_17(int) = Load : &:r0_16, ~mu0_2 +#-----| r0_18(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +# 1045| r0_19(glval) = FieldAddress[i] : r0_18 +# 1045| r0_20(int) = Load : &:r0_19, ~mu0_2 +# 1045| r0_21(int) = Add : r0_17, r0_20 +#-----| r0_22(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +# 1045| r0_23(glval) = FieldAddress[j] : r0_22 +# 1045| r0_24(int &) = Load : &:r0_23, ~mu0_2 +# 1045| r0_25(int) = Load : &:r0_24, ~mu0_2 +# 1045| r0_26(int) = Sub : r0_21, r0_25 +# 1045| r0_27(glval) = PointerAdd[1] : r0_11, r0_26 +# 1045| r0_28(char) = Load : &:r0_27, ~mu0_2 +# 1045| mu0_29(char) = Store : &:r0_6, r0_28 +# 1045| r0_30(glval) = VariableAddress[#return] : +# 1045| v0_31(void) = ReturnValue : &:r0_30, ~mu0_2 +# 1045| v0_32(void) = UnmodeledUse : mu* +# 1045| v0_33(void) = ExitFunction : # 1068| void RangeBasedFor(vector const&) # 1068| Block 0 -# 1068| v0_0(void) = EnterFunction : -# 1068| mu0_1(unknown) = AliasedDefinition : -# 1068| mu0_2(unknown) = UnmodeledDefinition : -# 1068| r0_3(glval &>) = VariableAddress[v] : -# 1068| mu0_4(vector &) = InitializeParameter[v] : &:r0_3 -# 1069| r0_5(glval &>) = VariableAddress[(__range)] : -# 1069| r0_6(glval &>) = VariableAddress[v] : -# 1069| r0_7(vector &) = Load : &:r0_6, ~mu0_2 -# 1069| mu0_8(vector &) = Store : &:r0_5, r0_7 -# 1069| r0_9(glval) = VariableAddress[(__begin)] : -#-----| r0_10(glval &>) = VariableAddress[(__range)] : -#-----| r0_11(vector &) = Load : &:r0_10, ~mu0_2 -# 1069| r0_12(glval) = FunctionAddress[begin] : -# 1069| r0_13(iterator) = Call : func:r0_12, this:r0_11 -# 1069| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 -# 1069| mu0_15(iterator) = Store : &:r0_9, r0_13 -# 1069| r0_16(glval) = VariableAddress[(__end)] : -#-----| r0_17(glval &>) = VariableAddress[(__range)] : -#-----| r0_18(vector &) = Load : &:r0_17, ~mu0_2 -# 1069| r0_19(glval) = FunctionAddress[end] : -# 1069| r0_20(iterator) = Call : func:r0_19, this:r0_18 -# 1069| mu0_21(unknown) = ^CallSideEffect : ~mu0_2 -# 1069| mu0_22(iterator) = Store : &:r0_16, r0_20 -#-----| Goto -> Block 1 - -#-----| Block 1 -#-----| r1_0(glval) = VariableAddress[(__begin)] : -#-----| r1_1(glval) = Convert : r1_0 -# 1069| r1_2(glval) = FunctionAddress[operator!=] : -#-----| r1_3(glval) = VariableAddress[(__end)] : -#-----| r1_4(iterator) = Load : &:r1_3, ~mu0_2 -# 1069| r1_5(bool) = Call : func:r1_2, this:r1_1, 0:r1_4 -# 1069| mu1_6(unknown) = ^CallSideEffect : ~mu0_2 -# 1069| v1_7(void) = ConditionalBranch : r1_5 -#-----| False -> Block 5 -#-----| True -> Block 2 - -# 1069| Block 2 -# 1069| r2_0(glval) = VariableAddress[e] : -#-----| r2_1(glval) = VariableAddress[(__begin)] : -#-----| r2_2(glval) = Convert : r2_1 -# 1069| r2_3(glval) = FunctionAddress[operator*] : -# 1069| r2_4(int &) = Call : func:r2_3, this:r2_2 -# 1069| mu2_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1069| r2_6(int) = Load : &:r2_4, ~mu0_2 -# 1069| mu2_7(int) = Store : &:r2_0, r2_6 -# 1070| r2_8(glval) = VariableAddress[e] : -# 1070| r2_9(int) = Load : &:r2_8, ~mu0_2 -# 1070| r2_10(int) = Constant[0] : -# 1070| r2_11(bool) = CompareGT : r2_9, r2_10 -# 1070| v2_12(void) = ConditionalBranch : r2_11 -#-----| False -> Block 4 -#-----| True -> Block 3 - -# 1071| Block 3 -# 1071| v3_0(void) = NoOp : +# 1068| v0_0(void) = EnterFunction : +# 1068| mu0_1(unknown) = AliasedDefinition : +# 1068| mu0_2(unknown) = UnmodeledDefinition : +# 1068| r0_3(glval &>) = VariableAddress[v] : +# 1068| mu0_4(vector &) = InitializeParameter[v] : &:r0_3 +# 1069| r0_5(glval &>) = VariableAddress[(__range)] : +# 1069| r0_6(glval &>) = VariableAddress[v] : +# 1069| r0_7(vector &) = Load : &:r0_6, ~mu0_2 +# 1069| mu0_8(vector &) = Store : &:r0_5, r0_7 +# 1069| r0_9(glval) = VariableAddress[(__begin)] : +#-----| r0_10(glval &>) = VariableAddress[(__range)] : +#-----| r0_11(vector &) = Load : &:r0_10, ~mu0_2 +# 1069| r0_12(glval) = FunctionAddress[begin] : +# 1069| r0_13(iterator) = Call : func:r0_12, this:r0_11 +# 1069| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 +#-----| r0_16(vector) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 +# 1069| mu0_17(iterator) = Store : &:r0_9, r0_13 +# 1069| r0_18(glval) = VariableAddress[(__end)] : +#-----| r0_19(glval &>) = VariableAddress[(__range)] : +#-----| r0_20(vector &) = Load : &:r0_19, ~mu0_2 +# 1069| r0_21(glval) = FunctionAddress[end] : +# 1069| r0_22(iterator) = Call : func:r0_21, this:r0_20 +# 1069| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_24(void) = ^IndirectReadSideEffect : &:r0_20, ~mu0_2 +#-----| r0_25(vector) = ^IndirectMayWriteSideEffect : &:r0_20, ~mu0_2 +# 1069| mu0_26(iterator) = Store : &:r0_18, r0_22 #-----| Goto -> Block 4 -# 1069| Block 4 -# 1069| v4_0(void) = NoOp : -#-----| r4_1(glval) = VariableAddress[(__begin)] : -# 1069| r4_2(glval) = FunctionAddress[operator++] : -# 1069| r4_3(iterator &) = Call : func:r4_2, this:r4_1 -# 1069| mu4_4(unknown) = ^CallSideEffect : ~mu0_2 -#-----| Goto (back edge) -> Block 1 - -# 1075| Block 5 -# 1075| r5_0(glval &>) = VariableAddress[(__range)] : -# 1075| r5_1(glval &>) = VariableAddress[v] : -# 1075| r5_2(vector &) = Load : &:r5_1, ~mu0_2 -# 1075| mu5_3(vector &) = Store : &:r5_0, r5_2 -# 1075| r5_4(glval) = VariableAddress[(__begin)] : -#-----| r5_5(glval &>) = VariableAddress[(__range)] : -#-----| r5_6(vector &) = Load : &:r5_5, ~mu0_2 -# 1075| r5_7(glval) = FunctionAddress[begin] : -# 1075| r5_8(iterator) = Call : func:r5_7, this:r5_6 -# 1075| mu5_9(unknown) = ^CallSideEffect : ~mu0_2 -# 1075| mu5_10(iterator) = Store : &:r5_4, r5_8 -# 1075| r5_11(glval) = VariableAddress[(__end)] : -#-----| r5_12(glval &>) = VariableAddress[(__range)] : -#-----| r5_13(vector &) = Load : &:r5_12, ~mu0_2 -# 1075| r5_14(glval) = FunctionAddress[end] : -# 1075| r5_15(iterator) = Call : func:r5_14, this:r5_13 -# 1075| mu5_16(unknown) = ^CallSideEffect : ~mu0_2 -# 1075| mu5_17(iterator) = Store : &:r5_11, r5_15 -#-----| Goto -> Block 6 - -#-----| Block 6 -#-----| r6_0(glval) = VariableAddress[(__begin)] : -#-----| r6_1(glval) = Convert : r6_0 -# 1075| r6_2(glval) = FunctionAddress[operator!=] : -#-----| r6_3(glval) = VariableAddress[(__end)] : -#-----| r6_4(iterator) = Load : &:r6_3, ~mu0_2 -# 1075| r6_5(bool) = Call : func:r6_2, this:r6_1, 0:r6_4 -# 1075| mu6_6(unknown) = ^CallSideEffect : ~mu0_2 -# 1075| v6_7(void) = ConditionalBranch : r6_5 +# 1075| Block 1 +# 1075| r1_0(glval) = VariableAddress[e] : +#-----| r1_1(glval) = VariableAddress[(__begin)] : +#-----| r1_2(glval) = Convert : r1_1 +# 1075| r1_3(glval) = FunctionAddress[operator*] : +# 1075| r1_4(int &) = Call : func:r1_3, this:r1_2 +# 1075| mu1_5(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v1_6(void) = ^IndirectReadSideEffect : &:r1_2, ~mu0_2 +#-----| r1_7(iterator) = ^IndirectMayWriteSideEffect : &:r1_2, ~mu0_2 +# 1075| r1_8(glval) = Convert : r1_4 +# 1075| mu1_9(int &) = Store : &:r1_0, r1_8 +# 1076| r1_10(glval) = VariableAddress[e] : +# 1076| r1_11(int &) = Load : &:r1_10, ~mu0_2 +# 1076| r1_12(int) = Load : &:r1_11, ~mu0_2 +# 1076| r1_13(int) = Constant[5] : +# 1076| r1_14(bool) = CompareLT : r1_12, r1_13 +# 1076| v1_15(void) = ConditionalBranch : r1_14 #-----| False -> Block 10 -#-----| True -> Block 8 +#-----| True -> Block 2 -#-----| Block 7 -#-----| r7_0(glval) = VariableAddress[(__begin)] : -# 1075| r7_1(glval) = FunctionAddress[operator++] : -# 1075| r7_2(iterator &) = Call : func:r7_1, this:r7_0 -# 1075| mu7_3(unknown) = ^CallSideEffect : ~mu0_2 -#-----| Goto (back edge) -> Block 6 +# 1077| Block 2 +# 1077| v2_0(void) = NoOp : +#-----| Goto -> Block 3 + +# 1079| Block 3 +# 1079| v3_0(void) = NoOp : +# 1080| v3_1(void) = NoOp : +# 1068| v3_2(void) = ReturnVoid : +# 1068| v3_3(void) = UnmodeledUse : mu* +# 1068| v3_4(void) = ExitFunction : + +#-----| Block 4 +#-----| r4_0(glval) = VariableAddress[(__begin)] : +#-----| r4_1(glval) = Convert : r4_0 +# 1069| r4_2(glval) = FunctionAddress[operator!=] : +#-----| r4_3(glval) = VariableAddress[(__end)] : +#-----| r4_4(iterator) = Load : &:r4_3, ~mu0_2 +# 1069| r4_5(bool) = Call : func:r4_2, this:r4_1, 0:r4_4 +# 1069| mu4_6(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v4_7(void) = ^IndirectReadSideEffect : &:r4_1, ~mu0_2 +#-----| r4_8(iterator) = ^IndirectMayWriteSideEffect : &:r4_1, ~mu0_2 +# 1069| v4_9(void) = ConditionalBranch : r4_5 +#-----| False -> Block 8 +#-----| True -> Block 5 + +# 1069| Block 5 +# 1069| r5_0(glval) = VariableAddress[e] : +#-----| r5_1(glval) = VariableAddress[(__begin)] : +#-----| r5_2(glval) = Convert : r5_1 +# 1069| r5_3(glval) = FunctionAddress[operator*] : +# 1069| r5_4(int &) = Call : func:r5_3, this:r5_2 +# 1069| mu5_5(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v5_6(void) = ^IndirectReadSideEffect : &:r5_2, ~mu0_2 +#-----| r5_7(iterator) = ^IndirectMayWriteSideEffect : &:r5_2, ~mu0_2 +# 1069| r5_8(int) = Load : &:r5_4, ~mu0_2 +# 1069| mu5_9(int) = Store : &:r5_0, r5_8 +# 1070| r5_10(glval) = VariableAddress[e] : +# 1070| r5_11(int) = Load : &:r5_10, ~mu0_2 +# 1070| r5_12(int) = Constant[0] : +# 1070| r5_13(bool) = CompareGT : r5_11, r5_12 +# 1070| v5_14(void) = ConditionalBranch : r5_13 +#-----| False -> Block 7 +#-----| True -> Block 6 + +# 1071| Block 6 +# 1071| v6_0(void) = NoOp : +#-----| Goto -> Block 7 + +# 1069| Block 7 +# 1069| v7_0(void) = NoOp : +#-----| r7_1(glval) = VariableAddress[(__begin)] : +# 1069| r7_2(glval) = FunctionAddress[operator++] : +# 1069| r7_3(iterator &) = Call : func:r7_2, this:r7_1 +# 1069| mu7_4(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v7_5(void) = ^IndirectReadSideEffect : &:r7_1, ~mu0_2 +#-----| r7_6(iterator) = ^IndirectMayWriteSideEffect : &:r7_1, ~mu0_2 +#-----| Goto (back edge) -> Block 4 # 1075| Block 8 -# 1075| r8_0(glval) = VariableAddress[e] : -#-----| r8_1(glval) = VariableAddress[(__begin)] : -#-----| r8_2(glval) = Convert : r8_1 -# 1075| r8_3(glval) = FunctionAddress[operator*] : -# 1075| r8_4(int &) = Call : func:r8_3, this:r8_2 -# 1075| mu8_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1075| r8_6(glval) = Convert : r8_4 -# 1075| mu8_7(int &) = Store : &:r8_0, r8_6 -# 1076| r8_8(glval) = VariableAddress[e] : -# 1076| r8_9(int &) = Load : &:r8_8, ~mu0_2 -# 1076| r8_10(int) = Load : &:r8_9, ~mu0_2 -# 1076| r8_11(int) = Constant[5] : -# 1076| r8_12(bool) = CompareLT : r8_10, r8_11 -# 1076| v8_13(void) = ConditionalBranch : r8_12 -#-----| False -> Block 7 -#-----| True -> Block 9 +# 1075| r8_0(glval &>) = VariableAddress[(__range)] : +# 1075| r8_1(glval &>) = VariableAddress[v] : +# 1075| r8_2(vector &) = Load : &:r8_1, ~mu0_2 +# 1075| mu8_3(vector &) = Store : &:r8_0, r8_2 +# 1075| r8_4(glval) = VariableAddress[(__begin)] : +#-----| r8_5(glval &>) = VariableAddress[(__range)] : +#-----| r8_6(vector &) = Load : &:r8_5, ~mu0_2 +# 1075| r8_7(glval) = FunctionAddress[begin] : +# 1075| r8_8(iterator) = Call : func:r8_7, this:r8_6 +# 1075| mu8_9(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v8_10(void) = ^IndirectReadSideEffect : &:r8_6, ~mu0_2 +#-----| r8_11(vector) = ^IndirectMayWriteSideEffect : &:r8_6, ~mu0_2 +# 1075| mu8_12(iterator) = Store : &:r8_4, r8_8 +# 1075| r8_13(glval) = VariableAddress[(__end)] : +#-----| r8_14(glval &>) = VariableAddress[(__range)] : +#-----| r8_15(vector &) = Load : &:r8_14, ~mu0_2 +# 1075| r8_16(glval) = FunctionAddress[end] : +# 1075| r8_17(iterator) = Call : func:r8_16, this:r8_15 +# 1075| mu8_18(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v8_19(void) = ^IndirectReadSideEffect : &:r8_15, ~mu0_2 +#-----| r8_20(vector) = ^IndirectMayWriteSideEffect : &:r8_15, ~mu0_2 +# 1075| mu8_21(iterator) = Store : &:r8_13, r8_17 +#-----| Goto -> Block 9 -# 1077| Block 9 -# 1077| v9_0(void) = NoOp : -#-----| Goto -> Block 10 +#-----| Block 9 +#-----| r9_0(glval) = VariableAddress[(__begin)] : +#-----| r9_1(glval) = Convert : r9_0 +# 1075| r9_2(glval) = FunctionAddress[operator!=] : +#-----| r9_3(glval) = VariableAddress[(__end)] : +#-----| r9_4(iterator) = Load : &:r9_3, ~mu0_2 +# 1075| r9_5(bool) = Call : func:r9_2, this:r9_1, 0:r9_4 +# 1075| mu9_6(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v9_7(void) = ^IndirectReadSideEffect : &:r9_1, ~mu0_2 +#-----| r9_8(iterator) = ^IndirectMayWriteSideEffect : &:r9_1, ~mu0_2 +# 1075| v9_9(void) = ConditionalBranch : r9_5 +#-----| False -> Block 3 +#-----| True -> Block 1 -# 1079| Block 10 -# 1079| v10_0(void) = NoOp : -# 1080| v10_1(void) = NoOp : -# 1068| v10_2(void) = ReturnVoid : -# 1068| v10_3(void) = UnmodeledUse : mu* -# 1068| v10_4(void) = ExitFunction : +#-----| Block 10 +#-----| r10_0(glval) = VariableAddress[(__begin)] : +# 1075| r10_1(glval) = FunctionAddress[operator++] : +# 1075| r10_2(iterator &) = Call : func:r10_1, this:r10_0 +# 1075| mu10_3(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v10_4(void) = ^IndirectReadSideEffect : &:r10_0, ~mu0_2 +#-----| r10_5(iterator) = ^IndirectMayWriteSideEffect : &:r10_0, ~mu0_2 +#-----| Goto (back edge) -> Block 9 # 1099| int AsmStmt(int) # 1099| Block 0 @@ -5228,7 +5378,9 @@ ir.cpp: # 1140| r7_3(char *) = Convert : r7_2 # 1140| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 1140| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1140| v7_6(void) = ThrowValue : &:r7_0, ~mu0_2 +# 1140| v7_6(void) = ^IndirectReadSideEffect[p#0] : &:r7_3, ~mu0_2 +# 1140| mu7_7(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r7_3, ~mu0_2 +# 1140| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 # 1142| Block 8 @@ -5243,15 +5395,17 @@ ir.cpp: #-----| Goto -> Block 10 # 1144| Block 10 -# 1144| r10_0(glval) = VariableAddress[s] : -# 1144| mu10_1(char *) = InitializeParameter[s] : &:r10_0 -# 1145| r10_2(glval) = VariableAddress[#throw1145:5] : -# 1145| r10_3(glval) = FunctionAddress[String] : -# 1145| r10_4(glval) = VariableAddress[s] : -# 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2 -# 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 -# 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 1145| v10_8(void) = ThrowValue : &:r10_2, ~mu0_2 +# 1144| r10_0(glval) = VariableAddress[s] : +# 1144| mu10_1(char *) = InitializeParameter[s] : &:r10_0 +# 1145| r10_2(glval) = VariableAddress[#throw1145:5] : +# 1145| r10_3(glval) = FunctionAddress[String] : +# 1145| r10_4(glval) = VariableAddress[s] : +# 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2 +# 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 +# 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 +# 1145| v10_8(void) = ^IndirectReadSideEffect[p#0] : &:r10_5, ~mu0_2 +# 1145| mu10_9(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r10_5, ~mu0_2 +# 1145| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 # 1147| Block 11 @@ -5332,6 +5486,33 @@ ir.cpp: # 1153| v0_57(void) = UnmodeledUse : mu* # 1153| v0_58(void) = ExitFunction : +# 1163| int ModeledCallTarget(int) +# 1163| Block 0 +# 1163| v0_0(void) = EnterFunction : +# 1163| mu0_1(unknown) = AliasedDefinition : +# 1163| mu0_2(unknown) = UnmodeledDefinition : +# 1163| r0_3(glval) = VariableAddress[x] : +# 1163| mu0_4(int) = InitializeParameter[x] : &:r0_3 +# 1164| r0_5(glval) = VariableAddress[y] : +# 1164| mu0_6(int) = Uninitialized[y] : &:r0_5 +# 1165| r0_7(glval) = FunctionAddress[memcpy] : +# 1165| r0_8(glval) = VariableAddress[y] : +# 1165| r0_9(void *) = Convert : r0_8 +# 1165| r0_10(glval) = VariableAddress[x] : +# 1165| r0_11(void *) = Convert : r0_10 +# 1165| r0_12(int) = Constant[4] : +# 1165| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12 +# 1165| v0_14(void) = ^BufferReadSideEffect[src] : &:r0_11, ~mu0_2 +# 1165| mu0_15(unknown) = ^BufferMustWriteSideEffect[dst] : &:r0_9 +# 1166| r0_16(glval) = VariableAddress[#return] : +# 1166| r0_17(glval) = VariableAddress[y] : +# 1166| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 1166| mu0_19(int) = Store : &:r0_16, r0_18 +# 1163| r0_20(glval) = VariableAddress[#return] : +# 1163| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 +# 1163| v0_22(void) = UnmodeledUse : mu* +# 1163| v0_23(void) = ExitFunction : + perf-regression.cpp: # 6| void Big::Big() # 6| Block 0 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 fe11d99f31f..be108ae5084 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 @@ -311,26 +311,29 @@ ssa.cpp: # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 -# 95| v0_0(void) = EnterFunction : -# 95| m0_1(unknown) = AliasedDefinition : -# 95| mu0_2(unknown) = UnmodeledDefinition : -# 95| r0_3(glval) = VariableAddress[a] : -# 95| m0_4(Point) = InitializeParameter[a] : &:r0_3 -# 95| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 -# 96| r0_6(glval) = VariableAddress[b] : -# 96| r0_7(glval) = VariableAddress[a] : -# 96| r0_8(Point) = Load : &:r0_7, m0_4 -# 96| m0_9(Point) = Store : &:r0_6, r0_8 -# 97| r0_10(glval) = FunctionAddress[Escape] : -# 97| r0_11(glval) = VariableAddress[a] : -# 97| r0_12(void *) = Convert : r0_11 -# 97| v0_13(void) = Call : func:r0_10, 0:r0_12 -# 97| m0_14(unknown) = ^CallSideEffect : ~m0_5 -# 97| m0_15(unknown) = Chi : total:m0_5, partial:m0_14 -# 98| v0_16(void) = NoOp : -# 95| v0_17(void) = ReturnVoid : -# 95| v0_18(void) = UnmodeledUse : mu* -# 95| v0_19(void) = ExitFunction : +# 95| v0_0(void) = EnterFunction : +# 95| m0_1(unknown) = AliasedDefinition : +# 95| mu0_2(unknown) = UnmodeledDefinition : +# 95| r0_3(glval) = VariableAddress[a] : +# 95| m0_4(Point) = InitializeParameter[a] : &:r0_3 +# 95| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 +# 96| r0_6(glval) = VariableAddress[b] : +# 96| r0_7(glval) = VariableAddress[a] : +# 96| r0_8(Point) = Load : &:r0_7, m0_4 +# 96| m0_9(Point) = Store : &:r0_6, r0_8 +# 97| r0_10(glval) = FunctionAddress[Escape] : +# 97| r0_11(glval) = VariableAddress[a] : +# 97| r0_12(void *) = Convert : r0_11 +# 97| v0_13(void) = Call : func:r0_10, 0:r0_12 +# 97| m0_14(unknown) = ^CallSideEffect : ~m0_5 +# 97| m0_15(unknown) = Chi : total:m0_5, partial:m0_14 +# 97| v0_16(void) = ^IndirectReadSideEffect[p] : &:r0_12, ~m0_15 +# 97| m0_17(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_12, ~m0_15 +# 97| m0_18(unknown) = Chi : total:m0_15, partial:m0_17 +# 98| v0_19(void) = NoOp : +# 95| v0_20(void) = ReturnVoid : +# 95| v0_21(void) = UnmodeledUse : mu* +# 95| v0_22(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -356,32 +359,35 @@ ssa.cpp: # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 -# 105| v0_0(void) = EnterFunction : -# 105| m0_1(unknown) = AliasedDefinition : -# 105| mu0_2(unknown) = UnmodeledDefinition : -# 105| r0_3(glval) = VariableAddress[a] : -# 105| m0_4(Point) = InitializeParameter[a] : &:r0_3 -# 105| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 -# 106| r0_6(glval) = VariableAddress[x] : -# 106| r0_7(glval) = VariableAddress[a] : -# 106| r0_8(glval) = FieldAddress[x] : r0_7 -# 106| r0_9(int) = Load : &:r0_8, ~m0_4 -# 106| m0_10(int) = Store : &:r0_6, r0_9 -# 107| r0_11(glval) = VariableAddress[y] : -# 107| r0_12(glval) = VariableAddress[a] : -# 107| r0_13(glval) = FieldAddress[y] : r0_12 -# 107| r0_14(int) = Load : &:r0_13, ~m0_4 -# 107| m0_15(int) = Store : &:r0_11, r0_14 -# 108| r0_16(glval) = FunctionAddress[Escape] : -# 108| r0_17(glval) = VariableAddress[a] : -# 108| r0_18(void *) = Convert : r0_17 -# 108| v0_19(void) = Call : func:r0_16, 0:r0_18 -# 108| m0_20(unknown) = ^CallSideEffect : ~m0_5 -# 108| m0_21(unknown) = Chi : total:m0_5, partial:m0_20 -# 109| v0_22(void) = NoOp : -# 105| v0_23(void) = ReturnVoid : -# 105| v0_24(void) = UnmodeledUse : mu* -# 105| v0_25(void) = ExitFunction : +# 105| v0_0(void) = EnterFunction : +# 105| m0_1(unknown) = AliasedDefinition : +# 105| mu0_2(unknown) = UnmodeledDefinition : +# 105| r0_3(glval) = VariableAddress[a] : +# 105| m0_4(Point) = InitializeParameter[a] : &:r0_3 +# 105| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 +# 106| r0_6(glval) = VariableAddress[x] : +# 106| r0_7(glval) = VariableAddress[a] : +# 106| r0_8(glval) = FieldAddress[x] : r0_7 +# 106| r0_9(int) = Load : &:r0_8, ~m0_4 +# 106| m0_10(int) = Store : &:r0_6, r0_9 +# 107| r0_11(glval) = VariableAddress[y] : +# 107| r0_12(glval) = VariableAddress[a] : +# 107| r0_13(glval) = FieldAddress[y] : r0_12 +# 107| r0_14(int) = Load : &:r0_13, ~m0_4 +# 107| m0_15(int) = Store : &:r0_11, r0_14 +# 108| r0_16(glval) = FunctionAddress[Escape] : +# 108| r0_17(glval) = VariableAddress[a] : +# 108| r0_18(void *) = Convert : r0_17 +# 108| v0_19(void) = Call : func:r0_16, 0:r0_18 +# 108| m0_20(unknown) = ^CallSideEffect : ~m0_5 +# 108| m0_21(unknown) = Chi : total:m0_5, partial:m0_20 +# 108| v0_22(void) = ^IndirectReadSideEffect[p] : &:r0_18, ~m0_21 +# 108| m0_23(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_18, ~m0_21 +# 108| m0_24(unknown) = Chi : total:m0_21, partial:m0_23 +# 109| v0_25(void) = NoOp : +# 105| v0_26(void) = ReturnVoid : +# 105| v0_27(void) = UnmodeledUse : mu* +# 105| v0_28(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -415,40 +421,43 @@ ssa.cpp: # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 -# 116| v0_0(void) = EnterFunction : -# 116| m0_1(unknown) = AliasedDefinition : -# 116| mu0_2(unknown) = UnmodeledDefinition : -# 116| r0_3(glval) = VariableAddress[x] : -# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 -# 116| r0_5(glval) = VariableAddress[y] : -# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 -# 117| r0_7(glval) = VariableAddress[a] : -# 117| m0_8(Point) = Uninitialized[a] : &:r0_7 -# 117| m0_9(unknown) = Chi : total:m0_1, partial:m0_8 -# 117| r0_10(glval) = FieldAddress[x] : r0_7 -# 117| r0_11(glval) = VariableAddress[x] : -# 117| r0_12(int) = Load : &:r0_11, m0_4 -# 117| m0_13(int) = Store : &:r0_10, r0_12 -# 117| m0_14(unknown) = Chi : total:m0_9, partial:m0_13 -# 117| r0_15(glval) = FieldAddress[y] : r0_7 -# 117| r0_16(glval) = VariableAddress[y] : -# 117| r0_17(int) = Load : &:r0_16, m0_6 -# 117| m0_18(int) = Store : &:r0_15, r0_17 -# 117| m0_19(unknown) = Chi : total:m0_14, partial:m0_18 -# 118| r0_20(glval) = VariableAddress[b] : -# 118| r0_21(glval) = VariableAddress[a] : -# 118| r0_22(Point) = Load : &:r0_21, ~m0_19 -# 118| m0_23(Point) = Store : &:r0_20, r0_22 -# 119| r0_24(glval) = FunctionAddress[Escape] : -# 119| r0_25(glval) = VariableAddress[a] : -# 119| r0_26(void *) = Convert : r0_25 -# 119| v0_27(void) = Call : func:r0_24, 0:r0_26 -# 119| m0_28(unknown) = ^CallSideEffect : ~m0_19 -# 119| m0_29(unknown) = Chi : total:m0_19, partial:m0_28 -# 120| v0_30(void) = NoOp : -# 116| v0_31(void) = ReturnVoid : -# 116| v0_32(void) = UnmodeledUse : mu* -# 116| v0_33(void) = ExitFunction : +# 116| v0_0(void) = EnterFunction : +# 116| m0_1(unknown) = AliasedDefinition : +# 116| mu0_2(unknown) = UnmodeledDefinition : +# 116| r0_3(glval) = VariableAddress[x] : +# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 +# 116| r0_5(glval) = VariableAddress[y] : +# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 +# 117| r0_7(glval) = VariableAddress[a] : +# 117| m0_8(Point) = Uninitialized[a] : &:r0_7 +# 117| m0_9(unknown) = Chi : total:m0_1, partial:m0_8 +# 117| r0_10(glval) = FieldAddress[x] : r0_7 +# 117| r0_11(glval) = VariableAddress[x] : +# 117| r0_12(int) = Load : &:r0_11, m0_4 +# 117| m0_13(int) = Store : &:r0_10, r0_12 +# 117| m0_14(unknown) = Chi : total:m0_9, partial:m0_13 +# 117| r0_15(glval) = FieldAddress[y] : r0_7 +# 117| r0_16(glval) = VariableAddress[y] : +# 117| r0_17(int) = Load : &:r0_16, m0_6 +# 117| m0_18(int) = Store : &:r0_15, r0_17 +# 117| m0_19(unknown) = Chi : total:m0_14, partial:m0_18 +# 118| r0_20(glval) = VariableAddress[b] : +# 118| r0_21(glval) = VariableAddress[a] : +# 118| r0_22(Point) = Load : &:r0_21, ~m0_19 +# 118| m0_23(Point) = Store : &:r0_20, r0_22 +# 119| r0_24(glval) = FunctionAddress[Escape] : +# 119| r0_25(glval) = VariableAddress[a] : +# 119| r0_26(void *) = Convert : r0_25 +# 119| v0_27(void) = Call : func:r0_24, 0:r0_26 +# 119| m0_28(unknown) = ^CallSideEffect : ~m0_19 +# 119| m0_29(unknown) = Chi : total:m0_19, partial:m0_28 +# 119| v0_30(void) = ^IndirectReadSideEffect[p] : &:r0_26, ~m0_29 +# 119| m0_31(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_26, ~m0_29 +# 119| m0_32(unknown) = Chi : total:m0_29, partial:m0_31 +# 120| v0_33(void) = NoOp : +# 116| v0_34(void) = ReturnVoid : +# 116| v0_35(void) = UnmodeledUse : mu* +# 116| v0_36(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -807,3 +816,33 @@ ssa.cpp: # 198| v0_43(void) = ReturnValue : &:r0_42, m0_41 # 198| v0_44(void) = UnmodeledUse : mu* # 198| v0_45(void) = ExitFunction : + +# 207| int ModeledCallTarget(int) +# 207| Block 0 +# 207| v0_0(void) = EnterFunction : +# 207| m0_1(unknown) = AliasedDefinition : +# 207| mu0_2(unknown) = UnmodeledDefinition : +# 207| r0_3(glval) = VariableAddress[x] : +# 207| m0_4(int) = InitializeParameter[x] : &:r0_3 +# 207| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 +# 208| r0_6(glval) = VariableAddress[y] : +# 208| m0_7(int) = Uninitialized[y] : &:r0_6 +# 208| m0_8(unknown) = Chi : total:m0_5, partial:m0_7 +# 209| r0_9(glval) = FunctionAddress[memcpy] : +# 209| r0_10(glval) = VariableAddress[y] : +# 209| r0_11(void *) = Convert : r0_10 +# 209| r0_12(glval) = VariableAddress[x] : +# 209| r0_13(void *) = Convert : r0_12 +# 209| r0_14(int) = Constant[4] : +# 209| r0_15(void *) = Call : func:r0_9, 0:r0_11, 1:r0_13, 2:r0_14 +# 209| v0_16(void) = ^BufferReadSideEffect[src] : &:r0_13, ~m0_4 +# 209| m0_17(unknown) = ^BufferMustWriteSideEffect[dst] : &:r0_11 +# 209| m0_18(unknown) = Chi : total:m0_8, partial:m0_17 +# 210| r0_19(glval) = VariableAddress[#return] : +# 210| r0_20(glval) = VariableAddress[y] : +# 210| r0_21(int) = Load : &:r0_20, ~m0_18 +# 210| m0_22(int) = Store : &:r0_19, r0_21 +# 207| r0_23(glval) = VariableAddress[#return] : +# 207| v0_24(void) = ReturnValue : &:r0_23, m0_22 +# 207| v0_25(void) = UnmodeledUse : mu* +# 207| v0_26(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp index 8ada4a691f9..4dfb0a2f6cd 100644 --- a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp +++ b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp @@ -200,4 +200,13 @@ int PureFunctions(char *str1, char *str2, int x) { ret += strlen(str1); ret += abs(x); return ret; -} \ No newline at end of file +} + +void *memcpy(void *dst, void *src, int size); + +int ModeledCallTarget(int x) { + int y; + memcpy(&y, &x, sizeof(int)); + return y; +} + diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index ce0d9323340..b9ee5be1e01 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -312,24 +312,26 @@ ssa.cpp: # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 -# 95| v0_0(void) = EnterFunction : -# 95| mu0_1(unknown) = AliasedDefinition : -# 95| mu0_2(unknown) = UnmodeledDefinition : -# 95| r0_3(glval) = VariableAddress[a] : -# 95| mu0_4(Point) = InitializeParameter[a] : &:r0_3 -# 96| r0_5(glval) = VariableAddress[b] : -# 96| r0_6(glval) = VariableAddress[a] : -# 96| r0_7(Point) = Load : &:r0_6, ~mu0_2 -# 96| m0_8(Point) = Store : &:r0_5, r0_7 -# 97| r0_9(glval) = FunctionAddress[Escape] : -# 97| r0_10(glval) = VariableAddress[a] : -# 97| r0_11(void *) = Convert : r0_10 -# 97| v0_12(void) = Call : func:r0_9, 0:r0_11 -# 97| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -# 98| v0_14(void) = NoOp : -# 95| v0_15(void) = ReturnVoid : -# 95| v0_16(void) = UnmodeledUse : mu* -# 95| v0_17(void) = ExitFunction : +# 95| v0_0(void) = EnterFunction : +# 95| mu0_1(unknown) = AliasedDefinition : +# 95| mu0_2(unknown) = UnmodeledDefinition : +# 95| r0_3(glval) = VariableAddress[a] : +# 95| mu0_4(Point) = InitializeParameter[a] : &:r0_3 +# 96| r0_5(glval) = VariableAddress[b] : +# 96| r0_6(glval) = VariableAddress[a] : +# 96| r0_7(Point) = Load : &:r0_6, ~mu0_2 +# 96| m0_8(Point) = Store : &:r0_5, r0_7 +# 97| r0_9(glval) = FunctionAddress[Escape] : +# 97| r0_10(glval) = VariableAddress[a] : +# 97| r0_11(void *) = Convert : r0_10 +# 97| v0_12(void) = Call : func:r0_9, 0:r0_11 +# 97| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +# 97| v0_14(void) = ^IndirectReadSideEffect[p] : &:r0_11, ~mu0_2 +# 97| mu0_15(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_11, ~mu0_2 +# 98| v0_16(void) = NoOp : +# 95| v0_17(void) = ReturnVoid : +# 95| v0_18(void) = UnmodeledUse : mu* +# 95| v0_19(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -355,30 +357,32 @@ ssa.cpp: # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 -# 105| v0_0(void) = EnterFunction : -# 105| mu0_1(unknown) = AliasedDefinition : -# 105| mu0_2(unknown) = UnmodeledDefinition : -# 105| r0_3(glval) = VariableAddress[a] : -# 105| mu0_4(Point) = InitializeParameter[a] : &:r0_3 -# 106| r0_5(glval) = VariableAddress[x] : -# 106| r0_6(glval) = VariableAddress[a] : -# 106| r0_7(glval) = FieldAddress[x] : r0_6 -# 106| r0_8(int) = Load : &:r0_7, ~mu0_2 -# 106| m0_9(int) = Store : &:r0_5, r0_8 -# 107| r0_10(glval) = VariableAddress[y] : -# 107| r0_11(glval) = VariableAddress[a] : -# 107| r0_12(glval) = FieldAddress[y] : r0_11 -# 107| r0_13(int) = Load : &:r0_12, ~mu0_2 -# 107| m0_14(int) = Store : &:r0_10, r0_13 -# 108| r0_15(glval) = FunctionAddress[Escape] : -# 108| r0_16(glval) = VariableAddress[a] : -# 108| r0_17(void *) = Convert : r0_16 -# 108| v0_18(void) = Call : func:r0_15, 0:r0_17 -# 108| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 -# 109| v0_20(void) = NoOp : -# 105| v0_21(void) = ReturnVoid : -# 105| v0_22(void) = UnmodeledUse : mu* -# 105| v0_23(void) = ExitFunction : +# 105| v0_0(void) = EnterFunction : +# 105| mu0_1(unknown) = AliasedDefinition : +# 105| mu0_2(unknown) = UnmodeledDefinition : +# 105| r0_3(glval) = VariableAddress[a] : +# 105| mu0_4(Point) = InitializeParameter[a] : &:r0_3 +# 106| r0_5(glval) = VariableAddress[x] : +# 106| r0_6(glval) = VariableAddress[a] : +# 106| r0_7(glval) = FieldAddress[x] : r0_6 +# 106| r0_8(int) = Load : &:r0_7, ~mu0_2 +# 106| m0_9(int) = Store : &:r0_5, r0_8 +# 107| r0_10(glval) = VariableAddress[y] : +# 107| r0_11(glval) = VariableAddress[a] : +# 107| r0_12(glval) = FieldAddress[y] : r0_11 +# 107| r0_13(int) = Load : &:r0_12, ~mu0_2 +# 107| m0_14(int) = Store : &:r0_10, r0_13 +# 108| r0_15(glval) = FunctionAddress[Escape] : +# 108| r0_16(glval) = VariableAddress[a] : +# 108| r0_17(void *) = Convert : r0_16 +# 108| v0_18(void) = Call : func:r0_15, 0:r0_17 +# 108| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 +# 108| v0_20(void) = ^IndirectReadSideEffect[p] : &:r0_17, ~mu0_2 +# 108| mu0_21(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_17, ~mu0_2 +# 109| v0_22(void) = NoOp : +# 105| v0_23(void) = ReturnVoid : +# 105| v0_24(void) = UnmodeledUse : mu* +# 105| v0_25(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -410,36 +414,38 @@ ssa.cpp: # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 -# 116| v0_0(void) = EnterFunction : -# 116| mu0_1(unknown) = AliasedDefinition : -# 116| mu0_2(unknown) = UnmodeledDefinition : -# 116| r0_3(glval) = VariableAddress[x] : -# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 -# 116| r0_5(glval) = VariableAddress[y] : -# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 -# 117| r0_7(glval) = VariableAddress[a] : -# 117| mu0_8(Point) = Uninitialized[a] : &:r0_7 -# 117| r0_9(glval) = FieldAddress[x] : r0_7 -# 117| r0_10(glval) = VariableAddress[x] : -# 117| r0_11(int) = Load : &:r0_10, m0_4 -# 117| mu0_12(int) = Store : &:r0_9, r0_11 -# 117| r0_13(glval) = FieldAddress[y] : r0_7 -# 117| r0_14(glval) = VariableAddress[y] : -# 117| r0_15(int) = Load : &:r0_14, m0_6 -# 117| mu0_16(int) = Store : &:r0_13, r0_15 -# 118| r0_17(glval) = VariableAddress[b] : -# 118| r0_18(glval) = VariableAddress[a] : -# 118| r0_19(Point) = Load : &:r0_18, ~mu0_2 -# 118| m0_20(Point) = Store : &:r0_17, r0_19 -# 119| r0_21(glval) = FunctionAddress[Escape] : -# 119| r0_22(glval) = VariableAddress[a] : -# 119| r0_23(void *) = Convert : r0_22 -# 119| v0_24(void) = Call : func:r0_21, 0:r0_23 -# 119| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 120| v0_26(void) = NoOp : -# 116| v0_27(void) = ReturnVoid : -# 116| v0_28(void) = UnmodeledUse : mu* -# 116| v0_29(void) = ExitFunction : +# 116| v0_0(void) = EnterFunction : +# 116| mu0_1(unknown) = AliasedDefinition : +# 116| mu0_2(unknown) = UnmodeledDefinition : +# 116| r0_3(glval) = VariableAddress[x] : +# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 +# 116| r0_5(glval) = VariableAddress[y] : +# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 +# 117| r0_7(glval) = VariableAddress[a] : +# 117| mu0_8(Point) = Uninitialized[a] : &:r0_7 +# 117| r0_9(glval) = FieldAddress[x] : r0_7 +# 117| r0_10(glval) = VariableAddress[x] : +# 117| r0_11(int) = Load : &:r0_10, m0_4 +# 117| mu0_12(int) = Store : &:r0_9, r0_11 +# 117| r0_13(glval) = FieldAddress[y] : r0_7 +# 117| r0_14(glval) = VariableAddress[y] : +# 117| r0_15(int) = Load : &:r0_14, m0_6 +# 117| mu0_16(int) = Store : &:r0_13, r0_15 +# 118| r0_17(glval) = VariableAddress[b] : +# 118| r0_18(glval) = VariableAddress[a] : +# 118| r0_19(Point) = Load : &:r0_18, ~mu0_2 +# 118| m0_20(Point) = Store : &:r0_17, r0_19 +# 119| r0_21(glval) = FunctionAddress[Escape] : +# 119| r0_22(glval) = VariableAddress[a] : +# 119| r0_23(void *) = Convert : r0_22 +# 119| v0_24(void) = Call : func:r0_21, 0:r0_23 +# 119| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +# 119| v0_26(void) = ^IndirectReadSideEffect[p] : &:r0_23, ~mu0_2 +# 119| mu0_27(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_23, ~mu0_2 +# 120| v0_28(void) = NoOp : +# 116| v0_29(void) = ReturnVoid : +# 116| v0_30(void) = UnmodeledUse : mu* +# 116| v0_31(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -773,3 +779,30 @@ ssa.cpp: # 198| v0_43(void) = ReturnValue : &:r0_42, m0_41 # 198| v0_44(void) = UnmodeledUse : mu* # 198| v0_45(void) = ExitFunction : + +# 207| int ModeledCallTarget(int) +# 207| Block 0 +# 207| v0_0(void) = EnterFunction : +# 207| mu0_1(unknown) = AliasedDefinition : +# 207| mu0_2(unknown) = UnmodeledDefinition : +# 207| r0_3(glval) = VariableAddress[x] : +# 207| mu0_4(int) = InitializeParameter[x] : &:r0_3 +# 208| r0_5(glval) = VariableAddress[y] : +# 208| mu0_6(int) = Uninitialized[y] : &:r0_5 +# 209| r0_7(glval) = FunctionAddress[memcpy] : +# 209| r0_8(glval) = VariableAddress[y] : +# 209| r0_9(void *) = Convert : r0_8 +# 209| r0_10(glval) = VariableAddress[x] : +# 209| r0_11(void *) = Convert : r0_10 +# 209| r0_12(int) = Constant[4] : +# 209| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12 +# 209| v0_14(void) = ^BufferReadSideEffect[src] : &:r0_11, ~mu0_2 +# 209| mu0_15(unknown) = ^BufferMustWriteSideEffect[dst] : &:r0_9 +# 210| r0_16(glval) = VariableAddress[#return] : +# 210| r0_17(glval) = VariableAddress[y] : +# 210| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 210| m0_19(int) = Store : &:r0_16, r0_18 +# 207| r0_20(glval) = VariableAddress[#return] : +# 207| v0_21(void) = ReturnValue : &:r0_20, m0_19 +# 207| v0_22(void) = UnmodeledUse : mu* +# 207| v0_23(void) = ExitFunction : diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll index a16b8eb88a0..dad156c93a7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll @@ -66,10 +66,10 @@ private newtype TOpcode = TCallSideEffect() or TCallReadSideEffect() or TIndirectReadSideEffect() or - TIndirectWriteSideEffect() or + TIndirectMustWriteSideEffect() or TIndirectMayWriteSideEffect() or TBufferReadSideEffect() or - TBufferWriteSideEffect() or + TBufferMustWriteSideEffect() or TBufferMayWriteSideEffect() or TChi() or TInlineAsm() or @@ -135,11 +135,16 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } +/** + * An opcode that definitely writes to a set of memory locations as a side effect. + */ +abstract class MustWriteSideEffectOpcode extends WriteSideEffectOpcode { } + /** * An opcode that may overwrite some, all, or none of an existing set of memory locations. Modeled * as a read of the original contents, plus a "may" write of the new contents. */ -abstract class MayWriteSideEffectOpcode extends SideEffectOpcode { } +abstract class MayWriteSideEffectOpcode extends WriteSideEffectOpcode { } /** * An opcode that accesses a buffer via an `AddressOperand` and a `BufferSizeOperand`. @@ -416,9 +421,9 @@ module Opcode { final override string toString() { result = "IndirectReadSideEffect" } } - class IndirectWriteSideEffect extends WriteSideEffectOpcode, MemoryAccessOpcode, - TIndirectWriteSideEffect { - final override string toString() { result = "IndirectWriteSideEffect" } + class IndirectMustWriteSideEffect extends MustWriteSideEffectOpcode, MemoryAccessOpcode, + TIndirectMustWriteSideEffect { + final override string toString() { result = "IndirectMustWriteSideEffect" } } class IndirectMayWriteSideEffect extends MayWriteSideEffectOpcode, MemoryAccessOpcode, @@ -430,9 +435,9 @@ module Opcode { final override string toString() { result = "BufferReadSideEffect" } } - class BufferWriteSideEffect extends WriteSideEffectOpcode, BufferAccessOpcode, - TBufferWriteSideEffect { - final override string toString() { result = "BufferWriteSideEffect" } + class BufferMustWriteSideEffect extends MustWriteSideEffectOpcode, BufferAccessOpcode, + TBufferMustWriteSideEffect { + final override string toString() { result = "BufferMustWriteSideEffect" } } class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode, @@ -456,3 +461,4 @@ module Opcode { final override string toString() { result = "NewObj" } } } + diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 43f9663d2cd..0f06e47a3ea 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -20,32 +20,23 @@ module InstructionSanity { exists(Opcode opcode | opcode = instr.getOpcode() and ( - opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag - or - opcode instanceof BinaryOpcode and + opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or ( - tag instanceof LeftOperandTag or - tag instanceof RightOperandTag - ) - or - opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag - or - opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand - or - opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag - or - opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag - or - opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag - or - opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag - or - opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag - or - opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag - or - opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag - or + opcode instanceof BinaryOpcode and + ( + tag instanceof LeftOperandTag or + tag instanceof RightOperandTag + ) + ) or + opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or + opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or + opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag or + opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag or + opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or + opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or + opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or + opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or + ( opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or @@ -609,7 +600,9 @@ class VariableInstruction extends Instruction { VariableInstruction() { var = Construction::getInstructionVariable(this) } - final override string getImmediateString() { result = var.toString() } + override string getImmediateString() { + result = var.toString() + } final IRVariable getVariable() { result = var } } @@ -655,9 +648,9 @@ class VariableAddressInstruction extends VariableInstruction { class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } - final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } - - final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } + override final MemoryAccessKind getResultMemoryAccess() { + result instanceof IndirectMemoryAccess + } } /** @@ -1174,21 +1167,48 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends SideEffectInstruction { - IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } + IndirectReadSideEffectInstruction() { + getOpcode() instanceof Opcode::IndirectReadSideEffect + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends SideEffectInstruction { - BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } + BufferReadSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferReadSideEffect + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } +} + +/** + * An instruction representing a side effect of a function call. + */ +class WriteSideEffectInstruction extends SideEffectInstruction { + WriteSideEffectInstruction() { + getOpcode() instanceof WriteSideEffectOpcode + } + + Instruction getArgumentInstruction() { + result = getAnOperand().(AddressOperand).getDef() + } } /** * An instruction representing the write of an indirect parameter within a function call. */ -class IndirectWriteSideEffectInstruction extends SideEffectInstruction { - IndirectWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectWriteSideEffect } +class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + IndirectMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::IndirectMustWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } } @@ -1197,8 +1217,10 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction { * An instruction representing the write of an indirect buffer parameter within a function call. The * entire buffer is overwritten. */ -class BufferWriteSideEffectInstruction extends SideEffectInstruction { - BufferWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferWriteSideEffect } +class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + BufferMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferMustWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } } @@ -1208,7 +1230,7 @@ class BufferWriteSideEffectInstruction extends SideEffectInstruction { * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ -class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { +class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectMayWriteSideEffect } @@ -1222,8 +1244,10 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { * An instruction representing the write of an indirect buffer parameter within a function call. * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ -class BufferMayWriteSideEffectInstruction extends SideEffectInstruction { - BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } +class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { + BufferMayWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferMayWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMayMemoryAccess diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index 1ced8ef3282..2161fe1efa4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -390,10 +390,10 @@ class SideEffectOperand extends TypedOperand { useInstr instanceof BufferReadSideEffectInstruction and result instanceof BufferMemoryAccess or - useInstr instanceof IndirectWriteSideEffectInstruction and + useInstr instanceof IndirectMustWriteSideEffectInstruction and result instanceof IndirectMemoryAccess or - useInstr instanceof BufferWriteSideEffectInstruction and + useInstr instanceof BufferMustWriteSideEffectInstruction and result instanceof BufferMemoryAccess or useInstr instanceof IndirectMayWriteSideEffectInstruction and From 49088e7f0913a18685625a39baf75366c60eb278 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 12 Sep 2019 16:01:19 -0700 Subject: [PATCH 0304/1227] C++: Fix formatting and dropped line --- .../aliased_ssa/Instruction.qll | 79 +++++++++---------- .../cpp/ir/implementation/raw/Instruction.qll | 79 +++++++++---------- .../unaliased_ssa/Instruction.qll | 79 +++++++++---------- .../ir/implementation/raw/Instruction.qll | 79 +++++++++---------- 4 files changed, 144 insertions(+), 172 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 0f06e47a3ea..f3703b3386c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -20,23 +20,32 @@ module InstructionSanity { exists(Opcode opcode | opcode = instr.getOpcode() and ( - opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or + opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag + or + opcode instanceof BinaryOpcode and ( - opcode instanceof BinaryOpcode and - ( - tag instanceof LeftOperandTag or - tag instanceof RightOperandTag - ) - ) or - opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or - opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or - opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag or - opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag or - opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or - opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or - opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or - opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or - + tag instanceof LeftOperandTag or + tag instanceof RightOperandTag + ) + or + opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag + or + opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand + or + opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag + or + opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag + or + opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag + or + opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag + or + opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag + or + opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag + or + opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag + or ( opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or @@ -600,9 +609,7 @@ class VariableInstruction extends Instruction { VariableInstruction() { var = Construction::getInstructionVariable(this) } - override string getImmediateString() { - result = var.toString() - } + override string getImmediateString() { result = var.toString() } final IRVariable getVariable() { result = var } } @@ -648,9 +655,9 @@ class VariableAddressInstruction extends VariableInstruction { class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } - override final MemoryAccessKind getResultMemoryAccess() { - result instanceof IndirectMemoryAccess - } + final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } } /** @@ -1167,39 +1174,27 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends SideEffectInstruction { - IndirectReadSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectReadSideEffect - } + IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends SideEffectInstruction { - BufferReadSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferReadSideEffect - } + BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** * An instruction representing a side effect of a function call. */ class WriteSideEffectInstruction extends SideEffectInstruction { - WriteSideEffectInstruction() { - getOpcode() instanceof WriteSideEffectOpcode - } + WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1245,9 +1240,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferMayWriteSideEffect - } + BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMayMemoryAccess diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 0f06e47a3ea..f3703b3386c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -20,23 +20,32 @@ module InstructionSanity { exists(Opcode opcode | opcode = instr.getOpcode() and ( - opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or + opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag + or + opcode instanceof BinaryOpcode and ( - opcode instanceof BinaryOpcode and - ( - tag instanceof LeftOperandTag or - tag instanceof RightOperandTag - ) - ) or - opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or - opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or - opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag or - opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag or - opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or - opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or - opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or - opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or - + tag instanceof LeftOperandTag or + tag instanceof RightOperandTag + ) + or + opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag + or + opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand + or + opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag + or + opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag + or + opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag + or + opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag + or + opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag + or + opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag + or + opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag + or ( opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or @@ -600,9 +609,7 @@ class VariableInstruction extends Instruction { VariableInstruction() { var = Construction::getInstructionVariable(this) } - override string getImmediateString() { - result = var.toString() - } + override string getImmediateString() { result = var.toString() } final IRVariable getVariable() { result = var } } @@ -648,9 +655,9 @@ class VariableAddressInstruction extends VariableInstruction { class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } - override final MemoryAccessKind getResultMemoryAccess() { - result instanceof IndirectMemoryAccess - } + final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } } /** @@ -1167,39 +1174,27 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends SideEffectInstruction { - IndirectReadSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectReadSideEffect - } + IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends SideEffectInstruction { - BufferReadSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferReadSideEffect - } + BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** * An instruction representing a side effect of a function call. */ class WriteSideEffectInstruction extends SideEffectInstruction { - WriteSideEffectInstruction() { - getOpcode() instanceof WriteSideEffectOpcode - } + WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1245,9 +1240,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferMayWriteSideEffect - } + BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMayMemoryAccess diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 0f06e47a3ea..f3703b3386c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -20,23 +20,32 @@ module InstructionSanity { exists(Opcode opcode | opcode = instr.getOpcode() and ( - opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or + opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag + or + opcode instanceof BinaryOpcode and ( - opcode instanceof BinaryOpcode and - ( - tag instanceof LeftOperandTag or - tag instanceof RightOperandTag - ) - ) or - opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or - opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or - opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag or - opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag or - opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or - opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or - opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or - opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or - + tag instanceof LeftOperandTag or + tag instanceof RightOperandTag + ) + or + opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag + or + opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand + or + opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag + or + opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag + or + opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag + or + opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag + or + opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag + or + opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag + or + opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag + or ( opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or @@ -600,9 +609,7 @@ class VariableInstruction extends Instruction { VariableInstruction() { var = Construction::getInstructionVariable(this) } - override string getImmediateString() { - result = var.toString() - } + override string getImmediateString() { result = var.toString() } final IRVariable getVariable() { result = var } } @@ -648,9 +655,9 @@ class VariableAddressInstruction extends VariableInstruction { class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } - override final MemoryAccessKind getResultMemoryAccess() { - result instanceof IndirectMemoryAccess - } + final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } } /** @@ -1167,39 +1174,27 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends SideEffectInstruction { - IndirectReadSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectReadSideEffect - } + IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends SideEffectInstruction { - BufferReadSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferReadSideEffect - } + BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** * An instruction representing a side effect of a function call. */ class WriteSideEffectInstruction extends SideEffectInstruction { - WriteSideEffectInstruction() { - getOpcode() instanceof WriteSideEffectOpcode - } + WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1245,9 +1240,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferMayWriteSideEffect - } + BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMayMemoryAccess diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 0f06e47a3ea..f3703b3386c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -20,23 +20,32 @@ module InstructionSanity { exists(Opcode opcode | opcode = instr.getOpcode() and ( - opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or + opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag + or + opcode instanceof BinaryOpcode and ( - opcode instanceof BinaryOpcode and - ( - tag instanceof LeftOperandTag or - tag instanceof RightOperandTag - ) - ) or - opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or - opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or - opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag or - opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag or - opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or - opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or - opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or - opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or - + tag instanceof LeftOperandTag or + tag instanceof RightOperandTag + ) + or + opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag + or + opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand + or + opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag + or + opcode instanceof OpcodeWithLoad and tag instanceof LoadOperandTag + or + opcode instanceof Opcode::Store and tag instanceof StoreValueOperandTag + or + opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag + or + opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag + or + opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag + or + opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag + or ( opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or @@ -600,9 +609,7 @@ class VariableInstruction extends Instruction { VariableInstruction() { var = Construction::getInstructionVariable(this) } - override string getImmediateString() { - result = var.toString() - } + override string getImmediateString() { result = var.toString() } final IRVariable getVariable() { result = var } } @@ -648,9 +655,9 @@ class VariableAddressInstruction extends VariableInstruction { class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } - override final MemoryAccessKind getResultMemoryAccess() { - result instanceof IndirectMemoryAccess - } + final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } } /** @@ -1167,39 +1174,27 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { * An instruction representing the read of an indirect parameter within a function call. */ class IndirectReadSideEffectInstruction extends SideEffectInstruction { - IndirectReadSideEffectInstruction() { - getOpcode() instanceof Opcode::IndirectReadSideEffect - } + IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** * An instruction representing the read of an indirect buffer parameter within a function call. */ class BufferReadSideEffectInstruction extends SideEffectInstruction { - BufferReadSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferReadSideEffect - } + BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** * An instruction representing a side effect of a function call. */ class WriteSideEffectInstruction extends SideEffectInstruction { - WriteSideEffectInstruction() { - getOpcode() instanceof WriteSideEffectOpcode - } + WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentInstruction() { - result = getAnOperand().(AddressOperand).getDef() - } + Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1245,9 +1240,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { - BufferMayWriteSideEffectInstruction() { - getOpcode() instanceof Opcode::BufferMayWriteSideEffect - } + BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMayMemoryAccess From 554d6390f7ce5a16191122fdaf8c94297c993c7c Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 13 Sep 2019 11:59:09 -0700 Subject: [PATCH 0305/1227] C++: clean up after rebase --- .../ir/implementation/aliased_ssa/internal/AliasAnalysis.qll | 2 +- .../cpp/ir/implementation/raw/internal/TranslatedCall.qll | 4 ---- .../implementation/unaliased_ssa/internal/AliasAnalysis.qll | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index da381515cb9..dc50ef01354 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -226,7 +226,7 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getVariable().getAST() = f + init.(InitializeParameterInstruction).getParameter() = f .getParameter(operand.(PositionalArgumentOperand).getIndex()) or init instanceof InitializeThisInstruction and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index c9d697470c1..58ffdabeca2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -94,10 +94,6 @@ abstract class TranslatedCall extends TranslatedExpr { then result = getSideEffects().getFirstInstruction() else result = getParent().getChildSuccessor(this) ) - or - hasSideEffect() and - tag = CallSideEffectTag() and - result = getParent().getChildSuccessor(this) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index da381515cb9..dc50ef01354 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -226,7 +226,7 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getVariable().getAST() = f + init.(InitializeParameterInstruction).getParameter() = f .getParameter(operand.(PositionalArgumentOperand).getIndex()) or init instanceof InitializeThisInstruction and From 24574be00787a4750d96060bc4303891d0b2e634 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 16 Sep 2019 15:02:44 -0700 Subject: [PATCH 0306/1227] C++: add SizedBuffer side effect instructions --- .../code/cpp/ir/implementation/Opcode.qll | 26 +- .../aliased_ssa/Instruction.qll | 51 +- .../ir/implementation/aliased_ssa/Operand.qll | 10 + .../ir/implementation/internal/OperandTag.qll | 2 +- .../cpp/ir/implementation/raw/Instruction.qll | 51 +- .../cpp/ir/implementation/raw/Operand.qll | 10 + .../unaliased_ssa/Instruction.qll | 51 +- .../implementation/unaliased_ssa/Operand.qll | 10 + .../test/library-tests/ir/ir/raw_ir.expected | 692 +++++++++--------- .../ir/ssa/aliased_ssa_ir.expected | 232 +++--- .../ir/ssa/unaliased_ssa_ir.expected | 204 +++--- 11 files changed, 761 insertions(+), 578 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index dad156c93a7..8be5a1eaa79 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -71,6 +71,9 @@ private newtype TOpcode = TBufferReadSideEffect() or TBufferMustWriteSideEffect() or TBufferMayWriteSideEffect() or + TSizedBufferReadSideEffect() or + TSizedBufferMustWriteSideEffect() or + TSizedBufferMayWriteSideEffect() or TChi() or TInlineAsm() or TUnreached() or @@ -147,10 +150,16 @@ abstract class MustWriteSideEffectOpcode extends WriteSideEffectOpcode { } abstract class MayWriteSideEffectOpcode extends WriteSideEffectOpcode { } /** - * An opcode that accesses a buffer via an `AddressOperand` and a `BufferSizeOperand`. + * An opcode that accesses a buffer via an `AddressOperand`. */ abstract class BufferAccessOpcode extends MemoryAccessOpcode { } +/** + * An opcode that accesses a buffer via an `AddressOperand` with a `BufferSizeOperand` specifying + * the number of elements accessed. + */ +abstract class SizedBufferAccessOpcode extends BufferAccessOpcode { } + module Opcode { class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } @@ -445,6 +454,21 @@ module Opcode { final override string toString() { result = "BufferMayWriteSideEffect" } } + class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferAccessOpcode, + TSizedBufferReadSideEffect { + final override string toString() { result = "SizedBufferReadSideEffect" } + } + + class SizedBufferMustWriteSideEffect extends MustWriteSideEffectOpcode, SizedBufferAccessOpcode, + TSizedBufferMustWriteSideEffect { + final override string toString() { result = "SizedBufferMustWriteSideEffect" } + } + + class SizedBufferMayWriteSideEffect extends MayWriteSideEffectOpcode, SizedBufferAccessOpcode, + TSizedBufferMayWriteSideEffect { + final override string toString() { result = "SizedBufferMayWriteSideEffect" } + } + class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index f3703b3386c..4ccb0bb8c22 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -30,7 +30,7 @@ module InstructionSanity { or opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or - opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand + opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag or opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or @@ -1176,7 +1176,7 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { class IndirectReadSideEffectInstruction extends SideEffectInstruction { IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1185,7 +1185,20 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction { class BufferReadSideEffectInstruction extends SideEffectInstruction { BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } +} + +/** + * An instruction representing the read of an indirect buffer parameter within a function call. + */ +class SizedBufferReadSideEffectInstruction extends SideEffectInstruction { + SizedBufferReadSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferReadSideEffect + } + + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } } /** @@ -1194,7 +1207,7 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1220,6 +1233,20 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } } +/** + * An instruction representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ +class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + SizedBufferMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + /** * An instruction representing the potential write of an indirect parameter within a function call. * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. @@ -1247,6 +1274,22 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { } } +/** + * An instruction representing the write of an indirect buffer parameter within a function call. + * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. + */ +class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { + SizedBufferMayWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { + result instanceof BufferMayMemoryAccess + } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + /** * An instruction representing a GNU or MSVC inline assembly statement. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 2161fe1efa4..a23fb081afe 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -254,6 +254,16 @@ class AddressOperand extends RegisterOperand { override string toString() { result = "Address" } } +/** + * The buffer size operand of an instruction that represents a read or write of + * a buffer. + */ +class BufferSizeOperand extends RegisterOperand { + override BufferSizeOperandTag tag; + + override string toString() { result = "BufferSize" } +} + /** * The source value operand of an instruction that loads a value from memory (e.g. `Load`, * `ReturnValue`, `ThrowValue`). diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll index d1172670a79..32d17bc2905 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll @@ -66,7 +66,7 @@ AddressOperandTag addressOperand() { result = TAddressOperand() } * The buffer size operand of an instruction that represents a read or write of * a buffer. */ -class BufferSizeOperand extends RegisterOperandTag, TBufferSizeOperand { +class BufferSizeOperandTag extends RegisterOperandTag, TBufferSizeOperand { final override string toString() { result = "BufferSize" } final override int getSortOrder() { result = 1 } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index f3703b3386c..4ccb0bb8c22 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -30,7 +30,7 @@ module InstructionSanity { or opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or - opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand + opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag or opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or @@ -1176,7 +1176,7 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { class IndirectReadSideEffectInstruction extends SideEffectInstruction { IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1185,7 +1185,20 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction { class BufferReadSideEffectInstruction extends SideEffectInstruction { BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } +} + +/** + * An instruction representing the read of an indirect buffer parameter within a function call. + */ +class SizedBufferReadSideEffectInstruction extends SideEffectInstruction { + SizedBufferReadSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferReadSideEffect + } + + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } } /** @@ -1194,7 +1207,7 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1220,6 +1233,20 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } } +/** + * An instruction representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ +class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + SizedBufferMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + /** * An instruction representing the potential write of an indirect parameter within a function call. * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. @@ -1247,6 +1274,22 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { } } +/** + * An instruction representing the write of an indirect buffer parameter within a function call. + * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. + */ +class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { + SizedBufferMayWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { + result instanceof BufferMayMemoryAccess + } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + /** * An instruction representing a GNU or MSVC inline assembly statement. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 2161fe1efa4..a23fb081afe 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -254,6 +254,16 @@ class AddressOperand extends RegisterOperand { override string toString() { result = "Address" } } +/** + * The buffer size operand of an instruction that represents a read or write of + * a buffer. + */ +class BufferSizeOperand extends RegisterOperand { + override BufferSizeOperandTag tag; + + override string toString() { result = "BufferSize" } +} + /** * The source value operand of an instruction that loads a value from memory (e.g. `Load`, * `ReturnValue`, `ThrowValue`). diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index f3703b3386c..4ccb0bb8c22 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -30,7 +30,7 @@ module InstructionSanity { or opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or - opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand + opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag or opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or @@ -1176,7 +1176,7 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { class IndirectReadSideEffectInstruction extends SideEffectInstruction { IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1185,7 +1185,20 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction { class BufferReadSideEffectInstruction extends SideEffectInstruction { BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } +} + +/** + * An instruction representing the read of an indirect buffer parameter within a function call. + */ +class SizedBufferReadSideEffectInstruction extends SideEffectInstruction { + SizedBufferReadSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferReadSideEffect + } + + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } } /** @@ -1194,7 +1207,7 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1220,6 +1233,20 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } } +/** + * An instruction representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ +class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + SizedBufferMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + /** * An instruction representing the potential write of an indirect parameter within a function call. * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. @@ -1247,6 +1274,22 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { } } +/** + * An instruction representing the write of an indirect buffer parameter within a function call. + * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. + */ +class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { + SizedBufferMayWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { + result instanceof BufferMayMemoryAccess + } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + /** * An instruction representing a GNU or MSVC inline assembly statement. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 2161fe1efa4..a23fb081afe 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -254,6 +254,16 @@ class AddressOperand extends RegisterOperand { override string toString() { result = "Address" } } +/** + * The buffer size operand of an instruction that represents a read or write of + * a buffer. + */ +class BufferSizeOperand extends RegisterOperand { + override BufferSizeOperandTag tag; + + override string toString() { result = "BufferSize" } +} + /** * The source value operand of an instruction that loads a value from memory (e.g. `Load`, * `ReturnValue`, `ThrowValue`). diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 84059acbea2..34c81febf78 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -15,7 +15,7 @@ bad_asts.cpp: # 16| r0_11(int) = Call : func:r0_9, this:r0_8, 0:r0_10 # 16| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 16| v0_13(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 -# 16| r0_14(S) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 +# 16| mu0_14(S) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 # 17| v0_15(void) = NoOp : # 14| v0_16(void) = ReturnVoid : # 14| v0_17(void) = UnmodeledUse : mu* @@ -2675,10 +2675,10 @@ ir.cpp: # 585| r0_8(char *) = Convert : r0_7 # 585| v0_9(void) = Call : func:r0_3, 0:r0_5, 1:r0_6, 2:r0_8 # 585| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 585| v0_11(void) = ^IndirectReadSideEffect[s] : &:r0_5, ~mu0_2 +# 585| v0_11(void) = ^IndirectReadSideEffect : &:r0_5, ~mu0_2 # 585| v0_12(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 -# 585| mu0_13(unknown) = ^BufferMayWriteSideEffect[s] : &:r0_5, ~mu0_2 -# 585| r0_14(unknown) = ^BufferMayWriteSideEffect : &:r0_8, ~mu0_2 +# 585| mu0_13(unknown) = ^BufferMayWriteSideEffect : &:r0_5, ~mu0_2 +# 585| mu0_14(unknown) = ^BufferMayWriteSideEffect : &:r0_8, ~mu0_2 # 586| v0_15(void) = NoOp : # 584| v0_16(void) = ReturnVoid : # 584| v0_17(void) = UnmodeledUse : mu* @@ -2708,38 +2708,38 @@ ir.cpp: # 615| void DeclareObject() # 615| Block 0 -# 615| v0_0(void) = EnterFunction : -# 615| mu0_1(unknown) = AliasedDefinition : -# 615| mu0_2(unknown) = UnmodeledDefinition : -# 616| r0_3(glval) = VariableAddress[s1] : -# 616| r0_4(glval) = FunctionAddress[String] : -# 616| v0_5(void) = Call : func:r0_4, this:r0_3 -# 616| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 617| r0_7(glval) = VariableAddress[s2] : -# 617| r0_8(glval) = FunctionAddress[String] : -# 617| r0_9(glval) = StringConstant["hello"] : -# 617| r0_10(char *) = Convert : r0_9 -# 617| v0_11(void) = Call : func:r0_8, this:r0_7, 0:r0_10 -# 617| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 617| v0_13(void) = ^IndirectReadSideEffect[p#0] : &:r0_10, ~mu0_2 -# 617| mu0_14(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_10, ~mu0_2 -# 618| r0_15(glval) = VariableAddress[s3] : -# 618| r0_16(glval) = FunctionAddress[ReturnObject] : -# 618| r0_17(String) = Call : func:r0_16 -# 618| mu0_18(unknown) = ^CallSideEffect : ~mu0_2 -# 618| mu0_19(String) = Store : &:r0_15, r0_17 -# 619| r0_20(glval) = VariableAddress[s4] : -# 619| r0_21(glval) = FunctionAddress[String] : -# 619| r0_22(glval) = StringConstant["test"] : -# 619| r0_23(char *) = Convert : r0_22 -# 619| v0_24(void) = Call : func:r0_21, this:r0_20, 0:r0_23 -# 619| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 619| v0_26(void) = ^IndirectReadSideEffect[p#0] : &:r0_23, ~mu0_2 -# 619| mu0_27(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_23, ~mu0_2 -# 620| v0_28(void) = NoOp : -# 615| v0_29(void) = ReturnVoid : -# 615| v0_30(void) = UnmodeledUse : mu* -# 615| v0_31(void) = ExitFunction : +# 615| v0_0(void) = EnterFunction : +# 615| mu0_1(unknown) = AliasedDefinition : +# 615| mu0_2(unknown) = UnmodeledDefinition : +# 616| r0_3(glval) = VariableAddress[s1] : +# 616| r0_4(glval) = FunctionAddress[String] : +# 616| v0_5(void) = Call : func:r0_4, this:r0_3 +# 616| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 +# 617| r0_7(glval) = VariableAddress[s2] : +# 617| r0_8(glval) = FunctionAddress[String] : +# 617| r0_9(glval) = StringConstant["hello"] : +# 617| r0_10(char *) = Convert : r0_9 +# 617| v0_11(void) = Call : func:r0_8, this:r0_7, 0:r0_10 +# 617| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 617| v0_13(void) = ^IndirectReadSideEffect : &:r0_10, ~mu0_2 +# 617| mu0_14(unknown) = ^BufferMayWriteSideEffect : &:r0_10, ~mu0_2 +# 618| r0_15(glval) = VariableAddress[s3] : +# 618| r0_16(glval) = FunctionAddress[ReturnObject] : +# 618| r0_17(String) = Call : func:r0_16 +# 618| mu0_18(unknown) = ^CallSideEffect : ~mu0_2 +# 618| mu0_19(String) = Store : &:r0_15, r0_17 +# 619| r0_20(glval) = VariableAddress[s4] : +# 619| r0_21(glval) = FunctionAddress[String] : +# 619| r0_22(glval) = StringConstant["test"] : +# 619| r0_23(char *) = Convert : r0_22 +# 619| v0_24(void) = Call : func:r0_21, this:r0_20, 0:r0_23 +# 619| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +# 619| v0_26(void) = ^IndirectReadSideEffect : &:r0_23, ~mu0_2 +# 619| mu0_27(unknown) = ^BufferMayWriteSideEffect : &:r0_23, ~mu0_2 +# 620| v0_28(void) = NoOp : +# 615| v0_29(void) = ReturnVoid : +# 615| v0_30(void) = UnmodeledUse : mu* +# 615| v0_31(void) = ExitFunction : # 622| void CallMethods(String&, String*, String) # 622| Block 0 @@ -2759,7 +2759,7 @@ ir.cpp: # 623| r0_13(char *) = Call : func:r0_12, this:r0_11 # 623| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 # 623| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 -# 623| r0_16(String) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 +# 623| mu0_16(String) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 # 624| r0_17(glval) = VariableAddress[p] : # 624| r0_18(String *) = Load : &:r0_17, ~mu0_2 # 624| r0_19(String *) = Convert : r0_18 @@ -2767,14 +2767,14 @@ ir.cpp: # 624| r0_21(char *) = Call : func:r0_20, this:r0_19 # 624| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 # 624| v0_23(void) = ^IndirectReadSideEffect : &:r0_19, ~mu0_2 -# 624| r0_24(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 +# 624| mu0_24(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 # 625| r0_25(glval) = VariableAddress[s] : # 625| r0_26(glval) = Convert : r0_25 # 625| r0_27(glval) = FunctionAddress[c_str] : # 625| r0_28(char *) = Call : func:r0_27, this:r0_26 # 625| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 # 625| v0_30(void) = ^IndirectReadSideEffect : &:r0_26, ~mu0_2 -# 625| r0_31(String) = ^IndirectMayWriteSideEffect : &:r0_26, ~mu0_2 +# 625| mu0_31(String) = ^IndirectMayWriteSideEffect : &:r0_26, ~mu0_2 # 626| v0_32(void) = NoOp : # 622| v0_33(void) = ReturnVoid : # 622| v0_34(void) = UnmodeledUse : mu* @@ -2882,21 +2882,21 @@ ir.cpp: # 653| r0_7(int) = Call : func:r0_5, this:r0_4, 0:r0_6 # 653| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 # 653| v0_9(void) = ^IndirectReadSideEffect : &:r0_4, ~mu0_2 -# 653| r0_10(C) = ^IndirectMayWriteSideEffect : &:r0_4, ~mu0_2 +# 653| mu0_10(C) = ^IndirectMayWriteSideEffect : &:r0_4, ~mu0_2 # 654| r0_11(C *) = CopyValue : r0_3 # 654| r0_12(glval) = FunctionAddress[InstanceMemberFunction] : # 654| r0_13(int) = Constant[1] : # 654| r0_14(int) = Call : func:r0_12, this:r0_11, 0:r0_13 # 654| mu0_15(unknown) = ^CallSideEffect : ~mu0_2 # 654| v0_16(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 -# 654| r0_17(C) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 +# 654| mu0_17(C) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 #-----| r0_18(C *) = CopyValue : r0_3 # 655| r0_19(glval) = FunctionAddress[InstanceMemberFunction] : # 655| r0_20(int) = Constant[2] : # 655| r0_21(int) = Call : func:r0_19, this:r0_18, 0:r0_20 # 655| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_23(void) = ^IndirectReadSideEffect : &:r0_18, ~mu0_2 -#-----| r0_24(C) = ^IndirectMayWriteSideEffect : &:r0_18, ~mu0_2 +#-----| mu0_24(C) = ^IndirectMayWriteSideEffect : &:r0_18, ~mu0_2 # 656| v0_25(void) = NoOp : # 652| v0_26(void) = ReturnVoid : # 652| v0_27(void) = UnmodeledUse : mu* @@ -2904,35 +2904,35 @@ ir.cpp: # 658| void C::C() # 658| Block 0 -# 658| v0_0(void) = EnterFunction : -# 658| mu0_1(unknown) = AliasedDefinition : -# 658| mu0_2(unknown) = UnmodeledDefinition : -# 658| r0_3(glval) = InitializeThis : -# 659| r0_4(glval) = FieldAddress[m_a] : r0_3 -# 659| r0_5(int) = Constant[1] : -# 659| mu0_6(int) = Store : &:r0_4, r0_5 -# 663| r0_7(glval) = FieldAddress[m_b] : r0_3 -# 663| r0_8(glval) = FunctionAddress[String] : -# 663| v0_9(void) = Call : func:r0_8, this:r0_7 -# 663| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 660| r0_11(glval) = FieldAddress[m_c] : r0_3 -# 660| r0_12(char) = Constant[3] : -# 660| mu0_13(char) = Store : &:r0_11, r0_12 -# 661| r0_14(glval) = FieldAddress[m_e] : r0_3 -# 661| r0_15(void *) = Constant[0] : -# 661| mu0_16(void *) = Store : &:r0_14, r0_15 -# 662| r0_17(glval) = FieldAddress[m_f] : r0_3 -# 662| r0_18(glval) = FunctionAddress[String] : -# 662| r0_19(glval) = StringConstant["test"] : -# 662| r0_20(char *) = Convert : r0_19 -# 662| v0_21(void) = Call : func:r0_18, this:r0_17, 0:r0_20 -# 662| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -# 662| v0_23(void) = ^IndirectReadSideEffect[p#0] : &:r0_20, ~mu0_2 -# 662| mu0_24(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_20, ~mu0_2 -# 664| v0_25(void) = NoOp : -# 658| v0_26(void) = ReturnVoid : -# 658| v0_27(void) = UnmodeledUse : mu* -# 658| v0_28(void) = ExitFunction : +# 658| v0_0(void) = EnterFunction : +# 658| mu0_1(unknown) = AliasedDefinition : +# 658| mu0_2(unknown) = UnmodeledDefinition : +# 658| r0_3(glval) = InitializeThis : +# 659| r0_4(glval) = FieldAddress[m_a] : r0_3 +# 659| r0_5(int) = Constant[1] : +# 659| mu0_6(int) = Store : &:r0_4, r0_5 +# 663| r0_7(glval) = FieldAddress[m_b] : r0_3 +# 663| r0_8(glval) = FunctionAddress[String] : +# 663| v0_9(void) = Call : func:r0_8, this:r0_7 +# 663| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 +# 660| r0_11(glval) = FieldAddress[m_c] : r0_3 +# 660| r0_12(char) = Constant[3] : +# 660| mu0_13(char) = Store : &:r0_11, r0_12 +# 661| r0_14(glval) = FieldAddress[m_e] : r0_3 +# 661| r0_15(void *) = Constant[0] : +# 661| mu0_16(void *) = Store : &:r0_14, r0_15 +# 662| r0_17(glval) = FieldAddress[m_f] : r0_3 +# 662| r0_18(glval) = FunctionAddress[String] : +# 662| r0_19(glval) = StringConstant["test"] : +# 662| r0_20(char *) = Convert : r0_19 +# 662| v0_21(void) = Call : func:r0_18, this:r0_17, 0:r0_20 +# 662| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 +# 662| v0_23(void) = ^IndirectReadSideEffect : &:r0_20, ~mu0_2 +# 662| mu0_24(unknown) = ^BufferMayWriteSideEffect : &:r0_20, ~mu0_2 +# 664| v0_25(void) = NoOp : +# 658| v0_26(void) = ReturnVoid : +# 658| v0_27(void) = UnmodeledUse : mu* +# 658| v0_28(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 @@ -3118,23 +3118,23 @@ ir.cpp: # 720| double CallNestedTemplateFunc() # 720| Block 0 -# 720| v0_0(void) = EnterFunction : -# 720| mu0_1(unknown) = AliasedDefinition : -# 720| mu0_2(unknown) = UnmodeledDefinition : -# 721| r0_3(glval) = VariableAddress[#return] : -# 721| r0_4(glval) = FunctionAddress[Func] : -# 721| r0_5(void *) = Constant[0] : -# 721| r0_6(char) = Constant[111] : -# 721| r0_7(long) = Call : func:r0_4, 0:r0_5, 1:r0_6 -# 721| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 721| v0_9(void) = ^IndirectReadSideEffect[x] : &:r0_5, ~mu0_2 -# 721| mu0_10(unknown) = ^BufferMayWriteSideEffect[x] : &:r0_5, ~mu0_2 -# 721| r0_11(double) = Convert : r0_7 -# 721| mu0_12(double) = Store : &:r0_3, r0_11 -# 720| r0_13(glval) = VariableAddress[#return] : -# 720| v0_14(void) = ReturnValue : &:r0_13, ~mu0_2 -# 720| v0_15(void) = UnmodeledUse : mu* -# 720| v0_16(void) = ExitFunction : +# 720| v0_0(void) = EnterFunction : +# 720| mu0_1(unknown) = AliasedDefinition : +# 720| mu0_2(unknown) = UnmodeledDefinition : +# 721| r0_3(glval) = VariableAddress[#return] : +# 721| r0_4(glval) = FunctionAddress[Func] : +# 721| r0_5(void *) = Constant[0] : +# 721| r0_6(char) = Constant[111] : +# 721| r0_7(long) = Call : func:r0_4, 0:r0_5, 1:r0_6 +# 721| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 +# 721| v0_9(void) = ^IndirectReadSideEffect : &:r0_5, ~mu0_2 +# 721| mu0_10(unknown) = ^BufferMayWriteSideEffect : &:r0_5, ~mu0_2 +# 721| r0_11(double) = Convert : r0_7 +# 721| mu0_12(double) = Store : &:r0_3, r0_11 +# 720| r0_13(glval) = VariableAddress[#return] : +# 720| v0_14(void) = ReturnValue : &:r0_13, ~mu0_2 +# 720| v0_15(void) = UnmodeledUse : mu* +# 720| v0_16(void) = ExitFunction : # 724| void TryCatch(bool) # 724| Block 0 @@ -3201,8 +3201,8 @@ ir.cpp: # 731| r7_3(char *) = Convert : r7_2 # 731| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 731| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 731| v7_6(void) = ^IndirectReadSideEffect[p#0] : &:r7_3, ~mu0_2 -# 731| mu7_7(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r7_3, ~mu0_2 +# 731| v7_6(void) = ^IndirectReadSideEffect : &:r7_3, ~mu0_2 +# 731| mu7_7(unknown) = ^BufferMayWriteSideEffect : &:r7_3, ~mu0_2 # 731| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 @@ -3218,17 +3218,17 @@ ir.cpp: #-----| Goto -> Block 10 # 735| Block 10 -# 735| r10_0(glval) = VariableAddress[s] : -# 735| mu10_1(char *) = InitializeParameter[s] : &:r10_0 -# 736| r10_2(glval) = VariableAddress[#throw736:5] : -# 736| r10_3(glval) = FunctionAddress[String] : -# 736| r10_4(glval) = VariableAddress[s] : -# 736| r10_5(char *) = Load : &:r10_4, ~mu0_2 -# 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 -# 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 736| v10_8(void) = ^IndirectReadSideEffect[p#0] : &:r10_5, ~mu0_2 -# 736| mu10_9(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r10_5, ~mu0_2 -# 736| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 +# 735| r10_0(glval) = VariableAddress[s] : +# 735| mu10_1(char *) = InitializeParameter[s] : &:r10_0 +# 736| r10_2(glval) = VariableAddress[#throw736:5] : +# 736| r10_3(glval) = FunctionAddress[String] : +# 736| r10_4(glval) = VariableAddress[s] : +# 736| r10_5(char *) = Load : &:r10_4, ~mu0_2 +# 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 +# 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 +# 736| v10_8(void) = ^IndirectReadSideEffect : &:r10_5, ~mu0_2 +# 736| mu10_9(unknown) = ^BufferMayWriteSideEffect : &:r10_5, ~mu0_2 +# 736| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 # 738| Block 11 @@ -3254,31 +3254,31 @@ ir.cpp: # 745| Base& Base::operator=(Base const&) # 745| Block 0 -# 745| v0_0(void) = EnterFunction : -# 745| mu0_1(unknown) = AliasedDefinition : -# 745| mu0_2(unknown) = UnmodeledDefinition : -# 745| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 -#-----| r0_6(Base *) = CopyValue : r0_3 -#-----| r0_7(glval) = FieldAddress[base_s] : r0_6 -# 745| r0_8(glval) = FunctionAddress[operator=] : -#-----| r0_9(glval) = VariableAddress[p#0] : -#-----| r0_10(Base &) = Load : &:r0_9, ~mu0_2 -#-----| r0_11(glval) = FieldAddress[base_s] : r0_10 -# 745| r0_12(String &) = Call : func:r0_8, this:r0_7, 0:r0_11 -# 745| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect[p#0] : &:r0_11, ~mu0_2 -#-----| r0_16(String) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_11, ~mu0_2 -#-----| r0_18(glval) = VariableAddress[#return] : -#-----| r0_19(Base *) = CopyValue : r0_3 -#-----| mu0_20(Base &) = Store : &:r0_18, r0_19 -# 745| r0_21(glval) = VariableAddress[#return] : -# 745| v0_22(void) = ReturnValue : &:r0_21, ~mu0_2 -# 745| v0_23(void) = UnmodeledUse : mu* -# 745| v0_24(void) = ExitFunction : +# 745| v0_0(void) = EnterFunction : +# 745| mu0_1(unknown) = AliasedDefinition : +# 745| mu0_2(unknown) = UnmodeledDefinition : +# 745| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 +#-----| r0_6(Base *) = CopyValue : r0_3 +#-----| r0_7(glval) = FieldAddress[base_s] : r0_6 +# 745| r0_8(glval) = FunctionAddress[operator=] : +#-----| r0_9(glval) = VariableAddress[p#0] : +#-----| r0_10(Base &) = Load : &:r0_9, ~mu0_2 +#-----| r0_11(glval) = FieldAddress[base_s] : r0_10 +# 745| r0_12(String &) = Call : func:r0_8, this:r0_7, 0:r0_11 +# 745| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 +#-----| mu0_16(String) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect : &:r0_11, ~mu0_2 +#-----| r0_18(glval) = VariableAddress[#return] : +#-----| r0_19(Base *) = CopyValue : r0_3 +#-----| mu0_20(Base &) = Store : &:r0_18, r0_19 +# 745| r0_21(glval) = VariableAddress[#return] : +# 745| v0_22(void) = ReturnValue : &:r0_21, ~mu0_2 +# 745| v0_23(void) = UnmodeledUse : mu* +# 745| v0_24(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 @@ -3329,43 +3329,43 @@ ir.cpp: # 754| Middle& Middle::operator=(Middle const&) # 754| Block 0 -# 754| v0_0(void) = EnterFunction : -# 754| mu0_1(unknown) = AliasedDefinition : -# 754| mu0_2(unknown) = UnmodeledDefinition : -# 754| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(Middle &) = InitializeParameter[p#0] : &:r0_4 -#-----| r0_6(Middle *) = CopyValue : r0_3 -#-----| r0_7(Base *) = ConvertToBase[Middle : Base] : r0_6 -# 754| r0_8(glval) = FunctionAddress[operator=] : -#-----| r0_9(glval) = VariableAddress[p#0] : -#-----| r0_10(Middle &) = Load : &:r0_9, ~mu0_2 -#-----| r0_11(Base *) = ConvertToBase[Middle : Base] : r0_10 -# 754| r0_12(Base &) = Call : func:r0_8, this:r0_7, 0:r0_11 -# 754| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect[p#0] : &:r0_11, ~mu0_2 -#-----| r0_16(Base) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_11, ~mu0_2 -#-----| r0_18(Middle *) = CopyValue : r0_3 -#-----| r0_19(glval) = FieldAddress[middle_s] : r0_18 -# 754| r0_20(glval) = FunctionAddress[operator=] : -#-----| r0_21(glval) = VariableAddress[p#0] : -#-----| r0_22(Middle &) = Load : &:r0_21, ~mu0_2 -#-----| r0_23(glval) = FieldAddress[middle_s] : r0_22 -# 754| r0_24(String &) = Call : func:r0_20, this:r0_19, 0:r0_23 -# 754| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_26(void) = ^IndirectReadSideEffect : &:r0_19, ~mu0_2 -#-----| v0_27(void) = ^IndirectReadSideEffect[p#0] : &:r0_23, ~mu0_2 -#-----| r0_28(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 -#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_23, ~mu0_2 -#-----| r0_30(glval) = VariableAddress[#return] : -#-----| r0_31(Middle *) = CopyValue : r0_3 -#-----| mu0_32(Middle &) = Store : &:r0_30, r0_31 -# 754| r0_33(glval) = VariableAddress[#return] : -# 754| v0_34(void) = ReturnValue : &:r0_33, ~mu0_2 -# 754| v0_35(void) = UnmodeledUse : mu* -# 754| v0_36(void) = ExitFunction : +# 754| v0_0(void) = EnterFunction : +# 754| mu0_1(unknown) = AliasedDefinition : +# 754| mu0_2(unknown) = UnmodeledDefinition : +# 754| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(Middle &) = InitializeParameter[p#0] : &:r0_4 +#-----| r0_6(Middle *) = CopyValue : r0_3 +#-----| r0_7(Base *) = ConvertToBase[Middle : Base] : r0_6 +# 754| r0_8(glval) = FunctionAddress[operator=] : +#-----| r0_9(glval) = VariableAddress[p#0] : +#-----| r0_10(Middle &) = Load : &:r0_9, ~mu0_2 +#-----| r0_11(Base *) = ConvertToBase[Middle : Base] : r0_10 +# 754| r0_12(Base &) = Call : func:r0_8, this:r0_7, 0:r0_11 +# 754| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 +#-----| mu0_16(Base) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect : &:r0_11, ~mu0_2 +#-----| r0_18(Middle *) = CopyValue : r0_3 +#-----| r0_19(glval) = FieldAddress[middle_s] : r0_18 +# 754| r0_20(glval) = FunctionAddress[operator=] : +#-----| r0_21(glval) = VariableAddress[p#0] : +#-----| r0_22(Middle &) = Load : &:r0_21, ~mu0_2 +#-----| r0_23(glval) = FieldAddress[middle_s] : r0_22 +# 754| r0_24(String &) = Call : func:r0_20, this:r0_19, 0:r0_23 +# 754| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_26(void) = ^IndirectReadSideEffect : &:r0_19, ~mu0_2 +#-----| v0_27(void) = ^IndirectReadSideEffect : &:r0_23, ~mu0_2 +#-----| mu0_28(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 +#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect : &:r0_23, ~mu0_2 +#-----| r0_30(glval) = VariableAddress[#return] : +#-----| r0_31(Middle *) = CopyValue : r0_3 +#-----| mu0_32(Middle &) = Store : &:r0_30, r0_31 +# 754| r0_33(glval) = VariableAddress[#return] : +# 754| v0_34(void) = ReturnValue : &:r0_33, ~mu0_2 +# 754| v0_35(void) = UnmodeledUse : mu* +# 754| v0_36(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 @@ -3422,9 +3422,9 @@ ir.cpp: # 763| r0_12(Middle &) = Call : func:r0_8, this:r0_7, 0:r0_11 # 763| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect[p#0] : &:r0_11, ~mu0_2 -#-----| r0_16(Middle) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_11, ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 +#-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect : &:r0_11, ~mu0_2 #-----| r0_18(Derived *) = CopyValue : r0_3 #-----| r0_19(glval) = FieldAddress[derived_s] : r0_18 # 763| r0_20(glval) = FunctionAddress[operator=] : @@ -3434,9 +3434,9 @@ ir.cpp: # 763| r0_24(String &) = Call : func:r0_20, this:r0_19, 0:r0_23 # 763| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_26(void) = ^IndirectReadSideEffect : &:r0_19, ~mu0_2 -#-----| v0_27(void) = ^IndirectReadSideEffect[p#0] : &:r0_23, ~mu0_2 -#-----| r0_28(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 -#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_23, ~mu0_2 +#-----| v0_27(void) = ^IndirectReadSideEffect : &:r0_23, ~mu0_2 +#-----| mu0_28(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 +#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect : &:r0_23, ~mu0_2 #-----| r0_30(glval) = VariableAddress[#return] : #-----| r0_31(Derived *) = CopyValue : r0_3 #-----| mu0_32(Derived &) = Store : &:r0_30, r0_31 @@ -3646,9 +3646,9 @@ ir.cpp: # 808| r0_28(Base &) = Call : func:r0_25, this:r0_24, 0:r0_27 # 808| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 # 808| v0_30(void) = ^IndirectReadSideEffect : &:r0_24, ~mu0_2 -# 808| v0_31(void) = ^IndirectReadSideEffect[p#0] : &:r0_27, ~mu0_2 -# 808| r0_32(Base) = ^IndirectMayWriteSideEffect : &:r0_24, ~mu0_2 -# 808| mu0_33(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_27, ~mu0_2 +# 808| v0_31(void) = ^IndirectReadSideEffect : &:r0_27, ~mu0_2 +# 808| mu0_32(Base) = ^IndirectMayWriteSideEffect : &:r0_24, ~mu0_2 +# 808| mu0_33(unknown) = ^BufferMayWriteSideEffect : &:r0_27, ~mu0_2 # 809| r0_34(glval) = VariableAddress[b] : # 809| r0_35(glval) = FunctionAddress[operator=] : # 809| r0_36(glval) = FunctionAddress[Base] : @@ -3656,15 +3656,15 @@ ir.cpp: # 809| r0_38(glval) = ConvertToBase[Middle : Base] : r0_37 # 809| v0_39(void) = Call : func:r0_36, 0:r0_38 # 809| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 -# 809| v0_41(void) = ^IndirectReadSideEffect[p#0] : &:r0_38, ~mu0_2 -# 809| mu0_42(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_38, ~mu0_2 +# 809| v0_41(void) = ^IndirectReadSideEffect : &:r0_38, ~mu0_2 +# 809| mu0_42(unknown) = ^BufferMayWriteSideEffect : &:r0_38, ~mu0_2 # 809| r0_43(glval) = Convert : v0_39 # 809| r0_44(Base &) = Call : func:r0_35, this:r0_34, 0:r0_43 # 809| mu0_45(unknown) = ^CallSideEffect : ~mu0_2 # 809| v0_46(void) = ^IndirectReadSideEffect : &:r0_34, ~mu0_2 -# 809| v0_47(void) = ^IndirectReadSideEffect[p#0] : &:r0_43, ~mu0_2 -# 809| r0_48(Base) = ^IndirectMayWriteSideEffect : &:r0_34, ~mu0_2 -# 809| mu0_49(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_43, ~mu0_2 +# 809| v0_47(void) = ^IndirectReadSideEffect : &:r0_43, ~mu0_2 +# 809| mu0_48(Base) = ^IndirectMayWriteSideEffect : &:r0_34, ~mu0_2 +# 809| mu0_49(unknown) = ^BufferMayWriteSideEffect : &:r0_43, ~mu0_2 # 810| r0_50(glval) = VariableAddress[b] : # 810| r0_51(glval) = FunctionAddress[operator=] : # 810| r0_52(glval) = FunctionAddress[Base] : @@ -3672,15 +3672,15 @@ ir.cpp: # 810| r0_54(glval) = ConvertToBase[Middle : Base] : r0_53 # 810| v0_55(void) = Call : func:r0_52, 0:r0_54 # 810| mu0_56(unknown) = ^CallSideEffect : ~mu0_2 -# 810| v0_57(void) = ^IndirectReadSideEffect[p#0] : &:r0_54, ~mu0_2 -# 810| mu0_58(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_54, ~mu0_2 +# 810| v0_57(void) = ^IndirectReadSideEffect : &:r0_54, ~mu0_2 +# 810| mu0_58(unknown) = ^BufferMayWriteSideEffect : &:r0_54, ~mu0_2 # 810| r0_59(glval) = Convert : v0_55 # 810| r0_60(Base &) = Call : func:r0_51, this:r0_50, 0:r0_59 # 810| mu0_61(unknown) = ^CallSideEffect : ~mu0_2 # 810| v0_62(void) = ^IndirectReadSideEffect : &:r0_50, ~mu0_2 -# 810| v0_63(void) = ^IndirectReadSideEffect[p#0] : &:r0_59, ~mu0_2 -# 810| r0_64(Base) = ^IndirectMayWriteSideEffect : &:r0_50, ~mu0_2 -# 810| mu0_65(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_59, ~mu0_2 +# 810| v0_63(void) = ^IndirectReadSideEffect : &:r0_59, ~mu0_2 +# 810| mu0_64(Base) = ^IndirectMayWriteSideEffect : &:r0_50, ~mu0_2 +# 810| mu0_65(unknown) = ^BufferMayWriteSideEffect : &:r0_59, ~mu0_2 # 811| r0_66(glval) = VariableAddress[pm] : # 811| r0_67(Middle *) = Load : &:r0_66, ~mu0_2 # 811| r0_68(Base *) = ConvertToBase[Middle : Base] : r0_67 @@ -3709,9 +3709,9 @@ ir.cpp: # 816| r0_91(Middle &) = Call : func:r0_87, this:r0_86, 0:r0_90 # 816| mu0_92(unknown) = ^CallSideEffect : ~mu0_2 # 816| v0_93(void) = ^IndirectReadSideEffect : &:r0_86, ~mu0_2 -# 816| v0_94(void) = ^IndirectReadSideEffect[p#0] : &:r0_90, ~mu0_2 -# 816| r0_95(Middle) = ^IndirectMayWriteSideEffect : &:r0_86, ~mu0_2 -# 816| mu0_96(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_90, ~mu0_2 +# 816| v0_94(void) = ^IndirectReadSideEffect : &:r0_90, ~mu0_2 +# 816| mu0_95(Middle) = ^IndirectMayWriteSideEffect : &:r0_86, ~mu0_2 +# 816| mu0_96(unknown) = ^BufferMayWriteSideEffect : &:r0_90, ~mu0_2 # 817| r0_97(glval) = VariableAddress[m] : # 817| r0_98(glval) = FunctionAddress[operator=] : # 817| r0_99(glval) = VariableAddress[b] : @@ -3720,9 +3720,9 @@ ir.cpp: # 817| r0_102(Middle &) = Call : func:r0_98, this:r0_97, 0:r0_101 # 817| mu0_103(unknown) = ^CallSideEffect : ~mu0_2 # 817| v0_104(void) = ^IndirectReadSideEffect : &:r0_97, ~mu0_2 -# 817| v0_105(void) = ^IndirectReadSideEffect[p#0] : &:r0_101, ~mu0_2 -# 817| r0_106(Middle) = ^IndirectMayWriteSideEffect : &:r0_97, ~mu0_2 -# 817| mu0_107(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_101, ~mu0_2 +# 817| v0_105(void) = ^IndirectReadSideEffect : &:r0_101, ~mu0_2 +# 817| mu0_106(Middle) = ^IndirectMayWriteSideEffect : &:r0_97, ~mu0_2 +# 817| mu0_107(unknown) = ^BufferMayWriteSideEffect : &:r0_101, ~mu0_2 # 818| r0_108(glval) = VariableAddress[pb] : # 818| r0_109(Base *) = Load : &:r0_108, ~mu0_2 # 818| r0_110(Middle *) = ConvertToDerived[Middle : Base] : r0_109 @@ -3746,9 +3746,9 @@ ir.cpp: # 822| r0_128(Base &) = Call : func:r0_124, this:r0_123, 0:r0_127 # 822| mu0_129(unknown) = ^CallSideEffect : ~mu0_2 # 822| v0_130(void) = ^IndirectReadSideEffect : &:r0_123, ~mu0_2 -# 822| v0_131(void) = ^IndirectReadSideEffect[p#0] : &:r0_127, ~mu0_2 -# 822| r0_132(Base) = ^IndirectMayWriteSideEffect : &:r0_123, ~mu0_2 -# 822| mu0_133(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_127, ~mu0_2 +# 822| v0_131(void) = ^IndirectReadSideEffect : &:r0_127, ~mu0_2 +# 822| mu0_132(Base) = ^IndirectMayWriteSideEffect : &:r0_123, ~mu0_2 +# 822| mu0_133(unknown) = ^BufferMayWriteSideEffect : &:r0_127, ~mu0_2 # 823| r0_134(glval) = VariableAddress[b] : # 823| r0_135(glval) = FunctionAddress[operator=] : # 823| r0_136(glval) = FunctionAddress[Base] : @@ -3757,15 +3757,15 @@ ir.cpp: # 823| r0_139(glval) = ConvertToBase[Middle : Base] : r0_138 # 823| v0_140(void) = Call : func:r0_136, 0:r0_139 # 823| mu0_141(unknown) = ^CallSideEffect : ~mu0_2 -# 823| v0_142(void) = ^IndirectReadSideEffect[p#0] : &:r0_139, ~mu0_2 -# 823| mu0_143(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_139, ~mu0_2 +# 823| v0_142(void) = ^IndirectReadSideEffect : &:r0_139, ~mu0_2 +# 823| mu0_143(unknown) = ^BufferMayWriteSideEffect : &:r0_139, ~mu0_2 # 823| r0_144(glval) = Convert : v0_140 # 823| r0_145(Base &) = Call : func:r0_135, this:r0_134, 0:r0_144 # 823| mu0_146(unknown) = ^CallSideEffect : ~mu0_2 # 823| v0_147(void) = ^IndirectReadSideEffect : &:r0_134, ~mu0_2 -# 823| v0_148(void) = ^IndirectReadSideEffect[p#0] : &:r0_144, ~mu0_2 -# 823| r0_149(Base) = ^IndirectMayWriteSideEffect : &:r0_134, ~mu0_2 -# 823| mu0_150(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_144, ~mu0_2 +# 823| v0_148(void) = ^IndirectReadSideEffect : &:r0_144, ~mu0_2 +# 823| mu0_149(Base) = ^IndirectMayWriteSideEffect : &:r0_134, ~mu0_2 +# 823| mu0_150(unknown) = ^BufferMayWriteSideEffect : &:r0_144, ~mu0_2 # 824| r0_151(glval) = VariableAddress[b] : # 824| r0_152(glval) = FunctionAddress[operator=] : # 824| r0_153(glval) = FunctionAddress[Base] : @@ -3774,15 +3774,15 @@ ir.cpp: # 824| r0_156(glval) = ConvertToBase[Middle : Base] : r0_155 # 824| v0_157(void) = Call : func:r0_153, 0:r0_156 # 824| mu0_158(unknown) = ^CallSideEffect : ~mu0_2 -# 824| v0_159(void) = ^IndirectReadSideEffect[p#0] : &:r0_156, ~mu0_2 -# 824| mu0_160(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_156, ~mu0_2 +# 824| v0_159(void) = ^IndirectReadSideEffect : &:r0_156, ~mu0_2 +# 824| mu0_160(unknown) = ^BufferMayWriteSideEffect : &:r0_156, ~mu0_2 # 824| r0_161(glval) = Convert : v0_157 # 824| r0_162(Base &) = Call : func:r0_152, this:r0_151, 0:r0_161 # 824| mu0_163(unknown) = ^CallSideEffect : ~mu0_2 # 824| v0_164(void) = ^IndirectReadSideEffect : &:r0_151, ~mu0_2 -# 824| v0_165(void) = ^IndirectReadSideEffect[p#0] : &:r0_161, ~mu0_2 -# 824| r0_166(Base) = ^IndirectMayWriteSideEffect : &:r0_151, ~mu0_2 -# 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_161, ~mu0_2 +# 824| v0_165(void) = ^IndirectReadSideEffect : &:r0_161, ~mu0_2 +# 824| mu0_166(Base) = ^IndirectMayWriteSideEffect : &:r0_151, ~mu0_2 +# 824| mu0_167(unknown) = ^BufferMayWriteSideEffect : &:r0_161, ~mu0_2 # 825| r0_168(glval) = VariableAddress[pd] : # 825| r0_169(Derived *) = Load : &:r0_168, ~mu0_2 # 825| r0_170(Middle *) = ConvertToBase[Derived : Middle] : r0_169 @@ -3815,9 +3815,9 @@ ir.cpp: # 830| r0_197(Derived &) = Call : func:r0_192, this:r0_191, 0:r0_196 # 830| mu0_198(unknown) = ^CallSideEffect : ~mu0_2 # 830| v0_199(void) = ^IndirectReadSideEffect : &:r0_191, ~mu0_2 -# 830| v0_200(void) = ^IndirectReadSideEffect[p#0] : &:r0_196, ~mu0_2 -# 830| r0_201(Derived) = ^IndirectMayWriteSideEffect : &:r0_191, ~mu0_2 -# 830| mu0_202(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_196, ~mu0_2 +# 830| v0_200(void) = ^IndirectReadSideEffect : &:r0_196, ~mu0_2 +# 830| mu0_201(Derived) = ^IndirectMayWriteSideEffect : &:r0_191, ~mu0_2 +# 830| mu0_202(unknown) = ^BufferMayWriteSideEffect : &:r0_196, ~mu0_2 # 831| r0_203(glval) = VariableAddress[d] : # 831| r0_204(glval) = FunctionAddress[operator=] : # 831| r0_205(glval) = VariableAddress[b] : @@ -3827,9 +3827,9 @@ ir.cpp: # 831| r0_209(Derived &) = Call : func:r0_204, this:r0_203, 0:r0_208 # 831| mu0_210(unknown) = ^CallSideEffect : ~mu0_2 # 831| v0_211(void) = ^IndirectReadSideEffect : &:r0_203, ~mu0_2 -# 831| v0_212(void) = ^IndirectReadSideEffect[p#0] : &:r0_208, ~mu0_2 -# 831| r0_213(Derived) = ^IndirectMayWriteSideEffect : &:r0_203, ~mu0_2 -# 831| mu0_214(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_208, ~mu0_2 +# 831| v0_212(void) = ^IndirectReadSideEffect : &:r0_208, ~mu0_2 +# 831| mu0_213(Derived) = ^IndirectMayWriteSideEffect : &:r0_203, ~mu0_2 +# 831| mu0_214(unknown) = ^BufferMayWriteSideEffect : &:r0_208, ~mu0_2 # 832| r0_215(glval) = VariableAddress[pb] : # 832| r0_216(Base *) = Load : &:r0_215, ~mu0_2 # 832| r0_217(Middle *) = ConvertToDerived[Middle : Base] : r0_216 @@ -3963,21 +3963,21 @@ ir.cpp: # 867| void String::String() # 867| Block 0 -# 867| v0_0(void) = EnterFunction : -# 867| mu0_1(unknown) = AliasedDefinition : -# 867| mu0_2(unknown) = UnmodeledDefinition : -# 867| r0_3(glval) = InitializeThis : -# 868| r0_4(glval) = FunctionAddress[String] : -# 868| r0_5(glval) = StringConstant[""] : -# 868| r0_6(char *) = Convert : r0_5 -# 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 -# 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 868| v0_9(void) = ^IndirectReadSideEffect[p#0] : &:r0_6, ~mu0_2 -# 868| mu0_10(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_6, ~mu0_2 -# 869| v0_11(void) = NoOp : -# 867| v0_12(void) = ReturnVoid : -# 867| v0_13(void) = UnmodeledUse : mu* -# 867| v0_14(void) = ExitFunction : +# 867| v0_0(void) = EnterFunction : +# 867| mu0_1(unknown) = AliasedDefinition : +# 867| mu0_2(unknown) = UnmodeledDefinition : +# 867| r0_3(glval) = InitializeThis : +# 868| r0_4(glval) = FunctionAddress[String] : +# 868| r0_5(glval) = StringConstant[""] : +# 868| r0_6(char *) = Convert : r0_5 +# 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 +# 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 +# 868| v0_9(void) = ^IndirectReadSideEffect : &:r0_6, ~mu0_2 +# 868| mu0_10(unknown) = ^BufferMayWriteSideEffect : &:r0_6, ~mu0_2 +# 869| v0_11(void) = NoOp : +# 867| v0_12(void) = ReturnVoid : +# 867| v0_13(void) = UnmodeledUse : mu* +# 867| v0_14(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 @@ -4149,67 +4149,67 @@ ir.cpp: # 940| void OperatorNew() # 940| Block 0 -# 940| v0_0(void) = EnterFunction : -# 940| mu0_1(unknown) = AliasedDefinition : -# 940| mu0_2(unknown) = UnmodeledDefinition : -# 941| r0_3(glval) = FunctionAddress[operator new] : -# 941| r0_4(unsigned long) = Constant[4] : -# 941| r0_5(void *) = Call : func:r0_3, 0:r0_4 -# 941| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 941| r0_7(int *) = Convert : r0_5 -# 942| r0_8(glval) = FunctionAddress[operator new] : -# 942| r0_9(unsigned long) = Constant[4] : -# 942| r0_10(float) = Constant[1.0] : -# 942| r0_11(void *) = Call : func:r0_8, 0:r0_9, 1:r0_10 -# 942| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 942| r0_13(int *) = Convert : r0_11 -# 943| r0_14(glval) = FunctionAddress[operator new] : -# 943| r0_15(unsigned long) = Constant[4] : -# 943| r0_16(void *) = Call : func:r0_14, 0:r0_15 -# 943| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 -# 943| r0_18(int *) = Convert : r0_16 -# 943| r0_19(int) = Constant[0] : -# 943| mu0_20(int) = Store : &:r0_18, r0_19 -# 944| r0_21(glval) = FunctionAddress[operator new] : -# 944| r0_22(unsigned long) = Constant[8] : -# 944| r0_23(void *) = Call : func:r0_21, 0:r0_22 -# 944| mu0_24(unknown) = ^CallSideEffect : ~mu0_2 -# 944| r0_25(String *) = Convert : r0_23 -# 944| r0_26(glval) = FunctionAddress[String] : -# 944| v0_27(void) = Call : func:r0_26, this:r0_25 -# 944| mu0_28(unknown) = ^CallSideEffect : ~mu0_2 -# 945| r0_29(glval) = FunctionAddress[operator new] : -# 945| r0_30(unsigned long) = Constant[8] : -# 945| r0_31(float) = Constant[1.0] : -# 945| r0_32(void *) = Call : func:r0_29, 0:r0_30, 1:r0_31 -# 945| mu0_33(unknown) = ^CallSideEffect : ~mu0_2 -# 945| r0_34(String *) = Convert : r0_32 -# 945| r0_35(glval) = FunctionAddress[String] : -# 945| r0_36(glval) = StringConstant["hello"] : -# 945| r0_37(char *) = Convert : r0_36 -# 945| v0_38(void) = Call : func:r0_35, this:r0_34, 0:r0_37 -# 945| mu0_39(unknown) = ^CallSideEffect : ~mu0_2 -# 945| v0_40(void) = ^IndirectReadSideEffect[p#0] : &:r0_37, ~mu0_2 -# 945| mu0_41(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_37, ~mu0_2 -# 946| r0_42(glval) = FunctionAddress[operator new] : -# 946| r0_43(unsigned long) = Constant[256] : -# 946| r0_44(align_val_t) = Constant[128] : -# 946| r0_45(void *) = Call : func:r0_42, 0:r0_43, 1:r0_44 -# 946| mu0_46(unknown) = ^CallSideEffect : ~mu0_2 -# 946| r0_47(Overaligned *) = Convert : r0_45 -# 947| r0_48(glval) = FunctionAddress[operator new] : -# 947| r0_49(unsigned long) = Constant[256] : -# 947| r0_50(align_val_t) = Constant[128] : -# 947| r0_51(float) = Constant[1.0] : -# 947| r0_52(void *) = Call : func:r0_48, 0:r0_49, 1:r0_50, 2:r0_51 -# 947| mu0_53(unknown) = ^CallSideEffect : ~mu0_2 -# 947| r0_54(Overaligned *) = Convert : r0_52 -# 947| r0_55(Overaligned) = Constant[0] : -# 947| mu0_56(Overaligned) = Store : &:r0_54, r0_55 -# 948| v0_57(void) = NoOp : -# 940| v0_58(void) = ReturnVoid : -# 940| v0_59(void) = UnmodeledUse : mu* -# 940| v0_60(void) = ExitFunction : +# 940| v0_0(void) = EnterFunction : +# 940| mu0_1(unknown) = AliasedDefinition : +# 940| mu0_2(unknown) = UnmodeledDefinition : +# 941| r0_3(glval) = FunctionAddress[operator new] : +# 941| r0_4(unsigned long) = Constant[4] : +# 941| r0_5(void *) = Call : func:r0_3, 0:r0_4 +# 941| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 +# 941| r0_7(int *) = Convert : r0_5 +# 942| r0_8(glval) = FunctionAddress[operator new] : +# 942| r0_9(unsigned long) = Constant[4] : +# 942| r0_10(float) = Constant[1.0] : +# 942| r0_11(void *) = Call : func:r0_8, 0:r0_9, 1:r0_10 +# 942| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 942| r0_13(int *) = Convert : r0_11 +# 943| r0_14(glval) = FunctionAddress[operator new] : +# 943| r0_15(unsigned long) = Constant[4] : +# 943| r0_16(void *) = Call : func:r0_14, 0:r0_15 +# 943| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 +# 943| r0_18(int *) = Convert : r0_16 +# 943| r0_19(int) = Constant[0] : +# 943| mu0_20(int) = Store : &:r0_18, r0_19 +# 944| r0_21(glval) = FunctionAddress[operator new] : +# 944| r0_22(unsigned long) = Constant[8] : +# 944| r0_23(void *) = Call : func:r0_21, 0:r0_22 +# 944| mu0_24(unknown) = ^CallSideEffect : ~mu0_2 +# 944| r0_25(String *) = Convert : r0_23 +# 944| r0_26(glval) = FunctionAddress[String] : +# 944| v0_27(void) = Call : func:r0_26, this:r0_25 +# 944| mu0_28(unknown) = ^CallSideEffect : ~mu0_2 +# 945| r0_29(glval) = FunctionAddress[operator new] : +# 945| r0_30(unsigned long) = Constant[8] : +# 945| r0_31(float) = Constant[1.0] : +# 945| r0_32(void *) = Call : func:r0_29, 0:r0_30, 1:r0_31 +# 945| mu0_33(unknown) = ^CallSideEffect : ~mu0_2 +# 945| r0_34(String *) = Convert : r0_32 +# 945| r0_35(glval) = FunctionAddress[String] : +# 945| r0_36(glval) = StringConstant["hello"] : +# 945| r0_37(char *) = Convert : r0_36 +# 945| v0_38(void) = Call : func:r0_35, this:r0_34, 0:r0_37 +# 945| mu0_39(unknown) = ^CallSideEffect : ~mu0_2 +# 945| v0_40(void) = ^IndirectReadSideEffect : &:r0_37, ~mu0_2 +# 945| mu0_41(unknown) = ^BufferMayWriteSideEffect : &:r0_37, ~mu0_2 +# 946| r0_42(glval) = FunctionAddress[operator new] : +# 946| r0_43(unsigned long) = Constant[256] : +# 946| r0_44(align_val_t) = Constant[128] : +# 946| r0_45(void *) = Call : func:r0_42, 0:r0_43, 1:r0_44 +# 946| mu0_46(unknown) = ^CallSideEffect : ~mu0_2 +# 946| r0_47(Overaligned *) = Convert : r0_45 +# 947| r0_48(glval) = FunctionAddress[operator new] : +# 947| r0_49(unsigned long) = Constant[256] : +# 947| r0_50(align_val_t) = Constant[128] : +# 947| r0_51(float) = Constant[1.0] : +# 947| r0_52(void *) = Call : func:r0_48, 0:r0_49, 1:r0_50, 2:r0_51 +# 947| mu0_53(unknown) = ^CallSideEffect : ~mu0_2 +# 947| r0_54(Overaligned *) = Convert : r0_52 +# 947| r0_55(Overaligned) = Constant[0] : +# 947| mu0_56(Overaligned) = Store : &:r0_54, r0_55 +# 948| v0_57(void) = NoOp : +# 940| v0_58(void) = ReturnVoid : +# 940| v0_59(void) = UnmodeledUse : mu* +# 940| v0_60(void) = ExitFunction : # 950| void OperatorNewArray(int) # 950| Block 0 @@ -4678,7 +4678,7 @@ ir.cpp: # 1035| r0_29(char) = Call : func:r0_27, this:r0_26, 0:r0_28 # 1035| mu0_30(unknown) = ^CallSideEffect : ~mu0_2 # 1035| v0_31(void) = ^IndirectReadSideEffect : &:r0_26, ~mu0_2 -# 1035| r0_32(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_26, ~mu0_2 +# 1035| mu0_32(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_26, ~mu0_2 # 1036| r0_33(glval) = VariableAddress[lambda_val] : # 1036| r0_34(glval) = FunctionAddress[(constructor)] : # 1036| r0_35(glval) = VariableAddress[#temp1036:21] : @@ -4694,8 +4694,8 @@ ir.cpp: # 1036| r0_45(decltype([...](...){...})) = Load : &:r0_35, ~mu0_2 # 1036| v0_46(void) = Call : func:r0_34, this:r0_33, 0:r0_45 # 1036| mu0_47(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| v0_48(void) = ^IndirectReadSideEffect[p#0] : &:r0_45, ~mu0_2 -# 1036| mu0_49(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_45, ~mu0_2 +# 1036| v0_48(void) = ^IndirectReadSideEffect : &:r0_45, ~mu0_2 +# 1036| mu0_49(unknown) = ^BufferMayWriteSideEffect : &:r0_45, ~mu0_2 # 1037| r0_50(glval) = VariableAddress[lambda_val] : # 1037| r0_51(glval) = Convert : r0_50 # 1037| r0_52(glval) = FunctionAddress[operator()] : @@ -4703,7 +4703,7 @@ ir.cpp: # 1037| r0_54(char) = Call : func:r0_52, this:r0_51, 0:r0_53 # 1037| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 # 1037| v0_56(void) = ^IndirectReadSideEffect : &:r0_51, ~mu0_2 -# 1037| r0_57(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_51, ~mu0_2 +# 1037| mu0_57(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_51, ~mu0_2 # 1038| r0_58(glval) = VariableAddress[lambda_ref_explicit] : # 1038| r0_59(glval) = VariableAddress[#temp1038:30] : # 1038| mu0_60(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_59 @@ -4720,7 +4720,7 @@ ir.cpp: # 1039| r0_71(char) = Call : func:r0_69, this:r0_68, 0:r0_70 # 1039| mu0_72(unknown) = ^CallSideEffect : ~mu0_2 # 1039| v0_73(void) = ^IndirectReadSideEffect : &:r0_68, ~mu0_2 -# 1039| r0_74(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_68, ~mu0_2 +# 1039| mu0_74(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_68, ~mu0_2 # 1040| r0_75(glval) = VariableAddress[lambda_val_explicit] : # 1040| r0_76(glval) = FunctionAddress[(constructor)] : # 1040| r0_77(glval) = VariableAddress[#temp1040:30] : @@ -4732,8 +4732,8 @@ ir.cpp: # 1040| r0_83(decltype([...](...){...})) = Load : &:r0_77, ~mu0_2 # 1040| v0_84(void) = Call : func:r0_76, this:r0_75, 0:r0_83 # 1040| mu0_85(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| v0_86(void) = ^IndirectReadSideEffect[p#0] : &:r0_83, ~mu0_2 -# 1040| mu0_87(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r0_83, ~mu0_2 +# 1040| v0_86(void) = ^IndirectReadSideEffect : &:r0_83, ~mu0_2 +# 1040| mu0_87(unknown) = ^BufferMayWriteSideEffect : &:r0_83, ~mu0_2 # 1041| r0_88(glval) = VariableAddress[lambda_val_explicit] : # 1041| r0_89(glval) = Convert : r0_88 # 1041| r0_90(glval) = FunctionAddress[operator()] : @@ -4741,7 +4741,7 @@ ir.cpp: # 1041| r0_92(char) = Call : func:r0_90, this:r0_89, 0:r0_91 # 1041| mu0_93(unknown) = ^CallSideEffect : ~mu0_2 # 1041| v0_94(void) = ^IndirectReadSideEffect : &:r0_89, ~mu0_2 -# 1041| r0_95(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_89, ~mu0_2 +# 1041| mu0_95(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_89, ~mu0_2 # 1042| r0_96(glval) = VariableAddress[lambda_mixed_explicit] : # 1042| r0_97(glval) = VariableAddress[#temp1042:32] : # 1042| mu0_98(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_97 @@ -4762,7 +4762,7 @@ ir.cpp: # 1043| r0_113(char) = Call : func:r0_111, this:r0_110, 0:r0_112 # 1043| mu0_114(unknown) = ^CallSideEffect : ~mu0_2 # 1043| v0_115(void) = ^IndirectReadSideEffect : &:r0_110, ~mu0_2 -# 1043| r0_116(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_110, ~mu0_2 +# 1043| mu0_116(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_110, ~mu0_2 # 1044| r0_117(glval) = VariableAddress[r] : # 1044| r0_118(glval) = VariableAddress[x] : # 1044| r0_119(int) = Load : &:r0_118, ~mu0_2 @@ -4798,7 +4798,7 @@ ir.cpp: # 1046| r0_149(char) = Call : func:r0_147, this:r0_146, 0:r0_148 # 1046| mu0_150(unknown) = ^CallSideEffect : ~mu0_2 # 1046| v0_151(void) = ^IndirectReadSideEffect : &:r0_146, ~mu0_2 -# 1046| r0_152(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_146, ~mu0_2 +# 1046| mu0_152(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_146, ~mu0_2 # 1047| v0_153(void) = NoOp : # 1031| v0_154(void) = ReturnVoid : # 1031| v0_155(void) = UnmodeledUse : mu* @@ -4863,7 +4863,7 @@ ir.cpp: # 1034| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1034| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 1034| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 -# 1034| r0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 +# 1034| mu0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 #-----| r0_15(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 #-----| r0_16(glval) = FieldAddress[x] : r0_15 #-----| r0_17(int &) = Load : &:r0_16, ~mu0_2 @@ -4906,7 +4906,7 @@ ir.cpp: # 1036| r0_10(char *) = Call : func:r0_9, this:r0_8 # 1036| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_12(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 -#-----| r0_13(String) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 +#-----| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 #-----| r0_14(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 #-----| r0_15(glval) = FieldAddress[x] : r0_14 #-----| r0_16(int) = Load : &:r0_15, ~mu0_2 @@ -4934,7 +4934,7 @@ ir.cpp: # 1038| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1038| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 1038| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 -# 1038| r0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 +# 1038| mu0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 # 1038| r0_15(int) = Constant[0] : # 1038| r0_16(glval) = PointerAdd[1] : r0_11, r0_15 # 1038| r0_17(char) = Load : &:r0_16, ~mu0_2 @@ -4991,7 +4991,7 @@ ir.cpp: # 1040| r0_10(char *) = Call : func:r0_9, this:r0_8 # 1040| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_12(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 -#-----| r0_13(String) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 +#-----| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 # 1040| r0_14(int) = Constant[0] : # 1040| r0_15(glval) = PointerAdd[1] : r0_10, r0_14 # 1040| r0_16(char) = Load : &:r0_15, ~mu0_2 @@ -5017,7 +5017,7 @@ ir.cpp: # 1042| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1042| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 1042| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 -# 1042| r0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 +# 1042| mu0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 #-----| r0_15(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 #-----| r0_16(glval) = FieldAddress[x] : r0_15 #-----| r0_17(int) = Load : &:r0_16, ~mu0_2 @@ -5045,7 +5045,7 @@ ir.cpp: # 1045| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1045| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 1045| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 -# 1045| r0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 +# 1045| mu0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 #-----| r0_15(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 #-----| r0_16(glval) = FieldAddress[x] : r0_15 #-----| r0_17(int) = Load : &:r0_16, ~mu0_2 @@ -5084,7 +5084,7 @@ ir.cpp: # 1069| r0_13(iterator) = Call : func:r0_12, this:r0_11 # 1069| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 -#-----| r0_16(vector) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 +#-----| mu0_16(vector) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 # 1069| mu0_17(iterator) = Store : &:r0_9, r0_13 # 1069| r0_18(glval) = VariableAddress[(__end)] : #-----| r0_19(glval &>) = VariableAddress[(__range)] : @@ -5093,7 +5093,7 @@ ir.cpp: # 1069| r0_22(iterator) = Call : func:r0_21, this:r0_20 # 1069| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_24(void) = ^IndirectReadSideEffect : &:r0_20, ~mu0_2 -#-----| r0_25(vector) = ^IndirectMayWriteSideEffect : &:r0_20, ~mu0_2 +#-----| mu0_25(vector) = ^IndirectMayWriteSideEffect : &:r0_20, ~mu0_2 # 1069| mu0_26(iterator) = Store : &:r0_18, r0_22 #-----| Goto -> Block 4 @@ -5105,7 +5105,7 @@ ir.cpp: # 1075| r1_4(int &) = Call : func:r1_3, this:r1_2 # 1075| mu1_5(unknown) = ^CallSideEffect : ~mu0_2 #-----| v1_6(void) = ^IndirectReadSideEffect : &:r1_2, ~mu0_2 -#-----| r1_7(iterator) = ^IndirectMayWriteSideEffect : &:r1_2, ~mu0_2 +#-----| mu1_7(iterator) = ^IndirectMayWriteSideEffect : &:r1_2, ~mu0_2 # 1075| r1_8(glval) = Convert : r1_4 # 1075| mu1_9(int &) = Store : &:r1_0, r1_8 # 1076| r1_10(glval) = VariableAddress[e] : @@ -5137,7 +5137,7 @@ ir.cpp: # 1069| r4_5(bool) = Call : func:r4_2, this:r4_1, 0:r4_4 # 1069| mu4_6(unknown) = ^CallSideEffect : ~mu0_2 #-----| v4_7(void) = ^IndirectReadSideEffect : &:r4_1, ~mu0_2 -#-----| r4_8(iterator) = ^IndirectMayWriteSideEffect : &:r4_1, ~mu0_2 +#-----| mu4_8(iterator) = ^IndirectMayWriteSideEffect : &:r4_1, ~mu0_2 # 1069| v4_9(void) = ConditionalBranch : r4_5 #-----| False -> Block 8 #-----| True -> Block 5 @@ -5150,7 +5150,7 @@ ir.cpp: # 1069| r5_4(int &) = Call : func:r5_3, this:r5_2 # 1069| mu5_5(unknown) = ^CallSideEffect : ~mu0_2 #-----| v5_6(void) = ^IndirectReadSideEffect : &:r5_2, ~mu0_2 -#-----| r5_7(iterator) = ^IndirectMayWriteSideEffect : &:r5_2, ~mu0_2 +#-----| mu5_7(iterator) = ^IndirectMayWriteSideEffect : &:r5_2, ~mu0_2 # 1069| r5_8(int) = Load : &:r5_4, ~mu0_2 # 1069| mu5_9(int) = Store : &:r5_0, r5_8 # 1070| r5_10(glval) = VariableAddress[e] : @@ -5172,7 +5172,7 @@ ir.cpp: # 1069| r7_3(iterator &) = Call : func:r7_2, this:r7_1 # 1069| mu7_4(unknown) = ^CallSideEffect : ~mu0_2 #-----| v7_5(void) = ^IndirectReadSideEffect : &:r7_1, ~mu0_2 -#-----| r7_6(iterator) = ^IndirectMayWriteSideEffect : &:r7_1, ~mu0_2 +#-----| mu7_6(iterator) = ^IndirectMayWriteSideEffect : &:r7_1, ~mu0_2 #-----| Goto (back edge) -> Block 4 # 1075| Block 8 @@ -5187,7 +5187,7 @@ ir.cpp: # 1075| r8_8(iterator) = Call : func:r8_7, this:r8_6 # 1075| mu8_9(unknown) = ^CallSideEffect : ~mu0_2 #-----| v8_10(void) = ^IndirectReadSideEffect : &:r8_6, ~mu0_2 -#-----| r8_11(vector) = ^IndirectMayWriteSideEffect : &:r8_6, ~mu0_2 +#-----| mu8_11(vector) = ^IndirectMayWriteSideEffect : &:r8_6, ~mu0_2 # 1075| mu8_12(iterator) = Store : &:r8_4, r8_8 # 1075| r8_13(glval) = VariableAddress[(__end)] : #-----| r8_14(glval &>) = VariableAddress[(__range)] : @@ -5196,7 +5196,7 @@ ir.cpp: # 1075| r8_17(iterator) = Call : func:r8_16, this:r8_15 # 1075| mu8_18(unknown) = ^CallSideEffect : ~mu0_2 #-----| v8_19(void) = ^IndirectReadSideEffect : &:r8_15, ~mu0_2 -#-----| r8_20(vector) = ^IndirectMayWriteSideEffect : &:r8_15, ~mu0_2 +#-----| mu8_20(vector) = ^IndirectMayWriteSideEffect : &:r8_15, ~mu0_2 # 1075| mu8_21(iterator) = Store : &:r8_13, r8_17 #-----| Goto -> Block 9 @@ -5209,7 +5209,7 @@ ir.cpp: # 1075| r9_5(bool) = Call : func:r9_2, this:r9_1, 0:r9_4 # 1075| mu9_6(unknown) = ^CallSideEffect : ~mu0_2 #-----| v9_7(void) = ^IndirectReadSideEffect : &:r9_1, ~mu0_2 -#-----| r9_8(iterator) = ^IndirectMayWriteSideEffect : &:r9_1, ~mu0_2 +#-----| mu9_8(iterator) = ^IndirectMayWriteSideEffect : &:r9_1, ~mu0_2 # 1075| v9_9(void) = ConditionalBranch : r9_5 #-----| False -> Block 3 #-----| True -> Block 1 @@ -5220,7 +5220,7 @@ ir.cpp: # 1075| r10_2(iterator &) = Call : func:r10_1, this:r10_0 # 1075| mu10_3(unknown) = ^CallSideEffect : ~mu0_2 #-----| v10_4(void) = ^IndirectReadSideEffect : &:r10_0, ~mu0_2 -#-----| r10_5(iterator) = ^IndirectMayWriteSideEffect : &:r10_0, ~mu0_2 +#-----| mu10_5(iterator) = ^IndirectMayWriteSideEffect : &:r10_0, ~mu0_2 #-----| Goto (back edge) -> Block 9 # 1099| int AsmStmt(int) @@ -5378,8 +5378,8 @@ ir.cpp: # 1140| r7_3(char *) = Convert : r7_2 # 1140| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 1140| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1140| v7_6(void) = ^IndirectReadSideEffect[p#0] : &:r7_3, ~mu0_2 -# 1140| mu7_7(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r7_3, ~mu0_2 +# 1140| v7_6(void) = ^IndirectReadSideEffect : &:r7_3, ~mu0_2 +# 1140| mu7_7(unknown) = ^BufferMayWriteSideEffect : &:r7_3, ~mu0_2 # 1140| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 @@ -5395,17 +5395,17 @@ ir.cpp: #-----| Goto -> Block 10 # 1144| Block 10 -# 1144| r10_0(glval) = VariableAddress[s] : -# 1144| mu10_1(char *) = InitializeParameter[s] : &:r10_0 -# 1145| r10_2(glval) = VariableAddress[#throw1145:5] : -# 1145| r10_3(glval) = FunctionAddress[String] : -# 1145| r10_4(glval) = VariableAddress[s] : -# 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2 -# 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 -# 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 1145| v10_8(void) = ^IndirectReadSideEffect[p#0] : &:r10_5, ~mu0_2 -# 1145| mu10_9(unknown) = ^BufferMayWriteSideEffect[p#0] : &:r10_5, ~mu0_2 -# 1145| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 +# 1144| r10_0(glval) = VariableAddress[s] : +# 1144| mu10_1(char *) = InitializeParameter[s] : &:r10_0 +# 1145| r10_2(glval) = VariableAddress[#throw1145:5] : +# 1145| r10_3(glval) = FunctionAddress[String] : +# 1145| r10_4(glval) = VariableAddress[s] : +# 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2 +# 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 +# 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 +# 1145| v10_8(void) = ^IndirectReadSideEffect : &:r10_5, ~mu0_2 +# 1145| mu10_9(unknown) = ^BufferMayWriteSideEffect : &:r10_5, ~mu0_2 +# 1145| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 # 1147| Block 11 @@ -5488,30 +5488,30 @@ ir.cpp: # 1163| int ModeledCallTarget(int) # 1163| Block 0 -# 1163| v0_0(void) = EnterFunction : -# 1163| mu0_1(unknown) = AliasedDefinition : -# 1163| mu0_2(unknown) = UnmodeledDefinition : -# 1163| r0_3(glval) = VariableAddress[x] : -# 1163| mu0_4(int) = InitializeParameter[x] : &:r0_3 -# 1164| r0_5(glval) = VariableAddress[y] : -# 1164| mu0_6(int) = Uninitialized[y] : &:r0_5 -# 1165| r0_7(glval) = FunctionAddress[memcpy] : -# 1165| r0_8(glval) = VariableAddress[y] : -# 1165| r0_9(void *) = Convert : r0_8 -# 1165| r0_10(glval) = VariableAddress[x] : -# 1165| r0_11(void *) = Convert : r0_10 -# 1165| r0_12(int) = Constant[4] : -# 1165| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12 -# 1165| v0_14(void) = ^BufferReadSideEffect[src] : &:r0_11, ~mu0_2 -# 1165| mu0_15(unknown) = ^BufferMustWriteSideEffect[dst] : &:r0_9 -# 1166| r0_16(glval) = VariableAddress[#return] : -# 1166| r0_17(glval) = VariableAddress[y] : -# 1166| r0_18(int) = Load : &:r0_17, ~mu0_2 -# 1166| mu0_19(int) = Store : &:r0_16, r0_18 -# 1163| r0_20(glval) = VariableAddress[#return] : -# 1163| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 -# 1163| v0_22(void) = UnmodeledUse : mu* -# 1163| v0_23(void) = ExitFunction : +# 1163| v0_0(void) = EnterFunction : +# 1163| mu0_1(unknown) = AliasedDefinition : +# 1163| mu0_2(unknown) = UnmodeledDefinition : +# 1163| r0_3(glval) = VariableAddress[x] : +# 1163| mu0_4(int) = InitializeParameter[x] : &:r0_3 +# 1164| r0_5(glval) = VariableAddress[y] : +# 1164| mu0_6(int) = Uninitialized[y] : &:r0_5 +# 1165| r0_7(glval) = FunctionAddress[memcpy] : +# 1165| r0_8(glval) = VariableAddress[y] : +# 1165| r0_9(void *) = Convert : r0_8 +# 1165| r0_10(glval) = VariableAddress[x] : +# 1165| r0_11(void *) = Convert : r0_10 +# 1165| r0_12(int) = Constant[4] : +# 1165| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12 +# 1165| v0_14(void) = ^BufferReadSideEffect : &:r0_11, ~mu0_2 +# 1165| mu0_15(unknown) = ^BufferMustWriteSideEffect : &:r0_9 +# 1166| r0_16(glval) = VariableAddress[#return] : +# 1166| r0_17(glval) = VariableAddress[y] : +# 1166| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 1166| mu0_19(int) = Store : &:r0_16, r0_18 +# 1163| r0_20(glval) = VariableAddress[#return] : +# 1163| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 +# 1163| v0_22(void) = UnmodeledUse : mu* +# 1163| v0_23(void) = ExitFunction : perf-regression.cpp: # 6| void Big::Big() 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 be108ae5084..69dabf45d07 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 @@ -311,29 +311,29 @@ ssa.cpp: # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 -# 95| v0_0(void) = EnterFunction : -# 95| m0_1(unknown) = AliasedDefinition : -# 95| mu0_2(unknown) = UnmodeledDefinition : -# 95| r0_3(glval) = VariableAddress[a] : -# 95| m0_4(Point) = InitializeParameter[a] : &:r0_3 -# 95| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 -# 96| r0_6(glval) = VariableAddress[b] : -# 96| r0_7(glval) = VariableAddress[a] : -# 96| r0_8(Point) = Load : &:r0_7, m0_4 -# 96| m0_9(Point) = Store : &:r0_6, r0_8 -# 97| r0_10(glval) = FunctionAddress[Escape] : -# 97| r0_11(glval) = VariableAddress[a] : -# 97| r0_12(void *) = Convert : r0_11 -# 97| v0_13(void) = Call : func:r0_10, 0:r0_12 -# 97| m0_14(unknown) = ^CallSideEffect : ~m0_5 -# 97| m0_15(unknown) = Chi : total:m0_5, partial:m0_14 -# 97| v0_16(void) = ^IndirectReadSideEffect[p] : &:r0_12, ~m0_15 -# 97| m0_17(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_12, ~m0_15 -# 97| m0_18(unknown) = Chi : total:m0_15, partial:m0_17 -# 98| v0_19(void) = NoOp : -# 95| v0_20(void) = ReturnVoid : -# 95| v0_21(void) = UnmodeledUse : mu* -# 95| v0_22(void) = ExitFunction : +# 95| v0_0(void) = EnterFunction : +# 95| m0_1(unknown) = AliasedDefinition : +# 95| mu0_2(unknown) = UnmodeledDefinition : +# 95| r0_3(glval) = VariableAddress[a] : +# 95| m0_4(Point) = InitializeParameter[a] : &:r0_3 +# 95| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 +# 96| r0_6(glval) = VariableAddress[b] : +# 96| r0_7(glval) = VariableAddress[a] : +# 96| r0_8(Point) = Load : &:r0_7, m0_4 +# 96| m0_9(Point) = Store : &:r0_6, r0_8 +# 97| r0_10(glval) = FunctionAddress[Escape] : +# 97| r0_11(glval) = VariableAddress[a] : +# 97| r0_12(void *) = Convert : r0_11 +# 97| v0_13(void) = Call : func:r0_10, 0:r0_12 +# 97| m0_14(unknown) = ^CallSideEffect : ~m0_5 +# 97| m0_15(unknown) = Chi : total:m0_5, partial:m0_14 +# 97| v0_16(void) = ^IndirectReadSideEffect : &:r0_12, ~m0_15 +# 97| m0_17(unknown) = ^BufferMayWriteSideEffect : &:r0_12, ~m0_15 +# 97| m0_18(unknown) = Chi : total:m0_15, partial:m0_17 +# 98| v0_19(void) = NoOp : +# 95| v0_20(void) = ReturnVoid : +# 95| v0_21(void) = UnmodeledUse : mu* +# 95| v0_22(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -359,35 +359,35 @@ ssa.cpp: # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 -# 105| v0_0(void) = EnterFunction : -# 105| m0_1(unknown) = AliasedDefinition : -# 105| mu0_2(unknown) = UnmodeledDefinition : -# 105| r0_3(glval) = VariableAddress[a] : -# 105| m0_4(Point) = InitializeParameter[a] : &:r0_3 -# 105| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 -# 106| r0_6(glval) = VariableAddress[x] : -# 106| r0_7(glval) = VariableAddress[a] : -# 106| r0_8(glval) = FieldAddress[x] : r0_7 -# 106| r0_9(int) = Load : &:r0_8, ~m0_4 -# 106| m0_10(int) = Store : &:r0_6, r0_9 -# 107| r0_11(glval) = VariableAddress[y] : -# 107| r0_12(glval) = VariableAddress[a] : -# 107| r0_13(glval) = FieldAddress[y] : r0_12 -# 107| r0_14(int) = Load : &:r0_13, ~m0_4 -# 107| m0_15(int) = Store : &:r0_11, r0_14 -# 108| r0_16(glval) = FunctionAddress[Escape] : -# 108| r0_17(glval) = VariableAddress[a] : -# 108| r0_18(void *) = Convert : r0_17 -# 108| v0_19(void) = Call : func:r0_16, 0:r0_18 -# 108| m0_20(unknown) = ^CallSideEffect : ~m0_5 -# 108| m0_21(unknown) = Chi : total:m0_5, partial:m0_20 -# 108| v0_22(void) = ^IndirectReadSideEffect[p] : &:r0_18, ~m0_21 -# 108| m0_23(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_18, ~m0_21 -# 108| m0_24(unknown) = Chi : total:m0_21, partial:m0_23 -# 109| v0_25(void) = NoOp : -# 105| v0_26(void) = ReturnVoid : -# 105| v0_27(void) = UnmodeledUse : mu* -# 105| v0_28(void) = ExitFunction : +# 105| v0_0(void) = EnterFunction : +# 105| m0_1(unknown) = AliasedDefinition : +# 105| mu0_2(unknown) = UnmodeledDefinition : +# 105| r0_3(glval) = VariableAddress[a] : +# 105| m0_4(Point) = InitializeParameter[a] : &:r0_3 +# 105| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 +# 106| r0_6(glval) = VariableAddress[x] : +# 106| r0_7(glval) = VariableAddress[a] : +# 106| r0_8(glval) = FieldAddress[x] : r0_7 +# 106| r0_9(int) = Load : &:r0_8, ~m0_4 +# 106| m0_10(int) = Store : &:r0_6, r0_9 +# 107| r0_11(glval) = VariableAddress[y] : +# 107| r0_12(glval) = VariableAddress[a] : +# 107| r0_13(glval) = FieldAddress[y] : r0_12 +# 107| r0_14(int) = Load : &:r0_13, ~m0_4 +# 107| m0_15(int) = Store : &:r0_11, r0_14 +# 108| r0_16(glval) = FunctionAddress[Escape] : +# 108| r0_17(glval) = VariableAddress[a] : +# 108| r0_18(void *) = Convert : r0_17 +# 108| v0_19(void) = Call : func:r0_16, 0:r0_18 +# 108| m0_20(unknown) = ^CallSideEffect : ~m0_5 +# 108| m0_21(unknown) = Chi : total:m0_5, partial:m0_20 +# 108| v0_22(void) = ^IndirectReadSideEffect : &:r0_18, ~m0_21 +# 108| m0_23(unknown) = ^BufferMayWriteSideEffect : &:r0_18, ~m0_21 +# 108| m0_24(unknown) = Chi : total:m0_21, partial:m0_23 +# 109| v0_25(void) = NoOp : +# 105| v0_26(void) = ReturnVoid : +# 105| v0_27(void) = UnmodeledUse : mu* +# 105| v0_28(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -421,43 +421,43 @@ ssa.cpp: # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 -# 116| v0_0(void) = EnterFunction : -# 116| m0_1(unknown) = AliasedDefinition : -# 116| mu0_2(unknown) = UnmodeledDefinition : -# 116| r0_3(glval) = VariableAddress[x] : -# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 -# 116| r0_5(glval) = VariableAddress[y] : -# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 -# 117| r0_7(glval) = VariableAddress[a] : -# 117| m0_8(Point) = Uninitialized[a] : &:r0_7 -# 117| m0_9(unknown) = Chi : total:m0_1, partial:m0_8 -# 117| r0_10(glval) = FieldAddress[x] : r0_7 -# 117| r0_11(glval) = VariableAddress[x] : -# 117| r0_12(int) = Load : &:r0_11, m0_4 -# 117| m0_13(int) = Store : &:r0_10, r0_12 -# 117| m0_14(unknown) = Chi : total:m0_9, partial:m0_13 -# 117| r0_15(glval) = FieldAddress[y] : r0_7 -# 117| r0_16(glval) = VariableAddress[y] : -# 117| r0_17(int) = Load : &:r0_16, m0_6 -# 117| m0_18(int) = Store : &:r0_15, r0_17 -# 117| m0_19(unknown) = Chi : total:m0_14, partial:m0_18 -# 118| r0_20(glval) = VariableAddress[b] : -# 118| r0_21(glval) = VariableAddress[a] : -# 118| r0_22(Point) = Load : &:r0_21, ~m0_19 -# 118| m0_23(Point) = Store : &:r0_20, r0_22 -# 119| r0_24(glval) = FunctionAddress[Escape] : -# 119| r0_25(glval) = VariableAddress[a] : -# 119| r0_26(void *) = Convert : r0_25 -# 119| v0_27(void) = Call : func:r0_24, 0:r0_26 -# 119| m0_28(unknown) = ^CallSideEffect : ~m0_19 -# 119| m0_29(unknown) = Chi : total:m0_19, partial:m0_28 -# 119| v0_30(void) = ^IndirectReadSideEffect[p] : &:r0_26, ~m0_29 -# 119| m0_31(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_26, ~m0_29 -# 119| m0_32(unknown) = Chi : total:m0_29, partial:m0_31 -# 120| v0_33(void) = NoOp : -# 116| v0_34(void) = ReturnVoid : -# 116| v0_35(void) = UnmodeledUse : mu* -# 116| v0_36(void) = ExitFunction : +# 116| v0_0(void) = EnterFunction : +# 116| m0_1(unknown) = AliasedDefinition : +# 116| mu0_2(unknown) = UnmodeledDefinition : +# 116| r0_3(glval) = VariableAddress[x] : +# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 +# 116| r0_5(glval) = VariableAddress[y] : +# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 +# 117| r0_7(glval) = VariableAddress[a] : +# 117| m0_8(Point) = Uninitialized[a] : &:r0_7 +# 117| m0_9(unknown) = Chi : total:m0_1, partial:m0_8 +# 117| r0_10(glval) = FieldAddress[x] : r0_7 +# 117| r0_11(glval) = VariableAddress[x] : +# 117| r0_12(int) = Load : &:r0_11, m0_4 +# 117| m0_13(int) = Store : &:r0_10, r0_12 +# 117| m0_14(unknown) = Chi : total:m0_9, partial:m0_13 +# 117| r0_15(glval) = FieldAddress[y] : r0_7 +# 117| r0_16(glval) = VariableAddress[y] : +# 117| r0_17(int) = Load : &:r0_16, m0_6 +# 117| m0_18(int) = Store : &:r0_15, r0_17 +# 117| m0_19(unknown) = Chi : total:m0_14, partial:m0_18 +# 118| r0_20(glval) = VariableAddress[b] : +# 118| r0_21(glval) = VariableAddress[a] : +# 118| r0_22(Point) = Load : &:r0_21, ~m0_19 +# 118| m0_23(Point) = Store : &:r0_20, r0_22 +# 119| r0_24(glval) = FunctionAddress[Escape] : +# 119| r0_25(glval) = VariableAddress[a] : +# 119| r0_26(void *) = Convert : r0_25 +# 119| v0_27(void) = Call : func:r0_24, 0:r0_26 +# 119| m0_28(unknown) = ^CallSideEffect : ~m0_19 +# 119| m0_29(unknown) = Chi : total:m0_19, partial:m0_28 +# 119| v0_30(void) = ^IndirectReadSideEffect : &:r0_26, ~m0_29 +# 119| m0_31(unknown) = ^BufferMayWriteSideEffect : &:r0_26, ~m0_29 +# 119| m0_32(unknown) = Chi : total:m0_29, partial:m0_31 +# 120| v0_33(void) = NoOp : +# 116| v0_34(void) = ReturnVoid : +# 116| v0_35(void) = UnmodeledUse : mu* +# 116| v0_36(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -819,30 +819,30 @@ ssa.cpp: # 207| int ModeledCallTarget(int) # 207| Block 0 -# 207| v0_0(void) = EnterFunction : -# 207| m0_1(unknown) = AliasedDefinition : -# 207| mu0_2(unknown) = UnmodeledDefinition : -# 207| r0_3(glval) = VariableAddress[x] : -# 207| m0_4(int) = InitializeParameter[x] : &:r0_3 -# 207| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 -# 208| r0_6(glval) = VariableAddress[y] : -# 208| m0_7(int) = Uninitialized[y] : &:r0_6 -# 208| m0_8(unknown) = Chi : total:m0_5, partial:m0_7 -# 209| r0_9(glval) = FunctionAddress[memcpy] : -# 209| r0_10(glval) = VariableAddress[y] : -# 209| r0_11(void *) = Convert : r0_10 -# 209| r0_12(glval) = VariableAddress[x] : -# 209| r0_13(void *) = Convert : r0_12 -# 209| r0_14(int) = Constant[4] : -# 209| r0_15(void *) = Call : func:r0_9, 0:r0_11, 1:r0_13, 2:r0_14 -# 209| v0_16(void) = ^BufferReadSideEffect[src] : &:r0_13, ~m0_4 -# 209| m0_17(unknown) = ^BufferMustWriteSideEffect[dst] : &:r0_11 -# 209| m0_18(unknown) = Chi : total:m0_8, partial:m0_17 -# 210| r0_19(glval) = VariableAddress[#return] : -# 210| r0_20(glval) = VariableAddress[y] : -# 210| r0_21(int) = Load : &:r0_20, ~m0_18 -# 210| m0_22(int) = Store : &:r0_19, r0_21 -# 207| r0_23(glval) = VariableAddress[#return] : -# 207| v0_24(void) = ReturnValue : &:r0_23, m0_22 -# 207| v0_25(void) = UnmodeledUse : mu* -# 207| v0_26(void) = ExitFunction : +# 207| v0_0(void) = EnterFunction : +# 207| m0_1(unknown) = AliasedDefinition : +# 207| mu0_2(unknown) = UnmodeledDefinition : +# 207| r0_3(glval) = VariableAddress[x] : +# 207| m0_4(int) = InitializeParameter[x] : &:r0_3 +# 207| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 +# 208| r0_6(glval) = VariableAddress[y] : +# 208| m0_7(int) = Uninitialized[y] : &:r0_6 +# 208| m0_8(unknown) = Chi : total:m0_5, partial:m0_7 +# 209| r0_9(glval) = FunctionAddress[memcpy] : +# 209| r0_10(glval) = VariableAddress[y] : +# 209| r0_11(void *) = Convert : r0_10 +# 209| r0_12(glval) = VariableAddress[x] : +# 209| r0_13(void *) = Convert : r0_12 +# 209| r0_14(int) = Constant[4] : +# 209| r0_15(void *) = Call : func:r0_9, 0:r0_11, 1:r0_13, 2:r0_14 +# 209| v0_16(void) = ^BufferReadSideEffect : &:r0_13, ~m0_4 +# 209| m0_17(unknown) = ^BufferMustWriteSideEffect : &:r0_11 +# 209| m0_18(unknown) = Chi : total:m0_8, partial:m0_17 +# 210| r0_19(glval) = VariableAddress[#return] : +# 210| r0_20(glval) = VariableAddress[y] : +# 210| r0_21(int) = Load : &:r0_20, ~m0_18 +# 210| m0_22(int) = Store : &:r0_19, r0_21 +# 207| r0_23(glval) = VariableAddress[#return] : +# 207| v0_24(void) = ReturnValue : &:r0_23, m0_22 +# 207| v0_25(void) = UnmodeledUse : mu* +# 207| v0_26(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index b9ee5be1e01..83b3d68bbc3 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -312,26 +312,26 @@ ssa.cpp: # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 -# 95| v0_0(void) = EnterFunction : -# 95| mu0_1(unknown) = AliasedDefinition : -# 95| mu0_2(unknown) = UnmodeledDefinition : -# 95| r0_3(glval) = VariableAddress[a] : -# 95| mu0_4(Point) = InitializeParameter[a] : &:r0_3 -# 96| r0_5(glval) = VariableAddress[b] : -# 96| r0_6(glval) = VariableAddress[a] : -# 96| r0_7(Point) = Load : &:r0_6, ~mu0_2 -# 96| m0_8(Point) = Store : &:r0_5, r0_7 -# 97| r0_9(glval) = FunctionAddress[Escape] : -# 97| r0_10(glval) = VariableAddress[a] : -# 97| r0_11(void *) = Convert : r0_10 -# 97| v0_12(void) = Call : func:r0_9, 0:r0_11 -# 97| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -# 97| v0_14(void) = ^IndirectReadSideEffect[p] : &:r0_11, ~mu0_2 -# 97| mu0_15(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_11, ~mu0_2 -# 98| v0_16(void) = NoOp : -# 95| v0_17(void) = ReturnVoid : -# 95| v0_18(void) = UnmodeledUse : mu* -# 95| v0_19(void) = ExitFunction : +# 95| v0_0(void) = EnterFunction : +# 95| mu0_1(unknown) = AliasedDefinition : +# 95| mu0_2(unknown) = UnmodeledDefinition : +# 95| r0_3(glval) = VariableAddress[a] : +# 95| mu0_4(Point) = InitializeParameter[a] : &:r0_3 +# 96| r0_5(glval) = VariableAddress[b] : +# 96| r0_6(glval) = VariableAddress[a] : +# 96| r0_7(Point) = Load : &:r0_6, ~mu0_2 +# 96| m0_8(Point) = Store : &:r0_5, r0_7 +# 97| r0_9(glval) = FunctionAddress[Escape] : +# 97| r0_10(glval) = VariableAddress[a] : +# 97| r0_11(void *) = Convert : r0_10 +# 97| v0_12(void) = Call : func:r0_9, 0:r0_11 +# 97| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +# 97| v0_14(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 +# 97| mu0_15(unknown) = ^BufferMayWriteSideEffect : &:r0_11, ~mu0_2 +# 98| v0_16(void) = NoOp : +# 95| v0_17(void) = ReturnVoid : +# 95| v0_18(void) = UnmodeledUse : mu* +# 95| v0_19(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -357,32 +357,32 @@ ssa.cpp: # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 -# 105| v0_0(void) = EnterFunction : -# 105| mu0_1(unknown) = AliasedDefinition : -# 105| mu0_2(unknown) = UnmodeledDefinition : -# 105| r0_3(glval) = VariableAddress[a] : -# 105| mu0_4(Point) = InitializeParameter[a] : &:r0_3 -# 106| r0_5(glval) = VariableAddress[x] : -# 106| r0_6(glval) = VariableAddress[a] : -# 106| r0_7(glval) = FieldAddress[x] : r0_6 -# 106| r0_8(int) = Load : &:r0_7, ~mu0_2 -# 106| m0_9(int) = Store : &:r0_5, r0_8 -# 107| r0_10(glval) = VariableAddress[y] : -# 107| r0_11(glval) = VariableAddress[a] : -# 107| r0_12(glval) = FieldAddress[y] : r0_11 -# 107| r0_13(int) = Load : &:r0_12, ~mu0_2 -# 107| m0_14(int) = Store : &:r0_10, r0_13 -# 108| r0_15(glval) = FunctionAddress[Escape] : -# 108| r0_16(glval) = VariableAddress[a] : -# 108| r0_17(void *) = Convert : r0_16 -# 108| v0_18(void) = Call : func:r0_15, 0:r0_17 -# 108| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 -# 108| v0_20(void) = ^IndirectReadSideEffect[p] : &:r0_17, ~mu0_2 -# 108| mu0_21(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_17, ~mu0_2 -# 109| v0_22(void) = NoOp : -# 105| v0_23(void) = ReturnVoid : -# 105| v0_24(void) = UnmodeledUse : mu* -# 105| v0_25(void) = ExitFunction : +# 105| v0_0(void) = EnterFunction : +# 105| mu0_1(unknown) = AliasedDefinition : +# 105| mu0_2(unknown) = UnmodeledDefinition : +# 105| r0_3(glval) = VariableAddress[a] : +# 105| mu0_4(Point) = InitializeParameter[a] : &:r0_3 +# 106| r0_5(glval) = VariableAddress[x] : +# 106| r0_6(glval) = VariableAddress[a] : +# 106| r0_7(glval) = FieldAddress[x] : r0_6 +# 106| r0_8(int) = Load : &:r0_7, ~mu0_2 +# 106| m0_9(int) = Store : &:r0_5, r0_8 +# 107| r0_10(glval) = VariableAddress[y] : +# 107| r0_11(glval) = VariableAddress[a] : +# 107| r0_12(glval) = FieldAddress[y] : r0_11 +# 107| r0_13(int) = Load : &:r0_12, ~mu0_2 +# 107| m0_14(int) = Store : &:r0_10, r0_13 +# 108| r0_15(glval) = FunctionAddress[Escape] : +# 108| r0_16(glval) = VariableAddress[a] : +# 108| r0_17(void *) = Convert : r0_16 +# 108| v0_18(void) = Call : func:r0_15, 0:r0_17 +# 108| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 +# 108| v0_20(void) = ^IndirectReadSideEffect : &:r0_17, ~mu0_2 +# 108| mu0_21(unknown) = ^BufferMayWriteSideEffect : &:r0_17, ~mu0_2 +# 109| v0_22(void) = NoOp : +# 105| v0_23(void) = ReturnVoid : +# 105| v0_24(void) = UnmodeledUse : mu* +# 105| v0_25(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -414,38 +414,38 @@ ssa.cpp: # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 -# 116| v0_0(void) = EnterFunction : -# 116| mu0_1(unknown) = AliasedDefinition : -# 116| mu0_2(unknown) = UnmodeledDefinition : -# 116| r0_3(glval) = VariableAddress[x] : -# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 -# 116| r0_5(glval) = VariableAddress[y] : -# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 -# 117| r0_7(glval) = VariableAddress[a] : -# 117| mu0_8(Point) = Uninitialized[a] : &:r0_7 -# 117| r0_9(glval) = FieldAddress[x] : r0_7 -# 117| r0_10(glval) = VariableAddress[x] : -# 117| r0_11(int) = Load : &:r0_10, m0_4 -# 117| mu0_12(int) = Store : &:r0_9, r0_11 -# 117| r0_13(glval) = FieldAddress[y] : r0_7 -# 117| r0_14(glval) = VariableAddress[y] : -# 117| r0_15(int) = Load : &:r0_14, m0_6 -# 117| mu0_16(int) = Store : &:r0_13, r0_15 -# 118| r0_17(glval) = VariableAddress[b] : -# 118| r0_18(glval) = VariableAddress[a] : -# 118| r0_19(Point) = Load : &:r0_18, ~mu0_2 -# 118| m0_20(Point) = Store : &:r0_17, r0_19 -# 119| r0_21(glval) = FunctionAddress[Escape] : -# 119| r0_22(glval) = VariableAddress[a] : -# 119| r0_23(void *) = Convert : r0_22 -# 119| v0_24(void) = Call : func:r0_21, 0:r0_23 -# 119| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 119| v0_26(void) = ^IndirectReadSideEffect[p] : &:r0_23, ~mu0_2 -# 119| mu0_27(unknown) = ^BufferMayWriteSideEffect[p] : &:r0_23, ~mu0_2 -# 120| v0_28(void) = NoOp : -# 116| v0_29(void) = ReturnVoid : -# 116| v0_30(void) = UnmodeledUse : mu* -# 116| v0_31(void) = ExitFunction : +# 116| v0_0(void) = EnterFunction : +# 116| mu0_1(unknown) = AliasedDefinition : +# 116| mu0_2(unknown) = UnmodeledDefinition : +# 116| r0_3(glval) = VariableAddress[x] : +# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 +# 116| r0_5(glval) = VariableAddress[y] : +# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 +# 117| r0_7(glval) = VariableAddress[a] : +# 117| mu0_8(Point) = Uninitialized[a] : &:r0_7 +# 117| r0_9(glval) = FieldAddress[x] : r0_7 +# 117| r0_10(glval) = VariableAddress[x] : +# 117| r0_11(int) = Load : &:r0_10, m0_4 +# 117| mu0_12(int) = Store : &:r0_9, r0_11 +# 117| r0_13(glval) = FieldAddress[y] : r0_7 +# 117| r0_14(glval) = VariableAddress[y] : +# 117| r0_15(int) = Load : &:r0_14, m0_6 +# 117| mu0_16(int) = Store : &:r0_13, r0_15 +# 118| r0_17(glval) = VariableAddress[b] : +# 118| r0_18(glval) = VariableAddress[a] : +# 118| r0_19(Point) = Load : &:r0_18, ~mu0_2 +# 118| m0_20(Point) = Store : &:r0_17, r0_19 +# 119| r0_21(glval) = FunctionAddress[Escape] : +# 119| r0_22(glval) = VariableAddress[a] : +# 119| r0_23(void *) = Convert : r0_22 +# 119| v0_24(void) = Call : func:r0_21, 0:r0_23 +# 119| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +# 119| v0_26(void) = ^IndirectReadSideEffect : &:r0_23, ~mu0_2 +# 119| mu0_27(unknown) = ^BufferMayWriteSideEffect : &:r0_23, ~mu0_2 +# 120| v0_28(void) = NoOp : +# 116| v0_29(void) = ReturnVoid : +# 116| v0_30(void) = UnmodeledUse : mu* +# 116| v0_31(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -782,27 +782,27 @@ ssa.cpp: # 207| int ModeledCallTarget(int) # 207| Block 0 -# 207| v0_0(void) = EnterFunction : -# 207| mu0_1(unknown) = AliasedDefinition : -# 207| mu0_2(unknown) = UnmodeledDefinition : -# 207| r0_3(glval) = VariableAddress[x] : -# 207| mu0_4(int) = InitializeParameter[x] : &:r0_3 -# 208| r0_5(glval) = VariableAddress[y] : -# 208| mu0_6(int) = Uninitialized[y] : &:r0_5 -# 209| r0_7(glval) = FunctionAddress[memcpy] : -# 209| r0_8(glval) = VariableAddress[y] : -# 209| r0_9(void *) = Convert : r0_8 -# 209| r0_10(glval) = VariableAddress[x] : -# 209| r0_11(void *) = Convert : r0_10 -# 209| r0_12(int) = Constant[4] : -# 209| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12 -# 209| v0_14(void) = ^BufferReadSideEffect[src] : &:r0_11, ~mu0_2 -# 209| mu0_15(unknown) = ^BufferMustWriteSideEffect[dst] : &:r0_9 -# 210| r0_16(glval) = VariableAddress[#return] : -# 210| r0_17(glval) = VariableAddress[y] : -# 210| r0_18(int) = Load : &:r0_17, ~mu0_2 -# 210| m0_19(int) = Store : &:r0_16, r0_18 -# 207| r0_20(glval) = VariableAddress[#return] : -# 207| v0_21(void) = ReturnValue : &:r0_20, m0_19 -# 207| v0_22(void) = UnmodeledUse : mu* -# 207| v0_23(void) = ExitFunction : +# 207| v0_0(void) = EnterFunction : +# 207| mu0_1(unknown) = AliasedDefinition : +# 207| mu0_2(unknown) = UnmodeledDefinition : +# 207| r0_3(glval) = VariableAddress[x] : +# 207| mu0_4(int) = InitializeParameter[x] : &:r0_3 +# 208| r0_5(glval) = VariableAddress[y] : +# 208| mu0_6(int) = Uninitialized[y] : &:r0_5 +# 209| r0_7(glval) = FunctionAddress[memcpy] : +# 209| r0_8(glval) = VariableAddress[y] : +# 209| r0_9(void *) = Convert : r0_8 +# 209| r0_10(glval) = VariableAddress[x] : +# 209| r0_11(void *) = Convert : r0_10 +# 209| r0_12(int) = Constant[4] : +# 209| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12 +# 209| v0_14(void) = ^BufferReadSideEffect : &:r0_11, ~mu0_2 +# 209| mu0_15(unknown) = ^BufferMustWriteSideEffect : &:r0_9 +# 210| r0_16(glval) = VariableAddress[#return] : +# 210| r0_17(glval) = VariableAddress[y] : +# 210| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 210| m0_19(int) = Store : &:r0_16, r0_18 +# 207| r0_20(glval) = VariableAddress[#return] : +# 207| v0_21(void) = ReturnValue : &:r0_20, m0_19 +# 207| v0_22(void) = UnmodeledUse : mu* +# 207| v0_23(void) = ExitFunction : From 8649978a43ebb0ce71dd72564d3048367f34c3c9 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 17 Sep 2019 16:41:23 -0700 Subject: [PATCH 0307/1227] C++: add indexes for specific side effects --- .../aliased_ssa/Instruction.qll | 11 + .../aliased_ssa/internal/SSAConstruction.qll | 5 + .../ir/implementation/internal/OperandTag.qll | 2 + .../cpp/ir/implementation/raw/Instruction.qll | 11 + .../raw/internal/IRConstruction.qll | 8 + .../raw/internal/TranslatedCall.qll | 44 +- .../raw/internal/TranslatedElement.qll | 6 + .../unaliased_ssa/Instruction.qll | 11 + .../internal/SSAConstruction.qll | 5 + .../cpp/models/implementations/Memcpy.qll | 9 +- .../code/cpp/models/interfaces/SideEffect.qll | 4 +- .../test/library-tests/ir/ir/raw_ir.expected | 1096 ++++++++--------- .../ir/ssa/aliased_ssa_ir.expected | 232 ++-- .../ir/ssa/unaliased_ssa_ir.expected | 204 +-- .../code/csharp/ir/implementation/Opcode.qll | 26 +- .../ir/implementation/internal/OperandTag.qll | 4 +- .../ir/implementation/raw/Instruction.qll | 62 +- .../csharp/ir/implementation/raw/Operand.qll | 10 + 18 files changed, 966 insertions(+), 784 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 4ccb0bb8c22..61a3885521d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -644,6 +644,17 @@ class ConstantValueInstruction extends Instruction { final string getValue() { result = value } } +class IndexedInstruction extends Instruction { + int index; + + IndexedInstruction() { index = Construction::getInstructionIndex(this) } + + + final override string getImmediateString() { result = index.toString() } + + final int getIndex() { result = index } +} + class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 1ca6e099795..0fb6676bb42 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -342,6 +342,11 @@ private module Cached { result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() } + cached + int getInstructionIndex(Instruction instruction) { + result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() + } + cached Function getInstructionFunction(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll index 32d17bc2905..227b1a34041 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll @@ -72,6 +72,8 @@ class BufferSizeOperandTag extends RegisterOperandTag, TBufferSizeOperand { final override int getSortOrder() { result = 1 } } +BufferSizeOperandTag bufferSizeOperand() { result = TBufferSizeOperand() } + /** * The operand representing the read side effect of a `SideEffectInstruction`. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 4ccb0bb8c22..61a3885521d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -644,6 +644,17 @@ class ConstantValueInstruction extends Instruction { final string getValue() { result = value } } +class IndexedInstruction extends Instruction { + int index; + + IndexedInstruction() { index = Construction::getInstructionIndex(this) } + + + final override string getImmediateString() { result = index.toString() } + + final int getIndex() { result = index } +} + class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 43283db2bc1..314eda43a4c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -259,6 +259,14 @@ private module Cached { .getInstructionConstantValue(getInstructionTag(instruction)) } + cached + int getInstructionIndex(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getInstructionIndex(tag) + ) + } + cached StringLiteral getInstructionStringLiteral(Instruction instruction) { result = getInstructionTranslatedElement(instruction) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 58ffdabeca2..8f3deca1cac 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -456,6 +456,12 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff operandTag instanceof SideEffectOperandTag and call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(index, _) and result = getEnclosingFunction().getUnmodeledDefinitionInstruction() + or + tag instanceof OnlyInstructionTag and + operandTag instanceof BufferSizeOperandTag and + result = getTranslatedExpr(call + .getArgument(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index)).getFullyConverted()) + .getResult() } override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { @@ -471,15 +477,26 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff predicate hasSpecificWriteSideEffect(Opcode op) { exists(boolean buffer, boolean mustWrite | - call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(index, buffer, mustWrite) and - ( - buffer = true and mustWrite = false and op instanceof Opcode::BufferMayWriteSideEffect - or - buffer = false and mustWrite = false and op instanceof Opcode::IndirectMayWriteSideEffect - or - buffer = true and mustWrite = true and op instanceof Opcode::BufferMustWriteSideEffect - or - buffer = false and mustWrite = true and op instanceof Opcode::IndirectMustWriteSideEffect + if exists(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index)) + then + call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(index, true, mustWrite) and + buffer = true and + ( + mustWrite = false and op instanceof Opcode::SizedBufferMayWriteSideEffect + or + mustWrite = true and op instanceof Opcode::SizedBufferMustWriteSideEffect + ) + else ( + call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(index, buffer, mustWrite) and + ( + buffer = true and mustWrite = false and op instanceof Opcode::BufferMayWriteSideEffect + or + buffer = false and mustWrite = false and op instanceof Opcode::IndirectMayWriteSideEffect + or + buffer = true and mustWrite = true and op instanceof Opcode::BufferMustWriteSideEffect + or + buffer = false and mustWrite = true and op instanceof Opcode::IndirectMustWriteSideEffect + ) ) ) or @@ -495,7 +512,9 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff predicate hasSpecificReadSideEffect(Opcode op) { exists(boolean buffer | call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(index, buffer) and - ( + if exists(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index)) + then buffer = true and op instanceof Opcode::SizedBufferReadSideEffect + else ( buffer = true and op instanceof Opcode::BufferReadSideEffect or buffer = false and op instanceof Opcode::IndirectReadSideEffect @@ -506,6 +525,11 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff op instanceof Opcode::IndirectReadSideEffect } + final override int getInstructionIndex(InstructionTag tag) { + tag = OnlyInstructionTag() and + result = index + } + /** * Gets the `TranslatedFunction` containing this expression. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 2304d85d7ad..01ed6a4d591 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -600,6 +600,12 @@ abstract class TranslatedElement extends TTranslatedElement { */ string getInstructionConstantValue(InstructionTag tag) { none() } + /** + * If the instruction specified by `tag` is an `IndexedInstruction`, gets the + * index for that instruction. + */ + int getInstructionIndex(InstructionTag tag) { none() } + /** * If the instruction specified by `tag` is a `PointerArithmeticInstruction`, * gets the size of the type pointed to by the pointer. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 4ccb0bb8c22..61a3885521d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -644,6 +644,17 @@ class ConstantValueInstruction extends Instruction { final string getValue() { result = value } } +class IndexedInstruction extends Instruction { + int index; + + IndexedInstruction() { index = Construction::getInstructionIndex(this) } + + + final override string getImmediateString() { result = index.toString() } + + final int getIndex() { result = index } +} + class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 1ca6e099795..0fb6676bb42 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -342,6 +342,11 @@ private module Cached { result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() } + cached + int getInstructionIndex(Instruction instruction) { + result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() + } + cached Function getInstructionFunction(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() 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 71ad3317e2d..0951daea11b 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll @@ -57,5 +57,12 @@ class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { i = 1 and buffer = true } -} + override ParameterIndex getParameterSizeIndex(ParameterIndex i) { + result = 2 and + ( + i = 0 or + i = 1 + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll index 156b57e4fdd..e13123d1025 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll @@ -34,5 +34,7 @@ abstract class SideEffectFunction extends Function { } predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { none() } -} + // TODO: name? + ParameterIndex getParameterSizeIndex(ParameterIndex i) { none() } +} diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 34c81febf78..16bf7da8507 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -14,8 +14,8 @@ bad_asts.cpp: # 16| r0_10(int) = Constant[1] : # 16| r0_11(int) = Call : func:r0_9, this:r0_8, 0:r0_10 # 16| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 16| v0_13(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 -# 16| mu0_14(S) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 +# 16| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_8, ~mu0_2 +# 16| mu0_14(S) = ^IndirectMayWriteSideEffect[-1] : &:r0_8, ~mu0_2 # 17| v0_15(void) = NoOp : # 14| v0_16(void) = ReturnVoid : # 14| v0_17(void) = UnmodeledUse : mu* @@ -2675,10 +2675,10 @@ ir.cpp: # 585| r0_8(char *) = Convert : r0_7 # 585| v0_9(void) = Call : func:r0_3, 0:r0_5, 1:r0_6, 2:r0_8 # 585| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 585| v0_11(void) = ^IndirectReadSideEffect : &:r0_5, ~mu0_2 -# 585| v0_12(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 -# 585| mu0_13(unknown) = ^BufferMayWriteSideEffect : &:r0_5, ~mu0_2 -# 585| mu0_14(unknown) = ^BufferMayWriteSideEffect : &:r0_8, ~mu0_2 +# 585| v0_11(void) = ^IndirectReadSideEffect[0] : &:r0_5, ~mu0_2 +# 585| v0_12(void) = ^IndirectReadSideEffect[2] : &:r0_8, ~mu0_2 +# 585| mu0_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_5, ~mu0_2 +# 585| mu0_14(unknown) = ^BufferMayWriteSideEffect[2] : &:r0_8, ~mu0_2 # 586| v0_15(void) = NoOp : # 584| v0_16(void) = ReturnVoid : # 584| v0_17(void) = UnmodeledUse : mu* @@ -2721,8 +2721,8 @@ ir.cpp: # 617| r0_10(char *) = Convert : r0_9 # 617| v0_11(void) = Call : func:r0_8, this:r0_7, 0:r0_10 # 617| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 617| v0_13(void) = ^IndirectReadSideEffect : &:r0_10, ~mu0_2 -# 617| mu0_14(unknown) = ^BufferMayWriteSideEffect : &:r0_10, ~mu0_2 +# 617| v0_13(void) = ^IndirectReadSideEffect[0] : &:r0_10, ~mu0_2 +# 617| mu0_14(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_10, ~mu0_2 # 618| r0_15(glval) = VariableAddress[s3] : # 618| r0_16(glval) = FunctionAddress[ReturnObject] : # 618| r0_17(String) = Call : func:r0_16 @@ -2734,8 +2734,8 @@ ir.cpp: # 619| r0_23(char *) = Convert : r0_22 # 619| v0_24(void) = Call : func:r0_21, this:r0_20, 0:r0_23 # 619| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 619| v0_26(void) = ^IndirectReadSideEffect : &:r0_23, ~mu0_2 -# 619| mu0_27(unknown) = ^BufferMayWriteSideEffect : &:r0_23, ~mu0_2 +# 619| v0_26(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 +# 619| mu0_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23, ~mu0_2 # 620| v0_28(void) = NoOp : # 615| v0_29(void) = ReturnVoid : # 615| v0_30(void) = UnmodeledUse : mu* @@ -2743,42 +2743,42 @@ ir.cpp: # 622| void CallMethods(String&, String*, String) # 622| Block 0 -# 622| v0_0(void) = EnterFunction : -# 622| mu0_1(unknown) = AliasedDefinition : -# 622| mu0_2(unknown) = UnmodeledDefinition : -# 622| r0_3(glval) = VariableAddress[r] : -# 622| mu0_4(String &) = InitializeParameter[r] : &:r0_3 -# 622| r0_5(glval) = VariableAddress[p] : -# 622| mu0_6(String *) = InitializeParameter[p] : &:r0_5 -# 622| r0_7(glval) = VariableAddress[s] : -# 622| mu0_8(String) = InitializeParameter[s] : &:r0_7 -# 623| r0_9(glval) = VariableAddress[r] : -# 623| r0_10(String &) = Load : &:r0_9, ~mu0_2 -# 623| r0_11(glval) = Convert : r0_10 -# 623| r0_12(glval) = FunctionAddress[c_str] : -# 623| r0_13(char *) = Call : func:r0_12, this:r0_11 -# 623| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 -# 623| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 -# 623| mu0_16(String) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 -# 624| r0_17(glval) = VariableAddress[p] : -# 624| r0_18(String *) = Load : &:r0_17, ~mu0_2 -# 624| r0_19(String *) = Convert : r0_18 -# 624| r0_20(glval) = FunctionAddress[c_str] : -# 624| r0_21(char *) = Call : func:r0_20, this:r0_19 -# 624| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -# 624| v0_23(void) = ^IndirectReadSideEffect : &:r0_19, ~mu0_2 -# 624| mu0_24(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 -# 625| r0_25(glval) = VariableAddress[s] : -# 625| r0_26(glval) = Convert : r0_25 -# 625| r0_27(glval) = FunctionAddress[c_str] : -# 625| r0_28(char *) = Call : func:r0_27, this:r0_26 -# 625| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 -# 625| v0_30(void) = ^IndirectReadSideEffect : &:r0_26, ~mu0_2 -# 625| mu0_31(String) = ^IndirectMayWriteSideEffect : &:r0_26, ~mu0_2 -# 626| v0_32(void) = NoOp : -# 622| v0_33(void) = ReturnVoid : -# 622| v0_34(void) = UnmodeledUse : mu* -# 622| v0_35(void) = ExitFunction : +# 622| v0_0(void) = EnterFunction : +# 622| mu0_1(unknown) = AliasedDefinition : +# 622| mu0_2(unknown) = UnmodeledDefinition : +# 622| r0_3(glval) = VariableAddress[r] : +# 622| mu0_4(String &) = InitializeParameter[r] : &:r0_3 +# 622| r0_5(glval) = VariableAddress[p] : +# 622| mu0_6(String *) = InitializeParameter[p] : &:r0_5 +# 622| r0_7(glval) = VariableAddress[s] : +# 622| mu0_8(String) = InitializeParameter[s] : &:r0_7 +# 623| r0_9(glval) = VariableAddress[r] : +# 623| r0_10(String &) = Load : &:r0_9, ~mu0_2 +# 623| r0_11(glval) = Convert : r0_10 +# 623| r0_12(glval) = FunctionAddress[c_str] : +# 623| r0_13(char *) = Call : func:r0_12, this:r0_11 +# 623| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 +# 623| v0_15(void) = ^IndirectReadSideEffect[-1] : &:r0_11, ~mu0_2 +# 623| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_11, ~mu0_2 +# 624| r0_17(glval) = VariableAddress[p] : +# 624| r0_18(String *) = Load : &:r0_17, ~mu0_2 +# 624| r0_19(String *) = Convert : r0_18 +# 624| r0_20(glval) = FunctionAddress[c_str] : +# 624| r0_21(char *) = Call : func:r0_20, this:r0_19 +# 624| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 +# 624| v0_23(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~mu0_2 +# 624| mu0_24(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19, ~mu0_2 +# 625| r0_25(glval) = VariableAddress[s] : +# 625| r0_26(glval) = Convert : r0_25 +# 625| r0_27(glval) = FunctionAddress[c_str] : +# 625| r0_28(char *) = Call : func:r0_27, this:r0_26 +# 625| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 +# 625| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_26, ~mu0_2 +# 625| mu0_31(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_26, ~mu0_2 +# 626| v0_32(void) = NoOp : +# 622| v0_33(void) = ReturnVoid : +# 622| v0_34(void) = UnmodeledUse : mu* +# 622| v0_35(void) = ExitFunction : # 630| int C::StaticMemberFunction(int) # 630| Block 0 @@ -2881,22 +2881,22 @@ ir.cpp: # 653| r0_6(int) = Constant[0] : # 653| r0_7(int) = Call : func:r0_5, this:r0_4, 0:r0_6 # 653| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 653| v0_9(void) = ^IndirectReadSideEffect : &:r0_4, ~mu0_2 -# 653| mu0_10(C) = ^IndirectMayWriteSideEffect : &:r0_4, ~mu0_2 +# 653| v0_9(void) = ^IndirectReadSideEffect[-1] : &:r0_4, ~mu0_2 +# 653| mu0_10(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_4, ~mu0_2 # 654| r0_11(C *) = CopyValue : r0_3 # 654| r0_12(glval) = FunctionAddress[InstanceMemberFunction] : # 654| r0_13(int) = Constant[1] : # 654| r0_14(int) = Call : func:r0_12, this:r0_11, 0:r0_13 # 654| mu0_15(unknown) = ^CallSideEffect : ~mu0_2 -# 654| v0_16(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 -# 654| mu0_17(C) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 +# 654| v0_16(void) = ^IndirectReadSideEffect[-1] : &:r0_11, ~mu0_2 +# 654| mu0_17(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_11, ~mu0_2 #-----| r0_18(C *) = CopyValue : r0_3 # 655| r0_19(glval) = FunctionAddress[InstanceMemberFunction] : # 655| r0_20(int) = Constant[2] : # 655| r0_21(int) = Call : func:r0_19, this:r0_18, 0:r0_20 # 655| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_23(void) = ^IndirectReadSideEffect : &:r0_18, ~mu0_2 -#-----| mu0_24(C) = ^IndirectMayWriteSideEffect : &:r0_18, ~mu0_2 +#-----| v0_23(void) = ^IndirectReadSideEffect[-1] : &:r0_18, ~mu0_2 +#-----| mu0_24(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_18, ~mu0_2 # 656| v0_25(void) = NoOp : # 652| v0_26(void) = ReturnVoid : # 652| v0_27(void) = UnmodeledUse : mu* @@ -2904,35 +2904,35 @@ ir.cpp: # 658| void C::C() # 658| Block 0 -# 658| v0_0(void) = EnterFunction : -# 658| mu0_1(unknown) = AliasedDefinition : -# 658| mu0_2(unknown) = UnmodeledDefinition : -# 658| r0_3(glval) = InitializeThis : -# 659| r0_4(glval) = FieldAddress[m_a] : r0_3 -# 659| r0_5(int) = Constant[1] : -# 659| mu0_6(int) = Store : &:r0_4, r0_5 -# 663| r0_7(glval) = FieldAddress[m_b] : r0_3 -# 663| r0_8(glval) = FunctionAddress[String] : -# 663| v0_9(void) = Call : func:r0_8, this:r0_7 -# 663| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 660| r0_11(glval) = FieldAddress[m_c] : r0_3 -# 660| r0_12(char) = Constant[3] : -# 660| mu0_13(char) = Store : &:r0_11, r0_12 -# 661| r0_14(glval) = FieldAddress[m_e] : r0_3 -# 661| r0_15(void *) = Constant[0] : -# 661| mu0_16(void *) = Store : &:r0_14, r0_15 -# 662| r0_17(glval) = FieldAddress[m_f] : r0_3 -# 662| r0_18(glval) = FunctionAddress[String] : -# 662| r0_19(glval) = StringConstant["test"] : -# 662| r0_20(char *) = Convert : r0_19 -# 662| v0_21(void) = Call : func:r0_18, this:r0_17, 0:r0_20 -# 662| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -# 662| v0_23(void) = ^IndirectReadSideEffect : &:r0_20, ~mu0_2 -# 662| mu0_24(unknown) = ^BufferMayWriteSideEffect : &:r0_20, ~mu0_2 -# 664| v0_25(void) = NoOp : -# 658| v0_26(void) = ReturnVoid : -# 658| v0_27(void) = UnmodeledUse : mu* -# 658| v0_28(void) = ExitFunction : +# 658| v0_0(void) = EnterFunction : +# 658| mu0_1(unknown) = AliasedDefinition : +# 658| mu0_2(unknown) = UnmodeledDefinition : +# 658| r0_3(glval) = InitializeThis : +# 659| r0_4(glval) = FieldAddress[m_a] : r0_3 +# 659| r0_5(int) = Constant[1] : +# 659| mu0_6(int) = Store : &:r0_4, r0_5 +# 663| r0_7(glval) = FieldAddress[m_b] : r0_3 +# 663| r0_8(glval) = FunctionAddress[String] : +# 663| v0_9(void) = Call : func:r0_8, this:r0_7 +# 663| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 +# 660| r0_11(glval) = FieldAddress[m_c] : r0_3 +# 660| r0_12(char) = Constant[3] : +# 660| mu0_13(char) = Store : &:r0_11, r0_12 +# 661| r0_14(glval) = FieldAddress[m_e] : r0_3 +# 661| r0_15(void *) = Constant[0] : +# 661| mu0_16(void *) = Store : &:r0_14, r0_15 +# 662| r0_17(glval) = FieldAddress[m_f] : r0_3 +# 662| r0_18(glval) = FunctionAddress[String] : +# 662| r0_19(glval) = StringConstant["test"] : +# 662| r0_20(char *) = Convert : r0_19 +# 662| v0_21(void) = Call : func:r0_18, this:r0_17, 0:r0_20 +# 662| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 +# 662| v0_23(void) = ^IndirectReadSideEffect[0] : &:r0_20, ~mu0_2 +# 662| mu0_24(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_20, ~mu0_2 +# 664| v0_25(void) = NoOp : +# 658| v0_26(void) = ReturnVoid : +# 658| v0_27(void) = UnmodeledUse : mu* +# 658| v0_28(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 @@ -3118,23 +3118,23 @@ ir.cpp: # 720| double CallNestedTemplateFunc() # 720| Block 0 -# 720| v0_0(void) = EnterFunction : -# 720| mu0_1(unknown) = AliasedDefinition : -# 720| mu0_2(unknown) = UnmodeledDefinition : -# 721| r0_3(glval) = VariableAddress[#return] : -# 721| r0_4(glval) = FunctionAddress[Func] : -# 721| r0_5(void *) = Constant[0] : -# 721| r0_6(char) = Constant[111] : -# 721| r0_7(long) = Call : func:r0_4, 0:r0_5, 1:r0_6 -# 721| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 721| v0_9(void) = ^IndirectReadSideEffect : &:r0_5, ~mu0_2 -# 721| mu0_10(unknown) = ^BufferMayWriteSideEffect : &:r0_5, ~mu0_2 -# 721| r0_11(double) = Convert : r0_7 -# 721| mu0_12(double) = Store : &:r0_3, r0_11 -# 720| r0_13(glval) = VariableAddress[#return] : -# 720| v0_14(void) = ReturnValue : &:r0_13, ~mu0_2 -# 720| v0_15(void) = UnmodeledUse : mu* -# 720| v0_16(void) = ExitFunction : +# 720| v0_0(void) = EnterFunction : +# 720| mu0_1(unknown) = AliasedDefinition : +# 720| mu0_2(unknown) = UnmodeledDefinition : +# 721| r0_3(glval) = VariableAddress[#return] : +# 721| r0_4(glval) = FunctionAddress[Func] : +# 721| r0_5(void *) = Constant[0] : +# 721| r0_6(char) = Constant[111] : +# 721| r0_7(long) = Call : func:r0_4, 0:r0_5, 1:r0_6 +# 721| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 +# 721| v0_9(void) = ^IndirectReadSideEffect[0] : &:r0_5, ~mu0_2 +# 721| mu0_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_5, ~mu0_2 +# 721| r0_11(double) = Convert : r0_7 +# 721| mu0_12(double) = Store : &:r0_3, r0_11 +# 720| r0_13(glval) = VariableAddress[#return] : +# 720| v0_14(void) = ReturnValue : &:r0_13, ~mu0_2 +# 720| v0_15(void) = UnmodeledUse : mu* +# 720| v0_16(void) = ExitFunction : # 724| void TryCatch(bool) # 724| Block 0 @@ -3201,8 +3201,8 @@ ir.cpp: # 731| r7_3(char *) = Convert : r7_2 # 731| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 731| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 731| v7_6(void) = ^IndirectReadSideEffect : &:r7_3, ~mu0_2 -# 731| mu7_7(unknown) = ^BufferMayWriteSideEffect : &:r7_3, ~mu0_2 +# 731| v7_6(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 +# 731| mu7_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3, ~mu0_2 # 731| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 @@ -3226,8 +3226,8 @@ ir.cpp: # 736| r10_5(char *) = Load : &:r10_4, ~mu0_2 # 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 # 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 736| v10_8(void) = ^IndirectReadSideEffect : &:r10_5, ~mu0_2 -# 736| mu10_9(unknown) = ^BufferMayWriteSideEffect : &:r10_5, ~mu0_2 +# 736| v10_8(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 +# 736| mu10_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5, ~mu0_2 # 736| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 @@ -3254,31 +3254,31 @@ ir.cpp: # 745| Base& Base::operator=(Base const&) # 745| Block 0 -# 745| v0_0(void) = EnterFunction : -# 745| mu0_1(unknown) = AliasedDefinition : -# 745| mu0_2(unknown) = UnmodeledDefinition : -# 745| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 -#-----| r0_6(Base *) = CopyValue : r0_3 -#-----| r0_7(glval) = FieldAddress[base_s] : r0_6 -# 745| r0_8(glval) = FunctionAddress[operator=] : -#-----| r0_9(glval) = VariableAddress[p#0] : -#-----| r0_10(Base &) = Load : &:r0_9, ~mu0_2 -#-----| r0_11(glval) = FieldAddress[base_s] : r0_10 -# 745| r0_12(String &) = Call : func:r0_8, this:r0_7, 0:r0_11 -# 745| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 -#-----| mu0_16(String) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect : &:r0_11, ~mu0_2 -#-----| r0_18(glval) = VariableAddress[#return] : -#-----| r0_19(Base *) = CopyValue : r0_3 -#-----| mu0_20(Base &) = Store : &:r0_18, r0_19 -# 745| r0_21(glval) = VariableAddress[#return] : -# 745| v0_22(void) = ReturnValue : &:r0_21, ~mu0_2 -# 745| v0_23(void) = UnmodeledUse : mu* -# 745| v0_24(void) = ExitFunction : +# 745| v0_0(void) = EnterFunction : +# 745| mu0_1(unknown) = AliasedDefinition : +# 745| mu0_2(unknown) = UnmodeledDefinition : +# 745| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 +#-----| r0_6(Base *) = CopyValue : r0_3 +#-----| r0_7(glval) = FieldAddress[base_s] : r0_6 +# 745| r0_8(glval) = FunctionAddress[operator=] : +#-----| r0_9(glval) = VariableAddress[p#0] : +#-----| r0_10(Base &) = Load : &:r0_9, ~mu0_2 +#-----| r0_11(glval) = FieldAddress[base_s] : r0_10 +# 745| r0_12(String &) = Call : func:r0_8, this:r0_7, 0:r0_11 +# 745| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 +#-----| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_7, ~mu0_2 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11, ~mu0_2 +#-----| r0_18(glval) = VariableAddress[#return] : +#-----| r0_19(Base *) = CopyValue : r0_3 +#-----| mu0_20(Base &) = Store : &:r0_18, r0_19 +# 745| r0_21(glval) = VariableAddress[#return] : +# 745| v0_22(void) = ReturnValue : &:r0_21, ~mu0_2 +# 745| v0_23(void) = UnmodeledUse : mu* +# 745| v0_24(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 @@ -3329,43 +3329,43 @@ ir.cpp: # 754| Middle& Middle::operator=(Middle const&) # 754| Block 0 -# 754| v0_0(void) = EnterFunction : -# 754| mu0_1(unknown) = AliasedDefinition : -# 754| mu0_2(unknown) = UnmodeledDefinition : -# 754| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(Middle &) = InitializeParameter[p#0] : &:r0_4 -#-----| r0_6(Middle *) = CopyValue : r0_3 -#-----| r0_7(Base *) = ConvertToBase[Middle : Base] : r0_6 -# 754| r0_8(glval) = FunctionAddress[operator=] : -#-----| r0_9(glval) = VariableAddress[p#0] : -#-----| r0_10(Middle &) = Load : &:r0_9, ~mu0_2 -#-----| r0_11(Base *) = ConvertToBase[Middle : Base] : r0_10 -# 754| r0_12(Base &) = Call : func:r0_8, this:r0_7, 0:r0_11 -# 754| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 -#-----| mu0_16(Base) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect : &:r0_11, ~mu0_2 -#-----| r0_18(Middle *) = CopyValue : r0_3 -#-----| r0_19(glval) = FieldAddress[middle_s] : r0_18 -# 754| r0_20(glval) = FunctionAddress[operator=] : -#-----| r0_21(glval) = VariableAddress[p#0] : -#-----| r0_22(Middle &) = Load : &:r0_21, ~mu0_2 -#-----| r0_23(glval) = FieldAddress[middle_s] : r0_22 -# 754| r0_24(String &) = Call : func:r0_20, this:r0_19, 0:r0_23 -# 754| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_26(void) = ^IndirectReadSideEffect : &:r0_19, ~mu0_2 -#-----| v0_27(void) = ^IndirectReadSideEffect : &:r0_23, ~mu0_2 -#-----| mu0_28(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 -#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect : &:r0_23, ~mu0_2 -#-----| r0_30(glval) = VariableAddress[#return] : -#-----| r0_31(Middle *) = CopyValue : r0_3 -#-----| mu0_32(Middle &) = Store : &:r0_30, r0_31 -# 754| r0_33(glval) = VariableAddress[#return] : -# 754| v0_34(void) = ReturnValue : &:r0_33, ~mu0_2 -# 754| v0_35(void) = UnmodeledUse : mu* -# 754| v0_36(void) = ExitFunction : +# 754| v0_0(void) = EnterFunction : +# 754| mu0_1(unknown) = AliasedDefinition : +# 754| mu0_2(unknown) = UnmodeledDefinition : +# 754| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(Middle &) = InitializeParameter[p#0] : &:r0_4 +#-----| r0_6(Middle *) = CopyValue : r0_3 +#-----| r0_7(Base *) = ConvertToBase[Middle : Base] : r0_6 +# 754| r0_8(glval) = FunctionAddress[operator=] : +#-----| r0_9(glval) = VariableAddress[p#0] : +#-----| r0_10(Middle &) = Load : &:r0_9, ~mu0_2 +#-----| r0_11(Base *) = ConvertToBase[Middle : Base] : r0_10 +# 754| r0_12(Base &) = Call : func:r0_8, this:r0_7, 0:r0_11 +# 754| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 +#-----| mu0_16(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_7, ~mu0_2 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11, ~mu0_2 +#-----| r0_18(Middle *) = CopyValue : r0_3 +#-----| r0_19(glval) = FieldAddress[middle_s] : r0_18 +# 754| r0_20(glval) = FunctionAddress[operator=] : +#-----| r0_21(glval) = VariableAddress[p#0] : +#-----| r0_22(Middle &) = Load : &:r0_21, ~mu0_2 +#-----| r0_23(glval) = FieldAddress[middle_s] : r0_22 +# 754| r0_24(String &) = Call : func:r0_20, this:r0_19, 0:r0_23 +# 754| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_26(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~mu0_2 +#-----| v0_27(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 +#-----| mu0_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19, ~mu0_2 +#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23, ~mu0_2 +#-----| r0_30(glval) = VariableAddress[#return] : +#-----| r0_31(Middle *) = CopyValue : r0_3 +#-----| mu0_32(Middle &) = Store : &:r0_30, r0_31 +# 754| r0_33(glval) = VariableAddress[#return] : +# 754| v0_34(void) = ReturnValue : &:r0_33, ~mu0_2 +# 754| v0_35(void) = UnmodeledUse : mu* +# 754| v0_36(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 @@ -3421,10 +3421,10 @@ ir.cpp: #-----| r0_11(Middle *) = ConvertToBase[Derived : Middle] : r0_10 # 763| r0_12(Middle &) = Call : func:r0_8, this:r0_7, 0:r0_11 # 763| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_14(void) = ^IndirectReadSideEffect : &:r0_7, ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 -#-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect : &:r0_7, ~mu0_2 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect : &:r0_11, ~mu0_2 +#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 +#-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_7, ~mu0_2 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11, ~mu0_2 #-----| r0_18(Derived *) = CopyValue : r0_3 #-----| r0_19(glval) = FieldAddress[derived_s] : r0_18 # 763| r0_20(glval) = FunctionAddress[operator=] : @@ -3433,10 +3433,10 @@ ir.cpp: #-----| r0_23(glval) = FieldAddress[derived_s] : r0_22 # 763| r0_24(String &) = Call : func:r0_20, this:r0_19, 0:r0_23 # 763| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_26(void) = ^IndirectReadSideEffect : &:r0_19, ~mu0_2 -#-----| v0_27(void) = ^IndirectReadSideEffect : &:r0_23, ~mu0_2 -#-----| mu0_28(String) = ^IndirectMayWriteSideEffect : &:r0_19, ~mu0_2 -#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect : &:r0_23, ~mu0_2 +#-----| v0_26(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~mu0_2 +#-----| v0_27(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 +#-----| mu0_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19, ~mu0_2 +#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23, ~mu0_2 #-----| r0_30(glval) = VariableAddress[#return] : #-----| r0_31(Derived *) = CopyValue : r0_3 #-----| mu0_32(Derived &) = Store : &:r0_30, r0_31 @@ -3645,10 +3645,10 @@ ir.cpp: # 808| r0_27(glval) = ConvertToBase[Middle : Base] : r0_26 # 808| r0_28(Base &) = Call : func:r0_25, this:r0_24, 0:r0_27 # 808| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 -# 808| v0_30(void) = ^IndirectReadSideEffect : &:r0_24, ~mu0_2 -# 808| v0_31(void) = ^IndirectReadSideEffect : &:r0_27, ~mu0_2 -# 808| mu0_32(Base) = ^IndirectMayWriteSideEffect : &:r0_24, ~mu0_2 -# 808| mu0_33(unknown) = ^BufferMayWriteSideEffect : &:r0_27, ~mu0_2 +# 808| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_24, ~mu0_2 +# 808| v0_31(void) = ^IndirectReadSideEffect[0] : &:r0_27, ~mu0_2 +# 808| mu0_32(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_24, ~mu0_2 +# 808| mu0_33(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_27, ~mu0_2 # 809| r0_34(glval) = VariableAddress[b] : # 809| r0_35(glval) = FunctionAddress[operator=] : # 809| r0_36(glval) = FunctionAddress[Base] : @@ -3656,15 +3656,15 @@ ir.cpp: # 809| r0_38(glval) = ConvertToBase[Middle : Base] : r0_37 # 809| v0_39(void) = Call : func:r0_36, 0:r0_38 # 809| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 -# 809| v0_41(void) = ^IndirectReadSideEffect : &:r0_38, ~mu0_2 -# 809| mu0_42(unknown) = ^BufferMayWriteSideEffect : &:r0_38, ~mu0_2 +# 809| v0_41(void) = ^IndirectReadSideEffect[0] : &:r0_38, ~mu0_2 +# 809| mu0_42(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_38, ~mu0_2 # 809| r0_43(glval) = Convert : v0_39 # 809| r0_44(Base &) = Call : func:r0_35, this:r0_34, 0:r0_43 # 809| mu0_45(unknown) = ^CallSideEffect : ~mu0_2 -# 809| v0_46(void) = ^IndirectReadSideEffect : &:r0_34, ~mu0_2 -# 809| v0_47(void) = ^IndirectReadSideEffect : &:r0_43, ~mu0_2 -# 809| mu0_48(Base) = ^IndirectMayWriteSideEffect : &:r0_34, ~mu0_2 -# 809| mu0_49(unknown) = ^BufferMayWriteSideEffect : &:r0_43, ~mu0_2 +# 809| v0_46(void) = ^IndirectReadSideEffect[-1] : &:r0_34, ~mu0_2 +# 809| v0_47(void) = ^IndirectReadSideEffect[0] : &:r0_43, ~mu0_2 +# 809| mu0_48(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_34, ~mu0_2 +# 809| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_43, ~mu0_2 # 810| r0_50(glval) = VariableAddress[b] : # 810| r0_51(glval) = FunctionAddress[operator=] : # 810| r0_52(glval) = FunctionAddress[Base] : @@ -3672,15 +3672,15 @@ ir.cpp: # 810| r0_54(glval) = ConvertToBase[Middle : Base] : r0_53 # 810| v0_55(void) = Call : func:r0_52, 0:r0_54 # 810| mu0_56(unknown) = ^CallSideEffect : ~mu0_2 -# 810| v0_57(void) = ^IndirectReadSideEffect : &:r0_54, ~mu0_2 -# 810| mu0_58(unknown) = ^BufferMayWriteSideEffect : &:r0_54, ~mu0_2 +# 810| v0_57(void) = ^IndirectReadSideEffect[0] : &:r0_54, ~mu0_2 +# 810| mu0_58(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_54, ~mu0_2 # 810| r0_59(glval) = Convert : v0_55 # 810| r0_60(Base &) = Call : func:r0_51, this:r0_50, 0:r0_59 # 810| mu0_61(unknown) = ^CallSideEffect : ~mu0_2 -# 810| v0_62(void) = ^IndirectReadSideEffect : &:r0_50, ~mu0_2 -# 810| v0_63(void) = ^IndirectReadSideEffect : &:r0_59, ~mu0_2 -# 810| mu0_64(Base) = ^IndirectMayWriteSideEffect : &:r0_50, ~mu0_2 -# 810| mu0_65(unknown) = ^BufferMayWriteSideEffect : &:r0_59, ~mu0_2 +# 810| v0_62(void) = ^IndirectReadSideEffect[-1] : &:r0_50, ~mu0_2 +# 810| v0_63(void) = ^IndirectReadSideEffect[0] : &:r0_59, ~mu0_2 +# 810| mu0_64(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_50, ~mu0_2 +# 810| mu0_65(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_59, ~mu0_2 # 811| r0_66(glval) = VariableAddress[pm] : # 811| r0_67(Middle *) = Load : &:r0_66, ~mu0_2 # 811| r0_68(Base *) = ConvertToBase[Middle : Base] : r0_67 @@ -3708,10 +3708,10 @@ ir.cpp: # 816| r0_90(glval) = Convert : r0_89 # 816| r0_91(Middle &) = Call : func:r0_87, this:r0_86, 0:r0_90 # 816| mu0_92(unknown) = ^CallSideEffect : ~mu0_2 -# 816| v0_93(void) = ^IndirectReadSideEffect : &:r0_86, ~mu0_2 -# 816| v0_94(void) = ^IndirectReadSideEffect : &:r0_90, ~mu0_2 -# 816| mu0_95(Middle) = ^IndirectMayWriteSideEffect : &:r0_86, ~mu0_2 -# 816| mu0_96(unknown) = ^BufferMayWriteSideEffect : &:r0_90, ~mu0_2 +# 816| v0_93(void) = ^IndirectReadSideEffect[-1] : &:r0_86, ~mu0_2 +# 816| v0_94(void) = ^IndirectReadSideEffect[0] : &:r0_90, ~mu0_2 +# 816| mu0_95(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_86, ~mu0_2 +# 816| mu0_96(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_90, ~mu0_2 # 817| r0_97(glval) = VariableAddress[m] : # 817| r0_98(glval) = FunctionAddress[operator=] : # 817| r0_99(glval) = VariableAddress[b] : @@ -3719,10 +3719,10 @@ ir.cpp: # 817| r0_101(glval) = Convert : r0_100 # 817| r0_102(Middle &) = Call : func:r0_98, this:r0_97, 0:r0_101 # 817| mu0_103(unknown) = ^CallSideEffect : ~mu0_2 -# 817| v0_104(void) = ^IndirectReadSideEffect : &:r0_97, ~mu0_2 -# 817| v0_105(void) = ^IndirectReadSideEffect : &:r0_101, ~mu0_2 -# 817| mu0_106(Middle) = ^IndirectMayWriteSideEffect : &:r0_97, ~mu0_2 -# 817| mu0_107(unknown) = ^BufferMayWriteSideEffect : &:r0_101, ~mu0_2 +# 817| v0_104(void) = ^IndirectReadSideEffect[-1] : &:r0_97, ~mu0_2 +# 817| v0_105(void) = ^IndirectReadSideEffect[0] : &:r0_101, ~mu0_2 +# 817| mu0_106(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_97, ~mu0_2 +# 817| mu0_107(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_101, ~mu0_2 # 818| r0_108(glval) = VariableAddress[pb] : # 818| r0_109(Base *) = Load : &:r0_108, ~mu0_2 # 818| r0_110(Middle *) = ConvertToDerived[Middle : Base] : r0_109 @@ -3745,10 +3745,10 @@ ir.cpp: # 822| r0_127(glval) = ConvertToBase[Middle : Base] : r0_126 # 822| r0_128(Base &) = Call : func:r0_124, this:r0_123, 0:r0_127 # 822| mu0_129(unknown) = ^CallSideEffect : ~mu0_2 -# 822| v0_130(void) = ^IndirectReadSideEffect : &:r0_123, ~mu0_2 -# 822| v0_131(void) = ^IndirectReadSideEffect : &:r0_127, ~mu0_2 -# 822| mu0_132(Base) = ^IndirectMayWriteSideEffect : &:r0_123, ~mu0_2 -# 822| mu0_133(unknown) = ^BufferMayWriteSideEffect : &:r0_127, ~mu0_2 +# 822| v0_130(void) = ^IndirectReadSideEffect[-1] : &:r0_123, ~mu0_2 +# 822| v0_131(void) = ^IndirectReadSideEffect[0] : &:r0_127, ~mu0_2 +# 822| mu0_132(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_123, ~mu0_2 +# 822| mu0_133(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_127, ~mu0_2 # 823| r0_134(glval) = VariableAddress[b] : # 823| r0_135(glval) = FunctionAddress[operator=] : # 823| r0_136(glval) = FunctionAddress[Base] : @@ -3757,15 +3757,15 @@ ir.cpp: # 823| r0_139(glval) = ConvertToBase[Middle : Base] : r0_138 # 823| v0_140(void) = Call : func:r0_136, 0:r0_139 # 823| mu0_141(unknown) = ^CallSideEffect : ~mu0_2 -# 823| v0_142(void) = ^IndirectReadSideEffect : &:r0_139, ~mu0_2 -# 823| mu0_143(unknown) = ^BufferMayWriteSideEffect : &:r0_139, ~mu0_2 +# 823| v0_142(void) = ^IndirectReadSideEffect[0] : &:r0_139, ~mu0_2 +# 823| mu0_143(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_139, ~mu0_2 # 823| r0_144(glval) = Convert : v0_140 # 823| r0_145(Base &) = Call : func:r0_135, this:r0_134, 0:r0_144 # 823| mu0_146(unknown) = ^CallSideEffect : ~mu0_2 -# 823| v0_147(void) = ^IndirectReadSideEffect : &:r0_134, ~mu0_2 -# 823| v0_148(void) = ^IndirectReadSideEffect : &:r0_144, ~mu0_2 -# 823| mu0_149(Base) = ^IndirectMayWriteSideEffect : &:r0_134, ~mu0_2 -# 823| mu0_150(unknown) = ^BufferMayWriteSideEffect : &:r0_144, ~mu0_2 +# 823| v0_147(void) = ^IndirectReadSideEffect[-1] : &:r0_134, ~mu0_2 +# 823| v0_148(void) = ^IndirectReadSideEffect[0] : &:r0_144, ~mu0_2 +# 823| mu0_149(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_134, ~mu0_2 +# 823| mu0_150(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_144, ~mu0_2 # 824| r0_151(glval) = VariableAddress[b] : # 824| r0_152(glval) = FunctionAddress[operator=] : # 824| r0_153(glval) = FunctionAddress[Base] : @@ -3774,15 +3774,15 @@ ir.cpp: # 824| r0_156(glval) = ConvertToBase[Middle : Base] : r0_155 # 824| v0_157(void) = Call : func:r0_153, 0:r0_156 # 824| mu0_158(unknown) = ^CallSideEffect : ~mu0_2 -# 824| v0_159(void) = ^IndirectReadSideEffect : &:r0_156, ~mu0_2 -# 824| mu0_160(unknown) = ^BufferMayWriteSideEffect : &:r0_156, ~mu0_2 +# 824| v0_159(void) = ^IndirectReadSideEffect[0] : &:r0_156, ~mu0_2 +# 824| mu0_160(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_156, ~mu0_2 # 824| r0_161(glval) = Convert : v0_157 # 824| r0_162(Base &) = Call : func:r0_152, this:r0_151, 0:r0_161 # 824| mu0_163(unknown) = ^CallSideEffect : ~mu0_2 -# 824| v0_164(void) = ^IndirectReadSideEffect : &:r0_151, ~mu0_2 -# 824| v0_165(void) = ^IndirectReadSideEffect : &:r0_161, ~mu0_2 -# 824| mu0_166(Base) = ^IndirectMayWriteSideEffect : &:r0_151, ~mu0_2 -# 824| mu0_167(unknown) = ^BufferMayWriteSideEffect : &:r0_161, ~mu0_2 +# 824| v0_164(void) = ^IndirectReadSideEffect[-1] : &:r0_151, ~mu0_2 +# 824| v0_165(void) = ^IndirectReadSideEffect[0] : &:r0_161, ~mu0_2 +# 824| mu0_166(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_151, ~mu0_2 +# 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_161, ~mu0_2 # 825| r0_168(glval) = VariableAddress[pd] : # 825| r0_169(Derived *) = Load : &:r0_168, ~mu0_2 # 825| r0_170(Middle *) = ConvertToBase[Derived : Middle] : r0_169 @@ -3814,10 +3814,10 @@ ir.cpp: # 830| r0_196(glval) = Convert : r0_195 # 830| r0_197(Derived &) = Call : func:r0_192, this:r0_191, 0:r0_196 # 830| mu0_198(unknown) = ^CallSideEffect : ~mu0_2 -# 830| v0_199(void) = ^IndirectReadSideEffect : &:r0_191, ~mu0_2 -# 830| v0_200(void) = ^IndirectReadSideEffect : &:r0_196, ~mu0_2 -# 830| mu0_201(Derived) = ^IndirectMayWriteSideEffect : &:r0_191, ~mu0_2 -# 830| mu0_202(unknown) = ^BufferMayWriteSideEffect : &:r0_196, ~mu0_2 +# 830| v0_199(void) = ^IndirectReadSideEffect[-1] : &:r0_191, ~mu0_2 +# 830| v0_200(void) = ^IndirectReadSideEffect[0] : &:r0_196, ~mu0_2 +# 830| mu0_201(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_191, ~mu0_2 +# 830| mu0_202(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_196, ~mu0_2 # 831| r0_203(glval) = VariableAddress[d] : # 831| r0_204(glval) = FunctionAddress[operator=] : # 831| r0_205(glval) = VariableAddress[b] : @@ -3826,10 +3826,10 @@ ir.cpp: # 831| r0_208(glval) = Convert : r0_207 # 831| r0_209(Derived &) = Call : func:r0_204, this:r0_203, 0:r0_208 # 831| mu0_210(unknown) = ^CallSideEffect : ~mu0_2 -# 831| v0_211(void) = ^IndirectReadSideEffect : &:r0_203, ~mu0_2 -# 831| v0_212(void) = ^IndirectReadSideEffect : &:r0_208, ~mu0_2 -# 831| mu0_213(Derived) = ^IndirectMayWriteSideEffect : &:r0_203, ~mu0_2 -# 831| mu0_214(unknown) = ^BufferMayWriteSideEffect : &:r0_208, ~mu0_2 +# 831| v0_211(void) = ^IndirectReadSideEffect[-1] : &:r0_203, ~mu0_2 +# 831| v0_212(void) = ^IndirectReadSideEffect[0] : &:r0_208, ~mu0_2 +# 831| mu0_213(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_203, ~mu0_2 +# 831| mu0_214(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_208, ~mu0_2 # 832| r0_215(glval) = VariableAddress[pb] : # 832| r0_216(Base *) = Load : &:r0_215, ~mu0_2 # 832| r0_217(Middle *) = ConvertToDerived[Middle : Base] : r0_216 @@ -3963,21 +3963,21 @@ ir.cpp: # 867| void String::String() # 867| Block 0 -# 867| v0_0(void) = EnterFunction : -# 867| mu0_1(unknown) = AliasedDefinition : -# 867| mu0_2(unknown) = UnmodeledDefinition : -# 867| r0_3(glval) = InitializeThis : -# 868| r0_4(glval) = FunctionAddress[String] : -# 868| r0_5(glval) = StringConstant[""] : -# 868| r0_6(char *) = Convert : r0_5 -# 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 -# 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 868| v0_9(void) = ^IndirectReadSideEffect : &:r0_6, ~mu0_2 -# 868| mu0_10(unknown) = ^BufferMayWriteSideEffect : &:r0_6, ~mu0_2 -# 869| v0_11(void) = NoOp : -# 867| v0_12(void) = ReturnVoid : -# 867| v0_13(void) = UnmodeledUse : mu* -# 867| v0_14(void) = ExitFunction : +# 867| v0_0(void) = EnterFunction : +# 867| mu0_1(unknown) = AliasedDefinition : +# 867| mu0_2(unknown) = UnmodeledDefinition : +# 867| r0_3(glval) = InitializeThis : +# 868| r0_4(glval) = FunctionAddress[String] : +# 868| r0_5(glval) = StringConstant[""] : +# 868| r0_6(char *) = Convert : r0_5 +# 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 +# 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 +# 868| v0_9(void) = ^IndirectReadSideEffect[0] : &:r0_6, ~mu0_2 +# 868| mu0_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6, ~mu0_2 +# 869| v0_11(void) = NoOp : +# 867| v0_12(void) = ReturnVoid : +# 867| v0_13(void) = UnmodeledUse : mu* +# 867| v0_14(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 @@ -4189,8 +4189,8 @@ ir.cpp: # 945| r0_37(char *) = Convert : r0_36 # 945| v0_38(void) = Call : func:r0_35, this:r0_34, 0:r0_37 # 945| mu0_39(unknown) = ^CallSideEffect : ~mu0_2 -# 945| v0_40(void) = ^IndirectReadSideEffect : &:r0_37, ~mu0_2 -# 945| mu0_41(unknown) = ^BufferMayWriteSideEffect : &:r0_37, ~mu0_2 +# 945| v0_40(void) = ^IndirectReadSideEffect[0] : &:r0_37, ~mu0_2 +# 945| mu0_41(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_37, ~mu0_2 # 946| r0_42(glval) = FunctionAddress[operator new] : # 946| r0_43(unsigned long) = Constant[256] : # 946| r0_44(align_val_t) = Constant[128] : @@ -4677,8 +4677,8 @@ ir.cpp: # 1035| r0_28(float) = Constant[1.0] : # 1035| r0_29(char) = Call : func:r0_27, this:r0_26, 0:r0_28 # 1035| mu0_30(unknown) = ^CallSideEffect : ~mu0_2 -# 1035| v0_31(void) = ^IndirectReadSideEffect : &:r0_26, ~mu0_2 -# 1035| mu0_32(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_26, ~mu0_2 +# 1035| v0_31(void) = ^IndirectReadSideEffect[-1] : &:r0_26, ~mu0_2 +# 1035| mu0_32(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_26, ~mu0_2 # 1036| r0_33(glval) = VariableAddress[lambda_val] : # 1036| r0_34(glval) = FunctionAddress[(constructor)] : # 1036| r0_35(glval) = VariableAddress[#temp1036:21] : @@ -4694,16 +4694,16 @@ ir.cpp: # 1036| r0_45(decltype([...](...){...})) = Load : &:r0_35, ~mu0_2 # 1036| v0_46(void) = Call : func:r0_34, this:r0_33, 0:r0_45 # 1036| mu0_47(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| v0_48(void) = ^IndirectReadSideEffect : &:r0_45, ~mu0_2 -# 1036| mu0_49(unknown) = ^BufferMayWriteSideEffect : &:r0_45, ~mu0_2 +# 1036| v0_48(void) = ^IndirectReadSideEffect[0] : &:r0_45, ~mu0_2 +# 1036| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_45, ~mu0_2 # 1037| r0_50(glval) = VariableAddress[lambda_val] : # 1037| r0_51(glval) = Convert : r0_50 # 1037| r0_52(glval) = FunctionAddress[operator()] : # 1037| r0_53(float) = Constant[2.0] : # 1037| r0_54(char) = Call : func:r0_52, this:r0_51, 0:r0_53 # 1037| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 -# 1037| v0_56(void) = ^IndirectReadSideEffect : &:r0_51, ~mu0_2 -# 1037| mu0_57(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_51, ~mu0_2 +# 1037| v0_56(void) = ^IndirectReadSideEffect[-1] : &:r0_51, ~mu0_2 +# 1037| mu0_57(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_51, ~mu0_2 # 1038| r0_58(glval) = VariableAddress[lambda_ref_explicit] : # 1038| r0_59(glval) = VariableAddress[#temp1038:30] : # 1038| mu0_60(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_59 @@ -4719,8 +4719,8 @@ ir.cpp: # 1039| r0_70(float) = Constant[3.0] : # 1039| r0_71(char) = Call : func:r0_69, this:r0_68, 0:r0_70 # 1039| mu0_72(unknown) = ^CallSideEffect : ~mu0_2 -# 1039| v0_73(void) = ^IndirectReadSideEffect : &:r0_68, ~mu0_2 -# 1039| mu0_74(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_68, ~mu0_2 +# 1039| v0_73(void) = ^IndirectReadSideEffect[-1] : &:r0_68, ~mu0_2 +# 1039| mu0_74(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_68, ~mu0_2 # 1040| r0_75(glval) = VariableAddress[lambda_val_explicit] : # 1040| r0_76(glval) = FunctionAddress[(constructor)] : # 1040| r0_77(glval) = VariableAddress[#temp1040:30] : @@ -4732,16 +4732,16 @@ ir.cpp: # 1040| r0_83(decltype([...](...){...})) = Load : &:r0_77, ~mu0_2 # 1040| v0_84(void) = Call : func:r0_76, this:r0_75, 0:r0_83 # 1040| mu0_85(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| v0_86(void) = ^IndirectReadSideEffect : &:r0_83, ~mu0_2 -# 1040| mu0_87(unknown) = ^BufferMayWriteSideEffect : &:r0_83, ~mu0_2 +# 1040| v0_86(void) = ^IndirectReadSideEffect[0] : &:r0_83, ~mu0_2 +# 1040| mu0_87(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_83, ~mu0_2 # 1041| r0_88(glval) = VariableAddress[lambda_val_explicit] : # 1041| r0_89(glval) = Convert : r0_88 # 1041| r0_90(glval) = FunctionAddress[operator()] : # 1041| r0_91(float) = Constant[4.0] : # 1041| r0_92(char) = Call : func:r0_90, this:r0_89, 0:r0_91 # 1041| mu0_93(unknown) = ^CallSideEffect : ~mu0_2 -# 1041| v0_94(void) = ^IndirectReadSideEffect : &:r0_89, ~mu0_2 -# 1041| mu0_95(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_89, ~mu0_2 +# 1041| v0_94(void) = ^IndirectReadSideEffect[-1] : &:r0_89, ~mu0_2 +# 1041| mu0_95(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_89, ~mu0_2 # 1042| r0_96(glval) = VariableAddress[lambda_mixed_explicit] : # 1042| r0_97(glval) = VariableAddress[#temp1042:32] : # 1042| mu0_98(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_97 @@ -4761,8 +4761,8 @@ ir.cpp: # 1043| r0_112(float) = Constant[5.0] : # 1043| r0_113(char) = Call : func:r0_111, this:r0_110, 0:r0_112 # 1043| mu0_114(unknown) = ^CallSideEffect : ~mu0_2 -# 1043| v0_115(void) = ^IndirectReadSideEffect : &:r0_110, ~mu0_2 -# 1043| mu0_116(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_110, ~mu0_2 +# 1043| v0_115(void) = ^IndirectReadSideEffect[-1] : &:r0_110, ~mu0_2 +# 1043| mu0_116(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_110, ~mu0_2 # 1044| r0_117(glval) = VariableAddress[r] : # 1044| r0_118(glval) = VariableAddress[x] : # 1044| r0_119(int) = Load : &:r0_118, ~mu0_2 @@ -4797,8 +4797,8 @@ ir.cpp: # 1046| r0_148(float) = Constant[6.0] : # 1046| r0_149(char) = Call : func:r0_147, this:r0_146, 0:r0_148 # 1046| mu0_150(unknown) = ^CallSideEffect : ~mu0_2 -# 1046| v0_151(void) = ^IndirectReadSideEffect : &:r0_146, ~mu0_2 -# 1046| mu0_152(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_146, ~mu0_2 +# 1046| v0_151(void) = ^IndirectReadSideEffect[-1] : &:r0_146, ~mu0_2 +# 1046| mu0_152(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_146, ~mu0_2 # 1047| v0_153(void) = NoOp : # 1031| v0_154(void) = ReturnVoid : # 1031| v0_155(void) = UnmodeledUse : mu* @@ -4849,32 +4849,32 @@ ir.cpp: # 1034| char (void Lambda(int, String const&))::(lambda [] type at line 1034, col. 21)::operator()(float) const # 1034| Block 0 -# 1034| v0_0(void) = EnterFunction : -# 1034| mu0_1(unknown) = AliasedDefinition : -# 1034| mu0_2(unknown) = UnmodeledDefinition : -# 1034| r0_3(glval) = InitializeThis : -# 1034| r0_4(glval) = VariableAddress[f] : -# 1034| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1034| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1034| r0_10(glval) = FunctionAddress[c_str] : -# 1034| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1034| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 1034| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 -# 1034| mu0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 -#-----| r0_15(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 -#-----| r0_16(glval) = FieldAddress[x] : r0_15 -#-----| r0_17(int &) = Load : &:r0_16, ~mu0_2 -# 1034| r0_18(int) = Load : &:r0_17, ~mu0_2 -# 1034| r0_19(glval) = PointerAdd[1] : r0_11, r0_18 -# 1034| r0_20(char) = Load : &:r0_19, ~mu0_2 -# 1034| mu0_21(char) = Store : &:r0_6, r0_20 -# 1034| r0_22(glval) = VariableAddress[#return] : -# 1034| v0_23(void) = ReturnValue : &:r0_22, ~mu0_2 -# 1034| v0_24(void) = UnmodeledUse : mu* -# 1034| v0_25(void) = ExitFunction : +# 1034| v0_0(void) = EnterFunction : +# 1034| mu0_1(unknown) = AliasedDefinition : +# 1034| mu0_2(unknown) = UnmodeledDefinition : +# 1034| r0_3(glval) = InitializeThis : +# 1034| r0_4(glval) = VariableAddress[f] : +# 1034| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1034| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 +# 1034| r0_10(glval) = FunctionAddress[c_str] : +# 1034| r0_11(char *) = Call : func:r0_10, this:r0_9 +# 1034| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 1034| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 +# 1034| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9, ~mu0_2 +#-----| r0_15(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 +#-----| r0_16(glval) = FieldAddress[x] : r0_15 +#-----| r0_17(int &) = Load : &:r0_16, ~mu0_2 +# 1034| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 1034| r0_19(glval) = PointerAdd[1] : r0_11, r0_18 +# 1034| r0_20(char) = Load : &:r0_19, ~mu0_2 +# 1034| mu0_21(char) = Store : &:r0_6, r0_20 +# 1034| r0_22(glval) = VariableAddress[#return] : +# 1034| v0_23(void) = ReturnValue : &:r0_22, ~mu0_2 +# 1034| v0_24(void) = UnmodeledUse : mu* +# 1034| v0_25(void) = ExitFunction : # 1036| void (void Lambda(int, String const&))::(lambda [] type at line 1036, col. 21)::~() # 1036| Block 0 @@ -4893,56 +4893,56 @@ ir.cpp: # 1036| char (void Lambda(int, String const&))::(lambda [] type at line 1036, col. 21)::operator()(float) const # 1036| Block 0 -# 1036| v0_0(void) = EnterFunction : -# 1036| mu0_1(unknown) = AliasedDefinition : -# 1036| mu0_2(unknown) = UnmodeledDefinition : -# 1036| r0_3(glval) = InitializeThis : -# 1036| r0_4(glval) = VariableAddress[f] : -# 1036| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1036| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -# 1036| r0_9(glval) = FunctionAddress[c_str] : -# 1036| r0_10(char *) = Call : func:r0_9, this:r0_8 -# 1036| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_12(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 -#-----| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 -#-----| r0_14(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 -#-----| r0_15(glval) = FieldAddress[x] : r0_14 -#-----| r0_16(int) = Load : &:r0_15, ~mu0_2 -# 1036| r0_17(glval) = PointerAdd[1] : r0_10, r0_16 -# 1036| r0_18(char) = Load : &:r0_17, ~mu0_2 -# 1036| mu0_19(char) = Store : &:r0_6, r0_18 -# 1036| r0_20(glval) = VariableAddress[#return] : -# 1036| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 -# 1036| v0_22(void) = UnmodeledUse : mu* -# 1036| v0_23(void) = ExitFunction : +# 1036| v0_0(void) = EnterFunction : +# 1036| mu0_1(unknown) = AliasedDefinition : +# 1036| mu0_2(unknown) = UnmodeledDefinition : +# 1036| r0_3(glval) = InitializeThis : +# 1036| r0_4(glval) = VariableAddress[f] : +# 1036| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1036| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +# 1036| r0_9(glval) = FunctionAddress[c_str] : +# 1036| r0_10(char *) = Call : func:r0_9, this:r0_8 +# 1036| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_12(void) = ^IndirectReadSideEffect[-1] : &:r0_8, ~mu0_2 +#-----| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8, ~mu0_2 +#-----| r0_14(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 +#-----| r0_15(glval) = FieldAddress[x] : r0_14 +#-----| r0_16(int) = Load : &:r0_15, ~mu0_2 +# 1036| r0_17(glval) = PointerAdd[1] : r0_10, r0_16 +# 1036| r0_18(char) = Load : &:r0_17, ~mu0_2 +# 1036| mu0_19(char) = Store : &:r0_6, r0_18 +# 1036| r0_20(glval) = VariableAddress[#return] : +# 1036| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 +# 1036| v0_22(void) = UnmodeledUse : mu* +# 1036| v0_23(void) = ExitFunction : # 1038| char (void Lambda(int, String const&))::(lambda [] type at line 1038, col. 30)::operator()(float) const # 1038| Block 0 -# 1038| v0_0(void) = EnterFunction : -# 1038| mu0_1(unknown) = AliasedDefinition : -# 1038| mu0_2(unknown) = UnmodeledDefinition : -# 1038| r0_3(glval) = InitializeThis : -# 1038| r0_4(glval) = VariableAddress[f] : -# 1038| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1038| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1038, col. 30 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1038| r0_10(glval) = FunctionAddress[c_str] : -# 1038| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1038| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 1038| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 -# 1038| mu0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 -# 1038| r0_15(int) = Constant[0] : -# 1038| r0_16(glval) = PointerAdd[1] : r0_11, r0_15 -# 1038| r0_17(char) = Load : &:r0_16, ~mu0_2 -# 1038| mu0_18(char) = Store : &:r0_6, r0_17 -# 1038| r0_19(glval) = VariableAddress[#return] : -# 1038| v0_20(void) = ReturnValue : &:r0_19, ~mu0_2 -# 1038| v0_21(void) = UnmodeledUse : mu* -# 1038| v0_22(void) = ExitFunction : +# 1038| v0_0(void) = EnterFunction : +# 1038| mu0_1(unknown) = AliasedDefinition : +# 1038| mu0_2(unknown) = UnmodeledDefinition : +# 1038| r0_3(glval) = InitializeThis : +# 1038| r0_4(glval) = VariableAddress[f] : +# 1038| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1038| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1038, col. 30 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 +# 1038| r0_10(glval) = FunctionAddress[c_str] : +# 1038| r0_11(char *) = Call : func:r0_10, this:r0_9 +# 1038| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 1038| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 +# 1038| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9, ~mu0_2 +# 1038| r0_15(int) = Constant[0] : +# 1038| r0_16(glval) = PointerAdd[1] : r0_11, r0_15 +# 1038| r0_17(char) = Load : &:r0_16, ~mu0_2 +# 1038| mu0_18(char) = Store : &:r0_6, r0_17 +# 1038| r0_19(glval) = VariableAddress[#return] : +# 1038| v0_20(void) = ReturnValue : &:r0_19, ~mu0_2 +# 1038| v0_21(void) = UnmodeledUse : mu* +# 1038| v0_22(void) = ExitFunction : # 1040| void (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::(constructor)((void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)&&) # 1040| Block 0 @@ -4978,142 +4978,142 @@ ir.cpp: # 1040| char (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::operator()(float) const # 1040| Block 0 -# 1040| v0_0(void) = EnterFunction : -# 1040| mu0_1(unknown) = AliasedDefinition : -# 1040| mu0_2(unknown) = UnmodeledDefinition : -# 1040| r0_3(glval) = InitializeThis : -# 1040| r0_4(glval) = VariableAddress[f] : -# 1040| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1040| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1040, col. 30 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -# 1040| r0_9(glval) = FunctionAddress[c_str] : -# 1040| r0_10(char *) = Call : func:r0_9, this:r0_8 -# 1040| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_12(void) = ^IndirectReadSideEffect : &:r0_8, ~mu0_2 -#-----| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_8, ~mu0_2 -# 1040| r0_14(int) = Constant[0] : -# 1040| r0_15(glval) = PointerAdd[1] : r0_10, r0_14 -# 1040| r0_16(char) = Load : &:r0_15, ~mu0_2 -# 1040| mu0_17(char) = Store : &:r0_6, r0_16 -# 1040| r0_18(glval) = VariableAddress[#return] : -# 1040| v0_19(void) = ReturnValue : &:r0_18, ~mu0_2 -# 1040| v0_20(void) = UnmodeledUse : mu* -# 1040| v0_21(void) = ExitFunction : +# 1040| v0_0(void) = EnterFunction : +# 1040| mu0_1(unknown) = AliasedDefinition : +# 1040| mu0_2(unknown) = UnmodeledDefinition : +# 1040| r0_3(glval) = InitializeThis : +# 1040| r0_4(glval) = VariableAddress[f] : +# 1040| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1040| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1040, col. 30 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +# 1040| r0_9(glval) = FunctionAddress[c_str] : +# 1040| r0_10(char *) = Call : func:r0_9, this:r0_8 +# 1040| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_12(void) = ^IndirectReadSideEffect[-1] : &:r0_8, ~mu0_2 +#-----| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8, ~mu0_2 +# 1040| r0_14(int) = Constant[0] : +# 1040| r0_15(glval) = PointerAdd[1] : r0_10, r0_14 +# 1040| r0_16(char) = Load : &:r0_15, ~mu0_2 +# 1040| mu0_17(char) = Store : &:r0_6, r0_16 +# 1040| r0_18(glval) = VariableAddress[#return] : +# 1040| v0_19(void) = ReturnValue : &:r0_18, ~mu0_2 +# 1040| v0_20(void) = UnmodeledUse : mu* +# 1040| v0_21(void) = ExitFunction : # 1042| char (void Lambda(int, String const&))::(lambda [] type at line 1042, col. 32)::operator()(float) const # 1042| Block 0 -# 1042| v0_0(void) = EnterFunction : -# 1042| mu0_1(unknown) = AliasedDefinition : -# 1042| mu0_2(unknown) = UnmodeledDefinition : -# 1042| r0_3(glval) = InitializeThis : -# 1042| r0_4(glval) = VariableAddress[f] : -# 1042| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1042| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1042| r0_10(glval) = FunctionAddress[c_str] : -# 1042| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1042| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 1042| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 -# 1042| mu0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 -#-----| r0_15(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 -#-----| r0_16(glval) = FieldAddress[x] : r0_15 -#-----| r0_17(int) = Load : &:r0_16, ~mu0_2 -# 1042| r0_18(glval) = PointerAdd[1] : r0_11, r0_17 -# 1042| r0_19(char) = Load : &:r0_18, ~mu0_2 -# 1042| mu0_20(char) = Store : &:r0_6, r0_19 -# 1042| r0_21(glval) = VariableAddress[#return] : -# 1042| v0_22(void) = ReturnValue : &:r0_21, ~mu0_2 -# 1042| v0_23(void) = UnmodeledUse : mu* -# 1042| v0_24(void) = ExitFunction : +# 1042| v0_0(void) = EnterFunction : +# 1042| mu0_1(unknown) = AliasedDefinition : +# 1042| mu0_2(unknown) = UnmodeledDefinition : +# 1042| r0_3(glval) = InitializeThis : +# 1042| r0_4(glval) = VariableAddress[f] : +# 1042| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1042| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 +# 1042| r0_10(glval) = FunctionAddress[c_str] : +# 1042| r0_11(char *) = Call : func:r0_10, this:r0_9 +# 1042| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 1042| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 +# 1042| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9, ~mu0_2 +#-----| r0_15(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 +#-----| r0_16(glval) = FieldAddress[x] : r0_15 +#-----| r0_17(int) = Load : &:r0_16, ~mu0_2 +# 1042| r0_18(glval) = PointerAdd[1] : r0_11, r0_17 +# 1042| r0_19(char) = Load : &:r0_18, ~mu0_2 +# 1042| mu0_20(char) = Store : &:r0_6, r0_19 +# 1042| r0_21(glval) = VariableAddress[#return] : +# 1042| v0_22(void) = ReturnValue : &:r0_21, ~mu0_2 +# 1042| v0_23(void) = UnmodeledUse : mu* +# 1042| v0_24(void) = ExitFunction : # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 23)::operator()(float) const # 1045| Block 0 -# 1045| v0_0(void) = EnterFunction : -# 1045| mu0_1(unknown) = AliasedDefinition : -# 1045| mu0_2(unknown) = UnmodeledDefinition : -# 1045| r0_3(glval) = InitializeThis : -# 1045| r0_4(glval) = VariableAddress[f] : -# 1045| mu0_5(float) = InitializeParameter[f] : &:r0_4 -# 1045| r0_6(glval) = VariableAddress[#return] : -#-----| r0_7(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -#-----| r0_8(glval) = FieldAddress[s] : r0_7 -#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 -# 1045| r0_10(glval) = FunctionAddress[c_str] : -# 1045| r0_11(char *) = Call : func:r0_10, this:r0_9 -# 1045| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 1045| v0_13(void) = ^IndirectReadSideEffect : &:r0_9, ~mu0_2 -# 1045| mu0_14(String) = ^IndirectMayWriteSideEffect : &:r0_9, ~mu0_2 -#-----| r0_15(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -#-----| r0_16(glval) = FieldAddress[x] : r0_15 -#-----| r0_17(int) = Load : &:r0_16, ~mu0_2 -#-----| r0_18(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -# 1045| r0_19(glval) = FieldAddress[i] : r0_18 -# 1045| r0_20(int) = Load : &:r0_19, ~mu0_2 -# 1045| r0_21(int) = Add : r0_17, r0_20 -#-----| r0_22(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 -# 1045| r0_23(glval) = FieldAddress[j] : r0_22 -# 1045| r0_24(int &) = Load : &:r0_23, ~mu0_2 -# 1045| r0_25(int) = Load : &:r0_24, ~mu0_2 -# 1045| r0_26(int) = Sub : r0_21, r0_25 -# 1045| r0_27(glval) = PointerAdd[1] : r0_11, r0_26 -# 1045| r0_28(char) = Load : &:r0_27, ~mu0_2 -# 1045| mu0_29(char) = Store : &:r0_6, r0_28 -# 1045| r0_30(glval) = VariableAddress[#return] : -# 1045| v0_31(void) = ReturnValue : &:r0_30, ~mu0_2 -# 1045| v0_32(void) = UnmodeledUse : mu* -# 1045| v0_33(void) = ExitFunction : +# 1045| v0_0(void) = EnterFunction : +# 1045| mu0_1(unknown) = AliasedDefinition : +# 1045| mu0_2(unknown) = UnmodeledDefinition : +# 1045| r0_3(glval) = InitializeThis : +# 1045| r0_4(glval) = VariableAddress[f] : +# 1045| mu0_5(float) = InitializeParameter[f] : &:r0_4 +# 1045| r0_6(glval) = VariableAddress[#return] : +#-----| r0_7(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +#-----| r0_8(glval) = FieldAddress[s] : r0_7 +#-----| r0_9(String &) = Load : &:r0_8, ~mu0_2 +# 1045| r0_10(glval) = FunctionAddress[c_str] : +# 1045| r0_11(char *) = Call : func:r0_10, this:r0_9 +# 1045| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 1045| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 +# 1045| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9, ~mu0_2 +#-----| r0_15(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +#-----| r0_16(glval) = FieldAddress[x] : r0_15 +#-----| r0_17(int) = Load : &:r0_16, ~mu0_2 +#-----| r0_18(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +# 1045| r0_19(glval) = FieldAddress[i] : r0_18 +# 1045| r0_20(int) = Load : &:r0_19, ~mu0_2 +# 1045| r0_21(int) = Add : r0_17, r0_20 +#-----| r0_22(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 +# 1045| r0_23(glval) = FieldAddress[j] : r0_22 +# 1045| r0_24(int &) = Load : &:r0_23, ~mu0_2 +# 1045| r0_25(int) = Load : &:r0_24, ~mu0_2 +# 1045| r0_26(int) = Sub : r0_21, r0_25 +# 1045| r0_27(glval) = PointerAdd[1] : r0_11, r0_26 +# 1045| r0_28(char) = Load : &:r0_27, ~mu0_2 +# 1045| mu0_29(char) = Store : &:r0_6, r0_28 +# 1045| r0_30(glval) = VariableAddress[#return] : +# 1045| v0_31(void) = ReturnValue : &:r0_30, ~mu0_2 +# 1045| v0_32(void) = UnmodeledUse : mu* +# 1045| v0_33(void) = ExitFunction : # 1068| void RangeBasedFor(vector const&) # 1068| Block 0 -# 1068| v0_0(void) = EnterFunction : -# 1068| mu0_1(unknown) = AliasedDefinition : -# 1068| mu0_2(unknown) = UnmodeledDefinition : -# 1068| r0_3(glval &>) = VariableAddress[v] : -# 1068| mu0_4(vector &) = InitializeParameter[v] : &:r0_3 -# 1069| r0_5(glval &>) = VariableAddress[(__range)] : -# 1069| r0_6(glval &>) = VariableAddress[v] : -# 1069| r0_7(vector &) = Load : &:r0_6, ~mu0_2 -# 1069| mu0_8(vector &) = Store : &:r0_5, r0_7 -# 1069| r0_9(glval) = VariableAddress[(__begin)] : -#-----| r0_10(glval &>) = VariableAddress[(__range)] : -#-----| r0_11(vector &) = Load : &:r0_10, ~mu0_2 -# 1069| r0_12(glval) = FunctionAddress[begin] : -# 1069| r0_13(iterator) = Call : func:r0_12, this:r0_11 -# 1069| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_15(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 -#-----| mu0_16(vector) = ^IndirectMayWriteSideEffect : &:r0_11, ~mu0_2 -# 1069| mu0_17(iterator) = Store : &:r0_9, r0_13 -# 1069| r0_18(glval) = VariableAddress[(__end)] : -#-----| r0_19(glval &>) = VariableAddress[(__range)] : -#-----| r0_20(vector &) = Load : &:r0_19, ~mu0_2 -# 1069| r0_21(glval) = FunctionAddress[end] : -# 1069| r0_22(iterator) = Call : func:r0_21, this:r0_20 -# 1069| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v0_24(void) = ^IndirectReadSideEffect : &:r0_20, ~mu0_2 -#-----| mu0_25(vector) = ^IndirectMayWriteSideEffect : &:r0_20, ~mu0_2 -# 1069| mu0_26(iterator) = Store : &:r0_18, r0_22 +# 1068| v0_0(void) = EnterFunction : +# 1068| mu0_1(unknown) = AliasedDefinition : +# 1068| mu0_2(unknown) = UnmodeledDefinition : +# 1068| r0_3(glval &>) = VariableAddress[v] : +# 1068| mu0_4(vector &) = InitializeParameter[v] : &:r0_3 +# 1069| r0_5(glval &>) = VariableAddress[(__range)] : +# 1069| r0_6(glval &>) = VariableAddress[v] : +# 1069| r0_7(vector &) = Load : &:r0_6, ~mu0_2 +# 1069| mu0_8(vector &) = Store : &:r0_5, r0_7 +# 1069| r0_9(glval) = VariableAddress[(__begin)] : +#-----| r0_10(glval &>) = VariableAddress[(__range)] : +#-----| r0_11(vector &) = Load : &:r0_10, ~mu0_2 +# 1069| r0_12(glval) = FunctionAddress[begin] : +# 1069| r0_13(iterator) = Call : func:r0_12, this:r0_11 +# 1069| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_15(void) = ^IndirectReadSideEffect[-1] : &:r0_11, ~mu0_2 +#-----| mu0_16(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_11, ~mu0_2 +# 1069| mu0_17(iterator) = Store : &:r0_9, r0_13 +# 1069| r0_18(glval) = VariableAddress[(__end)] : +#-----| r0_19(glval &>) = VariableAddress[(__range)] : +#-----| r0_20(vector &) = Load : &:r0_19, ~mu0_2 +# 1069| r0_21(glval) = FunctionAddress[end] : +# 1069| r0_22(iterator) = Call : func:r0_21, this:r0_20 +# 1069| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v0_24(void) = ^IndirectReadSideEffect[-1] : &:r0_20, ~mu0_2 +#-----| mu0_25(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_20, ~mu0_2 +# 1069| mu0_26(iterator) = Store : &:r0_18, r0_22 #-----| Goto -> Block 4 # 1075| Block 1 -# 1075| r1_0(glval) = VariableAddress[e] : -#-----| r1_1(glval) = VariableAddress[(__begin)] : -#-----| r1_2(glval) = Convert : r1_1 -# 1075| r1_3(glval) = FunctionAddress[operator*] : -# 1075| r1_4(int &) = Call : func:r1_3, this:r1_2 -# 1075| mu1_5(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v1_6(void) = ^IndirectReadSideEffect : &:r1_2, ~mu0_2 -#-----| mu1_7(iterator) = ^IndirectMayWriteSideEffect : &:r1_2, ~mu0_2 -# 1075| r1_8(glval) = Convert : r1_4 -# 1075| mu1_9(int &) = Store : &:r1_0, r1_8 -# 1076| r1_10(glval) = VariableAddress[e] : -# 1076| r1_11(int &) = Load : &:r1_10, ~mu0_2 -# 1076| r1_12(int) = Load : &:r1_11, ~mu0_2 -# 1076| r1_13(int) = Constant[5] : -# 1076| r1_14(bool) = CompareLT : r1_12, r1_13 -# 1076| v1_15(void) = ConditionalBranch : r1_14 +# 1075| r1_0(glval) = VariableAddress[e] : +#-----| r1_1(glval) = VariableAddress[(__begin)] : +#-----| r1_2(glval) = Convert : r1_1 +# 1075| r1_3(glval) = FunctionAddress[operator*] : +# 1075| r1_4(int &) = Call : func:r1_3, this:r1_2 +# 1075| mu1_5(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v1_6(void) = ^IndirectReadSideEffect[-1] : &:r1_2, ~mu0_2 +#-----| mu1_7(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r1_2, ~mu0_2 +# 1075| r1_8(glval) = Convert : r1_4 +# 1075| mu1_9(int &) = Store : &:r1_0, r1_8 +# 1076| r1_10(glval) = VariableAddress[e] : +# 1076| r1_11(int &) = Load : &:r1_10, ~mu0_2 +# 1076| r1_12(int) = Load : &:r1_11, ~mu0_2 +# 1076| r1_13(int) = Constant[5] : +# 1076| r1_14(bool) = CompareLT : r1_12, r1_13 +# 1076| v1_15(void) = ConditionalBranch : r1_14 #-----| False -> Block 10 #-----| True -> Block 2 @@ -5129,35 +5129,35 @@ ir.cpp: # 1068| v3_4(void) = ExitFunction : #-----| Block 4 -#-----| r4_0(glval) = VariableAddress[(__begin)] : -#-----| r4_1(glval) = Convert : r4_0 -# 1069| r4_2(glval) = FunctionAddress[operator!=] : -#-----| r4_3(glval) = VariableAddress[(__end)] : -#-----| r4_4(iterator) = Load : &:r4_3, ~mu0_2 -# 1069| r4_5(bool) = Call : func:r4_2, this:r4_1, 0:r4_4 -# 1069| mu4_6(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v4_7(void) = ^IndirectReadSideEffect : &:r4_1, ~mu0_2 -#-----| mu4_8(iterator) = ^IndirectMayWriteSideEffect : &:r4_1, ~mu0_2 -# 1069| v4_9(void) = ConditionalBranch : r4_5 +#-----| r4_0(glval) = VariableAddress[(__begin)] : +#-----| r4_1(glval) = Convert : r4_0 +# 1069| r4_2(glval) = FunctionAddress[operator!=] : +#-----| r4_3(glval) = VariableAddress[(__end)] : +#-----| r4_4(iterator) = Load : &:r4_3, ~mu0_2 +# 1069| r4_5(bool) = Call : func:r4_2, this:r4_1, 0:r4_4 +# 1069| mu4_6(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v4_7(void) = ^IndirectReadSideEffect[-1] : &:r4_1, ~mu0_2 +#-----| mu4_8(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r4_1, ~mu0_2 +# 1069| v4_9(void) = ConditionalBranch : r4_5 #-----| False -> Block 8 #-----| True -> Block 5 # 1069| Block 5 -# 1069| r5_0(glval) = VariableAddress[e] : -#-----| r5_1(glval) = VariableAddress[(__begin)] : -#-----| r5_2(glval) = Convert : r5_1 -# 1069| r5_3(glval) = FunctionAddress[operator*] : -# 1069| r5_4(int &) = Call : func:r5_3, this:r5_2 -# 1069| mu5_5(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v5_6(void) = ^IndirectReadSideEffect : &:r5_2, ~mu0_2 -#-----| mu5_7(iterator) = ^IndirectMayWriteSideEffect : &:r5_2, ~mu0_2 -# 1069| r5_8(int) = Load : &:r5_4, ~mu0_2 -# 1069| mu5_9(int) = Store : &:r5_0, r5_8 -# 1070| r5_10(glval) = VariableAddress[e] : -# 1070| r5_11(int) = Load : &:r5_10, ~mu0_2 -# 1070| r5_12(int) = Constant[0] : -# 1070| r5_13(bool) = CompareGT : r5_11, r5_12 -# 1070| v5_14(void) = ConditionalBranch : r5_13 +# 1069| r5_0(glval) = VariableAddress[e] : +#-----| r5_1(glval) = VariableAddress[(__begin)] : +#-----| r5_2(glval) = Convert : r5_1 +# 1069| r5_3(glval) = FunctionAddress[operator*] : +# 1069| r5_4(int &) = Call : func:r5_3, this:r5_2 +# 1069| mu5_5(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v5_6(void) = ^IndirectReadSideEffect[-1] : &:r5_2, ~mu0_2 +#-----| mu5_7(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r5_2, ~mu0_2 +# 1069| r5_8(int) = Load : &:r5_4, ~mu0_2 +# 1069| mu5_9(int) = Store : &:r5_0, r5_8 +# 1070| r5_10(glval) = VariableAddress[e] : +# 1070| r5_11(int) = Load : &:r5_10, ~mu0_2 +# 1070| r5_12(int) = Constant[0] : +# 1070| r5_13(bool) = CompareGT : r5_11, r5_12 +# 1070| v5_14(void) = ConditionalBranch : r5_13 #-----| False -> Block 7 #-----| True -> Block 6 @@ -5166,61 +5166,61 @@ ir.cpp: #-----| Goto -> Block 7 # 1069| Block 7 -# 1069| v7_0(void) = NoOp : -#-----| r7_1(glval) = VariableAddress[(__begin)] : -# 1069| r7_2(glval) = FunctionAddress[operator++] : -# 1069| r7_3(iterator &) = Call : func:r7_2, this:r7_1 -# 1069| mu7_4(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v7_5(void) = ^IndirectReadSideEffect : &:r7_1, ~mu0_2 -#-----| mu7_6(iterator) = ^IndirectMayWriteSideEffect : &:r7_1, ~mu0_2 +# 1069| v7_0(void) = NoOp : +#-----| r7_1(glval) = VariableAddress[(__begin)] : +# 1069| r7_2(glval) = FunctionAddress[operator++] : +# 1069| r7_3(iterator &) = Call : func:r7_2, this:r7_1 +# 1069| mu7_4(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v7_5(void) = ^IndirectReadSideEffect[-1] : &:r7_1, ~mu0_2 +#-----| mu7_6(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r7_1, ~mu0_2 #-----| Goto (back edge) -> Block 4 # 1075| Block 8 -# 1075| r8_0(glval &>) = VariableAddress[(__range)] : -# 1075| r8_1(glval &>) = VariableAddress[v] : -# 1075| r8_2(vector &) = Load : &:r8_1, ~mu0_2 -# 1075| mu8_3(vector &) = Store : &:r8_0, r8_2 -# 1075| r8_4(glval) = VariableAddress[(__begin)] : -#-----| r8_5(glval &>) = VariableAddress[(__range)] : -#-----| r8_6(vector &) = Load : &:r8_5, ~mu0_2 -# 1075| r8_7(glval) = FunctionAddress[begin] : -# 1075| r8_8(iterator) = Call : func:r8_7, this:r8_6 -# 1075| mu8_9(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v8_10(void) = ^IndirectReadSideEffect : &:r8_6, ~mu0_2 -#-----| mu8_11(vector) = ^IndirectMayWriteSideEffect : &:r8_6, ~mu0_2 -# 1075| mu8_12(iterator) = Store : &:r8_4, r8_8 -# 1075| r8_13(glval) = VariableAddress[(__end)] : -#-----| r8_14(glval &>) = VariableAddress[(__range)] : -#-----| r8_15(vector &) = Load : &:r8_14, ~mu0_2 -# 1075| r8_16(glval) = FunctionAddress[end] : -# 1075| r8_17(iterator) = Call : func:r8_16, this:r8_15 -# 1075| mu8_18(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v8_19(void) = ^IndirectReadSideEffect : &:r8_15, ~mu0_2 -#-----| mu8_20(vector) = ^IndirectMayWriteSideEffect : &:r8_15, ~mu0_2 -# 1075| mu8_21(iterator) = Store : &:r8_13, r8_17 +# 1075| r8_0(glval &>) = VariableAddress[(__range)] : +# 1075| r8_1(glval &>) = VariableAddress[v] : +# 1075| r8_2(vector &) = Load : &:r8_1, ~mu0_2 +# 1075| mu8_3(vector &) = Store : &:r8_0, r8_2 +# 1075| r8_4(glval) = VariableAddress[(__begin)] : +#-----| r8_5(glval &>) = VariableAddress[(__range)] : +#-----| r8_6(vector &) = Load : &:r8_5, ~mu0_2 +# 1075| r8_7(glval) = FunctionAddress[begin] : +# 1075| r8_8(iterator) = Call : func:r8_7, this:r8_6 +# 1075| mu8_9(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v8_10(void) = ^IndirectReadSideEffect[-1] : &:r8_6, ~mu0_2 +#-----| mu8_11(vector) = ^IndirectMayWriteSideEffect[-1] : &:r8_6, ~mu0_2 +# 1075| mu8_12(iterator) = Store : &:r8_4, r8_8 +# 1075| r8_13(glval) = VariableAddress[(__end)] : +#-----| r8_14(glval &>) = VariableAddress[(__range)] : +#-----| r8_15(vector &) = Load : &:r8_14, ~mu0_2 +# 1075| r8_16(glval) = FunctionAddress[end] : +# 1075| r8_17(iterator) = Call : func:r8_16, this:r8_15 +# 1075| mu8_18(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v8_19(void) = ^IndirectReadSideEffect[-1] : &:r8_15, ~mu0_2 +#-----| mu8_20(vector) = ^IndirectMayWriteSideEffect[-1] : &:r8_15, ~mu0_2 +# 1075| mu8_21(iterator) = Store : &:r8_13, r8_17 #-----| Goto -> Block 9 #-----| Block 9 -#-----| r9_0(glval) = VariableAddress[(__begin)] : -#-----| r9_1(glval) = Convert : r9_0 -# 1075| r9_2(glval) = FunctionAddress[operator!=] : -#-----| r9_3(glval) = VariableAddress[(__end)] : -#-----| r9_4(iterator) = Load : &:r9_3, ~mu0_2 -# 1075| r9_5(bool) = Call : func:r9_2, this:r9_1, 0:r9_4 -# 1075| mu9_6(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v9_7(void) = ^IndirectReadSideEffect : &:r9_1, ~mu0_2 -#-----| mu9_8(iterator) = ^IndirectMayWriteSideEffect : &:r9_1, ~mu0_2 -# 1075| v9_9(void) = ConditionalBranch : r9_5 +#-----| r9_0(glval) = VariableAddress[(__begin)] : +#-----| r9_1(glval) = Convert : r9_0 +# 1075| r9_2(glval) = FunctionAddress[operator!=] : +#-----| r9_3(glval) = VariableAddress[(__end)] : +#-----| r9_4(iterator) = Load : &:r9_3, ~mu0_2 +# 1075| r9_5(bool) = Call : func:r9_2, this:r9_1, 0:r9_4 +# 1075| mu9_6(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v9_7(void) = ^IndirectReadSideEffect[-1] : &:r9_1, ~mu0_2 +#-----| mu9_8(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r9_1, ~mu0_2 +# 1075| v9_9(void) = ConditionalBranch : r9_5 #-----| False -> Block 3 #-----| True -> Block 1 #-----| Block 10 -#-----| r10_0(glval) = VariableAddress[(__begin)] : -# 1075| r10_1(glval) = FunctionAddress[operator++] : -# 1075| r10_2(iterator &) = Call : func:r10_1, this:r10_0 -# 1075| mu10_3(unknown) = ^CallSideEffect : ~mu0_2 -#-----| v10_4(void) = ^IndirectReadSideEffect : &:r10_0, ~mu0_2 -#-----| mu10_5(iterator) = ^IndirectMayWriteSideEffect : &:r10_0, ~mu0_2 +#-----| r10_0(glval) = VariableAddress[(__begin)] : +# 1075| r10_1(glval) = FunctionAddress[operator++] : +# 1075| r10_2(iterator &) = Call : func:r10_1, this:r10_0 +# 1075| mu10_3(unknown) = ^CallSideEffect : ~mu0_2 +#-----| v10_4(void) = ^IndirectReadSideEffect[-1] : &:r10_0, ~mu0_2 +#-----| mu10_5(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r10_0, ~mu0_2 #-----| Goto (back edge) -> Block 9 # 1099| int AsmStmt(int) @@ -5378,8 +5378,8 @@ ir.cpp: # 1140| r7_3(char *) = Convert : r7_2 # 1140| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 1140| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1140| v7_6(void) = ^IndirectReadSideEffect : &:r7_3, ~mu0_2 -# 1140| mu7_7(unknown) = ^BufferMayWriteSideEffect : &:r7_3, ~mu0_2 +# 1140| v7_6(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 +# 1140| mu7_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3, ~mu0_2 # 1140| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 @@ -5403,8 +5403,8 @@ ir.cpp: # 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2 # 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 # 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 1145| v10_8(void) = ^IndirectReadSideEffect : &:r10_5, ~mu0_2 -# 1145| mu10_9(unknown) = ^BufferMayWriteSideEffect : &:r10_5, ~mu0_2 +# 1145| v10_8(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 +# 1145| mu10_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5, ~mu0_2 # 1145| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 @@ -5488,30 +5488,30 @@ ir.cpp: # 1163| int ModeledCallTarget(int) # 1163| Block 0 -# 1163| v0_0(void) = EnterFunction : -# 1163| mu0_1(unknown) = AliasedDefinition : -# 1163| mu0_2(unknown) = UnmodeledDefinition : -# 1163| r0_3(glval) = VariableAddress[x] : -# 1163| mu0_4(int) = InitializeParameter[x] : &:r0_3 -# 1164| r0_5(glval) = VariableAddress[y] : -# 1164| mu0_6(int) = Uninitialized[y] : &:r0_5 -# 1165| r0_7(glval) = FunctionAddress[memcpy] : -# 1165| r0_8(glval) = VariableAddress[y] : -# 1165| r0_9(void *) = Convert : r0_8 -# 1165| r0_10(glval) = VariableAddress[x] : -# 1165| r0_11(void *) = Convert : r0_10 -# 1165| r0_12(int) = Constant[4] : -# 1165| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12 -# 1165| v0_14(void) = ^BufferReadSideEffect : &:r0_11, ~mu0_2 -# 1165| mu0_15(unknown) = ^BufferMustWriteSideEffect : &:r0_9 -# 1166| r0_16(glval) = VariableAddress[#return] : -# 1166| r0_17(glval) = VariableAddress[y] : -# 1166| r0_18(int) = Load : &:r0_17, ~mu0_2 -# 1166| mu0_19(int) = Store : &:r0_16, r0_18 -# 1163| r0_20(glval) = VariableAddress[#return] : -# 1163| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 -# 1163| v0_22(void) = UnmodeledUse : mu* -# 1163| v0_23(void) = ExitFunction : +# 1163| v0_0(void) = EnterFunction : +# 1163| mu0_1(unknown) = AliasedDefinition : +# 1163| mu0_2(unknown) = UnmodeledDefinition : +# 1163| r0_3(glval) = VariableAddress[x] : +# 1163| mu0_4(int) = InitializeParameter[x] : &:r0_3 +# 1164| r0_5(glval) = VariableAddress[y] : +# 1164| mu0_6(int) = Uninitialized[y] : &:r0_5 +# 1165| r0_7(glval) = FunctionAddress[memcpy] : +# 1165| r0_8(glval) = VariableAddress[y] : +# 1165| r0_9(void *) = Convert : r0_8 +# 1165| r0_10(glval) = VariableAddress[x] : +# 1165| r0_11(void *) = Convert : r0_10 +# 1165| r0_12(int) = Constant[4] : +# 1165| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12 +# 1165| v0_14(void) = ^SizedBufferReadSideEffect[1] : &:r0_11, r0_12, ~mu0_2 +# 1165| mu0_15(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r0_9, r0_12 +# 1166| r0_16(glval) = VariableAddress[#return] : +# 1166| r0_17(glval) = VariableAddress[y] : +# 1166| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 1166| mu0_19(int) = Store : &:r0_16, r0_18 +# 1163| r0_20(glval) = VariableAddress[#return] : +# 1163| v0_21(void) = ReturnValue : &:r0_20, ~mu0_2 +# 1163| v0_22(void) = UnmodeledUse : mu* +# 1163| v0_23(void) = ExitFunction : perf-regression.cpp: # 6| void Big::Big() 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 69dabf45d07..7143eaa7990 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 @@ -311,29 +311,29 @@ ssa.cpp: # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 -# 95| v0_0(void) = EnterFunction : -# 95| m0_1(unknown) = AliasedDefinition : -# 95| mu0_2(unknown) = UnmodeledDefinition : -# 95| r0_3(glval) = VariableAddress[a] : -# 95| m0_4(Point) = InitializeParameter[a] : &:r0_3 -# 95| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 -# 96| r0_6(glval) = VariableAddress[b] : -# 96| r0_7(glval) = VariableAddress[a] : -# 96| r0_8(Point) = Load : &:r0_7, m0_4 -# 96| m0_9(Point) = Store : &:r0_6, r0_8 -# 97| r0_10(glval) = FunctionAddress[Escape] : -# 97| r0_11(glval) = VariableAddress[a] : -# 97| r0_12(void *) = Convert : r0_11 -# 97| v0_13(void) = Call : func:r0_10, 0:r0_12 -# 97| m0_14(unknown) = ^CallSideEffect : ~m0_5 -# 97| m0_15(unknown) = Chi : total:m0_5, partial:m0_14 -# 97| v0_16(void) = ^IndirectReadSideEffect : &:r0_12, ~m0_15 -# 97| m0_17(unknown) = ^BufferMayWriteSideEffect : &:r0_12, ~m0_15 -# 97| m0_18(unknown) = Chi : total:m0_15, partial:m0_17 -# 98| v0_19(void) = NoOp : -# 95| v0_20(void) = ReturnVoid : -# 95| v0_21(void) = UnmodeledUse : mu* -# 95| v0_22(void) = ExitFunction : +# 95| v0_0(void) = EnterFunction : +# 95| m0_1(unknown) = AliasedDefinition : +# 95| mu0_2(unknown) = UnmodeledDefinition : +# 95| r0_3(glval) = VariableAddress[a] : +# 95| m0_4(Point) = InitializeParameter[a] : &:r0_3 +# 95| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 +# 96| r0_6(glval) = VariableAddress[b] : +# 96| r0_7(glval) = VariableAddress[a] : +# 96| r0_8(Point) = Load : &:r0_7, m0_4 +# 96| m0_9(Point) = Store : &:r0_6, r0_8 +# 97| r0_10(glval) = FunctionAddress[Escape] : +# 97| r0_11(glval) = VariableAddress[a] : +# 97| r0_12(void *) = Convert : r0_11 +# 97| v0_13(void) = Call : func:r0_10, 0:r0_12 +# 97| m0_14(unknown) = ^CallSideEffect : ~m0_5 +# 97| m0_15(unknown) = Chi : total:m0_5, partial:m0_14 +# 97| v0_16(void) = ^IndirectReadSideEffect[0] : &:r0_12, ~m0_15 +# 97| m0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12, ~m0_15 +# 97| m0_18(unknown) = Chi : total:m0_15, partial:m0_17 +# 98| v0_19(void) = NoOp : +# 95| v0_20(void) = ReturnVoid : +# 95| v0_21(void) = UnmodeledUse : mu* +# 95| v0_22(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -359,35 +359,35 @@ ssa.cpp: # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 -# 105| v0_0(void) = EnterFunction : -# 105| m0_1(unknown) = AliasedDefinition : -# 105| mu0_2(unknown) = UnmodeledDefinition : -# 105| r0_3(glval) = VariableAddress[a] : -# 105| m0_4(Point) = InitializeParameter[a] : &:r0_3 -# 105| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 -# 106| r0_6(glval) = VariableAddress[x] : -# 106| r0_7(glval) = VariableAddress[a] : -# 106| r0_8(glval) = FieldAddress[x] : r0_7 -# 106| r0_9(int) = Load : &:r0_8, ~m0_4 -# 106| m0_10(int) = Store : &:r0_6, r0_9 -# 107| r0_11(glval) = VariableAddress[y] : -# 107| r0_12(glval) = VariableAddress[a] : -# 107| r0_13(glval) = FieldAddress[y] : r0_12 -# 107| r0_14(int) = Load : &:r0_13, ~m0_4 -# 107| m0_15(int) = Store : &:r0_11, r0_14 -# 108| r0_16(glval) = FunctionAddress[Escape] : -# 108| r0_17(glval) = VariableAddress[a] : -# 108| r0_18(void *) = Convert : r0_17 -# 108| v0_19(void) = Call : func:r0_16, 0:r0_18 -# 108| m0_20(unknown) = ^CallSideEffect : ~m0_5 -# 108| m0_21(unknown) = Chi : total:m0_5, partial:m0_20 -# 108| v0_22(void) = ^IndirectReadSideEffect : &:r0_18, ~m0_21 -# 108| m0_23(unknown) = ^BufferMayWriteSideEffect : &:r0_18, ~m0_21 -# 108| m0_24(unknown) = Chi : total:m0_21, partial:m0_23 -# 109| v0_25(void) = NoOp : -# 105| v0_26(void) = ReturnVoid : -# 105| v0_27(void) = UnmodeledUse : mu* -# 105| v0_28(void) = ExitFunction : +# 105| v0_0(void) = EnterFunction : +# 105| m0_1(unknown) = AliasedDefinition : +# 105| mu0_2(unknown) = UnmodeledDefinition : +# 105| r0_3(glval) = VariableAddress[a] : +# 105| m0_4(Point) = InitializeParameter[a] : &:r0_3 +# 105| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 +# 106| r0_6(glval) = VariableAddress[x] : +# 106| r0_7(glval) = VariableAddress[a] : +# 106| r0_8(glval) = FieldAddress[x] : r0_7 +# 106| r0_9(int) = Load : &:r0_8, ~m0_4 +# 106| m0_10(int) = Store : &:r0_6, r0_9 +# 107| r0_11(glval) = VariableAddress[y] : +# 107| r0_12(glval) = VariableAddress[a] : +# 107| r0_13(glval) = FieldAddress[y] : r0_12 +# 107| r0_14(int) = Load : &:r0_13, ~m0_4 +# 107| m0_15(int) = Store : &:r0_11, r0_14 +# 108| r0_16(glval) = FunctionAddress[Escape] : +# 108| r0_17(glval) = VariableAddress[a] : +# 108| r0_18(void *) = Convert : r0_17 +# 108| v0_19(void) = Call : func:r0_16, 0:r0_18 +# 108| m0_20(unknown) = ^CallSideEffect : ~m0_5 +# 108| m0_21(unknown) = Chi : total:m0_5, partial:m0_20 +# 108| v0_22(void) = ^IndirectReadSideEffect[0] : &:r0_18, ~m0_21 +# 108| m0_23(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_18, ~m0_21 +# 108| m0_24(unknown) = Chi : total:m0_21, partial:m0_23 +# 109| v0_25(void) = NoOp : +# 105| v0_26(void) = ReturnVoid : +# 105| v0_27(void) = UnmodeledUse : mu* +# 105| v0_28(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -421,43 +421,43 @@ ssa.cpp: # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 -# 116| v0_0(void) = EnterFunction : -# 116| m0_1(unknown) = AliasedDefinition : -# 116| mu0_2(unknown) = UnmodeledDefinition : -# 116| r0_3(glval) = VariableAddress[x] : -# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 -# 116| r0_5(glval) = VariableAddress[y] : -# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 -# 117| r0_7(glval) = VariableAddress[a] : -# 117| m0_8(Point) = Uninitialized[a] : &:r0_7 -# 117| m0_9(unknown) = Chi : total:m0_1, partial:m0_8 -# 117| r0_10(glval) = FieldAddress[x] : r0_7 -# 117| r0_11(glval) = VariableAddress[x] : -# 117| r0_12(int) = Load : &:r0_11, m0_4 -# 117| m0_13(int) = Store : &:r0_10, r0_12 -# 117| m0_14(unknown) = Chi : total:m0_9, partial:m0_13 -# 117| r0_15(glval) = FieldAddress[y] : r0_7 -# 117| r0_16(glval) = VariableAddress[y] : -# 117| r0_17(int) = Load : &:r0_16, m0_6 -# 117| m0_18(int) = Store : &:r0_15, r0_17 -# 117| m0_19(unknown) = Chi : total:m0_14, partial:m0_18 -# 118| r0_20(glval) = VariableAddress[b] : -# 118| r0_21(glval) = VariableAddress[a] : -# 118| r0_22(Point) = Load : &:r0_21, ~m0_19 -# 118| m0_23(Point) = Store : &:r0_20, r0_22 -# 119| r0_24(glval) = FunctionAddress[Escape] : -# 119| r0_25(glval) = VariableAddress[a] : -# 119| r0_26(void *) = Convert : r0_25 -# 119| v0_27(void) = Call : func:r0_24, 0:r0_26 -# 119| m0_28(unknown) = ^CallSideEffect : ~m0_19 -# 119| m0_29(unknown) = Chi : total:m0_19, partial:m0_28 -# 119| v0_30(void) = ^IndirectReadSideEffect : &:r0_26, ~m0_29 -# 119| m0_31(unknown) = ^BufferMayWriteSideEffect : &:r0_26, ~m0_29 -# 119| m0_32(unknown) = Chi : total:m0_29, partial:m0_31 -# 120| v0_33(void) = NoOp : -# 116| v0_34(void) = ReturnVoid : -# 116| v0_35(void) = UnmodeledUse : mu* -# 116| v0_36(void) = ExitFunction : +# 116| v0_0(void) = EnterFunction : +# 116| m0_1(unknown) = AliasedDefinition : +# 116| mu0_2(unknown) = UnmodeledDefinition : +# 116| r0_3(glval) = VariableAddress[x] : +# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 +# 116| r0_5(glval) = VariableAddress[y] : +# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 +# 117| r0_7(glval) = VariableAddress[a] : +# 117| m0_8(Point) = Uninitialized[a] : &:r0_7 +# 117| m0_9(unknown) = Chi : total:m0_1, partial:m0_8 +# 117| r0_10(glval) = FieldAddress[x] : r0_7 +# 117| r0_11(glval) = VariableAddress[x] : +# 117| r0_12(int) = Load : &:r0_11, m0_4 +# 117| m0_13(int) = Store : &:r0_10, r0_12 +# 117| m0_14(unknown) = Chi : total:m0_9, partial:m0_13 +# 117| r0_15(glval) = FieldAddress[y] : r0_7 +# 117| r0_16(glval) = VariableAddress[y] : +# 117| r0_17(int) = Load : &:r0_16, m0_6 +# 117| m0_18(int) = Store : &:r0_15, r0_17 +# 117| m0_19(unknown) = Chi : total:m0_14, partial:m0_18 +# 118| r0_20(glval) = VariableAddress[b] : +# 118| r0_21(glval) = VariableAddress[a] : +# 118| r0_22(Point) = Load : &:r0_21, ~m0_19 +# 118| m0_23(Point) = Store : &:r0_20, r0_22 +# 119| r0_24(glval) = FunctionAddress[Escape] : +# 119| r0_25(glval) = VariableAddress[a] : +# 119| r0_26(void *) = Convert : r0_25 +# 119| v0_27(void) = Call : func:r0_24, 0:r0_26 +# 119| m0_28(unknown) = ^CallSideEffect : ~m0_19 +# 119| m0_29(unknown) = Chi : total:m0_19, partial:m0_28 +# 119| v0_30(void) = ^IndirectReadSideEffect[0] : &:r0_26, ~m0_29 +# 119| m0_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26, ~m0_29 +# 119| m0_32(unknown) = Chi : total:m0_29, partial:m0_31 +# 120| v0_33(void) = NoOp : +# 116| v0_34(void) = ReturnVoid : +# 116| v0_35(void) = UnmodeledUse : mu* +# 116| v0_36(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -819,30 +819,30 @@ ssa.cpp: # 207| int ModeledCallTarget(int) # 207| Block 0 -# 207| v0_0(void) = EnterFunction : -# 207| m0_1(unknown) = AliasedDefinition : -# 207| mu0_2(unknown) = UnmodeledDefinition : -# 207| r0_3(glval) = VariableAddress[x] : -# 207| m0_4(int) = InitializeParameter[x] : &:r0_3 -# 207| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 -# 208| r0_6(glval) = VariableAddress[y] : -# 208| m0_7(int) = Uninitialized[y] : &:r0_6 -# 208| m0_8(unknown) = Chi : total:m0_5, partial:m0_7 -# 209| r0_9(glval) = FunctionAddress[memcpy] : -# 209| r0_10(glval) = VariableAddress[y] : -# 209| r0_11(void *) = Convert : r0_10 -# 209| r0_12(glval) = VariableAddress[x] : -# 209| r0_13(void *) = Convert : r0_12 -# 209| r0_14(int) = Constant[4] : -# 209| r0_15(void *) = Call : func:r0_9, 0:r0_11, 1:r0_13, 2:r0_14 -# 209| v0_16(void) = ^BufferReadSideEffect : &:r0_13, ~m0_4 -# 209| m0_17(unknown) = ^BufferMustWriteSideEffect : &:r0_11 -# 209| m0_18(unknown) = Chi : total:m0_8, partial:m0_17 -# 210| r0_19(glval) = VariableAddress[#return] : -# 210| r0_20(glval) = VariableAddress[y] : -# 210| r0_21(int) = Load : &:r0_20, ~m0_18 -# 210| m0_22(int) = Store : &:r0_19, r0_21 -# 207| r0_23(glval) = VariableAddress[#return] : -# 207| v0_24(void) = ReturnValue : &:r0_23, m0_22 -# 207| v0_25(void) = UnmodeledUse : mu* -# 207| v0_26(void) = ExitFunction : +# 207| v0_0(void) = EnterFunction : +# 207| m0_1(unknown) = AliasedDefinition : +# 207| mu0_2(unknown) = UnmodeledDefinition : +# 207| r0_3(glval) = VariableAddress[x] : +# 207| m0_4(int) = InitializeParameter[x] : &:r0_3 +# 207| m0_5(unknown) = Chi : total:m0_1, partial:m0_4 +# 208| r0_6(glval) = VariableAddress[y] : +# 208| m0_7(int) = Uninitialized[y] : &:r0_6 +# 208| m0_8(unknown) = Chi : total:m0_5, partial:m0_7 +# 209| r0_9(glval) = FunctionAddress[memcpy] : +# 209| r0_10(glval) = VariableAddress[y] : +# 209| r0_11(void *) = Convert : r0_10 +# 209| r0_12(glval) = VariableAddress[x] : +# 209| r0_13(void *) = Convert : r0_12 +# 209| r0_14(int) = Constant[4] : +# 209| r0_15(void *) = Call : func:r0_9, 0:r0_11, 1:r0_13, 2:r0_14 +# 209| v0_16(void) = ^SizedBufferReadSideEffect[1] : &:r0_13, r0_14, ~mu0_2 +# 209| m0_17(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r0_11, r0_14 +# 209| m0_18(unknown) = Chi : total:m0_8, partial:m0_17 +# 210| r0_19(glval) = VariableAddress[#return] : +# 210| r0_20(glval) = VariableAddress[y] : +# 210| r0_21(int) = Load : &:r0_20, ~m0_18 +# 210| m0_22(int) = Store : &:r0_19, r0_21 +# 207| r0_23(glval) = VariableAddress[#return] : +# 207| v0_24(void) = ReturnValue : &:r0_23, m0_22 +# 207| v0_25(void) = UnmodeledUse : mu* +# 207| v0_26(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 83b3d68bbc3..15a6127e737 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -312,26 +312,26 @@ ssa.cpp: # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 -# 95| v0_0(void) = EnterFunction : -# 95| mu0_1(unknown) = AliasedDefinition : -# 95| mu0_2(unknown) = UnmodeledDefinition : -# 95| r0_3(glval) = VariableAddress[a] : -# 95| mu0_4(Point) = InitializeParameter[a] : &:r0_3 -# 96| r0_5(glval) = VariableAddress[b] : -# 96| r0_6(glval) = VariableAddress[a] : -# 96| r0_7(Point) = Load : &:r0_6, ~mu0_2 -# 96| m0_8(Point) = Store : &:r0_5, r0_7 -# 97| r0_9(glval) = FunctionAddress[Escape] : -# 97| r0_10(glval) = VariableAddress[a] : -# 97| r0_11(void *) = Convert : r0_10 -# 97| v0_12(void) = Call : func:r0_9, 0:r0_11 -# 97| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -# 97| v0_14(void) = ^IndirectReadSideEffect : &:r0_11, ~mu0_2 -# 97| mu0_15(unknown) = ^BufferMayWriteSideEffect : &:r0_11, ~mu0_2 -# 98| v0_16(void) = NoOp : -# 95| v0_17(void) = ReturnVoid : -# 95| v0_18(void) = UnmodeledUse : mu* -# 95| v0_19(void) = ExitFunction : +# 95| v0_0(void) = EnterFunction : +# 95| mu0_1(unknown) = AliasedDefinition : +# 95| mu0_2(unknown) = UnmodeledDefinition : +# 95| r0_3(glval) = VariableAddress[a] : +# 95| mu0_4(Point) = InitializeParameter[a] : &:r0_3 +# 96| r0_5(glval) = VariableAddress[b] : +# 96| r0_6(glval) = VariableAddress[a] : +# 96| r0_7(Point) = Load : &:r0_6, ~mu0_2 +# 96| m0_8(Point) = Store : &:r0_5, r0_7 +# 97| r0_9(glval) = FunctionAddress[Escape] : +# 97| r0_10(glval) = VariableAddress[a] : +# 97| r0_11(void *) = Convert : r0_10 +# 97| v0_12(void) = Call : func:r0_9, 0:r0_11 +# 97| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +# 97| v0_14(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 +# 97| mu0_15(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11, ~mu0_2 +# 98| v0_16(void) = NoOp : +# 95| v0_17(void) = ReturnVoid : +# 95| v0_18(void) = UnmodeledUse : mu* +# 95| v0_19(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -357,32 +357,32 @@ ssa.cpp: # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 -# 105| v0_0(void) = EnterFunction : -# 105| mu0_1(unknown) = AliasedDefinition : -# 105| mu0_2(unknown) = UnmodeledDefinition : -# 105| r0_3(glval) = VariableAddress[a] : -# 105| mu0_4(Point) = InitializeParameter[a] : &:r0_3 -# 106| r0_5(glval) = VariableAddress[x] : -# 106| r0_6(glval) = VariableAddress[a] : -# 106| r0_7(glval) = FieldAddress[x] : r0_6 -# 106| r0_8(int) = Load : &:r0_7, ~mu0_2 -# 106| m0_9(int) = Store : &:r0_5, r0_8 -# 107| r0_10(glval) = VariableAddress[y] : -# 107| r0_11(glval) = VariableAddress[a] : -# 107| r0_12(glval) = FieldAddress[y] : r0_11 -# 107| r0_13(int) = Load : &:r0_12, ~mu0_2 -# 107| m0_14(int) = Store : &:r0_10, r0_13 -# 108| r0_15(glval) = FunctionAddress[Escape] : -# 108| r0_16(glval) = VariableAddress[a] : -# 108| r0_17(void *) = Convert : r0_16 -# 108| v0_18(void) = Call : func:r0_15, 0:r0_17 -# 108| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 -# 108| v0_20(void) = ^IndirectReadSideEffect : &:r0_17, ~mu0_2 -# 108| mu0_21(unknown) = ^BufferMayWriteSideEffect : &:r0_17, ~mu0_2 -# 109| v0_22(void) = NoOp : -# 105| v0_23(void) = ReturnVoid : -# 105| v0_24(void) = UnmodeledUse : mu* -# 105| v0_25(void) = ExitFunction : +# 105| v0_0(void) = EnterFunction : +# 105| mu0_1(unknown) = AliasedDefinition : +# 105| mu0_2(unknown) = UnmodeledDefinition : +# 105| r0_3(glval) = VariableAddress[a] : +# 105| mu0_4(Point) = InitializeParameter[a] : &:r0_3 +# 106| r0_5(glval) = VariableAddress[x] : +# 106| r0_6(glval) = VariableAddress[a] : +# 106| r0_7(glval) = FieldAddress[x] : r0_6 +# 106| r0_8(int) = Load : &:r0_7, ~mu0_2 +# 106| m0_9(int) = Store : &:r0_5, r0_8 +# 107| r0_10(glval) = VariableAddress[y] : +# 107| r0_11(glval) = VariableAddress[a] : +# 107| r0_12(glval) = FieldAddress[y] : r0_11 +# 107| r0_13(int) = Load : &:r0_12, ~mu0_2 +# 107| m0_14(int) = Store : &:r0_10, r0_13 +# 108| r0_15(glval) = FunctionAddress[Escape] : +# 108| r0_16(glval) = VariableAddress[a] : +# 108| r0_17(void *) = Convert : r0_16 +# 108| v0_18(void) = Call : func:r0_15, 0:r0_17 +# 108| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 +# 108| v0_20(void) = ^IndirectReadSideEffect[0] : &:r0_17, ~mu0_2 +# 108| mu0_21(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_17, ~mu0_2 +# 109| v0_22(void) = NoOp : +# 105| v0_23(void) = ReturnVoid : +# 105| v0_24(void) = UnmodeledUse : mu* +# 105| v0_25(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -414,38 +414,38 @@ ssa.cpp: # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 -# 116| v0_0(void) = EnterFunction : -# 116| mu0_1(unknown) = AliasedDefinition : -# 116| mu0_2(unknown) = UnmodeledDefinition : -# 116| r0_3(glval) = VariableAddress[x] : -# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 -# 116| r0_5(glval) = VariableAddress[y] : -# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 -# 117| r0_7(glval) = VariableAddress[a] : -# 117| mu0_8(Point) = Uninitialized[a] : &:r0_7 -# 117| r0_9(glval) = FieldAddress[x] : r0_7 -# 117| r0_10(glval) = VariableAddress[x] : -# 117| r0_11(int) = Load : &:r0_10, m0_4 -# 117| mu0_12(int) = Store : &:r0_9, r0_11 -# 117| r0_13(glval) = FieldAddress[y] : r0_7 -# 117| r0_14(glval) = VariableAddress[y] : -# 117| r0_15(int) = Load : &:r0_14, m0_6 -# 117| mu0_16(int) = Store : &:r0_13, r0_15 -# 118| r0_17(glval) = VariableAddress[b] : -# 118| r0_18(glval) = VariableAddress[a] : -# 118| r0_19(Point) = Load : &:r0_18, ~mu0_2 -# 118| m0_20(Point) = Store : &:r0_17, r0_19 -# 119| r0_21(glval) = FunctionAddress[Escape] : -# 119| r0_22(glval) = VariableAddress[a] : -# 119| r0_23(void *) = Convert : r0_22 -# 119| v0_24(void) = Call : func:r0_21, 0:r0_23 -# 119| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 119| v0_26(void) = ^IndirectReadSideEffect : &:r0_23, ~mu0_2 -# 119| mu0_27(unknown) = ^BufferMayWriteSideEffect : &:r0_23, ~mu0_2 -# 120| v0_28(void) = NoOp : -# 116| v0_29(void) = ReturnVoid : -# 116| v0_30(void) = UnmodeledUse : mu* -# 116| v0_31(void) = ExitFunction : +# 116| v0_0(void) = EnterFunction : +# 116| mu0_1(unknown) = AliasedDefinition : +# 116| mu0_2(unknown) = UnmodeledDefinition : +# 116| r0_3(glval) = VariableAddress[x] : +# 116| m0_4(int) = InitializeParameter[x] : &:r0_3 +# 116| r0_5(glval) = VariableAddress[y] : +# 116| m0_6(int) = InitializeParameter[y] : &:r0_5 +# 117| r0_7(glval) = VariableAddress[a] : +# 117| mu0_8(Point) = Uninitialized[a] : &:r0_7 +# 117| r0_9(glval) = FieldAddress[x] : r0_7 +# 117| r0_10(glval) = VariableAddress[x] : +# 117| r0_11(int) = Load : &:r0_10, m0_4 +# 117| mu0_12(int) = Store : &:r0_9, r0_11 +# 117| r0_13(glval) = FieldAddress[y] : r0_7 +# 117| r0_14(glval) = VariableAddress[y] : +# 117| r0_15(int) = Load : &:r0_14, m0_6 +# 117| mu0_16(int) = Store : &:r0_13, r0_15 +# 118| r0_17(glval) = VariableAddress[b] : +# 118| r0_18(glval) = VariableAddress[a] : +# 118| r0_19(Point) = Load : &:r0_18, ~mu0_2 +# 118| m0_20(Point) = Store : &:r0_17, r0_19 +# 119| r0_21(glval) = FunctionAddress[Escape] : +# 119| r0_22(glval) = VariableAddress[a] : +# 119| r0_23(void *) = Convert : r0_22 +# 119| v0_24(void) = Call : func:r0_21, 0:r0_23 +# 119| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +# 119| v0_26(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 +# 119| mu0_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23, ~mu0_2 +# 120| v0_28(void) = NoOp : +# 116| v0_29(void) = ReturnVoid : +# 116| v0_30(void) = UnmodeledUse : mu* +# 116| v0_31(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -782,27 +782,27 @@ ssa.cpp: # 207| int ModeledCallTarget(int) # 207| Block 0 -# 207| v0_0(void) = EnterFunction : -# 207| mu0_1(unknown) = AliasedDefinition : -# 207| mu0_2(unknown) = UnmodeledDefinition : -# 207| r0_3(glval) = VariableAddress[x] : -# 207| mu0_4(int) = InitializeParameter[x] : &:r0_3 -# 208| r0_5(glval) = VariableAddress[y] : -# 208| mu0_6(int) = Uninitialized[y] : &:r0_5 -# 209| r0_7(glval) = FunctionAddress[memcpy] : -# 209| r0_8(glval) = VariableAddress[y] : -# 209| r0_9(void *) = Convert : r0_8 -# 209| r0_10(glval) = VariableAddress[x] : -# 209| r0_11(void *) = Convert : r0_10 -# 209| r0_12(int) = Constant[4] : -# 209| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12 -# 209| v0_14(void) = ^BufferReadSideEffect : &:r0_11, ~mu0_2 -# 209| mu0_15(unknown) = ^BufferMustWriteSideEffect : &:r0_9 -# 210| r0_16(glval) = VariableAddress[#return] : -# 210| r0_17(glval) = VariableAddress[y] : -# 210| r0_18(int) = Load : &:r0_17, ~mu0_2 -# 210| m0_19(int) = Store : &:r0_16, r0_18 -# 207| r0_20(glval) = VariableAddress[#return] : -# 207| v0_21(void) = ReturnValue : &:r0_20, m0_19 -# 207| v0_22(void) = UnmodeledUse : mu* -# 207| v0_23(void) = ExitFunction : +# 207| v0_0(void) = EnterFunction : +# 207| mu0_1(unknown) = AliasedDefinition : +# 207| mu0_2(unknown) = UnmodeledDefinition : +# 207| r0_3(glval) = VariableAddress[x] : +# 207| mu0_4(int) = InitializeParameter[x] : &:r0_3 +# 208| r0_5(glval) = VariableAddress[y] : +# 208| mu0_6(int) = Uninitialized[y] : &:r0_5 +# 209| r0_7(glval) = FunctionAddress[memcpy] : +# 209| r0_8(glval) = VariableAddress[y] : +# 209| r0_9(void *) = Convert : r0_8 +# 209| r0_10(glval) = VariableAddress[x] : +# 209| r0_11(void *) = Convert : r0_10 +# 209| r0_12(int) = Constant[4] : +# 209| r0_13(void *) = Call : func:r0_7, 0:r0_9, 1:r0_11, 2:r0_12 +# 209| v0_14(void) = ^SizedBufferReadSideEffect[1] : &:r0_11, r0_12, ~mu0_2 +# 209| mu0_15(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r0_9, r0_12 +# 210| r0_16(glval) = VariableAddress[#return] : +# 210| r0_17(glval) = VariableAddress[y] : +# 210| r0_18(int) = Load : &:r0_17, ~mu0_2 +# 210| m0_19(int) = Store : &:r0_16, r0_18 +# 207| r0_20(glval) = VariableAddress[#return] : +# 207| v0_21(void) = ReturnValue : &:r0_20, m0_19 +# 207| v0_22(void) = UnmodeledUse : mu* +# 207| v0_23(void) = ExitFunction : diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll index dad156c93a7..8be5a1eaa79 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll @@ -71,6 +71,9 @@ private newtype TOpcode = TBufferReadSideEffect() or TBufferMustWriteSideEffect() or TBufferMayWriteSideEffect() or + TSizedBufferReadSideEffect() or + TSizedBufferMustWriteSideEffect() or + TSizedBufferMayWriteSideEffect() or TChi() or TInlineAsm() or TUnreached() or @@ -147,10 +150,16 @@ abstract class MustWriteSideEffectOpcode extends WriteSideEffectOpcode { } abstract class MayWriteSideEffectOpcode extends WriteSideEffectOpcode { } /** - * An opcode that accesses a buffer via an `AddressOperand` and a `BufferSizeOperand`. + * An opcode that accesses a buffer via an `AddressOperand`. */ abstract class BufferAccessOpcode extends MemoryAccessOpcode { } +/** + * An opcode that accesses a buffer via an `AddressOperand` with a `BufferSizeOperand` specifying + * the number of elements accessed. + */ +abstract class SizedBufferAccessOpcode extends BufferAccessOpcode { } + module Opcode { class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } @@ -445,6 +454,21 @@ module Opcode { final override string toString() { result = "BufferMayWriteSideEffect" } } + class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferAccessOpcode, + TSizedBufferReadSideEffect { + final override string toString() { result = "SizedBufferReadSideEffect" } + } + + class SizedBufferMustWriteSideEffect extends MustWriteSideEffectOpcode, SizedBufferAccessOpcode, + TSizedBufferMustWriteSideEffect { + final override string toString() { result = "SizedBufferMustWriteSideEffect" } + } + + class SizedBufferMayWriteSideEffect extends MayWriteSideEffectOpcode, SizedBufferAccessOpcode, + TSizedBufferMayWriteSideEffect { + final override string toString() { result = "SizedBufferMayWriteSideEffect" } + } + class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll index d1172670a79..227b1a34041 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll @@ -66,12 +66,14 @@ AddressOperandTag addressOperand() { result = TAddressOperand() } * The buffer size operand of an instruction that represents a read or write of * a buffer. */ -class BufferSizeOperand extends RegisterOperandTag, TBufferSizeOperand { +class BufferSizeOperandTag extends RegisterOperandTag, TBufferSizeOperand { final override string toString() { result = "BufferSize" } final override int getSortOrder() { result = 1 } } +BufferSizeOperandTag bufferSizeOperand() { result = TBufferSizeOperand() } + /** * The operand representing the read side effect of a `SideEffectInstruction`. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index f3703b3386c..61a3885521d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -30,7 +30,7 @@ module InstructionSanity { or opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or - opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand + opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag or opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or @@ -644,6 +644,17 @@ class ConstantValueInstruction extends Instruction { final string getValue() { result = value } } +class IndexedInstruction extends Instruction { + int index; + + IndexedInstruction() { index = Construction::getInstructionIndex(this) } + + + final override string getImmediateString() { result = index.toString() } + + final int getIndex() { result = index } +} + class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } @@ -1176,7 +1187,7 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { class IndirectReadSideEffectInstruction extends SideEffectInstruction { IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1185,7 +1196,20 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction { class BufferReadSideEffectInstruction extends SideEffectInstruction { BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } +} + +/** + * An instruction representing the read of an indirect buffer parameter within a function call. + */ +class SizedBufferReadSideEffectInstruction extends SideEffectInstruction { + SizedBufferReadSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferReadSideEffect + } + + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } } /** @@ -1194,7 +1218,7 @@ class BufferReadSideEffectInstruction extends SideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentInstruction() { result = getAnOperand().(AddressOperand).getDef() } + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1220,6 +1244,20 @@ class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } } +/** + * An instruction representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ +class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + SizedBufferMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + /** * An instruction representing the potential write of an indirect parameter within a function call. * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. @@ -1247,6 +1285,22 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { } } +/** + * An instruction representing the write of an indirect buffer parameter within a function call. + * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. + */ +class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { + SizedBufferMayWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { + result instanceof BufferMayMemoryAccess + } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + /** * An instruction representing a GNU or MSVC inline assembly statement. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index 2161fe1efa4..a23fb081afe 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -254,6 +254,16 @@ class AddressOperand extends RegisterOperand { override string toString() { result = "Address" } } +/** + * The buffer size operand of an instruction that represents a read or write of + * a buffer. + */ +class BufferSizeOperand extends RegisterOperand { + override BufferSizeOperandTag tag; + + override string toString() { result = "BufferSize" } +} + /** * The source value operand of an instruction that loads a value from memory (e.g. `Load`, * `ReturnValue`, `ThrowValue`). From fcfc11052ab35b9a7f2f7985a9d7df5c89a5116d Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 19 Sep 2019 14:35:07 -0700 Subject: [PATCH 0308/1227] C++: add QLDoc to side effect functions --- .../semmle/code/cpp/models/interfaces/SideEffect.qll | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll index e13123d1025..cc69365d8af 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll @@ -29,12 +29,24 @@ abstract class SideEffectFunction extends Function { */ abstract predicate hasOnlySpecificWriteSideEffects(); + /** + * Holds if the value pointed to by the parameter at index `i` is written to. `buffer` is true + * if the write may be at an offset. `mustWrite` is true if the write is unconditional. + */ predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { none() } + /** + * Holds if the value pointed to by the parameter at index `i` is read from. `buffer` is true + * if the read may be at an offset. + */ predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { none() } // TODO: name? + /** + * Gets the index of the parameter that indicates the size of the buffer pointed to by the + * parameter at index `i`. + */ ParameterIndex getParameterSizeIndex(ParameterIndex i) { none() } } From 9f20cb83c3c8aeebbfbcc1b4f1f8c2012409c973 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 23 Sep 2019 13:18:10 -0400 Subject: [PATCH 0309/1227] C++/C#: Autoformat --- cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll | 1 - .../code/cpp/ir/implementation/aliased_ssa/Instruction.qll | 1 - .../src/semmle/code/cpp/ir/implementation/raw/Instruction.qll | 1 - .../cpp/ir/implementation/raw/internal/TranslatedCall.qll | 4 ++-- .../code/cpp/ir/implementation/unaliased_ssa/Instruction.qll | 1 - .../code/cpp/models/implementations/IdentityFunction.qll | 1 - cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll | 1 - cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll | 4 ++-- csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll | 1 - .../semmle/code/csharp/ir/implementation/raw/Instruction.qll | 1 - 10 files changed, 4 insertions(+), 12 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index 8be5a1eaa79..0c1009b4fac 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -485,4 +485,3 @@ module Opcode { final override string toString() { result = "NewObj" } } } - diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 61a3885521d..83e6141052c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -648,7 +648,6 @@ class IndexedInstruction extends Instruction { int index; IndexedInstruction() { index = Construction::getInstructionIndex(this) } - final override string getImmediateString() { result = index.toString() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 61a3885521d..83e6141052c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -648,7 +648,6 @@ class IndexedInstruction extends Instruction { int index; IndexedInstruction() { index = Construction::getInstructionIndex(this) } - final override string getImmediateString() { result = index.toString() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 8f3deca1cac..f421e58ad0f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -460,8 +460,8 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff tag instanceof OnlyInstructionTag and operandTag instanceof BufferSizeOperandTag and result = getTranslatedExpr(call - .getArgument(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index)).getFullyConverted()) - .getResult() + .getArgument(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index)) + .getFullyConverted()).getResult() } override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 61a3885521d..83e6141052c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -648,7 +648,6 @@ class IndexedInstruction extends Instruction { int index; IndexedInstruction() { index = Construction::getInstructionIndex(this) } - final override string getImmediateString() { result = index.toString() } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll index 3e7fa713bd8..865a74b5571 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll @@ -37,4 +37,3 @@ class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFuncti input.isParameter(0) and output.isReturnValue() } } - diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index d3d63870577..c5729c5d0f6 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -95,4 +95,3 @@ class PureFunction extends TaintFunction, SideEffectFunction { override predicate hasOnlySpecificWriteSideEffects() { any() } } - diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll index cc69365d8af..905e79eb32b 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffect.qll @@ -31,7 +31,7 @@ abstract class SideEffectFunction extends Function { /** * Holds if the value pointed to by the parameter at index `i` is written to. `buffer` is true - * if the write may be at an offset. `mustWrite` is true if the write is unconditional. + * if the write may be at an offset. `mustWrite` is true if the write is unconditional. */ predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { none() @@ -39,7 +39,7 @@ abstract class SideEffectFunction extends Function { /** * Holds if the value pointed to by the parameter at index `i` is read from. `buffer` is true - * if the read may be at an offset. + * if the read may be at an offset. */ predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll index 8be5a1eaa79..0c1009b4fac 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll @@ -485,4 +485,3 @@ module Opcode { final override string toString() { result = "NewObj" } } } - diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 61a3885521d..83e6141052c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -648,7 +648,6 @@ class IndexedInstruction extends Instruction { int index; IndexedInstruction() { index = Construction::getInstructionIndex(this) } - final override string getImmediateString() { result = index.toString() } From a45a6e48f8cc79ae6defc116c664033c4e08a166 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 27 Sep 2019 17:16:47 -0400 Subject: [PATCH 0310/1227] C++: remove side effect operands from non-reads --- .../aliased_ssa/Instruction.qll | 4 +- .../cpp/ir/implementation/raw/Instruction.qll | 4 +- .../raw/internal/TranslatedCall.qll | 7 +- .../unaliased_ssa/Instruction.qll | 4 +- .../test/library-tests/ir/ir/raw_ir.expected | 154 +++++++++--------- .../ir/ssa/aliased_ssa_ir.expected | 6 +- .../ir/ssa/unaliased_ssa_ir.expected | 6 +- .../syntax-zoo/aliased_ssa_sanity.expected | 4 + .../syntax-zoo/raw_sanity.expected | 7 +- .../syntax-zoo/unaliased_ssa_sanity.expected | 4 + 10 files changed, 104 insertions(+), 96 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 83e6141052c..efc873b8f44 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -48,8 +48,8 @@ module InstructionSanity { or ( opcode instanceof ReadSideEffectOpcode or - opcode instanceof MayWriteSideEffectOpcode or - opcode instanceof Opcode::InlineAsm + opcode instanceof Opcode::InlineAsm or + opcode instanceof Opcode::CallSideEffect ) and tag instanceof SideEffectOperandTag ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 83e6141052c..efc873b8f44 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -48,8 +48,8 @@ module InstructionSanity { or ( opcode instanceof ReadSideEffectOpcode or - opcode instanceof MayWriteSideEffectOpcode or - opcode instanceof Opcode::InlineAsm + opcode instanceof Opcode::InlineAsm or + opcode instanceof Opcode::CallSideEffect ) and tag instanceof SideEffectOperandTag ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index f421e58ad0f..4a7aa607f57 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -449,12 +449,7 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff or tag instanceof OnlyInstructionTag and operandTag instanceof SideEffectOperandTag and - not call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(index, _, true) and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() - or - tag instanceof OnlyInstructionTag and - operandTag instanceof SideEffectOperandTag and - call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(index, _) and + not isWrite() and result = getEnclosingFunction().getUnmodeledDefinitionInstruction() or tag instanceof OnlyInstructionTag and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 83e6141052c..efc873b8f44 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -48,8 +48,8 @@ module InstructionSanity { or ( opcode instanceof ReadSideEffectOpcode or - opcode instanceof MayWriteSideEffectOpcode or - opcode instanceof Opcode::InlineAsm + opcode instanceof Opcode::InlineAsm or + opcode instanceof Opcode::CallSideEffect ) and tag instanceof SideEffectOperandTag ) diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 16bf7da8507..3bff2bff690 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -15,7 +15,7 @@ bad_asts.cpp: # 16| r0_11(int) = Call : func:r0_9, this:r0_8, 0:r0_10 # 16| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 16| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_8, ~mu0_2 -# 16| mu0_14(S) = ^IndirectMayWriteSideEffect[-1] : &:r0_8, ~mu0_2 +# 16| mu0_14(S) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 # 17| v0_15(void) = NoOp : # 14| v0_16(void) = ReturnVoid : # 14| v0_17(void) = UnmodeledUse : mu* @@ -2677,8 +2677,8 @@ ir.cpp: # 585| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 # 585| v0_11(void) = ^IndirectReadSideEffect[0] : &:r0_5, ~mu0_2 # 585| v0_12(void) = ^IndirectReadSideEffect[2] : &:r0_8, ~mu0_2 -# 585| mu0_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_5, ~mu0_2 -# 585| mu0_14(unknown) = ^BufferMayWriteSideEffect[2] : &:r0_8, ~mu0_2 +# 585| mu0_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_5 +# 585| mu0_14(unknown) = ^BufferMayWriteSideEffect[2] : &:r0_8 # 586| v0_15(void) = NoOp : # 584| v0_16(void) = ReturnVoid : # 584| v0_17(void) = UnmodeledUse : mu* @@ -2722,7 +2722,7 @@ ir.cpp: # 617| v0_11(void) = Call : func:r0_8, this:r0_7, 0:r0_10 # 617| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 617| v0_13(void) = ^IndirectReadSideEffect[0] : &:r0_10, ~mu0_2 -# 617| mu0_14(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_10, ~mu0_2 +# 617| mu0_14(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_10 # 618| r0_15(glval) = VariableAddress[s3] : # 618| r0_16(glval) = FunctionAddress[ReturnObject] : # 618| r0_17(String) = Call : func:r0_16 @@ -2735,7 +2735,7 @@ ir.cpp: # 619| v0_24(void) = Call : func:r0_21, this:r0_20, 0:r0_23 # 619| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 # 619| v0_26(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 -# 619| mu0_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23, ~mu0_2 +# 619| mu0_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23 # 620| v0_28(void) = NoOp : # 615| v0_29(void) = ReturnVoid : # 615| v0_30(void) = UnmodeledUse : mu* @@ -2759,7 +2759,7 @@ ir.cpp: # 623| r0_13(char *) = Call : func:r0_12, this:r0_11 # 623| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 # 623| v0_15(void) = ^IndirectReadSideEffect[-1] : &:r0_11, ~mu0_2 -# 623| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_11, ~mu0_2 +# 623| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_11 # 624| r0_17(glval) = VariableAddress[p] : # 624| r0_18(String *) = Load : &:r0_17, ~mu0_2 # 624| r0_19(String *) = Convert : r0_18 @@ -2767,14 +2767,14 @@ ir.cpp: # 624| r0_21(char *) = Call : func:r0_20, this:r0_19 # 624| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 # 624| v0_23(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~mu0_2 -# 624| mu0_24(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19, ~mu0_2 +# 624| mu0_24(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19 # 625| r0_25(glval) = VariableAddress[s] : # 625| r0_26(glval) = Convert : r0_25 # 625| r0_27(glval) = FunctionAddress[c_str] : # 625| r0_28(char *) = Call : func:r0_27, this:r0_26 # 625| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 # 625| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_26, ~mu0_2 -# 625| mu0_31(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_26, ~mu0_2 +# 625| mu0_31(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_26 # 626| v0_32(void) = NoOp : # 622| v0_33(void) = ReturnVoid : # 622| v0_34(void) = UnmodeledUse : mu* @@ -2882,21 +2882,21 @@ ir.cpp: # 653| r0_7(int) = Call : func:r0_5, this:r0_4, 0:r0_6 # 653| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 # 653| v0_9(void) = ^IndirectReadSideEffect[-1] : &:r0_4, ~mu0_2 -# 653| mu0_10(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_4, ~mu0_2 +# 653| mu0_10(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 # 654| r0_11(C *) = CopyValue : r0_3 # 654| r0_12(glval) = FunctionAddress[InstanceMemberFunction] : # 654| r0_13(int) = Constant[1] : # 654| r0_14(int) = Call : func:r0_12, this:r0_11, 0:r0_13 # 654| mu0_15(unknown) = ^CallSideEffect : ~mu0_2 # 654| v0_16(void) = ^IndirectReadSideEffect[-1] : &:r0_11, ~mu0_2 -# 654| mu0_17(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_11, ~mu0_2 +# 654| mu0_17(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_11 #-----| r0_18(C *) = CopyValue : r0_3 # 655| r0_19(glval) = FunctionAddress[InstanceMemberFunction] : # 655| r0_20(int) = Constant[2] : # 655| r0_21(int) = Call : func:r0_19, this:r0_18, 0:r0_20 # 655| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_23(void) = ^IndirectReadSideEffect[-1] : &:r0_18, ~mu0_2 -#-----| mu0_24(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_18, ~mu0_2 +#-----| mu0_24(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_18 # 656| v0_25(void) = NoOp : # 652| v0_26(void) = ReturnVoid : # 652| v0_27(void) = UnmodeledUse : mu* @@ -2928,7 +2928,7 @@ ir.cpp: # 662| v0_21(void) = Call : func:r0_18, this:r0_17, 0:r0_20 # 662| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 # 662| v0_23(void) = ^IndirectReadSideEffect[0] : &:r0_20, ~mu0_2 -# 662| mu0_24(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_20, ~mu0_2 +# 662| mu0_24(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_20 # 664| v0_25(void) = NoOp : # 658| v0_26(void) = ReturnVoid : # 658| v0_27(void) = UnmodeledUse : mu* @@ -3128,7 +3128,7 @@ ir.cpp: # 721| r0_7(long) = Call : func:r0_4, 0:r0_5, 1:r0_6 # 721| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 # 721| v0_9(void) = ^IndirectReadSideEffect[0] : &:r0_5, ~mu0_2 -# 721| mu0_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_5, ~mu0_2 +# 721| mu0_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_5 # 721| r0_11(double) = Convert : r0_7 # 721| mu0_12(double) = Store : &:r0_3, r0_11 # 720| r0_13(glval) = VariableAddress[#return] : @@ -3202,7 +3202,7 @@ ir.cpp: # 731| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 731| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 # 731| v7_6(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 -# 731| mu7_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3, ~mu0_2 +# 731| mu7_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 # 731| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 @@ -3227,7 +3227,7 @@ ir.cpp: # 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 # 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 # 736| v10_8(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 -# 736| mu10_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5, ~mu0_2 +# 736| mu10_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 # 736| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 @@ -3270,8 +3270,8 @@ ir.cpp: # 745| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~mu0_2 #-----| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 -#-----| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_7, ~mu0_2 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11, ~mu0_2 +#-----| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 #-----| r0_18(glval) = VariableAddress[#return] : #-----| r0_19(Base *) = CopyValue : r0_3 #-----| mu0_20(Base &) = Store : &:r0_18, r0_19 @@ -3345,8 +3345,8 @@ ir.cpp: # 754| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~mu0_2 #-----| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 -#-----| mu0_16(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_7, ~mu0_2 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11, ~mu0_2 +#-----| mu0_16(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 #-----| r0_18(Middle *) = CopyValue : r0_3 #-----| r0_19(glval) = FieldAddress[middle_s] : r0_18 # 754| r0_20(glval) = FunctionAddress[operator=] : @@ -3357,8 +3357,8 @@ ir.cpp: # 754| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_26(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~mu0_2 #-----| v0_27(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 -#-----| mu0_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19, ~mu0_2 -#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23, ~mu0_2 +#-----| mu0_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19 +#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23 #-----| r0_30(glval) = VariableAddress[#return] : #-----| r0_31(Middle *) = CopyValue : r0_3 #-----| mu0_32(Middle &) = Store : &:r0_30, r0_31 @@ -3423,8 +3423,8 @@ ir.cpp: # 763| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~mu0_2 #-----| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 -#-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_7, ~mu0_2 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11, ~mu0_2 +#-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 #-----| r0_18(Derived *) = CopyValue : r0_3 #-----| r0_19(glval) = FieldAddress[derived_s] : r0_18 # 763| r0_20(glval) = FunctionAddress[operator=] : @@ -3435,8 +3435,8 @@ ir.cpp: # 763| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_26(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~mu0_2 #-----| v0_27(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 -#-----| mu0_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19, ~mu0_2 -#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23, ~mu0_2 +#-----| mu0_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19 +#-----| mu0_29(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23 #-----| r0_30(glval) = VariableAddress[#return] : #-----| r0_31(Derived *) = CopyValue : r0_3 #-----| mu0_32(Derived &) = Store : &:r0_30, r0_31 @@ -3647,8 +3647,8 @@ ir.cpp: # 808| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 # 808| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_24, ~mu0_2 # 808| v0_31(void) = ^IndirectReadSideEffect[0] : &:r0_27, ~mu0_2 -# 808| mu0_32(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_24, ~mu0_2 -# 808| mu0_33(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_27, ~mu0_2 +# 808| mu0_32(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_24 +# 808| mu0_33(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_27 # 809| r0_34(glval) = VariableAddress[b] : # 809| r0_35(glval) = FunctionAddress[operator=] : # 809| r0_36(glval) = FunctionAddress[Base] : @@ -3657,14 +3657,14 @@ ir.cpp: # 809| v0_39(void) = Call : func:r0_36, 0:r0_38 # 809| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 # 809| v0_41(void) = ^IndirectReadSideEffect[0] : &:r0_38, ~mu0_2 -# 809| mu0_42(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_38, ~mu0_2 +# 809| mu0_42(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_38 # 809| r0_43(glval) = Convert : v0_39 # 809| r0_44(Base &) = Call : func:r0_35, this:r0_34, 0:r0_43 # 809| mu0_45(unknown) = ^CallSideEffect : ~mu0_2 # 809| v0_46(void) = ^IndirectReadSideEffect[-1] : &:r0_34, ~mu0_2 # 809| v0_47(void) = ^IndirectReadSideEffect[0] : &:r0_43, ~mu0_2 -# 809| mu0_48(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_34, ~mu0_2 -# 809| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_43, ~mu0_2 +# 809| mu0_48(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_34 +# 809| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_43 # 810| r0_50(glval) = VariableAddress[b] : # 810| r0_51(glval) = FunctionAddress[operator=] : # 810| r0_52(glval) = FunctionAddress[Base] : @@ -3673,14 +3673,14 @@ ir.cpp: # 810| v0_55(void) = Call : func:r0_52, 0:r0_54 # 810| mu0_56(unknown) = ^CallSideEffect : ~mu0_2 # 810| v0_57(void) = ^IndirectReadSideEffect[0] : &:r0_54, ~mu0_2 -# 810| mu0_58(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_54, ~mu0_2 +# 810| mu0_58(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_54 # 810| r0_59(glval) = Convert : v0_55 # 810| r0_60(Base &) = Call : func:r0_51, this:r0_50, 0:r0_59 # 810| mu0_61(unknown) = ^CallSideEffect : ~mu0_2 # 810| v0_62(void) = ^IndirectReadSideEffect[-1] : &:r0_50, ~mu0_2 # 810| v0_63(void) = ^IndirectReadSideEffect[0] : &:r0_59, ~mu0_2 -# 810| mu0_64(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_50, ~mu0_2 -# 810| mu0_65(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_59, ~mu0_2 +# 810| mu0_64(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_50 +# 810| mu0_65(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_59 # 811| r0_66(glval) = VariableAddress[pm] : # 811| r0_67(Middle *) = Load : &:r0_66, ~mu0_2 # 811| r0_68(Base *) = ConvertToBase[Middle : Base] : r0_67 @@ -3710,8 +3710,8 @@ ir.cpp: # 816| mu0_92(unknown) = ^CallSideEffect : ~mu0_2 # 816| v0_93(void) = ^IndirectReadSideEffect[-1] : &:r0_86, ~mu0_2 # 816| v0_94(void) = ^IndirectReadSideEffect[0] : &:r0_90, ~mu0_2 -# 816| mu0_95(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_86, ~mu0_2 -# 816| mu0_96(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_90, ~mu0_2 +# 816| mu0_95(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_86 +# 816| mu0_96(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_90 # 817| r0_97(glval) = VariableAddress[m] : # 817| r0_98(glval) = FunctionAddress[operator=] : # 817| r0_99(glval) = VariableAddress[b] : @@ -3721,8 +3721,8 @@ ir.cpp: # 817| mu0_103(unknown) = ^CallSideEffect : ~mu0_2 # 817| v0_104(void) = ^IndirectReadSideEffect[-1] : &:r0_97, ~mu0_2 # 817| v0_105(void) = ^IndirectReadSideEffect[0] : &:r0_101, ~mu0_2 -# 817| mu0_106(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_97, ~mu0_2 -# 817| mu0_107(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_101, ~mu0_2 +# 817| mu0_106(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_97 +# 817| mu0_107(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_101 # 818| r0_108(glval) = VariableAddress[pb] : # 818| r0_109(Base *) = Load : &:r0_108, ~mu0_2 # 818| r0_110(Middle *) = ConvertToDerived[Middle : Base] : r0_109 @@ -3747,8 +3747,8 @@ ir.cpp: # 822| mu0_129(unknown) = ^CallSideEffect : ~mu0_2 # 822| v0_130(void) = ^IndirectReadSideEffect[-1] : &:r0_123, ~mu0_2 # 822| v0_131(void) = ^IndirectReadSideEffect[0] : &:r0_127, ~mu0_2 -# 822| mu0_132(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_123, ~mu0_2 -# 822| mu0_133(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_127, ~mu0_2 +# 822| mu0_132(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_123 +# 822| mu0_133(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_127 # 823| r0_134(glval) = VariableAddress[b] : # 823| r0_135(glval) = FunctionAddress[operator=] : # 823| r0_136(glval) = FunctionAddress[Base] : @@ -3758,14 +3758,14 @@ ir.cpp: # 823| v0_140(void) = Call : func:r0_136, 0:r0_139 # 823| mu0_141(unknown) = ^CallSideEffect : ~mu0_2 # 823| v0_142(void) = ^IndirectReadSideEffect[0] : &:r0_139, ~mu0_2 -# 823| mu0_143(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_139, ~mu0_2 +# 823| mu0_143(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_139 # 823| r0_144(glval) = Convert : v0_140 # 823| r0_145(Base &) = Call : func:r0_135, this:r0_134, 0:r0_144 # 823| mu0_146(unknown) = ^CallSideEffect : ~mu0_2 # 823| v0_147(void) = ^IndirectReadSideEffect[-1] : &:r0_134, ~mu0_2 # 823| v0_148(void) = ^IndirectReadSideEffect[0] : &:r0_144, ~mu0_2 -# 823| mu0_149(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_134, ~mu0_2 -# 823| mu0_150(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_144, ~mu0_2 +# 823| mu0_149(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_134 +# 823| mu0_150(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_144 # 824| r0_151(glval) = VariableAddress[b] : # 824| r0_152(glval) = FunctionAddress[operator=] : # 824| r0_153(glval) = FunctionAddress[Base] : @@ -3775,14 +3775,14 @@ ir.cpp: # 824| v0_157(void) = Call : func:r0_153, 0:r0_156 # 824| mu0_158(unknown) = ^CallSideEffect : ~mu0_2 # 824| v0_159(void) = ^IndirectReadSideEffect[0] : &:r0_156, ~mu0_2 -# 824| mu0_160(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_156, ~mu0_2 +# 824| mu0_160(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_156 # 824| r0_161(glval) = Convert : v0_157 # 824| r0_162(Base &) = Call : func:r0_152, this:r0_151, 0:r0_161 # 824| mu0_163(unknown) = ^CallSideEffect : ~mu0_2 # 824| v0_164(void) = ^IndirectReadSideEffect[-1] : &:r0_151, ~mu0_2 # 824| v0_165(void) = ^IndirectReadSideEffect[0] : &:r0_161, ~mu0_2 -# 824| mu0_166(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_151, ~mu0_2 -# 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_161, ~mu0_2 +# 824| mu0_166(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_151 +# 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_161 # 825| r0_168(glval) = VariableAddress[pd] : # 825| r0_169(Derived *) = Load : &:r0_168, ~mu0_2 # 825| r0_170(Middle *) = ConvertToBase[Derived : Middle] : r0_169 @@ -3816,8 +3816,8 @@ ir.cpp: # 830| mu0_198(unknown) = ^CallSideEffect : ~mu0_2 # 830| v0_199(void) = ^IndirectReadSideEffect[-1] : &:r0_191, ~mu0_2 # 830| v0_200(void) = ^IndirectReadSideEffect[0] : &:r0_196, ~mu0_2 -# 830| mu0_201(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_191, ~mu0_2 -# 830| mu0_202(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_196, ~mu0_2 +# 830| mu0_201(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_191 +# 830| mu0_202(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_196 # 831| r0_203(glval) = VariableAddress[d] : # 831| r0_204(glval) = FunctionAddress[operator=] : # 831| r0_205(glval) = VariableAddress[b] : @@ -3828,8 +3828,8 @@ ir.cpp: # 831| mu0_210(unknown) = ^CallSideEffect : ~mu0_2 # 831| v0_211(void) = ^IndirectReadSideEffect[-1] : &:r0_203, ~mu0_2 # 831| v0_212(void) = ^IndirectReadSideEffect[0] : &:r0_208, ~mu0_2 -# 831| mu0_213(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_203, ~mu0_2 -# 831| mu0_214(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_208, ~mu0_2 +# 831| mu0_213(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_203 +# 831| mu0_214(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_208 # 832| r0_215(glval) = VariableAddress[pb] : # 832| r0_216(Base *) = Load : &:r0_215, ~mu0_2 # 832| r0_217(Middle *) = ConvertToDerived[Middle : Base] : r0_216 @@ -3973,7 +3973,7 @@ ir.cpp: # 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 # 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 # 868| v0_9(void) = ^IndirectReadSideEffect[0] : &:r0_6, ~mu0_2 -# 868| mu0_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6, ~mu0_2 +# 868| mu0_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6 # 869| v0_11(void) = NoOp : # 867| v0_12(void) = ReturnVoid : # 867| v0_13(void) = UnmodeledUse : mu* @@ -4190,7 +4190,7 @@ ir.cpp: # 945| v0_38(void) = Call : func:r0_35, this:r0_34, 0:r0_37 # 945| mu0_39(unknown) = ^CallSideEffect : ~mu0_2 # 945| v0_40(void) = ^IndirectReadSideEffect[0] : &:r0_37, ~mu0_2 -# 945| mu0_41(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_37, ~mu0_2 +# 945| mu0_41(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_37 # 946| r0_42(glval) = FunctionAddress[operator new] : # 946| r0_43(unsigned long) = Constant[256] : # 946| r0_44(align_val_t) = Constant[128] : @@ -4678,7 +4678,7 @@ ir.cpp: # 1035| r0_29(char) = Call : func:r0_27, this:r0_26, 0:r0_28 # 1035| mu0_30(unknown) = ^CallSideEffect : ~mu0_2 # 1035| v0_31(void) = ^IndirectReadSideEffect[-1] : &:r0_26, ~mu0_2 -# 1035| mu0_32(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_26, ~mu0_2 +# 1035| mu0_32(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_26 # 1036| r0_33(glval) = VariableAddress[lambda_val] : # 1036| r0_34(glval) = FunctionAddress[(constructor)] : # 1036| r0_35(glval) = VariableAddress[#temp1036:21] : @@ -4695,7 +4695,7 @@ ir.cpp: # 1036| v0_46(void) = Call : func:r0_34, this:r0_33, 0:r0_45 # 1036| mu0_47(unknown) = ^CallSideEffect : ~mu0_2 # 1036| v0_48(void) = ^IndirectReadSideEffect[0] : &:r0_45, ~mu0_2 -# 1036| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_45, ~mu0_2 +# 1036| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_45 # 1037| r0_50(glval) = VariableAddress[lambda_val] : # 1037| r0_51(glval) = Convert : r0_50 # 1037| r0_52(glval) = FunctionAddress[operator()] : @@ -4703,7 +4703,7 @@ ir.cpp: # 1037| r0_54(char) = Call : func:r0_52, this:r0_51, 0:r0_53 # 1037| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 # 1037| v0_56(void) = ^IndirectReadSideEffect[-1] : &:r0_51, ~mu0_2 -# 1037| mu0_57(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_51, ~mu0_2 +# 1037| mu0_57(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_51 # 1038| r0_58(glval) = VariableAddress[lambda_ref_explicit] : # 1038| r0_59(glval) = VariableAddress[#temp1038:30] : # 1038| mu0_60(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_59 @@ -4720,7 +4720,7 @@ ir.cpp: # 1039| r0_71(char) = Call : func:r0_69, this:r0_68, 0:r0_70 # 1039| mu0_72(unknown) = ^CallSideEffect : ~mu0_2 # 1039| v0_73(void) = ^IndirectReadSideEffect[-1] : &:r0_68, ~mu0_2 -# 1039| mu0_74(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_68, ~mu0_2 +# 1039| mu0_74(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_68 # 1040| r0_75(glval) = VariableAddress[lambda_val_explicit] : # 1040| r0_76(glval) = FunctionAddress[(constructor)] : # 1040| r0_77(glval) = VariableAddress[#temp1040:30] : @@ -4733,7 +4733,7 @@ ir.cpp: # 1040| v0_84(void) = Call : func:r0_76, this:r0_75, 0:r0_83 # 1040| mu0_85(unknown) = ^CallSideEffect : ~mu0_2 # 1040| v0_86(void) = ^IndirectReadSideEffect[0] : &:r0_83, ~mu0_2 -# 1040| mu0_87(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_83, ~mu0_2 +# 1040| mu0_87(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_83 # 1041| r0_88(glval) = VariableAddress[lambda_val_explicit] : # 1041| r0_89(glval) = Convert : r0_88 # 1041| r0_90(glval) = FunctionAddress[operator()] : @@ -4741,7 +4741,7 @@ ir.cpp: # 1041| r0_92(char) = Call : func:r0_90, this:r0_89, 0:r0_91 # 1041| mu0_93(unknown) = ^CallSideEffect : ~mu0_2 # 1041| v0_94(void) = ^IndirectReadSideEffect[-1] : &:r0_89, ~mu0_2 -# 1041| mu0_95(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_89, ~mu0_2 +# 1041| mu0_95(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_89 # 1042| r0_96(glval) = VariableAddress[lambda_mixed_explicit] : # 1042| r0_97(glval) = VariableAddress[#temp1042:32] : # 1042| mu0_98(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_97 @@ -4762,7 +4762,7 @@ ir.cpp: # 1043| r0_113(char) = Call : func:r0_111, this:r0_110, 0:r0_112 # 1043| mu0_114(unknown) = ^CallSideEffect : ~mu0_2 # 1043| v0_115(void) = ^IndirectReadSideEffect[-1] : &:r0_110, ~mu0_2 -# 1043| mu0_116(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_110, ~mu0_2 +# 1043| mu0_116(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_110 # 1044| r0_117(glval) = VariableAddress[r] : # 1044| r0_118(glval) = VariableAddress[x] : # 1044| r0_119(int) = Load : &:r0_118, ~mu0_2 @@ -4798,7 +4798,7 @@ ir.cpp: # 1046| r0_149(char) = Call : func:r0_147, this:r0_146, 0:r0_148 # 1046| mu0_150(unknown) = ^CallSideEffect : ~mu0_2 # 1046| v0_151(void) = ^IndirectReadSideEffect[-1] : &:r0_146, ~mu0_2 -# 1046| mu0_152(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_146, ~mu0_2 +# 1046| mu0_152(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_146 # 1047| v0_153(void) = NoOp : # 1031| v0_154(void) = ReturnVoid : # 1031| v0_155(void) = UnmodeledUse : mu* @@ -4863,7 +4863,7 @@ ir.cpp: # 1034| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1034| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 1034| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 -# 1034| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9, ~mu0_2 +# 1034| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 #-----| r0_15(lambda [] type at line 1034, col. 21 *) = CopyValue : r0_3 #-----| r0_16(glval) = FieldAddress[x] : r0_15 #-----| r0_17(int &) = Load : &:r0_16, ~mu0_2 @@ -4906,7 +4906,7 @@ ir.cpp: # 1036| r0_10(char *) = Call : func:r0_9, this:r0_8 # 1036| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_12(void) = ^IndirectReadSideEffect[-1] : &:r0_8, ~mu0_2 -#-----| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8, ~mu0_2 +#-----| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 #-----| r0_14(lambda [] type at line 1036, col. 21 *) = CopyValue : r0_3 #-----| r0_15(glval) = FieldAddress[x] : r0_14 #-----| r0_16(int) = Load : &:r0_15, ~mu0_2 @@ -4934,7 +4934,7 @@ ir.cpp: # 1038| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1038| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 1038| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 -# 1038| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9, ~mu0_2 +# 1038| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 # 1038| r0_15(int) = Constant[0] : # 1038| r0_16(glval) = PointerAdd[1] : r0_11, r0_15 # 1038| r0_17(char) = Load : &:r0_16, ~mu0_2 @@ -4991,7 +4991,7 @@ ir.cpp: # 1040| r0_10(char *) = Call : func:r0_9, this:r0_8 # 1040| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_12(void) = ^IndirectReadSideEffect[-1] : &:r0_8, ~mu0_2 -#-----| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8, ~mu0_2 +#-----| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 # 1040| r0_14(int) = Constant[0] : # 1040| r0_15(glval) = PointerAdd[1] : r0_10, r0_14 # 1040| r0_16(char) = Load : &:r0_15, ~mu0_2 @@ -5017,7 +5017,7 @@ ir.cpp: # 1042| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1042| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 1042| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 -# 1042| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9, ~mu0_2 +# 1042| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 #-----| r0_15(lambda [] type at line 1042, col. 32 *) = CopyValue : r0_3 #-----| r0_16(glval) = FieldAddress[x] : r0_15 #-----| r0_17(int) = Load : &:r0_16, ~mu0_2 @@ -5045,7 +5045,7 @@ ir.cpp: # 1045| r0_11(char *) = Call : func:r0_10, this:r0_9 # 1045| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 # 1045| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~mu0_2 -# 1045| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9, ~mu0_2 +# 1045| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 #-----| r0_15(lambda [] type at line 1045, col. 23 *) = CopyValue : r0_3 #-----| r0_16(glval) = FieldAddress[x] : r0_15 #-----| r0_17(int) = Load : &:r0_16, ~mu0_2 @@ -5084,7 +5084,7 @@ ir.cpp: # 1069| r0_13(iterator) = Call : func:r0_12, this:r0_11 # 1069| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_15(void) = ^IndirectReadSideEffect[-1] : &:r0_11, ~mu0_2 -#-----| mu0_16(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_11, ~mu0_2 +#-----| mu0_16(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_11 # 1069| mu0_17(iterator) = Store : &:r0_9, r0_13 # 1069| r0_18(glval) = VariableAddress[(__end)] : #-----| r0_19(glval &>) = VariableAddress[(__range)] : @@ -5093,7 +5093,7 @@ ir.cpp: # 1069| r0_22(iterator) = Call : func:r0_21, this:r0_20 # 1069| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 #-----| v0_24(void) = ^IndirectReadSideEffect[-1] : &:r0_20, ~mu0_2 -#-----| mu0_25(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_20, ~mu0_2 +#-----| mu0_25(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_20 # 1069| mu0_26(iterator) = Store : &:r0_18, r0_22 #-----| Goto -> Block 4 @@ -5105,7 +5105,7 @@ ir.cpp: # 1075| r1_4(int &) = Call : func:r1_3, this:r1_2 # 1075| mu1_5(unknown) = ^CallSideEffect : ~mu0_2 #-----| v1_6(void) = ^IndirectReadSideEffect[-1] : &:r1_2, ~mu0_2 -#-----| mu1_7(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r1_2, ~mu0_2 +#-----| mu1_7(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r1_2 # 1075| r1_8(glval) = Convert : r1_4 # 1075| mu1_9(int &) = Store : &:r1_0, r1_8 # 1076| r1_10(glval) = VariableAddress[e] : @@ -5137,7 +5137,7 @@ ir.cpp: # 1069| r4_5(bool) = Call : func:r4_2, this:r4_1, 0:r4_4 # 1069| mu4_6(unknown) = ^CallSideEffect : ~mu0_2 #-----| v4_7(void) = ^IndirectReadSideEffect[-1] : &:r4_1, ~mu0_2 -#-----| mu4_8(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r4_1, ~mu0_2 +#-----| mu4_8(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r4_1 # 1069| v4_9(void) = ConditionalBranch : r4_5 #-----| False -> Block 8 #-----| True -> Block 5 @@ -5150,7 +5150,7 @@ ir.cpp: # 1069| r5_4(int &) = Call : func:r5_3, this:r5_2 # 1069| mu5_5(unknown) = ^CallSideEffect : ~mu0_2 #-----| v5_6(void) = ^IndirectReadSideEffect[-1] : &:r5_2, ~mu0_2 -#-----| mu5_7(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r5_2, ~mu0_2 +#-----| mu5_7(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r5_2 # 1069| r5_8(int) = Load : &:r5_4, ~mu0_2 # 1069| mu5_9(int) = Store : &:r5_0, r5_8 # 1070| r5_10(glval) = VariableAddress[e] : @@ -5172,7 +5172,7 @@ ir.cpp: # 1069| r7_3(iterator &) = Call : func:r7_2, this:r7_1 # 1069| mu7_4(unknown) = ^CallSideEffect : ~mu0_2 #-----| v7_5(void) = ^IndirectReadSideEffect[-1] : &:r7_1, ~mu0_2 -#-----| mu7_6(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r7_1, ~mu0_2 +#-----| mu7_6(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r7_1 #-----| Goto (back edge) -> Block 4 # 1075| Block 8 @@ -5187,7 +5187,7 @@ ir.cpp: # 1075| r8_8(iterator) = Call : func:r8_7, this:r8_6 # 1075| mu8_9(unknown) = ^CallSideEffect : ~mu0_2 #-----| v8_10(void) = ^IndirectReadSideEffect[-1] : &:r8_6, ~mu0_2 -#-----| mu8_11(vector) = ^IndirectMayWriteSideEffect[-1] : &:r8_6, ~mu0_2 +#-----| mu8_11(vector) = ^IndirectMayWriteSideEffect[-1] : &:r8_6 # 1075| mu8_12(iterator) = Store : &:r8_4, r8_8 # 1075| r8_13(glval) = VariableAddress[(__end)] : #-----| r8_14(glval &>) = VariableAddress[(__range)] : @@ -5196,7 +5196,7 @@ ir.cpp: # 1075| r8_17(iterator) = Call : func:r8_16, this:r8_15 # 1075| mu8_18(unknown) = ^CallSideEffect : ~mu0_2 #-----| v8_19(void) = ^IndirectReadSideEffect[-1] : &:r8_15, ~mu0_2 -#-----| mu8_20(vector) = ^IndirectMayWriteSideEffect[-1] : &:r8_15, ~mu0_2 +#-----| mu8_20(vector) = ^IndirectMayWriteSideEffect[-1] : &:r8_15 # 1075| mu8_21(iterator) = Store : &:r8_13, r8_17 #-----| Goto -> Block 9 @@ -5209,7 +5209,7 @@ ir.cpp: # 1075| r9_5(bool) = Call : func:r9_2, this:r9_1, 0:r9_4 # 1075| mu9_6(unknown) = ^CallSideEffect : ~mu0_2 #-----| v9_7(void) = ^IndirectReadSideEffect[-1] : &:r9_1, ~mu0_2 -#-----| mu9_8(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r9_1, ~mu0_2 +#-----| mu9_8(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r9_1 # 1075| v9_9(void) = ConditionalBranch : r9_5 #-----| False -> Block 3 #-----| True -> Block 1 @@ -5220,7 +5220,7 @@ ir.cpp: # 1075| r10_2(iterator &) = Call : func:r10_1, this:r10_0 # 1075| mu10_3(unknown) = ^CallSideEffect : ~mu0_2 #-----| v10_4(void) = ^IndirectReadSideEffect[-1] : &:r10_0, ~mu0_2 -#-----| mu10_5(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r10_0, ~mu0_2 +#-----| mu10_5(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r10_0 #-----| Goto (back edge) -> Block 9 # 1099| int AsmStmt(int) @@ -5379,7 +5379,7 @@ ir.cpp: # 1140| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 1140| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 # 1140| v7_6(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 -# 1140| mu7_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3, ~mu0_2 +# 1140| mu7_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 # 1140| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 @@ -5404,7 +5404,7 @@ ir.cpp: # 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 # 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 # 1145| v10_8(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 -# 1145| mu10_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5, ~mu0_2 +# 1145| mu10_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 # 1145| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 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 7143eaa7990..9d005c57ca8 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 @@ -328,7 +328,7 @@ ssa.cpp: # 97| m0_14(unknown) = ^CallSideEffect : ~m0_5 # 97| m0_15(unknown) = Chi : total:m0_5, partial:m0_14 # 97| v0_16(void) = ^IndirectReadSideEffect[0] : &:r0_12, ~m0_15 -# 97| m0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12, ~m0_15 +# 97| m0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12 # 97| m0_18(unknown) = Chi : total:m0_15, partial:m0_17 # 98| v0_19(void) = NoOp : # 95| v0_20(void) = ReturnVoid : @@ -382,7 +382,7 @@ ssa.cpp: # 108| m0_20(unknown) = ^CallSideEffect : ~m0_5 # 108| m0_21(unknown) = Chi : total:m0_5, partial:m0_20 # 108| v0_22(void) = ^IndirectReadSideEffect[0] : &:r0_18, ~m0_21 -# 108| m0_23(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_18, ~m0_21 +# 108| m0_23(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_18 # 108| m0_24(unknown) = Chi : total:m0_21, partial:m0_23 # 109| v0_25(void) = NoOp : # 105| v0_26(void) = ReturnVoid : @@ -452,7 +452,7 @@ ssa.cpp: # 119| m0_28(unknown) = ^CallSideEffect : ~m0_19 # 119| m0_29(unknown) = Chi : total:m0_19, partial:m0_28 # 119| v0_30(void) = ^IndirectReadSideEffect[0] : &:r0_26, ~m0_29 -# 119| m0_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26, ~m0_29 +# 119| m0_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 # 119| m0_32(unknown) = Chi : total:m0_29, partial:m0_31 # 120| v0_33(void) = NoOp : # 116| v0_34(void) = ReturnVoid : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 15a6127e737..a68690c7055 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -327,7 +327,7 @@ ssa.cpp: # 97| v0_12(void) = Call : func:r0_9, 0:r0_11 # 97| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 # 97| v0_14(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 -# 97| mu0_15(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11, ~mu0_2 +# 97| mu0_15(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 # 98| v0_16(void) = NoOp : # 95| v0_17(void) = ReturnVoid : # 95| v0_18(void) = UnmodeledUse : mu* @@ -378,7 +378,7 @@ ssa.cpp: # 108| v0_18(void) = Call : func:r0_15, 0:r0_17 # 108| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 # 108| v0_20(void) = ^IndirectReadSideEffect[0] : &:r0_17, ~mu0_2 -# 108| mu0_21(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_17, ~mu0_2 +# 108| mu0_21(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_17 # 109| v0_22(void) = NoOp : # 105| v0_23(void) = ReturnVoid : # 105| v0_24(void) = UnmodeledUse : mu* @@ -441,7 +441,7 @@ ssa.cpp: # 119| v0_24(void) = Call : func:r0_21, 0:r0_23 # 119| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 # 119| v0_26(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 -# 119| mu0_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23, ~mu0_2 +# 119| mu0_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23 # 120| v0_28(void) = NoOp : # 116| v0_29(void) = ReturnVoid : # 116| v0_30(void) = UnmodeledUse : mu* diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index 0891f1e0b6c..5fb356f5701 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -1,5 +1,9 @@ missingOperand | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | +| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | allocators.cpp:14:5:14:8 | IR: main | int main() | +| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | no_dynamic_init.cpp:9:5:9:8 | IR: main | int main() | +| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | parameterinitializer.cpp:18:5:18:8 | IR: main | int main() | +| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | stream_it.cpp:16:5:16:8 | IR: main | int main() | | try_catch.cpp:13:5:13:16 | ThrowValue: throw ... | Instruction 'ThrowValue' is missing an expected operand with tag 'Load' in function '$@'. | try_catch.cpp:11:6:11:17 | IR: bypass_catch | void bypass_catch() | unexpectedOperand duplicateOperand diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index e3e241f35e8..426424a5fd4 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -27,7 +27,7 @@ instructionWithoutSuccessor | assume0.cpp:7:2:7:2 | CallSideEffect: call to f | | assume0.cpp:9:11:9:11 | Constant: (bool)... | | condition_decls.cpp:16:19:16:20 | CallSideEffect: call to BoxedInt | -| condition_decls.cpp:26:19:26:19 | CallSideEffect: call to operator int | +| condition_decls.cpp:26:19:26:20 | IndirectMayWriteSideEffect: bi | | condition_decls.cpp:26:23:26:24 | CallSideEffect: call to BoxedInt | | condition_decls.cpp:41:22:41:23 | CallSideEffect: call to BoxedInt | | condition_decls.cpp:48:52:48:53 | CallSideEffect: call to BoxedInt | @@ -614,12 +614,14 @@ useNotDominatedByDefinition | assume0.cpp:11:2:11:2 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | assume0.cpp:5:6:5:6 | IR: h | void h() | | condition_decls.cpp:16:15:16:15 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | | condition_decls.cpp:16:15:16:16 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | +| condition_decls.cpp:16:15:16:16 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | | condition_decls.cpp:17:5:17:15 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | | condition_decls.cpp:17:11:17:15 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | | condition_decls.cpp:20:5:20:15 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | | condition_decls.cpp:20:11:20:15 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | | condition_decls.cpp:26:19:26:19 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | | condition_decls.cpp:26:19:26:20 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | +| condition_decls.cpp:26:19:26:20 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | | condition_decls.cpp:28:5:28:15 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | | condition_decls.cpp:28:11:28:15 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | | condition_decls.cpp:31:5:31:15 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | @@ -628,14 +630,17 @@ useNotDominatedByDefinition | condition_decls.cpp:34:9:34:13 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | | condition_decls.cpp:41:18:41:18 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | | condition_decls.cpp:41:18:41:19 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | +| condition_decls.cpp:41:18:41:19 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | | condition_decls.cpp:42:5:42:7 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | | condition_decls.cpp:44:3:44:5 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | | condition_decls.cpp:48:48:48:48 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | | condition_decls.cpp:48:48:48:49 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | +| condition_decls.cpp:48:48:48:49 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | | condition_decls.cpp:48:56:48:61 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | | condition_decls.cpp:49:5:49:7 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | | condition_decls.cpp:51:3:51:5 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | | cpp11.cpp:28:21:28:21 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | cpp11.cpp:27:7:27:14 | IR: getFirst | int range_based_for_11::getFirst() | +| file://:0:0:0:0 | Operand | Operand 'Operand' is not dominated by its definition in function '$@'. | cpp11.cpp:27:7:27:14 | IR: getFirst | int range_based_for_11::getFirst() | | misc.c:68:16:68:16 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | misc.c:16:6:16:10 | IR: misc1 | void misc1(int, int) | | misc.c:70:13:70:15 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | misc.c:16:6:16:10 | IR: misc1 | void misc1(int, int) | | misc.c:72:11:72:11 | Load | Operand 'Load' is not dominated by its definition in function '$@'. | misc.c:16:6:16:10 | IR: misc1 | void misc1(int, int) | diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index d68395fe136..22a395b3f89 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -1,5 +1,9 @@ missingOperand | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | +| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | allocators.cpp:14:5:14:8 | IR: main | int main() | +| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | no_dynamic_init.cpp:9:5:9:8 | IR: main | int main() | +| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | parameterinitializer.cpp:18:5:18:8 | IR: main | int main() | +| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | stream_it.cpp:16:5:16:8 | IR: main | int main() | | try_catch.cpp:13:5:13:16 | ThrowValue: throw ... | Instruction 'ThrowValue' is missing an expected operand with tag 'Load' in function '$@'. | try_catch.cpp:11:6:11:17 | IR: bypass_catch | void bypass_catch() | unexpectedOperand duplicateOperand From ee3b40bd89b214c0fc9f265ad295d9c45fe085ab Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 30 Sep 2019 09:19:50 -0700 Subject: [PATCH 0311/1227] C#: sync changes and accept test output --- .../semmle/code/csharp/ir/implementation/raw/Instruction.qll | 4 ++-- .../csharp/ir/implementation/raw/internal/IRConstruction.qll | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 83e6141052c..efc873b8f44 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -48,8 +48,8 @@ module InstructionSanity { or ( opcode instanceof ReadSideEffectOpcode or - opcode instanceof MayWriteSideEffectOpcode or - opcode instanceof Opcode::InlineAsm + opcode instanceof Opcode::InlineAsm or + opcode instanceof Opcode::CallSideEffect ) and tag instanceof SideEffectOperandTag ) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll index 372f5383db0..a7a5943972e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll @@ -252,6 +252,9 @@ private module Cached { .getInstructionArrayAccess(getInstructionTag(instruction)) } + cached + int getInstructionIndex(Instruction instruction) { none() } + cached Callable getInstructionFunction(Instruction instruction) { result = getInstructionTranslatedElement(instruction) From d1e2ddcf99406dcfa4b9cf12ee825a5b8707d87e Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 30 Sep 2019 12:53:00 -0700 Subject: [PATCH 0312/1227] C#: sync unalised_ssa IR stage and add to check --- config/identical-files.json | 42 ++++++--- .../unaliased_ssa/Instruction.qll | 90 ++++++++++++++++--- .../implementation/unaliased_ssa/Operand.qll | 14 ++- .../internal/SSAConstruction.qll | 5 ++ 4 files changed, 125 insertions(+), 26 deletions(-) diff --git a/config/identical-files.json b/config/identical-files.json index 6a216ac256d..25c696289b8 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -47,31 +47,36 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll" ], "IR IRBlock": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll" ], "IR IRVariable": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll" ], "IR IRFunction": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll" ], "IR Operand": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll" ], "IR Operand Tag": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll", @@ -85,19 +90,22 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll" ], "IR IRSanity": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll" ], "IR PrintIR": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll" ], "IR IntegerConstant": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll", @@ -205,21 +213,27 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll" ], "C# IR InstructionImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll" ], "C# IR IRImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll" ], "C# IR IRBlockImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll" ], "C# IR IRVariableImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll" ], "C# IR OperandImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll" ], "C# IR PrintIRImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll" + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll" ] } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 43f9663d2cd..efc873b8f44 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -30,7 +30,7 @@ module InstructionSanity { or opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or - opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand + opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag or opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or @@ -48,8 +48,8 @@ module InstructionSanity { or ( opcode instanceof ReadSideEffectOpcode or - opcode instanceof MayWriteSideEffectOpcode or - opcode instanceof Opcode::InlineAsm + opcode instanceof Opcode::InlineAsm or + opcode instanceof Opcode::CallSideEffect ) and tag instanceof SideEffectOperandTag ) @@ -609,7 +609,7 @@ class VariableInstruction extends Instruction { VariableInstruction() { var = Construction::getInstructionVariable(this) } - final override string getImmediateString() { result = var.toString() } + override string getImmediateString() { result = var.toString() } final IRVariable getVariable() { result = var } } @@ -644,6 +644,16 @@ class ConstantValueInstruction extends Instruction { final string getValue() { result = value } } +class IndexedInstruction extends Instruction { + int index; + + IndexedInstruction() { index = Construction::getInstructionIndex(this) } + + final override string getImmediateString() { result = index.toString() } + + final int getIndex() { result = index } +} + class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } @@ -1175,6 +1185,8 @@ class CallReadSideEffectInstruction extends SideEffectInstruction { */ class IndirectReadSideEffectInstruction extends SideEffectInstruction { IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect } + + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } } /** @@ -1182,13 +1194,39 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction { */ class BufferReadSideEffectInstruction extends SideEffectInstruction { BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect } + + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } +} + +/** + * An instruction representing the read of an indirect buffer parameter within a function call. + */ +class SizedBufferReadSideEffectInstruction extends SideEffectInstruction { + SizedBufferReadSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferReadSideEffect + } + + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + +/** + * An instruction representing a side effect of a function call. + */ +class WriteSideEffectInstruction extends SideEffectInstruction { + WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } + + Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } } /** * An instruction representing the write of an indirect parameter within a function call. */ -class IndirectWriteSideEffectInstruction extends SideEffectInstruction { - IndirectWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectWriteSideEffect } +class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + IndirectMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::IndirectMustWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess } } @@ -1197,18 +1235,34 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction { * An instruction representing the write of an indirect buffer parameter within a function call. The * entire buffer is overwritten. */ -class BufferWriteSideEffectInstruction extends SideEffectInstruction { - BufferWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferWriteSideEffect } +class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + BufferMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::BufferMustWriteSideEffect + } final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } } +/** + * An instruction representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ +class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction { + SizedBufferMustWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + /** * An instruction representing the potential write of an indirect parameter within a function call. * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ -class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { +class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { IndirectMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectMayWriteSideEffect } @@ -1222,7 +1276,7 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction { * An instruction representing the write of an indirect buffer parameter within a function call. * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ -class BufferMayWriteSideEffectInstruction extends SideEffectInstruction { +class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect } final override MemoryAccessKind getResultMemoryAccess() { @@ -1230,6 +1284,22 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction { } } +/** + * An instruction representing the write of an indirect buffer parameter within a function call. + * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. + */ +class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { + SizedBufferMayWriteSideEffectInstruction() { + getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect + } + + final override MemoryAccessKind getResultMemoryAccess() { + result instanceof BufferMayMemoryAccess + } + + Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } +} + /** * An instruction representing a GNU or MSVC inline assembly statement. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index 1ced8ef3282..a23fb081afe 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -254,6 +254,16 @@ class AddressOperand extends RegisterOperand { override string toString() { result = "Address" } } +/** + * The buffer size operand of an instruction that represents a read or write of + * a buffer. + */ +class BufferSizeOperand extends RegisterOperand { + override BufferSizeOperandTag tag; + + override string toString() { result = "BufferSize" } +} + /** * The source value operand of an instruction that loads a value from memory (e.g. `Load`, * `ReturnValue`, `ThrowValue`). @@ -390,10 +400,10 @@ class SideEffectOperand extends TypedOperand { useInstr instanceof BufferReadSideEffectInstruction and result instanceof BufferMemoryAccess or - useInstr instanceof IndirectWriteSideEffectInstruction and + useInstr instanceof IndirectMustWriteSideEffectInstruction and result instanceof IndirectMemoryAccess or - useInstr instanceof BufferWriteSideEffectInstruction and + useInstr instanceof BufferMustWriteSideEffectInstruction and result instanceof BufferMemoryAccess or useInstr instanceof IndirectMayWriteSideEffectInstruction and diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 8f2ed18f060..f65f18b1ec2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -345,6 +345,11 @@ private module Cached { result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() } + cached + int getInstructionIndex(Instruction instruction) { + result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() + } + cached Language::Function getInstructionFunction(Instruction instruction) { result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() From 413926f67535e78f3ad06f2bcd25bc739d2383fb Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 30 Sep 2019 12:19:40 +0200 Subject: [PATCH 0313/1227] C#: Prepend enclosing method in local function TRAP labels --- .../Semmle.Extraction.CSharp/Entities/LocalFunction.cs | 10 +++++++++- csharp/ql/test/library-tests/csharp7/CSharp7.cs | 2 +- .../library-tests/csharp7/ExpressionBodies.expected | 2 +- .../library-tests/csharp7/LocalFunctionCalls.expected | 2 +- .../csharp7/LocalFunctionParameters.expected | 2 ++ .../library-tests/csharp7/LocalFunctionStmts.expected | 2 +- .../test/library-tests/csharp7/LocalFunctions.expected | 2 +- .../csharp7/UnboundLocalFunctions.expected | 1 + 8 files changed, 17 insertions(+), 6 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs index 93c382cdd5e..64a2c1e3eac 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs @@ -11,9 +11,17 @@ namespace Semmle.Extraction.CSharp.Entities { } + Method ContainingMethod => + symbol.OriginalDefinition.ContainingSymbol is IMethodSymbol m + ? Method.Create(Context, m) + : throw new InternalError(symbol, "Unable to determine local function's containing callable"); + public override void WriteId(TextWriter trapFile) { + trapFile.WriteSubId(ContainingMethod); + trapFile.Write(".("); trapFile.WriteSubId(Location); + trapFile.Write(')'); if (symbol.IsGenericMethod && !IsSourceDeclaration) { trapFile.Write('<'); @@ -41,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities // the "static" modifier is present. if (symbol.DeclaringSyntaxReferences.SingleOrDefault().GetSyntax() is LocalFunctionStatementSyntax fn) { - foreach(var modifier in fn.Modifiers) + foreach (var modifier in fn.Modifiers) { Modifier.HasModifier(Context, trapFile, this, modifier.Text); } diff --git a/csharp/ql/test/library-tests/csharp7/CSharp7.cs b/csharp/ql/test/library-tests/csharp7/CSharp7.cs index 0b0c543216f..05d5896f4a9 100644 --- a/csharp/ql/test/library-tests/csharp7/CSharp7.cs +++ b/csharp/ql/test/library-tests/csharp7/CSharp7.cs @@ -162,7 +162,7 @@ class LocalFunctions U h(T t, U u) { - int f2() => f(); + int f2(S s, T _t) => f(); f(); return g(u); } diff --git a/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected b/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected index 666074d0a7b..b7dd392b22a 100644 --- a/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected +++ b/csharp/ql/test/library-tests/csharp7/ExpressionBodies.expected @@ -12,7 +12,7 @@ | CSharp7.cs:152:13:152:26 | f9 | CSharp7.cs:152:25:152:25 | 0 | | CSharp7.cs:160:9:160:24 | f | CSharp7.cs:160:23:160:23 | 1 | | CSharp7.cs:161:9:161:25 | g | CSharp7.cs:161:24:161:24 | access to parameter t | -| CSharp7.cs:165:13:165:31 | f2 | CSharp7.cs:165:25:165:30 | call to local function f | +| CSharp7.cs:165:13:165:43 | f2 | CSharp7.cs:165:37:165:42 | call to local function f | | CSharp7.cs:177:9:177:40 | f | CSharp7.cs:177:31:177:39 | ... + ... | | CSharp7.cs:178:9:178:32 | g | CSharp7.cs:178:31:178:31 | access to parameter s | | CSharp7.cs:284:32:284:61 | (...) => ... | CSharp7.cs:284:40:284:61 | (..., ...) | diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected index 3b3f42f3282..9ecf8790464 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionCalls.expected @@ -3,7 +3,7 @@ | CSharp7.cs:147:30:147:34 | call to local function f7 | CSharp7.cs:143:9:143:31 | f7 | CSharp7.cs:143:9:143:31 | f7 | | CSharp7.cs:148:20:148:24 | call to local function f9 | CSharp7.cs:147:13:147:35 | f9 | CSharp7.cs:147:13:147:35 | f9 | | CSharp7.cs:155:16:155:20 | call to local function f1 | CSharp7.cs:131:9:131:39 | f1 | CSharp7.cs:131:9:131:39 | f1 | -| CSharp7.cs:165:25:165:30 | call to local function f | CSharp7.cs:160:9:160:24 | f | CSharp7.cs:160:9:160:24 | f | +| CSharp7.cs:165:37:165:42 | call to local function f | CSharp7.cs:160:9:160:24 | f | CSharp7.cs:160:9:160:24 | f | | CSharp7.cs:166:13:166:18 | call to local function f | CSharp7.cs:160:9:160:24 | f | CSharp7.cs:160:9:160:24 | f | | CSharp7.cs:167:20:167:23 | call to local function g | CSharp7.cs:161:9:161:25 | g | CSharp7.cs:161:9:161:25 | g | | CSharp7.cs:170:9:170:15 | call to local function h | CSharp7.cs:163:9:168:9 | h | CSharp7.cs:163:9:168:9 | h | diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected index f6d9e852c2e..a3aabd4f16f 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionParameters.expected @@ -12,6 +12,8 @@ | CSharp7.cs:163:9:168:9 | h | 1 | CSharp7.cs:163:26:163:26 | u | Boolean | | CSharp7.cs:163:9:168:9 | h | 1 | CSharp7.cs:163:26:163:26 | u | Int32 | | CSharp7.cs:163:9:168:9 | h | 1 | CSharp7.cs:163:26:163:26 | u | U | +| CSharp7.cs:165:13:165:43 | f2 | 0 | CSharp7.cs:165:25:165:25 | s | S | +| CSharp7.cs:165:13:165:43 | f2 | 1 | CSharp7.cs:165:30:165:31 | _t | T | | CSharp7.cs:177:9:177:40 | f | 0 | CSharp7.cs:177:25:177:25 | s | String | | CSharp7.cs:178:9:178:32 | g | 0 | CSharp7.cs:178:25:178:25 | s | String | | CSharp7.cs:179:9:179:40 | h | 0 | CSharp7.cs:179:25:179:25 | s | String | diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected index 2b610230a5c..06375392141 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalFunctionStmts.expected @@ -9,7 +9,7 @@ | CSharp7.cs:160:9:160:24 | f(...) | CSharp7.cs:160:9:160:24 | f | | CSharp7.cs:161:9:161:25 | g(...) | CSharp7.cs:161:9:161:25 | g | | CSharp7.cs:163:9:168:9 | h(...) | CSharp7.cs:163:9:168:9 | h | -| CSharp7.cs:165:13:165:31 | f2(...) | CSharp7.cs:165:13:165:31 | f2 | +| CSharp7.cs:165:13:165:43 | f2(...) | CSharp7.cs:165:13:165:43 | f2 | | CSharp7.cs:177:9:177:40 | f(...) | CSharp7.cs:177:9:177:40 | f | | CSharp7.cs:178:9:178:32 | g(...) | CSharp7.cs:178:9:178:32 | g | | CSharp7.cs:179:9:179:40 | h(...) | CSharp7.cs:179:9:179:40 | h | diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected index 8dae79ab5ea..ad990659314 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected @@ -13,7 +13,7 @@ | CSharp7.cs:163:9:168:9 | h | h | Boolean | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:163:9:168:9 | h(...) | h(string, bool) | | CSharp7.cs:163:9:168:9 | h | h | Int32 | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:163:9:168:9 | h(...) | h(int, int) | | CSharp7.cs:163:9:168:9 | h | h | U | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:163:9:168:9 | h(...) | h(T, U) | -| CSharp7.cs:165:13:165:31 | f2 | f2 | Int32 | CSharp7.cs:164:9:168:9 | {...} | CSharp7.cs:165:13:165:31 | f2(...) | f2() | +| CSharp7.cs:165:13:165:43 | f2 | f2 | Int32 | CSharp7.cs:164:9:168:9 | {...} | CSharp7.cs:165:13:165:43 | f2(...) | f2(S, T) | | CSharp7.cs:177:9:177:40 | f | f | String | CSharp7.cs:175:5:184:5 | {...} | CSharp7.cs:177:9:177:40 | f(...) | f(string) | | CSharp7.cs:178:9:178:32 | g | g | String | CSharp7.cs:175:5:184:5 | {...} | CSharp7.cs:178:9:178:32 | g(...) | g(string) | | CSharp7.cs:179:9:179:40 | h | h | String | CSharp7.cs:175:5:184:5 | {...} | CSharp7.cs:179:9:179:40 | h(...) | h(string) | diff --git a/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected b/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected index a1d186c0f31..594f51bac56 100644 --- a/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected +++ b/csharp/ql/test/library-tests/csharp7/UnboundLocalFunctions.expected @@ -4,3 +4,4 @@ | CSharp7.cs:161:9:161:25 | g | 0 | CSharp7.cs:161:13:161:13 | T | | CSharp7.cs:163:9:168:9 | h | 0 | CSharp7.cs:163:13:163:13 | T | | CSharp7.cs:163:9:168:9 | h | 1 | CSharp7.cs:163:16:163:16 | U | +| CSharp7.cs:165:13:165:43 | f2 | 0 | CSharp7.cs:165:20:165:20 | S | From 7c319efb8bcbd059127db2280c87dcbb0ddb2671 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 1 Oct 2019 09:33:30 +0200 Subject: [PATCH 0314/1227] C++: Data flow through reference parameters --- change-notes/1.23/analysis-cpp.md | 1 + .../cpp/dataflow/internal/DataFlowPrivate.qll | 56 ++++++-- .../cpp/dataflow/internal/DataFlowUtil.qll | 30 +++- .../code/cpp/dataflow/internal/FlowVar.qll | 32 +++++ .../dataflow/dataflow-tests/lambdas.cpp | 2 +- .../dataflow/dataflow-tests/ref.cpp | 134 ++++++++++++++++++ .../dataflow/dataflow-tests/test.expected | 11 ++ .../dataflow-tests/test_diff.expected | 7 + .../dataflow/dataflow-tests/test_ir.expected | 4 + .../dataflow-tests/uninitialized.expected | 16 +++ .../dataflow/fields/flow.expected | 3 + .../dataflow/taint-tests/localTaint.expected | 8 ++ .../dataflow/taint-tests/taint.cpp | 2 +- .../dataflow/taint-tests/taint.expected | 1 + .../dataflow/taint-tests/test_diff.expected | 1 + 15 files changed, 293 insertions(+), 15 deletions(-) create mode 100644 cpp/ql/test/library-tests/dataflow/dataflow-tests/ref.cpp diff --git a/change-notes/1.23/analysis-cpp.md b/change-notes/1.23/analysis-cpp.md index 5a97e1347bb..3e782d37b11 100644 --- a/change-notes/1.23/analysis-cpp.md +++ b/change-notes/1.23/analysis-cpp.md @@ -30,6 +30,7 @@ The following changes in version 1.23 affect C/C++ analysis in all applications. picture of the partial flow paths from a given source. The feature is disabled by default and can be enabled for individual configurations by overriding `int explorationLimit()`. +* The data-flow library now supports flow out of C++ reference parameters. * The data-flow library now allows flow through the address-of operator (`&`). * The `DataFlow::DefinitionByReferenceNode` class now considers `f(x)` to be a definition of `x` when `x` is a variable of pointer type. It no longer diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index ed007554d4c..7b180c183b2 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -51,7 +51,9 @@ class ArgumentNode extends Node { DataFlowCall getCall() { this.argumentOf(result, _) } } -private newtype TReturnKind = TNormalReturnKind() +private newtype TReturnKind = + TNormalReturnKind() or + TRefReturnKind(int i) { exists(Parameter parameter | i = parameter.getIndex()) } /** * A return kind. A return kind describes how a value can be returned @@ -59,23 +61,54 @@ private newtype TReturnKind = TNormalReturnKind() */ class ReturnKind extends TReturnKind { /** Gets a textual representation of this return kind. */ - string toString() { result = "return" } + string toString() { + this instanceof TNormalReturnKind and + result = "return" + or + this instanceof TRefReturnKind and + result = "ref" + } } -/** A data flow node that occurs as the result of a `ReturnStmt`. */ -class ReturnNode extends ExprNode { - ReturnNode() { exists(ReturnStmt ret | this.getExpr() = ret.getExpr()) } +/** A data flow node that represents a returned value. */ +abstract class ReturnNode extends Node { + /** Gets the kind of this returned value. */ + abstract ReturnKind getKind(); +} + +/** A `ReturnNode` that occurs as the result of a `ReturnStmt`. */ +private class NormalReturnNode extends ReturnNode, ExprNode { + NormalReturnNode() { exists(ReturnStmt ret | this.getExpr() = ret.getExpr()) } /** Gets the kind of this returned value. */ - ReturnKind getKind() { result = TNormalReturnKind() } + override ReturnKind getKind() { result = TNormalReturnKind() } +} + +/** + * A `ReturnNode` that occurs as a result of a definition of a reference + * parameter reaching the end of a function body. + */ +private class RefReturnNode extends ReturnNode, RefParameterFinalValueNode { + /** Gets the kind of this returned value. */ + override ReturnKind getKind() { result = TRefReturnKind(this.getParameter().getIndex()) } } /** A data flow node that represents the output of a call. */ -class OutNode extends ExprNode { - OutNode() { this.getExpr() instanceof Call } +abstract class OutNode extends Node { + /** Gets the underlying call. */ + abstract DataFlowCall getCall(); +} + +private class ExprOutNode extends OutNode, ExprNode { + ExprOutNode() { this.getExpr() instanceof Call } /** Gets the underlying call. */ - DataFlowCall getCall() { result = this.getExpr() } + override DataFlowCall getCall() { result = this.getExpr() } +} + +private class RefOutNode extends OutNode, DefinitionByReferenceNode { + /** Gets the underlying call. */ + override DataFlowCall getCall() { result = this.getArgument().getParent() } } /** @@ -85,6 +118,11 @@ class OutNode extends ExprNode { OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { result = call.getNode() and kind = TNormalReturnKind() + or + exists(int i | + result.asDefiningArgument() = call.getArgument(i) and + kind = TRefReturnKind(i) + ) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index e48d92719ec..0caa2ab05df 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -25,7 +25,8 @@ private newtype TNode = not c.getTarget().getParameter(i).getUnderlyingType().(PointerType).getBaseType().isConst() ) } or - TUninitializedNode(LocalVariable v) { not v.hasInitializer() } + TUninitializedNode(LocalVariable v) { not v.hasInitializer() } or + TRefParameterFinalValueNode(Parameter p) { exists(FlowVar var | var.reachesRefParameter(p)) } /** * A node in a data flow graph. @@ -248,6 +249,23 @@ class UninitializedNode extends Node, TUninitializedNode { LocalVariable getLocalVariable() { result = v } } +/** INTERNAL: do not use. The final value of a non-const ref parameter. */ +class RefParameterFinalValueNode extends Node, TRefParameterFinalValueNode { + Parameter p; + + RefParameterFinalValueNode() { this = TRefParameterFinalValueNode(p) } + + override Function getFunction() { result = p.getFunction() } + + override Type getType() { result = p.getType() } + + override string toString() { result = p.toString() } + + override Location getLocation() { result = p.getLocation() } + + Parameter getParameter() { result = p } +} + /** * A node associated with an object after an operation that might have * changed its state. @@ -490,7 +508,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { or var.definedPartiallyAt(nodeFrom.asPartialDefinition()) ) and - varToExprStep(var, nodeTo.asExpr()) + varToNodeStep(var, nodeTo) ) or // Expr -> DefinitionByReferenceNode @@ -533,9 +551,13 @@ private predicate exprToVarStep(Expr assignedExpr, FlowVar var) { } /** - * Holds if the expression `e` is an access of the variable `var`. + * Holds if the node `n` is an access of the variable `var`. */ -private predicate varToExprStep(FlowVar var, Expr e) { e = var.getAnAccess() } +private predicate varToNodeStep(FlowVar var, Node n) { + n.asExpr() = var.getAnAccess() + or + var.reachesRefParameter(n.(RefParameterFinalValueNode).getParameter()) +} /** * Holds if data flows from `fromExpr` to `toExpr` directly, in the case diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll index b7820b9f34e..cb2fb44bed2 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -62,9 +62,20 @@ class FlowVar extends TFlowVar { cached abstract predicate definedByReference(Expr arg); + /** + * Holds if this `FlowVar` is a `PartialDefinition` whose defined expression + * is `e`. + */ cached abstract predicate definedPartiallyAt(Expr e); + /** + * Holds if this `FlowVar` is a definition of a reference parameter `p` that + * persists until the function returns. + */ + cached + abstract predicate reachesRefParameter(Parameter p); + /** * Holds if this `FlowVar` corresponds to the initial value of `v`. The following * is an exhaustive list of cases where this may happen. @@ -338,6 +349,9 @@ module FlowVar_internal { param = v } + // `fullySupportedSsaVariable` excludes reference types + override predicate reachesRefParameter(Parameter p) { none() } + /** * Holds if this `SsaVar` corresponds to a non-phi definition. Users of this * library will never directly use an `SsaVar` that comes from a phi node, @@ -387,6 +401,13 @@ module FlowVar_internal { sbb = v.(Parameter).getFunction().getEntryPoint() } + override predicate reachesRefParameter(Parameter p) { + parameterIsNonConstReference(p) and + p = v and + // This definition reaches the exit node of the function CFG + getAReachedBlockVarSBB(this).getANode() = p.getFunction() + } + override predicate definedByInitialValue(LocalScopeVariable lsv) { blockVarDefinedByVariable(sbb, lsv) and lsv = v @@ -593,12 +614,23 @@ module FlowVar_internal { private predicate variableLiveInSBB(SubBasicBlock sbb, Variable v) { variableAccessInSBB(v, sbb, _) or + // Non-const reference parameters are live at the end of the function + parameterIsNonConstReference(v) and + sbb.contains(v.(Parameter).getFunction()) + or exists(SubBasicBlock succ | succ = sbb.getASuccessor() | variableLiveInSBB(succ, v) and not variableNotLiveBefore(succ, v) ) } + predicate parameterIsNonConstReference(Parameter p) { + exists(ReferenceType refType | + refType = p.getUnderlyingType() and + not refType.getBaseType().isConst() + ) + } + /** * Holds if liveness of `v` should stop propagating backwards from `sbb`. */ diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/lambdas.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/lambdas.cpp index 480b9016fa3..4b4f95347ef 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/lambdas.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/lambdas.cpp @@ -43,5 +43,5 @@ void test_lambdas() c = source(); }; e(t, u, w); - sink(w); // flow from source() [NOT DETECTED] + sink(w); // flow from source() } diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/ref.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/ref.cpp new file mode 100644 index 00000000000..8e1ac7657ea --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/ref.cpp @@ -0,0 +1,134 @@ +int source(); + +template +void sink(T); + +extern int arbitrary; + +namespace withoutFields { + template + void assign(T &lhs, T rhs) { + lhs = rhs; + } + + template + void assignWrapper(T &lhs, T rhs) { + assign(lhs, rhs); + } + + void notAssign(int &lhs, int rhs) { + lhs = rhs; + if (arbitrary) { + lhs = 1; + } else { + lhs = 2; + } + } + + void sourceToParam(int &out) { + out = source(); + if (arbitrary) { + out = 1; + } + } + + void sourceToParamWrapper(int &out) { + if (arbitrary) { + sourceToParam(out); + } else { + out = 1; + } + } + + void notSource(int &out) { + out = source(); + if (arbitrary) { + out = 1; + } else { + out = 2; + } + } + + void testRefs() { + int x1, x2, x3, x4; + + assignWrapper(x1, source()); + sink(x1); // flow [FALSE POSITIVE from uninitialized] + + notAssign(x2, source()); + sink(x2); // no flow [FALSE POSITIVE from uninitialized] + + sourceToParamWrapper(x3); + sink(x3); // flow [FALSE POSITIVE from uninitialized] + + notSource(x4); + sink(x4); // no flow [FALSE POSITIVE from uninitialized] + } +} + +namespace withFields { + struct Int { + int val; + }; + + void assign(Int &lhs, int rhs) { + lhs.val = rhs; + } + + void assignWrapper(Int &lhs, int rhs) { + assign(lhs, rhs); + } + + void notAssign(Int &lhs, int rhs) { + lhs.val = rhs; + // Field flow ignores that the field is subsequently overwritten, leading + // to false flow here. + if (arbitrary) { + lhs.val = 1; + } else { + lhs.val = 2; + } + } + + void sourceToParam(Int &out) { + out.val = source(); + if (arbitrary) { + out.val = 1; + } + } + + void sourceToParamWrapper(Int &out) { + if (arbitrary) { + sourceToParam(out); + } else { + out.val = 1; + } + } + + void notSource(Int &out) { + out.val = source(); + // Field flow ignores that the field is subsequently overwritten, leading + // to false flow here. + if (arbitrary) { + out.val = 1; + } else { + out.val = 2; + } + } + + void testRefs() { + Int x1, x2, x3, x4; + + assignWrapper(x1, source()); + sink(x1.val); // flow + + notAssign(x2, source()); + sink(x2.val); // no flow [FALSE POSITIVE] + + sourceToParamWrapper(x3); + sink(x3.val); // flow + + notSource(x4); + sink(x4.val); // no flow [FALSE POSITIVE] + } +} diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected index 56bbfd387de..b9fca1f678f 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected @@ -11,6 +11,17 @@ | lambdas.cpp:29:3:29:6 | t | lambdas.cpp:8:10:8:15 | call to source | | lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source | | lambdas.cpp:41:8:41:8 | a | lambdas.cpp:8:10:8:15 | call to source | +| lambdas.cpp:46:7:46:7 | w | lambdas.cpp:43:7:43:12 | call to source | +| ref.cpp:56:10:56:11 | x1 | ref.cpp:53:9:53:10 | x1 | +| ref.cpp:56:10:56:11 | x1 | ref.cpp:55:23:55:28 | call to source | +| ref.cpp:59:10:59:11 | x2 | ref.cpp:53:13:53:14 | x2 | +| ref.cpp:62:10:62:11 | x3 | ref.cpp:29:11:29:16 | call to source | +| ref.cpp:62:10:62:11 | x3 | ref.cpp:53:17:53:18 | x3 | +| ref.cpp:65:10:65:11 | x4 | ref.cpp:53:21:53:22 | x4 | +| ref.cpp:123:13:123:15 | val | ref.cpp:122:23:122:28 | call to source | +| ref.cpp:126:13:126:15 | val | ref.cpp:125:19:125:24 | call to source | +| ref.cpp:129:13:129:15 | val | ref.cpp:94:15:94:20 | call to source | +| ref.cpp:132:13:132:15 | val | ref.cpp:109:15:109:20 | call to source | | test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source | | test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source | | test.cpp:10:8:10:9 | t2 | test.cpp:6:12:6:17 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected index a7aa78c03af..3585b0fb9d4 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected @@ -8,6 +8,13 @@ | lambdas.cpp:8:10:8:15 | lambdas.cpp:29:3:29:6 | AST only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:35:8:35:8 | AST only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:41:8:41:8 | AST only | +| lambdas.cpp:43:7:43:12 | lambdas.cpp:46:7:46:7 | AST only | +| ref.cpp:29:11:29:16 | ref.cpp:62:10:62:11 | AST only | +| ref.cpp:55:23:55:28 | ref.cpp:56:10:56:11 | AST only | +| ref.cpp:94:15:94:20 | ref.cpp:129:13:129:15 | AST only | +| ref.cpp:109:15:109:20 | ref.cpp:132:13:132:15 | AST only | +| ref.cpp:122:23:122:28 | ref.cpp:123:13:123:15 | AST only | +| ref.cpp:125:19:125:24 | ref.cpp:126:13:126:15 | AST only | | test.cpp:89:28:89:34 | test.cpp:92:8:92:14 | IR only | | test.cpp:100:13:100:18 | test.cpp:103:10:103:12 | AST only | | test.cpp:109:9:109:14 | test.cpp:110:10:110:12 | IR only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected index 83ba546480f..259c9b5c894 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected @@ -5,6 +5,10 @@ | clang.cpp:37:10:37:11 | Load: m2 | clang.cpp:34:32:34:37 | Call: call to source | | clang.cpp:41:18:41:19 | Load: m2 | clang.cpp:39:42:39:47 | Call: call to source | | clang.cpp:45:17:45:18 | Load: m2 | clang.cpp:43:35:43:40 | Call: call to source | +| ref.cpp:56:10:56:11 | Load: x1 | ref.cpp:53:9:53:10 | Uninitialized: definition of x1 | +| ref.cpp:59:10:59:11 | Load: x2 | ref.cpp:53:13:53:14 | Uninitialized: definition of x2 | +| ref.cpp:62:10:62:11 | Load: x3 | ref.cpp:53:17:53:18 | Uninitialized: definition of x3 | +| ref.cpp:65:10:65:11 | Load: x4 | ref.cpp:53:21:53:22 | Uninitialized: definition of x4 | | test.cpp:7:8:7:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source | | test.cpp:9:8:9:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source | | test.cpp:10:8:10:9 | Load: t2 | test.cpp:6:12:6:17 | Call: call to source | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected index 9cffdb99e60..b66b5704719 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected @@ -1,3 +1,19 @@ +| ref.cpp:53:9:53:10 | x1 | ref.cpp:55:19:55:20 | x1 | +| ref.cpp:53:9:53:10 | x1 | ref.cpp:56:10:56:11 | x1 | +| ref.cpp:53:13:53:14 | x2 | ref.cpp:58:15:58:16 | x2 | +| ref.cpp:53:13:53:14 | x2 | ref.cpp:59:10:59:11 | x2 | +| ref.cpp:53:17:53:18 | x3 | ref.cpp:61:26:61:27 | x3 | +| ref.cpp:53:17:53:18 | x3 | ref.cpp:62:10:62:11 | x3 | +| ref.cpp:53:21:53:22 | x4 | ref.cpp:64:15:64:16 | x4 | +| ref.cpp:53:21:53:22 | x4 | ref.cpp:65:10:65:11 | x4 | +| ref.cpp:120:9:120:10 | x1 | ref.cpp:122:19:122:20 | x1 | +| ref.cpp:120:9:120:10 | x1 | ref.cpp:123:10:123:11 | x1 | +| ref.cpp:120:13:120:14 | x2 | ref.cpp:125:15:125:16 | x2 | +| ref.cpp:120:13:120:14 | x2 | ref.cpp:126:10:126:11 | x2 | +| ref.cpp:120:17:120:18 | x3 | ref.cpp:128:26:128:27 | x3 | +| ref.cpp:120:17:120:18 | x3 | ref.cpp:129:10:129:11 | x3 | +| ref.cpp:120:21:120:22 | x4 | ref.cpp:131:15:131:16 | x4 | +| ref.cpp:120:21:120:22 | x4 | ref.cpp:132:10:132:11 | x4 | | test.cpp:75:7:75:8 | u1 | test.cpp:76:8:76:9 | u1 | | test.cpp:83:7:83:8 | u2 | test.cpp:84:13:84:14 | u2 | | test.cpp:83:7:83:8 | u2 | test.cpp:85:8:85:9 | u2 | diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index 68a99d530fc..ec787229fff 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -125,6 +125,8 @@ edges | aliasing.cpp:9:3:9:3 | s [post update] [m1] | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | | aliasing.cpp:9:3:9:22 | ... = ... | aliasing.cpp:9:3:9:3 | s [post update] [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | ... = ... | +| aliasing.cpp:12:25:12:25 | s [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | +| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:12:25:12:25 | s [m1] | | aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | | aliasing.cpp:13:3:13:21 | ... = ... | aliasing.cpp:13:3:13:3 | s [post update] [m1] | | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | ... = ... | @@ -379,6 +381,7 @@ nodes | aliasing.cpp:9:3:9:3 | s [post update] [m1] | semmle.label | s [post update] [m1] | | aliasing.cpp:9:3:9:22 | ... = ... | semmle.label | ... = ... | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:12:25:12:25 | s [m1] | semmle.label | s [m1] | | aliasing.cpp:13:3:13:3 | s [post update] [m1] | semmle.label | s [post update] [m1] | | aliasing.cpp:13:3:13:21 | ... = ... | semmle.label | ... = ... | | aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | 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 d93bbd617e2..49e75af6fb9 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -1,3 +1,8 @@ +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | | @@ -223,7 +228,10 @@ | taint.cpp:249:18:249:18 | a | taint.cpp:250:8:250:8 | a | | | taint.cpp:249:25:249:25 | b | taint.cpp:251:8:251:8 | b | | | taint.cpp:255:11:259:2 | [...](...){...} | taint.cpp:260:2:260:2 | e | | +| taint.cpp:255:19:255:19 | a | taint.cpp:255:19:255:19 | a | | | taint.cpp:255:19:255:19 | a | taint.cpp:256:8:256:8 | a | | +| taint.cpp:255:27:255:27 | b | taint.cpp:255:27:255:27 | b | | | taint.cpp:255:27:255:27 | b | taint.cpp:257:8:257:8 | b | | +| taint.cpp:258:7:258:12 | call to source | taint.cpp:255:35:255:35 | c | | | taint.cpp:258:7:258:12 | call to source | taint.cpp:258:3:258:14 | ... = ... | | | taint.cpp:260:10:260:10 | ref arg w | taint.cpp:261:7:261:7 | w | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp index d29c45cd63e..301b35d7ec4 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -258,5 +258,5 @@ void test_lambdas() c = source(); }; e(t, u, w); - sink(w); // tainted [NOT DETECTED] + sink(w); // tainted } diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index 0793bf29e19..bab7beca677 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -28,3 +28,4 @@ | taint.cpp:244:3:244:6 | t | taint.cpp:223:10:223:15 | call to source | | taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source | | taint.cpp:256:8:256:8 | a | taint.cpp:223:10:223:15 | call to source | +| taint.cpp:261:7:261:7 | w | taint.cpp:258:7:258:12 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index 45798f7ef06..35ed5d3a766 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -21,3 +21,4 @@ | taint.cpp:244:3:244:6 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:250:8:250:8 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:256:8:256:8 | taint.cpp:223:10:223:15 | AST only | +| taint.cpp:261:7:261:7 | taint.cpp:258:7:258:12 | AST only | From 34b625900a3c83c1b21b17d4680d262918d4d4a2 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 1 Oct 2019 11:50:33 +0200 Subject: [PATCH 0315/1227] C++: Avoid `extends Operation` in LeapYear.qll The `Operation` class is abstract, and extending it caused cached stages to be recomputed all the way down to the AST. This meant that the leap year queries evaluated their own copy of SSA and data flow. --- cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll b/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll index f75305dbf2a..23b66bd94a6 100644 --- a/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll +++ b/cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll @@ -30,7 +30,7 @@ private predicate additionalLogicalCheck(Expr e, string operation, int valueToCh /** * An `Operation` that seems to be checking for leap year. */ -class CheckForLeapYearOperation extends Operation { +class CheckForLeapYearOperation extends Expr { CheckForLeapYearOperation() { exists(BinaryArithmeticOperation bo | bo = this | bo.getAnOperand().getValue().toInt() = 4 and @@ -39,8 +39,6 @@ class CheckForLeapYearOperation extends Operation { additionalLogicalCheck(this.getEnclosingElement(), "%", 400) ) } - - override string getOperator() { result = "LeapYearCheck" } } /** From 427325b04a15f0d5dd34451d0f7514ae59f2ffdf Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Tue, 1 Oct 2019 11:23:41 +0100 Subject: [PATCH 0316/1227] QL etudes: Update with Robert's suggestions --- .../learn-ql/ql-etudes/river-crossing-1.ql | 17 +++++------ .../learn-ql/ql-etudes/river-crossing.ql | 19 ++++++------- .../learn-ql/ql-etudes/river-crossing.rst | 28 +++++++++---------- 3 files changed, 29 insertions(+), 35 deletions(-) diff --git a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql index c0b95918d7c..80d828c7389 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql +++ b/docs/language/learn-ql/ql-etudes/river-crossing-1.ql @@ -33,11 +33,8 @@ class Shore extends string { /** A record of where everything is. */ class State extends string { Shore manShore; - Shore goatShore; - Shore cabbageShore; - Shore wolfShore; State() { this = manShore + "," + goatShore + "," + cabbageShore + "," + wolfShore } @@ -57,16 +54,16 @@ class State extends string { } /** - * Holds if eating occurs. This happens when predator and prey are on the same shore - * and the man is not present. + * Holds if the state is safe. This occurs when neither the goat nor the cabbage + * can get eaten. */ - predicate eating(Shore predatorShore, Shore preyShore) { - predatorShore = preyShore and manShore != predatorShore + predicate isSafe() { + // The goat can't eat the cabbage. + (goatShore != cabbageShore or goatShore = manShore) and + // The wolf can't eat the goat. + (wolfShore != goatShore or wolfShore = manShore) } - /** Holds if nothing gets eaten in this state. */ - predicate isSafe() { not (eating(goatShore, cabbageShore) or eating(wolfShore, goatShore)) } - /** Returns the state that is reached after safely ferrying a cargo item. */ State safeFerry(Cargo cargo) { result = this.ferry(cargo) and result.isSafe() } diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.ql b/docs/language/learn-ql/ql-etudes/river-crossing.ql index 58a3ada6ab1..6b0e5cfe2a3 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.ql +++ b/docs/language/learn-ql/ql-etudes/river-crossing.ql @@ -45,11 +45,8 @@ string renderState(Shore manShore, Shore goatShore, Shore cabbageShore, Shore wo /** A record of where everything is. */ class State extends string { Shore manShore; - Shore goatShore; - Shore cabbageShore; - Shore wolfShore; State() { this = renderState(manShore, goatShore, cabbageShore, wolfShore) } @@ -70,16 +67,16 @@ class State extends string { } /** - * Holds if eating occurs. This happens when predator and prey are on the same shore - * and the man is not present. + * Holds if the state is safe. This occurs when neither the goat nor the cabbage + * can get eaten. */ - predicate eating(Shore predatorShore, Shore preyShore) { - predatorShore = preyShore and manShore != predatorShore + predicate isSafe() { + // The goat can't eat the cabbage. + (goatShore != cabbageShore or goatShore = manShore) and + // The wolf can't eat the goat. + (wolfShore != goatShore or wolfShore = manShore) } - /** Holds if nothing gets eaten in this state. */ - predicate isSafe() { not (eating(goatShore, cabbageShore) or eating(wolfShore, goatShore)) } - /** Returns the state that is reached after safely ferrying a cargo item. */ State safeFerry(Cargo cargo) { result = this.ferry(cargo) and result.isSafe() } @@ -91,7 +88,7 @@ class State extends string { State reachesVia(string path, string visitedStates) { // Trivial case: a state is always reachable from itself. this = result and - visitedStates = "" and + visitedStates = this and path = "" or // A state is reachable using pathSoFar and then safely ferrying cargo. diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.rst b/docs/language/learn-ql/ql-etudes/river-crossing.rst index 588ece6aaa6..f565a571898 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.rst +++ b/docs/language/learn-ql/ql-etudes/river-crossing.rst @@ -42,7 +42,7 @@ a piece of cargo. *Show/hide code* .. literalinclude:: river-crossing.ql - :lines: 15-22 + :lines: 15-23 Second, any item can be on one of two shores. Let's call these the "left shore" and the "right shore". Define a class ``Shore`` containing ``"Left"`` and ``"Right"``. @@ -75,7 +75,7 @@ temporary variables in the body of a class are called `fields `__ + ➤ `See solution in the query console `__ #. This query models the man and the cargo items in a different way, using an `abstract `__ From eed24f193313e3b06f37507a4b15a85c1e91f68e Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 1 Oct 2019 13:44:49 +0200 Subject: [PATCH 0317/1227] C++: Improve join orders with QL CFG Size estimates are slightly different when we enable the QL CFG, and this caused bad join orders in these predicates. --- cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll index b7820b9f34e..5af9237f38f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -490,7 +490,7 @@ module FlowVar_internal { exists(VariableAccess va | va.getTarget() = result and readAccess(va) and - bbNotInLoop(va.getBasicBlock()) + exists(BasicBlock bb | bb = va.getBasicBlock() | not this.bbInLoop(bb)) ) } @@ -679,10 +679,11 @@ module FlowVar_internal { predicate dominatedByOverwrite(UninitializedLocalVariable v, VariableAccess va) { exists(BasicBlock bb, int vaIndex | va = bb.getNode(vaIndex) and - va.getTarget() = v - | + va.getTarget() = v and vaIndex > indexOfFirstOverwriteInBB(v, bb) or + va = bb.getNode(vaIndex) and + va.getTarget() = v and bbStrictlyDominates(getAnOverwritingBB(v), bb) ) } From 0990ceb09ac90a1902473f79fbf9bf4baa44b756 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 1 Oct 2019 14:20:28 +0200 Subject: [PATCH 0318/1227] C++: Remove bbNotInLoop and its caller in FlowVar This change is needed when enabling the QL CFG on certain snapshots such as notaz/picodrive. It removes the `bbNotInLoop` predicate, which was always a liability because it's inherently quadratic. The real slowdown came in `skipLoop`, where all true-upon-entry loops were crossed with all definitions of variables that should take their definition from the loop body. --- .../code/cpp/dataflow/internal/FlowVar.qll | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll index 5af9237f38f..55d8fb0356c 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -513,9 +513,9 @@ module FlowVar_internal { bbInLoopCondition(bb) } - predicate bbNotInLoop(BasicBlock bb) { - not this.bbInLoop(bb) and - bb.getEnclosingFunction() = this.getEnclosingFunction() + /** Holds if `sbb` is inside this loop. */ + predicate sbbInLoop(SubBasicBlock sbb) { + this.bbInLoop(sbb.getBasicBlock()) } /** @@ -537,22 +537,19 @@ module FlowVar_internal { } /** - * Holds if some loop always assigns to `v` before leaving through an edge - * from `bbInside` in its condition to `bbOutside` outside the loop, where - * (`sbbDef`, `v`) is a `BlockVar` defined outside the loop. Also, `v` must - * be used outside the loop. + * Holds if `loop` always assigns to `v` before leaving through an edge + * from `bbInside` in its condition to `bbOutside` outside the loop. Also, + * `v` must be used outside the loop. */ predicate skipLoop( - SubBasicBlock sbbInside, SubBasicBlock sbbOutside, SubBasicBlock sbbDef, Variable v + SubBasicBlock sbbInside, SubBasicBlock sbbOutside, Variable v, AlwaysTrueUponEntryLoop loop ) { - exists(AlwaysTrueUponEntryLoop loop, BasicBlock bbInside, BasicBlock bbOutside | + exists(BasicBlock bbInside, BasicBlock bbOutside | loop.alwaysAssignsBeforeLeavingCondition(bbInside, bbOutside, v) and bbInside = sbbInside.getBasicBlock() and bbOutside = sbbOutside.getBasicBlock() and sbbInside.lastInBB() and - sbbOutside.firstInBB() and - loop.bbNotInLoop(sbbDef.getBasicBlock()) and - exists(TBlockVar(sbbDef, v)) + sbbOutside.firstInBB() ) } @@ -571,7 +568,9 @@ module FlowVar_internal { start = TBlockVar(sbbDef, v) and result = mid.getASuccessor() and variableLiveInSBB(result, v) and - not skipLoop(mid, result, sbbDef, v) and + forall(AlwaysTrueUponEntryLoop loop | skipLoop(mid, result, v, loop) | + loop.sbbInLoop(sbbDef) + ) and not assignmentLikeOperation(result, v, _, _) ) } From aa1368741b951df97f90431c98958667b70d068c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 1 Oct 2019 14:37:07 +0200 Subject: [PATCH 0319/1227] rename suspicious-method-name to suspicious-method-name-declaration --- change-notes/1.23/analysis-javascript.md | 2 +- ...MethodName.qhelp => SuspiciousMethodNameDeclaration.qhelp} | 4 ++-- ...iciousMethodName.ql => SuspiciousMethodNameDeclaration.ql} | 4 ++-- ...iciousMethodName.ts => SuspiciousMethodNameDeclaration.ts} | 0 ...odNameFixed.ts => SuspiciousMethodNameDeclarationFixed.ts} | 0 .../SuspiciousMethodNameDeclaration.expected} | 0 .../SuspiciousMethodNameDeclaration.qlref} | 0 .../tst.js | 0 .../tst.ts | 0 9 files changed, 5 insertions(+), 5 deletions(-) rename javascript/ql/src/Declarations/{SuspiciousMethodName.qhelp => SuspiciousMethodNameDeclaration.qhelp} (92%) rename javascript/ql/src/Declarations/{SuspiciousMethodName.ql => SuspiciousMethodNameDeclaration.ql} (96%) rename javascript/ql/src/Declarations/examples/{SuspiciousMethodName.ts => SuspiciousMethodNameDeclaration.ts} (100%) rename javascript/ql/src/Declarations/examples/{SuspiciousMethodNameFixed.ts => SuspiciousMethodNameDeclarationFixed.ts} (100%) rename javascript/ql/test/query-tests/Declarations/{SuspiciousMethodName/SuspiciousMethodName.expected => SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected} (100%) rename javascript/ql/test/query-tests/Declarations/{SuspiciousMethodName/SuspiciousMethodName.qlref => SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.qlref} (100%) rename javascript/ql/test/query-tests/Declarations/{SuspiciousMethodName => SuspiciousMethodNameDeclaration}/tst.js (100%) rename javascript/ql/test/query-tests/Declarations/{SuspiciousMethodName => SuspiciousMethodNameDeclaration}/tst.ts (100%) diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md index e26862392f4..04b5e6cb541 100644 --- a/change-notes/1.23/analysis-javascript.md +++ b/change-notes/1.23/analysis-javascript.md @@ -16,7 +16,7 @@ |---------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Unused index variable (`js/unused-index-variable`) | correctness | Highlights loops that iterate over an array, but do not use the index variable to access array elements, indicating a possible typo or logic error. Results are shown on LGTM by default. | | Loop bound injection (`js/loop-bound-injection`) | security, external/cwe/cwe-834 | Highlights loops where a user-controlled object with an arbitrary .length value can trick the server to loop indefinitely. Results are not shown on LGTM by default. | -| Suspicious method name (`js/suspicious-method-name`) | correctness, typescript, methods | Highlights suspiciously named methods where the developer likely meant to write a constructor or function. Results are shown on LGTM by default. | +| Suspicious method name (`js/suspicious-method-name-declaration`) | correctness, typescript, methods | Highlights suspiciously named methods where the developer likely meant to write a constructor or function. Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/javascript/ql/src/Declarations/SuspiciousMethodName.qhelp b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp similarity index 92% rename from javascript/ql/src/Declarations/SuspiciousMethodName.qhelp rename to javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp index 6a2a46913d6..efb72133b4c 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodName.qhelp +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp @@ -33,7 +33,7 @@ and a method called constructor. The interface does not declare a class Point with a constructor, which was likely what the developer meant to create.

    - +

    The below example is a fixed version of the above, where the interface is @@ -41,7 +41,7 @@ instead declared as a class, thereby describing the type the developer meant in the first place.

    - + diff --git a/javascript/ql/src/Declarations/SuspiciousMethodName.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql similarity index 96% rename from javascript/ql/src/Declarations/SuspiciousMethodName.ql rename to javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index c65bb1448ac..dfe5b9f6e74 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodName.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -1,10 +1,10 @@ /** - * @name Suspicious method name + * @name Suspicious method name declaration * @description A method having the name "function", "new", or "constructor" * is usually caused by a programmer being confused about the TypeScript syntax. * @kind problem * @problem.severity warning - * @id js/suspicious-method-name + * @id js/suspicious-method-name-declaration * @precision high * @tags correctness * typescript diff --git a/javascript/ql/src/Declarations/examples/SuspiciousMethodName.ts b/javascript/ql/src/Declarations/examples/SuspiciousMethodNameDeclaration.ts similarity index 100% rename from javascript/ql/src/Declarations/examples/SuspiciousMethodName.ts rename to javascript/ql/src/Declarations/examples/SuspiciousMethodNameDeclaration.ts diff --git a/javascript/ql/src/Declarations/examples/SuspiciousMethodNameFixed.ts b/javascript/ql/src/Declarations/examples/SuspiciousMethodNameDeclarationFixed.ts similarity index 100% rename from javascript/ql/src/Declarations/examples/SuspiciousMethodNameFixed.ts rename to javascript/ql/src/Declarations/examples/SuspiciousMethodNameDeclarationFixed.ts diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.expected b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected similarity index 100% rename from javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.expected rename to javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.qlref b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.qlref similarity index 100% rename from javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/SuspiciousMethodName.qlref rename to javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.qlref diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.js b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/tst.js similarity index 100% rename from javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.js rename to javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/tst.js diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.ts b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/tst.ts similarity index 100% rename from javascript/ql/test/query-tests/Declarations/SuspiciousMethodName/tst.ts rename to javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/tst.ts From 1e2aad5a296f6bcf026d07c295c4865a384ec0a1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 1 Oct 2019 14:56:00 +0200 Subject: [PATCH 0320/1227] fix pointer in .qlref, and update expected test results --- .../SuspiciousMethodNameDeclaration.expected | 2 +- .../SuspiciousMethodNameDeclaration.qlref | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected index 444715e8182..8b11a5f8479 100644 --- a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected +++ b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected @@ -1,4 +1,4 @@ -| tst.ts:7:3:7:24 | constru ... string; | Declares a suspiciously named method "constructor". Did you mean "new"? | +| tst.ts:7:3:7:24 | constru ... string; | Declares a suspiciously named method "constructor". Did you mean to write a class instead of an interface? | | tst.ts:16:3:16:21 | function(): number; | Declares a suspiciously named method "function". Did you mean to omit "function"? | | tst.ts:37:3:37:21 | function(): number; | Declares a suspiciously named method "function". Did you mean to omit "function"? | | tst.ts:48:3:48:13 | new(): Quz; | Declares a suspiciously named method "new". Did you mean "constructor"? | diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.qlref b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.qlref index 7db43af7e2f..f9446bc51e2 100644 --- a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.qlref +++ b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.qlref @@ -1 +1 @@ -Declarations/SuspiciousMethodName.ql \ No newline at end of file +Declarations/SuspiciousMethodNameDeclaration.ql \ No newline at end of file From 26a0bfac398aa727ccd1af28a4659f98a85a88b9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 1 Oct 2019 15:06:45 +0200 Subject: [PATCH 0321/1227] refactor js/suspicious-method-name-declaration to use isSynthetic predicate --- .../SuspiciousMethodNameDeclaration.ql | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index dfe5b9f6e74..635a95bb2db 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -26,14 +26,6 @@ predicate isSuspisousMethodName(string name, ClassOrInterface container) { name = "new" and container instanceof ClassDefinition } -/** - * Holds if the beginning of the location is before the end. - */ -predicate isRealLocation(Location l) { - l.getEndLine() > l.getStartLine() or - (l.getStartLine() = l.getEndLine() and l.getEndColumn() > l.getStartColumn()) -} - from MethodDeclaration member, ClassOrInterface container, string suffixMsg where container.getLocation().getFile().getFileType().isTypeScript() and @@ -44,11 +36,9 @@ where not ( member.getName() = "new" and container instanceof ClassDefinition and - exists(MemberDeclaration constructor | + exists(ConstructorDeclaration constructor | container.getAMember() = constructor and - constructor.getName() = "constructor" and - // Test that it is not an implicitly declared constructor. - isRealLocation(constructor.getLocation()) + not constructor.isSynthetic() ) ) and @@ -66,7 +56,7 @@ where member.getName() = "function" and exists(MethodDeclaration other | other = container.getMethod(_) | other.getName() != "function" and - isRealLocation(other.getLocation()) + not other.(ConstructorDeclaration).isSynthetic() ) ) and From 6c176fc967001a525ec63ef8a8009998fbb4e9c0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 1 Oct 2019 15:28:57 +0200 Subject: [PATCH 0322/1227] introduce name as a variable, and adjust alert messages --- .../SuspiciousMethodNameDeclaration.ql | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index 635a95bb2db..0f4114552e6 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -26,20 +26,17 @@ predicate isSuspisousMethodName(string name, ClassOrInterface container) { name = "new" and container instanceof ClassDefinition } -from MethodDeclaration member, ClassOrInterface container, string suffixMsg +from MethodDeclaration member, ClassOrInterface container, string name, string msg where container.getLocation().getFile().getFileType().isTypeScript() and - container.getAMember() = member and - isSuspisousMethodName(member.getName(), container) and + container.getMember(name) = member and + isSuspisousMethodName(name, container) and // Assume that a "new" method is intentional if the class has an explicit constructor. not ( - member.getName() = "new" and + name = "new" and container instanceof ClassDefinition and - exists(ConstructorDeclaration constructor | - container.getAMember() = constructor and - not constructor.isSynthetic() - ) + not container.getMember("constructor").(ConstructorDeclaration).isSynthetic() ) and // Explicitly declared static methods are fine. @@ -53,18 +50,18 @@ where // The developer was not confused about "function" when there are other methods in the interface. not ( - member.getName() = "function" and - exists(MethodDeclaration other | other = container.getMethod(_) | - other.getName() != "function" and + name = "function" and + exists(MethodDeclaration other | other = container.getAMethod() | + name != "function" and not other.(ConstructorDeclaration).isSynthetic() ) ) and ( - member.getName() = "constructor" and suffixMsg = "Did you mean to write a class instead of an interface?" + name = "constructor" and msg = "The member name 'constructor' does not declare a constructor in interface declarations, but it does in class declarations." or - member.getName() = "new" and suffixMsg = "Did you mean \"constructor\"?" + name = "new" and msg = "The member name 'new' does not declare a constructor, but 'constructor' does in class declarations." or - member.getName() = "function" and suffixMsg = "Did you mean to omit \"function\"?" + name = "function" and msg = "The member name 'function' does not declare a function, it declares a method named 'function'." ) -select member, "Declares a suspiciously named method \"" + member.getName() + "\". " + suffixMsg +select member, msg From 2ad85d16bd603330beb8c4a559349d2b02ec8930 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 1 Oct 2019 15:53:22 +0200 Subject: [PATCH 0323/1227] refactor a list of negated conjunctions to a disjunction --- .../SuspiciousMethodNameDeclaration.ql | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index 0f4114552e6..b84d3505899 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -32,30 +32,33 @@ where container.getMember(name) = member and isSuspisousMethodName(name, container) and - // Assume that a "new" method is intentional if the class has an explicit constructor. + // Cases to ignore. not ( - name = "new" and - container instanceof ClassDefinition and - not container.getMember("constructor").(ConstructorDeclaration).isSynthetic() - ) and - - // Explicitly declared static methods are fine. - not ( - container instanceof ClassDefinition and - member.isStatic() - ) and - - // Only looking for declared methods. Methods with a body are OK. - not exists(member.getBody().getBody()) and - - // The developer was not confused about "function" when there are other methods in the interface. - not ( - name = "function" and - exists(MethodDeclaration other | other = container.getAMethod() | - name != "function" and - not other.(ConstructorDeclaration).isSynthetic() + ( // Assume that a "new" method is intentional if the class has an explicit constructor. + name = "new" and + container instanceof ClassDefinition and + not container.getMember("constructor").(ConstructorDeclaration).isSynthetic() + ) + or + ( // Explicitly declared static methods are fine. + container instanceof ClassDefinition and + member.isStatic() ) - ) and + or + // Only looking for declared methods. Methods with a body are OK. + exists(member.getBody().getBody()) + + or + ( // The developer was not confused about "function" when there are other methods in the interface. + name = "function" and + exists(MethodDeclaration other | other = container.getAMethod() | + name != "function" and + not other.(ConstructorDeclaration).isSynthetic() + ) + ) + ) + + and ( name = "constructor" and msg = "The member name 'constructor' does not declare a constructor in interface declarations, but it does in class declarations." From 584b9d4e30ab7ff1e8a28805881ea69629218349 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 1 Oct 2019 15:53:37 +0200 Subject: [PATCH 0324/1227] update expected test output --- .../SuspiciousMethodNameDeclaration.expected | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected index 8b11a5f8479..b033253ccd6 100644 --- a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected +++ b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected @@ -1,4 +1,5 @@ -| tst.ts:7:3:7:24 | constru ... string; | Declares a suspiciously named method "constructor". Did you mean to write a class instead of an interface? | -| tst.ts:16:3:16:21 | function(): number; | Declares a suspiciously named method "function". Did you mean to omit "function"? | -| tst.ts:37:3:37:21 | function(): number; | Declares a suspiciously named method "function". Did you mean to omit "function"? | -| tst.ts:48:3:48:13 | new(): Quz; | Declares a suspiciously named method "new". Did you mean "constructor"? | +| tst.ts:4:3:4:22 | function (): number; | The member name 'function' does not declare a function, it declares a method named 'function'. | +| tst.ts:7:3:7:24 | constru ... string; | The member name 'constructor' does not declare a constructor in interface declarations, but it does in class declarations. | +| tst.ts:16:3:16:21 | function(): number; | The member name 'function' does not declare a function, it declares a method named 'function'. | +| tst.ts:37:3:37:21 | function(): number; | The member name 'function' does not declare a function, it declares a method named 'function'. | +| tst.ts:48:3:48:13 | new(): Quz; | The member name 'new' does not declare a constructor, but 'constructor' does in class declarations. | From 3c7d79481f3bf629e3a487d5be9d5f558269e1d1 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 1 Oct 2019 15:54:41 +0200 Subject: [PATCH 0325/1227] C++: Autoformat FlowVar.qll --- cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll index 55d8fb0356c..0792d0d43af 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -514,9 +514,7 @@ module FlowVar_internal { } /** Holds if `sbb` is inside this loop. */ - predicate sbbInLoop(SubBasicBlock sbb) { - this.bbInLoop(sbb.getBasicBlock()) - } + predicate sbbInLoop(SubBasicBlock sbb) { this.bbInLoop(sbb.getBasicBlock()) } /** * Holds if `bb` is a basic block inside this loop where `v` has not been @@ -568,9 +566,7 @@ module FlowVar_internal { start = TBlockVar(sbbDef, v) and result = mid.getASuccessor() and variableLiveInSBB(result, v) and - forall(AlwaysTrueUponEntryLoop loop | skipLoop(mid, result, v, loop) | - loop.sbbInLoop(sbbDef) - ) and + forall(AlwaysTrueUponEntryLoop loop | skipLoop(mid, result, v, loop) | loop.sbbInLoop(sbbDef)) and not assignmentLikeOperation(result, v, _, _) ) } From a66e33ea5e5610cb703787fb12fe33991fb38883 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 1 Oct 2019 15:56:45 +0200 Subject: [PATCH 0326/1227] add references to TypeScript spec for "new" and "constructor" keywords --- .../ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp index efb72133b4c..f34fdda1639 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp @@ -46,5 +46,8 @@ in the first place. +
  • TypeScript specification: Constructor Type Literals
  • +
  • TypeScript specification: Constructor Parameters
  • +
    From bace8c723db477d9aace46b3dd8d80c68aa12601 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 1 Oct 2019 14:53:37 -0700 Subject: [PATCH 0327/1227] C++: side effect instrs for constructor qualifiers This adds IndirectMustWriteSideEffects for constructor qualifiers. The introduced sanity failures result from constructor calls without qualifier operands in the IR --- .../raw/internal/TranslatedCall.qll | 30 + .../raw/internal/TranslatedElement.qll | 2 +- .../ir/ir/aliased_ssa_sanity.expected | 4 + .../test/library-tests/ir/ir/raw_ir.expected | 1258 +++++++++-------- .../library-tests/ir/ir/raw_sanity.expected | 4 + .../ir/ir/unaliased_ssa_sanity.expected | 4 + .../syntax-zoo/aliased_ssa_sanity.expected | 41 +- .../syntax-zoo/raw_sanity.expected | 50 +- .../syntax-zoo/unaliased_ssa_sanity.expected | 47 +- 9 files changed, 799 insertions(+), 641 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 4a7aa607f57..0ee86785b52 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -374,6 +374,35 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects { override Function getFunction() { result = expr.getEnclosingFunction() } } +class TranslatedStructorCallSideEffects extends TranslatedSideEffects { + TranslatedStructorCallSideEffects() { getParent().(TranslatedStructorCall).hasQualifier() } + + override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type t, boolean isGLValue) { + opcode instanceof Opcode::IndirectMustWriteSideEffect and + tag instanceof OnlyInstructionTag and + t = expr.getTarget().getDeclaringType() and + isGLValue = false + } + + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { + ( + if exists(getChild(0)) + then result = getChild(0).getFirstInstruction() + else result = getParent().getChildSuccessor(this) + ) and + tag = OnlyInstructionTag() and + kind instanceof GotoEdge + } + + override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } + + override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + tag instanceof OnlyInstructionTag and + operandTag instanceof AddressOperandTag and + result = getParent().(TranslatedStructorCall).getQualifierResult() + } +} + class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEffect { Call call; Expr arg; @@ -537,3 +566,4 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff */ override Function getFunction() { result = arg.getEnclosingFunction() } } + diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 01ed6a4d591..db34d69f4c8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -372,7 +372,7 @@ newtype TTranslatedElement = // The declaration/initialization part of a `ConditionDeclExpr` TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or // The side effects of a `Call` { - TTranslatedSideEffects(Call expr) { exists(TTranslatedArgumentSideEffect(expr, _, _, _)) } or // A precise side effect of an argument to a `Call` { + TTranslatedSideEffects(Call expr) { exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or expr instanceof ConstructorCall } or // A precise side effect of an argument to a `Call` { TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) { ( expr = call.getArgument(n).getFullyConverted() diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected index ae680785ce6..283f13d4bf4 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected @@ -1,4 +1,8 @@ missingOperand +| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 3bff2bff690..55a8cc56e01 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -2715,31 +2715,34 @@ ir.cpp: # 616| r0_4(glval) = FunctionAddress[String] : # 616| v0_5(void) = Call : func:r0_4, this:r0_3 # 616| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 617| r0_7(glval) = VariableAddress[s2] : -# 617| r0_8(glval) = FunctionAddress[String] : -# 617| r0_9(glval) = StringConstant["hello"] : -# 617| r0_10(char *) = Convert : r0_9 -# 617| v0_11(void) = Call : func:r0_8, this:r0_7, 0:r0_10 -# 617| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 617| v0_13(void) = ^IndirectReadSideEffect[0] : &:r0_10, ~mu0_2 -# 617| mu0_14(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_10 -# 618| r0_15(glval) = VariableAddress[s3] : -# 618| r0_16(glval) = FunctionAddress[ReturnObject] : -# 618| r0_17(String) = Call : func:r0_16 -# 618| mu0_18(unknown) = ^CallSideEffect : ~mu0_2 -# 618| mu0_19(String) = Store : &:r0_15, r0_17 -# 619| r0_20(glval) = VariableAddress[s4] : -# 619| r0_21(glval) = FunctionAddress[String] : -# 619| r0_22(glval) = StringConstant["test"] : -# 619| r0_23(char *) = Convert : r0_22 -# 619| v0_24(void) = Call : func:r0_21, this:r0_20, 0:r0_23 -# 619| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 619| v0_26(void) = ^IndirectReadSideEffect[0] : &:r0_23, ~mu0_2 -# 619| mu0_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_23 -# 620| v0_28(void) = NoOp : -# 615| v0_29(void) = ReturnVoid : -# 615| v0_30(void) = UnmodeledUse : mu* -# 615| v0_31(void) = ExitFunction : +# 616| mu0_7(String) = ^IndirectMustWriteSideEffect : &:r0_3 +# 617| r0_8(glval) = VariableAddress[s2] : +# 617| r0_9(glval) = FunctionAddress[String] : +# 617| r0_10(glval) = StringConstant["hello"] : +# 617| r0_11(char *) = Convert : r0_10 +# 617| v0_12(void) = Call : func:r0_9, this:r0_8, 0:r0_11 +# 617| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +# 617| mu0_14(String) = ^IndirectMustWriteSideEffect : &:r0_8 +# 617| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 +# 617| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 +# 618| r0_17(glval) = VariableAddress[s3] : +# 618| r0_18(glval) = FunctionAddress[ReturnObject] : +# 618| r0_19(String) = Call : func:r0_18 +# 618| mu0_20(unknown) = ^CallSideEffect : ~mu0_2 +# 618| mu0_21(String) = Store : &:r0_17, r0_19 +# 619| r0_22(glval) = VariableAddress[s4] : +# 619| r0_23(glval) = FunctionAddress[String] : +# 619| r0_24(glval) = StringConstant["test"] : +# 619| r0_25(char *) = Convert : r0_24 +# 619| v0_26(void) = Call : func:r0_23, this:r0_22, 0:r0_25 +# 619| mu0_27(unknown) = ^CallSideEffect : ~mu0_2 +# 619| mu0_28(String) = ^IndirectMustWriteSideEffect : &:r0_22 +# 619| v0_29(void) = ^IndirectReadSideEffect[0] : &:r0_25, ~mu0_2 +# 619| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_25 +# 620| v0_31(void) = NoOp : +# 615| v0_32(void) = ReturnVoid : +# 615| v0_33(void) = UnmodeledUse : mu* +# 615| v0_34(void) = ExitFunction : # 622| void CallMethods(String&, String*, String) # 622| Block 0 @@ -2915,24 +2918,26 @@ ir.cpp: # 663| r0_8(glval) = FunctionAddress[String] : # 663| v0_9(void) = Call : func:r0_8, this:r0_7 # 663| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 660| r0_11(glval) = FieldAddress[m_c] : r0_3 -# 660| r0_12(char) = Constant[3] : -# 660| mu0_13(char) = Store : &:r0_11, r0_12 -# 661| r0_14(glval) = FieldAddress[m_e] : r0_3 -# 661| r0_15(void *) = Constant[0] : -# 661| mu0_16(void *) = Store : &:r0_14, r0_15 -# 662| r0_17(glval) = FieldAddress[m_f] : r0_3 -# 662| r0_18(glval) = FunctionAddress[String] : -# 662| r0_19(glval) = StringConstant["test"] : -# 662| r0_20(char *) = Convert : r0_19 -# 662| v0_21(void) = Call : func:r0_18, this:r0_17, 0:r0_20 -# 662| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -# 662| v0_23(void) = ^IndirectReadSideEffect[0] : &:r0_20, ~mu0_2 -# 662| mu0_24(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_20 -# 664| v0_25(void) = NoOp : -# 658| v0_26(void) = ReturnVoid : -# 658| v0_27(void) = UnmodeledUse : mu* -# 658| v0_28(void) = ExitFunction : +# 663| mu0_11(String) = ^IndirectMustWriteSideEffect : &:r0_7 +# 660| r0_12(glval) = FieldAddress[m_c] : r0_3 +# 660| r0_13(char) = Constant[3] : +# 660| mu0_14(char) = Store : &:r0_12, r0_13 +# 661| r0_15(glval) = FieldAddress[m_e] : r0_3 +# 661| r0_16(void *) = Constant[0] : +# 661| mu0_17(void *) = Store : &:r0_15, r0_16 +# 662| r0_18(glval) = FieldAddress[m_f] : r0_3 +# 662| r0_19(glval) = FunctionAddress[String] : +# 662| r0_20(glval) = StringConstant["test"] : +# 662| r0_21(char *) = Convert : r0_20 +# 662| v0_22(void) = Call : func:r0_19, this:r0_18, 0:r0_21 +# 662| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 +# 662| mu0_24(String) = ^IndirectMustWriteSideEffect : &:r0_18 +# 662| v0_25(void) = ^IndirectReadSideEffect[0] : &:r0_21, ~mu0_2 +# 662| mu0_26(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_21 +# 664| v0_27(void) = NoOp : +# 658| v0_28(void) = ReturnVoid : +# 658| v0_29(void) = UnmodeledUse : mu* +# 658| v0_30(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 @@ -3201,9 +3206,10 @@ ir.cpp: # 731| r7_3(char *) = Convert : r7_2 # 731| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 731| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 731| v7_6(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 -# 731| mu7_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 -# 731| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 +# 731| mu7_6(String) = ^IndirectMustWriteSideEffect : &:r7_0 +# 731| v7_7(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 +# 731| mu7_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 +# 731| v7_9(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 # 733| Block 8 @@ -3226,9 +3232,10 @@ ir.cpp: # 736| r10_5(char *) = Load : &:r10_4, ~mu0_2 # 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 # 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 736| v10_8(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 -# 736| mu10_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 -# 736| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 +# 736| mu10_8(String) = ^IndirectMustWriteSideEffect : &:r10_2 +# 736| v10_9(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 +# 736| mu10_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 +# 736| v10_11(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 # 738| Block 11 @@ -3282,35 +3289,37 @@ ir.cpp: # 745| void Base::Base(Base const&) # 745| Block 0 -# 745| v0_0(void) = EnterFunction : -# 745| mu0_1(unknown) = AliasedDefinition : -# 745| mu0_2(unknown) = UnmodeledDefinition : -# 745| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 -# 745| r0_6(glval) = FieldAddress[base_s] : r0_3 -# 745| r0_7(glval) = FunctionAddress[String] : -# 745| v0_8(void) = Call : func:r0_7, this:r0_6 -# 745| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 -# 745| v0_10(void) = NoOp : -# 745| v0_11(void) = ReturnVoid : -# 745| v0_12(void) = UnmodeledUse : mu* -# 745| v0_13(void) = ExitFunction : +# 745| v0_0(void) = EnterFunction : +# 745| mu0_1(unknown) = AliasedDefinition : +# 745| mu0_2(unknown) = UnmodeledDefinition : +# 745| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 +# 745| r0_6(glval) = FieldAddress[base_s] : r0_3 +# 745| r0_7(glval) = FunctionAddress[String] : +# 745| v0_8(void) = Call : func:r0_7, this:r0_6 +# 745| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 +# 745| mu0_10(String) = ^IndirectMustWriteSideEffect : &:r0_6 +# 745| v0_11(void) = NoOp : +# 745| v0_12(void) = ReturnVoid : +# 745| v0_13(void) = UnmodeledUse : mu* +# 745| v0_14(void) = ExitFunction : # 748| void Base::Base() # 748| Block 0 -# 748| v0_0(void) = EnterFunction : -# 748| mu0_1(unknown) = AliasedDefinition : -# 748| mu0_2(unknown) = UnmodeledDefinition : -# 748| r0_3(glval) = InitializeThis : -# 748| r0_4(glval) = FieldAddress[base_s] : r0_3 -# 748| r0_5(glval) = FunctionAddress[String] : -# 748| v0_6(void) = Call : func:r0_5, this:r0_4 -# 748| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 749| v0_8(void) = NoOp : -# 748| v0_9(void) = ReturnVoid : -# 748| v0_10(void) = UnmodeledUse : mu* -# 748| v0_11(void) = ExitFunction : +# 748| v0_0(void) = EnterFunction : +# 748| mu0_1(unknown) = AliasedDefinition : +# 748| mu0_2(unknown) = UnmodeledDefinition : +# 748| r0_3(glval) = InitializeThis : +# 748| r0_4(glval) = FieldAddress[base_s] : r0_3 +# 748| r0_5(glval) = FunctionAddress[String] : +# 748| v0_6(void) = Call : func:r0_5, this:r0_4 +# 748| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +# 748| mu0_8(String) = ^IndirectMustWriteSideEffect : &:r0_4 +# 749| v0_9(void) = NoOp : +# 748| v0_10(void) = ReturnVoid : +# 748| v0_11(void) = UnmodeledUse : mu* +# 748| v0_12(void) = ExitFunction : # 750| void Base::~Base() # 750| Block 0 @@ -3369,22 +3378,24 @@ ir.cpp: # 757| void Middle::Middle() # 757| Block 0 -# 757| v0_0(void) = EnterFunction : -# 757| mu0_1(unknown) = AliasedDefinition : -# 757| mu0_2(unknown) = UnmodeledDefinition : -# 757| r0_3(glval) = InitializeThis : -# 757| r0_4(glval) = ConvertToBase[Middle : Base] : r0_3 -# 757| r0_5(glval) = FunctionAddress[Base] : -# 757| v0_6(void) = Call : func:r0_5, this:r0_4 -# 757| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 757| r0_8(glval) = FieldAddress[middle_s] : r0_3 -# 757| r0_9(glval) = FunctionAddress[String] : -# 757| v0_10(void) = Call : func:r0_9, this:r0_8 -# 757| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 758| v0_12(void) = NoOp : -# 757| v0_13(void) = ReturnVoid : -# 757| v0_14(void) = UnmodeledUse : mu* -# 757| v0_15(void) = ExitFunction : +# 757| v0_0(void) = EnterFunction : +# 757| mu0_1(unknown) = AliasedDefinition : +# 757| mu0_2(unknown) = UnmodeledDefinition : +# 757| r0_3(glval) = InitializeThis : +# 757| r0_4(glval) = ConvertToBase[Middle : Base] : r0_3 +# 757| r0_5(glval) = FunctionAddress[Base] : +# 757| v0_6(void) = Call : func:r0_5, this:r0_4 +# 757| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +# 757| mu0_8(Base) = ^IndirectMustWriteSideEffect : &:r0_4 +# 757| r0_9(glval) = FieldAddress[middle_s] : r0_3 +# 757| r0_10(glval) = FunctionAddress[String] : +# 757| v0_11(void) = Call : func:r0_10, this:r0_9 +# 757| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 757| mu0_13(String) = ^IndirectMustWriteSideEffect : &:r0_9 +# 758| v0_14(void) = NoOp : +# 757| v0_15(void) = ReturnVoid : +# 757| v0_16(void) = UnmodeledUse : mu* +# 757| v0_17(void) = ExitFunction : # 759| void Middle::~Middle() # 759| Block 0 @@ -3447,22 +3458,24 @@ ir.cpp: # 766| void Derived::Derived() # 766| Block 0 -# 766| v0_0(void) = EnterFunction : -# 766| mu0_1(unknown) = AliasedDefinition : -# 766| mu0_2(unknown) = UnmodeledDefinition : -# 766| r0_3(glval) = InitializeThis : -# 766| r0_4(glval) = ConvertToBase[Derived : Middle] : r0_3 -# 766| r0_5(glval) = FunctionAddress[Middle] : -# 766| v0_6(void) = Call : func:r0_5, this:r0_4 -# 766| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 766| r0_8(glval) = FieldAddress[derived_s] : r0_3 -# 766| r0_9(glval) = FunctionAddress[String] : -# 766| v0_10(void) = Call : func:r0_9, this:r0_8 -# 766| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 767| v0_12(void) = NoOp : -# 766| v0_13(void) = ReturnVoid : -# 766| v0_14(void) = UnmodeledUse : mu* -# 766| v0_15(void) = ExitFunction : +# 766| v0_0(void) = EnterFunction : +# 766| mu0_1(unknown) = AliasedDefinition : +# 766| mu0_2(unknown) = UnmodeledDefinition : +# 766| r0_3(glval) = InitializeThis : +# 766| r0_4(glval) = ConvertToBase[Derived : Middle] : r0_3 +# 766| r0_5(glval) = FunctionAddress[Middle] : +# 766| v0_6(void) = Call : func:r0_5, this:r0_4 +# 766| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +# 766| mu0_8(Middle) = ^IndirectMustWriteSideEffect : &:r0_4 +# 766| r0_9(glval) = FieldAddress[derived_s] : r0_3 +# 766| r0_10(glval) = FunctionAddress[String] : +# 766| v0_11(void) = Call : func:r0_10, this:r0_9 +# 766| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 766| mu0_13(String) = ^IndirectMustWriteSideEffect : &:r0_9 +# 767| v0_14(void) = NoOp : +# 766| v0_15(void) = ReturnVoid : +# 766| v0_16(void) = UnmodeledUse : mu* +# 766| v0_17(void) = ExitFunction : # 768| void Derived::~Derived() # 768| Block 0 @@ -3493,14 +3506,16 @@ ir.cpp: # 775| r0_5(glval) = FunctionAddress[Base] : # 775| v0_6(void) = Call : func:r0_5, this:r0_4 # 775| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 775| r0_8(glval) = FieldAddress[middlevb1_s] : r0_3 -# 775| r0_9(glval) = FunctionAddress[String] : -# 775| v0_10(void) = Call : func:r0_9, this:r0_8 -# 775| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 776| v0_12(void) = NoOp : -# 775| v0_13(void) = ReturnVoid : -# 775| v0_14(void) = UnmodeledUse : mu* -# 775| v0_15(void) = ExitFunction : +# 775| mu0_8(Base) = ^IndirectMustWriteSideEffect : &:r0_4 +# 775| r0_9(glval) = FieldAddress[middlevb1_s] : r0_3 +# 775| r0_10(glval) = FunctionAddress[String] : +# 775| v0_11(void) = Call : func:r0_10, this:r0_9 +# 775| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 775| mu0_13(String) = ^IndirectMustWriteSideEffect : &:r0_9 +# 776| v0_14(void) = NoOp : +# 775| v0_15(void) = ReturnVoid : +# 775| v0_16(void) = UnmodeledUse : mu* +# 775| v0_17(void) = ExitFunction : # 777| void MiddleVB1::~MiddleVB1() # 777| Block 0 @@ -3531,14 +3546,16 @@ ir.cpp: # 784| r0_5(glval) = FunctionAddress[Base] : # 784| v0_6(void) = Call : func:r0_5, this:r0_4 # 784| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 784| r0_8(glval) = FieldAddress[middlevb2_s] : r0_3 -# 784| r0_9(glval) = FunctionAddress[String] : -# 784| v0_10(void) = Call : func:r0_9, this:r0_8 -# 784| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 785| v0_12(void) = NoOp : -# 784| v0_13(void) = ReturnVoid : -# 784| v0_14(void) = UnmodeledUse : mu* -# 784| v0_15(void) = ExitFunction : +# 784| mu0_8(Base) = ^IndirectMustWriteSideEffect : &:r0_4 +# 784| r0_9(glval) = FieldAddress[middlevb2_s] : r0_3 +# 784| r0_10(glval) = FunctionAddress[String] : +# 784| v0_11(void) = Call : func:r0_10, this:r0_9 +# 784| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 784| mu0_13(String) = ^IndirectMustWriteSideEffect : &:r0_9 +# 785| v0_14(void) = NoOp : +# 784| v0_15(void) = ReturnVoid : +# 784| v0_16(void) = UnmodeledUse : mu* +# 784| v0_17(void) = ExitFunction : # 786| void MiddleVB2::~MiddleVB2() # 786| Block 0 @@ -3569,22 +3586,26 @@ ir.cpp: # 793| r0_5(glval) = FunctionAddress[Base] : # 793| v0_6(void) = Call : func:r0_5, this:r0_4 # 793| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 793| r0_8(glval) = ConvertToBase[DerivedVB : MiddleVB1] : r0_3 -# 793| r0_9(glval) = FunctionAddress[MiddleVB1] : -# 793| v0_10(void) = Call : func:r0_9, this:r0_8 -# 793| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 793| r0_12(glval) = ConvertToBase[DerivedVB : MiddleVB2] : r0_3 -# 793| r0_13(glval) = FunctionAddress[MiddleVB2] : -# 793| v0_14(void) = Call : func:r0_13, this:r0_12 -# 793| mu0_15(unknown) = ^CallSideEffect : ~mu0_2 -# 793| r0_16(glval) = FieldAddress[derivedvb_s] : r0_3 -# 793| r0_17(glval) = FunctionAddress[String] : -# 793| v0_18(void) = Call : func:r0_17, this:r0_16 -# 793| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 -# 794| v0_20(void) = NoOp : -# 793| v0_21(void) = ReturnVoid : -# 793| v0_22(void) = UnmodeledUse : mu* -# 793| v0_23(void) = ExitFunction : +# 793| mu0_8(Base) = ^IndirectMustWriteSideEffect : &:r0_4 +# 793| r0_9(glval) = ConvertToBase[DerivedVB : MiddleVB1] : r0_3 +# 793| r0_10(glval) = FunctionAddress[MiddleVB1] : +# 793| v0_11(void) = Call : func:r0_10, this:r0_9 +# 793| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 793| mu0_13(MiddleVB1) = ^IndirectMustWriteSideEffect : &:r0_9 +# 793| r0_14(glval) = ConvertToBase[DerivedVB : MiddleVB2] : r0_3 +# 793| r0_15(glval) = FunctionAddress[MiddleVB2] : +# 793| v0_16(void) = Call : func:r0_15, this:r0_14 +# 793| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 +# 793| mu0_18(MiddleVB2) = ^IndirectMustWriteSideEffect : &:r0_14 +# 793| r0_19(glval) = FieldAddress[derivedvb_s] : r0_3 +# 793| r0_20(glval) = FunctionAddress[String] : +# 793| v0_21(void) = Call : func:r0_20, this:r0_19 +# 793| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 +# 793| mu0_23(String) = ^IndirectMustWriteSideEffect : &:r0_19 +# 794| v0_24(void) = NoOp : +# 793| v0_25(void) = ReturnVoid : +# 793| v0_26(void) = UnmodeledUse : mu* +# 793| v0_27(void) = ExitFunction : # 795| void DerivedVB::~DerivedVB() # 795| Block 0 @@ -3622,251 +3643,258 @@ ir.cpp: # 800| r0_4(glval) = FunctionAddress[Base] : # 800| v0_5(void) = Call : func:r0_4, this:r0_3 # 800| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 801| r0_7(glval) = VariableAddress[m] : -# 801| r0_8(glval) = FunctionAddress[Middle] : -# 801| v0_9(void) = Call : func:r0_8, this:r0_7 -# 801| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 802| r0_11(glval) = VariableAddress[d] : -# 802| r0_12(glval) = FunctionAddress[Derived] : -# 802| v0_13(void) = Call : func:r0_12, this:r0_11 -# 802| mu0_14(unknown) = ^CallSideEffect : ~mu0_2 -# 804| r0_15(glval) = VariableAddress[pb] : -# 804| r0_16(glval) = VariableAddress[b] : -# 804| mu0_17(Base *) = Store : &:r0_15, r0_16 -# 805| r0_18(glval) = VariableAddress[pm] : -# 805| r0_19(glval) = VariableAddress[m] : -# 805| mu0_20(Middle *) = Store : &:r0_18, r0_19 -# 806| r0_21(glval) = VariableAddress[pd] : -# 806| r0_22(glval) = VariableAddress[d] : -# 806| mu0_23(Derived *) = Store : &:r0_21, r0_22 -# 808| r0_24(glval) = VariableAddress[b] : -# 808| r0_25(glval) = FunctionAddress[operator=] : -# 808| r0_26(glval) = VariableAddress[m] : -# 808| r0_27(glval) = ConvertToBase[Middle : Base] : r0_26 -# 808| r0_28(Base &) = Call : func:r0_25, this:r0_24, 0:r0_27 -# 808| mu0_29(unknown) = ^CallSideEffect : ~mu0_2 -# 808| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_24, ~mu0_2 -# 808| v0_31(void) = ^IndirectReadSideEffect[0] : &:r0_27, ~mu0_2 -# 808| mu0_32(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_24 -# 808| mu0_33(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_27 -# 809| r0_34(glval) = VariableAddress[b] : -# 809| r0_35(glval) = FunctionAddress[operator=] : -# 809| r0_36(glval) = FunctionAddress[Base] : -# 809| r0_37(glval) = VariableAddress[m] : -# 809| r0_38(glval) = ConvertToBase[Middle : Base] : r0_37 -# 809| v0_39(void) = Call : func:r0_36, 0:r0_38 -# 809| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 -# 809| v0_41(void) = ^IndirectReadSideEffect[0] : &:r0_38, ~mu0_2 -# 809| mu0_42(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_38 -# 809| r0_43(glval) = Convert : v0_39 -# 809| r0_44(Base &) = Call : func:r0_35, this:r0_34, 0:r0_43 -# 809| mu0_45(unknown) = ^CallSideEffect : ~mu0_2 -# 809| v0_46(void) = ^IndirectReadSideEffect[-1] : &:r0_34, ~mu0_2 -# 809| v0_47(void) = ^IndirectReadSideEffect[0] : &:r0_43, ~mu0_2 -# 809| mu0_48(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_34 -# 809| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_43 -# 810| r0_50(glval) = VariableAddress[b] : -# 810| r0_51(glval) = FunctionAddress[operator=] : -# 810| r0_52(glval) = FunctionAddress[Base] : -# 810| r0_53(glval) = VariableAddress[m] : -# 810| r0_54(glval) = ConvertToBase[Middle : Base] : r0_53 -# 810| v0_55(void) = Call : func:r0_52, 0:r0_54 -# 810| mu0_56(unknown) = ^CallSideEffect : ~mu0_2 -# 810| v0_57(void) = ^IndirectReadSideEffect[0] : &:r0_54, ~mu0_2 -# 810| mu0_58(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_54 -# 810| r0_59(glval) = Convert : v0_55 -# 810| r0_60(Base &) = Call : func:r0_51, this:r0_50, 0:r0_59 -# 810| mu0_61(unknown) = ^CallSideEffect : ~mu0_2 -# 810| v0_62(void) = ^IndirectReadSideEffect[-1] : &:r0_50, ~mu0_2 -# 810| v0_63(void) = ^IndirectReadSideEffect[0] : &:r0_59, ~mu0_2 -# 810| mu0_64(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_50 -# 810| mu0_65(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_59 -# 811| r0_66(glval) = VariableAddress[pm] : -# 811| r0_67(Middle *) = Load : &:r0_66, ~mu0_2 -# 811| r0_68(Base *) = ConvertToBase[Middle : Base] : r0_67 -# 811| r0_69(glval) = VariableAddress[pb] : -# 811| mu0_70(Base *) = Store : &:r0_69, r0_68 -# 812| r0_71(glval) = VariableAddress[pm] : -# 812| r0_72(Middle *) = Load : &:r0_71, ~mu0_2 -# 812| r0_73(Base *) = ConvertToBase[Middle : Base] : r0_72 -# 812| r0_74(glval) = VariableAddress[pb] : -# 812| mu0_75(Base *) = Store : &:r0_74, r0_73 -# 813| r0_76(glval) = VariableAddress[pm] : -# 813| r0_77(Middle *) = Load : &:r0_76, ~mu0_2 -# 813| r0_78(Base *) = ConvertToBase[Middle : Base] : r0_77 -# 813| r0_79(glval) = VariableAddress[pb] : -# 813| mu0_80(Base *) = Store : &:r0_79, r0_78 -# 814| r0_81(glval) = VariableAddress[pm] : -# 814| r0_82(Middle *) = Load : &:r0_81, ~mu0_2 -# 814| r0_83(Base *) = Convert : r0_82 -# 814| r0_84(glval) = VariableAddress[pb] : -# 814| mu0_85(Base *) = Store : &:r0_84, r0_83 -# 816| r0_86(glval) = VariableAddress[m] : -# 816| r0_87(glval) = FunctionAddress[operator=] : -# 816| r0_88(glval) = VariableAddress[b] : -# 816| r0_89(glval) = ConvertToDerived[Middle : Base] : r0_88 -# 816| r0_90(glval) = Convert : r0_89 -# 816| r0_91(Middle &) = Call : func:r0_87, this:r0_86, 0:r0_90 -# 816| mu0_92(unknown) = ^CallSideEffect : ~mu0_2 -# 816| v0_93(void) = ^IndirectReadSideEffect[-1] : &:r0_86, ~mu0_2 -# 816| v0_94(void) = ^IndirectReadSideEffect[0] : &:r0_90, ~mu0_2 -# 816| mu0_95(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_86 -# 816| mu0_96(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_90 -# 817| r0_97(glval) = VariableAddress[m] : -# 817| r0_98(glval) = FunctionAddress[operator=] : -# 817| r0_99(glval) = VariableAddress[b] : -# 817| r0_100(glval) = ConvertToDerived[Middle : Base] : r0_99 -# 817| r0_101(glval) = Convert : r0_100 -# 817| r0_102(Middle &) = Call : func:r0_98, this:r0_97, 0:r0_101 -# 817| mu0_103(unknown) = ^CallSideEffect : ~mu0_2 -# 817| v0_104(void) = ^IndirectReadSideEffect[-1] : &:r0_97, ~mu0_2 -# 817| v0_105(void) = ^IndirectReadSideEffect[0] : &:r0_101, ~mu0_2 -# 817| mu0_106(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_97 -# 817| mu0_107(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_101 -# 818| r0_108(glval) = VariableAddress[pb] : -# 818| r0_109(Base *) = Load : &:r0_108, ~mu0_2 -# 818| r0_110(Middle *) = ConvertToDerived[Middle : Base] : r0_109 -# 818| r0_111(glval) = VariableAddress[pm] : -# 818| mu0_112(Middle *) = Store : &:r0_111, r0_110 -# 819| r0_113(glval) = VariableAddress[pb] : -# 819| r0_114(Base *) = Load : &:r0_113, ~mu0_2 -# 819| r0_115(Middle *) = ConvertToDerived[Middle : Base] : r0_114 -# 819| r0_116(glval) = VariableAddress[pm] : -# 819| mu0_117(Middle *) = Store : &:r0_116, r0_115 -# 820| r0_118(glval) = VariableAddress[pb] : -# 820| r0_119(Base *) = Load : &:r0_118, ~mu0_2 -# 820| r0_120(Middle *) = Convert : r0_119 -# 820| r0_121(glval) = VariableAddress[pm] : -# 820| mu0_122(Middle *) = Store : &:r0_121, r0_120 -# 822| r0_123(glval) = VariableAddress[b] : -# 822| r0_124(glval) = FunctionAddress[operator=] : -# 822| r0_125(glval) = VariableAddress[d] : -# 822| r0_126(glval) = ConvertToBase[Derived : Middle] : r0_125 -# 822| r0_127(glval) = ConvertToBase[Middle : Base] : r0_126 -# 822| r0_128(Base &) = Call : func:r0_124, this:r0_123, 0:r0_127 -# 822| mu0_129(unknown) = ^CallSideEffect : ~mu0_2 -# 822| v0_130(void) = ^IndirectReadSideEffect[-1] : &:r0_123, ~mu0_2 -# 822| v0_131(void) = ^IndirectReadSideEffect[0] : &:r0_127, ~mu0_2 -# 822| mu0_132(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_123 -# 822| mu0_133(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_127 -# 823| r0_134(glval) = VariableAddress[b] : -# 823| r0_135(glval) = FunctionAddress[operator=] : -# 823| r0_136(glval) = FunctionAddress[Base] : -# 823| r0_137(glval) = VariableAddress[d] : -# 823| r0_138(glval) = ConvertToBase[Derived : Middle] : r0_137 -# 823| r0_139(glval) = ConvertToBase[Middle : Base] : r0_138 -# 823| v0_140(void) = Call : func:r0_136, 0:r0_139 -# 823| mu0_141(unknown) = ^CallSideEffect : ~mu0_2 -# 823| v0_142(void) = ^IndirectReadSideEffect[0] : &:r0_139, ~mu0_2 -# 823| mu0_143(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_139 -# 823| r0_144(glval) = Convert : v0_140 -# 823| r0_145(Base &) = Call : func:r0_135, this:r0_134, 0:r0_144 +# 800| mu0_7(Base) = ^IndirectMustWriteSideEffect : &:r0_3 +# 801| r0_8(glval) = VariableAddress[m] : +# 801| r0_9(glval) = FunctionAddress[Middle] : +# 801| v0_10(void) = Call : func:r0_9, this:r0_8 +# 801| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 +# 801| mu0_12(Middle) = ^IndirectMustWriteSideEffect : &:r0_8 +# 802| r0_13(glval) = VariableAddress[d] : +# 802| r0_14(glval) = FunctionAddress[Derived] : +# 802| v0_15(void) = Call : func:r0_14, this:r0_13 +# 802| mu0_16(unknown) = ^CallSideEffect : ~mu0_2 +# 802| mu0_17(Derived) = ^IndirectMustWriteSideEffect : &:r0_13 +# 804| r0_18(glval) = VariableAddress[pb] : +# 804| r0_19(glval) = VariableAddress[b] : +# 804| mu0_20(Base *) = Store : &:r0_18, r0_19 +# 805| r0_21(glval) = VariableAddress[pm] : +# 805| r0_22(glval) = VariableAddress[m] : +# 805| mu0_23(Middle *) = Store : &:r0_21, r0_22 +# 806| r0_24(glval) = VariableAddress[pd] : +# 806| r0_25(glval) = VariableAddress[d] : +# 806| mu0_26(Derived *) = Store : &:r0_24, r0_25 +# 808| r0_27(glval) = VariableAddress[b] : +# 808| r0_28(glval) = FunctionAddress[operator=] : +# 808| r0_29(glval) = VariableAddress[m] : +# 808| r0_30(glval) = ConvertToBase[Middle : Base] : r0_29 +# 808| r0_31(Base &) = Call : func:r0_28, this:r0_27, 0:r0_30 +# 808| mu0_32(unknown) = ^CallSideEffect : ~mu0_2 +# 808| v0_33(void) = ^IndirectReadSideEffect[-1] : &:r0_27, ~mu0_2 +# 808| v0_34(void) = ^IndirectReadSideEffect[0] : &:r0_30, ~mu0_2 +# 808| mu0_35(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_27 +# 808| mu0_36(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_30 +# 809| r0_37(glval) = VariableAddress[b] : +# 809| r0_38(glval) = FunctionAddress[operator=] : +# 809| r0_39(glval) = FunctionAddress[Base] : +# 809| r0_40(glval) = VariableAddress[m] : +# 809| r0_41(glval) = ConvertToBase[Middle : Base] : r0_40 +# 809| v0_42(void) = Call : func:r0_39, 0:r0_41 +# 809| mu0_43(unknown) = ^CallSideEffect : ~mu0_2 +# 809| mu0_44(Base) = ^IndirectMustWriteSideEffect : +# 809| v0_45(void) = ^IndirectReadSideEffect[0] : &:r0_41, ~mu0_2 +# 809| mu0_46(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_41 +# 809| r0_47(glval) = Convert : v0_42 +# 809| r0_48(Base &) = Call : func:r0_38, this:r0_37, 0:r0_47 +# 809| mu0_49(unknown) = ^CallSideEffect : ~mu0_2 +# 809| v0_50(void) = ^IndirectReadSideEffect[-1] : &:r0_37, ~mu0_2 +# 809| v0_51(void) = ^IndirectReadSideEffect[0] : &:r0_47, ~mu0_2 +# 809| mu0_52(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_37 +# 809| mu0_53(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_47 +# 810| r0_54(glval) = VariableAddress[b] : +# 810| r0_55(glval) = FunctionAddress[operator=] : +# 810| r0_56(glval) = FunctionAddress[Base] : +# 810| r0_57(glval) = VariableAddress[m] : +# 810| r0_58(glval) = ConvertToBase[Middle : Base] : r0_57 +# 810| v0_59(void) = Call : func:r0_56, 0:r0_58 +# 810| mu0_60(unknown) = ^CallSideEffect : ~mu0_2 +# 810| mu0_61(Base) = ^IndirectMustWriteSideEffect : +# 810| v0_62(void) = ^IndirectReadSideEffect[0] : &:r0_58, ~mu0_2 +# 810| mu0_63(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_58 +# 810| r0_64(glval) = Convert : v0_59 +# 810| r0_65(Base &) = Call : func:r0_55, this:r0_54, 0:r0_64 +# 810| mu0_66(unknown) = ^CallSideEffect : ~mu0_2 +# 810| v0_67(void) = ^IndirectReadSideEffect[-1] : &:r0_54, ~mu0_2 +# 810| v0_68(void) = ^IndirectReadSideEffect[0] : &:r0_64, ~mu0_2 +# 810| mu0_69(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_54 +# 810| mu0_70(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_64 +# 811| r0_71(glval) = VariableAddress[pm] : +# 811| r0_72(Middle *) = Load : &:r0_71, ~mu0_2 +# 811| r0_73(Base *) = ConvertToBase[Middle : Base] : r0_72 +# 811| r0_74(glval) = VariableAddress[pb] : +# 811| mu0_75(Base *) = Store : &:r0_74, r0_73 +# 812| r0_76(glval) = VariableAddress[pm] : +# 812| r0_77(Middle *) = Load : &:r0_76, ~mu0_2 +# 812| r0_78(Base *) = ConvertToBase[Middle : Base] : r0_77 +# 812| r0_79(glval) = VariableAddress[pb] : +# 812| mu0_80(Base *) = Store : &:r0_79, r0_78 +# 813| r0_81(glval) = VariableAddress[pm] : +# 813| r0_82(Middle *) = Load : &:r0_81, ~mu0_2 +# 813| r0_83(Base *) = ConvertToBase[Middle : Base] : r0_82 +# 813| r0_84(glval) = VariableAddress[pb] : +# 813| mu0_85(Base *) = Store : &:r0_84, r0_83 +# 814| r0_86(glval) = VariableAddress[pm] : +# 814| r0_87(Middle *) = Load : &:r0_86, ~mu0_2 +# 814| r0_88(Base *) = Convert : r0_87 +# 814| r0_89(glval) = VariableAddress[pb] : +# 814| mu0_90(Base *) = Store : &:r0_89, r0_88 +# 816| r0_91(glval) = VariableAddress[m] : +# 816| r0_92(glval) = FunctionAddress[operator=] : +# 816| r0_93(glval) = VariableAddress[b] : +# 816| r0_94(glval) = ConvertToDerived[Middle : Base] : r0_93 +# 816| r0_95(glval) = Convert : r0_94 +# 816| r0_96(Middle &) = Call : func:r0_92, this:r0_91, 0:r0_95 +# 816| mu0_97(unknown) = ^CallSideEffect : ~mu0_2 +# 816| v0_98(void) = ^IndirectReadSideEffect[-1] : &:r0_91, ~mu0_2 +# 816| v0_99(void) = ^IndirectReadSideEffect[0] : &:r0_95, ~mu0_2 +# 816| mu0_100(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_91 +# 816| mu0_101(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_95 +# 817| r0_102(glval) = VariableAddress[m] : +# 817| r0_103(glval) = FunctionAddress[operator=] : +# 817| r0_104(glval) = VariableAddress[b] : +# 817| r0_105(glval) = ConvertToDerived[Middle : Base] : r0_104 +# 817| r0_106(glval) = Convert : r0_105 +# 817| r0_107(Middle &) = Call : func:r0_103, this:r0_102, 0:r0_106 +# 817| mu0_108(unknown) = ^CallSideEffect : ~mu0_2 +# 817| v0_109(void) = ^IndirectReadSideEffect[-1] : &:r0_102, ~mu0_2 +# 817| v0_110(void) = ^IndirectReadSideEffect[0] : &:r0_106, ~mu0_2 +# 817| mu0_111(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_102 +# 817| mu0_112(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_106 +# 818| r0_113(glval) = VariableAddress[pb] : +# 818| r0_114(Base *) = Load : &:r0_113, ~mu0_2 +# 818| r0_115(Middle *) = ConvertToDerived[Middle : Base] : r0_114 +# 818| r0_116(glval) = VariableAddress[pm] : +# 818| mu0_117(Middle *) = Store : &:r0_116, r0_115 +# 819| r0_118(glval) = VariableAddress[pb] : +# 819| r0_119(Base *) = Load : &:r0_118, ~mu0_2 +# 819| r0_120(Middle *) = ConvertToDerived[Middle : Base] : r0_119 +# 819| r0_121(glval) = VariableAddress[pm] : +# 819| mu0_122(Middle *) = Store : &:r0_121, r0_120 +# 820| r0_123(glval) = VariableAddress[pb] : +# 820| r0_124(Base *) = Load : &:r0_123, ~mu0_2 +# 820| r0_125(Middle *) = Convert : r0_124 +# 820| r0_126(glval) = VariableAddress[pm] : +# 820| mu0_127(Middle *) = Store : &:r0_126, r0_125 +# 822| r0_128(glval) = VariableAddress[b] : +# 822| r0_129(glval) = FunctionAddress[operator=] : +# 822| r0_130(glval) = VariableAddress[d] : +# 822| r0_131(glval) = ConvertToBase[Derived : Middle] : r0_130 +# 822| r0_132(glval) = ConvertToBase[Middle : Base] : r0_131 +# 822| r0_133(Base &) = Call : func:r0_129, this:r0_128, 0:r0_132 +# 822| mu0_134(unknown) = ^CallSideEffect : ~mu0_2 +# 822| v0_135(void) = ^IndirectReadSideEffect[-1] : &:r0_128, ~mu0_2 +# 822| v0_136(void) = ^IndirectReadSideEffect[0] : &:r0_132, ~mu0_2 +# 822| mu0_137(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_128 +# 822| mu0_138(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_132 +# 823| r0_139(glval) = VariableAddress[b] : +# 823| r0_140(glval) = FunctionAddress[operator=] : +# 823| r0_141(glval) = FunctionAddress[Base] : +# 823| r0_142(glval) = VariableAddress[d] : +# 823| r0_143(glval) = ConvertToBase[Derived : Middle] : r0_142 +# 823| r0_144(glval) = ConvertToBase[Middle : Base] : r0_143 +# 823| v0_145(void) = Call : func:r0_141, 0:r0_144 # 823| mu0_146(unknown) = ^CallSideEffect : ~mu0_2 -# 823| v0_147(void) = ^IndirectReadSideEffect[-1] : &:r0_134, ~mu0_2 +# 823| mu0_147(Base) = ^IndirectMustWriteSideEffect : # 823| v0_148(void) = ^IndirectReadSideEffect[0] : &:r0_144, ~mu0_2 -# 823| mu0_149(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_134 -# 823| mu0_150(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_144 -# 824| r0_151(glval) = VariableAddress[b] : -# 824| r0_152(glval) = FunctionAddress[operator=] : -# 824| r0_153(glval) = FunctionAddress[Base] : -# 824| r0_154(glval) = VariableAddress[d] : -# 824| r0_155(glval) = ConvertToBase[Derived : Middle] : r0_154 -# 824| r0_156(glval) = ConvertToBase[Middle : Base] : r0_155 -# 824| v0_157(void) = Call : func:r0_153, 0:r0_156 -# 824| mu0_158(unknown) = ^CallSideEffect : ~mu0_2 -# 824| v0_159(void) = ^IndirectReadSideEffect[0] : &:r0_156, ~mu0_2 -# 824| mu0_160(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_156 -# 824| r0_161(glval) = Convert : v0_157 -# 824| r0_162(Base &) = Call : func:r0_152, this:r0_151, 0:r0_161 -# 824| mu0_163(unknown) = ^CallSideEffect : ~mu0_2 -# 824| v0_164(void) = ^IndirectReadSideEffect[-1] : &:r0_151, ~mu0_2 -# 824| v0_165(void) = ^IndirectReadSideEffect[0] : &:r0_161, ~mu0_2 -# 824| mu0_166(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_151 -# 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_161 -# 825| r0_168(glval) = VariableAddress[pd] : -# 825| r0_169(Derived *) = Load : &:r0_168, ~mu0_2 -# 825| r0_170(Middle *) = ConvertToBase[Derived : Middle] : r0_169 -# 825| r0_171(Base *) = ConvertToBase[Middle : Base] : r0_170 -# 825| r0_172(glval) = VariableAddress[pb] : -# 825| mu0_173(Base *) = Store : &:r0_172, r0_171 -# 826| r0_174(glval) = VariableAddress[pd] : -# 826| r0_175(Derived *) = Load : &:r0_174, ~mu0_2 -# 826| r0_176(Middle *) = ConvertToBase[Derived : Middle] : r0_175 -# 826| r0_177(Base *) = ConvertToBase[Middle : Base] : r0_176 -# 826| r0_178(glval) = VariableAddress[pb] : -# 826| mu0_179(Base *) = Store : &:r0_178, r0_177 -# 827| r0_180(glval) = VariableAddress[pd] : -# 827| r0_181(Derived *) = Load : &:r0_180, ~mu0_2 -# 827| r0_182(Middle *) = ConvertToBase[Derived : Middle] : r0_181 -# 827| r0_183(Base *) = ConvertToBase[Middle : Base] : r0_182 -# 827| r0_184(glval) = VariableAddress[pb] : -# 827| mu0_185(Base *) = Store : &:r0_184, r0_183 -# 828| r0_186(glval) = VariableAddress[pd] : -# 828| r0_187(Derived *) = Load : &:r0_186, ~mu0_2 -# 828| r0_188(Base *) = Convert : r0_187 -# 828| r0_189(glval) = VariableAddress[pb] : -# 828| mu0_190(Base *) = Store : &:r0_189, r0_188 -# 830| r0_191(glval) = VariableAddress[d] : -# 830| r0_192(glval) = FunctionAddress[operator=] : -# 830| r0_193(glval) = VariableAddress[b] : -# 830| r0_194(glval) = ConvertToDerived[Middle : Base] : r0_193 -# 830| r0_195(glval) = ConvertToDerived[Derived : Middle] : r0_194 -# 830| r0_196(glval) = Convert : r0_195 -# 830| r0_197(Derived &) = Call : func:r0_192, this:r0_191, 0:r0_196 -# 830| mu0_198(unknown) = ^CallSideEffect : ~mu0_2 -# 830| v0_199(void) = ^IndirectReadSideEffect[-1] : &:r0_191, ~mu0_2 -# 830| v0_200(void) = ^IndirectReadSideEffect[0] : &:r0_196, ~mu0_2 -# 830| mu0_201(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_191 -# 830| mu0_202(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_196 -# 831| r0_203(glval) = VariableAddress[d] : -# 831| r0_204(glval) = FunctionAddress[operator=] : -# 831| r0_205(glval) = VariableAddress[b] : -# 831| r0_206(glval) = ConvertToDerived[Middle : Base] : r0_205 -# 831| r0_207(glval) = ConvertToDerived[Derived : Middle] : r0_206 -# 831| r0_208(glval) = Convert : r0_207 -# 831| r0_209(Derived &) = Call : func:r0_204, this:r0_203, 0:r0_208 -# 831| mu0_210(unknown) = ^CallSideEffect : ~mu0_2 -# 831| v0_211(void) = ^IndirectReadSideEffect[-1] : &:r0_203, ~mu0_2 -# 831| v0_212(void) = ^IndirectReadSideEffect[0] : &:r0_208, ~mu0_2 -# 831| mu0_213(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_203 -# 831| mu0_214(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_208 -# 832| r0_215(glval) = VariableAddress[pb] : -# 832| r0_216(Base *) = Load : &:r0_215, ~mu0_2 -# 832| r0_217(Middle *) = ConvertToDerived[Middle : Base] : r0_216 -# 832| r0_218(Derived *) = ConvertToDerived[Derived : Middle] : r0_217 -# 832| r0_219(glval) = VariableAddress[pd] : -# 832| mu0_220(Derived *) = Store : &:r0_219, r0_218 -# 833| r0_221(glval) = VariableAddress[pb] : -# 833| r0_222(Base *) = Load : &:r0_221, ~mu0_2 -# 833| r0_223(Middle *) = ConvertToDerived[Middle : Base] : r0_222 -# 833| r0_224(Derived *) = ConvertToDerived[Derived : Middle] : r0_223 -# 833| r0_225(glval) = VariableAddress[pd] : -# 833| mu0_226(Derived *) = Store : &:r0_225, r0_224 -# 834| r0_227(glval) = VariableAddress[pb] : -# 834| r0_228(Base *) = Load : &:r0_227, ~mu0_2 -# 834| r0_229(Derived *) = Convert : r0_228 -# 834| r0_230(glval) = VariableAddress[pd] : -# 834| mu0_231(Derived *) = Store : &:r0_230, r0_229 -# 836| r0_232(glval) = VariableAddress[pmv] : -# 836| r0_233(MiddleVB1 *) = Constant[0] : -# 836| mu0_234(MiddleVB1 *) = Store : &:r0_232, r0_233 -# 837| r0_235(glval) = VariableAddress[pdv] : -# 837| r0_236(DerivedVB *) = Constant[0] : -# 837| mu0_237(DerivedVB *) = Store : &:r0_235, r0_236 -# 838| r0_238(glval) = VariableAddress[pmv] : -# 838| r0_239(MiddleVB1 *) = Load : &:r0_238, ~mu0_2 -# 838| r0_240(Base *) = ConvertToVirtualBase[MiddleVB1 : Base] : r0_239 -# 838| r0_241(glval) = VariableAddress[pb] : -# 838| mu0_242(Base *) = Store : &:r0_241, r0_240 -# 839| r0_243(glval) = VariableAddress[pdv] : -# 839| r0_244(DerivedVB *) = Load : &:r0_243, ~mu0_2 -# 839| r0_245(Base *) = ConvertToVirtualBase[DerivedVB : Base] : r0_244 -# 839| r0_246(glval) = VariableAddress[pb] : -# 839| mu0_247(Base *) = Store : &:r0_246, r0_245 -# 840| v0_248(void) = NoOp : -# 799| v0_249(void) = ReturnVoid : -# 799| v0_250(void) = UnmodeledUse : mu* -# 799| v0_251(void) = ExitFunction : +# 823| mu0_149(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_144 +# 823| r0_150(glval) = Convert : v0_145 +# 823| r0_151(Base &) = Call : func:r0_140, this:r0_139, 0:r0_150 +# 823| mu0_152(unknown) = ^CallSideEffect : ~mu0_2 +# 823| v0_153(void) = ^IndirectReadSideEffect[-1] : &:r0_139, ~mu0_2 +# 823| v0_154(void) = ^IndirectReadSideEffect[0] : &:r0_150, ~mu0_2 +# 823| mu0_155(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_139 +# 823| mu0_156(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_150 +# 824| r0_157(glval) = VariableAddress[b] : +# 824| r0_158(glval) = FunctionAddress[operator=] : +# 824| r0_159(glval) = FunctionAddress[Base] : +# 824| r0_160(glval) = VariableAddress[d] : +# 824| r0_161(glval) = ConvertToBase[Derived : Middle] : r0_160 +# 824| r0_162(glval) = ConvertToBase[Middle : Base] : r0_161 +# 824| v0_163(void) = Call : func:r0_159, 0:r0_162 +# 824| mu0_164(unknown) = ^CallSideEffect : ~mu0_2 +# 824| mu0_165(Base) = ^IndirectMustWriteSideEffect : +# 824| v0_166(void) = ^IndirectReadSideEffect[0] : &:r0_162, ~mu0_2 +# 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_162 +# 824| r0_168(glval) = Convert : v0_163 +# 824| r0_169(Base &) = Call : func:r0_158, this:r0_157, 0:r0_168 +# 824| mu0_170(unknown) = ^CallSideEffect : ~mu0_2 +# 824| v0_171(void) = ^IndirectReadSideEffect[-1] : &:r0_157, ~mu0_2 +# 824| v0_172(void) = ^IndirectReadSideEffect[0] : &:r0_168, ~mu0_2 +# 824| mu0_173(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_157 +# 824| mu0_174(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_168 +# 825| r0_175(glval) = VariableAddress[pd] : +# 825| r0_176(Derived *) = Load : &:r0_175, ~mu0_2 +# 825| r0_177(Middle *) = ConvertToBase[Derived : Middle] : r0_176 +# 825| r0_178(Base *) = ConvertToBase[Middle : Base] : r0_177 +# 825| r0_179(glval) = VariableAddress[pb] : +# 825| mu0_180(Base *) = Store : &:r0_179, r0_178 +# 826| r0_181(glval) = VariableAddress[pd] : +# 826| r0_182(Derived *) = Load : &:r0_181, ~mu0_2 +# 826| r0_183(Middle *) = ConvertToBase[Derived : Middle] : r0_182 +# 826| r0_184(Base *) = ConvertToBase[Middle : Base] : r0_183 +# 826| r0_185(glval) = VariableAddress[pb] : +# 826| mu0_186(Base *) = Store : &:r0_185, r0_184 +# 827| r0_187(glval) = VariableAddress[pd] : +# 827| r0_188(Derived *) = Load : &:r0_187, ~mu0_2 +# 827| r0_189(Middle *) = ConvertToBase[Derived : Middle] : r0_188 +# 827| r0_190(Base *) = ConvertToBase[Middle : Base] : r0_189 +# 827| r0_191(glval) = VariableAddress[pb] : +# 827| mu0_192(Base *) = Store : &:r0_191, r0_190 +# 828| r0_193(glval) = VariableAddress[pd] : +# 828| r0_194(Derived *) = Load : &:r0_193, ~mu0_2 +# 828| r0_195(Base *) = Convert : r0_194 +# 828| r0_196(glval) = VariableAddress[pb] : +# 828| mu0_197(Base *) = Store : &:r0_196, r0_195 +# 830| r0_198(glval) = VariableAddress[d] : +# 830| r0_199(glval) = FunctionAddress[operator=] : +# 830| r0_200(glval) = VariableAddress[b] : +# 830| r0_201(glval) = ConvertToDerived[Middle : Base] : r0_200 +# 830| r0_202(glval) = ConvertToDerived[Derived : Middle] : r0_201 +# 830| r0_203(glval) = Convert : r0_202 +# 830| r0_204(Derived &) = Call : func:r0_199, this:r0_198, 0:r0_203 +# 830| mu0_205(unknown) = ^CallSideEffect : ~mu0_2 +# 830| v0_206(void) = ^IndirectReadSideEffect[-1] : &:r0_198, ~mu0_2 +# 830| v0_207(void) = ^IndirectReadSideEffect[0] : &:r0_203, ~mu0_2 +# 830| mu0_208(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_198 +# 830| mu0_209(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_203 +# 831| r0_210(glval) = VariableAddress[d] : +# 831| r0_211(glval) = FunctionAddress[operator=] : +# 831| r0_212(glval) = VariableAddress[b] : +# 831| r0_213(glval) = ConvertToDerived[Middle : Base] : r0_212 +# 831| r0_214(glval) = ConvertToDerived[Derived : Middle] : r0_213 +# 831| r0_215(glval) = Convert : r0_214 +# 831| r0_216(Derived &) = Call : func:r0_211, this:r0_210, 0:r0_215 +# 831| mu0_217(unknown) = ^CallSideEffect : ~mu0_2 +# 831| v0_218(void) = ^IndirectReadSideEffect[-1] : &:r0_210, ~mu0_2 +# 831| v0_219(void) = ^IndirectReadSideEffect[0] : &:r0_215, ~mu0_2 +# 831| mu0_220(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_210 +# 831| mu0_221(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_215 +# 832| r0_222(glval) = VariableAddress[pb] : +# 832| r0_223(Base *) = Load : &:r0_222, ~mu0_2 +# 832| r0_224(Middle *) = ConvertToDerived[Middle : Base] : r0_223 +# 832| r0_225(Derived *) = ConvertToDerived[Derived : Middle] : r0_224 +# 832| r0_226(glval) = VariableAddress[pd] : +# 832| mu0_227(Derived *) = Store : &:r0_226, r0_225 +# 833| r0_228(glval) = VariableAddress[pb] : +# 833| r0_229(Base *) = Load : &:r0_228, ~mu0_2 +# 833| r0_230(Middle *) = ConvertToDerived[Middle : Base] : r0_229 +# 833| r0_231(Derived *) = ConvertToDerived[Derived : Middle] : r0_230 +# 833| r0_232(glval) = VariableAddress[pd] : +# 833| mu0_233(Derived *) = Store : &:r0_232, r0_231 +# 834| r0_234(glval) = VariableAddress[pb] : +# 834| r0_235(Base *) = Load : &:r0_234, ~mu0_2 +# 834| r0_236(Derived *) = Convert : r0_235 +# 834| r0_237(glval) = VariableAddress[pd] : +# 834| mu0_238(Derived *) = Store : &:r0_237, r0_236 +# 836| r0_239(glval) = VariableAddress[pmv] : +# 836| r0_240(MiddleVB1 *) = Constant[0] : +# 836| mu0_241(MiddleVB1 *) = Store : &:r0_239, r0_240 +# 837| r0_242(glval) = VariableAddress[pdv] : +# 837| r0_243(DerivedVB *) = Constant[0] : +# 837| mu0_244(DerivedVB *) = Store : &:r0_242, r0_243 +# 838| r0_245(glval) = VariableAddress[pmv] : +# 838| r0_246(MiddleVB1 *) = Load : &:r0_245, ~mu0_2 +# 838| r0_247(Base *) = ConvertToVirtualBase[MiddleVB1 : Base] : r0_246 +# 838| r0_248(glval) = VariableAddress[pb] : +# 838| mu0_249(Base *) = Store : &:r0_248, r0_247 +# 839| r0_250(glval) = VariableAddress[pdv] : +# 839| r0_251(DerivedVB *) = Load : &:r0_250, ~mu0_2 +# 839| r0_252(Base *) = ConvertToVirtualBase[DerivedVB : Base] : r0_251 +# 839| r0_253(glval) = VariableAddress[pb] : +# 839| mu0_254(Base *) = Store : &:r0_253, r0_252 +# 840| v0_255(void) = NoOp : +# 799| v0_256(void) = ReturnVoid : +# 799| v0_257(void) = UnmodeledUse : mu* +# 799| v0_258(void) = ExitFunction : # 842| void PolymorphicBase::PolymorphicBase() # 842| Block 0 @@ -3889,10 +3917,11 @@ ir.cpp: # 846| r0_5(glval) = FunctionAddress[PolymorphicBase] : # 846| v0_6(void) = Call : func:r0_5, this:r0_4 # 846| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 846| v0_8(void) = NoOp : -# 846| v0_9(void) = ReturnVoid : -# 846| v0_10(void) = UnmodeledUse : mu* -# 846| v0_11(void) = ExitFunction : +# 846| mu0_8(PolymorphicBase) = ^IndirectMustWriteSideEffect : &:r0_4 +# 846| v0_9(void) = NoOp : +# 846| v0_10(void) = ReturnVoid : +# 846| v0_11(void) = UnmodeledUse : mu* +# 846| v0_12(void) = ExitFunction : # 846| void PolymorphicDerived::~PolymorphicDerived() # 846| Block 0 @@ -3918,48 +3947,50 @@ ir.cpp: #-----| r0_4(glval) = FunctionAddress[PolymorphicBase] : #-----| v0_5(void) = Call : func:r0_4, this:r0_3 #-----| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 851| r0_7(glval) = VariableAddress[d] : -# 851| r0_8(glval) = FunctionAddress[PolymorphicDerived] : -# 851| v0_9(void) = Call : func:r0_8, this:r0_7 -# 851| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 853| r0_11(glval) = VariableAddress[pb] : -# 853| r0_12(glval) = VariableAddress[b] : -# 853| mu0_13(PolymorphicBase *) = Store : &:r0_11, r0_12 -# 854| r0_14(glval) = VariableAddress[pd] : -# 854| r0_15(glval) = VariableAddress[d] : -# 854| mu0_16(PolymorphicDerived *) = Store : &:r0_14, r0_15 -# 857| r0_17(glval) = VariableAddress[pd] : -# 857| r0_18(PolymorphicDerived *) = Load : &:r0_17, ~mu0_2 -# 857| r0_19(PolymorphicBase *) = CheckedConvertOrNull : r0_18 -# 857| r0_20(glval) = VariableAddress[pb] : -# 857| mu0_21(PolymorphicBase *) = Store : &:r0_20, r0_19 -# 858| r0_22(glval) = VariableAddress[rb] : -# 858| r0_23(glval) = VariableAddress[d] : -# 858| r0_24(glval) = CheckedConvertOrThrow : r0_23 -# 858| mu0_25(PolymorphicBase &) = Store : &:r0_22, r0_24 -# 860| r0_26(glval) = VariableAddress[pb] : -# 860| r0_27(PolymorphicBase *) = Load : &:r0_26, ~mu0_2 -# 860| r0_28(PolymorphicDerived *) = CheckedConvertOrNull : r0_27 -# 860| r0_29(glval) = VariableAddress[pd] : -# 860| mu0_30(PolymorphicDerived *) = Store : &:r0_29, r0_28 -# 861| r0_31(glval) = VariableAddress[rd] : -# 861| r0_32(glval) = VariableAddress[b] : -# 861| r0_33(glval) = CheckedConvertOrThrow : r0_32 -# 861| mu0_34(PolymorphicDerived &) = Store : &:r0_31, r0_33 -# 863| r0_35(glval) = VariableAddress[pv] : -# 863| r0_36(glval) = VariableAddress[pb] : -# 863| r0_37(PolymorphicBase *) = Load : &:r0_36, ~mu0_2 -# 863| r0_38(void *) = DynamicCastToVoid : r0_37 -# 863| mu0_39(void *) = Store : &:r0_35, r0_38 -# 864| r0_40(glval) = VariableAddress[pcv] : -# 864| r0_41(glval) = VariableAddress[pd] : -# 864| r0_42(PolymorphicDerived *) = Load : &:r0_41, ~mu0_2 -# 864| r0_43(void *) = DynamicCastToVoid : r0_42 -# 864| mu0_44(void *) = Store : &:r0_40, r0_43 -# 865| v0_45(void) = NoOp : -# 849| v0_46(void) = ReturnVoid : -# 849| v0_47(void) = UnmodeledUse : mu* -# 849| v0_48(void) = ExitFunction : +#-----| mu0_7(PolymorphicBase) = ^IndirectMustWriteSideEffect : &:r0_3 +# 851| r0_8(glval) = VariableAddress[d] : +# 851| r0_9(glval) = FunctionAddress[PolymorphicDerived] : +# 851| v0_10(void) = Call : func:r0_9, this:r0_8 +# 851| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 +# 851| mu0_12(PolymorphicDerived) = ^IndirectMustWriteSideEffect : &:r0_8 +# 853| r0_13(glval) = VariableAddress[pb] : +# 853| r0_14(glval) = VariableAddress[b] : +# 853| mu0_15(PolymorphicBase *) = Store : &:r0_13, r0_14 +# 854| r0_16(glval) = VariableAddress[pd] : +# 854| r0_17(glval) = VariableAddress[d] : +# 854| mu0_18(PolymorphicDerived *) = Store : &:r0_16, r0_17 +# 857| r0_19(glval) = VariableAddress[pd] : +# 857| r0_20(PolymorphicDerived *) = Load : &:r0_19, ~mu0_2 +# 857| r0_21(PolymorphicBase *) = CheckedConvertOrNull : r0_20 +# 857| r0_22(glval) = VariableAddress[pb] : +# 857| mu0_23(PolymorphicBase *) = Store : &:r0_22, r0_21 +# 858| r0_24(glval) = VariableAddress[rb] : +# 858| r0_25(glval) = VariableAddress[d] : +# 858| r0_26(glval) = CheckedConvertOrThrow : r0_25 +# 858| mu0_27(PolymorphicBase &) = Store : &:r0_24, r0_26 +# 860| r0_28(glval) = VariableAddress[pb] : +# 860| r0_29(PolymorphicBase *) = Load : &:r0_28, ~mu0_2 +# 860| r0_30(PolymorphicDerived *) = CheckedConvertOrNull : r0_29 +# 860| r0_31(glval) = VariableAddress[pd] : +# 860| mu0_32(PolymorphicDerived *) = Store : &:r0_31, r0_30 +# 861| r0_33(glval) = VariableAddress[rd] : +# 861| r0_34(glval) = VariableAddress[b] : +# 861| r0_35(glval) = CheckedConvertOrThrow : r0_34 +# 861| mu0_36(PolymorphicDerived &) = Store : &:r0_33, r0_35 +# 863| r0_37(glval) = VariableAddress[pv] : +# 863| r0_38(glval) = VariableAddress[pb] : +# 863| r0_39(PolymorphicBase *) = Load : &:r0_38, ~mu0_2 +# 863| r0_40(void *) = DynamicCastToVoid : r0_39 +# 863| mu0_41(void *) = Store : &:r0_37, r0_40 +# 864| r0_42(glval) = VariableAddress[pcv] : +# 864| r0_43(glval) = VariableAddress[pd] : +# 864| r0_44(PolymorphicDerived *) = Load : &:r0_43, ~mu0_2 +# 864| r0_45(void *) = DynamicCastToVoid : r0_44 +# 864| mu0_46(void *) = Store : &:r0_42, r0_45 +# 865| v0_47(void) = NoOp : +# 849| v0_48(void) = ReturnVoid : +# 849| v0_49(void) = UnmodeledUse : mu* +# 849| v0_50(void) = ExitFunction : # 867| void String::String() # 867| Block 0 @@ -3972,12 +4003,13 @@ ir.cpp: # 868| r0_6(char *) = Convert : r0_5 # 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 # 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 868| v0_9(void) = ^IndirectReadSideEffect[0] : &:r0_6, ~mu0_2 -# 868| mu0_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6 -# 869| v0_11(void) = NoOp : -# 867| v0_12(void) = ReturnVoid : -# 867| v0_13(void) = UnmodeledUse : mu* -# 867| v0_14(void) = ExitFunction : +# 868| mu0_9(String) = ^IndirectMustWriteSideEffect : &:r0_3 +# 868| v0_10(void) = ^IndirectReadSideEffect[0] : &:r0_6, ~mu0_2 +# 868| mu0_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6 +# 869| v0_12(void) = NoOp : +# 867| v0_13(void) = ReturnVoid : +# 867| v0_14(void) = UnmodeledUse : mu* +# 867| v0_15(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 @@ -4178,38 +4210,40 @@ ir.cpp: # 944| r0_26(glval) = FunctionAddress[String] : # 944| v0_27(void) = Call : func:r0_26, this:r0_25 # 944| mu0_28(unknown) = ^CallSideEffect : ~mu0_2 -# 945| r0_29(glval) = FunctionAddress[operator new] : -# 945| r0_30(unsigned long) = Constant[8] : -# 945| r0_31(float) = Constant[1.0] : -# 945| r0_32(void *) = Call : func:r0_29, 0:r0_30, 1:r0_31 -# 945| mu0_33(unknown) = ^CallSideEffect : ~mu0_2 -# 945| r0_34(String *) = Convert : r0_32 -# 945| r0_35(glval) = FunctionAddress[String] : -# 945| r0_36(glval) = StringConstant["hello"] : -# 945| r0_37(char *) = Convert : r0_36 -# 945| v0_38(void) = Call : func:r0_35, this:r0_34, 0:r0_37 -# 945| mu0_39(unknown) = ^CallSideEffect : ~mu0_2 -# 945| v0_40(void) = ^IndirectReadSideEffect[0] : &:r0_37, ~mu0_2 -# 945| mu0_41(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_37 -# 946| r0_42(glval) = FunctionAddress[operator new] : -# 946| r0_43(unsigned long) = Constant[256] : -# 946| r0_44(align_val_t) = Constant[128] : -# 946| r0_45(void *) = Call : func:r0_42, 0:r0_43, 1:r0_44 -# 946| mu0_46(unknown) = ^CallSideEffect : ~mu0_2 -# 946| r0_47(Overaligned *) = Convert : r0_45 -# 947| r0_48(glval) = FunctionAddress[operator new] : -# 947| r0_49(unsigned long) = Constant[256] : -# 947| r0_50(align_val_t) = Constant[128] : -# 947| r0_51(float) = Constant[1.0] : -# 947| r0_52(void *) = Call : func:r0_48, 0:r0_49, 1:r0_50, 2:r0_51 -# 947| mu0_53(unknown) = ^CallSideEffect : ~mu0_2 -# 947| r0_54(Overaligned *) = Convert : r0_52 -# 947| r0_55(Overaligned) = Constant[0] : -# 947| mu0_56(Overaligned) = Store : &:r0_54, r0_55 -# 948| v0_57(void) = NoOp : -# 940| v0_58(void) = ReturnVoid : -# 940| v0_59(void) = UnmodeledUse : mu* -# 940| v0_60(void) = ExitFunction : +# 944| mu0_29(String) = ^IndirectMustWriteSideEffect : &:r0_25 +# 945| r0_30(glval) = FunctionAddress[operator new] : +# 945| r0_31(unsigned long) = Constant[8] : +# 945| r0_32(float) = Constant[1.0] : +# 945| r0_33(void *) = Call : func:r0_30, 0:r0_31, 1:r0_32 +# 945| mu0_34(unknown) = ^CallSideEffect : ~mu0_2 +# 945| r0_35(String *) = Convert : r0_33 +# 945| r0_36(glval) = FunctionAddress[String] : +# 945| r0_37(glval) = StringConstant["hello"] : +# 945| r0_38(char *) = Convert : r0_37 +# 945| v0_39(void) = Call : func:r0_36, this:r0_35, 0:r0_38 +# 945| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 +# 945| mu0_41(String) = ^IndirectMustWriteSideEffect : &:r0_35 +# 945| v0_42(void) = ^IndirectReadSideEffect[0] : &:r0_38, ~mu0_2 +# 945| mu0_43(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_38 +# 946| r0_44(glval) = FunctionAddress[operator new] : +# 946| r0_45(unsigned long) = Constant[256] : +# 946| r0_46(align_val_t) = Constant[128] : +# 946| r0_47(void *) = Call : func:r0_44, 0:r0_45, 1:r0_46 +# 946| mu0_48(unknown) = ^CallSideEffect : ~mu0_2 +# 946| r0_49(Overaligned *) = Convert : r0_47 +# 947| r0_50(glval) = FunctionAddress[operator new] : +# 947| r0_51(unsigned long) = Constant[256] : +# 947| r0_52(align_val_t) = Constant[128] : +# 947| r0_53(float) = Constant[1.0] : +# 947| r0_54(void *) = Call : func:r0_50, 0:r0_51, 1:r0_52, 2:r0_53 +# 947| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 +# 947| r0_56(Overaligned *) = Convert : r0_54 +# 947| r0_57(Overaligned) = Constant[0] : +# 947| mu0_58(Overaligned) = Store : &:r0_56, r0_57 +# 948| v0_59(void) = NoOp : +# 940| v0_60(void) = ReturnVoid : +# 940| v0_61(void) = UnmodeledUse : mu* +# 940| v0_62(void) = ExitFunction : # 950| void OperatorNewArray(int) # 950| Block 0 @@ -4687,122 +4721,126 @@ ir.cpp: #-----| r0_38(glval) = FunctionAddress[String] : #-----| v0_39(void) = Call : func:r0_38, this:r0_37 #-----| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| r0_41(glval) = FieldAddress[x] : r0_35 -#-----| r0_42(glval) = VariableAddress[x] : -#-----| r0_43(int) = Load : &:r0_42, ~mu0_2 -#-----| mu0_44(int) = Store : &:r0_41, r0_43 -# 1036| r0_45(decltype([...](...){...})) = Load : &:r0_35, ~mu0_2 -# 1036| v0_46(void) = Call : func:r0_34, this:r0_33, 0:r0_45 -# 1036| mu0_47(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| v0_48(void) = ^IndirectReadSideEffect[0] : &:r0_45, ~mu0_2 -# 1036| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_45 -# 1037| r0_50(glval) = VariableAddress[lambda_val] : -# 1037| r0_51(glval) = Convert : r0_50 -# 1037| r0_52(glval) = FunctionAddress[operator()] : -# 1037| r0_53(float) = Constant[2.0] : -# 1037| r0_54(char) = Call : func:r0_52, this:r0_51, 0:r0_53 -# 1037| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 -# 1037| v0_56(void) = ^IndirectReadSideEffect[-1] : &:r0_51, ~mu0_2 -# 1037| mu0_57(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_51 -# 1038| r0_58(glval) = VariableAddress[lambda_ref_explicit] : -# 1038| r0_59(glval) = VariableAddress[#temp1038:30] : -# 1038| mu0_60(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_59 -# 1038| r0_61(glval) = FieldAddress[s] : r0_59 -# 1038| r0_62(glval) = VariableAddress[s] : -# 1038| r0_63(String &) = Load : &:r0_62, ~mu0_2 -# 1038| mu0_64(String &) = Store : &:r0_61, r0_63 -# 1038| r0_65(decltype([...](...){...})) = Load : &:r0_59, ~mu0_2 -# 1038| mu0_66(decltype([...](...){...})) = Store : &:r0_58, r0_65 -# 1039| r0_67(glval) = VariableAddress[lambda_ref_explicit] : -# 1039| r0_68(glval) = Convert : r0_67 -# 1039| r0_69(glval) = FunctionAddress[operator()] : -# 1039| r0_70(float) = Constant[3.0] : -# 1039| r0_71(char) = Call : func:r0_69, this:r0_68, 0:r0_70 -# 1039| mu0_72(unknown) = ^CallSideEffect : ~mu0_2 -# 1039| v0_73(void) = ^IndirectReadSideEffect[-1] : &:r0_68, ~mu0_2 -# 1039| mu0_74(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_68 -# 1040| r0_75(glval) = VariableAddress[lambda_val_explicit] : -# 1040| r0_76(glval) = FunctionAddress[(constructor)] : -# 1040| r0_77(glval) = VariableAddress[#temp1040:30] : -# 1040| mu0_78(decltype([...](...){...})) = Uninitialized[#temp1040:30] : &:r0_77 -# 1040| r0_79(glval) = FieldAddress[s] : r0_77 -#-----| r0_80(glval) = FunctionAddress[String] : -#-----| v0_81(void) = Call : func:r0_80, this:r0_79 -#-----| mu0_82(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| r0_83(decltype([...](...){...})) = Load : &:r0_77, ~mu0_2 -# 1040| v0_84(void) = Call : func:r0_76, this:r0_75, 0:r0_83 -# 1040| mu0_85(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| v0_86(void) = ^IndirectReadSideEffect[0] : &:r0_83, ~mu0_2 -# 1040| mu0_87(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_83 -# 1041| r0_88(glval) = VariableAddress[lambda_val_explicit] : -# 1041| r0_89(glval) = Convert : r0_88 -# 1041| r0_90(glval) = FunctionAddress[operator()] : -# 1041| r0_91(float) = Constant[4.0] : -# 1041| r0_92(char) = Call : func:r0_90, this:r0_89, 0:r0_91 -# 1041| mu0_93(unknown) = ^CallSideEffect : ~mu0_2 -# 1041| v0_94(void) = ^IndirectReadSideEffect[-1] : &:r0_89, ~mu0_2 -# 1041| mu0_95(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_89 -# 1042| r0_96(glval) = VariableAddress[lambda_mixed_explicit] : -# 1042| r0_97(glval) = VariableAddress[#temp1042:32] : -# 1042| mu0_98(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_97 -# 1042| r0_99(glval) = FieldAddress[s] : r0_97 -# 1042| r0_100(glval) = VariableAddress[s] : -# 1042| r0_101(String &) = Load : &:r0_100, ~mu0_2 -# 1042| mu0_102(String &) = Store : &:r0_99, r0_101 -# 1042| r0_103(glval) = FieldAddress[x] : r0_97 -# 1042| r0_104(glval) = VariableAddress[x] : -# 1042| r0_105(int) = Load : &:r0_104, ~mu0_2 -# 1042| mu0_106(int) = Store : &:r0_103, r0_105 -# 1042| r0_107(decltype([...](...){...})) = Load : &:r0_97, ~mu0_2 -# 1042| mu0_108(decltype([...](...){...})) = Store : &:r0_96, r0_107 -# 1043| r0_109(glval) = VariableAddress[lambda_mixed_explicit] : -# 1043| r0_110(glval) = Convert : r0_109 -# 1043| r0_111(glval) = FunctionAddress[operator()] : -# 1043| r0_112(float) = Constant[5.0] : -# 1043| r0_113(char) = Call : func:r0_111, this:r0_110, 0:r0_112 -# 1043| mu0_114(unknown) = ^CallSideEffect : ~mu0_2 -# 1043| v0_115(void) = ^IndirectReadSideEffect[-1] : &:r0_110, ~mu0_2 -# 1043| mu0_116(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_110 -# 1044| r0_117(glval) = VariableAddress[r] : -# 1044| r0_118(glval) = VariableAddress[x] : -# 1044| r0_119(int) = Load : &:r0_118, ~mu0_2 -# 1044| r0_120(int) = Constant[1] : -# 1044| r0_121(int) = Sub : r0_119, r0_120 -# 1044| mu0_122(int) = Store : &:r0_117, r0_121 -# 1045| r0_123(glval) = VariableAddress[lambda_inits] : -# 1045| r0_124(glval) = VariableAddress[#temp1045:23] : -# 1045| mu0_125(decltype([...](...){...})) = Uninitialized[#temp1045:23] : &:r0_124 -# 1045| r0_126(glval) = FieldAddress[s] : r0_124 -# 1045| r0_127(glval) = VariableAddress[s] : -# 1045| r0_128(String &) = Load : &:r0_127, ~mu0_2 -# 1045| mu0_129(String &) = Store : &:r0_126, r0_128 -# 1045| r0_130(glval) = FieldAddress[x] : r0_124 -# 1045| r0_131(glval) = VariableAddress[x] : -# 1045| r0_132(int) = Load : &:r0_131, ~mu0_2 -# 1045| mu0_133(int) = Store : &:r0_130, r0_132 -# 1045| r0_134(glval) = FieldAddress[i] : r0_124 +#-----| mu0_41(String) = ^IndirectMustWriteSideEffect : &:r0_37 +# 1036| r0_42(glval) = FieldAddress[x] : r0_35 +#-----| r0_43(glval) = VariableAddress[x] : +#-----| r0_44(int) = Load : &:r0_43, ~mu0_2 +#-----| mu0_45(int) = Store : &:r0_42, r0_44 +# 1036| r0_46(decltype([...](...){...})) = Load : &:r0_35, ~mu0_2 +# 1036| v0_47(void) = Call : func:r0_34, this:r0_33, 0:r0_46 +# 1036| mu0_48(unknown) = ^CallSideEffect : ~mu0_2 +# 1036| mu0_49(decltype([...](...){...})) = ^IndirectMustWriteSideEffect : &:r0_33 +# 1036| v0_50(void) = ^IndirectReadSideEffect[0] : &:r0_46, ~mu0_2 +# 1036| mu0_51(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_46 +# 1037| r0_52(glval) = VariableAddress[lambda_val] : +# 1037| r0_53(glval) = Convert : r0_52 +# 1037| r0_54(glval) = FunctionAddress[operator()] : +# 1037| r0_55(float) = Constant[2.0] : +# 1037| r0_56(char) = Call : func:r0_54, this:r0_53, 0:r0_55 +# 1037| mu0_57(unknown) = ^CallSideEffect : ~mu0_2 +# 1037| v0_58(void) = ^IndirectReadSideEffect[-1] : &:r0_53, ~mu0_2 +# 1037| mu0_59(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_53 +# 1038| r0_60(glval) = VariableAddress[lambda_ref_explicit] : +# 1038| r0_61(glval) = VariableAddress[#temp1038:30] : +# 1038| mu0_62(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_61 +# 1038| r0_63(glval) = FieldAddress[s] : r0_61 +# 1038| r0_64(glval) = VariableAddress[s] : +# 1038| r0_65(String &) = Load : &:r0_64, ~mu0_2 +# 1038| mu0_66(String &) = Store : &:r0_63, r0_65 +# 1038| r0_67(decltype([...](...){...})) = Load : &:r0_61, ~mu0_2 +# 1038| mu0_68(decltype([...](...){...})) = Store : &:r0_60, r0_67 +# 1039| r0_69(glval) = VariableAddress[lambda_ref_explicit] : +# 1039| r0_70(glval) = Convert : r0_69 +# 1039| r0_71(glval) = FunctionAddress[operator()] : +# 1039| r0_72(float) = Constant[3.0] : +# 1039| r0_73(char) = Call : func:r0_71, this:r0_70, 0:r0_72 +# 1039| mu0_74(unknown) = ^CallSideEffect : ~mu0_2 +# 1039| v0_75(void) = ^IndirectReadSideEffect[-1] : &:r0_70, ~mu0_2 +# 1039| mu0_76(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_70 +# 1040| r0_77(glval) = VariableAddress[lambda_val_explicit] : +# 1040| r0_78(glval) = FunctionAddress[(constructor)] : +# 1040| r0_79(glval) = VariableAddress[#temp1040:30] : +# 1040| mu0_80(decltype([...](...){...})) = Uninitialized[#temp1040:30] : &:r0_79 +# 1040| r0_81(glval) = FieldAddress[s] : r0_79 +#-----| r0_82(glval) = FunctionAddress[String] : +#-----| v0_83(void) = Call : func:r0_82, this:r0_81 +#-----| mu0_84(unknown) = ^CallSideEffect : ~mu0_2 +#-----| mu0_85(String) = ^IndirectMustWriteSideEffect : &:r0_81 +# 1040| r0_86(decltype([...](...){...})) = Load : &:r0_79, ~mu0_2 +# 1040| v0_87(void) = Call : func:r0_78, this:r0_77, 0:r0_86 +# 1040| mu0_88(unknown) = ^CallSideEffect : ~mu0_2 +# 1040| mu0_89(decltype([...](...){...})) = ^IndirectMustWriteSideEffect : &:r0_77 +# 1040| v0_90(void) = ^IndirectReadSideEffect[0] : &:r0_86, ~mu0_2 +# 1040| mu0_91(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_86 +# 1041| r0_92(glval) = VariableAddress[lambda_val_explicit] : +# 1041| r0_93(glval) = Convert : r0_92 +# 1041| r0_94(glval) = FunctionAddress[operator()] : +# 1041| r0_95(float) = Constant[4.0] : +# 1041| r0_96(char) = Call : func:r0_94, this:r0_93, 0:r0_95 +# 1041| mu0_97(unknown) = ^CallSideEffect : ~mu0_2 +# 1041| v0_98(void) = ^IndirectReadSideEffect[-1] : &:r0_93, ~mu0_2 +# 1041| mu0_99(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_93 +# 1042| r0_100(glval) = VariableAddress[lambda_mixed_explicit] : +# 1042| r0_101(glval) = VariableAddress[#temp1042:32] : +# 1042| mu0_102(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_101 +# 1042| r0_103(glval) = FieldAddress[s] : r0_101 +# 1042| r0_104(glval) = VariableAddress[s] : +# 1042| r0_105(String &) = Load : &:r0_104, ~mu0_2 +# 1042| mu0_106(String &) = Store : &:r0_103, r0_105 +# 1042| r0_107(glval) = FieldAddress[x] : r0_101 +# 1042| r0_108(glval) = VariableAddress[x] : +# 1042| r0_109(int) = Load : &:r0_108, ~mu0_2 +# 1042| mu0_110(int) = Store : &:r0_107, r0_109 +# 1042| r0_111(decltype([...](...){...})) = Load : &:r0_101, ~mu0_2 +# 1042| mu0_112(decltype([...](...){...})) = Store : &:r0_100, r0_111 +# 1043| r0_113(glval) = VariableAddress[lambda_mixed_explicit] : +# 1043| r0_114(glval) = Convert : r0_113 +# 1043| r0_115(glval) = FunctionAddress[operator()] : +# 1043| r0_116(float) = Constant[5.0] : +# 1043| r0_117(char) = Call : func:r0_115, this:r0_114, 0:r0_116 +# 1043| mu0_118(unknown) = ^CallSideEffect : ~mu0_2 +# 1043| v0_119(void) = ^IndirectReadSideEffect[-1] : &:r0_114, ~mu0_2 +# 1043| mu0_120(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_114 +# 1044| r0_121(glval) = VariableAddress[r] : +# 1044| r0_122(glval) = VariableAddress[x] : +# 1044| r0_123(int) = Load : &:r0_122, ~mu0_2 +# 1044| r0_124(int) = Constant[1] : +# 1044| r0_125(int) = Sub : r0_123, r0_124 +# 1044| mu0_126(int) = Store : &:r0_121, r0_125 +# 1045| r0_127(glval) = VariableAddress[lambda_inits] : +# 1045| r0_128(glval) = VariableAddress[#temp1045:23] : +# 1045| mu0_129(decltype([...](...){...})) = Uninitialized[#temp1045:23] : &:r0_128 +# 1045| r0_130(glval) = FieldAddress[s] : r0_128 +# 1045| r0_131(glval) = VariableAddress[s] : +# 1045| r0_132(String &) = Load : &:r0_131, ~mu0_2 +# 1045| mu0_133(String &) = Store : &:r0_130, r0_132 +# 1045| r0_134(glval) = FieldAddress[x] : r0_128 # 1045| r0_135(glval) = VariableAddress[x] : # 1045| r0_136(int) = Load : &:r0_135, ~mu0_2 -# 1045| r0_137(int) = Constant[1] : -# 1045| r0_138(int) = Add : r0_136, r0_137 -# 1045| mu0_139(int) = Store : &:r0_134, r0_138 -# 1045| r0_140(glval) = FieldAddress[j] : r0_124 -# 1045| r0_141(glval) = VariableAddress[r] : -# 1045| mu0_142(int &) = Store : &:r0_140, r0_141 -# 1045| r0_143(decltype([...](...){...})) = Load : &:r0_124, ~mu0_2 -# 1045| mu0_144(decltype([...](...){...})) = Store : &:r0_123, r0_143 -# 1046| r0_145(glval) = VariableAddress[lambda_inits] : -# 1046| r0_146(glval) = Convert : r0_145 -# 1046| r0_147(glval) = FunctionAddress[operator()] : -# 1046| r0_148(float) = Constant[6.0] : -# 1046| r0_149(char) = Call : func:r0_147, this:r0_146, 0:r0_148 -# 1046| mu0_150(unknown) = ^CallSideEffect : ~mu0_2 -# 1046| v0_151(void) = ^IndirectReadSideEffect[-1] : &:r0_146, ~mu0_2 -# 1046| mu0_152(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_146 -# 1047| v0_153(void) = NoOp : -# 1031| v0_154(void) = ReturnVoid : -# 1031| v0_155(void) = UnmodeledUse : mu* -# 1031| v0_156(void) = ExitFunction : +# 1045| mu0_137(int) = Store : &:r0_134, r0_136 +# 1045| r0_138(glval) = FieldAddress[i] : r0_128 +# 1045| r0_139(glval) = VariableAddress[x] : +# 1045| r0_140(int) = Load : &:r0_139, ~mu0_2 +# 1045| r0_141(int) = Constant[1] : +# 1045| r0_142(int) = Add : r0_140, r0_141 +# 1045| mu0_143(int) = Store : &:r0_138, r0_142 +# 1045| r0_144(glval) = FieldAddress[j] : r0_128 +# 1045| r0_145(glval) = VariableAddress[r] : +# 1045| mu0_146(int &) = Store : &:r0_144, r0_145 +# 1045| r0_147(decltype([...](...){...})) = Load : &:r0_128, ~mu0_2 +# 1045| mu0_148(decltype([...](...){...})) = Store : &:r0_127, r0_147 +# 1046| r0_149(glval) = VariableAddress[lambda_inits] : +# 1046| r0_150(glval) = Convert : r0_149 +# 1046| r0_151(glval) = FunctionAddress[operator()] : +# 1046| r0_152(float) = Constant[6.0] : +# 1046| r0_153(char) = Call : func:r0_151, this:r0_150, 0:r0_152 +# 1046| mu0_154(unknown) = ^CallSideEffect : ~mu0_2 +# 1046| v0_155(void) = ^IndirectReadSideEffect[-1] : &:r0_150, ~mu0_2 +# 1046| mu0_156(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_150 +# 1047| v0_157(void) = NoOp : +# 1031| v0_158(void) = ReturnVoid : +# 1031| v0_159(void) = UnmodeledUse : mu* +# 1031| v0_160(void) = ExitFunction : # 1032| void (void Lambda(int, String const&))::(lambda [] type at line 1032, col. 23)::(constructor)((void Lambda(int, String const&))::(lambda [] type at line 1032, col. 23)&&) # 1032| Block 0 @@ -4946,20 +4984,21 @@ ir.cpp: # 1040| void (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::(constructor)((void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)&&) # 1040| Block 0 -# 1040| v0_0(void) = EnterFunction : -# 1040| mu0_1(unknown) = AliasedDefinition : -# 1040| mu0_2(unknown) = UnmodeledDefinition : -# 1040| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(lambda [] type at line 1040, col. 30 &&) = InitializeParameter[p#0] : &:r0_4 -# 1040| r0_6(glval) = FieldAddress[s] : r0_3 -# 1040| r0_7(glval) = FunctionAddress[String] : -# 1040| v0_8(void) = Call : func:r0_7, this:r0_6 -# 1040| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| v0_10(void) = NoOp : -# 1040| v0_11(void) = ReturnVoid : -# 1040| v0_12(void) = UnmodeledUse : mu* -# 1040| v0_13(void) = ExitFunction : +# 1040| v0_0(void) = EnterFunction : +# 1040| mu0_1(unknown) = AliasedDefinition : +# 1040| mu0_2(unknown) = UnmodeledDefinition : +# 1040| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(lambda [] type at line 1040, col. 30 &&) = InitializeParameter[p#0] : &:r0_4 +# 1040| r0_6(glval) = FieldAddress[s] : r0_3 +# 1040| r0_7(glval) = FunctionAddress[String] : +# 1040| v0_8(void) = Call : func:r0_7, this:r0_6 +# 1040| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 +# 1040| mu0_10(String) = ^IndirectMustWriteSideEffect : &:r0_6 +# 1040| v0_11(void) = NoOp : +# 1040| v0_12(void) = ReturnVoid : +# 1040| v0_13(void) = UnmodeledUse : mu* +# 1040| v0_14(void) = ExitFunction : # 1040| void (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::~() # 1040| Block 0 @@ -5378,9 +5417,10 @@ ir.cpp: # 1140| r7_3(char *) = Convert : r7_2 # 1140| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 1140| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1140| v7_6(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 -# 1140| mu7_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 -# 1140| v7_8(void) = ThrowValue : &:r7_0, ~mu0_2 +# 1140| mu7_6(String) = ^IndirectMustWriteSideEffect : &:r7_0 +# 1140| v7_7(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 +# 1140| mu7_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 +# 1140| v7_9(void) = ThrowValue : &:r7_0, ~mu0_2 #-----| Exception -> Block 9 # 1142| Block 8 @@ -5403,9 +5443,10 @@ ir.cpp: # 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2 # 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 # 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 1145| v10_8(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 -# 1145| mu10_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 -# 1145| v10_10(void) = ThrowValue : &:r10_2, ~mu0_2 +# 1145| mu10_8(String) = ^IndirectMustWriteSideEffect : &:r10_2 +# 1145| v10_9(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 +# 1145| mu10_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 +# 1145| v10_11(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 # 1147| Block 11 @@ -5544,11 +5585,12 @@ perf-regression.cpp: # 10| r0_9(glval) = FunctionAddress[Big] : # 10| v0_10(void) = Call : func:r0_9, this:r0_8 # 10| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 10| mu0_12(Big *) = Store : &:r0_3, r0_8 -# 12| r0_13(glval) = VariableAddress[#return] : -# 12| r0_14(int) = Constant[0] : -# 12| mu0_15(int) = Store : &:r0_13, r0_14 -# 9| r0_16(glval) = VariableAddress[#return] : -# 9| v0_17(void) = ReturnValue : &:r0_16, ~mu0_2 -# 9| v0_18(void) = UnmodeledUse : mu* -# 9| v0_19(void) = ExitFunction : +# 10| mu0_12(Big) = ^IndirectMustWriteSideEffect : &:r0_8 +# 10| mu0_13(Big *) = Store : &:r0_3, r0_8 +# 12| r0_14(glval) = VariableAddress[#return] : +# 12| r0_15(int) = Constant[0] : +# 12| mu0_16(int) = Store : &:r0_14, r0_15 +# 9| r0_17(glval) = VariableAddress[#return] : +# 9| v0_18(void) = ReturnValue : &:r0_17, ~mu0_2 +# 9| v0_19(void) = UnmodeledUse : mu* +# 9| v0_20(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected index ae680785ce6..283f13d4bf4 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected @@ -1,4 +1,8 @@ missingOperand +| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected index ae680785ce6..283f13d4bf4 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -1,4 +1,8 @@ missingOperand +| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index 5fb356f5701..c7c6e112878 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -1,10 +1,33 @@ missingOperand +| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:17:82:55 | IndirectMustWriteSideEffect: call to (constructor) | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMustWriteSideEffect: call to C | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | allocators.cpp:14:5:14:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | no_dynamic_init.cpp:9:5:9:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | parameterinitializer.cpp:18:5:18:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | stream_it.cpp:16:5:16:8 | IR: main | int main() | -| try_catch.cpp:13:5:13:16 | ThrowValue: throw ... | Instruction 'ThrowValue' is missing an expected operand with tag 'Load' in function '$@'. | try_catch.cpp:11:6:11:17 | IR: bypass_catch | void bypass_catch() | unexpectedOperand duplicateOperand missingPhiOperand @@ -13,10 +36,10 @@ missingOperandType instructionWithoutSuccessor | VacuousDestructorCall.cpp:2:29:2:29 | InitializeParameter: y | | assume0.cpp:7:2:7:2 | Chi: call to f | -| condition_decls.cpp:16:19:16:20 | Chi: call to BoxedInt | -| condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | +| condition_decls.cpp:16:19:16:20 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:26:23:26:24 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:41:22:41:23 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:48:52:48:53 | IndirectMustWriteSideEffect: call to BoxedInt | | cpp17.cpp:15:11:15:21 | Convert: (void *)... | | misc.c:171:10:171:13 | Uninitialized: definition of str2 | | misc.c:219:47:219:48 | InitializeParameter: sp | diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index 426424a5fd4..6d832e6a831 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -3,6 +3,34 @@ missingOperand | condition_decls.cpp:26:3:36:3 | Switch: switch (...) ... | Instruction 'Switch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | | condition_decls.cpp:41:9:41:23 | ConditionalBranch: (condition decl) | Instruction 'ConditionalBranch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | | condition_decls.cpp:48:39:48:53 | ConditionalBranch: (condition decl) | Instruction 'ConditionalBranch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | +| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:17:82:55 | IndirectMustWriteSideEffect: call to (constructor) | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMustWriteSideEffect: call to C | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | | misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | @@ -26,11 +54,11 @@ instructionWithoutSuccessor | VacuousDestructorCall.cpp:4:3:4:3 | Load: y | | assume0.cpp:7:2:7:2 | CallSideEffect: call to f | | assume0.cpp:9:11:9:11 | Constant: (bool)... | -| condition_decls.cpp:16:19:16:20 | CallSideEffect: call to BoxedInt | +| condition_decls.cpp:16:19:16:20 | IndirectMustWriteSideEffect: call to BoxedInt | | condition_decls.cpp:26:19:26:20 | IndirectMayWriteSideEffect: bi | -| condition_decls.cpp:26:23:26:24 | CallSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | CallSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | CallSideEffect: call to BoxedInt | +| condition_decls.cpp:26:23:26:24 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:41:22:41:23 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:48:52:48:53 | IndirectMustWriteSideEffect: call to BoxedInt | | cpp17.cpp:15:11:15:21 | Convert: (void *)... | | file://:0:0:0:0 | CompareNE: (bool)... | | file://:0:0:0:0 | CompareNE: (bool)... | @@ -54,16 +82,16 @@ instructionWithoutSuccessor | ms_try_except.cpp:17:13:17:17 | Store: ... = ... | | ms_try_except.cpp:19:17:19:21 | Sub: ... - ... | | ms_try_except.cpp:20:9:20:13 | Store: ... = ... | -| ms_try_mix.cpp:11:12:11:15 | CallSideEffect: call to C | +| ms_try_mix.cpp:11:12:11:15 | IndirectMustWriteSideEffect: call to C | | ms_try_mix.cpp:16:13:16:19 | ThrowValue: throw ... | -| ms_try_mix.cpp:18:16:18:19 | CallSideEffect: call to C | +| ms_try_mix.cpp:18:16:18:19 | IndirectMustWriteSideEffect: call to C | | ms_try_mix.cpp:20:15:20:39 | Constant: 1 | -| ms_try_mix.cpp:21:16:21:19 | CallSideEffect: call to C | -| ms_try_mix.cpp:28:12:28:15 | CallSideEffect: call to C | +| ms_try_mix.cpp:21:16:21:19 | IndirectMustWriteSideEffect: call to C | +| ms_try_mix.cpp:28:12:28:15 | IndirectMustWriteSideEffect: call to C | | ms_try_mix.cpp:33:13:33:19 | ThrowValue: throw ... | -| ms_try_mix.cpp:35:16:35:19 | CallSideEffect: call to C | -| ms_try_mix.cpp:38:16:38:19 | CallSideEffect: call to C | -| ms_try_mix.cpp:48:10:48:13 | CallSideEffect: call to C | +| ms_try_mix.cpp:35:16:35:19 | IndirectMustWriteSideEffect: call to C | +| ms_try_mix.cpp:38:16:38:19 | IndirectMustWriteSideEffect: call to C | +| ms_try_mix.cpp:48:10:48:13 | IndirectMustWriteSideEffect: call to C | | ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... | | ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } | | pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} | diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index 22a395b3f89..51c69186d92 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -1,10 +1,33 @@ missingOperand +| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:17:82:55 | IndirectMustWriteSideEffect: call to (constructor) | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMustWriteSideEffect: call to C | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | allocators.cpp:14:5:14:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | no_dynamic_init.cpp:9:5:9:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | parameterinitializer.cpp:18:5:18:8 | IR: main | int main() | -| parameterinitializer.cpp:27:3:27:6 | IndirectReadSideEffect: my_c | Instruction 'IndirectReadSideEffect' is missing an expected operand with tag 'SideEffect' in function '$@'. | stream_it.cpp:16:5:16:8 | IR: main | int main() | -| try_catch.cpp:13:5:13:16 | ThrowValue: throw ... | Instruction 'ThrowValue' is missing an expected operand with tag 'Load' in function '$@'. | try_catch.cpp:11:6:11:17 | IR: bypass_catch | void bypass_catch() | unexpectedOperand duplicateOperand missingPhiOperand @@ -22,17 +45,17 @@ missingOperandType instructionWithoutSuccessor | VacuousDestructorCall.cpp:2:29:2:29 | InitializeParameter: y | | assume0.cpp:7:2:7:2 | CallSideEffect: call to f | -| condition_decls.cpp:16:19:16:20 | CallSideEffect: call to BoxedInt | -| condition_decls.cpp:26:23:26:24 | CallSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | CallSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | CallSideEffect: call to BoxedInt | +| condition_decls.cpp:16:19:16:20 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:26:23:26:24 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:41:22:41:23 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:48:52:48:53 | IndirectMustWriteSideEffect: call to BoxedInt | | cpp17.cpp:15:11:15:21 | Convert: (void *)... | | misc.c:171:10:171:13 | Uninitialized: definition of str2 | | misc.c:219:47:219:48 | InitializeParameter: sp | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| ms_try_mix.cpp:11:12:11:15 | CallSideEffect: call to C | -| ms_try_mix.cpp:28:12:28:15 | CallSideEffect: call to C | -| ms_try_mix.cpp:48:10:48:13 | CallSideEffect: call to C | +| ms_try_mix.cpp:11:12:11:15 | IndirectMustWriteSideEffect: call to C | +| ms_try_mix.cpp:28:12:28:15 | IndirectMustWriteSideEffect: call to C | +| ms_try_mix.cpp:48:10:48:13 | IndirectMustWriteSideEffect: call to C | | pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} | | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | From 56ed2f618d932f221976391dd46f754ca208fbe0 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Wed, 2 Oct 2019 09:05:31 +0100 Subject: [PATCH 0328/1227] Add alias for easier user-searching --- docs/language/support/versions-compilers.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/support/versions-compilers.csv b/docs/language/support/versions-compilers.csv index b70ac87335f..74f69d662b6 100644 --- a/docs/language/support/versions-compilers.csv +++ b/docs/language/support/versions-compilers.csv @@ -10,7 +10,7 @@ C#,C# up to 7.3. with .NET up to 4.8 [3]_.,"Microsoft Visual Studio up to 2019, .NET Core up to 2.2","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" COBOL,ANSI 85 or newer [4]_.,Not applicable,"``.cbl``, ``.CBL``, ``.cpy``, ``.CPY``, ``.copy``, ``.COPY``" -Go, "Go up to 1.13", "Go 1.11 or more recent", ``.go`` +Go (aka Golang), "Go up to 1.13", "Go 1.11 or more recent", ``.go`` Java,"Java 6 to 12 [5]_.","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [6]_.",``.java`` From 28c34ad41e56a3bc9ae26952e293d0eb1800482e Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 2 Oct 2019 10:42:06 +0100 Subject: [PATCH 0329/1227] C#: Address review comments. --- csharp/ql/src/semmle/code/csharp/Stmt.qll | 4 +++- .../src/semmle/code/csharp/controlflow/ControlFlowGraph.qll | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index dc11e83f065..35498fc6e06 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -225,7 +225,9 @@ private module SwithStmtInternal { /** Implicitly reorder case statements to put the default case last if needed. */ private predicate caseIndex(SwitchStmt ss, CaseStmt case, int index) { exists(int i | case = ss.getChildStmt(i) | - if case instanceof DefaultCase then index = 1000000 else index = i + if case instanceof DefaultCase + then index = max(int j | exists(ss.getChildStmt(j))) + 1 + else index = i ) } diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 3afce0b1994..581105dd519 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -741,7 +741,6 @@ module ControlFlow { TLastRecBooleanNegationCompletion() or TLastRecNonBooleanCompletion() or TLastRecBreakCompletion() or - TLastRecNonBreakCompletion() or TLastRecSwitchAbnormalCompletion() or TLastRecInvalidOperationException() or TLastRecNonContinueCompletion() or @@ -1150,10 +1149,6 @@ module ControlFlow { c0 instanceof BreakCompletion and c instanceof BreakNormalCompletion or - rec = TLastRecNonBreakCompletion() and - not c0 instanceof BreakCompletion and - c = c0 - or rec = TLastRecSwitchAbnormalCompletion() and not c instanceof BreakCompletion and not c instanceof NormalCompletion and From 0154e31e64d2e03378803711ccf147f065368d3b Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 2 Oct 2019 11:47:53 +0200 Subject: [PATCH 0330/1227] Java: Add change note. --- change-notes/1.23/analysis-java.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.23/analysis-java.md b/change-notes/1.23/analysis-java.md index 76085832c01..68a91151709 100644 --- a/change-notes/1.23/analysis-java.md +++ b/change-notes/1.23/analysis-java.md @@ -6,6 +6,7 @@ The following changes in version 1.23 affect Java analysis in all applications. | **Query** | **Expected impact** | **Change** | |------------------------------|------------------------|-----------------------------------| +| Dereferenced variable may be null (`java/dereferenced-value-may-be-null`) | Fewer false positives | Certain indirect null guards involving two auxiliary variables known to be equal can now be detected. | | Query built from user-controlled sources (`java/sql-injection`) | More results | The query now identifies arguments to `Statement.executeLargeUpdate` and `Connection.prepareCall` as SQL expressions sinks. | | Query built from local-user-controlled sources (`java/sql-injection-local`) | More results | The query now identifies arguments to `Statement.executeLargeUpdate` and `Connection.prepareCall` as SQL expressions sinks. | | Query built without neutralizing special characters (`java/concatenated-sql-query`) | More results | The query now identifies arguments to `Statement.executeLargeUpdate` and `Connection.prepareCall` as SQL expressions sinks. | From 3dd2a6c325e91fecda7a4c8ee835f4dcc4da691e Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Wed, 2 Oct 2019 12:21:23 +0100 Subject: [PATCH 0331/1227] QL etudes: Add further explanation + link --- docs/language/learn-ql/beginner/heir.rst | 1 + docs/language/learn-ql/ql-etudes/river-crossing.rst | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/language/learn-ql/beginner/heir.rst b/docs/language/learn-ql/beginner/heir.rst index 6b76f0af7d3..b5efd73fc40 100644 --- a/docs/language/learn-ql/beginner/heir.rst +++ b/docs/language/learn-ql/beginner/heir.rst @@ -160,4 +160,5 @@ What next? ---------- - Learn more about recursion in the `QL language handbook `__. +- Put your QL skills to the test and solve the :doc:`River crossing puzzle <../ql-etudes/river-crossing>`. - Start using QL to analyze projects. See :doc:`Learning QL <../../index>` for a summary of the available languages and resources. diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.rst b/docs/language/learn-ql/ql-etudes/river-crossing.rst index f565a571898..70b09f0643c 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.rst +++ b/docs/language/learn-ql/ql-etudes/river-crossing.rst @@ -227,8 +227,11 @@ that returns the resulting path. .. literalinclude:: river-crossing.ql :lines: 115-117 -For now, the path defined in the above predicate ``reachesVia`` just lists the order of cargo items to ferry. -You could tweak the predicates and the select clause to make the solution clearer. Here are some suggestions: +The `don't-care expression `__ (``_``), +as the second argument to the ``reachesVia`` predicate, represents any value of ``visitedStates``. + +For now, the path defined in ``reachesVia`` just lists the order of cargo items to ferry. +You could tweak the predicate and the select clause to make the solution clearer. Here are some suggestions: - Display more information, such as the direction in which the cargo is ferried, for example ``"Goat to the left shore"``. From 9c54eef45a81de4111b4cfcbb2dc6a6519604e27 Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Mon, 30 Sep 2019 10:38:10 +0100 Subject: [PATCH 0332/1227] QL HB: Update aggregation section --- docs/language/ql-handbook/expressions.rst | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/language/ql-handbook/expressions.rst b/docs/language/ql-handbook/expressions.rst index c73c16db704..03e33693b41 100644 --- a/docs/language/ql-handbook/expressions.rst +++ b/docs/language/ql-handbook/expressions.rst @@ -303,22 +303,22 @@ Let us apply these steps to the ``sum`` aggregate in the following query: .. code-block:: ql select sum(int i, int j | - exists(string char | char = "hello".charAt(i)) and exists(string char | char = "world!".charAt(j)) | i) + exists(string s | s = "hello".charAt(i)) and exists(string s | s = "world!".charAt(j)) | i) #. Input variables: ``i``, ``j``. #. All possible tuples ``(, )`` satisfying the given condition: - ``(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 0), (1, 1),...,(4, 5)``. + ``(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 0), (1, 1), ..., (4, 5)``. - ``30`` tuples are generated in this step. + 30 tuples are generated in this step. #. Apply the `` i`` on all tuples. This means selecting all values of ``i`` from all tuples: ``0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4.`` #. Apply the aggregation function ``sum`` on the above values to get the final result ``60``. -If we change ```` to ``i+j`` in the above query, the query result is ``135`` since -applying ``i+j`` on all tuples results in following values:  +If we change ```` to ``i + j`` in the above query, the query result is ``135`` since +applying ``i + j`` on all tuples results in following values:  \ ``0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 9``. Next, consider the following query: @@ -327,11 +327,15 @@ Next, consider the following query: select count(string s | s = "hello" | s.charAt(_)) -``s`` is the input variable of the aggregate. A single tuple ``("hello")`` is generated after -applying step 2. When the `` charAt(_)`` is applied on this tuple, it generates ``4`` -distinct values ``'h', 'e', 'l', 'o'``. Note that ``'l'`` only appears once as this step collects -the distinct values generated as a result of applying ````. Finally, ``count`` is -applied on these values, and the query returns ``4``. +#. ``s`` is the input variable of the aggregate. + +#. A single tuple ``"hello"`` is generated in this step. + +#. The `` charAt(_)`` is applied on this tuple. The underscore ``_`` in ``charAt(_)`` + is a :ref:`don't-care expression `, which represents any value. + ``s.charAt(_)`` generates four distinct values ``h, e, l, o``. + +#. Finally, ``count`` is applied on these values, and the query returns ``4``. From f87cb4d6acbf010487f4ccb84cb9a1e20485d42a Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 2 Oct 2019 14:28:54 +0200 Subject: [PATCH 0333/1227] Java/C++/C#: Address review comments and fix test. --- .../dataflow/internal/DataFlowImplCommon.qll | 15 ++++++ .../dataflow/internal/DataFlowImplCommon.qll | 15 ++++++ csharp/ql/src/semmle/code/csharp/Caching.qll | 2 +- .../dataflow/internal/DataFlowImplCommon.qll | 15 ++++++ .../dataflow/internal/DataFlowPrivate.qll | 1 - .../internal/TaintTrackingPrivate.qll | 1 - .../dataflow/internal/DataFlowImplCommon.qll | 15 ++++++ .../dataflow/gettersetter/A.java | 51 +++++++++++++++++++ .../gettersetter/gettersetter.expected | 9 ++++ .../dataflow/gettersetter/gettersetter.ql | 11 ++++ 10 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 java/ql/test/library-tests/dataflow/gettersetter/A.java create mode 100644 java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected create mode 100644 java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 6463600846f..8b4b01de79d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -34,6 +34,16 @@ private module ImplCommon { ) } + /* + * The `FlowThrough_*` modules take a `step` relation as input and provide + * an `argumentValueFlowsThrough` relation as output. + * + * `FlowThrough_v1` includes just `simpleLocalFlowStep`, which is then used + * to detect getters and setters. + * `FlowThrough_v2` then includes a little bit of local field flow on top + * of `simpleLocalFlowStep`. + */ + private module FlowThrough_v1 { private predicate step = simpleLocalFlowStep/2; @@ -233,6 +243,11 @@ private module ImplCommon { FlowThrough_v1::argumentValueFlowsThrough(node1, node2, _) } + /** + * Holds if `p` can flow to `node` in the same callable allowing local flow + * steps and value flow through methods. Call contexts are only accounted + * for in the nested calls. + */ private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { p = node or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 6463600846f..8b4b01de79d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -34,6 +34,16 @@ private module ImplCommon { ) } + /* + * The `FlowThrough_*` modules take a `step` relation as input and provide + * an `argumentValueFlowsThrough` relation as output. + * + * `FlowThrough_v1` includes just `simpleLocalFlowStep`, which is then used + * to detect getters and setters. + * `FlowThrough_v2` then includes a little bit of local field flow on top + * of `simpleLocalFlowStep`. + */ + private module FlowThrough_v1 { private predicate step = simpleLocalFlowStep/2; @@ -233,6 +243,11 @@ private module ImplCommon { FlowThrough_v1::argumentValueFlowsThrough(node1, node2, _) } + /** + * Holds if `p` can flow to `node` in the same callable allowing local flow + * steps and value flow through methods. Call contexts are only accounted + * for in the nested calls. + */ private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { p = node or diff --git a/csharp/ql/src/semmle/code/csharp/Caching.qll b/csharp/ql/src/semmle/code/csharp/Caching.qll index ec239e93f41..ec94a15064a 100644 --- a/csharp/ql/src/semmle/code/csharp/Caching.qll +++ b/csharp/ql/src/semmle/code/csharp/Caching.qll @@ -50,7 +50,7 @@ module Stages { cached module DataFlowStage { private import semmle.code.csharp.dataflow.internal.DataFlowPrivate - private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon + private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon::Public private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate cached diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 6463600846f..8b4b01de79d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -34,6 +34,16 @@ private module ImplCommon { ) } + /* + * The `FlowThrough_*` modules take a `step` relation as input and provide + * an `argumentValueFlowsThrough` relation as output. + * + * `FlowThrough_v1` includes just `simpleLocalFlowStep`, which is then used + * to detect getters and setters. + * `FlowThrough_v2` then includes a little bit of local field flow on top + * of `simpleLocalFlowStep`. + */ + private module FlowThrough_v1 { private predicate step = simpleLocalFlowStep/2; @@ -233,6 +243,11 @@ private module ImplCommon { FlowThrough_v1::argumentValueFlowsThrough(node1, node2, _) } + /** + * Holds if `p` can flow to `node` in the same callable allowing local flow + * steps and value flow through methods. Call contexts are only accounted + * for in the nested calls. + */ private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { p = node or diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 477688191a0..d757ef87901 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -3,7 +3,6 @@ private import cil private import dotnet private import DataFlowPublic private import DataFlowDispatch -private import DataFlowImplCommon private import ControlFlowReachability private import DelegateDataFlow private import semmle.code.csharp.Caching diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index 425724f3a22..8c24227f73a 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -1,6 +1,5 @@ private import csharp private import TaintTrackingPublic -private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.dataflow.internal.ControlFlowReachability private import semmle.code.csharp.dataflow.LibraryTypeDataFlow diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 6463600846f..8b4b01de79d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -34,6 +34,16 @@ private module ImplCommon { ) } + /* + * The `FlowThrough_*` modules take a `step` relation as input and provide + * an `argumentValueFlowsThrough` relation as output. + * + * `FlowThrough_v1` includes just `simpleLocalFlowStep`, which is then used + * to detect getters and setters. + * `FlowThrough_v2` then includes a little bit of local field flow on top + * of `simpleLocalFlowStep`. + */ + private module FlowThrough_v1 { private predicate step = simpleLocalFlowStep/2; @@ -233,6 +243,11 @@ private module ImplCommon { FlowThrough_v1::argumentValueFlowsThrough(node1, node2, _) } + /** + * Holds if `p` can flow to `node` in the same callable allowing local flow + * steps and value flow through methods. Call contexts are only accounted + * for in the nested calls. + */ private predicate parameterValueFlowNoCtx(ParameterNode p, Node node) { p = node or diff --git a/java/ql/test/library-tests/dataflow/gettersetter/A.java b/java/ql/test/library-tests/dataflow/gettersetter/A.java new file mode 100644 index 00000000000..910bdd80547 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/gettersetter/A.java @@ -0,0 +1,51 @@ +public class A { + int foo; + + int getFoo() { + return this.foo; + } + + void setFoo(int x) { + this.foo = x; + } + + static A withFoo(int x) { + A a = new A(); + a.foo = x; + return a; + } + + static void run() { + A a = new A(); + a.setFoo(1); + int x = a.getFoo(); + A a2 = withFoo(2); + x = a.aGetter(); + x = a2.notAGetter(); + } + + static class C1 { + A maybeId(A a) { + return a; + } + } + + static class C2 extends C1 { + @Override + A maybeId(A a) { + return new A(); + } + } + + static A maybeIdWrap(A a, C1 c) { + return c.maybeId(a); + } + + int aGetter() { + return maybeIdWrap(this, new C1()).foo; + } + + int notAGetter() { + return maybeIdWrap(this, new C2()).foo; + } +} diff --git a/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected b/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected new file mode 100644 index 00000000000..62bf8c1612b --- /dev/null +++ b/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected @@ -0,0 +1,9 @@ +| Read | A.java:5:12:5:15 | this | A.java:5:12:5:19 | this.foo | A.java:2:7:2:9 | foo | +| Read | A.java:21:13:21:13 | a | A.java:21:13:21:22 | getFoo(...) | A.java:2:7:2:9 | foo | +| Read | A.java:23:9:23:9 | a | A.java:23:9:23:19 | aGetter(...) | A.java:2:7:2:9 | foo | +| Read | A.java:45:12:45:38 | maybeIdWrap(...) | A.java:45:12:45:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | +| Read | A.java:49:12:49:38 | maybeIdWrap(...) | A.java:49:12:49:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | +| Store | A.java:9:16:9:16 | x | A.java:9:5:9:8 | this [post update] | A.java:2:7:2:9 | foo | +| Store | A.java:14:13:14:13 | x | A.java:14:5:14:5 | a [post update] | A.java:2:7:2:9 | foo | +| Store | A.java:20:14:20:14 | 1 | A.java:20:5:20:5 | a [post update] | A.java:2:7:2:9 | foo | +| Store | A.java:22:20:22:20 | 2 | A.java:22:12:22:21 | withFoo(...) | A.java:2:7:2:9 | foo | diff --git a/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql b/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql new file mode 100644 index 00000000000..fce874b0b79 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql @@ -0,0 +1,11 @@ +import java +import semmle.code.java.dataflow.internal.DataFlowImplCommon::Public +import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Public +import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Private + +from Node n1, Content f, Node n2, string k +where + read(n1, f, n2) and k = "Read" + or + store(n1, f, n2) and k = "Store" +select k, n1, n2, f From 22aac8e72397835c7aade7d924582bc44d9efb61 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 2 Oct 2019 14:49:33 +0200 Subject: [PATCH 0334/1227] ensure that the existence of non-synthetic constructor is checked correctly --- .../ql/src/Declarations/SuspiciousMethodNameDeclaration.ql | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index b84d3505899..ffa2801792c 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -37,7 +37,10 @@ where ( // Assume that a "new" method is intentional if the class has an explicit constructor. name = "new" and container instanceof ClassDefinition and - not container.getMember("constructor").(ConstructorDeclaration).isSynthetic() + exists(ConstructorDeclaration constructor | + container.getMember("constructor") = constructor and + not constructor.isSynthetic() + ) ) or ( // Explicitly declared static methods are fine. From e5290f3bb0437313eb4ed6c252c6bb0d5b227cdf Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 2 Oct 2019 14:51:47 +0200 Subject: [PATCH 0335/1227] remove some parentheses --- .../SuspiciousMethodNameDeclaration.ql | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index ffa2801792c..f95bc1cad89 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -34,30 +34,26 @@ where // Cases to ignore. not ( - ( // Assume that a "new" method is intentional if the class has an explicit constructor. - name = "new" and - container instanceof ClassDefinition and - exists(ConstructorDeclaration constructor | - container.getMember("constructor") = constructor and - not constructor.isSynthetic() - ) - ) + // Assume that a "new" method is intentional if the class has an explicit constructor. + name = "new" and + container instanceof ClassDefinition and + exists(ConstructorDeclaration constructor | + container.getMember("constructor") = constructor and + not constructor.isSynthetic() + ) or - ( // Explicitly declared static methods are fine. - container instanceof ClassDefinition and - member.isStatic() - ) + // Explicitly declared static methods are fine. + container instanceof ClassDefinition and + member.isStatic() or // Only looking for declared methods. Methods with a body are OK. exists(member.getBody().getBody()) - or - ( // The developer was not confused about "function" when there are other methods in the interface. - name = "function" and - exists(MethodDeclaration other | other = container.getAMethod() | - name != "function" and - not other.(ConstructorDeclaration).isSynthetic() - ) + // The developer was not confused about "function" when there are other methods in the interface. + name = "function" and + exists(MethodDeclaration other | other = container.getAMethod() | + name != "function" and + not other.(ConstructorDeclaration).isSynthetic() ) ) From c0b7538cf0ed829f702ff1d947a3cebcbd8cf3a4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 2 Oct 2019 14:56:41 +0200 Subject: [PATCH 0336/1227] made the blacklist for methods named "function" work again --- .../ql/src/Declarations/SuspiciousMethodNameDeclaration.ql | 2 +- .../SuspiciousMethodNameDeclaration.expected | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index f95bc1cad89..a15566a40ac 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -52,7 +52,7 @@ where // The developer was not confused about "function" when there are other methods in the interface. name = "function" and exists(MethodDeclaration other | other = container.getAMethod() | - name != "function" and + other.getName() != "function" and not other.(ConstructorDeclaration).isSynthetic() ) ) diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected index b033253ccd6..dd7c5fa355b 100644 --- a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected +++ b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/SuspiciousMethodNameDeclaration.expected @@ -1,4 +1,3 @@ -| tst.ts:4:3:4:22 | function (): number; | The member name 'function' does not declare a function, it declares a method named 'function'. | | tst.ts:7:3:7:24 | constru ... string; | The member name 'constructor' does not declare a constructor in interface declarations, but it does in class declarations. | | tst.ts:16:3:16:21 | function(): number; | The member name 'function' does not declare a function, it declares a method named 'function'. | | tst.ts:37:3:37:21 | function(): number; | The member name 'function' does not declare a function, it declares a method named 'function'. | From 0c46e5c1a8dfd42eac20477a091eae8afd816690 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 2 Oct 2019 15:01:25 +0200 Subject: [PATCH 0337/1227] update description of js/suspicious-method-name-declaration --- .../ql/src/Declarations/SuspiciousMethodNameDeclaration.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index a15566a40ac..7831344f5ec 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -1,7 +1,7 @@ /** * @name Suspicious method name declaration - * @description A method having the name "function", "new", or "constructor" - * is usually caused by a programmer being confused about the TypeScript syntax. + * @description Declaring a class or interface method with a special name may cause a normal + * named method to be declared when a special type was expected. * @kind problem * @problem.severity warning * @id js/suspicious-method-name-declaration From 2b5e3aebb750ee906e515c4d86b537e6a0044a80 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 2 Oct 2019 15:03:38 +0200 Subject: [PATCH 0338/1227] change tabs to spaces --- .../Declarations/SuspiciousMethodNameDeclaration.ql | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index 7831344f5ec..a8a068ffa9f 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -34,14 +34,14 @@ where // Cases to ignore. not ( - // Assume that a "new" method is intentional if the class has an explicit constructor. - name = "new" and - container instanceof ClassDefinition and - exists(ConstructorDeclaration constructor | + // Assume that a "new" method is intentional if the class has an explicit constructor. + name = "new" and + container instanceof ClassDefinition and + exists(ConstructorDeclaration constructor | container.getMember("constructor") = constructor and not constructor.isSynthetic() ) - or + or // Explicitly declared static methods are fine. container instanceof ClassDefinition and member.isStatic() From 6ebefbb67d721a8cdf94a98ad8af56f735d4e56c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 2 Oct 2019 16:23:08 +0200 Subject: [PATCH 0339/1227] C#: Improve a few join-orders in `Splitting.qll` --- .../csharp/controlflow/internal/Splitting.qll | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll index e9063076144..40915f905ea 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll @@ -527,15 +527,20 @@ module FinallySplitting { override string toString() { result = "Finally (" + nestLevel + ")" } } + pragma[noinline] + private predicate hasEntry0( + ControlFlowElement pred, FinallyControlFlowElement succ, int nestLevel, Completion c + ) { + succ.isEntryNode() and + nestLevel = nestLevel(succ.getTryStmt()) and + succ = succ(pred, c) + } + private class FinallySplitInternal extends SplitInternal, FinallySplitImpl { override FinallySplitKind getKind() { result.getNestLevel() = this.getNestLevel() } override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) { - succ = any(FinallyControlFlowElement entry | - entry.isEntryNode() and - this.getNestLevel() = nestLevel(entry.getTryStmt()) - ) and - succ = succ(pred, c) and + hasEntry0(pred, succ, this.getNestLevel(), c) and this.getType().isSplitForEntryCompletion(c) } @@ -550,17 +555,22 @@ module FinallySplitting { (exists(succ(pred, _)) or exists(succExit(pred, _))) } + pragma[noinline] + private predicate exit0(ControlFlowElement pred, TryStmt try, int nestLevel, Completion c) { + this.appliesToPredecessor(pred) and + nestLevel = nestLevel(try) and + pred = last(try, c) + } + /** * Holds if `pred` may exit this split with completion `c`. The Boolean * `inherited` indicates whether `c` is an inherited completion from a `try`/ * `catch` block. */ private predicate exit(ControlFlowElement pred, Completion c, boolean inherited) { - this.appliesToPredecessor(pred) and exists(TryStmt try, FinallySplitType type | - type = this.getType() and - nestLevel(try) = this.getNestLevel() and - pred = last(try, c) + exit0(pred, try, this.getNestLevel(), c) and + type = this.getType() | if pred = last(try.getFinally(), c) then @@ -1019,13 +1029,21 @@ module BooleanSplitting { override string toString() { result = kind.toString() } } + pragma[noinline] + private predicate hasEntry0( + ControlFlowElement pred, ControlFlowElement succ, BooleanSplitSubKind kind, boolean b, + Completion c + ) { + kind.startsSplit(pred) and + succ = succ(pred, c) and + b = c.getInnerCompletion().(BooleanCompletion).getValue() + } + private class BooleanSplitInternal extends SplitInternal, BooleanSplitImpl { override BooleanSplitKind getKind() { result.getSubKind() = this.getSubKind() } override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) { - succ = succ(pred, c) and - this.getSubKind().startsSplit(pred) and - this.getBranch() = c.getInnerCompletion().(BooleanCompletion).getValue() + hasEntry0(pred, succ, this.getSubKind(), this.getBranch(), c) } override predicate hasEntry(Callable c, ControlFlowElement succ) { none() } From 17085dc05c8e8412078e589e72156f7e892b0bf6 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 2 Oct 2019 16:26:38 +0200 Subject: [PATCH 0340/1227] C#: Fix typo --- csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql index 4fef7c41256..646ab04ac1f 100644 --- a/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql +++ b/csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql @@ -90,7 +90,7 @@ private class Conf extends DataFlow::Configuration { } /** Holds if `disposable` may not be disposed. */ -predicate mayNotBeDiposed(LocalScopeDisposableCreation disposable) { +predicate mayNotBeDisposed(LocalScopeDisposableCreation disposable) { exists(Conf conf, DataFlow::ExprNode e | e.getExpr() = disposable and conf.isSource(e) and @@ -103,5 +103,5 @@ predicate mayNotBeDiposed(LocalScopeDisposableCreation disposable) { } from LocalScopeDisposableCreation disposable -where mayNotBeDiposed(disposable) +where mayNotBeDisposed(disposable) select disposable, "Disposable '" + disposable.getType() + "' is created here but is not disposed." From b66479c028abb73869d34952856629eec4cd066d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 2 Oct 2019 16:31:26 +0200 Subject: [PATCH 0341/1227] C#: Add change note --- change-notes/1.23/analysis-csharp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.23/analysis-csharp.md b/change-notes/1.23/analysis-csharp.md index 243a1efec8a..90d4bf06d37 100644 --- a/change-notes/1.23/analysis-csharp.md +++ b/change-notes/1.23/analysis-csharp.md @@ -16,6 +16,7 @@ The following changes in version 1.23 affect C# analysis in all applications. | **Query** | **Expected impact** | **Change** | |------------------------------|------------------------|-----------------------------------| | Dereferenced variable may be null (`cs/dereferenced-value-may-be-null`) | Fewer false positive results | More `null` checks are now taken into account, including `null` checks for `dynamic` expressions and `null` checks such as `object alwaysNull = null; if (x != alwaysNull) ...`. | +| Missing Dispose call on local IDisposable (`cs/local-not-disposed`) | Fewer false positive results | The query has been rewritten in order to identify more dispose patterns. For example, a local `IDisposable` that is disposed of by passing through a fluent API is no longer reported. | ## Removal of old queries From 384013e0dcc251a84578345e90d9e2ebf1bfe649 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 2 Oct 2019 17:13:00 +0200 Subject: [PATCH 0342/1227] Python: Add tests for reachability when using `nonlocal`. --- .../UnreachableCode.expected | 0 .../UnreachableCode.qlref | 1 + .../unreachable_nonlocal/nonlocal.py | 51 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.expected create mode 100644 python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.qlref create mode 100644 python/ql/test/query-tests/Statements/unreachable_nonlocal/nonlocal.py diff --git a/python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.expected b/python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.qlref b/python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.qlref new file mode 100644 index 00000000000..5b7891f0026 --- /dev/null +++ b/python/ql/test/query-tests/Statements/unreachable_nonlocal/UnreachableCode.qlref @@ -0,0 +1 @@ +Statements/UnreachableCode.ql diff --git a/python/ql/test/query-tests/Statements/unreachable_nonlocal/nonlocal.py b/python/ql/test/query-tests/Statements/unreachable_nonlocal/nonlocal.py new file mode 100644 index 00000000000..4f35f513178 --- /dev/null +++ b/python/ql/test/query-tests/Statements/unreachable_nonlocal/nonlocal.py @@ -0,0 +1,51 @@ + +def nonlocal_fp(): + test = False + def set_test(): + nonlocal test + test = True + set_test() + if test: + raise Exception("Foo") + + +# A couple of false negatives, roughly in order of complexity + +# test is nonlocal, but not mutated +def nonlocal_fn1(): + test = False + def set_test(): + nonlocal test + set_test() + if test: + raise Exception("Foo") + +# test is nonlocal and mutated, but does not change truthiness +def nonlocal_fn2(): + test = False + def set_test(): + nonlocal test + test = 0 + set_test() + if test: + raise Exception("Foo") + +# test is nonlocal and changes truthiness, but the function is never called +def nonlocal_fn3(): + test = False + def set_test(): + nonlocal test + test = True + if test: + raise Exception("Foo") + +# test is nonlocal and changes truthiness, but only if the given argument is true +def nonlocal_fn4(x): + test = False + def set_test(): + nonlocal test + test = True + if x: + set_test() + if test: + raise Exception("Foo") From 53f522c7f66284cdcb034bb5bdc5d4a4dd72fe1b Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 2 Oct 2019 10:11:58 -0700 Subject: [PATCH 0343/1227] C++: respond to PR comments and autoformat --- .../raw/internal/TranslatedCall.qll | 3 +- .../raw/internal/TranslatedElement.qll | 6 +- .../ir/ir/aliased_ssa_sanity.expected | 8 +- .../test/library-tests/ir/ir/raw_ir.expected | 164 +++++++++--------- .../library-tests/ir/ir/raw_sanity.expected | 8 +- .../ir/ir/unaliased_ssa_sanity.expected | 8 +- .../syntax-zoo/aliased_ssa_sanity.expected | 64 +++---- .../syntax-zoo/raw_sanity.expected | 78 ++++----- .../syntax-zoo/unaliased_ssa_sanity.expected | 70 ++++---- 9 files changed, 205 insertions(+), 204 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 0ee86785b52..08f782db9fc 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -378,7 +378,7 @@ class TranslatedStructorCallSideEffects extends TranslatedSideEffects { TranslatedStructorCallSideEffects() { getParent().(TranslatedStructorCall).hasQualifier() } override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type t, boolean isGLValue) { - opcode instanceof Opcode::IndirectMustWriteSideEffect and + opcode instanceof Opcode::IndirectMayWriteSideEffect and tag instanceof OnlyInstructionTag and t = expr.getTarget().getDeclaringType() and isGLValue = false @@ -566,4 +566,3 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff */ override Function getFunction() { result = arg.getEnclosingFunction() } } - diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index db34d69f4c8..81756678095 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -371,8 +371,10 @@ newtype TTranslatedElement = TTranslatedAllocationSize(NewOrNewArrayExpr newExpr) { not ignoreExpr(newExpr) } or // The declaration/initialization part of a `ConditionDeclExpr` TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or - // The side effects of a `Call` { - TTranslatedSideEffects(Call expr) { exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or expr instanceof ConstructorCall } or // A precise side effect of an argument to a `Call` { + // The side effects of a `Call` + TTranslatedSideEffects(Call expr) { + exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or expr instanceof ConstructorCall + } or // A precise side effect of an argument to a `Call` TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) { ( expr = call.getArgument(n).getFullyConverted() diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected index 283f13d4bf4..d86f9a05334 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 55a8cc56e01..b4a798f6e73 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -2715,14 +2715,14 @@ ir.cpp: # 616| r0_4(glval) = FunctionAddress[String] : # 616| v0_5(void) = Call : func:r0_4, this:r0_3 # 616| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 616| mu0_7(String) = ^IndirectMustWriteSideEffect : &:r0_3 +# 616| mu0_7(String) = ^IndirectMayWriteSideEffect : &:r0_3 # 617| r0_8(glval) = VariableAddress[s2] : # 617| r0_9(glval) = FunctionAddress[String] : # 617| r0_10(glval) = StringConstant["hello"] : # 617| r0_11(char *) = Convert : r0_10 # 617| v0_12(void) = Call : func:r0_9, this:r0_8, 0:r0_11 # 617| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -# 617| mu0_14(String) = ^IndirectMustWriteSideEffect : &:r0_8 +# 617| mu0_14(String) = ^IndirectMayWriteSideEffect : &:r0_8 # 617| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 # 617| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 # 618| r0_17(glval) = VariableAddress[s3] : @@ -2736,7 +2736,7 @@ ir.cpp: # 619| r0_25(char *) = Convert : r0_24 # 619| v0_26(void) = Call : func:r0_23, this:r0_22, 0:r0_25 # 619| mu0_27(unknown) = ^CallSideEffect : ~mu0_2 -# 619| mu0_28(String) = ^IndirectMustWriteSideEffect : &:r0_22 +# 619| mu0_28(String) = ^IndirectMayWriteSideEffect : &:r0_22 # 619| v0_29(void) = ^IndirectReadSideEffect[0] : &:r0_25, ~mu0_2 # 619| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_25 # 620| v0_31(void) = NoOp : @@ -2918,7 +2918,7 @@ ir.cpp: # 663| r0_8(glval) = FunctionAddress[String] : # 663| v0_9(void) = Call : func:r0_8, this:r0_7 # 663| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 663| mu0_11(String) = ^IndirectMustWriteSideEffect : &:r0_7 +# 663| mu0_11(String) = ^IndirectMayWriteSideEffect : &:r0_7 # 660| r0_12(glval) = FieldAddress[m_c] : r0_3 # 660| r0_13(char) = Constant[3] : # 660| mu0_14(char) = Store : &:r0_12, r0_13 @@ -2931,7 +2931,7 @@ ir.cpp: # 662| r0_21(char *) = Convert : r0_20 # 662| v0_22(void) = Call : func:r0_19, this:r0_18, 0:r0_21 # 662| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 -# 662| mu0_24(String) = ^IndirectMustWriteSideEffect : &:r0_18 +# 662| mu0_24(String) = ^IndirectMayWriteSideEffect : &:r0_18 # 662| v0_25(void) = ^IndirectReadSideEffect[0] : &:r0_21, ~mu0_2 # 662| mu0_26(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_21 # 664| v0_27(void) = NoOp : @@ -3206,7 +3206,7 @@ ir.cpp: # 731| r7_3(char *) = Convert : r7_2 # 731| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 731| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 731| mu7_6(String) = ^IndirectMustWriteSideEffect : &:r7_0 +# 731| mu7_6(String) = ^IndirectMayWriteSideEffect : &:r7_0 # 731| v7_7(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 # 731| mu7_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 # 731| v7_9(void) = ThrowValue : &:r7_0, ~mu0_2 @@ -3232,7 +3232,7 @@ ir.cpp: # 736| r10_5(char *) = Load : &:r10_4, ~mu0_2 # 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 # 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 736| mu10_8(String) = ^IndirectMustWriteSideEffect : &:r10_2 +# 736| mu10_8(String) = ^IndirectMayWriteSideEffect : &:r10_2 # 736| v10_9(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 # 736| mu10_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 # 736| v10_11(void) = ThrowValue : &:r10_2, ~mu0_2 @@ -3289,37 +3289,37 @@ ir.cpp: # 745| void Base::Base(Base const&) # 745| Block 0 -# 745| v0_0(void) = EnterFunction : -# 745| mu0_1(unknown) = AliasedDefinition : -# 745| mu0_2(unknown) = UnmodeledDefinition : -# 745| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 -# 745| r0_6(glval) = FieldAddress[base_s] : r0_3 -# 745| r0_7(glval) = FunctionAddress[String] : -# 745| v0_8(void) = Call : func:r0_7, this:r0_6 -# 745| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 -# 745| mu0_10(String) = ^IndirectMustWriteSideEffect : &:r0_6 -# 745| v0_11(void) = NoOp : -# 745| v0_12(void) = ReturnVoid : -# 745| v0_13(void) = UnmodeledUse : mu* -# 745| v0_14(void) = ExitFunction : +# 745| v0_0(void) = EnterFunction : +# 745| mu0_1(unknown) = AliasedDefinition : +# 745| mu0_2(unknown) = UnmodeledDefinition : +# 745| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 +# 745| r0_6(glval) = FieldAddress[base_s] : r0_3 +# 745| r0_7(glval) = FunctionAddress[String] : +# 745| v0_8(void) = Call : func:r0_7, this:r0_6 +# 745| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 +# 745| mu0_10(String) = ^IndirectMayWriteSideEffect : &:r0_6 +# 745| v0_11(void) = NoOp : +# 745| v0_12(void) = ReturnVoid : +# 745| v0_13(void) = UnmodeledUse : mu* +# 745| v0_14(void) = ExitFunction : # 748| void Base::Base() # 748| Block 0 -# 748| v0_0(void) = EnterFunction : -# 748| mu0_1(unknown) = AliasedDefinition : -# 748| mu0_2(unknown) = UnmodeledDefinition : -# 748| r0_3(glval) = InitializeThis : -# 748| r0_4(glval) = FieldAddress[base_s] : r0_3 -# 748| r0_5(glval) = FunctionAddress[String] : -# 748| v0_6(void) = Call : func:r0_5, this:r0_4 -# 748| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 748| mu0_8(String) = ^IndirectMustWriteSideEffect : &:r0_4 -# 749| v0_9(void) = NoOp : -# 748| v0_10(void) = ReturnVoid : -# 748| v0_11(void) = UnmodeledUse : mu* -# 748| v0_12(void) = ExitFunction : +# 748| v0_0(void) = EnterFunction : +# 748| mu0_1(unknown) = AliasedDefinition : +# 748| mu0_2(unknown) = UnmodeledDefinition : +# 748| r0_3(glval) = InitializeThis : +# 748| r0_4(glval) = FieldAddress[base_s] : r0_3 +# 748| r0_5(glval) = FunctionAddress[String] : +# 748| v0_6(void) = Call : func:r0_5, this:r0_4 +# 748| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +# 748| mu0_8(String) = ^IndirectMayWriteSideEffect : &:r0_4 +# 749| v0_9(void) = NoOp : +# 748| v0_10(void) = ReturnVoid : +# 748| v0_11(void) = UnmodeledUse : mu* +# 748| v0_12(void) = ExitFunction : # 750| void Base::~Base() # 750| Block 0 @@ -3386,12 +3386,12 @@ ir.cpp: # 757| r0_5(glval) = FunctionAddress[Base] : # 757| v0_6(void) = Call : func:r0_5, this:r0_4 # 757| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 757| mu0_8(Base) = ^IndirectMustWriteSideEffect : &:r0_4 +# 757| mu0_8(Base) = ^IndirectMayWriteSideEffect : &:r0_4 # 757| r0_9(glval) = FieldAddress[middle_s] : r0_3 # 757| r0_10(glval) = FunctionAddress[String] : # 757| v0_11(void) = Call : func:r0_10, this:r0_9 # 757| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 757| mu0_13(String) = ^IndirectMustWriteSideEffect : &:r0_9 +# 757| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_9 # 758| v0_14(void) = NoOp : # 757| v0_15(void) = ReturnVoid : # 757| v0_16(void) = UnmodeledUse : mu* @@ -3466,12 +3466,12 @@ ir.cpp: # 766| r0_5(glval) = FunctionAddress[Middle] : # 766| v0_6(void) = Call : func:r0_5, this:r0_4 # 766| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 766| mu0_8(Middle) = ^IndirectMustWriteSideEffect : &:r0_4 +# 766| mu0_8(Middle) = ^IndirectMayWriteSideEffect : &:r0_4 # 766| r0_9(glval) = FieldAddress[derived_s] : r0_3 # 766| r0_10(glval) = FunctionAddress[String] : # 766| v0_11(void) = Call : func:r0_10, this:r0_9 # 766| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 766| mu0_13(String) = ^IndirectMustWriteSideEffect : &:r0_9 +# 766| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_9 # 767| v0_14(void) = NoOp : # 766| v0_15(void) = ReturnVoid : # 766| v0_16(void) = UnmodeledUse : mu* @@ -3506,12 +3506,12 @@ ir.cpp: # 775| r0_5(glval) = FunctionAddress[Base] : # 775| v0_6(void) = Call : func:r0_5, this:r0_4 # 775| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 775| mu0_8(Base) = ^IndirectMustWriteSideEffect : &:r0_4 +# 775| mu0_8(Base) = ^IndirectMayWriteSideEffect : &:r0_4 # 775| r0_9(glval) = FieldAddress[middlevb1_s] : r0_3 # 775| r0_10(glval) = FunctionAddress[String] : # 775| v0_11(void) = Call : func:r0_10, this:r0_9 # 775| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 775| mu0_13(String) = ^IndirectMustWriteSideEffect : &:r0_9 +# 775| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_9 # 776| v0_14(void) = NoOp : # 775| v0_15(void) = ReturnVoid : # 775| v0_16(void) = UnmodeledUse : mu* @@ -3546,12 +3546,12 @@ ir.cpp: # 784| r0_5(glval) = FunctionAddress[Base] : # 784| v0_6(void) = Call : func:r0_5, this:r0_4 # 784| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 784| mu0_8(Base) = ^IndirectMustWriteSideEffect : &:r0_4 +# 784| mu0_8(Base) = ^IndirectMayWriteSideEffect : &:r0_4 # 784| r0_9(glval) = FieldAddress[middlevb2_s] : r0_3 # 784| r0_10(glval) = FunctionAddress[String] : # 784| v0_11(void) = Call : func:r0_10, this:r0_9 # 784| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 784| mu0_13(String) = ^IndirectMustWriteSideEffect : &:r0_9 +# 784| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_9 # 785| v0_14(void) = NoOp : # 784| v0_15(void) = ReturnVoid : # 784| v0_16(void) = UnmodeledUse : mu* @@ -3586,22 +3586,22 @@ ir.cpp: # 793| r0_5(glval) = FunctionAddress[Base] : # 793| v0_6(void) = Call : func:r0_5, this:r0_4 # 793| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 793| mu0_8(Base) = ^IndirectMustWriteSideEffect : &:r0_4 +# 793| mu0_8(Base) = ^IndirectMayWriteSideEffect : &:r0_4 # 793| r0_9(glval) = ConvertToBase[DerivedVB : MiddleVB1] : r0_3 # 793| r0_10(glval) = FunctionAddress[MiddleVB1] : # 793| v0_11(void) = Call : func:r0_10, this:r0_9 # 793| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 793| mu0_13(MiddleVB1) = ^IndirectMustWriteSideEffect : &:r0_9 +# 793| mu0_13(MiddleVB1) = ^IndirectMayWriteSideEffect : &:r0_9 # 793| r0_14(glval) = ConvertToBase[DerivedVB : MiddleVB2] : r0_3 # 793| r0_15(glval) = FunctionAddress[MiddleVB2] : # 793| v0_16(void) = Call : func:r0_15, this:r0_14 # 793| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 -# 793| mu0_18(MiddleVB2) = ^IndirectMustWriteSideEffect : &:r0_14 +# 793| mu0_18(MiddleVB2) = ^IndirectMayWriteSideEffect : &:r0_14 # 793| r0_19(glval) = FieldAddress[derivedvb_s] : r0_3 # 793| r0_20(glval) = FunctionAddress[String] : # 793| v0_21(void) = Call : func:r0_20, this:r0_19 # 793| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -# 793| mu0_23(String) = ^IndirectMustWriteSideEffect : &:r0_19 +# 793| mu0_23(String) = ^IndirectMayWriteSideEffect : &:r0_19 # 794| v0_24(void) = NoOp : # 793| v0_25(void) = ReturnVoid : # 793| v0_26(void) = UnmodeledUse : mu* @@ -3643,17 +3643,17 @@ ir.cpp: # 800| r0_4(glval) = FunctionAddress[Base] : # 800| v0_5(void) = Call : func:r0_4, this:r0_3 # 800| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 800| mu0_7(Base) = ^IndirectMustWriteSideEffect : &:r0_3 +# 800| mu0_7(Base) = ^IndirectMayWriteSideEffect : &:r0_3 # 801| r0_8(glval) = VariableAddress[m] : # 801| r0_9(glval) = FunctionAddress[Middle] : # 801| v0_10(void) = Call : func:r0_9, this:r0_8 # 801| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 801| mu0_12(Middle) = ^IndirectMustWriteSideEffect : &:r0_8 +# 801| mu0_12(Middle) = ^IndirectMayWriteSideEffect : &:r0_8 # 802| r0_13(glval) = VariableAddress[d] : # 802| r0_14(glval) = FunctionAddress[Derived] : # 802| v0_15(void) = Call : func:r0_14, this:r0_13 # 802| mu0_16(unknown) = ^CallSideEffect : ~mu0_2 -# 802| mu0_17(Derived) = ^IndirectMustWriteSideEffect : &:r0_13 +# 802| mu0_17(Derived) = ^IndirectMayWriteSideEffect : &:r0_13 # 804| r0_18(glval) = VariableAddress[pb] : # 804| r0_19(glval) = VariableAddress[b] : # 804| mu0_20(Base *) = Store : &:r0_18, r0_19 @@ -3680,7 +3680,7 @@ ir.cpp: # 809| r0_41(glval) = ConvertToBase[Middle : Base] : r0_40 # 809| v0_42(void) = Call : func:r0_39, 0:r0_41 # 809| mu0_43(unknown) = ^CallSideEffect : ~mu0_2 -# 809| mu0_44(Base) = ^IndirectMustWriteSideEffect : +# 809| mu0_44(Base) = ^IndirectMayWriteSideEffect : # 809| v0_45(void) = ^IndirectReadSideEffect[0] : &:r0_41, ~mu0_2 # 809| mu0_46(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_41 # 809| r0_47(glval) = Convert : v0_42 @@ -3697,7 +3697,7 @@ ir.cpp: # 810| r0_58(glval) = ConvertToBase[Middle : Base] : r0_57 # 810| v0_59(void) = Call : func:r0_56, 0:r0_58 # 810| mu0_60(unknown) = ^CallSideEffect : ~mu0_2 -# 810| mu0_61(Base) = ^IndirectMustWriteSideEffect : +# 810| mu0_61(Base) = ^IndirectMayWriteSideEffect : # 810| v0_62(void) = ^IndirectReadSideEffect[0] : &:r0_58, ~mu0_2 # 810| mu0_63(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_58 # 810| r0_64(glval) = Convert : v0_59 @@ -3783,7 +3783,7 @@ ir.cpp: # 823| r0_144(glval) = ConvertToBase[Middle : Base] : r0_143 # 823| v0_145(void) = Call : func:r0_141, 0:r0_144 # 823| mu0_146(unknown) = ^CallSideEffect : ~mu0_2 -# 823| mu0_147(Base) = ^IndirectMustWriteSideEffect : +# 823| mu0_147(Base) = ^IndirectMayWriteSideEffect : # 823| v0_148(void) = ^IndirectReadSideEffect[0] : &:r0_144, ~mu0_2 # 823| mu0_149(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_144 # 823| r0_150(glval) = Convert : v0_145 @@ -3801,7 +3801,7 @@ ir.cpp: # 824| r0_162(glval) = ConvertToBase[Middle : Base] : r0_161 # 824| v0_163(void) = Call : func:r0_159, 0:r0_162 # 824| mu0_164(unknown) = ^CallSideEffect : ~mu0_2 -# 824| mu0_165(Base) = ^IndirectMustWriteSideEffect : +# 824| mu0_165(Base) = ^IndirectMayWriteSideEffect : # 824| v0_166(void) = ^IndirectReadSideEffect[0] : &:r0_162, ~mu0_2 # 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_162 # 824| r0_168(glval) = Convert : v0_163 @@ -3917,7 +3917,7 @@ ir.cpp: # 846| r0_5(glval) = FunctionAddress[PolymorphicBase] : # 846| v0_6(void) = Call : func:r0_5, this:r0_4 # 846| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 846| mu0_8(PolymorphicBase) = ^IndirectMustWriteSideEffect : &:r0_4 +# 846| mu0_8(PolymorphicBase) = ^IndirectMayWriteSideEffect : &:r0_4 # 846| v0_9(void) = NoOp : # 846| v0_10(void) = ReturnVoid : # 846| v0_11(void) = UnmodeledUse : mu* @@ -3947,12 +3947,12 @@ ir.cpp: #-----| r0_4(glval) = FunctionAddress[PolymorphicBase] : #-----| v0_5(void) = Call : func:r0_4, this:r0_3 #-----| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -#-----| mu0_7(PolymorphicBase) = ^IndirectMustWriteSideEffect : &:r0_3 +#-----| mu0_7(PolymorphicBase) = ^IndirectMayWriteSideEffect : &:r0_3 # 851| r0_8(glval) = VariableAddress[d] : # 851| r0_9(glval) = FunctionAddress[PolymorphicDerived] : # 851| v0_10(void) = Call : func:r0_9, this:r0_8 # 851| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 851| mu0_12(PolymorphicDerived) = ^IndirectMustWriteSideEffect : &:r0_8 +# 851| mu0_12(PolymorphicDerived) = ^IndirectMayWriteSideEffect : &:r0_8 # 853| r0_13(glval) = VariableAddress[pb] : # 853| r0_14(glval) = VariableAddress[b] : # 853| mu0_15(PolymorphicBase *) = Store : &:r0_13, r0_14 @@ -4003,7 +4003,7 @@ ir.cpp: # 868| r0_6(char *) = Convert : r0_5 # 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 # 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 868| mu0_9(String) = ^IndirectMustWriteSideEffect : &:r0_3 +# 868| mu0_9(String) = ^IndirectMayWriteSideEffect : &:r0_3 # 868| v0_10(void) = ^IndirectReadSideEffect[0] : &:r0_6, ~mu0_2 # 868| mu0_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6 # 869| v0_12(void) = NoOp : @@ -4210,7 +4210,7 @@ ir.cpp: # 944| r0_26(glval) = FunctionAddress[String] : # 944| v0_27(void) = Call : func:r0_26, this:r0_25 # 944| mu0_28(unknown) = ^CallSideEffect : ~mu0_2 -# 944| mu0_29(String) = ^IndirectMustWriteSideEffect : &:r0_25 +# 944| mu0_29(String) = ^IndirectMayWriteSideEffect : &:r0_25 # 945| r0_30(glval) = FunctionAddress[operator new] : # 945| r0_31(unsigned long) = Constant[8] : # 945| r0_32(float) = Constant[1.0] : @@ -4222,7 +4222,7 @@ ir.cpp: # 945| r0_38(char *) = Convert : r0_37 # 945| v0_39(void) = Call : func:r0_36, this:r0_35, 0:r0_38 # 945| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 -# 945| mu0_41(String) = ^IndirectMustWriteSideEffect : &:r0_35 +# 945| mu0_41(String) = ^IndirectMayWriteSideEffect : &:r0_35 # 945| v0_42(void) = ^IndirectReadSideEffect[0] : &:r0_38, ~mu0_2 # 945| mu0_43(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_38 # 946| r0_44(glval) = FunctionAddress[operator new] : @@ -4721,7 +4721,7 @@ ir.cpp: #-----| r0_38(glval) = FunctionAddress[String] : #-----| v0_39(void) = Call : func:r0_38, this:r0_37 #-----| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 -#-----| mu0_41(String) = ^IndirectMustWriteSideEffect : &:r0_37 +#-----| mu0_41(String) = ^IndirectMayWriteSideEffect : &:r0_37 # 1036| r0_42(glval) = FieldAddress[x] : r0_35 #-----| r0_43(glval) = VariableAddress[x] : #-----| r0_44(int) = Load : &:r0_43, ~mu0_2 @@ -4729,7 +4729,7 @@ ir.cpp: # 1036| r0_46(decltype([...](...){...})) = Load : &:r0_35, ~mu0_2 # 1036| v0_47(void) = Call : func:r0_34, this:r0_33, 0:r0_46 # 1036| mu0_48(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| mu0_49(decltype([...](...){...})) = ^IndirectMustWriteSideEffect : &:r0_33 +# 1036| mu0_49(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_33 # 1036| v0_50(void) = ^IndirectReadSideEffect[0] : &:r0_46, ~mu0_2 # 1036| mu0_51(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_46 # 1037| r0_52(glval) = VariableAddress[lambda_val] : @@ -4765,11 +4765,11 @@ ir.cpp: #-----| r0_82(glval) = FunctionAddress[String] : #-----| v0_83(void) = Call : func:r0_82, this:r0_81 #-----| mu0_84(unknown) = ^CallSideEffect : ~mu0_2 -#-----| mu0_85(String) = ^IndirectMustWriteSideEffect : &:r0_81 +#-----| mu0_85(String) = ^IndirectMayWriteSideEffect : &:r0_81 # 1040| r0_86(decltype([...](...){...})) = Load : &:r0_79, ~mu0_2 # 1040| v0_87(void) = Call : func:r0_78, this:r0_77, 0:r0_86 # 1040| mu0_88(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| mu0_89(decltype([...](...){...})) = ^IndirectMustWriteSideEffect : &:r0_77 +# 1040| mu0_89(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_77 # 1040| v0_90(void) = ^IndirectReadSideEffect[0] : &:r0_86, ~mu0_2 # 1040| mu0_91(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_86 # 1041| r0_92(glval) = VariableAddress[lambda_val_explicit] : @@ -4984,21 +4984,21 @@ ir.cpp: # 1040| void (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::(constructor)((void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)&&) # 1040| Block 0 -# 1040| v0_0(void) = EnterFunction : -# 1040| mu0_1(unknown) = AliasedDefinition : -# 1040| mu0_2(unknown) = UnmodeledDefinition : -# 1040| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(lambda [] type at line 1040, col. 30 &&) = InitializeParameter[p#0] : &:r0_4 -# 1040| r0_6(glval) = FieldAddress[s] : r0_3 -# 1040| r0_7(glval) = FunctionAddress[String] : -# 1040| v0_8(void) = Call : func:r0_7, this:r0_6 -# 1040| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| mu0_10(String) = ^IndirectMustWriteSideEffect : &:r0_6 -# 1040| v0_11(void) = NoOp : -# 1040| v0_12(void) = ReturnVoid : -# 1040| v0_13(void) = UnmodeledUse : mu* -# 1040| v0_14(void) = ExitFunction : +# 1040| v0_0(void) = EnterFunction : +# 1040| mu0_1(unknown) = AliasedDefinition : +# 1040| mu0_2(unknown) = UnmodeledDefinition : +# 1040| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(lambda [] type at line 1040, col. 30 &&) = InitializeParameter[p#0] : &:r0_4 +# 1040| r0_6(glval) = FieldAddress[s] : r0_3 +# 1040| r0_7(glval) = FunctionAddress[String] : +# 1040| v0_8(void) = Call : func:r0_7, this:r0_6 +# 1040| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 +# 1040| mu0_10(String) = ^IndirectMayWriteSideEffect : &:r0_6 +# 1040| v0_11(void) = NoOp : +# 1040| v0_12(void) = ReturnVoid : +# 1040| v0_13(void) = UnmodeledUse : mu* +# 1040| v0_14(void) = ExitFunction : # 1040| void (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::~() # 1040| Block 0 @@ -5417,7 +5417,7 @@ ir.cpp: # 1140| r7_3(char *) = Convert : r7_2 # 1140| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 1140| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1140| mu7_6(String) = ^IndirectMustWriteSideEffect : &:r7_0 +# 1140| mu7_6(String) = ^IndirectMayWriteSideEffect : &:r7_0 # 1140| v7_7(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 # 1140| mu7_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 # 1140| v7_9(void) = ThrowValue : &:r7_0, ~mu0_2 @@ -5443,7 +5443,7 @@ ir.cpp: # 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2 # 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 # 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 1145| mu10_8(String) = ^IndirectMustWriteSideEffect : &:r10_2 +# 1145| mu10_8(String) = ^IndirectMayWriteSideEffect : &:r10_2 # 1145| v10_9(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 # 1145| mu10_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 # 1145| v10_11(void) = ThrowValue : &:r10_2, ~mu0_2 @@ -5585,7 +5585,7 @@ perf-regression.cpp: # 10| r0_9(glval) = FunctionAddress[Big] : # 10| v0_10(void) = Call : func:r0_9, this:r0_8 # 10| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 10| mu0_12(Big) = ^IndirectMustWriteSideEffect : &:r0_8 +# 10| mu0_12(Big) = ^IndirectMayWriteSideEffect : &:r0_8 # 10| mu0_13(Big *) = Store : &:r0_3, r0_8 # 12| r0_14(glval) = VariableAddress[#return] : # 12| r0_15(int) = Constant[0] : diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected index 283f13d4bf4..d86f9a05334 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected index 283f13d4bf4..d86f9a05334 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index c7c6e112878..552c0693ad4 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -1,32 +1,32 @@ missingOperand -| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:17:82:55 | IndirectMustWriteSideEffect: call to (constructor) | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMustWriteSideEffect: call to C | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:17:82:55 | IndirectMayWriteSideEffect: call to (constructor) | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | unexpectedOperand duplicateOperand @@ -36,10 +36,10 @@ missingOperandType instructionWithoutSuccessor | VacuousDestructorCall.cpp:2:29:2:29 | InitializeParameter: y | | assume0.cpp:7:2:7:2 | Chi: call to f | -| condition_decls.cpp:16:19:16:20 | IndirectMustWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:26:23:26:24 | IndirectMustWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | IndirectMustWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | | cpp17.cpp:15:11:15:21 | Convert: (void *)... | | misc.c:171:10:171:13 | Uninitialized: definition of str2 | | misc.c:219:47:219:48 | InitializeParameter: sp | diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index 6d832e6a831..2b3d6b07fc1 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -3,34 +3,34 @@ missingOperand | condition_decls.cpp:26:3:36:3 | Switch: switch (...) ... | Instruction 'Switch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | | condition_decls.cpp:41:9:41:23 | ConditionalBranch: (condition decl) | Instruction 'ConditionalBranch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | | condition_decls.cpp:48:39:48:53 | ConditionalBranch: (condition decl) | Instruction 'ConditionalBranch' is missing an expected operand with tag 'Condition' in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | -| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:17:82:55 | IndirectMustWriteSideEffect: call to (constructor) | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMustWriteSideEffect: call to C | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:17:82:55 | IndirectMayWriteSideEffect: call to (constructor) | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | | misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | @@ -54,11 +54,11 @@ instructionWithoutSuccessor | VacuousDestructorCall.cpp:4:3:4:3 | Load: y | | assume0.cpp:7:2:7:2 | CallSideEffect: call to f | | assume0.cpp:9:11:9:11 | Constant: (bool)... | -| condition_decls.cpp:16:19:16:20 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | | condition_decls.cpp:26:19:26:20 | IndirectMayWriteSideEffect: bi | -| condition_decls.cpp:26:23:26:24 | IndirectMustWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | IndirectMustWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | | cpp17.cpp:15:11:15:21 | Convert: (void *)... | | file://:0:0:0:0 | CompareNE: (bool)... | | file://:0:0:0:0 | CompareNE: (bool)... | @@ -82,16 +82,16 @@ instructionWithoutSuccessor | ms_try_except.cpp:17:13:17:17 | Store: ... = ... | | ms_try_except.cpp:19:17:19:21 | Sub: ... - ... | | ms_try_except.cpp:20:9:20:13 | Store: ... = ... | -| ms_try_mix.cpp:11:12:11:15 | IndirectMustWriteSideEffect: call to C | +| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | | ms_try_mix.cpp:16:13:16:19 | ThrowValue: throw ... | -| ms_try_mix.cpp:18:16:18:19 | IndirectMustWriteSideEffect: call to C | +| ms_try_mix.cpp:18:16:18:19 | IndirectMayWriteSideEffect: call to C | | ms_try_mix.cpp:20:15:20:39 | Constant: 1 | -| ms_try_mix.cpp:21:16:21:19 | IndirectMustWriteSideEffect: call to C | -| ms_try_mix.cpp:28:12:28:15 | IndirectMustWriteSideEffect: call to C | +| ms_try_mix.cpp:21:16:21:19 | IndirectMayWriteSideEffect: call to C | +| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | | ms_try_mix.cpp:33:13:33:19 | ThrowValue: throw ... | -| ms_try_mix.cpp:35:16:35:19 | IndirectMustWriteSideEffect: call to C | -| ms_try_mix.cpp:38:16:38:19 | IndirectMustWriteSideEffect: call to C | -| ms_try_mix.cpp:48:10:48:13 | IndirectMustWriteSideEffect: call to C | +| ms_try_mix.cpp:35:16:35:19 | IndirectMayWriteSideEffect: call to C | +| ms_try_mix.cpp:38:16:38:19 | IndirectMayWriteSideEffect: call to C | +| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | | ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... | | ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } | | pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} | diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected index 51c69186d92..e984a30e3c5 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -1,32 +1,32 @@ missingOperand -| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMustWriteSideEffect: call to C1 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMustWriteSideEffect: call to C2 | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:17:82:55 | IndirectMustWriteSideEffect: call to (constructor) | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMustWriteSideEffect: call to Val | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMustWriteSideEffect: call to C | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMustWriteSideEffect: call to Base | Instruction 'IndirectMustWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:17:82:55 | IndirectMayWriteSideEffect: call to (constructor) | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | | misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | unexpectedOperand duplicateOperand @@ -45,17 +45,17 @@ missingOperandType instructionWithoutSuccessor | VacuousDestructorCall.cpp:2:29:2:29 | InitializeParameter: y | | assume0.cpp:7:2:7:2 | CallSideEffect: call to f | -| condition_decls.cpp:16:19:16:20 | IndirectMustWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:26:23:26:24 | IndirectMustWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | IndirectMustWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | IndirectMustWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | +| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | | cpp17.cpp:15:11:15:21 | Convert: (void *)... | | misc.c:171:10:171:13 | Uninitialized: definition of str2 | | misc.c:219:47:219:48 | InitializeParameter: sp | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| ms_try_mix.cpp:11:12:11:15 | IndirectMustWriteSideEffect: call to C | -| ms_try_mix.cpp:28:12:28:15 | IndirectMustWriteSideEffect: call to C | -| ms_try_mix.cpp:48:10:48:13 | IndirectMustWriteSideEffect: call to C | +| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | +| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | +| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | | pointer_to_member.cpp:36:11:36:30 | FieldAddress: {...} | | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | From 98b97b09be3ac7aa0a9d67f61ee5a40da84e6ea7 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 11 Jul 2019 13:48:51 -0700 Subject: [PATCH 0344/1227] C++: add hasGlobalOrStdName to Declaration --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index fa061b239cc..55d9a39dbdc 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -119,6 +119,11 @@ abstract class Declaration extends Locatable, @declaration { /** Holds if this declaration has the given name in the global namespace. */ predicate hasGlobalName(string name) { this.hasQualifiedName("", "", name) } + /** Holds if this declaration has the given name in the global namespace or the `std` namespace. */ + predicate hasGlobalOrStdName(string name) { + this.hasQualifiedName("std", "", name) + } + /** Gets a specifier of this declaration. */ abstract Specifier getASpecifier(); From bff68a00ac074a08fce4112a6f59288a440f09f5 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 11 Jul 2019 15:57:26 -0700 Subject: [PATCH 0345/1227] C++: Add Declaration.hasStdName --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 55d9a39dbdc..7c38acc564e 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -119,9 +119,17 @@ abstract class Declaration extends Locatable, @declaration { /** Holds if this declaration has the given name in the global namespace. */ predicate hasGlobalName(string name) { this.hasQualifiedName("", "", name) } + + /** Holds if this declaration has the given name in the `std` namespace. */ + predicate hasStdName(string name) { + this.hasQualifiedName("std", "", name) + } + /** Holds if this declaration has the given name in the global namespace or the `std` namespace. */ predicate hasGlobalOrStdName(string name) { - this.hasQualifiedName("std", "", name) + this.hasGlobalName(name) + or + this.hasStdName(name) } /** Gets a specifier of this declaration. */ From 03f72d207cbcc02cedc5973d9ffcb0cd2f00ea00 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 11 Jul 2019 16:00:41 -0700 Subject: [PATCH 0346/1227] C++: use Declaration.hasGlobalOrStdName --- .../src/Critical/DescriptorMayNotBeClosed.ql | 2 +- cpp/ql/src/Critical/DescriptorNeverClosed.ql | 2 +- cpp/ql/src/Critical/MemoryMayNotBeFreed.ql | 4 +- cpp/ql/src/Critical/OverflowCalculated.ql | 9 ++- cpp/ql/src/Critical/OverflowDestination.ql | 2 +- cpp/ql/src/Critical/OverflowStatic.ql | 16 ++--- cpp/ql/src/Critical/SizeCheck.ql | 4 +- cpp/ql/src/Critical/SizeCheck2.ql | 4 +- cpp/ql/src/Critical/UseAfterFree.ql | 2 +- cpp/ql/src/DefaultOptions.qll | 4 +- .../src/Security/CWE/CWE-022/TaintedPath.ql | 7 ++- cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql | 4 +- .../CWE/CWE-121/UnterminatedVarargsCall.ql | 2 +- .../CWE/CWE-131/NoSpaceForZeroTerminator.ql | 5 +- .../Security/CWE/CWE-497/ExposedSystemData.ql | 60 +++++++++---------- .../CWE/CWE-676/DangerousFunctionOverflow.ql | 2 +- cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql | 4 +- cpp/ql/src/jsf/4.10 Classes/AV Rule 97.ql | 4 +- cpp/ql/src/semmle/code/cpp/Function.qll | 2 +- cpp/ql/src/semmle/code/cpp/commons/Alloc.qll | 16 +++-- .../semmle/code/cpp/commons/Environment.qll | 2 +- cpp/ql/src/semmle/code/cpp/commons/File.qll | 12 ++-- .../code/cpp/commons/StringAnalysis.qll | 4 +- .../code/cpp/controlflow/Dereferenced.qll | 2 +- .../semmle/code/cpp/controlflow/Nullness.qll | 4 +- .../cpp/models/implementations/Printf.qll | 22 +++---- .../code/cpp/models/implementations/Pure.qll | 4 +- .../code/cpp/security/CommandExecution.qll | 2 +- .../semmle/code/cpp/security/FileWrite.qll | 2 +- .../semmle/code/cpp/security/OutputWrite.qll | 4 +- .../src/semmle/code/cpp/security/Security.qll | 14 +++-- .../code/cpp/security/TaintTracking.qll | 36 +++++------ 32 files changed, 138 insertions(+), 125 deletions(-) diff --git a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql index 9c93e066119..47401c6eea5 100644 --- a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql +++ b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql @@ -13,7 +13,7 @@ import semmle.code.cpp.pointsto.PointsTo import Negativity predicate closeCall(FunctionCall fc, Variable v) { - fc.getTarget().hasGlobalName("close") and v.getAnAccess() = fc.getArgument(0) + fc.getTarget().hasGlobalOrStdName("close") and v.getAnAccess() = fc.getArgument(0) or exists(FunctionCall midcall, Function mid, int arg | fc.getArgument(arg) = v.getAnAccess() and diff --git a/cpp/ql/src/Critical/DescriptorNeverClosed.ql b/cpp/ql/src/Critical/DescriptorNeverClosed.ql index b52af1bf2a3..f06708f4ae3 100644 --- a/cpp/ql/src/Critical/DescriptorNeverClosed.ql +++ b/cpp/ql/src/Critical/DescriptorNeverClosed.ql @@ -13,7 +13,7 @@ import semmle.code.cpp.pointsto.PointsTo predicate closed(Expr e) { exists(FunctionCall fc | - fc.getTarget().hasGlobalName("close") and + fc.getTarget().hasGlobalOrStdName("close") and fc.getArgument(0) = e ) } diff --git a/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql b/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql index 9bba8e9896d..2bede681912 100644 --- a/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql +++ b/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql @@ -53,7 +53,7 @@ predicate allocCallOrIndirect(Expr e) { * can cause memory leaks. */ predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode verified) { - reallocCall.getTarget().hasGlobalName("realloc") and + reallocCall.getTarget().hasGlobalOrStdName("realloc") and reallocCall.getArgument(0) = v.getAnAccess() and ( exists(Variable newV, ControlFlowNode node | @@ -79,7 +79,7 @@ predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode predicate freeCallOrIndirect(ControlFlowNode n, Variable v) { // direct free call freeCall(n, v.getAnAccess()) and - not n.(FunctionCall).getTarget().hasGlobalName("realloc") + not n.(FunctionCall).getTarget().hasGlobalOrStdName("realloc") or // verified realloc call verifiedRealloc(_, v, n) diff --git a/cpp/ql/src/Critical/OverflowCalculated.ql b/cpp/ql/src/Critical/OverflowCalculated.ql index 36ee0140cf7..c528be8ca24 100644 --- a/cpp/ql/src/Critical/OverflowCalculated.ql +++ b/cpp/ql/src/Critical/OverflowCalculated.ql @@ -14,8 +14,7 @@ import cpp class MallocCall extends FunctionCall { MallocCall() { - this.getTarget().hasGlobalName("malloc") or - this.getTarget().hasQualifiedName("std", "malloc") + this.getTarget().hasGlobalOrStdName("malloc") } Expr getAllocatedSize() { @@ -36,12 +35,12 @@ predicate spaceProblem(FunctionCall append, string msg) { malloc.getAllocatedSize() = add and buffer.getAnAccess() = strlen.getStringExpr() and ( - insert.getTarget().hasGlobalName("strcpy") or + insert.getTarget().hasGlobalOrStdName("strcpy") or insert.getTarget().hasGlobalName("strncpy") ) and ( - append.getTarget().hasGlobalName("strcat") or - append.getTarget().hasGlobalName("strncat") + append.getTarget().hasGlobalOrStdName("strcat") or + append.getTarget().hasGlobalOrStdName("strncat") ) and malloc.getASuccessor+() = insert and insert.getArgument(1) = buffer.getAnAccess() and diff --git a/cpp/ql/src/Critical/OverflowDestination.ql b/cpp/ql/src/Critical/OverflowDestination.ql index d7b02b5d8d5..ad925daed62 100644 --- a/cpp/ql/src/Critical/OverflowDestination.ql +++ b/cpp/ql/src/Critical/OverflowDestination.ql @@ -25,7 +25,7 @@ import semmle.code.cpp.security.TaintTracking predicate sourceSized(FunctionCall fc, Expr src) { exists(string name | (name = "strncpy" or name = "strncat" or name = "memcpy" or name = "memmove") and - fc.getTarget().hasGlobalName(name) + fc.getTarget().hasGlobalOrStdName(name) ) and exists(Expr dest, Expr size, Variable v | fc.getArgument(0) = dest and diff --git a/cpp/ql/src/Critical/OverflowStatic.ql b/cpp/ql/src/Critical/OverflowStatic.ql index 1892d5acff1..8cee2500797 100644 --- a/cpp/ql/src/Critical/OverflowStatic.ql +++ b/cpp/ql/src/Critical/OverflowStatic.ql @@ -58,21 +58,21 @@ predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) { } predicate bufferAndSizeFunction(Function f, int buf, int size) { - f.hasGlobalName("read") and buf = 1 and size = 2 + f.hasGlobalOrStdName("read") and buf = 1 and size = 2 or - f.hasGlobalName("fgets") and buf = 0 and size = 1 + f.hasGlobalOrStdName("fgets") and buf = 0 and size = 1 or - f.hasGlobalName("strncpy") and buf = 0 and size = 2 + f.hasGlobalOrStdName("strncpy") and buf = 0 and size = 2 or - f.hasGlobalName("strncat") and buf = 0 and size = 2 + f.hasGlobalOrStdName("strncat") and buf = 0 and size = 2 or - f.hasGlobalName("memcpy") and buf = 0 and size = 2 + f.hasGlobalOrStdName("memcpy") and buf = 0 and size = 2 or - f.hasGlobalName("memmove") and buf = 0 and size = 2 + f.hasGlobalOrStdName("memmove") and buf = 0 and size = 2 or - f.hasGlobalName("snprintf") and buf = 0 and size = 1 + f.hasGlobalOrStdName("snprintf") and buf = 0 and size = 1 or - f.hasGlobalName("vsnprintf") and buf = 0 and size = 1 + f.hasGlobalOrStdName("vsnprintf") and buf = 0 and size = 1 } class CallWithBufferSize extends FunctionCall { diff --git a/cpp/ql/src/Critical/SizeCheck.ql b/cpp/ql/src/Critical/SizeCheck.ql index da841b73c9b..313763ba56c 100644 --- a/cpp/ql/src/Critical/SizeCheck.ql +++ b/cpp/ql/src/Critical/SizeCheck.ql @@ -17,12 +17,12 @@ import cpp class Allocation extends FunctionCall { Allocation() { exists(string name | - this.getTarget().hasGlobalName(name) and + this.getTarget().hasGlobalOrStdName(name) and (name = "malloc" or name = "calloc" or name = "realloc") ) } - private string getName() { this.getTarget().hasGlobalName(result) } + private string getName() { this.getTarget().hasGlobalOrStdName(result) } int getSize() { this.getName() = "malloc" and diff --git a/cpp/ql/src/Critical/SizeCheck2.ql b/cpp/ql/src/Critical/SizeCheck2.ql index 3cb5d1d28b0..1b716d79d49 100644 --- a/cpp/ql/src/Critical/SizeCheck2.ql +++ b/cpp/ql/src/Critical/SizeCheck2.ql @@ -17,12 +17,12 @@ import cpp class Allocation extends FunctionCall { Allocation() { exists(string name | - this.getTarget().hasGlobalName(name) and + this.getTarget().hasGlobalOrStdName(name) and (name = "malloc" or name = "calloc" or name = "realloc") ) } - private string getName() { this.getTarget().hasGlobalName(result) } + private string getName() { this.getTarget().hasGlobalOrStdName(result) } int getSize() { this.getName() = "malloc" and diff --git a/cpp/ql/src/Critical/UseAfterFree.ql b/cpp/ql/src/Critical/UseAfterFree.ql index db78c206ea1..9efbb6c3b44 100644 --- a/cpp/ql/src/Critical/UseAfterFree.ql +++ b/cpp/ql/src/Critical/UseAfterFree.ql @@ -16,7 +16,7 @@ import semmle.code.cpp.controlflow.LocalScopeVariableReachability predicate isFreeExpr(Expr e, LocalScopeVariable v) { exists(VariableAccess va | va.getTarget() = v | exists(FunctionCall fc | fc = e | - fc.getTarget().hasGlobalName("free") and + fc.getTarget().hasGlobalOrStdName("free") and va = fc.getArgument(0) ) or diff --git a/cpp/ql/src/DefaultOptions.qll b/cpp/ql/src/DefaultOptions.qll index 27e5584369e..3e03ec9ee65 100644 --- a/cpp/ql/src/DefaultOptions.qll +++ b/cpp/ql/src/DefaultOptions.qll @@ -59,7 +59,7 @@ class Options extends string { predicate exits(Function f) { f.getAnAttribute().hasName("noreturn") or - exists(string name | f.hasGlobalName(name) | + exists(string name | f.hasGlobalOrStdName(name) | name = "exit" or name = "_exit" or name = "abort" or @@ -91,7 +91,7 @@ class Options extends string { * By default holds only for `fgets`. */ predicate alwaysCheckReturnValue(Function f) { - f.hasGlobalName("fgets") or + f.hasGlobalOrStdName("fgets") or CustomOptions::alwaysCheckReturnValue(f) // old Options.qll } diff --git a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql index 096b1468bb9..fba0ddda4a1 100644 --- a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql +++ b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql @@ -34,8 +34,13 @@ class FileFunction extends FunctionWithWrappers { nme.matches("CreateFile%") ) or + exists(string nme | this.hasStdName(nme) | + nme = "fopen" or + nme = "open" + ) + or // on any of the fstream classes, or filebuf - exists(string nme | this.getDeclaringType().getSimpleName() = nme | + exists(string nme | this.getDeclaringType().hasStdName(nme) | nme = "basic_fstream" or nme = "basic_ifstream" or nme = "basic_ofstream" or diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql index 4469517c369..8b7fb83df81 100644 --- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql +++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql @@ -17,8 +17,8 @@ import semmle.code.cpp.security.TaintTracking /** A call that prints its arguments to `stdout`. */ class PrintStdoutCall extends FunctionCall { PrintStdoutCall() { - getTarget().hasGlobalName("puts") or - getTarget().hasGlobalName("printf") + getTarget().hasGlobalOrStdName("puts") or + getTarget().hasGlobalOrStdName("printf") } } diff --git a/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql b/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql index 473f0f72f12..77225ad0577 100644 --- a/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql +++ b/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql @@ -66,7 +66,7 @@ class VarargsFunction extends Function { } predicate isWhitelisted() { - this.hasGlobalName("open") or + this.hasGlobalOrStdName("open") or this.hasGlobalName("fcntl") or this.hasGlobalName("ptrace") } diff --git a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql index 575752f0b74..ff17daca05c 100644 --- a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql +++ b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql @@ -19,10 +19,7 @@ import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.models.implementations.Memcpy class MallocCall extends FunctionCall { - MallocCall() { - this.getTarget().hasGlobalName("malloc") or - this.getTarget().hasQualifiedName("std", "malloc") - } + MallocCall() { this.getTarget().hasGlobalOrStdName("malloc") } Expr getAllocatedSize() { if this.getArgument(0) instanceof VariableAccess diff --git a/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql b/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql index fa74c85555d..63eca292297 100644 --- a/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql +++ b/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql @@ -190,11 +190,11 @@ private predicate windowsSystemInfo(FunctionCall source, Element use) { // void WINAPI GetSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo); // void WINAPI GetNativeSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo); ( - source.getTarget().hasName("GetVersionEx") or - source.getTarget().hasName("GetVersionExA") or - source.getTarget().hasName("GetVersionExW") or - source.getTarget().hasName("GetSystemInfo") or - source.getTarget().hasName("GetNativeSystemInfo") + source.getTarget().hasGlobalName("GetVersionEx") or + source.getTarget().hasGlobalName("GetVersionExA") or + source.getTarget().hasGlobalName("GetVersionExW") or + source.getTarget().hasGlobalName("GetSystemInfo") or + source.getTarget().hasGlobalName("GetNativeSystemInfo") ) and use = source.getArgument(0) } @@ -216,9 +216,9 @@ private predicate windowsFolderPath(FunctionCall source, Element use) { // _In_ BOOL fCreate // ); ( - source.getTarget().hasName("SHGetSpecialFolderPath") or - source.getTarget().hasName("SHGetSpecialFolderPathA") or - source.getTarget().hasName("SHGetSpecialFolderPathW") + source.getTarget().hasGlobalName("SHGetSpecialFolderPath") or + source.getTarget().hasGlobalName("SHGetSpecialFolderPathA") or + source.getTarget().hasGlobalName("SHGetSpecialFolderPathW") ) and use = source.getArgument(1) or @@ -228,7 +228,7 @@ private predicate windowsFolderPath(FunctionCall source, Element use) { // _In_opt_ HANDLE hToken, // _Out_ PWSTR *ppszPath // ); - source.getTarget().hasName("SHGetKnownFolderPath") and + source.getTarget().hasGlobalName("SHGetKnownFolderPath") and use = source.getArgument(3) or // HRESULT SHGetFolderPath( @@ -239,9 +239,9 @@ private predicate windowsFolderPath(FunctionCall source, Element use) { // _Out_ LPTSTR pszPath // ); ( - source.getTarget().hasName("SHGetFolderPath") or - source.getTarget().hasName("SHGetFolderPathA") or - source.getTarget().hasName("SHGetFolderPathW") + source.getTarget().hasGlobalName("SHGetFolderPath") or + source.getTarget().hasGlobalName("SHGetFolderPathA") or + source.getTarget().hasGlobalName("SHGetFolderPathW") ) and use = source.getArgument(4) or @@ -254,9 +254,9 @@ private predicate windowsFolderPath(FunctionCall source, Element use) { // _Out_ LPTSTR pszPath // ); ( - source.getTarget().hasName("SHGetFolderPathAndSubDir") or - source.getTarget().hasName("SHGetFolderPathAndSubDirA") or - source.getTarget().hasName("SHGetFolderPathAndSubDirW") + source.getTarget().hasGlobalName("SHGetFolderPathAndSubDir") or + source.getTarget().hasGlobalName("SHGetFolderPathAndSubDirA") or + source.getTarget().hasGlobalName("SHGetFolderPathAndSubDirW") ) and use = source.getArgument(5) } @@ -273,9 +273,9 @@ class WindowsFolderPath extends SystemData { private predicate logonUser(FunctionCall source, VariableAccess use) { ( - source.getTarget().hasName("LogonUser") or - source.getTarget().hasName("LogonUserW") or - source.getTarget().hasName("LogonUserA") + source.getTarget().hasGlobalName("LogonUser") or + source.getTarget().hasGlobalName("LogonUserW") or + source.getTarget().hasGlobalName("LogonUserA") ) and use = source.getAnArgument() } @@ -297,9 +297,9 @@ private predicate regQuery(FunctionCall source, VariableAccess use) { // _Inout_opt_ PLONG lpcbValue // ); ( - source.getTarget().hasName("RegQueryValue") or - source.getTarget().hasName("RegQueryValueA") or - source.getTarget().hasName("RegQueryValueW") + source.getTarget().hasGlobalName("RegQueryValue") or + source.getTarget().hasGlobalName("RegQueryValueA") or + source.getTarget().hasGlobalName("RegQueryValueW") ) and use = source.getArgument(2) or @@ -311,9 +311,9 @@ private predicate regQuery(FunctionCall source, VariableAccess use) { // _Inout_opt_ LPDWORD ldwTotsize // ); ( - source.getTarget().hasName("RegQueryMultipleValues") or - source.getTarget().hasName("RegQueryMultipleValuesA") or - source.getTarget().hasName("RegQueryMultipleValuesW") + source.getTarget().hasGlobalName("RegQueryMultipleValues") or + source.getTarget().hasGlobalName("RegQueryMultipleValuesA") or + source.getTarget().hasGlobalName("RegQueryMultipleValuesW") ) and use = source.getArgument(3) or @@ -326,9 +326,9 @@ private predicate regQuery(FunctionCall source, VariableAccess use) { // _Inout_opt_ LPDWORD lpcbData // ); ( - source.getTarget().hasName("RegQueryValueEx") or - source.getTarget().hasName("RegQueryValueExA") or - source.getTarget().hasName("RegQueryValueExW") + source.getTarget().hasGlobalName("RegQueryValueEx") or + source.getTarget().hasGlobalName("RegQueryValueExA") or + source.getTarget().hasGlobalName("RegQueryValueExW") ) and use = source.getArgument(4) or @@ -342,9 +342,9 @@ private predicate regQuery(FunctionCall source, VariableAccess use) { // _Inout_opt_ LPDWORD pcbData // ); ( - source.getTarget().hasName("RegGetValue") or - source.getTarget().hasName("RegGetValueA") or - source.getTarget().hasName("RegGetValueW") + source.getTarget().hasGlobalName("RegGetValue") or + source.getTarget().hasGlobalName("RegGetValueA") or + source.getTarget().hasGlobalName("RegGetValueW") ) and use = source.getArgument(5) } diff --git a/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql b/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql index 84d7b48e265..fe9b56bd521 100644 --- a/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql +++ b/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql @@ -15,5 +15,5 @@ import cpp from FunctionCall call, Function target where call.getTarget() = target and - target.hasGlobalName("gets") + target.hasGlobalOrStdName("gets") select call, "gets does not guard against buffer overflow" diff --git a/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql b/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql index 4b1f45185d1..f2512b93003 100644 --- a/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql +++ b/cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql @@ -22,7 +22,7 @@ predicate acquireExpr(Expr acquire, string kind) { exists(FunctionCall fc, Function f, string name | fc = acquire and f = fc.getTarget() and - f.hasGlobalName(name) and + f.hasGlobalOrStdName(name) and ( name = "fopen" and kind = "file" @@ -46,7 +46,7 @@ predicate releaseExpr(Expr release, Expr resource, string kind) { exists(FunctionCall fc, Function f, string name | fc = release and f = fc.getTarget() and - f.hasGlobalName(name) and + f.hasGlobalOrStdName(name) and ( name = "fclose" and resource = fc.getArgument(0) and diff --git a/cpp/ql/src/jsf/4.10 Classes/AV Rule 97.ql b/cpp/ql/src/jsf/4.10 Classes/AV Rule 97.ql index 501101f706c..872a7443e6e 100644 --- a/cpp/ql/src/jsf/4.10 Classes/AV Rule 97.ql +++ b/cpp/ql/src/jsf/4.10 Classes/AV Rule 97.ql @@ -22,8 +22,8 @@ predicate containsArray(Type t) { or containsArray(t.getUnderlyingType()) and not exists(TypedefType allowed | allowed = t | - allowed.hasGlobalName("jmp_buf") or - allowed.hasGlobalName("va_list") + allowed.hasGlobalOrStdName("jmp_buf") or + allowed.hasGlobalOrStdName("va_list") ) } diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 94d11d63575..8c86d6b1267 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -434,7 +434,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { // ... and likewise for destructors. this.(Destructor).getADestruction().mayBeGloballyImpure() else - not exists(string name | this.hasGlobalName(name) | + not exists(string name | this.hasGlobalOrStdName(name) | // Unless it's a function that we know is side-effect-free, it may // have side-effects. name = "strcmp" or diff --git a/cpp/ql/src/semmle/code/cpp/commons/Alloc.qll b/cpp/ql/src/semmle/code/cpp/commons/Alloc.qll index e90aea37781..618afd624c4 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Alloc.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Alloc.qll @@ -5,13 +5,17 @@ import cpp */ predicate allocationFunction(Function f) { exists(string name | - f.hasGlobalName(name) and + f.hasGlobalOrStdName(name) and ( name = "malloc" or name = "calloc" or name = "realloc" or name = "strdup" or - name = "wcsdup" or + name = "wcsdup" + ) + or + f.hasGlobalName(name) and + ( name = "_strdup" or name = "_wcsdup" or name = "_mbsdup" or @@ -59,7 +63,7 @@ predicate allocationCall(FunctionCall fc) { allocationFunction(fc.getTarget()) and ( // realloc(ptr, 0) only frees the pointer - fc.getTarget().hasGlobalName("realloc") implies not fc.getArgument(1).getValue() = "0" + fc.getTarget().hasGlobalOrStdName("realloc") implies not fc.getArgument(1).getValue() = "0" ) } @@ -73,7 +77,10 @@ predicate freeFunction(Function f, int argNum) { name = "free" and argNum = 0 or name = "realloc" and argNum = 0 - or + ) + or + f.hasGlobalOrStdName(name) and + ( name = "ExFreePoolWithTag" and argNum = 0 or name = "ExFreeToLookasideListEx" and argNum = 1 @@ -188,3 +195,4 @@ predicate isDeallocationExpr(Expr e) { e instanceof DeleteExpr or e instanceof DeleteArrayExpr } + diff --git a/cpp/ql/src/semmle/code/cpp/commons/Environment.qll b/cpp/ql/src/semmle/code/cpp/commons/Environment.qll index e36244f4d5c..f3f1759dd5c 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Environment.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Environment.qll @@ -28,7 +28,7 @@ class EnvironmentRead extends Expr { private predicate readsEnvironment(Expr read, string sourceDescription) { exists(FunctionCall call, string name | read = call and - call.getTarget().hasGlobalName(name) and + call.getTarget().hasGlobalOrStdName(name) and (name = "getenv" or name = "secure_getenv" or name = "_wgetenv") and sourceDescription = name ) diff --git a/cpp/ql/src/semmle/code/cpp/commons/File.qll b/cpp/ql/src/semmle/code/cpp/commons/File.qll index 192918d25b3..05b4cfeaac4 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/File.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/File.qll @@ -5,8 +5,8 @@ import cpp */ predicate fopenCall(FunctionCall fc) { exists(Function f | f = fc.getTarget() | - f.hasGlobalName("fopen") or - f.hasGlobalName("open") or + f.hasGlobalOrStdName("fopen") or + f.hasGlobalOrStdName("open") or f.hasGlobalName("_open") or f.hasGlobalName("_wopen") or f.hasGlobalName("CreateFile") or @@ -23,16 +23,16 @@ predicate fopenCall(FunctionCall fc) { */ predicate fcloseCall(FunctionCall fc, Expr closed) { exists(Function f | f = fc.getTarget() | - f.hasGlobalName("fclose") and + f.hasGlobalOrStdName("fclose") and closed = fc.getArgument(0) or - f.hasGlobalName("close") and + f.hasGlobalOrStdName("close") and closed = fc.getArgument(0) or - f.hasGlobalName("_close") and + f.hasGlobalOrStdName("_close") and closed = fc.getArgument(0) or - f.hasGlobalName("CloseHandle") and + f.hasGlobalOrStdName("CloseHandle") and closed = fc.getArgument(0) ) } diff --git a/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll b/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll index e10e52df07d..772bb42e319 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll @@ -53,8 +53,8 @@ class AnalysedString extends Expr { */ class StrlenCall extends FunctionCall { StrlenCall() { - this.getTarget().hasGlobalName("strlen") or - this.getTarget().hasGlobalName("wcslen") or + this.getTarget().hasGlobalOrStdName("strlen") or + this.getTarget().hasGlobalOrStdName("wcslen") or this.getTarget().hasGlobalName("_mbslen") or this.getTarget().hasGlobalName("_mbslen_l") or this.getTarget().hasGlobalName("_mbstrlen") or diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll index cfd3efa91f3..69c5963af30 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll @@ -6,7 +6,7 @@ import Nullness */ predicate callDereferences(FunctionCall fc, int i) { exists(string name | - fc.getTarget().hasGlobalName(name) and + fc.getTarget().hasGlobalOrStdName(name) and ( name = "bcopy" and i in [0 .. 1] or diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll index 54b14aadd9d..caaa5b54e8c 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll @@ -264,9 +264,9 @@ predicate callMayReturnNull(Call call) { * Holds if `f` may, directly or indirectly, return a null literal. */ predicate mayReturnNull(Function f) { - f.hasGlobalName("malloc") + f.hasGlobalOrStdName("malloc") or - f.hasGlobalName("calloc") + f.hasGlobalOrStdName("calloc") or // f.hasGlobalName("strchr") // or diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index 5654c1a9c99..58721897802 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -7,9 +7,9 @@ class Printf extends FormattingFunction { Printf() { this instanceof TopLevelFunction and ( - hasGlobalName("printf") or + hasGlobalOrStdName("printf") or hasGlobalName("printf_s") or - hasGlobalName("wprintf") or + hasGlobalOrStdName("wprintf") or hasGlobalName("wprintf_s") or hasGlobalName("g_printf") ) and @@ -19,7 +19,7 @@ class Printf extends FormattingFunction { override int getFormatParameterIndex() { result = 0 } override predicate isWideCharDefault() { - hasGlobalName("wprintf") or + hasGlobalOrStdName("wprintf") or hasGlobalName("wprintf_s") } } @@ -31,8 +31,8 @@ class Fprintf extends FormattingFunction { Fprintf() { this instanceof TopLevelFunction and ( - hasGlobalName("fprintf") or - hasGlobalName("fwprintf") or + hasGlobalOrStdName("fprintf") or + hasGlobalOrStdName("fwprintf") or hasGlobalName("g_fprintf") ) and not exists(getDefinition().getFile().getRelativePath()) @@ -40,7 +40,7 @@ class Fprintf extends FormattingFunction { override int getFormatParameterIndex() { result = 1 } - override predicate isWideCharDefault() { hasGlobalName("fwprintf") } + override predicate isWideCharDefault() { hasGlobalOrStdName("fwprintf") } override int getOutputParameterIndex() { result = 0 } } @@ -52,10 +52,10 @@ class Sprintf extends FormattingFunction { Sprintf() { this instanceof TopLevelFunction and ( - hasGlobalName("sprintf") or + hasGlobalOrStdName("sprintf") or hasGlobalName("_sprintf_l") or hasGlobalName("__swprintf_l") or - hasGlobalName("wsprintf") or + hasGlobalOrStdName("wsprintf") or hasGlobalName("g_strdup_printf") or hasGlobalName("g_sprintf") or hasGlobalName("__builtin___sprintf_chk") @@ -99,8 +99,8 @@ class Snprintf extends FormattingFunction { Snprintf() { this instanceof TopLevelFunction and ( - hasGlobalName("snprintf") or // C99 defines snprintf - hasGlobalName("swprintf") or // The s version of wide-char printf is also always the n version + hasGlobalOrStdName("snprintf") or // C99 defines snprintf + hasGlobalOrStdName("swprintf") or // The s version of wide-char printf is also always the n version // Microsoft has _snprintf as well as several other variations hasGlobalName("sprintf_s") or hasGlobalName("snprintf_s") or @@ -160,7 +160,7 @@ class Snprintf extends FormattingFunction { */ predicate returnsFullFormatLength() { ( - hasGlobalName("snprintf") or + hasGlobalOrStdName("snprintf") or hasGlobalName("g_snprintf") or hasGlobalName("__builtin___snprintf_chk") or hasGlobalName("snprintf_s") diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index c5729c5d0f6..59b8c25700f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -6,7 +6,7 @@ import semmle.code.cpp.models.interfaces.SideEffect class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { PureStrFunction() { exists(string name | - hasGlobalName(name) and + hasGlobalOrStdName(name) and ( name = "atof" or name = "atoi" or @@ -75,7 +75,7 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE class PureFunction extends TaintFunction, SideEffectFunction { PureFunction() { exists(string name | - hasGlobalName(name) and + hasGlobalOrStdName(name) and ( name = "abs" or name = "labs" diff --git a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll index 9988e20290c..c7bea7eede7 100644 --- a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll +++ b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll @@ -8,7 +8,7 @@ import semmle.code.cpp.security.FunctionWithWrappers */ class SystemFunction extends FunctionWithWrappers { SystemFunction() { - hasGlobalName("system") or + hasGlobalOrStdName("system") or hasGlobalName("popen") or // Windows variants hasGlobalName("_popen") or diff --git a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll index 6363e3a5d14..219f3d0a75b 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll @@ -125,7 +125,7 @@ private predicate fileWrite(Call write, Expr source, Expr dest) { exists(Function f, int s, int d | f = write.getTarget() and source = write.getArgument(s) and dest = write.getArgument(d) | - exists(string name | f.hasGlobalName(name) | + exists(string name | f.hasGlobalOrStdName(name) | // named functions name = "fwrite" and s = 0 and d = 3 or diff --git a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll index 751a7a71ec7..06abfdb454d 100644 --- a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll @@ -63,8 +63,8 @@ private predicate outputWrite(Expr write, Expr source) { or // puts, putchar ( - f.hasGlobalName("puts") or - f.hasGlobalName("putchar") + f.hasGlobalOrStdName("puts") or + f.hasGlobalOrStdName("putchar") ) and arg = 0 or diff --git a/cpp/ql/src/semmle/code/cpp/security/Security.qll b/cpp/ql/src/semmle/code/cpp/security/Security.qll index 1a1c1d61ce8..c2b967071a6 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Security.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Security.qll @@ -70,7 +70,7 @@ class SecurityOptions extends string { */ predicate userInputArgument(FunctionCall functionCall, int arg) { exists(string fname | - functionCall.getTarget().hasGlobalName(fname) and + functionCall.getTarget().hasGlobalOrStdName(fname) and exists(functionCall.getArgument(arg)) and ( fname = "read" and arg = 1 @@ -83,6 +83,14 @@ class SecurityOptions extends string { or fname = "gets" and arg = 0 or + fname = "scanf" and arg >= 1 + or + fname = "fscanf" and arg >= 2 + ) + or + functionCall.getTarget().hasGlobalName(fname) and + exists(functionCall.getArgument(arg)) and + ( fname = "getaddrinfo" and arg = 3 or fname = "recv" and arg = 1 @@ -91,10 +99,6 @@ class SecurityOptions extends string { (arg = 1 or arg = 4 or arg = 5) or fname = "recvmsg" and arg = 1 - or - fname = "scanf" and arg >= 1 - or - fname = "fscanf" and arg >= 2 ) ) } diff --git a/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll b/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll index 1ef0a6f7092..b7bdd1416c7 100644 --- a/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll @@ -425,35 +425,35 @@ private int maxArgIndex(Function f) { /** Functions that copy the value of one argument to another */ private predicate copyValueBetweenArguments(Function f, int sourceArg, int destArg) { - f.hasGlobalName("memcpy") and sourceArg = 1 and destArg = 0 + f.hasGlobalOrStdName("memcpy") and sourceArg = 1 and destArg = 0 or f.hasGlobalName("__builtin___memcpy_chk") and sourceArg = 1 and destArg = 0 or - f.hasGlobalName("memmove") and sourceArg = 1 and destArg = 0 + f.hasGlobalOrStdName("memmove") and sourceArg = 1 and destArg = 0 or - f.hasGlobalName("strcat") and sourceArg = 1 and destArg = 0 + f.hasGlobalOrStdName("strcat") and sourceArg = 1 and destArg = 0 or f.hasGlobalName("_mbscat") and sourceArg = 1 and destArg = 0 or - f.hasGlobalName("wcsncat") and sourceArg = 1 and destArg = 0 + f.hasGlobalOrStdName("wcscat") and sourceArg = 1 and destArg = 0 or - f.hasGlobalName("strncat") and sourceArg = 1 and destArg = 0 + f.hasGlobalOrStdName("strncat") and sourceArg = 1 and destArg = 0 or f.hasGlobalName("_mbsncat") and sourceArg = 1 and destArg = 0 or f.hasGlobalName("wcsncat") and sourceArg = 1 and destArg = 0 or - f.hasGlobalName("strcpy") and sourceArg = 1 and destArg = 0 + f.hasGlobalOrStdName("strcpy") and sourceArg = 1 and destArg = 0 or f.hasGlobalName("_mbscpy") and sourceArg = 1 and destArg = 0 or - f.hasGlobalName("wcscpy") and sourceArg = 1 and destArg = 0 + f.hasGlobalOrStdName("wcscpy") and sourceArg = 1 and destArg = 0 or - f.hasGlobalName("strncpy") and sourceArg = 1 and destArg = 0 + f.hasGlobalOrStdName("strncpy") and sourceArg = 1 and destArg = 0 or f.hasGlobalName("_mbsncpy") and sourceArg = 1 and destArg = 0 or - f.hasGlobalName("wcsncpy") and sourceArg = 1 and destArg = 0 + f.hasGlobalOrStdName("wcsncpy") and sourceArg = 1 and destArg = 0 or f.hasGlobalName("inet_aton") and sourceArg = 0 and destArg = 1 or @@ -473,31 +473,31 @@ private predicate returnArgument(Function f, int sourceArg) { or f.hasGlobalName("__builtin___memcpy_chk") and sourceArg = 0 or - f.hasGlobalName("memmove") and sourceArg = 0 + f.hasGlobalOrStdName("memmove") and sourceArg = 0 or - f.hasGlobalName("strcat") and sourceArg = 0 + f.hasGlobalOrStdName("strcat") and sourceArg = 0 or f.hasGlobalName("_mbscat") and sourceArg = 0 or - f.hasGlobalName("wcsncat") and sourceArg = 0 + f.hasGlobalOrStdName("wcsncat") and sourceArg = 0 or - f.hasGlobalName("strncat") and sourceArg = 0 + f.hasGlobalOrStdName("strncat") and sourceArg = 0 or f.hasGlobalName("_mbsncat") and sourceArg = 0 or - f.hasGlobalName("wcsncat") and sourceArg = 0 + f.hasGlobalOrStdName("wcsncat") and sourceArg = 0 or - f.hasGlobalName("strcpy") and sourceArg = 0 + f.hasGlobalOrStdName("strcpy") and sourceArg = 0 or f.hasGlobalName("_mbscpy") and sourceArg = 0 or - f.hasGlobalName("wcscpy") and sourceArg = 0 + f.hasGlobalOrStdName("wcscpy") and sourceArg = 0 or - f.hasGlobalName("strncpy") and sourceArg = 0 + f.hasGlobalOrStdName("strncpy") and sourceArg = 0 or f.hasGlobalName("_mbsncpy") and sourceArg = 0 or - f.hasGlobalName("wcsncpy") and sourceArg = 0 + f.hasGlobalOrStdName("wcsncpy") and sourceArg = 0 or f.hasGlobalName("inet_ntoa") and sourceArg = 0 or From 68c38ba34af4d29b86379bb1aea1109230c7dc47 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 12 Jul 2019 10:34:15 -0700 Subject: [PATCH 0347/1227] C++: Add change note --- change-notes/1.23/analysis-cpp.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.23/analysis-cpp.md b/change-notes/1.23/analysis-cpp.md index 5a97e1347bb..f0f0889c282 100644 --- a/change-notes/1.23/analysis-cpp.md +++ b/change-notes/1.23/analysis-cpp.md @@ -42,3 +42,5 @@ The following changes in version 1.23 affect C/C++ analysis in all applications. clarity (e.g. `isOutReturnPointer()` to `isReturnValueDeref()`). The existing member predicates have been deprecated, and will be removed in a future release. Code that uses the old member predicates should be updated to use the corresponding new member predicate. +* The predicates `Declaration.hasStdName()` and `Declaration.hasGlobalOrStdName` + have been added, simplifying handling of C++ standard library functions. From 4018ed67a60168975d311560274b0225b51630ec Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 2 Oct 2019 11:21:10 -0700 Subject: [PATCH 0348/1227] C++: respond to PR comments --- cpp/ql/src/Critical/OverflowCalculated.ql | 2 +- cpp/ql/src/Critical/OverflowStatic.ql | 2 +- cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql | 5 +---- cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql | 2 +- cpp/ql/src/semmle/code/cpp/commons/File.qll | 4 ++-- cpp/ql/src/semmle/code/cpp/security/Security.qll | 4 ++-- cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll | 2 +- 7 files changed, 9 insertions(+), 12 deletions(-) diff --git a/cpp/ql/src/Critical/OverflowCalculated.ql b/cpp/ql/src/Critical/OverflowCalculated.ql index c528be8ca24..0ad898decd5 100644 --- a/cpp/ql/src/Critical/OverflowCalculated.ql +++ b/cpp/ql/src/Critical/OverflowCalculated.ql @@ -36,7 +36,7 @@ predicate spaceProblem(FunctionCall append, string msg) { buffer.getAnAccess() = strlen.getStringExpr() and ( insert.getTarget().hasGlobalOrStdName("strcpy") or - insert.getTarget().hasGlobalName("strncpy") + insert.getTarget().hasGlobalOrStdName("strncpy") ) and ( append.getTarget().hasGlobalOrStdName("strcat") or diff --git a/cpp/ql/src/Critical/OverflowStatic.ql b/cpp/ql/src/Critical/OverflowStatic.ql index 8cee2500797..82ffc879331 100644 --- a/cpp/ql/src/Critical/OverflowStatic.ql +++ b/cpp/ql/src/Critical/OverflowStatic.ql @@ -58,7 +58,7 @@ predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) { } predicate bufferAndSizeFunction(Function f, int buf, int size) { - f.hasGlobalOrStdName("read") and buf = 1 and size = 2 + f.hasGlobalName("read") and buf = 1 and size = 2 or f.hasGlobalOrStdName("fgets") and buf = 0 and size = 1 or diff --git a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql index fba0ddda4a1..5d02533124a 100644 --- a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql +++ b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql @@ -34,10 +34,7 @@ class FileFunction extends FunctionWithWrappers { nme.matches("CreateFile%") ) or - exists(string nme | this.hasStdName(nme) | - nme = "fopen" or - nme = "open" - ) + this.hasStdName("fopen") or // on any of the fstream classes, or filebuf exists(string nme | this.getDeclaringType().hasStdName(nme) | diff --git a/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql b/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql index 77225ad0577..473f0f72f12 100644 --- a/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql +++ b/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql @@ -66,7 +66,7 @@ class VarargsFunction extends Function { } predicate isWhitelisted() { - this.hasGlobalOrStdName("open") or + this.hasGlobalName("open") or this.hasGlobalName("fcntl") or this.hasGlobalName("ptrace") } diff --git a/cpp/ql/src/semmle/code/cpp/commons/File.qll b/cpp/ql/src/semmle/code/cpp/commons/File.qll index 05b4cfeaac4..ea8f8b9dc65 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/File.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/File.qll @@ -26,10 +26,10 @@ predicate fcloseCall(FunctionCall fc, Expr closed) { f.hasGlobalOrStdName("fclose") and closed = fc.getArgument(0) or - f.hasGlobalOrStdName("close") and + f.hasGlobalName("close") and closed = fc.getArgument(0) or - f.hasGlobalOrStdName("_close") and + f.hasGlobalName("_close") and closed = fc.getArgument(0) or f.hasGlobalOrStdName("CloseHandle") and diff --git a/cpp/ql/src/semmle/code/cpp/security/Security.qll b/cpp/ql/src/semmle/code/cpp/security/Security.qll index c2b967071a6..c12a70b52c6 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Security.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Security.qll @@ -73,8 +73,6 @@ class SecurityOptions extends string { functionCall.getTarget().hasGlobalOrStdName(fname) and exists(functionCall.getArgument(arg)) and ( - fname = "read" and arg = 1 - or fname = "fread" and arg = 0 or fname = "fgets" and arg = 0 @@ -91,6 +89,8 @@ class SecurityOptions extends string { functionCall.getTarget().hasGlobalName(fname) and exists(functionCall.getArgument(arg)) and ( + fname = "read" and arg = 1 + or fname = "getaddrinfo" and arg = 3 or fname = "recv" and arg = 1 diff --git a/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll b/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll index b7bdd1416c7..31d8ad00f9c 100644 --- a/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll @@ -459,7 +459,7 @@ private predicate copyValueBetweenArguments(Function f, int sourceArg, int destA or f.hasGlobalName("inet_pton") and sourceArg = 1 and destArg = 2 or - f.hasGlobalName("strftime") and sourceArg in [2 .. maxArgIndex(f)] and destArg = 0 + f.hasGlobalOrStdName("strftime") and sourceArg in [2 .. maxArgIndex(f)] and destArg = 0 or exists(FormattingFunction ff | ff = f | sourceArg in [ff.getFormatParameterIndex() .. maxArgIndex(f)] and From 8bed418022ea1e546391f2a72d1ededc15188e3e Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 2 Jan 2019 16:30:41 +0100 Subject: [PATCH 0349/1227] C++: enable the QL-based CFG code --- change-notes/1.23/analysis-cpp.md | 4 ++++ .../src/semmle/code/cpp/controlflow/ControlFlowGraph.qll | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/change-notes/1.23/analysis-cpp.md b/change-notes/1.23/analysis-cpp.md index 5a97e1347bb..097851fa83b 100644 --- a/change-notes/1.23/analysis-cpp.md +++ b/change-notes/1.23/analysis-cpp.md @@ -42,3 +42,7 @@ The following changes in version 1.23 affect C/C++ analysis in all applications. clarity (e.g. `isOutReturnPointer()` to `isReturnValueDeref()`). The existing member predicates have been deprecated, and will be removed in a future release. Code that uses the old member predicates should be updated to use the corresponding new member predicate. +* The control-flow graph is now computed in QL, not in the extractor. This can + lead to regressions (or improvements) in how queries are optimized because + optimization in QL relies on static size estimates, and the control-flow edge + relations will now have different size estimates than before. diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll index e4965cb8637..9174f474a8f 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll @@ -1,6 +1,7 @@ import cpp import BasicBlocks private import semmle.code.cpp.controlflow.internal.ConstantExprs +private import semmle.code.cpp.controlflow.internal.CFG /** * A control-flow node is either a statement or an expression; in addition, @@ -86,11 +87,11 @@ import ControlFlowGraphPublic class ControlFlowNodeBase extends ElementBase, @cfgnode { } predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { - truecond(unresolveElement(n1), unresolveElement(n2)) + qlCFGTrueSuccessor(n1, n2) } predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { - falsecond(unresolveElement(n1), unresolveElement(n2)) + qlCFGFalseSuccessor(n1, n2) } /** @@ -120,7 +121,7 @@ abstract class AdditionalControlFlowEdge extends ControlFlowNodeBase { * `AdditionalControlFlowEdge`. Use this relation instead of `successors`. */ predicate successors_extended(ControlFlowNodeBase source, ControlFlowNodeBase target) { - successors(unresolveElement(source), unresolveElement(target)) + qlCFGSuccessor(source, target) or source.(AdditionalControlFlowEdge).getAnEdgeTarget() = target } From 2eed38e2d45ac4f1b6621fe6752c7aaa4cfecdc9 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 3 Oct 2019 11:48:03 +0200 Subject: [PATCH 0350/1227] C++: Accept slight CFG regression in static init Hopefully it does not make a difference in practice whether uninstantiated template functions are considered to have control flow through initializers of their static variables. --- .../depends_initializers/InitializerCFG.expected | 4 ++-- .../depends_initializers/template_static_instantiated.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/ql/test/library-tests/depends_initializers/InitializerCFG.expected b/cpp/ql/test/library-tests/depends_initializers/InitializerCFG.expected index da871c2fbda..862cd295942 100644 --- a/cpp/ql/test/library-tests/depends_initializers/InitializerCFG.expected +++ b/cpp/ql/test/library-tests/depends_initializers/InitializerCFG.expected @@ -40,7 +40,7 @@ | template_static_instantiated.cpp:23:28:23:34 | initializer for static_int_one | myTemplateFunction | | template_static_instantiated.cpp:23:28:23:34 | initializer for static_int_one | myTemplateFunction | | template_static_instantiated.cpp:24:24:24:24 | initializer for static_t_1 | | -| template_static_instantiated.cpp:24:24:24:24 | initializer for static_t_1 | | +| template_static_instantiated.cpp:24:24:24:24 | initializer for static_t_1 | myTemplateFunction | | template_static_instantiated.cpp:25:22:25:24 | initializer for static_t_c | myTemplateFunction | | template_static_instantiated.cpp:25:24:25:24 | initializer for static_t_c | | | template_static_instantiated.cpp:26:22:26:24 | initializer for static_t_v | myTemplateFunction | @@ -72,7 +72,7 @@ | template_static_instantiated.cpp:47:29:47:35 | initializer for static_int_one | myMethod | | template_static_instantiated.cpp:47:29:47:35 | initializer for static_int_one | myMethod | | template_static_instantiated.cpp:48:25:48:25 | initializer for static_t_1 | | -| template_static_instantiated.cpp:48:25:48:25 | initializer for static_t_1 | | +| template_static_instantiated.cpp:48:25:48:25 | initializer for static_t_1 | myMethod | | template_static_instantiated.cpp:49:23:49:25 | initializer for static_t_c | myMethod | | template_static_instantiated.cpp:49:25:49:25 | initializer for static_t_c | | | template_static_instantiated.cpp:50:23:50:25 | initializer for static_t_v | myMethod | diff --git a/cpp/ql/test/library-tests/depends_initializers/template_static_instantiated.cpp b/cpp/ql/test/library-tests/depends_initializers/template_static_instantiated.cpp index ad703eee4af..e0a4b735aee 100644 --- a/cpp/ql/test/library-tests/depends_initializers/template_static_instantiated.cpp +++ b/cpp/ql/test/library-tests/depends_initializers/template_static_instantiated.cpp @@ -21,7 +21,7 @@ template void myTemplateFunction() static int static_int_c = c; // [initializer is not populated] static int static_int_v = v; // [initializer is not populated] static int static_int_one = one(); // [initializer is not populated] - static T static_t_1 = 1; // [initializer is not populated] + static T static_t_1 = 1; // [initializer is not populated] [BUG: CPP-450] static T static_t_c = c; // [initializer is not populated] static T static_t_v = v; // [initializer is not populated] static T static_t_one = one(); // [initializer is not populated] @@ -45,7 +45,7 @@ public: static int static_int_c = c; // [initializer is not populated] static int static_int_v = v; // [initializer is not populated] static int static_int_one = one(); // [initializer is not populated] - static T static_t_1 = 1; // [initializer is not populated] + static T static_t_1 = 1; // [initializer is not populated] [BUG: CPP-450] static T static_t_c = c; // [initializer is not populated] static T static_t_v = v; // [initializer is not populated] static T static_t_one = one(); // [initializer is not populated] From 41d344a8b7b8d0f5bc7af57031842dfb9d59edae Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 3 Oct 2019 12:08:22 +0200 Subject: [PATCH 0351/1227] C++: Support `if constexpr` in QL CFG This fixes the test `cpp/ql/test/library-tests/constexpr_if/cfg.ql`, which broke when the QL CFG was enabled. The new cases are just copy-pastes of the `IfStmt` cases (they don't share a useful common superclass) with added checks for whether their constant value equals 0. --- .../code/cpp/controlflow/internal/CFG.qll | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/internal/CFG.qll b/cpp/ql/src/semmle/code/cpp/controlflow/internal/CFG.qll index 3200987c347..3e302f71847 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/internal/CFG.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/internal/CFG.qll @@ -888,6 +888,21 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) { p2.nodeAfter(n2, s) ) or + // ConstexprIfStmt -> condition ; { then, else } -> // same as IfStmt + exists(ConstexprIfStmt s | + p1.nodeAt(n1, s) and + p2.nodeBefore(n2, s.getCondition()) + or + p1.nodeAfter(n1, s.getThen()) and + p2.nodeBeforeDestructors(n2, s) + or + p1.nodeAfter(n1, s.getElse()) and + p2.nodeBeforeDestructors(n2, s) + or + p1.nodeAfterDestructors(n1, s) and + p2.nodeAfter(n2, s) + ) + or // WhileStmt -> condition ; body -> condition ; after dtors -> after exists(WhileStmt s | p1.nodeAt(n1, s) and @@ -1175,9 +1190,8 @@ private class ExceptionSource extends Node { } /** - * Holds if `test` is the test of a control-flow construct that will always - * have true/false sub-edges out of it, where the `truth`-sub-edge goes to - * `(n2, p2)`. + * Holds if `test` is the test of a control-flow construct where the `truth` + * sub-edge goes to `(n2, p2)`. */ private predicate conditionJumpsTop(Expr test, boolean truth, Node n2, Pos p2) { exists(IfStmt s | test = s.getCondition() | @@ -1192,6 +1206,24 @@ private predicate conditionJumpsTop(Expr test, boolean truth, Node n2, Pos p2) { p2.nodeBeforeDestructors(n2, s) ) or + exists(ConstexprIfStmt s, string cond | + test = s.getCondition() and + cond = test.getFullyConverted().getValue() + | + truth = true and + cond != "0" and + p2.nodeBefore(n2, s.getThen()) + or + truth = false and + cond = "0" and + p2.nodeBefore(n2, s.getElse()) + or + not exists(s.getElse()) and + truth = false and + cond = "0" and + p2.nodeBeforeDestructors(n2, s) + ) + or exists(Loop l | ( l instanceof WhileStmt From 3e6f8fb6be686e6f40307398a31bac8df56238fe Mon Sep 17 00:00:00 2001 From: AlexTereshenkov <50622389+AlexTereshenkov@users.noreply.github.com> Date: Thu, 3 Oct 2019 11:23:11 +0100 Subject: [PATCH 0352/1227] Add bind-socket-all-network-interfaces Python query (#2048) Add bind-socket-all-network-interfaces Python query --- change-notes/1.23/analysis-python.md | 2 +- .../CVE-2018-1281/BindToAllInterfaces.py | 13 ++++++ .../CVE-2018-1281/BindToAllInterfaces.qhelp | 45 +++++++++++++++++++ .../CVE-2018-1281/BindToAllInterfaces.ql | 38 ++++++++++++++++ .../BindToAllInterfaces.expected | 3 ++ .../CVE-2018-1281/BindToAllInterfaces.qlref | 1 + .../CVE-2018-1281/BindToAllInterfaces_test.py | 17 +++++++ .../Security/CVE-2018-1281/options | 1 + 8 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.py create mode 100644 python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.qhelp create mode 100644 python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql create mode 100644 python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected create mode 100644 python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref create mode 100644 python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces_test.py create mode 100644 python/ql/test/query-tests/Security/CVE-2018-1281/options diff --git a/change-notes/1.23/analysis-python.md b/change-notes/1.23/analysis-python.md index 3319697fcfb..f0a830289a6 100644 --- a/change-notes/1.23/analysis-python.md +++ b/change-notes/1.23/analysis-python.md @@ -11,4 +11,4 @@ |-----------|----------|-------------| | Clear-text logging of sensitive information (`py/clear-text-logging-sensitive-data`) | security, external/cwe/cwe-312 | Finds instances where sensitive information is logged without encryption or hashing. Results are shown on LGTM by default. | | Clear-text storage of sensitive information (`py/clear-text-storage-sensitive-data`) | security, external/cwe/cwe-312 | Finds instances where sensitive information is stored without encryption or hashing. Results are shown on LGTM by default. | - +| Binding a socket to all network interfaces (`py/bind-socket-all-network-interfaces`) | security | Finds instances where a socket is bound to all network interfaces. Results are shown on LGTM by default. | diff --git a/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.py b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.py new file mode 100644 index 00000000000..e3de8345c6d --- /dev/null +++ b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.py @@ -0,0 +1,13 @@ +import socket + +# binds to all interfaces, insecure +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('0.0.0.0', 31137)) + +# binds to all interfaces, insecure +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('', 4040)) + +# binds only to a dedicated interface, secure +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('84.68.10.12', 8080)) diff --git a/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.qhelp b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.qhelp new file mode 100644 index 00000000000..df7caab5eaf --- /dev/null +++ b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.qhelp @@ -0,0 +1,45 @@ + + + + +

    Sockets can be used to communicate +with other machines on a network. +You can use the (IP address, port) pair +to define the access restrictions for the socket you create. +When using the built-in Python socket module +(for instance, when building a message sender service +or an FTP server data transmitter), +one has to bind the port to some interface. +When you bind the port to all interfaces +using 0.0.0.0 as the IP address, +you essentially allow it to accept connections from any IPv4 address +provided that it can get to the socket via routing. +Binding to all interfaces is therefore associated with security risks.

    +
    + + +

    Bind your service incoming traffic only to a dedicated interface. +If you need to bind more than one interface +using the built-in socket module, +create multiple sockets (instead of binding to one socket to all interfaces).

    +
    + + +

    In this example, two sockets are insecure because they are bound to all interfaces; +one through the 0.0.0.0 notation +and another one through an empty string ''. +

    + +
    + + +
  • Python reference: + Socket families.
  • +
  • Python reference: + Socket Programming HOWTO.
  • +
  • Common Vulnerabilities and Exposures: + CVE-2018-1281 Detail.
  • +
    +
    diff --git a/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql new file mode 100644 index 00000000000..0c160111fba --- /dev/null +++ b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql @@ -0,0 +1,38 @@ +/** + * @name Binding a socket to all network interfaces + * @description Binding a socket to all interfaces opens it up to traffic from any IPv4 address + * and is therefore associated with security risks. + * @kind problem + * @tags security + * @problem.severity error + * @sub-severity low + * @precision high + * @id py/bind-socket-all-network-interfaces + */ + +import python + +Value aSocket() { result.getClass() = Value::named("socket.socket") } + +CallNode socketBindCall() { + result = aSocket().attr("bind").(CallableValue).getACall() and major_version() = 3 + or + result.getFunction().(AttrNode).getObject("bind").pointsTo(aSocket()) and + major_version() = 2 +} + +string allInterfaces() { result = "0.0.0.0" or result = "" } + +Value getTextValue(string address) { + result = Value::forUnicode(address) and major_version() = 3 + or + result = Value::forString(address) and major_version() = 2 +} + +from CallNode call, TupleValue args, string address +where + call = socketBindCall() and + call.getArg(0).pointsTo(args) and + args.getItem(0) = getTextValue(address) and + address = allInterfaces() +select call.getNode(), "'" + address + "' binds a socket to all interfaces." diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected new file mode 100644 index 00000000000..c7c519ad121 --- /dev/null +++ b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected @@ -0,0 +1,3 @@ +| BindToAllInterfaces_test.py:5:1:5:26 | Attribute() | '0.0.0.0' binds a socket to all interfaces. | +| BindToAllInterfaces_test.py:9:1:9:18 | Attribute() | '' binds a socket to all interfaces. | +| BindToAllInterfaces_test.py:17:1:17:26 | Attribute() | '0.0.0.0' binds a socket to all interfaces. | diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref new file mode 100644 index 00000000000..f06cc3d869d --- /dev/null +++ b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref @@ -0,0 +1 @@ +Security/CVE-2018-1281/BindToAllInterfaces.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces_test.py b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces_test.py new file mode 100644 index 00000000000..3332f07d076 --- /dev/null +++ b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces_test.py @@ -0,0 +1,17 @@ +import socket + +# binds to all interfaces, insecure +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('0.0.0.0', 31137)) + +# binds to all interfaces, insecure +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('', 4040)) + +# binds only to a dedicated interface, secure +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('84.68.10.12', 8080)) + +# binds to all interfaces, insecure +ALL_LOCALS = "0.0.0.0" +s.bind((ALL_LOCALS, 9090)) diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/options b/python/ql/test/query-tests/Security/CVE-2018-1281/options new file mode 100644 index 00000000000..5a5d97a828e --- /dev/null +++ b/python/ql/test/query-tests/Security/CVE-2018-1281/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=3 \ No newline at end of file From 01a3a037bcf9b93d60ce6ee253e0b69e8baa90fc Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 3 Oct 2019 13:13:09 +0200 Subject: [PATCH 0353/1227] C++: Make complex_numbers/expr.ql less brittle This test used `getAQlClass`, which caused it to break when new classes were added anywhere in the libraries. That's now avoided by switching to `getCanonicalQLClass`. It turns out that `getCanonicalQLClass` didn't support arithmetic expressions on complex numbers, so that support had to be added. --- .../code/cpp/exprs/ArithmeticOperation.qll | 22 +++ cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll | 2 + .../complex_numbers/expr.expected | 142 ------------------ .../library-tests/complex_numbers/expr.ql | 2 +- 4 files changed, 25 insertions(+), 143 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll index 48af2b539c7..12d36d9b0bc 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll @@ -32,6 +32,8 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr { */ class ConjugationExpr extends UnaryArithmeticOperation, @conjugation { override string getOperator() { result = "~" } + + override string getCanonicalQLClass() { result = "ConjugationExpr" } } /** @@ -142,6 +144,8 @@ class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @post */ class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr { override string getOperator() { result = "__real" } + + override string getCanonicalQLClass() { result = "RealPartExpr" } } /** @@ -149,6 +153,8 @@ class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr { */ class ImaginaryPartExpr extends UnaryArithmeticOperation, @imagpartexpr { override string getOperator() { result = "__imag" } + + override string getCanonicalQLClass() { result = "ImaginaryPartExpr" } } /** @@ -217,6 +223,8 @@ class RemExpr extends BinaryArithmeticOperation, @remexpr { class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr { override string getOperator() { result = "*" } + override string getCanonicalQLClass() { result = "ImaginaryMulExpr" } + override int getPrecedence() { result = 13 } } @@ -226,6 +234,8 @@ class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr { class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr { override string getOperator() { result = "/" } + override string getCanonicalQLClass() { result = "ImaginaryDivExpr" } + override int getPrecedence() { result = 13 } } @@ -235,6 +245,8 @@ class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr { class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr { override string getOperator() { result = "+" } + override string getCanonicalQLClass() { result = "RealImaginaryAddExpr" } + override int getPrecedence() { result = 12 } } @@ -244,6 +256,8 @@ class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr { class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr { override string getOperator() { result = "+" } + override string getCanonicalQLClass() { result = "ImaginaryRealAddExpr" } + override int getPrecedence() { result = 12 } } @@ -253,6 +267,8 @@ class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr { class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr { override string getOperator() { result = "-" } + override string getCanonicalQLClass() { result = "RealImaginarySubExpr" } + override int getPrecedence() { result = 12 } } @@ -262,6 +278,8 @@ class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr { class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr { override string getOperator() { result = "-" } + override string getCanonicalQLClass() { result = "ImaginaryRealSubExpr" } + override int getPrecedence() { result = 12 } } @@ -270,6 +288,8 @@ class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr { */ class MinExpr extends BinaryArithmeticOperation, @minexpr { override string getOperator() { result = "?" } + + override string getCanonicalQLClass() { result = "MaxExpr" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll index 73d54c678b0..8da597bba96 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll @@ -294,6 +294,8 @@ class IfStmt extends ConditionalStmt, @stmt_if { * ``` */ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { + override string getCanonicalQLClass() { result = "ConstexprIfStmt" } + /** * Gets the condition expression of this 'constexpr if' statement. * diff --git a/cpp/ql/test/library-tests/complex_numbers/expr.expected b/cpp/ql/test/library-tests/complex_numbers/expr.expected index 230793f402b..c48f9edc749 100644 --- a/cpp/ql/test/library-tests/complex_numbers/expr.expected +++ b/cpp/ql/test/library-tests/complex_numbers/expr.expected @@ -1,177 +1,35 @@ -| conjugation.c:3:5:3:5 | x | AnalysedExpr | -| conjugation.c:3:5:3:5 | x | CompileTimeVariableExpr | -| conjugation.c:3:5:3:5 | x | DefOrUse | | conjugation.c:3:5:3:5 | x | VariableAccess | -| conjugation.c:3:5:3:10 | ... = ... | AnalysedExpr | | conjugation.c:3:5:3:10 | ... = ... | AssignExpr | -| conjugation.c:3:5:3:10 | ... = ... | CompileTimeVariableExpr | -| conjugation.c:3:5:3:10 | ... = ... | Def | -| conjugation.c:3:5:3:10 | ... = ... | ExprInVoidContext | -| conjugation.c:3:5:3:10 | ... = ... | NameQualifiableElement | -| conjugation.c:3:5:3:10 | ... = ... | RangeSsaDefinition | -| conjugation.c:3:5:3:10 | ... = ... | SsaDefinition | -| conjugation.c:3:9:3:10 | ~ ... | AnalysedExpr | -| conjugation.c:3:9:3:10 | ~ ... | CompileTimeVariableExpr | | conjugation.c:3:9:3:10 | ~ ... | ConjugationExpr | -| conjugation.c:3:9:3:10 | ~ ... | DefOrUse | -| conjugation.c:3:9:3:10 | ~ ... | NameQualifiableElement | -| conjugation.c:3:10:3:10 | x | AnalysedExpr | -| conjugation.c:3:10:3:10 | x | CompileTimeVariableExpr | -| conjugation.c:3:10:3:10 | x | Use | | conjugation.c:3:10:3:10 | x | VariableAccess | -| test.c:5:5:5:5 | z | AnalysedExpr | -| test.c:5:5:5:5 | z | CompileTimeVariableExpr | -| test.c:5:5:5:5 | z | DefOrUse | | test.c:5:5:5:5 | z | VariableAccess | -| test.c:5:5:5:13 | ... = ... | AnalysedExpr | | test.c:5:5:5:13 | ... = ... | AssignExpr | -| test.c:5:5:5:13 | ... = ... | CompileTimeVariableExpr | -| test.c:5:5:5:13 | ... = ... | Def | -| test.c:5:5:5:13 | ... = ... | ExprInVoidContext | -| test.c:5:5:5:13 | ... = ... | NameQualifiableElement | -| test.c:5:5:5:13 | ... = ... | RangeSsaDefinition | -| test.c:5:5:5:13 | ... = ... | SsaDefinition | -| test.c:5:9:5:9 | x | AnalysedExpr | -| test.c:5:9:5:9 | x | CompileTimeVariableExpr | -| test.c:5:9:5:9 | x | Use | | test.c:5:9:5:9 | x | VariableAccess | -| test.c:5:9:5:13 | ... * ... | AnalysedExpr | -| test.c:5:9:5:13 | ... * ... | CompileTimeVariableExpr | -| test.c:5:9:5:13 | ... * ... | DefOrUse | | test.c:5:9:5:13 | ... * ... | ImaginaryMulExpr | -| test.c:5:9:5:13 | ... * ... | NameQualifiableElement | -| test.c:5:13:5:13 | y | AnalysedExpr | -| test.c:5:13:5:13 | y | CompileTimeVariableExpr | -| test.c:5:13:5:13 | y | Use | | test.c:5:13:5:13 | y | VariableAccess | -| test.c:6:5:6:5 | z | AnalysedExpr | -| test.c:6:5:6:5 | z | CompileTimeVariableExpr | -| test.c:6:5:6:5 | z | DefOrUse | | test.c:6:5:6:5 | z | VariableAccess | -| test.c:6:5:6:13 | ... = ... | AnalysedExpr | | test.c:6:5:6:13 | ... = ... | AssignExpr | -| test.c:6:5:6:13 | ... = ... | CompileTimeVariableExpr | -| test.c:6:5:6:13 | ... = ... | Def | -| test.c:6:5:6:13 | ... = ... | ExprInVoidContext | -| test.c:6:5:6:13 | ... = ... | NameQualifiableElement | -| test.c:6:5:6:13 | ... = ... | RangeSsaDefinition | -| test.c:6:5:6:13 | ... = ... | SsaDefinition | -| test.c:6:9:6:9 | z | AnalysedExpr | -| test.c:6:9:6:9 | z | CompileTimeVariableExpr | -| test.c:6:9:6:9 | z | Use | | test.c:6:9:6:9 | z | VariableAccess | -| test.c:6:9:6:13 | (double)... | AnalysedExpr | | test.c:6:9:6:13 | (double)... | CStyleCast | -| test.c:6:9:6:13 | (double)... | CompileTimeVariableExpr | -| test.c:6:9:6:13 | (double)... | DefOrUse | -| test.c:6:9:6:13 | (double)... | FloatingPointConversion | -| test.c:6:9:6:13 | (double)... | NameQualifiableElement | -| test.c:6:9:6:13 | ... / ... | AnalysedExpr | -| test.c:6:9:6:13 | ... / ... | CompileTimeVariableExpr | -| test.c:6:9:6:13 | ... / ... | DefOrUse | | test.c:6:9:6:13 | ... / ... | ImaginaryDivExpr | -| test.c:6:9:6:13 | ... / ... | NameQualifiableElement | -| test.c:6:13:6:13 | y | AnalysedExpr | -| test.c:6:13:6:13 | y | CompileTimeVariableExpr | -| test.c:6:13:6:13 | y | Use | | test.c:6:13:6:13 | y | VariableAccess | -| test.c:7:5:7:5 | w | AnalysedExpr | -| test.c:7:5:7:5 | w | CompileTimeVariableExpr | -| test.c:7:5:7:5 | w | DefOrUse | | test.c:7:5:7:5 | w | VariableAccess | -| test.c:7:5:7:13 | ... = ... | AnalysedExpr | | test.c:7:5:7:13 | ... = ... | AssignExpr | -| test.c:7:5:7:13 | ... = ... | CompileTimeVariableExpr | -| test.c:7:5:7:13 | ... = ... | Def | -| test.c:7:5:7:13 | ... = ... | ExprInVoidContext | -| test.c:7:5:7:13 | ... = ... | NameQualifiableElement | -| test.c:7:5:7:13 | ... = ... | RangeSsaDefinition | -| test.c:7:5:7:13 | ... = ... | SsaDefinition | -| test.c:7:9:7:9 | z | AnalysedExpr | -| test.c:7:9:7:9 | z | CompileTimeVariableExpr | -| test.c:7:9:7:9 | z | Use | | test.c:7:9:7:9 | z | VariableAccess | -| test.c:7:9:7:13 | ... + ... | AnalysedExpr | -| test.c:7:9:7:13 | ... + ... | CompileTimeVariableExpr | -| test.c:7:9:7:13 | ... + ... | DefOrUse | -| test.c:7:9:7:13 | ... + ... | NameQualifiableElement | | test.c:7:9:7:13 | ... + ... | RealImaginaryAddExpr | -| test.c:7:13:7:13 | x | AnalysedExpr | -| test.c:7:13:7:13 | x | CompileTimeVariableExpr | -| test.c:7:13:7:13 | x | Use | | test.c:7:13:7:13 | x | VariableAccess | -| test.c:8:5:8:5 | w | AnalysedExpr | -| test.c:8:5:8:5 | w | CompileTimeVariableExpr | -| test.c:8:5:8:5 | w | DefOrUse | | test.c:8:5:8:5 | w | VariableAccess | -| test.c:8:5:8:13 | ... = ... | AnalysedExpr | | test.c:8:5:8:13 | ... = ... | AssignExpr | -| test.c:8:5:8:13 | ... = ... | CompileTimeVariableExpr | -| test.c:8:5:8:13 | ... = ... | Def | -| test.c:8:5:8:13 | ... = ... | ExprInVoidContext | -| test.c:8:5:8:13 | ... = ... | NameQualifiableElement | -| test.c:8:5:8:13 | ... = ... | RangeSsaDefinition | -| test.c:8:5:8:13 | ... = ... | SsaDefinition | -| test.c:8:9:8:9 | x | AnalysedExpr | -| test.c:8:9:8:9 | x | CompileTimeVariableExpr | -| test.c:8:9:8:9 | x | Use | | test.c:8:9:8:9 | x | VariableAccess | -| test.c:8:9:8:13 | ... + ... | AnalysedExpr | -| test.c:8:9:8:13 | ... + ... | CompileTimeVariableExpr | -| test.c:8:9:8:13 | ... + ... | DefOrUse | | test.c:8:9:8:13 | ... + ... | ImaginaryRealAddExpr | -| test.c:8:9:8:13 | ... + ... | NameQualifiableElement | -| test.c:8:13:8:13 | z | AnalysedExpr | -| test.c:8:13:8:13 | z | CompileTimeVariableExpr | -| test.c:8:13:8:13 | z | Use | | test.c:8:13:8:13 | z | VariableAccess | -| test.c:9:5:9:5 | w | AnalysedExpr | -| test.c:9:5:9:5 | w | CompileTimeVariableExpr | -| test.c:9:5:9:5 | w | DefOrUse | | test.c:9:5:9:5 | w | VariableAccess | -| test.c:9:5:9:13 | ... = ... | AnalysedExpr | | test.c:9:5:9:13 | ... = ... | AssignExpr | -| test.c:9:5:9:13 | ... = ... | CompileTimeVariableExpr | -| test.c:9:5:9:13 | ... = ... | Def | -| test.c:9:5:9:13 | ... = ... | ExprInVoidContext | -| test.c:9:5:9:13 | ... = ... | NameQualifiableElement | -| test.c:9:5:9:13 | ... = ... | RangeSsaDefinition | -| test.c:9:5:9:13 | ... = ... | SsaDefinition | -| test.c:9:9:9:9 | z | AnalysedExpr | -| test.c:9:9:9:9 | z | CompileTimeVariableExpr | -| test.c:9:9:9:9 | z | Use | | test.c:9:9:9:9 | z | VariableAccess | -| test.c:9:9:9:13 | ... - ... | AnalysedExpr | -| test.c:9:9:9:13 | ... - ... | CompileTimeVariableExpr | -| test.c:9:9:9:13 | ... - ... | DefOrUse | -| test.c:9:9:9:13 | ... - ... | NameQualifiableElement | | test.c:9:9:9:13 | ... - ... | RealImaginarySubExpr | -| test.c:9:13:9:13 | x | AnalysedExpr | -| test.c:9:13:9:13 | x | CompileTimeVariableExpr | -| test.c:9:13:9:13 | x | Use | | test.c:9:13:9:13 | x | VariableAccess | -| test.c:10:5:10:5 | w | AnalysedExpr | -| test.c:10:5:10:5 | w | CompileTimeVariableExpr | -| test.c:10:5:10:5 | w | DefOrUse | | test.c:10:5:10:5 | w | VariableAccess | -| test.c:10:5:10:13 | ... = ... | AnalysedExpr | | test.c:10:5:10:13 | ... = ... | AssignExpr | -| test.c:10:5:10:13 | ... = ... | CompileTimeVariableExpr | -| test.c:10:5:10:13 | ... = ... | Def | -| test.c:10:5:10:13 | ... = ... | ExprInVoidContext | -| test.c:10:5:10:13 | ... = ... | NameQualifiableElement | -| test.c:10:5:10:13 | ... = ... | RangeSsaDefinition | -| test.c:10:5:10:13 | ... = ... | SsaDefinition | -| test.c:10:9:10:9 | x | AnalysedExpr | -| test.c:10:9:10:9 | x | CompileTimeVariableExpr | -| test.c:10:9:10:9 | x | Use | | test.c:10:9:10:9 | x | VariableAccess | -| test.c:10:9:10:13 | ... - ... | AnalysedExpr | -| test.c:10:9:10:13 | ... - ... | CompileTimeVariableExpr | -| test.c:10:9:10:13 | ... - ... | DefOrUse | | test.c:10:9:10:13 | ... - ... | ImaginaryRealSubExpr | -| test.c:10:9:10:13 | ... - ... | NameQualifiableElement | -| test.c:10:13:10:13 | z | AnalysedExpr | -| test.c:10:13:10:13 | z | CompileTimeVariableExpr | -| test.c:10:13:10:13 | z | Use | | test.c:10:13:10:13 | z | VariableAccess | diff --git a/cpp/ql/test/library-tests/complex_numbers/expr.ql b/cpp/ql/test/library-tests/complex_numbers/expr.ql index 903359f5f72..0f2e6f14d4e 100644 --- a/cpp/ql/test/library-tests/complex_numbers/expr.ql +++ b/cpp/ql/test/library-tests/complex_numbers/expr.ql @@ -1,4 +1,4 @@ import cpp from Expr e -select e, e.getAQlClass() +select e, e.getCanonicalQLClass() From 06d1d6ed5db22c12f1935021dfb81ddce6bed9ce Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Mon, 23 Sep 2019 15:23:50 +0100 Subject: [PATCH 0354/1227] C++: Fix synthetic_destructor_call key uniqueness. --- cpp/ql/src/semmlecode.cpp.dbscheme | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index 678a0f9164f..999628cd904 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -1061,10 +1061,11 @@ compgenerated(unique int id: @element ref); * destructed in reverse construction order, so for a given `element` * these should be called from highest to lowest `i`. */ +#keyset[destructor_call, element] synthetic_destructor_call( int element: @element ref, int i: int ref, - unique int destructor_call: @routineexpr ref + int destructor_call: @routineexpr ref ); namespaces( From d62730a9f3e7fd23a29b0a702f2eda5e5649fa41 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Tue, 24 Sep 2019 16:15:01 +0100 Subject: [PATCH 0355/1227] C++: Update synthetic_destructor_call keysets. Reorder the [ destructor_call, expr ] tuple. Add a [ expr, i ] tuple. --- cpp/ql/src/semmlecode.cpp.dbscheme | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index 999628cd904..0417f73f30e 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -1061,7 +1061,8 @@ compgenerated(unique int id: @element ref); * destructed in reverse construction order, so for a given `element` * these should be called from highest to lowest `i`. */ -#keyset[destructor_call, element] +#keyset[element, destructor_call] +#keyset[element, i] synthetic_destructor_call( int element: @element ref, int i: int ref, From a7f682a9bef7a67a52569433be77b38d0aa53cb4 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Thu, 26 Sep 2019 13:00:20 +0100 Subject: [PATCH 0356/1227] C++: Update *variables keysets. --- cpp/ql/src/semmlecode.cpp.dbscheme | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index 0417f73f30e..0ed3da4a31c 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -521,18 +521,21 @@ params( overrides(int new: @function ref, int old: @function ref); +#keyset[id, type_id] membervariables( - unique int id: @membervariable, + int id: @membervariable, int type_id: @type ref, string name: string ref ); +#keyset[id, type_id] globalvariables( - unique int id: @globalvariable, + int id: @globalvariable, int type_id: @type ref, string name: string ref ); +#keyset[id, type_id] localvariables( int id: @localvariable, int type_id: @type ref, From 618d0a9603f1c749fd7e034404d1b65e25db2ff8 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Thu, 3 Oct 2019 15:15:01 +0100 Subject: [PATCH 0357/1227] C++: Update DB Stats --- cpp/ql/src/semmlecode.cpp.dbscheme.stats | 3119 +++++++++++----------- 1 file changed, 1582 insertions(+), 1537 deletions(-) diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme.stats b/cpp/ql/src/semmlecode.cpp.dbscheme.stats index e5b3ff92488..e917061409d 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/src/semmlecode.cpp.dbscheme.stats @@ -1,7 +1,7 @@ @compilation -10590 +10588 @externalDataElement @@ -25,7 +25,7 @@ @location_default -9666045 +9664446 @location_stmt @@ -37,43 +37,43 @@ @diagnostic -76172 +76160 @file -66178 +66167 @folder -12109 +12107 @macroinvocation -40821746 +40814994 @function -3566471 +3565918 @fun_decl -3669417 +3668312 @var_decl -5603886 +5602108 @type_decl -1469408 +1469165 @namespace_decl -151652 +151627 @using -320654 +320601 @static_assert @@ -81,15 +81,15 @@ @parameter -4781331 +4779409 @membervariable -329712 +325099 @globalvariable -301143 +301136 @localvariable @@ -105,19 +105,19 @@ @derivedtype -4572704 +4572470 @decltype -45849 +45841 @usertype -4328015 +4327300 @mangledname -533074 +532986 @type_mention @@ -125,11 +125,11 @@ @routinetype -444646 +444572 @ptrtomember -12182 +12180 @specifier @@ -173,19 +173,19 @@ @derivation -370358 +370297 @frienddecl -231217 +231178 @comment -1743921 +1743633 @namespace -8498 +8497 @specialnamequalifyingelement @@ -197,7 +197,7 @@ @value -8776937 +8776796 @initialiser @@ -209,7 +209,7 @@ @errorexpr -48074 +48066 @address_of @@ -217,7 +217,7 @@ @reference_to -1078015 +1077837 @indirect @@ -225,7 +225,7 @@ @ref_indirect -1267930 +1267903 @array_to_pointer @@ -281,11 +281,11 @@ @preincrexpr -63965 +63954 @predecrexpr -26590 +26586 @conditionalexpr @@ -345,7 +345,7 @@ @pdiffexpr -25873 +25868 @lshiftexpr @@ -413,7 +413,7 @@ @assignmulexpr -7599 +7597 @assigndivexpr @@ -461,7 +461,7 @@ @commaexpr -10723 +10721 @subscriptexpr @@ -473,7 +473,7 @@ @callexpr -248555 +248513 @vastartexpr @@ -501,19 +501,19 @@ @new_expr -29520 +29515 @delete_expr -6565 +6564 @throw_expr -23781 +23777 @condition_decl -7647 +7646 @braced_init_list @@ -541,7 +541,7 @@ @routineexpr -2308754 +2309113 @type_operand @@ -661,15 +661,15 @@ @ctordirectinit -93279 +93264 @ctorvirtualinit -6905 +6904 @ctorfieldinit -209696 +209661 @ctordelegatinginit @@ -677,19 +677,19 @@ @dtordirectdestruct -30833 +30828 @dtorvirtualdestruct -2699 +2698 @dtorfielddestruct -32548 +32542 @static_cast -224773 +224735 @reinterpret_cast @@ -697,7 +697,7 @@ @const_cast -5848 +5847 @dynamic_cast @@ -713,7 +713,7 @@ @param_ref -53217 +53208 @noopexpr @@ -829,7 +829,7 @@ @builtinaddressof -4389 +4388 @vec_fill @@ -853,7 +853,7 @@ @stmt_while -32912 +32907 @stmt_goto @@ -865,11 +865,11 @@ @stmt_return -1197363 +1197201 @stmt_block -1398476 +1398281 @stmt_end_test_while @@ -893,7 +893,7 @@ @stmt_try_block -18967 +18964 @stmt_microsoft_try @@ -901,7 +901,7 @@ @stmt_decl -647242 +647378 @stmt_set_vla_size @@ -941,39 +941,39 @@ @ppd_plain_include -321760 +321707 @ppd_define -350005 +349947 @ppd_if -171105 +171077 @ppd_ifdef -66834 +66823 @ppd_ifndef -91808 +91793 @ppd_elif -22772 +22768 @ppd_else -63649 +63638 @ppd_endif -329749 +329694 @ppd_undef -21155 +21152 @ppd_line @@ -1030,11 +1030,11 @@ compilations -10590 +10588 id -10590 +10588 cwd @@ -1052,7 +1052,7 @@ 1 2 -10590 +10588 @@ -1354,11 +1354,11 @@ compilation_compiling_files -10590 +10588 id -10590 +10588 num @@ -1366,7 +1366,7 @@ file -5374 +5373 @@ -1380,7 +1380,7 @@ 1 2 -10590 +10588 @@ -1396,7 +1396,7 @@ 1 2 -10590 +10588 @@ -1449,7 +1449,7 @@ 2 3 -5045 +5044 3 @@ -1470,7 +1470,7 @@ 1 2 -5374 +5373 @@ -1480,11 +1480,11 @@ compilation_time -42262 +42255 id -10565 +10563 num @@ -1496,7 +1496,7 @@ seconds -12389 +12788 @@ -1510,7 +1510,7 @@ 1 2 -10565 +10563 @@ -1526,7 +1526,7 @@ 4 5 -10565 +10563 @@ -1540,14 +1540,19 @@ 12 +2 +3 +24 + + 3 4 -2942 +2941 4 5 -7623 +7597 @@ -1593,8 +1598,8 @@ 12 -1019 -1020 +1052 +1053 12 @@ -1651,13 +1656,13 @@ 12 -546 -547 +564 +565 12 -590 -591 +619 +620 12 @@ -1674,27 +1679,27 @@ 1 2 -7890 +8363 2 3 -2589 +2504 3 4 -875 +850 4 -14 -936 +10 +960 -15 -625 -97 +11 +616 +109 @@ -1710,7 +1715,7 @@ 1 2 -12389 +12788 @@ -1726,12 +1731,17 @@ 1 2 -10784 +11025 2 3 -1604 +1750 + + +3 +4 +12 @@ -1741,15 +1751,15 @@ diagnostic_for -940552 +940397 diagnostic -940552 +940397 compilation -10225 +10223 file_number @@ -1757,7 +1767,7 @@ file_number_diagnostic_number -7209 +7208 @@ -1771,7 +1781,7 @@ 1 2 -940552 +940397 @@ -1787,7 +1797,7 @@ 1 2 -940552 +940397 @@ -1803,7 +1813,7 @@ 1 2 -940552 +940397 @@ -1824,7 +1834,7 @@ 7 8 -5228 +5227 8 @@ -1865,7 +1875,7 @@ 1 2 -10225 +10223 @@ -1886,7 +1896,7 @@ 7 8 -5228 +5227 8 @@ -2031,7 +2041,7 @@ 4 9 -620 +619 10 @@ -2092,7 +2102,7 @@ 1 2 -7209 +7208 @@ -2102,15 +2112,15 @@ compilation_finished -10590 +10588 id -10590 +10588 cpu_seconds -8425 +8533 elapsed_seconds @@ -2128,7 +2138,7 @@ 1 2 -10590 +10588 @@ -2144,7 +2154,7 @@ 1 2 -10590 +10588 @@ -2160,17 +2170,17 @@ 1 2 -7258 +7269 2 3 -705 +826 3 -10 -462 +9 +437 @@ -2186,12 +2196,12 @@ 1 2 -7963 +8059 2 3 -462 +474 @@ -2212,16 +2222,16 @@ 2 3 -36 +24 -5 -6 +3 +4 12 -9 -10 +4 +5 12 @@ -2230,38 +2240,43 @@ 12 +11 +12 +12 + + 18 19 12 -27 -28 +29 +30 12 -49 -50 +47 +48 12 -121 -122 +126 +127 12 -128 -129 +133 +134 12 -246 -247 +236 +237 12 -251 -252 +249 +250 12 @@ -2283,16 +2298,16 @@ 2 3 -36 +24 -5 -6 +3 +4 12 -9 -10 +4 +5 12 @@ -2301,38 +2316,43 @@ 12 +11 +12 +12 + + 18 19 12 -27 -28 +29 +30 12 -49 -50 +45 +46 12 -96 -97 +98 +99 12 -117 -118 +124 +125 12 -167 -168 +173 +174 12 -226 -227 +221 +222 12 @@ -5241,11 +5261,11 @@ header_to_external_package -9094 +9093 fileid -9094 +9093 package @@ -5263,7 +5283,7 @@ 1 2 -9094 +9093 @@ -6532,31 +6552,31 @@ locations_default -9666045 +9664446 id -9666045 +9664446 container -78288 +78275 startLine -161111 +161084 startColumn -6018 +6017 endLine -160929 +160902 endColumn -8170 +8169 @@ -6570,7 +6590,7 @@ 1 2 -9666045 +9664446 @@ -6586,7 +6606,7 @@ 1 2 -9666045 +9664446 @@ -6602,7 +6622,7 @@ 1 2 -9666045 +9664446 @@ -6618,7 +6638,7 @@ 1 2 -9666045 +9664446 @@ -6634,7 +6654,7 @@ 1 2 -9666045 +9664446 @@ -6650,62 +6670,62 @@ 1 2 -12754 +12752 2 19 -6626 +6625 19 25 -6091 +6090 25 31 -6067 +6066 31 41 -6492 +6491 41 54 -6140 +6138 54 72 -6176 +6175 72 99 -5969 +5968 99 137 -5945 +5944 137 221 -5896 +5895 221 431 -5872 +5871 431 19703 -4255 +4254 @@ -6721,62 +6741,62 @@ 1 2 -12754 +12752 2 15 -6504 +6503 15 20 -6760 +6758 20 25 -6103 +6102 25 32 -6711 +6710 32 41 -6285 +6284 41 53 -6322 +6321 53 70 -5933 +5932 70 96 -5909 +5908 96 152 -5884 +5883 152 325 -5872 +5871 325 8863 -3246 +3245 @@ -6792,62 +6812,62 @@ 1 2 -12754 +12752 2 4 -6723 +6722 4 8 -7088 +7087 8 11 -5896 +5895 11 14 -6419 +6418 14 18 -6881 +6880 18 23 -6395 +6394 23 29 -6456 +6455 29 37 -6261 +6260 37 50 -6225 +6224 50 78 -5945 +5944 78 167 -1240 +1239 @@ -6863,62 +6883,62 @@ 1 2 -12754 +12752 2 15 -6480 +6479 15 20 -6796 +6795 20 25 -6030 +6029 25 32 -6711 +6710 32 41 -6298 +6297 41 53 -6310 +6309 53 70 -6018 +6017 70 96 -5921 +5920 96 153 -5933 +5932 153 332 -5884 +5883 332 8863 -3149 +3148 @@ -6934,57 +6954,57 @@ 1 2 -12754 +12752 2 14 -6237 +6236 14 19 -6711 +6710 19 23 -6225 +6224 23 27 -6006 +6005 27 32 -6188 +6187 32 38 -6006 +6005 38 45 -6140 +6138 45 54 -5921 +5920 54 65 -5994 +5993 65 79 -5884 +5883 79 @@ -7005,57 +7025,57 @@ 1 2 -31198 +31193 2 3 -19806 +19802 3 4 -18237 +18234 4 5 -10261 +10260 5 6 -9130 +9129 6 7 -6735 +6734 7 9 -14346 +14344 9 13 -13945 +13943 13 30 -12352 +12350 30 112 -12121 +12119 112 2168 -12085 +12083 2193 @@ -7076,42 +7096,42 @@ 1 2 -57278 +57268 2 3 -35502 +35496 3 4 -11343 +11341 4 5 -8985 +8983 5 8 -14796 +14794 8 26 -12365 +12363 26 115 -12097 +12095 115 6440 -8741 +8740 @@ -7127,57 +7147,57 @@ 1 2 -32292 +32287 2 3 -19696 +19693 3 4 -20547 +20544 4 5 -9738 +9737 5 6 -9386 +9384 6 7 -6857 +6856 7 9 -14614 +14612 9 13 -14030 +14028 13 27 -12438 +12436 27 60 -12134 +12132 60 153 -9374 +9372 @@ -7193,22 +7213,22 @@ 1 2 -119930 +119911 2 3 -18979 +18976 3 7 -13532 +13530 7 184 -8668 +8667 @@ -7224,57 +7244,57 @@ 1 2 -32317 +32311 2 3 -19587 +19584 3 4 -19027 +19024 4 5 -10249 +10247 5 6 -9410 +9409 6 7 -6638 +6637 7 9 -14638 +14636 9 13 -13702 +13700 13 28 -12146 +12144 28 68 -12121 +12119 68 190 -11270 +11269 @@ -7315,27 +7335,27 @@ 16 38 -462 +461 39 126 -462 +461 135 517 -462 +461 553 5009 -462 +461 5423 19562 -462 +461 23702 @@ -7376,22 +7396,22 @@ 15 55 -462 +461 59 223 -462 +461 229 1196 -462 +461 1266 2344 -462 +461 2536 @@ -7442,22 +7462,22 @@ 21 60 -462 +461 60 208 -462 +461 209 929 -462 +461 957 1965 -462 +461 1969 @@ -7508,22 +7528,22 @@ 21 60 -462 +461 60 208 -462 +461 209 931 -462 +461 958 1966 -462 +461 1969 @@ -7574,7 +7594,7 @@ 51 90 -462 +461 91 @@ -7595,57 +7615,57 @@ 1 2 -30675 +30670 2 3 -20243 +20240 3 4 -17982 +17979 4 5 -10431 +10430 5 6 -8899 +8898 6 7 -6869 +6868 7 9 -14371 +14368 9 13 -13994 +13992 13 30 -12304 +12302 30 111 -12146 +12144 111 2100 -12073 +12071 2100 @@ -7666,42 +7686,42 @@ 1 2 -56767 +56758 2 3 -35660 +35654 3 4 -11343 +11341 4 5 -9106 +9105 5 7 -11951 +11949 7 19 -12340 +12338 19 76 -12085 +12083 76 6440 -11672 +11670 @@ -7717,22 +7737,22 @@ 1 2 -118812 +118792 2 3 -19271 +19267 3 7 -12985 +12983 7 46 -9860 +9858 @@ -7748,57 +7768,57 @@ 1 2 -31757 +31752 2 3 -20085 +20082 3 4 -20255 +20252 4 5 -9994 +9992 5 6 -9264 +9263 6 7 -6978 +6977 7 9 -14602 +14599 9 13 -14103 +14101 13 27 -12352 +12350 27 60 -12109 +12107 60 153 -9422 +9421 @@ -7814,57 +7834,57 @@ 1 2 -31806 +31801 2 3 -19976 +19973 3 4 -18748 +18745 4 5 -10492 +10490 5 6 -9264 +9263 6 7 -6711 +6710 7 9 -14529 +14526 9 13 -14176 +14174 13 29 -12352 +12350 29 71 -12134 +12132 71 190 -10735 +10734 @@ -7880,7 +7900,7 @@ 1 2 -2310 +2309 2 @@ -7905,22 +7925,22 @@ 17 49 -620 +619 55 236 -620 +619 241 4440 -620 +619 4617 11969 -620 +619 12066 @@ -7941,7 +7961,7 @@ 1 2 -3258 +3257 2 @@ -7961,22 +7981,22 @@ 9 29 -620 +619 29 166 -620 +619 172 1667 -620 +619 1667 2846 -620 +619 2870 @@ -8022,22 +8042,22 @@ 17 45 -620 +619 45 189 -620 +619 192 1191 -620 +619 1218 2414 -620 +619 2469 @@ -8134,27 +8154,27 @@ 17 46 -620 +619 46 194 -620 +619 202 1220 -620 +619 1252 2470 -620 +619 2481 4808 -231 +230 @@ -11633,19 +11653,19 @@ numlines -544795 +544741 element_id -537220 +537168 num_lines -10273 +10272 num_code -7939 +7938 num_comment @@ -11663,12 +11683,12 @@ 1 2 -529731 +529679 2 7 -7489 +7488 @@ -11684,12 +11704,12 @@ 1 2 -529791 +529740 2 7 -7428 +7427 @@ -11705,7 +11725,7 @@ 1 2 -537135 +537083 2 @@ -11726,7 +11746,7 @@ 1 2 -4656 +4655 2 @@ -11777,7 +11797,7 @@ 1 2 -4729 +4728 2 @@ -11792,12 +11812,12 @@ 4 6 -851 +850 6 11 -924 +923 11 @@ -11828,7 +11848,7 @@ 1 2 -4717 +4716 2 @@ -11879,12 +11899,12 @@ 1 2 -3185 +3184 2 3 -1240 +1239 3 @@ -11899,12 +11919,12 @@ 6 10 -620 +619 10 21 -620 +619 21 @@ -11950,7 +11970,7 @@ 6 10 -693 +692 10 @@ -11981,12 +12001,12 @@ 1 2 -3234 +3233 2 3 -1228 +1227 3 @@ -11996,7 +12016,7 @@ 4 6 -620 +619 6 @@ -12016,7 +12036,7 @@ 28 33 -231 +230 @@ -12169,11 +12189,11 @@ diagnostics -76172 +76160 id -76172 +76160 severity @@ -12189,7 +12209,7 @@ full_error_message -65959 +65948 location @@ -12207,7 +12227,7 @@ 1 2 -76172 +76160 @@ -12223,7 +12243,7 @@ 1 2 -76172 +76160 @@ -12239,7 +12259,7 @@ 1 2 -76172 +76160 @@ -12255,7 +12275,7 @@ 1 2 -76172 +76160 @@ -12271,7 +12291,7 @@ 1 2 -76172 +76160 @@ -12702,7 +12722,7 @@ 1 2 -65947 +65936 841 @@ -12723,7 +12743,7 @@ 1 2 -65959 +65948 @@ -12739,7 +12759,7 @@ 1 2 -65959 +65948 @@ -12755,7 +12775,7 @@ 1 2 -65959 +65948 @@ -12771,7 +12791,7 @@ 1 2 -65959 +65948 @@ -12881,19 +12901,19 @@ files -66178 +66167 id -66178 +66167 name -66178 +66167 simple -45156 +45148 ext @@ -12915,7 +12935,7 @@ 1 2 -66178 +66167 @@ -12931,7 +12951,7 @@ 1 2 -66178 +66167 @@ -12947,7 +12967,7 @@ 1 2 -66178 +66167 @@ -12963,7 +12983,7 @@ 1 2 -66178 +66167 @@ -12979,7 +12999,7 @@ 1 2 -66178 +66167 @@ -12995,7 +13015,7 @@ 1 2 -66178 +66167 @@ -13011,7 +13031,7 @@ 1 2 -66178 +66167 @@ -13027,7 +13047,7 @@ 1 2 -66178 +66167 @@ -13043,12 +13063,12 @@ 1 2 -34201 +34196 2 3 -6869 +6868 3 @@ -13074,12 +13094,12 @@ 1 2 -34201 +34196 2 3 -6869 +6868 3 @@ -13105,12 +13125,12 @@ 1 2 -40329 +40322 2 3 -4194 +4193 3 @@ -13131,7 +13151,7 @@ 1 2 -45156 +45148 @@ -13389,19 +13409,19 @@ folders -12109 +12107 id -12109 +12107 name -12109 +12107 simple -3477 +3476 @@ -13415,7 +13435,7 @@ 1 2 -12109 +12107 @@ -13431,7 +13451,7 @@ 1 2 -12109 +12107 @@ -13447,7 +13467,7 @@ 1 2 -12109 +12107 @@ -13463,7 +13483,7 @@ 1 2 -12109 +12107 @@ -13545,15 +13565,15 @@ containerparent -78263 +78250 parent -12109 +12107 child -78263 +78250 @@ -13567,7 +13587,7 @@ 1 2 -5507 +5506 2 @@ -13597,12 +13617,12 @@ 14 30 -924 +923 30 153 -462 +461 @@ -13618,7 +13638,7 @@ 1 2 -78263 +78250 @@ -13628,11 +13648,11 @@ fileannotations -5689566 +5688625 id -5349 +5348 kind @@ -13640,11 +13660,11 @@ name -60196 +60186 value -49326 +49318 @@ -13663,7 +13683,7 @@ 2 3 -5203 +5202 @@ -13879,47 +13899,47 @@ 1 2 -9872 +9871 2 3 -6492 +6491 3 6 -4997 +4996 6 8 -4936 +4935 8 14 -4851 +4850 14 18 -4425 +4424 18 21 -4620 +4619 21 34 -4863 +4862 34 128 -4814 +4813 129 @@ -13929,7 +13949,7 @@ 236 395 -4559 +4558 395 @@ -13950,7 +13970,7 @@ 1 2 -60196 +60186 @@ -13966,12 +13986,12 @@ 1 2 -11039 +11038 2 3 -8729 +8728 3 @@ -13986,7 +14006,7 @@ 6 10 -5471 +5470 10 @@ -13996,32 +14016,32 @@ 14 17 -4644 +4643 17 22 -4644 +4643 22 40 -4559 +4558 40 83 -4583 +4582 83 163 -4535 +4534 164 1933 -1240 +1239 @@ -14037,7 +14057,7 @@ 1 2 -7526 +7524 2 @@ -14047,12 +14067,12 @@ 5 8 -3574 +3573 8 21 -3805 +3804 21 @@ -14062,7 +14082,7 @@ 23 25 -4462 +4461 25 @@ -14092,12 +14112,12 @@ 328 407 -4316 +4315 407 441 -1313 +1312 @@ -14113,7 +14133,7 @@ 1 2 -49314 +49306 2 @@ -14134,17 +14154,17 @@ 1 2 -7550 +7549 2 5 -2796 +2795 5 8 -3611 +3610 8 @@ -14159,27 +14179,27 @@ 18 21 -4073 +4072 21 31 -4462 +4461 31 42 -4024 +4023 42 54 -3769 +3768 54 81 -3781 +3780 81 @@ -14480,19 +14500,19 @@ macroinvocations -40821746 +40814994 id -40821746 +40814994 macro_id -89388 +89374 location -837108 +836970 kind @@ -14510,7 +14530,7 @@ 1 2 -40821746 +40814994 @@ -14526,7 +14546,7 @@ 1 2 -40821746 +40814994 @@ -14542,7 +14562,7 @@ 1 2 -40821746 +40814994 @@ -14558,12 +14578,12 @@ 1 2 -19271 +19267 2 3 -16948 +16946 3 @@ -14573,37 +14593,37 @@ 4 6 -7927 +7925 6 11 -7659 +7658 11 21 -7161 +7160 21 41 -6760 +6758 41 104 -6711 +6710 104 454 -6711 +6710 454 201153 -6492 +6491 @@ -14619,32 +14639,32 @@ 1 2 -47490 +47483 2 3 -11805 +11803 3 4 -5896 +5895 4 6 -7684 +7682 6 13 -7404 +7403 13 65 -6735 +6734 65 @@ -14665,12 +14685,12 @@ 1 2 -82580 +82566 2 3 -6808 +6807 @@ -14686,42 +14706,42 @@ 1 2 -314271 +314219 2 3 -186425 +186394 3 4 -44439 +44431 4 5 -58542 +58533 5 8 -67698 +67687 8 16 -64123 +64113 16 46 -64840 +64830 46 262302 -36767 +36761 @@ -14737,12 +14757,12 @@ 1 2 -783173 +783044 2 353 -53934 +53925 @@ -14758,7 +14778,7 @@ 1 2 -837108 +836970 @@ -14831,15 +14851,15 @@ macroparent -35828140 +35822215 id -35828140 +35822215 parent_id -27899913 +27895299 @@ -14853,7 +14873,7 @@ 1 2 -35828140 +35822215 @@ -14869,17 +14889,17 @@ 1 2 -21481229 +21477676 2 3 -5475383 +5474478 3 88 -943300 +943144 @@ -14967,11 +14987,11 @@ macro_argument_unexpanded -104821103 +104803767 invocation -31137110 +31131960 argument_index @@ -14979,7 +14999,7 @@ text -345992 +345935 @@ -14993,22 +15013,22 @@ 1 2 -8805677 +8804221 2 3 -12967718 +12965574 3 4 -7093708 +7092535 4 67 -2270005 +2269629 @@ -15024,22 +15044,22 @@ 1 2 -8881753 +8880284 2 3 -13154922 +13152746 3 4 -6886443 +6885304 4 67 -2213991 +2213625 @@ -15107,57 +15127,57 @@ 1 2 -42542 +42535 2 3 -69303 +69291 3 4 -15623 +15621 4 5 -46384 +46376 5 8 -26517 +26513 8 12 -15562 +15560 12 16 -24535 +24531 16 22 -26408 +26403 22 42 -26262 +26257 42 113 -25982 +25978 113 51881 -25958 +25953 51881 @@ -15178,17 +15198,17 @@ 1 2 -250123 +250082 2 3 -84464 +84450 3 9 -11404 +11402 @@ -15198,11 +15218,11 @@ macro_argument_expanded -104821103 +104803767 invocation -31137110 +31131960 argument_index @@ -15210,7 +15230,7 @@ text -209526 +209491 @@ -15224,22 +15244,22 @@ 1 2 -8805677 +8804221 2 3 -12967718 +12965574 3 4 -7093708 +7092535 4 67 -2270005 +2269629 @@ -15255,22 +15275,22 @@ 1 2 -12797439 +12795323 2 3 -11171126 +11169279 3 4 -5962973 +5961987 4 9 -1205570 +1205370 @@ -15312,7 +15332,7 @@ 1 2 -693 +692 2 @@ -15338,22 +15358,22 @@ 1 2 -25824 +25820 2 3 -42591 +42583 3 4 -6760 +6758 4 5 -15793 +15791 5 @@ -15363,37 +15383,37 @@ 6 7 -24560 +24555 7 9 -16705 +16702 9 15 -19149 +19146 15 31 -15854 +15851 31 87 -15915 +15912 87 393 -15745 +15742 396 1164221 -7258 +7257 @@ -15409,17 +15429,17 @@ 1 2 -105669 +105651 2 3 -87990 +87976 3 6 -15781 +15779 6 @@ -15434,15 +15454,15 @@ functions -3566471 +3565918 id -3566471 +3565918 name -315900 +315848 kind @@ -15460,7 +15480,7 @@ 1 2 -3566471 +3565918 @@ -15476,7 +15496,7 @@ 1 2 -3566471 +3565918 @@ -15492,27 +15512,27 @@ 1 2 -214718 +214682 2 3 -31271 +31266 3 5 -28377 +28360 5 13 -23818 +23826 13 109484 -17714 +17711 @@ -15528,12 +15548,12 @@ 1 2 -314283 +314231 2 3 -1617 +1616 @@ -15572,8 +15592,8 @@ 12 -108976 -108977 +108979 +108980 12 @@ -15635,15 +15655,15 @@ function_entry_point -1068641 +1068501 id -1065395 +1065255 entry_point -1068641 +1068501 @@ -15657,12 +15677,12 @@ 1 2 -1062453 +1062313 2 9 -2942 +2941 @@ -15678,7 +15698,7 @@ 1 2 -1068641 +1068501 @@ -15688,15 +15708,15 @@ function_return_type -3578144 +3577053 id -3566435 +3565347 return_type -1030695 +1030524 @@ -15710,12 +15730,12 @@ 1 2 -3555225 +3554138 2 6 -11210 +11208 @@ -15731,17 +15751,17 @@ 1 2 -316581 +316529 2 3 -649625 +649518 3 -81739 -64488 +81742 +64477 @@ -15762,49 +15782,49 @@ function_deleted -51259 +51251 id -51259 +51251 function_defaulted -9556 +9554 id -9556 +9554 fun_decls -3669417 +3668312 id -3669417 +3668312 function -3485812 +3484737 type_id -1023400 +1023231 name -282550 +281968 location -876623 +875943 @@ -15818,7 +15838,7 @@ 1 2 -3669417 +3668312 @@ -15834,7 +15854,7 @@ 1 2 -3669417 +3668312 @@ -15850,7 +15870,7 @@ 1 2 -3669417 +3668312 @@ -15866,7 +15886,7 @@ 1 2 -3669417 +3668312 @@ -15882,12 +15902,12 @@ 1 2 -3344750 +3343699 2 9 -141062 +141038 @@ -15903,12 +15923,12 @@ 1 2 -3467429 +3466357 2 6 -18383 +18380 @@ -15924,7 +15944,7 @@ 1 2 -3485812 +3484737 @@ -15940,12 +15960,12 @@ 1 2 -3390891 +3389832 2 9 -94920 +94905 @@ -15961,17 +15981,17 @@ 1 2 -302611 +302561 2 3 -648105 +647998 3 -87014 -72683 +87017 +72671 @@ -15987,17 +16007,17 @@ 1 2 -315608 +315556 2 3 -644154 +644047 3 -80915 -63637 +80918 +63626 @@ -16013,12 +16033,12 @@ 1 2 -953708 +953550 2 7429 -69692 +69680 @@ -16034,17 +16054,17 @@ 1 2 -917828 +917676 2 5 -82020 +82007 5 22296 -23550 +23547 @@ -16060,32 +16080,32 @@ 1 2 -169914 +169351 2 3 -32560 +32554 3 4 -18882 +18866 4 7 -25642 +25650 7 19 -21265 +21261 19 109747 -14286 +14283 @@ -16101,32 +16121,32 @@ 1 2 -181720 +181155 2 3 -31417 +31412 3 4 -16669 +16654 4 7 -22614 +22623 7 26 -21386 +21383 26 109468 -8741 +8740 @@ -16142,17 +16162,17 @@ 1 2 -246621 +246046 2 5 -23186 +23182 5 56198 -12742 +12739 @@ -16168,27 +16188,27 @@ 1 2 -181051 +180486 2 3 -47831 +47823 3 4 -18043 +18040 4 8 -22699 +22696 8 8793 -12924 +12922 @@ -16204,22 +16224,22 @@ 1 2 -590438 +589769 2 3 -147883 +147895 3 5 -69801 +69790 5 179 -65777 +65766 179 @@ -16240,22 +16260,22 @@ 1 2 -603399 +602727 2 3 -164734 +164743 3 9 -69765 +69753 9 3027 -38724 +38718 @@ -16271,17 +16291,17 @@ 1 2 -774589 +773926 2 4 -68208 +68197 4 1514 -33824 +33819 @@ -16297,12 +16317,12 @@ 1 2 -848975 +848299 2 134 -27648 +27643 @@ -16312,11 +16332,11 @@ fun_def -1297573 +1296860 id -1297573 +1296860 @@ -16564,26 +16584,26 @@ fun_decl_empty_throws -1416969 +1416734 fun_decl -1416969 +1416734 fun_decl_noexcept -16571 +16569 fun_decl -15696 +15693 constant -16438 +16435 @@ -16597,7 +16617,7 @@ 1 2 -14821 +14818 2 @@ -16618,7 +16638,7 @@ 1 2 -16304 +16301 2 @@ -16633,11 +16653,11 @@ fun_decl_empty_noexcept -364619 +364559 fun_decl -364619 +364559 @@ -16692,11 +16712,11 @@ param_decl_bind -4832591 +4830661 id -4832591 +4830661 index @@ -16704,7 +16724,7 @@ fun_decl -3159917 +3158896 @@ -16718,7 +16738,7 @@ 1 2 -4832591 +4830661 @@ -16734,7 +16754,7 @@ 1 2 -4832591 +4830661 @@ -16778,28 +16798,28 @@ 24 -882 -1212 +885 +1215 24 -1692 -2653 +1695 +2656 24 -4904 -13237 +4907 +13240 24 -34857 -76103 +34828 +76062 24 -259895 -259896 +259854 +259855 12 @@ -16844,28 +16864,28 @@ 24 -882 -1212 +885 +1215 24 -1692 -2653 +1695 +2656 24 -4904 -13237 +4907 +13240 24 -34857 -76103 +34828 +76062 24 -259895 -259896 +259854 +259855 12 @@ -16882,22 +16902,22 @@ 1 2 -2234636 +2234266 2 3 -501474 +501246 3 4 -262877 +262445 4 33 -160929 +160938 @@ -16913,22 +16933,22 @@ 1 2 -2234636 +2234266 2 3 -501474 +501246 3 4 -262877 +262445 4 33 -160929 +160938 @@ -16938,27 +16958,27 @@ var_decls -5603886 +5602108 id -5603886 +5602108 variable -5342175 +5340611 type_id -2038459 +2038122 name -139615 +139592 location -1360152 +1358468 @@ -16972,7 +16992,7 @@ 1 2 -5603886 +5602108 @@ -16988,7 +17008,7 @@ 1 2 -5603886 +5602108 @@ -17004,7 +17024,7 @@ 1 2 -5603886 +5602108 @@ -17020,7 +17040,7 @@ 1 2 -5603886 +5602108 @@ -17036,12 +17056,12 @@ 1 2 -5147993 +5146145 2 9 -194182 +194466 @@ -17057,12 +17077,12 @@ 1 2 -5292508 +5290709 2 7 -49667 +49902 @@ -17078,12 +17098,12 @@ 1 2 -5323427 +5321866 2 3 -18748 +18745 @@ -17099,12 +17119,12 @@ 1 2 -5226865 +5225490 2 9 -115310 +115121 @@ -17120,22 +17140,22 @@ 1 2 -1580816 +1580554 2 3 -244992 +244952 3 9 -154631 +154593 9 5708 -58020 +58022 @@ -17151,22 +17171,22 @@ 1 2 -1607187 +1606922 2 3 -235095 +234801 3 11 -155141 +155359 11 5254 -41034 +41040 @@ -17182,17 +17202,17 @@ 1 2 -1851073 +1850767 2 5 -162473 +162446 5 770 -24912 +24908 @@ -17208,17 +17228,17 @@ 1 2 -1771886 +1771593 2 4 -165160 +165132 4 3604 -101413 +101396 @@ -17234,37 +17254,37 @@ 1 2 -58956 +58861 2 3 -20851 +20860 3 4 -12304 +12290 4 6 -12644 +12715 6 10 -11514 +11524 10 22 -10675 +10673 22 255 -10492 +10490 263 @@ -17285,37 +17305,37 @@ 1 2 -62299 +62277 2 3 -20183 +20118 3 4 -13386 +13359 4 6 -11927 +11949 6 11 -11428 +11499 11 28 -10517 +10515 28 148426 -9872 +9871 @@ -17331,27 +17351,27 @@ 1 2 -84975 +84961 2 3 -18164 +18161 3 4 -9702 +9700 4 7 -11684 +11682 7 28 -10577 +10576 28 @@ -17372,32 +17392,32 @@ 1 2 -80342 +80329 2 3 -21277 +21273 3 4 -7781 +7780 4 7 -12425 +12423 7 21 -10565 +10563 21 9993 -7222 +7220 @@ -17413,22 +17433,22 @@ 1 2 -1010196 +1008108 2 3 -144296 +144734 3 6 -124101 +124044 6 114124 -81558 +81581 @@ -17444,22 +17464,22 @@ 1 2 -1062416 +1060320 2 3 -107517 +107961 3 6 -111918 +111863 6 113877 -78300 +78323 @@ -17475,17 +17495,17 @@ 1 2 -1167781 +1166129 2 3 -93060 +93045 3 104379 -99310 +99293 @@ -17501,12 +17521,12 @@ 1 2 -1350207 +1348524 2 52 -9945 +9943 @@ -17516,11 +17536,11 @@ var_def -2574671 +2573394 id -2574671 +2573394 @@ -17590,19 +17610,19 @@ type_decls -1469408 +1469165 id -1469408 +1469165 type_id -1434233 +1433996 location -1203770 +1203571 @@ -17616,7 +17636,7 @@ 1 2 -1469408 +1469165 @@ -17632,7 +17652,7 @@ 1 2 -1469408 +1469165 @@ -17648,12 +17668,12 @@ 1 2 -1408664 +1408431 2 24 -25569 +25564 @@ -17669,12 +17689,12 @@ 1 2 -1410099 +1409866 2 24 -24134 +24130 @@ -17690,12 +17710,12 @@ 1 2 -1142771 +1142582 2 469 -60998 +60988 @@ -17711,12 +17731,12 @@ 1 2 -1144413 +1144223 2 469 -59357 +59347 @@ -17726,45 +17746,45 @@ type_def -1035826 +1035654 id -1035826 +1035654 type_decl_top -297602 +297552 type_decl -297602 +297552 namespace_decls -151652 +151627 id -151652 +151627 namespace_id -8486 +8485 location -135445 +135422 bodylocation -135809 +135787 @@ -17778,7 +17798,7 @@ 1 2 -151652 +151627 @@ -17794,7 +17814,7 @@ 1 2 -151652 +151627 @@ -17810,7 +17830,7 @@ 1 2 -151652 +151627 @@ -17826,7 +17846,7 @@ 1 2 -4012 +4011 2 @@ -17877,7 +17897,7 @@ 1 2 -4012 +4011 2 @@ -17928,7 +17948,7 @@ 1 2 -4012 +4011 2 @@ -17979,12 +17999,12 @@ 1 2 -126155 +126135 2 8 -9289 +9287 @@ -18000,12 +18020,12 @@ 1 2 -126155 +126135 2 8 -9289 +9287 @@ -18021,7 +18041,7 @@ 1 2 -134618 +134595 2 @@ -18042,12 +18062,12 @@ 1 2 -126921 +126900 2 11 -8887 +8886 @@ -18063,12 +18083,12 @@ 1 2 -126921 +126900 2 9 -8887 +8886 @@ -18084,7 +18104,7 @@ 1 2 -135372 +135349 2 @@ -18099,19 +18119,19 @@ usings -320654 +320601 id -320654 +320601 element_id -49010 +49002 location -26468 +26464 @@ -18125,7 +18145,7 @@ 1 2 -320654 +320601 @@ -18141,7 +18161,7 @@ 1 2 -320654 +320601 @@ -18157,12 +18177,12 @@ 1 2 -41241 +41234 2 4 -4170 +4169 4 @@ -18183,12 +18203,12 @@ 1 2 -41241 +41234 2 4 -4170 +4169 4 @@ -18209,12 +18229,12 @@ 1 2 -20037 +20033 2 3 -2541 +2540 3 @@ -18240,12 +18260,12 @@ 1 2 -20037 +20033 2 3 -2541 +2540 3 @@ -18265,15 +18285,15 @@ using_container -485267 +485187 parent -8668 +8667 child -301079 +301029 @@ -18287,7 +18307,7 @@ 1 2 -3380 +3379 2 @@ -18317,7 +18337,7 @@ 178 179 -1398 +1397 179 @@ -18343,22 +18363,22 @@ 1 2 -217514 +217478 2 3 -55782 +55773 3 6 -22663 +22659 6 47 -5118 +5117 @@ -18734,15 +18754,15 @@ params -4805477 +4803552 id -4781331 +4779409 function -3119333 +3118318 index @@ -18750,7 +18770,7 @@ type_id -1866028 +1865720 @@ -18764,7 +18784,7 @@ 1 2 -4780589 +4778668 2 @@ -18785,7 +18805,7 @@ 1 2 -4781331 +4779409 @@ -18801,12 +18821,12 @@ 1 2 -4759664 +4757747 2 7 -21666 +21662 @@ -18822,22 +18842,22 @@ 1 2 -2208057 +2207692 2 3 -483079 +482853 3 4 -264652 +264220 4 33 -163543 +163552 @@ -18853,22 +18873,22 @@ 1 2 -2208057 +2207692 2 3 -483079 +482853 3 4 -264652 +264220 4 33 -163543 +163552 @@ -18884,22 +18904,22 @@ 1 2 -2315356 +2314438 2 3 -493170 +493113 3 5 -271011 +270978 5 20 -39794 +39787 @@ -18943,28 +18963,28 @@ 24 -880 -1206 +883 +1209 24 -1656 -2593 +1659 +2596 24 -4877 -13452 +4880 +13455 24 -35218 -74951 +35189 +74910 24 -256386 -256387 +256345 +256346 12 @@ -19009,28 +19029,28 @@ 24 -880 -1206 +883 +1209 24 -1656 -2593 +1659 +2596 24 -4877 -13452 +4880 +13455 24 -35218 -74951 +35189 +74910 24 -256557 -256558 +256516 +256517 12 @@ -19113,22 +19133,22 @@ 1 2 -1495172 +1494924 2 3 -199653 +199620 3 13 -141706 +141683 13 5275 -29496 +29491 @@ -19144,22 +19164,22 @@ 1 2 -1517288 +1517025 2 3 -187288 +187257 3 17 -140916 +140905 17 4798 -20535 +20532 @@ -19175,12 +19195,12 @@ 1 2 -1751301 +1751012 2 33 -114727 +114708 @@ -19278,19 +19298,19 @@ membervariables -329712 +329658 id -329712 +325099 type_id -145110 +145086 name -59077 +59068 @@ -19304,7 +19324,12 @@ 1 2 -329712 +320637 + + +2 +7 +4461 @@ -19320,7 +19345,7 @@ 1 2 -329712 +325099 @@ -19336,22 +19361,22 @@ 1 2 -118411 +118391 2 3 -13398 +13396 3 11 -10991 +10989 11 1212 -2310 +2309 @@ -19367,17 +19392,17 @@ 1 2 -125937 +125916 2 3 -9884 +9883 3 266 -9289 +9287 @@ -19393,27 +19418,27 @@ 1 2 -31222 +31217 2 3 -9058 +9056 3 4 -5945 +5944 4 6 -4486 +4485 6 15 -4535 +4534 15 @@ -19434,22 +19459,22 @@ 1 2 -38262 +38256 2 3 -7526 +7524 3 4 -4036 +4035 4 7 -4766 +4765 7 @@ -19473,7 +19498,7 @@ id -301143 +301136 type_id @@ -19495,7 +19520,12 @@ 1 2 -301143 +301129 + + +2 +3 +7 @@ -19511,7 +19541,7 @@ 1 2 -301143 +301136 @@ -21723,15 +21753,15 @@ derivedtypes -4572704 +4572470 id -4572704 +4572470 name -2240812 +2240442 kind @@ -21739,7 +21769,7 @@ type_id -2743236 +2743025 @@ -21753,7 +21783,7 @@ 1 2 -4572704 +4572470 @@ -21769,7 +21799,7 @@ 1 2 -4572704 +4572470 @@ -21785,7 +21815,7 @@ 1 2 -4572704 +4572470 @@ -21801,17 +21831,17 @@ 1 2 -1641146 +1640352 2 3 -478908 +479352 3 42612 -120757 +120737 @@ -21827,7 +21857,7 @@ 1 2 -2240788 +2240417 2 @@ -21848,17 +21878,17 @@ 1 2 -1641146 +1640631 2 3 -478908 +479072 3 42594 -120757 +120737 @@ -21877,8 +21907,8 @@ 12 -38 -39 +61 +62 12 @@ -21887,8 +21917,8 @@ 12 -25102 -25103 +25122 +25123 12 @@ -21989,8 +22019,8 @@ 12 -25102 -25103 +25122 +25123 12 @@ -22027,22 +22057,22 @@ 1 2 -1661767 +1661711 2 3 -405581 +405562 3 4 -615800 +615674 4 -198 -60087 +202 +60077 @@ -22058,22 +22088,22 @@ 1 2 -1663092 +1663036 2 3 -405435 +405416 3 4 -614621 +614495 4 198 -60087 +60077 @@ -22089,22 +22119,22 @@ 1 2 -1663444 +1663388 2 3 -406845 +406827 3 4 -614584 +614458 4 7 -58360 +58350 @@ -22114,11 +22144,11 @@ pointerishsize -3358659 +3358347 id -3358659 +3358347 size @@ -22140,7 +22170,7 @@ 1 2 -3358659 +3358347 @@ -22156,7 +22186,7 @@ 1 2 -3358659 +3358347 @@ -22175,8 +22205,8 @@ 12 -276220 -276221 +276240 +276241 12 @@ -22207,8 +22237,8 @@ 12 -276241 -276242 +276261 +276262 12 @@ -22235,19 +22265,19 @@ arraysizes -18553 +18830 id -18553 +18830 num_elements -2395 +2394 bytesize -2784 +2783 alignment @@ -22265,7 +22295,7 @@ 1 2 -18553 +18830 @@ -22281,7 +22311,7 @@ 1 2 -18553 +18830 @@ -22297,7 +22327,7 @@ 1 2 -18553 +18830 @@ -22341,8 +22371,8 @@ 182 -37 -112 +38 +116 158 @@ -22395,7 +22425,7 @@ 1 2 -1775 +1774 2 @@ -22461,12 +22491,12 @@ 17 53 -231 +218 55 -70 -36 +75 +48 @@ -22542,13 +22572,13 @@ 12 -11 -12 +17 +18 12 -12 -13 +18 +19 12 @@ -22557,8 +22587,8 @@ 12 -44 -45 +50 +51 12 @@ -22567,8 +22597,8 @@ 12 -384 -385 +389 +390 12 @@ -22676,15 +22706,15 @@ typedefbase -1884327 +1884015 id -1884327 +1884015 type_id -897232 +897083 @@ -22698,7 +22728,7 @@ 1 2 -1884327 +1884015 @@ -22714,22 +22744,22 @@ 1 2 -702441 +702325 2 3 -93218 +93203 3 7 -76014 +76002 7 5391 -25557 +25552 @@ -22739,19 +22769,19 @@ decltypes -45849 +45841 id -45849 +45841 expr -43332 +43325 base_type -6480 +6479 parentheses_would_change_meaning @@ -22769,7 +22799,7 @@ 1 2 -45849 +45841 @@ -22785,7 +22815,7 @@ 1 2 -45849 +45841 @@ -22801,7 +22831,7 @@ 1 2 -45849 +45841 @@ -22817,7 +22847,7 @@ 1 2 -40815 +40809 2 @@ -22838,7 +22868,7 @@ 1 2 -40815 +40809 2 @@ -22859,7 +22889,7 @@ 1 2 -43332 +43325 @@ -22875,12 +22905,12 @@ 1 2 -3623 +3622 2 3 -2553 +2552 3 @@ -22901,7 +22931,7 @@ 1 2 -2541 +2540 2 @@ -22932,7 +22962,7 @@ 1 2 -6480 +6479 @@ -23005,15 +23035,15 @@ usertypes -4328015 +4327300 id -4328015 +4327300 name -899578 +899429 kind @@ -23031,7 +23061,7 @@ 1 2 -4328015 +4327300 @@ -23047,7 +23077,7 @@ 1 2 -4328015 +4327300 @@ -23063,22 +23093,22 @@ 1 2 -597490 +597391 2 3 -199592 +199559 3 9 -71783 +71771 9 31201 -30712 +30707 @@ -23094,12 +23124,12 @@ 1 2 -842494 +842355 2 10 -57083 +57074 @@ -23236,11 +23266,11 @@ usertypesize -1364918 +1364692 id -1364918 +1364692 size @@ -23262,7 +23292,7 @@ 1 2 -1364918 +1364692 @@ -23278,7 +23308,7 @@ 1 2 -1364918 +1364692 @@ -23531,15 +23561,15 @@ mangled_name -4326447 +4325731 id -4326447 +4325731 mangled_name -533074 +532986 @@ -23553,7 +23583,7 @@ 1 2 -4326447 +4325731 @@ -23569,32 +23599,32 @@ 1 2 -326831 +326776 2 3 -67771 +67759 3 4 -35794 +35788 4 8 -44998 +44990 8 36 -40183 +40177 36 8470 -17495 +17493 @@ -23604,59 +23634,59 @@ is_pod_class -1041528 +1041356 id -1041528 +1041356 is_standard_layout_class -1119026 +1118841 id -1119026 +1118841 is_complete -1346085 +1345862 id -1346085 +1345862 is_class_template -246658 +246617 id -246658 +246617 class_instantiation -1109032 +1108848 to -1107305 +1107122 from -72525 +72513 @@ -23670,12 +23700,12 @@ 1 2 -1105676 +1105493 2 4 -1629 +1628 @@ -23691,42 +23721,42 @@ 1 2 -21605 +21601 2 3 -12900 +12897 3 4 -7489 +7488 4 5 -4790 +4789 5 7 -5872 +5871 7 11 -6516 +6515 11 20 -5544 +5543 20 89 -5471 +5470 89 @@ -23741,11 +23771,11 @@ class_template_argument -2800453 +2799990 type_id -1339823 +1339602 index @@ -23753,7 +23783,7 @@ arg_type -921439 +921287 @@ -23767,27 +23797,27 @@ 1 2 -593757 +593659 2 3 -438178 +438105 3 4 -175628 +175599 4 7 -108647 +108629 7 113 -23611 +23607 @@ -23803,22 +23833,22 @@ 1 2 -619740 +619637 2 3 -445764 +445691 3 4 -188030 +187999 4 113 -86288 +86274 @@ -23926,22 +23956,22 @@ 1 2 -571203 +571109 2 3 -205818 +205784 3 5 -75382 +75369 5 5259 -69035 +69024 @@ -23957,17 +23987,17 @@ 1 2 -806055 +805922 2 3 -96027 +96011 3 22 -19356 +19353 @@ -23977,15 +24007,15 @@ is_proxy_class_for -50080 +50072 id -50080 +50072 templ_param_id -50080 +50072 @@ -23999,7 +24029,7 @@ 1 2 -50080 +50072 @@ -24015,7 +24045,7 @@ 1 2 -50080 +50072 @@ -24331,26 +24361,26 @@ is_function_template -1058258 +1058083 id -1058258 +1058083 function_instantiation -739585 +739463 to -739585 +739463 from -136125 +136103 @@ -24364,7 +24394,7 @@ 1 2 -739585 +739463 @@ -24380,32 +24410,32 @@ 1 2 -63029 +63018 2 3 -32402 +32396 3 4 -8194 +8193 4 5 -9301 +9299 5 10 -10942 +10940 10 57 -10225 +10223 58 @@ -24420,11 +24450,11 @@ function_template_argument -1911112 +1910796 function_id -1112606 +1112422 index @@ -24432,7 +24462,7 @@ arg_type -369908 +369847 @@ -24446,22 +24476,22 @@ 1 2 -634901 +634796 2 3 -361093 +361033 3 5 -84659 +84645 5 21 -31952 +31947 @@ -24477,22 +24507,22 @@ 1 2 -658075 +657966 2 3 -332448 +332393 3 5 -90920 +90905 5 21 -31162 +31156 @@ -24730,27 +24760,27 @@ 1 2 -249588 +249547 2 3 -48706 +48698 3 6 -29788 +29783 6 19 -28000 +27996 19 906 -13824 +13821 @@ -24766,12 +24796,12 @@ 1 2 -341287 +341230 2 5 -28134 +28129 5 @@ -24786,26 +24816,26 @@ is_variable_template -19781 +19778 id -19781 +19778 variable_instantiation -31842 +31837 to -31842 +31837 from -6735 +6734 @@ -24819,7 +24849,7 @@ 1 2 -31842 +31837 @@ -24835,7 +24865,7 @@ 1 2 -2383 +2382 2 @@ -24850,7 +24880,7 @@ 4 5 -693 +692 5 @@ -24875,11 +24905,11 @@ variable_template_argument -5536 +5529 variable_id -1047 +843 index @@ -24901,12 +24931,12 @@ 1 2 -856 +692 2 3 -151 +112 3 @@ -24927,37 +24957,42 @@ 1 2 -553 +369 2 3 -164 +125 3 4 -59 +65 4 6 -79 +72 6 8 -85 +72 8 -26 -79 +13 +65 -30 +13 +85 +65 + + +202 203 -26 +6 @@ -24981,18 +25016,18 @@ 6 -12 -13 +9 +10 6 -21 -22 +17 +18 6 -155 -156 +125 +126 6 @@ -25086,15 +25121,15 @@ routinetypes -444646 +444572 id -444646 +444572 return_type -184832 +184802 @@ -25108,7 +25143,7 @@ 1 2 -444646 +444572 @@ -25124,17 +25159,17 @@ 1 2 -148345 +148320 2 3 -21046 +21042 3 18 -13945 +13943 18 @@ -25149,11 +25184,11 @@ routinetypeargs -741324 +741201 routine -362820 +362760 index @@ -25161,7 +25196,7 @@ type_id -209429 +209394 @@ -25175,27 +25210,27 @@ 1 2 -169440 +169412 2 3 -95370 +95355 3 4 -58153 +58144 4 6 -31356 +31351 6 33 -8498 +8497 @@ -25211,22 +25246,22 @@ 1 2 -194863 +194831 2 3 -95869 +95853 3 4 -49715 +49707 4 22 -22371 +22367 @@ -25384,27 +25419,27 @@ 1 2 -123712 +123691 2 3 -40876 +40869 3 4 -13508 +13505 4 7 -17945 +17942 7 1097 -13386 +13384 @@ -25420,17 +25455,17 @@ 1 2 -156856 +156830 2 3 -41168 +41161 3 33 -11404 +11402 @@ -25440,15 +25475,15 @@ ptrtomembers -12182 +12180 id -12182 +12180 type_id -10249 +10247 class_id @@ -25466,7 +25501,7 @@ 1 2 -12182 +12180 @@ -25482,7 +25517,7 @@ 1 2 -12182 +12180 @@ -25498,7 +25533,7 @@ 1 2 -9896 +9895 2 @@ -25519,7 +25554,7 @@ 1 2 -9896 +9895 2 @@ -25540,7 +25575,7 @@ 1 2 -4620 +4619 2 @@ -25550,7 +25585,7 @@ 8 9 -462 +461 16 @@ -25571,7 +25606,7 @@ 1 2 -4620 +4619 2 @@ -25581,7 +25616,7 @@ 8 9 -462 +461 16 @@ -25644,11 +25679,11 @@ typespecifiers -1465104 +1464861 type_id -1460423 +1460181 spec_id @@ -25666,7 +25701,7 @@ 1 2 -1455742 +1455501 2 @@ -25727,11 +25762,11 @@ funspecifiers -11372263 +11370456 func_id -3512537 +3511992 spec_id @@ -25749,27 +25784,27 @@ 1 2 -342673 +342616 2 3 -464124 +464083 3 4 -909305 +909155 4 5 -1670679 +1670402 5 8 -125754 +125733 @@ -25833,8 +25868,8 @@ 12 -25327 -25328 +25330 +25331 12 @@ -25858,8 +25893,8 @@ 12 -263006 -263007 +263009 +263010 12 @@ -25870,11 +25905,11 @@ varspecifiers -1124177 +1124158 var_id -935111 +935091 spec_id @@ -25892,7 +25927,7 @@ 1 2 -795278 +795258 2 @@ -25926,8 +25961,8 @@ 6 -452 -453 +447 +448 6 @@ -25936,8 +25971,8 @@ 6 -8407 -8408 +8409 +8410 6 @@ -27178,15 +27213,15 @@ typeattributes -12121 +12119 type_id -10833 +10831 spec_id -12121 +12119 @@ -27200,7 +27235,7 @@ 1 2 -10298 +10296 2 @@ -27221,7 +27256,7 @@ 1 2 -12121 +12119 @@ -27231,15 +27266,15 @@ funcattributes -327062 +327044 func_id -174935 +174943 spec_id -327062 +327044 @@ -27253,17 +27288,17 @@ 1 2 -94057 +94078 2 3 -13556 +13554 3 4 -65144 +65134 4 @@ -27284,7 +27319,7 @@ 1 2 -327062 +327044 @@ -27400,15 +27435,15 @@ unspecifiedtype -9371300 +9370273 type_id -9371300 +9370273 unspecified_type_id -5063090 +5062776 @@ -27422,7 +27457,7 @@ 1 2 -9371300 +9370273 @@ -27438,17 +27473,17 @@ 1 2 -2734080 +2733689 2 3 -1949800 +1949939 3 7841 -379209 +379146 @@ -27458,11 +27493,11 @@ member -5113037 +5112192 parent -809934 +809800 index @@ -27470,7 +27505,7 @@ child -5068306 +5067468 @@ -27484,47 +27519,47 @@ 1 2 -46955 +46948 2 3 -191689 +191658 3 4 -208371 +208336 4 5 -90300 +90285 5 7 -65084 +65073 7 9 -67224 +67212 9 15 -68233 +68221 15 39 -62482 +62471 39 245 -9593 +9591 @@ -27540,47 +27575,47 @@ 1 2 -46226 +46218 2 3 -191823 +191791 3 4 -202729 +202696 4 5 -93170 +93154 5 7 -65777 +65766 7 9 -67357 +67346 9 15 -69072 +69060 15 37 -61242 +61231 37 281 -12535 +12533 @@ -27611,42 +27646,42 @@ 9 18 -231 +230 23 100 -231 +230 122 186 -231 +230 188 293 -231 +230 296 374 -231 +230 375 542 -231 +230 572 3257 -231 +230 3427 21556 -231 +230 29162 @@ -27677,32 +27712,32 @@ 5 7 -231 +230 7 13 -231 +230 13 70 -231 +230 71 160 -231 +230 160 256 -231 +230 263 345 -231 +230 346 @@ -27712,12 +27747,12 @@ 492 1685 -231 +230 1926 8765 -231 +230 10213 @@ -27738,7 +27773,7 @@ 1 2 -5068306 +5067468 @@ -27754,12 +27789,12 @@ 1 2 -5043394 +5042560 2 11 -24912 +24908 @@ -27769,15 +27804,15 @@ enclosingfunction -131773 +131751 child -131773 +131751 parent -74251 +74239 @@ -27791,7 +27826,7 @@ 1 2 -131773 +131751 @@ -27807,22 +27842,22 @@ 1 2 -39247 +39240 2 3 -21933 +21930 3 4 -7209 +7208 4 6 -5653 +5652 6 @@ -27837,15 +27872,15 @@ derivations -370358 +370297 derivation -370358 +370297 sub -346612 +346555 index @@ -27853,11 +27888,11 @@ super -237819 +237779 location -96367 +96351 @@ -27871,7 +27906,7 @@ 1 2 -370358 +370297 @@ -27887,7 +27922,7 @@ 1 2 -370358 +370297 @@ -27903,7 +27938,7 @@ 1 2 -370358 +370297 @@ -27919,7 +27954,7 @@ 1 2 -370358 +370297 @@ -27935,12 +27970,12 @@ 1 2 -326174 +326120 2 7 -20438 +20434 @@ -27956,12 +27991,12 @@ 1 2 -334989 +334933 2 7 -11623 +11621 @@ -27977,12 +28012,12 @@ 1 2 -326186 +326132 2 7 -20426 +20422 @@ -27998,12 +28033,12 @@ 1 2 -334977 +334921 2 7 -11635 +11633 @@ -28183,12 +28218,12 @@ 1 2 -222390 +222353 2 766 -15429 +15426 @@ -28204,12 +28239,12 @@ 1 2 -222402 +222365 2 766 -15416 +15414 @@ -28225,7 +28260,7 @@ 1 2 -237320 +237281 2 @@ -28246,12 +28281,12 @@ 1 2 -229733 +229695 2 439 -8085 +8084 @@ -28267,17 +28302,17 @@ 1 2 -74677 +74664 2 3 -9325 +9323 3 8 -7307 +7306 8 @@ -28298,22 +28333,22 @@ 1 2 -77206 +77193 2 3 -7003 +7002 3 9 -7611 +7609 9 682 -4547 +4546 @@ -28329,7 +28364,7 @@ 1 2 -96343 +96327 2 @@ -28350,17 +28385,17 @@ 1 2 -77680 +77667 2 3 -9045 +9044 3 11 -7270 +7269 11 @@ -28375,11 +28410,11 @@ derspecifiers -372996 +372934 der_id -370321 +370260 spec_id @@ -28397,7 +28432,7 @@ 1 2 -367646 +367586 2 @@ -28443,11 +28478,11 @@ direct_base_offsets -282075 +282029 der_id -282075 +282029 offset @@ -28465,7 +28500,7 @@ 1 2 -282075 +282029 @@ -28546,7 +28581,7 @@ virtual_base_offsets -7027 +7026 sub @@ -28837,23 +28872,23 @@ frienddecls -231217 +231178 id -231217 +231178 type_id -19514 +19511 decl_id -28815 +28810 location -8097 +8096 @@ -28867,7 +28902,7 @@ 1 2 -231217 +231178 @@ -28883,7 +28918,7 @@ 1 2 -231217 +231178 @@ -28899,7 +28934,7 @@ 1 2 -231217 +231178 @@ -28915,12 +28950,12 @@ 1 2 -6857 +6856 2 3 -2468 +2467 3 @@ -28940,17 +28975,17 @@ 10 16 -1471 +1470 16 34 -1787 +1786 36 59 -1471 +1470 59 @@ -28971,12 +29006,12 @@ 1 2 -6857 +6856 2 3 -2468 +2467 3 @@ -28996,17 +29031,17 @@ 10 16 -1471 +1470 16 34 -1787 +1786 36 59 -1471 +1470 59 @@ -29027,12 +29062,12 @@ 1 2 -17751 +17748 2 5 -1544 +1543 5 @@ -29053,7 +29088,7 @@ 1 2 -15818 +15815 2 @@ -29063,7 +29098,7 @@ 3 5 -2480 +2479 5 @@ -29078,7 +29113,7 @@ 20 28 -2468 +2467 28 @@ -29099,7 +29134,7 @@ 1 2 -15818 +15815 2 @@ -29109,7 +29144,7 @@ 3 5 -2480 +2479 5 @@ -29124,7 +29159,7 @@ 20 28 -2468 +2467 28 @@ -29145,7 +29180,7 @@ 1 2 -28219 +28215 2 @@ -29166,7 +29201,7 @@ 1 2 -6918 +6917 2 @@ -29192,7 +29227,7 @@ 1 2 -7611 +7609 2 @@ -29213,7 +29248,7 @@ 1 2 -6930 +6929 2 @@ -29233,19 +29268,19 @@ comments -1743921 +1743633 id -1743921 +1743633 contents -864635 +864492 location -1743921 +1743633 @@ -29259,7 +29294,7 @@ 1 2 -1743921 +1743633 @@ -29275,7 +29310,7 @@ 1 2 -1743921 +1743633 @@ -29291,17 +29326,17 @@ 1 2 -731646 +731525 2 3 -83163 +83149 3 10736 -49825 +49817 @@ -29317,17 +29352,17 @@ 1 2 -731646 +731525 2 3 -83163 +83149 3 10736 -49825 +49817 @@ -29343,7 +29378,7 @@ 1 2 -1743921 +1743633 @@ -29359,7 +29394,7 @@ 1 2 -1743921 +1743633 @@ -29369,15 +29404,15 @@ commentbinding -778395 +778436 id -679134 +679021 element -747391 +747438 @@ -29391,17 +29426,17 @@ 1 2 -616274 +616002 2 4 -58384 +58545 4 97 -4474 +4473 @@ -29417,12 +29452,12 @@ 1 2 -716387 +716439 2 3 -31004 +30998 @@ -29485,22 +29520,22 @@ compgenerated -6721234 +6720341 id -6721234 +6720341 synthetic_destructor_call -59503 +59493 element -47430 +47422 i @@ -29508,7 +29543,7 @@ destructor_call -59503 +49573 @@ -29522,17 +29557,17 @@ 1 2 -38797 +38791 2 3 -6322 +6321 3 29 -2310 +2309 @@ -29548,17 +29583,17 @@ 1 2 -38797 +38791 2 3 -6322 +6321 3 29 -2310 +2309 @@ -29646,7 +29681,17 @@ 1 2 -59503 +43823 + + +2 +3 +3719 + + +3 +26 +2030 @@ -29662,7 +29707,7 @@ 1 2 -59503 +49573 @@ -29672,15 +29717,15 @@ namespaces -8498 +8497 id -8498 +8497 name -4571 +4570 @@ -29694,7 +29739,7 @@ 1 2 -8498 +8497 @@ -29710,12 +29755,12 @@ 1 2 -3842 +3841 2 3 -462 +461 3 @@ -29741,15 +29786,15 @@ namespacembrs -1562177 +1561845 parentid -7915 +7913 memberid -1562177 +1561845 @@ -29798,7 +29843,7 @@ 27 46 -620 +619 46 @@ -29834,7 +29879,7 @@ 1 2 -1562177 +1561845 @@ -30134,11 +30179,11 @@ iscall -2364889 +2365240 caller -2364889 +2365240 kind @@ -30156,7 +30201,7 @@ 1 2 -2364889 +2365240 @@ -30180,8 +30225,8 @@ 12 -187583 -187584 +187644 +187645 12 @@ -30192,11 +30237,11 @@ numtemplatearguments -157974 +157948 expr_id -157974 +157948 num @@ -30214,7 +30259,7 @@ 1 2 -157974 +157948 @@ -30637,7 +30682,7 @@ var -1549120 +1549133 @@ -30672,7 +30717,7 @@ 1 2 -685862 +685882 2 @@ -30682,7 +30727,7 @@ 3 4 -236837 +236831 4 @@ -30790,11 +30835,11 @@ expr_allocator -27696 +27692 expr -27696 +27692 func @@ -30816,7 +30861,7 @@ 1 2 -27696 +27692 @@ -30832,7 +30877,7 @@ 1 2 -27696 +27692 @@ -30941,11 +30986,11 @@ expr_deallocator -31004 +30998 expr -31004 +30998 func @@ -30967,7 +31012,7 @@ 1 2 -31004 +30998 @@ -30983,7 +31028,7 @@ 1 2 -31004 +30998 @@ -31257,11 +31302,11 @@ values -8776937 +8776796 id -8776937 +8776796 str @@ -31279,7 +31324,7 @@ 1 2 -8776937 +8776796 @@ -31304,7 +31349,7 @@ 3 -4044676 +4044535 45824 @@ -31315,11 +31360,11 @@ valuetext -4759522 +4759381 id -4759522 +4759381 text @@ -31337,7 +31382,7 @@ 1 2 -4759522 +4759381 @@ -31378,15 +31423,15 @@ valuebind -9499212 +9499071 val -8769772 +8769631 expr -9499212 +9499071 @@ -31400,7 +31445,7 @@ 1 2 -8041064 +8040923 2 @@ -31426,7 +31471,7 @@ 1 2 -9499212 +9499071 @@ -31436,15 +31481,15 @@ fieldoffsets -259582 +259539 id -259582 +259539 byteoffset -3915 +3914 bitoffset @@ -31462,7 +31507,7 @@ 1 2 -259582 +259539 @@ -31478,7 +31523,7 @@ 1 2 -259582 +259539 @@ -31494,7 +31539,7 @@ 1 2 -1690 +1689 2 @@ -31545,7 +31590,7 @@ 1 2 -3854 +3853 2 @@ -31841,7 +31886,7 @@ var -649678 +649685 expr @@ -31911,12 +31956,12 @@ 1 2 -561980 +562000 2 16 -29092 +29079 16 @@ -31942,12 +31987,12 @@ 1 2 -561980 +562000 2 16 -29092 +29079 16 @@ -31973,11 +32018,11 @@ 1 2 -649665 +649672 2 -4 +3 13 @@ -32139,15 +32184,15 @@ expr_ancestor -67783 +67772 exp -67187 +67176 ancestor -49703 +49695 @@ -32161,7 +32206,7 @@ 1 2 -66616 +66605 2 @@ -32182,12 +32227,12 @@ 1 2 -37411 +37405 2 3 -10152 +10150 3 @@ -32468,15 +32513,15 @@ expr_types -18622475 +18617681 id -18449753 +18444987 typeid -1372858 +1372679 value_category @@ -32494,12 +32539,12 @@ 1 2 -18277261 +18272524 2 4 -172491 +172463 @@ -32515,7 +32560,7 @@ 1 2 -18449753 +18444987 @@ -32531,42 +32576,42 @@ 1 2 -530691 +530579 2 3 -259315 +259272 3 4 -113571 +113565 4 5 -95382 +95403 5 8 -122848 +122840 8 14 -105669 +105663 14 45 -102969 +102952 45 -111447 -42408 +111456 +42401 @@ -32582,17 +32627,17 @@ 1 2 -1207284 +1207133 2 3 -157743 +157717 3 4 -7830 +7828 @@ -32611,13 +32656,13 @@ 12 -340829 -340830 +340895 +340896 12 -1172082 -1172083 +1171875 +1171876 12 @@ -32637,13 +32682,13 @@ 12 -29728 -29729 +29730 +29731 12 -96108 -96109 +96110 +96111 12 @@ -32654,15 +32699,15 @@ new_allocated_type -29532 +29527 expr -29532 +29527 type_id -18237 +18234 @@ -32676,7 +32721,7 @@ 1 2 -29532 +29527 @@ -32692,12 +32737,12 @@ 1 2 -12669 +12667 2 3 -4036 +4035 3 @@ -33317,15 +33362,15 @@ condition_decl_bind -7647 +7646 expr -7647 +7646 decl -7647 +7646 @@ -33339,7 +33384,7 @@ 1 2 -7647 +7646 @@ -33355,7 +33400,7 @@ 1 2 -7647 +7646 @@ -33413,7 +33458,7 @@ 3 6 -231 +230 6 @@ -35082,19 +35127,19 @@ stmts -4943889 +4943740 id -4943889 +4943740 kind -231 +230 location -1317792 +1317574 @@ -35108,7 +35153,7 @@ 1 2 -4943889 +4943740 @@ -35124,7 +35169,7 @@ 1 2 -4943889 +4943740 @@ -35213,23 +35258,23 @@ 12 -53234 -53235 +53254 +53255 12 -85849 -85850 +85878 +85879 12 -98480 -98481 +98483 +98484 12 -115021 -115022 +115024 +115025 12 @@ -35352,32 +35397,32 @@ 1 2 -780425 +779628 2 3 -178534 +179173 3 4 -120295 +120275 4 6 -106909 +106891 6 19 -102811 +102794 19 4895 -28815 +28810 @@ -35393,12 +35438,12 @@ 1 2 -1291907 +1291693 2 9 -25885 +25881 @@ -35696,15 +35741,15 @@ while_body -32912 +32907 while_stmt -32912 +32907 body_id -32912 +32907 @@ -35718,7 +35763,7 @@ 1 2 -32912 +32907 @@ -35734,7 +35779,7 @@ 1 2 -32912 +32907 @@ -37041,15 +37086,15 @@ blockscope -1398451 +1398256 block -1398451 +1398256 enclosing -1254459 +1254288 @@ -37063,7 +37108,7 @@ 1 2 -1398451 +1398256 @@ -37079,12 +37124,12 @@ 1 2 -1171794 +1171636 2 509 -82665 +82651 @@ -37285,11 +37330,11 @@ preprocdirects -1456362 +1456121 id -1456362 +1456121 kind @@ -37297,7 +37342,7 @@ location -1449371 +1449131 @@ -37311,7 +37356,7 @@ 1 2 -1456362 +1456121 @@ -37327,7 +37372,7 @@ 1 2 -1456362 +1456121 @@ -37495,7 +37540,7 @@ 1 2 -1449006 +1448766 2 @@ -37516,7 +37561,7 @@ 1 2 -1449371 +1449131 @@ -37526,15 +37571,15 @@ preprocpair -416171 +416102 begin -329749 +329694 elseelifend -416171 +416102 @@ -37548,17 +37593,17 @@ 1 2 -261442 +261399 2 3 -60257 +60247 3 53 -8048 +8047 @@ -37574,7 +37619,7 @@ 1 2 -416171 +416102 @@ -37584,41 +37629,41 @@ preproctrue -183142 +183112 branch -183142 +183112 preprocfalse -130022 +130000 branch -130022 +130000 preproctext -1062951 +1062775 id -1062951 +1062775 head -510168 +510083 body -192990 +192959 @@ -37632,7 +37677,7 @@ 1 2 -1062951 +1062775 @@ -37648,7 +37693,7 @@ 1 2 -1062951 +1062775 @@ -37664,22 +37709,22 @@ 1 2 -380522 +380459 2 3 -86130 +86116 3 19 -38420 +38414 19 752 -5094 +5093 @@ -37695,12 +37740,12 @@ 1 2 -486288 +486208 2 38 -23879 +23875 @@ -37716,12 +37761,12 @@ 1 2 -181282 +181252 2 64395 -11708 +11706 @@ -37737,12 +37782,12 @@ 1 2 -182923 +182893 2 21671 -10067 +10065 @@ -37752,15 +37797,15 @@ includes -321858 +321805 id -321858 +321805 included -60172 +60162 @@ -37774,7 +37819,7 @@ 1 2 -321858 +321805 @@ -37790,32 +37835,32 @@ 1 2 -29508 +29503 2 3 -9896 +9895 3 4 -5118 +5117 4 6 -5349 +5348 6 11 -4644 +4643 11 41 -4559 +4558 41 @@ -37878,11 +37923,11 @@ link_parent -19146504 +19143338 element -5077231 +5076427 link_target @@ -37900,32 +37945,32 @@ 1 2 -1439595 +1439430 2 3 -1904972 +1904620 3 4 -772523 +772395 4 6 -426238 +426167 6 27 -383161 +383097 27 45 -150740 +150715 From d06e3d79c679b7f76494c9d2e90f2c4b9775407e Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Thu, 3 Oct 2019 15:16:19 +0100 Subject: [PATCH 0358/1227] C++: Add DB Upgrade script --- .../old.dbscheme | 1910 ++++++++++++++++ .../semmlecode.cpp.dbscheme | 1915 +++++++++++++++++ .../upgrade.properties | 2 + 3 files changed, 3827 insertions(+) create mode 100644 cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/old.dbscheme create mode 100644 cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/semmlecode.cpp.dbscheme create mode 100644 cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/upgrade.properties diff --git a/cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/old.dbscheme b/cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/old.dbscheme new file mode 100644 index 00000000000..678a0f9164f --- /dev/null +++ b/cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/old.dbscheme @@ -0,0 +1,1910 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +fun_decls( + unique int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +var_decls( + unique int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +membervariables( + unique int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +globalvariables( + unique int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + unique int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/semmlecode.cpp.dbscheme b/cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..0ed3da4a31c --- /dev/null +++ b/cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/semmlecode.cpp.dbscheme @@ -0,0 +1,1915 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +fun_decls( + unique int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +var_decls( + unique int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/upgrade.properties b/cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/upgrade.properties new file mode 100644 index 00000000000..939053f9d1d --- /dev/null +++ b/cpp/upgrades/678a0f9164f610429552ff211ec47d7975123d96/upgrade.properties @@ -0,0 +1,2 @@ +description: Update keys for synthetic_destructor_call and *variable tuples +compatibility: full From 5946a4a06632eec000ebfa8e17b06b6b408d5c34 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 3 Oct 2019 17:56:29 +0200 Subject: [PATCH 0359/1227] Python: Teach `py/unused-local-variable` about `nonlocal`. --- .../ql/src/Variables/UnusedLocalVariable.ql | 1 + .../UnusedLocalVariable.expected | 1 + .../UnusedLocalVariable.qlref | 1 + .../unused_local_nonlocal/variables_test.py | 36 +++++++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.expected create mode 100644 python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.qlref create mode 100644 python/ql/test/query-tests/Variables/unused_local_nonlocal/variables_test.py diff --git a/python/ql/src/Variables/UnusedLocalVariable.ql b/python/ql/src/Variables/UnusedLocalVariable.ql index 42f28c5e085..ede7ad8bf8d 100644 --- a/python/ql/src/Variables/UnusedLocalVariable.ql +++ b/python/ql/src/Variables/UnusedLocalVariable.ql @@ -21,6 +21,7 @@ predicate unused_local(Name unused, LocalVariable v) { def.isUnused() and not exists(def.getARedef()) and def.isRelevant() and + not v = any(Nonlocal n).getAVariable() and not exists(def.getNode().getParentNode().(FunctionDef).getDefinedFunction().getADecorator()) and not exists(def.getNode().getParentNode().(ClassDef).getDefinedClass().getADecorator()) ) diff --git a/python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.expected b/python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.expected new file mode 100644 index 00000000000..3cb5b2a8e63 --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.expected @@ -0,0 +1 @@ +| variables_test.py:32:9:32:12 | test | The value assigned to local variable 'test' is never used. | diff --git a/python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.qlref b/python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.qlref new file mode 100644 index 00000000000..bd6e5aaa069 --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused_local_nonlocal/UnusedLocalVariable.qlref @@ -0,0 +1 @@ +Variables/UnusedLocalVariable.ql diff --git a/python/ql/test/query-tests/Variables/unused_local_nonlocal/variables_test.py b/python/ql/test/query-tests/Variables/unused_local_nonlocal/variables_test.py new file mode 100644 index 00000000000..4986a6f4eb3 --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused_local_nonlocal/variables_test.py @@ -0,0 +1,36 @@ + +# FPs involving nonlocal + +def nonlocal_fp(): + test = False + def set_test(): + nonlocal test + test = True + set_test() + if test: + print("Test is set.") + +nonlocal_fp() + +def nonlocal_fp2(): + test = False + + def set_test(): + nonlocal test + test = True + set_test() + result = 5 + if not test: + return + return result + +def not_fp(): + test = False + def nonlocal_test(): + nonlocal test + def set_test(): + test = True + nonlocal_test() + set_test() + if test: + print("Test is set.") From 26da6a1178b492860b5c3ddf4971efd9841538e9 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 3 Oct 2019 17:58:52 +0200 Subject: [PATCH 0360/1227] Python: Apply autoformat. --- python/ql/src/Variables/UnusedLocalVariable.ql | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/python/ql/src/Variables/UnusedLocalVariable.ql b/python/ql/src/Variables/UnusedLocalVariable.ql index ede7ad8bf8d..ab280151bf3 100644 --- a/python/ql/src/Variables/UnusedLocalVariable.ql +++ b/python/ql/src/Variables/UnusedLocalVariable.ql @@ -15,8 +15,7 @@ import python import Definition predicate unused_local(Name unused, LocalVariable v) { - forex(Definition def | - def.getNode() = unused | + forex(Definition def | def.getNode() = unused | def.getVariable() = v and def.isUnused() and not exists(def.getARedef()) and @@ -27,9 +26,9 @@ predicate unused_local(Name unused, LocalVariable v) { ) } - from Name unused, LocalVariable v -where unused_local(unused, v) and -// If unused is part of a tuple, count it as unused if all elements of that tuple are unused. -forall(Name el | el = unused.getParentNode().(Tuple).getAnElt() | unused_local(el, _)) +where + unused_local(unused, v) and + // If unused is part of a tuple, count it as unused if all elements of that tuple are unused. + forall(Name el | el = unused.getParentNode().(Tuple).getAnElt() | unused_local(el, _)) select unused, "The value assigned to local variable '" + v.getId() + "' is never used." From 47b9c497fa0b0728ea9d4b3e1006dc2597d9af51 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 3 Oct 2019 12:25:41 -0700 Subject: [PATCH 0361/1227] C++: IR SSA tests for explicit constructor calls --- .../ir/ssa/aliased_ssa_ir.expected | 69 +++++++++++++++++++ cpp/ql/test/library-tests/ir/ssa/ssa.cpp | 13 ++++ .../ir/ssa/unaliased_ssa_ir.expected | 64 +++++++++++++++++ 3 files changed, 146 insertions(+) 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 9d005c57ca8..adf2d6b4092 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 @@ -846,3 +846,72 @@ ssa.cpp: # 207| v0_24(void) = ReturnValue : &:r0_23, m0_22 # 207| v0_25(void) = UnmodeledUse : mu* # 207| v0_26(void) = ExitFunction : + +# 215| void Constructible::Constructible(int) +# 215| Block 0 +# 215| v0_0(void) = EnterFunction : +# 215| m0_1(unknown) = AliasedDefinition : +# 215| mu0_2(unknown) = UnmodeledDefinition : +# 215| r0_3(glval) = InitializeThis : +# 215| r0_4(glval) = VariableAddress[x] : +# 215| m0_5(int) = InitializeParameter[x] : &:r0_4 +# 215| v0_6(void) = NoOp : +# 215| v0_7(void) = ReturnVoid : +# 215| v0_8(void) = UnmodeledUse : mu* +# 215| v0_9(void) = ExitFunction : + +# 216| void Constructible::g() +# 216| Block 0 +# 216| v0_0(void) = EnterFunction : +# 216| m0_1(unknown) = AliasedDefinition : +# 216| mu0_2(unknown) = UnmodeledDefinition : +# 216| r0_3(glval) = InitializeThis : +# 216| v0_4(void) = NoOp : +# 216| v0_5(void) = ReturnVoid : +# 216| v0_6(void) = UnmodeledUse : mu* +# 216| v0_7(void) = ExitFunction : + +# 219| void ExplicitConstructorCalls() +# 219| Block 0 +# 219| v0_0(void) = EnterFunction : +# 219| m0_1(unknown) = AliasedDefinition : +# 219| mu0_2(unknown) = UnmodeledDefinition : +# 220| r0_3(glval) = VariableAddress[c] : +# 220| r0_4(glval) = FunctionAddress[Constructible] : +# 220| r0_5(int) = Constant[1] : +# 220| v0_6(void) = Call : func:r0_4, this:r0_3, 0:r0_5 +# 220| m0_7(unknown) = ^CallSideEffect : ~m0_1 +# 220| m0_8(unknown) = Chi : total:m0_1, partial:m0_7 +# 220| m0_9(Constructible) = ^IndirectMayWriteSideEffect : &:r0_3 +# 221| r0_10(glval) = VariableAddress[c] : +# 221| r0_11(glval) = FunctionAddress[g] : +# 221| v0_12(void) = Call : func:r0_11, this:r0_10 +# 221| m0_13(unknown) = ^CallSideEffect : ~m0_8 +# 221| m0_14(unknown) = Chi : total:m0_8, partial:m0_13 +# 221| v0_15(void) = ^IndirectReadSideEffect[-1] : &:r0_10, m0_9 +# 221| m0_16(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_10 +# 222| r0_17(glval) = VariableAddress[c] : +# 222| r0_18(glval) = FunctionAddress[g] : +# 222| v0_19(void) = Call : func:r0_18, this:r0_17 +# 222| m0_20(unknown) = ^CallSideEffect : ~m0_14 +# 222| m0_21(unknown) = Chi : total:m0_14, partial:m0_20 +# 222| v0_22(void) = ^IndirectReadSideEffect[-1] : &:r0_17, m0_16 +# 222| m0_23(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_17 +# 223| r0_24(glval) = VariableAddress[c2] : +# 223| r0_25(glval) = FunctionAddress[Constructible] : +# 223| r0_26(int) = Constant[2] : +# 223| v0_27(void) = Call : func:r0_25, this:r0_24, 0:r0_26 +# 223| m0_28(unknown) = ^CallSideEffect : ~m0_21 +# 223| m0_29(unknown) = Chi : total:m0_21, partial:m0_28 +# 223| m0_30(Constructible) = ^IndirectMayWriteSideEffect : &:r0_24 +# 224| r0_31(glval) = VariableAddress[c2] : +# 224| r0_32(glval) = FunctionAddress[g] : +# 224| v0_33(void) = Call : func:r0_32, this:r0_31 +# 224| m0_34(unknown) = ^CallSideEffect : ~m0_29 +# 224| m0_35(unknown) = Chi : total:m0_29, partial:m0_34 +# 224| v0_36(void) = ^IndirectReadSideEffect[-1] : &:r0_31, m0_30 +# 224| m0_37(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_31 +# 225| v0_38(void) = NoOp : +# 219| v0_39(void) = ReturnVoid : +# 219| v0_40(void) = UnmodeledUse : mu* +# 219| v0_41(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp index 4dfb0a2f6cd..cd6df07e3a7 100644 --- a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp +++ b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp @@ -210,3 +210,16 @@ int ModeledCallTarget(int x) { return y; } +class Constructible { + public: + Constructible(int x) {}; + void g() {} +}; + +void ExplicitConstructorCalls() { + Constructible c(1); + c.g(); + c.g(); + Constructible c2 = Constructible(2); + c2.g(); +} diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index a68690c7055..63db25f8d80 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -806,3 +806,67 @@ ssa.cpp: # 207| v0_21(void) = ReturnValue : &:r0_20, m0_19 # 207| v0_22(void) = UnmodeledUse : mu* # 207| v0_23(void) = ExitFunction : + +# 215| void Constructible::Constructible(int) +# 215| Block 0 +# 215| v0_0(void) = EnterFunction : +# 215| mu0_1(unknown) = AliasedDefinition : +# 215| mu0_2(unknown) = UnmodeledDefinition : +# 215| r0_3(glval) = InitializeThis : +# 215| r0_4(glval) = VariableAddress[x] : +# 215| m0_5(int) = InitializeParameter[x] : &:r0_4 +# 215| v0_6(void) = NoOp : +# 215| v0_7(void) = ReturnVoid : +# 215| v0_8(void) = UnmodeledUse : mu* +# 215| v0_9(void) = ExitFunction : + +# 216| void Constructible::g() +# 216| Block 0 +# 216| v0_0(void) = EnterFunction : +# 216| mu0_1(unknown) = AliasedDefinition : +# 216| mu0_2(unknown) = UnmodeledDefinition : +# 216| r0_3(glval) = InitializeThis : +# 216| v0_4(void) = NoOp : +# 216| v0_5(void) = ReturnVoid : +# 216| v0_6(void) = UnmodeledUse : mu* +# 216| v0_7(void) = ExitFunction : + +# 219| void ExplicitConstructorCalls() +# 219| Block 0 +# 219| v0_0(void) = EnterFunction : +# 219| mu0_1(unknown) = AliasedDefinition : +# 219| mu0_2(unknown) = UnmodeledDefinition : +# 220| r0_3(glval) = VariableAddress[c] : +# 220| r0_4(glval) = FunctionAddress[Constructible] : +# 220| r0_5(int) = Constant[1] : +# 220| v0_6(void) = Call : func:r0_4, this:r0_3, 0:r0_5 +# 220| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +# 220| m0_8(Constructible) = ^IndirectMayWriteSideEffect : &:r0_3 +# 221| r0_9(glval) = VariableAddress[c] : +# 221| r0_10(glval) = FunctionAddress[g] : +# 221| v0_11(void) = Call : func:r0_10, this:r0_9 +# 221| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 221| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, m0_8 +# 221| m0_14(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 +# 222| r0_15(glval) = VariableAddress[c] : +# 222| r0_16(glval) = FunctionAddress[g] : +# 222| v0_17(void) = Call : func:r0_16, this:r0_15 +# 222| mu0_18(unknown) = ^CallSideEffect : ~mu0_2 +# 222| v0_19(void) = ^IndirectReadSideEffect[-1] : &:r0_15, m0_14 +# 222| m0_20(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_15 +# 223| r0_21(glval) = VariableAddress[c2] : +# 223| r0_22(glval) = FunctionAddress[Constructible] : +# 223| r0_23(int) = Constant[2] : +# 223| v0_24(void) = Call : func:r0_22, this:r0_21, 0:r0_23 +# 223| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 +# 223| m0_26(Constructible) = ^IndirectMayWriteSideEffect : &:r0_21 +# 224| r0_27(glval) = VariableAddress[c2] : +# 224| r0_28(glval) = FunctionAddress[g] : +# 224| v0_29(void) = Call : func:r0_28, this:r0_27 +# 224| mu0_30(unknown) = ^CallSideEffect : ~mu0_2 +# 224| v0_31(void) = ^IndirectReadSideEffect[-1] : &:r0_27, m0_26 +# 224| m0_32(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_27 +# 225| v0_33(void) = NoOp : +# 219| v0_34(void) = ReturnVoid : +# 219| v0_35(void) = UnmodeledUse : mu* +# 219| v0_36(void) = ExitFunction : From a76c4d9b3b0831f186d43ba341007c2be83afc69 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 3 Oct 2019 12:39:32 -0700 Subject: [PATCH 0362/1227] C++: index for constructor qualifier side effects --- .../cpp/ir/implementation/raw/internal/TranslatedCall.qll | 5 +++++ cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected | 4 ++-- cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 08f782db9fc..64e6c1ca806 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -401,6 +401,11 @@ class TranslatedStructorCallSideEffects extends TranslatedSideEffects { operandTag instanceof AddressOperandTag and result = getParent().(TranslatedStructorCall).getQualifierResult() } + + final override int getInstructionIndex(InstructionTag tag) { + tag = OnlyInstructionTag() and + result = -1 + } } class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEffect { 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 adf2d6b4092..be58a43a415 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 @@ -882,7 +882,7 @@ ssa.cpp: # 220| v0_6(void) = Call : func:r0_4, this:r0_3, 0:r0_5 # 220| m0_7(unknown) = ^CallSideEffect : ~m0_1 # 220| m0_8(unknown) = Chi : total:m0_1, partial:m0_7 -# 220| m0_9(Constructible) = ^IndirectMayWriteSideEffect : &:r0_3 +# 220| m0_9(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 # 221| r0_10(glval) = VariableAddress[c] : # 221| r0_11(glval) = FunctionAddress[g] : # 221| v0_12(void) = Call : func:r0_11, this:r0_10 @@ -903,7 +903,7 @@ ssa.cpp: # 223| v0_27(void) = Call : func:r0_25, this:r0_24, 0:r0_26 # 223| m0_28(unknown) = ^CallSideEffect : ~m0_21 # 223| m0_29(unknown) = Chi : total:m0_21, partial:m0_28 -# 223| m0_30(Constructible) = ^IndirectMayWriteSideEffect : &:r0_24 +# 223| m0_30(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_24 # 224| r0_31(glval) = VariableAddress[c2] : # 224| r0_32(glval) = FunctionAddress[g] : # 224| v0_33(void) = Call : func:r0_32, this:r0_31 diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 63db25f8d80..6006ee38036 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -841,7 +841,7 @@ ssa.cpp: # 220| r0_5(int) = Constant[1] : # 220| v0_6(void) = Call : func:r0_4, this:r0_3, 0:r0_5 # 220| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 220| m0_8(Constructible) = ^IndirectMayWriteSideEffect : &:r0_3 +# 220| m0_8(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 # 221| r0_9(glval) = VariableAddress[c] : # 221| r0_10(glval) = FunctionAddress[g] : # 221| v0_11(void) = Call : func:r0_10, this:r0_9 @@ -859,7 +859,7 @@ ssa.cpp: # 223| r0_23(int) = Constant[2] : # 223| v0_24(void) = Call : func:r0_22, this:r0_21, 0:r0_23 # 223| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 223| m0_26(Constructible) = ^IndirectMayWriteSideEffect : &:r0_21 +# 223| m0_26(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 # 224| r0_27(glval) = VariableAddress[c2] : # 224| r0_28(glval) = FunctionAddress[g] : # 224| v0_29(void) = Call : func:r0_28, this:r0_27 From c1e3821ab00ea58da5307db451cbb018c35a2c09 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 3 Oct 2019 12:51:58 -0700 Subject: [PATCH 0363/1227] IR: rename getVariable to getIRVariable --- .../code/cpp/ir/implementation/aliased_ssa/Instruction.qll | 2 +- .../cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll | 4 ++-- .../ir/implementation/aliased_ssa/internal/AliasAnalysis.qll | 4 ++-- .../implementation/aliased_ssa/internal/SSAConstruction.qll | 2 +- .../src/semmle/code/cpp/ir/implementation/raw/Instruction.qll | 2 +- .../code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll | 4 ++-- .../code/cpp/ir/implementation/unaliased_ssa/Instruction.qll | 2 +- .../ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll | 4 ++-- .../implementation/unaliased_ssa/internal/AliasAnalysis.qll | 4 ++-- .../implementation/unaliased_ssa/internal/SSAConstruction.qll | 2 +- .../semmle/code/csharp/ir/implementation/raw/Instruction.qll | 2 +- .../csharp/ir/implementation/unaliased_ssa/Instruction.qll | 2 +- .../ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll | 4 ++-- .../implementation/unaliased_ssa/internal/AliasAnalysis.qll | 4 ++-- .../implementation/unaliased_ssa/internal/SSAConstruction.qll | 2 +- 15 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index efc873b8f44..1726ecdda68 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -611,7 +611,7 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } - final IRVariable getVariable() { result = var } + final IRVariable getIRVariable() { result = var } } class FieldInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll index e3e52df8931..df6c5be7728 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll @@ -135,14 +135,14 @@ private predicate variableAddressValueNumber( VariableAddressInstruction instr, IRFunction irFunc, IRVariable var ) { instr.getEnclosingIRFunction() = irFunc and - instr.getVariable() = var + instr.getIRVariable() = var } private predicate initializeParameterValueNumber( InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var ) { instr.getEnclosingIRFunction() = irFunc and - instr.getVariable() = var + instr.getIRVariable() = var } private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index dc50ef01354..b9aa07c1b36 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -282,7 +282,7 @@ private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) { // The variable's address escapes if the result of any // VariableAddressInstruction that computes the variable's address escapes. exists(VariableAddressInstruction instr | - instr.getVariable() = var and + instr.getIRVariable() = var and resultEscapesNonReturn(instr) ) } @@ -305,7 +305,7 @@ predicate variableAddressEscapes(IRVariable var) { */ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) { // The address of a variable points to that variable, at offset 0. - instr.(VariableAddressInstruction).getVariable() = var and + instr.(VariableAddressInstruction).getIRVariable() = var and bitOffset = 0 or exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset | diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 0fb6676bb42..3010825d50b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -334,7 +334,7 @@ private module Cached { IRVariable getInstructionVariable(Instruction instruction) { result = getNewIRVariable(getOldInstruction(instruction) .(OldIR::VariableInstruction) - .getVariable()) + .getIRVariable()) } cached diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index efc873b8f44..1726ecdda68 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -611,7 +611,7 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } - final IRVariable getVariable() { result = var } + final IRVariable getIRVariable() { result = var } } class FieldInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll index e3e52df8931..df6c5be7728 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -135,14 +135,14 @@ private predicate variableAddressValueNumber( VariableAddressInstruction instr, IRFunction irFunc, IRVariable var ) { instr.getEnclosingIRFunction() = irFunc and - instr.getVariable() = var + instr.getIRVariable() = var } private predicate initializeParameterValueNumber( InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var ) { instr.getEnclosingIRFunction() = irFunc and - instr.getVariable() = var + instr.getIRVariable() = var } private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index efc873b8f44..1726ecdda68 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -611,7 +611,7 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } - final IRVariable getVariable() { result = var } + final IRVariable getIRVariable() { result = var } } class FieldInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index e3e52df8931..df6c5be7728 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -135,14 +135,14 @@ private predicate variableAddressValueNumber( VariableAddressInstruction instr, IRFunction irFunc, IRVariable var ) { instr.getEnclosingIRFunction() = irFunc and - instr.getVariable() = var + instr.getIRVariable() = var } private predicate initializeParameterValueNumber( InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var ) { instr.getEnclosingIRFunction() = irFunc and - instr.getVariable() = var + instr.getIRVariable() = var } private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index dc50ef01354..b9aa07c1b36 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -282,7 +282,7 @@ private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) { // The variable's address escapes if the result of any // VariableAddressInstruction that computes the variable's address escapes. exists(VariableAddressInstruction instr | - instr.getVariable() = var and + instr.getIRVariable() = var and resultEscapesNonReturn(instr) ) } @@ -305,7 +305,7 @@ predicate variableAddressEscapes(IRVariable var) { */ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) { // The address of a variable points to that variable, at offset 0. - instr.(VariableAddressInstruction).getVariable() = var and + instr.(VariableAddressInstruction).getIRVariable() = var and bitOffset = 0 or exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset | diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 0fb6676bb42..3010825d50b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -334,7 +334,7 @@ private module Cached { IRVariable getInstructionVariable(Instruction instruction) { result = getNewIRVariable(getOldInstruction(instruction) .(OldIR::VariableInstruction) - .getVariable()) + .getIRVariable()) } cached diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index efc873b8f44..1726ecdda68 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -611,7 +611,7 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } - final IRVariable getVariable() { result = var } + final IRVariable getIRVariable() { result = var } } class FieldInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index efc873b8f44..1726ecdda68 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -611,7 +611,7 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } - final IRVariable getVariable() { result = var } + final IRVariable getIRVariable() { result = var } } class FieldInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 53b4f5c9647..f887d39d10b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -135,14 +135,14 @@ private predicate variableAddressValueNumber( VariableAddressInstruction instr, IRFunction irFunc, IRVariable var ) { instr.getEnclosingIRFunction() = irFunc and - instr.getVariable() = var + instr.getIRVariable() = var } private predicate initializeParameterValueNumber( InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var ) { instr.getEnclosingIRFunction() = irFunc and - instr.getVariable() = var + instr.getIRVariable() = var } private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index 43d5a378793..1f5064f6766 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -269,7 +269,7 @@ private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) { // The variable's address escapes if the result of any // VariableAddressInstruction that computes the variable's address escapes. exists(VariableAddressInstruction instr | - instr.getVariable() = var and + instr.getIRVariable() = var and resultEscapesNonReturn(instr) ) } @@ -292,7 +292,7 @@ predicate variableAddressEscapes(IRVariable var) { */ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) { // The address of a variable points to that variable, at offset 0. - instr.(VariableAddressInstruction).getVariable() = var and + instr.(VariableAddressInstruction).getIRVariable() = var and bitOffset = 0 or exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset | diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index f65f18b1ec2..159b6328ab0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -337,7 +337,7 @@ private module Cached { IRVariable getInstructionVariable(Instruction instruction) { result = getNewIRVariable(getOldInstruction(instruction) .(OldIR::VariableInstruction) - .getVariable()) + .getIRVariable()) } cached From 6e587f3f2afcdd336ed23bf2b8627c51ae8680a9 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 3 Oct 2019 13:12:06 -0700 Subject: [PATCH 0364/1227] IR: Add VariableInstruction.getASTVariable --- .../code/cpp/ir/implementation/aliased_ssa/Instruction.qll | 5 +++++ .../semmle/code/cpp/ir/implementation/raw/Instruction.qll | 5 +++++ .../code/cpp/ir/implementation/unaliased_ssa/Instruction.qll | 5 +++++ .../semmle/code/csharp/ir/implementation/raw/Instruction.qll | 5 +++++ .../csharp/ir/implementation/unaliased_ssa/Instruction.qll | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 1726ecdda68..3244afeb144 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -612,6 +612,11 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } final IRVariable getIRVariable() { result = var } + + /** + * Gets the AST variable that this instruction's IR variable refers to, if one exists. + */ + final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } class FieldInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 1726ecdda68..3244afeb144 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -612,6 +612,11 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } final IRVariable getIRVariable() { result = var } + + /** + * Gets the AST variable that this instruction's IR variable refers to, if one exists. + */ + final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } class FieldInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 1726ecdda68..3244afeb144 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -612,6 +612,11 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } final IRVariable getIRVariable() { result = var } + + /** + * Gets the AST variable that this instruction's IR variable refers to, if one exists. + */ + final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } class FieldInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 1726ecdda68..3244afeb144 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -612,6 +612,11 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } final IRVariable getIRVariable() { result = var } + + /** + * Gets the AST variable that this instruction's IR variable refers to, if one exists. + */ + final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } class FieldInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 1726ecdda68..3244afeb144 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -612,6 +612,11 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } final IRVariable getIRVariable() { result = var } + + /** + * Gets the AST variable that this instruction's IR variable refers to, if one exists. + */ + final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } class FieldInstruction extends Instruction { From bc973973dfde5dd3940cb5caf0e3038626f488a3 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 3 Oct 2019 14:43:54 -0700 Subject: [PATCH 0365/1227] C++: accept test changes --- .../test/library-tests/ir/ir/raw_ir.expected | 554 +++++++++--------- 1 file changed, 277 insertions(+), 277 deletions(-) diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index b4a798f6e73..933cd6bc2e3 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -2708,41 +2708,41 @@ ir.cpp: # 615| void DeclareObject() # 615| Block 0 -# 615| v0_0(void) = EnterFunction : -# 615| mu0_1(unknown) = AliasedDefinition : -# 615| mu0_2(unknown) = UnmodeledDefinition : -# 616| r0_3(glval) = VariableAddress[s1] : -# 616| r0_4(glval) = FunctionAddress[String] : -# 616| v0_5(void) = Call : func:r0_4, this:r0_3 -# 616| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 616| mu0_7(String) = ^IndirectMayWriteSideEffect : &:r0_3 -# 617| r0_8(glval) = VariableAddress[s2] : -# 617| r0_9(glval) = FunctionAddress[String] : -# 617| r0_10(glval) = StringConstant["hello"] : -# 617| r0_11(char *) = Convert : r0_10 -# 617| v0_12(void) = Call : func:r0_9, this:r0_8, 0:r0_11 -# 617| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -# 617| mu0_14(String) = ^IndirectMayWriteSideEffect : &:r0_8 -# 617| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 -# 617| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 -# 618| r0_17(glval) = VariableAddress[s3] : -# 618| r0_18(glval) = FunctionAddress[ReturnObject] : -# 618| r0_19(String) = Call : func:r0_18 -# 618| mu0_20(unknown) = ^CallSideEffect : ~mu0_2 -# 618| mu0_21(String) = Store : &:r0_17, r0_19 -# 619| r0_22(glval) = VariableAddress[s4] : -# 619| r0_23(glval) = FunctionAddress[String] : -# 619| r0_24(glval) = StringConstant["test"] : -# 619| r0_25(char *) = Convert : r0_24 -# 619| v0_26(void) = Call : func:r0_23, this:r0_22, 0:r0_25 -# 619| mu0_27(unknown) = ^CallSideEffect : ~mu0_2 -# 619| mu0_28(String) = ^IndirectMayWriteSideEffect : &:r0_22 -# 619| v0_29(void) = ^IndirectReadSideEffect[0] : &:r0_25, ~mu0_2 -# 619| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_25 -# 620| v0_31(void) = NoOp : -# 615| v0_32(void) = ReturnVoid : -# 615| v0_33(void) = UnmodeledUse : mu* -# 615| v0_34(void) = ExitFunction : +# 615| v0_0(void) = EnterFunction : +# 615| mu0_1(unknown) = AliasedDefinition : +# 615| mu0_2(unknown) = UnmodeledDefinition : +# 616| r0_3(glval) = VariableAddress[s1] : +# 616| r0_4(glval) = FunctionAddress[String] : +# 616| v0_5(void) = Call : func:r0_4, this:r0_3 +# 616| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 +# 616| mu0_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 +# 617| r0_8(glval) = VariableAddress[s2] : +# 617| r0_9(glval) = FunctionAddress[String] : +# 617| r0_10(glval) = StringConstant["hello"] : +# 617| r0_11(char *) = Convert : r0_10 +# 617| v0_12(void) = Call : func:r0_9, this:r0_8, 0:r0_11 +# 617| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +# 617| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 +# 617| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 +# 617| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 +# 618| r0_17(glval) = VariableAddress[s3] : +# 618| r0_18(glval) = FunctionAddress[ReturnObject] : +# 618| r0_19(String) = Call : func:r0_18 +# 618| mu0_20(unknown) = ^CallSideEffect : ~mu0_2 +# 618| mu0_21(String) = Store : &:r0_17, r0_19 +# 619| r0_22(glval) = VariableAddress[s4] : +# 619| r0_23(glval) = FunctionAddress[String] : +# 619| r0_24(glval) = StringConstant["test"] : +# 619| r0_25(char *) = Convert : r0_24 +# 619| v0_26(void) = Call : func:r0_23, this:r0_22, 0:r0_25 +# 619| mu0_27(unknown) = ^CallSideEffect : ~mu0_2 +# 619| mu0_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_22 +# 619| v0_29(void) = ^IndirectReadSideEffect[0] : &:r0_25, ~mu0_2 +# 619| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_25 +# 620| v0_31(void) = NoOp : +# 615| v0_32(void) = ReturnVoid : +# 615| v0_33(void) = UnmodeledUse : mu* +# 615| v0_34(void) = ExitFunction : # 622| void CallMethods(String&, String*, String) # 622| Block 0 @@ -2907,37 +2907,37 @@ ir.cpp: # 658| void C::C() # 658| Block 0 -# 658| v0_0(void) = EnterFunction : -# 658| mu0_1(unknown) = AliasedDefinition : -# 658| mu0_2(unknown) = UnmodeledDefinition : -# 658| r0_3(glval) = InitializeThis : -# 659| r0_4(glval) = FieldAddress[m_a] : r0_3 -# 659| r0_5(int) = Constant[1] : -# 659| mu0_6(int) = Store : &:r0_4, r0_5 -# 663| r0_7(glval) = FieldAddress[m_b] : r0_3 -# 663| r0_8(glval) = FunctionAddress[String] : -# 663| v0_9(void) = Call : func:r0_8, this:r0_7 -# 663| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 -# 663| mu0_11(String) = ^IndirectMayWriteSideEffect : &:r0_7 -# 660| r0_12(glval) = FieldAddress[m_c] : r0_3 -# 660| r0_13(char) = Constant[3] : -# 660| mu0_14(char) = Store : &:r0_12, r0_13 -# 661| r0_15(glval) = FieldAddress[m_e] : r0_3 -# 661| r0_16(void *) = Constant[0] : -# 661| mu0_17(void *) = Store : &:r0_15, r0_16 -# 662| r0_18(glval) = FieldAddress[m_f] : r0_3 -# 662| r0_19(glval) = FunctionAddress[String] : -# 662| r0_20(glval) = StringConstant["test"] : -# 662| r0_21(char *) = Convert : r0_20 -# 662| v0_22(void) = Call : func:r0_19, this:r0_18, 0:r0_21 -# 662| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 -# 662| mu0_24(String) = ^IndirectMayWriteSideEffect : &:r0_18 -# 662| v0_25(void) = ^IndirectReadSideEffect[0] : &:r0_21, ~mu0_2 -# 662| mu0_26(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_21 -# 664| v0_27(void) = NoOp : -# 658| v0_28(void) = ReturnVoid : -# 658| v0_29(void) = UnmodeledUse : mu* -# 658| v0_30(void) = ExitFunction : +# 658| v0_0(void) = EnterFunction : +# 658| mu0_1(unknown) = AliasedDefinition : +# 658| mu0_2(unknown) = UnmodeledDefinition : +# 658| r0_3(glval) = InitializeThis : +# 659| r0_4(glval) = FieldAddress[m_a] : r0_3 +# 659| r0_5(int) = Constant[1] : +# 659| mu0_6(int) = Store : &:r0_4, r0_5 +# 663| r0_7(glval) = FieldAddress[m_b] : r0_3 +# 663| r0_8(glval) = FunctionAddress[String] : +# 663| v0_9(void) = Call : func:r0_8, this:r0_7 +# 663| mu0_10(unknown) = ^CallSideEffect : ~mu0_2 +# 663| mu0_11(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 +# 660| r0_12(glval) = FieldAddress[m_c] : r0_3 +# 660| r0_13(char) = Constant[3] : +# 660| mu0_14(char) = Store : &:r0_12, r0_13 +# 661| r0_15(glval) = FieldAddress[m_e] : r0_3 +# 661| r0_16(void *) = Constant[0] : +# 661| mu0_17(void *) = Store : &:r0_15, r0_16 +# 662| r0_18(glval) = FieldAddress[m_f] : r0_3 +# 662| r0_19(glval) = FunctionAddress[String] : +# 662| r0_20(glval) = StringConstant["test"] : +# 662| r0_21(char *) = Convert : r0_20 +# 662| v0_22(void) = Call : func:r0_19, this:r0_18, 0:r0_21 +# 662| mu0_23(unknown) = ^CallSideEffect : ~mu0_2 +# 662| mu0_24(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_18 +# 662| v0_25(void) = ^IndirectReadSideEffect[0] : &:r0_21, ~mu0_2 +# 662| mu0_26(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_21 +# 664| v0_27(void) = NoOp : +# 658| v0_28(void) = ReturnVoid : +# 658| v0_29(void) = UnmodeledUse : mu* +# 658| v0_30(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 @@ -3206,7 +3206,7 @@ ir.cpp: # 731| r7_3(char *) = Convert : r7_2 # 731| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 731| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 731| mu7_6(String) = ^IndirectMayWriteSideEffect : &:r7_0 +# 731| mu7_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r7_0 # 731| v7_7(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 # 731| mu7_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 # 731| v7_9(void) = ThrowValue : &:r7_0, ~mu0_2 @@ -3224,18 +3224,18 @@ ir.cpp: #-----| Goto -> Block 10 # 735| Block 10 -# 735| r10_0(glval) = VariableAddress[s] : -# 735| mu10_1(char *) = InitializeParameter[s] : &:r10_0 -# 736| r10_2(glval) = VariableAddress[#throw736:5] : -# 736| r10_3(glval) = FunctionAddress[String] : -# 736| r10_4(glval) = VariableAddress[s] : -# 736| r10_5(char *) = Load : &:r10_4, ~mu0_2 -# 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 -# 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 736| mu10_8(String) = ^IndirectMayWriteSideEffect : &:r10_2 -# 736| v10_9(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 -# 736| mu10_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 -# 736| v10_11(void) = ThrowValue : &:r10_2, ~mu0_2 +# 735| r10_0(glval) = VariableAddress[s] : +# 735| mu10_1(char *) = InitializeParameter[s] : &:r10_0 +# 736| r10_2(glval) = VariableAddress[#throw736:5] : +# 736| r10_3(glval) = FunctionAddress[String] : +# 736| r10_4(glval) = VariableAddress[s] : +# 736| r10_5(char *) = Load : &:r10_4, ~mu0_2 +# 736| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 +# 736| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 +# 736| mu10_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r10_2 +# 736| v10_9(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 +# 736| mu10_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 +# 736| v10_11(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 # 738| Block 11 @@ -3289,37 +3289,37 @@ ir.cpp: # 745| void Base::Base(Base const&) # 745| Block 0 -# 745| v0_0(void) = EnterFunction : -# 745| mu0_1(unknown) = AliasedDefinition : -# 745| mu0_2(unknown) = UnmodeledDefinition : -# 745| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 -# 745| r0_6(glval) = FieldAddress[base_s] : r0_3 -# 745| r0_7(glval) = FunctionAddress[String] : -# 745| v0_8(void) = Call : func:r0_7, this:r0_6 -# 745| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 -# 745| mu0_10(String) = ^IndirectMayWriteSideEffect : &:r0_6 -# 745| v0_11(void) = NoOp : -# 745| v0_12(void) = ReturnVoid : -# 745| v0_13(void) = UnmodeledUse : mu* -# 745| v0_14(void) = ExitFunction : +# 745| v0_0(void) = EnterFunction : +# 745| mu0_1(unknown) = AliasedDefinition : +# 745| mu0_2(unknown) = UnmodeledDefinition : +# 745| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(Base &) = InitializeParameter[p#0] : &:r0_4 +# 745| r0_6(glval) = FieldAddress[base_s] : r0_3 +# 745| r0_7(glval) = FunctionAddress[String] : +# 745| v0_8(void) = Call : func:r0_7, this:r0_6 +# 745| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 +# 745| mu0_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 +# 745| v0_11(void) = NoOp : +# 745| v0_12(void) = ReturnVoid : +# 745| v0_13(void) = UnmodeledUse : mu* +# 745| v0_14(void) = ExitFunction : # 748| void Base::Base() # 748| Block 0 -# 748| v0_0(void) = EnterFunction : -# 748| mu0_1(unknown) = AliasedDefinition : -# 748| mu0_2(unknown) = UnmodeledDefinition : -# 748| r0_3(glval) = InitializeThis : -# 748| r0_4(glval) = FieldAddress[base_s] : r0_3 -# 748| r0_5(glval) = FunctionAddress[String] : -# 748| v0_6(void) = Call : func:r0_5, this:r0_4 -# 748| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 748| mu0_8(String) = ^IndirectMayWriteSideEffect : &:r0_4 -# 749| v0_9(void) = NoOp : -# 748| v0_10(void) = ReturnVoid : -# 748| v0_11(void) = UnmodeledUse : mu* -# 748| v0_12(void) = ExitFunction : +# 748| v0_0(void) = EnterFunction : +# 748| mu0_1(unknown) = AliasedDefinition : +# 748| mu0_2(unknown) = UnmodeledDefinition : +# 748| r0_3(glval) = InitializeThis : +# 748| r0_4(glval) = FieldAddress[base_s] : r0_3 +# 748| r0_5(glval) = FunctionAddress[String] : +# 748| v0_6(void) = Call : func:r0_5, this:r0_4 +# 748| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +# 748| mu0_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 +# 749| v0_9(void) = NoOp : +# 748| v0_10(void) = ReturnVoid : +# 748| v0_11(void) = UnmodeledUse : mu* +# 748| v0_12(void) = ExitFunction : # 750| void Base::~Base() # 750| Block 0 @@ -3378,24 +3378,24 @@ ir.cpp: # 757| void Middle::Middle() # 757| Block 0 -# 757| v0_0(void) = EnterFunction : -# 757| mu0_1(unknown) = AliasedDefinition : -# 757| mu0_2(unknown) = UnmodeledDefinition : -# 757| r0_3(glval) = InitializeThis : -# 757| r0_4(glval) = ConvertToBase[Middle : Base] : r0_3 -# 757| r0_5(glval) = FunctionAddress[Base] : -# 757| v0_6(void) = Call : func:r0_5, this:r0_4 -# 757| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 757| mu0_8(Base) = ^IndirectMayWriteSideEffect : &:r0_4 -# 757| r0_9(glval) = FieldAddress[middle_s] : r0_3 -# 757| r0_10(glval) = FunctionAddress[String] : -# 757| v0_11(void) = Call : func:r0_10, this:r0_9 -# 757| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 757| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_9 -# 758| v0_14(void) = NoOp : -# 757| v0_15(void) = ReturnVoid : -# 757| v0_16(void) = UnmodeledUse : mu* -# 757| v0_17(void) = ExitFunction : +# 757| v0_0(void) = EnterFunction : +# 757| mu0_1(unknown) = AliasedDefinition : +# 757| mu0_2(unknown) = UnmodeledDefinition : +# 757| r0_3(glval) = InitializeThis : +# 757| r0_4(glval) = ConvertToBase[Middle : Base] : r0_3 +# 757| r0_5(glval) = FunctionAddress[Base] : +# 757| v0_6(void) = Call : func:r0_5, this:r0_4 +# 757| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +# 757| mu0_8(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 +# 757| r0_9(glval) = FieldAddress[middle_s] : r0_3 +# 757| r0_10(glval) = FunctionAddress[String] : +# 757| v0_11(void) = Call : func:r0_10, this:r0_9 +# 757| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 757| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 +# 758| v0_14(void) = NoOp : +# 757| v0_15(void) = ReturnVoid : +# 757| v0_16(void) = UnmodeledUse : mu* +# 757| v0_17(void) = ExitFunction : # 759| void Middle::~Middle() # 759| Block 0 @@ -3466,12 +3466,12 @@ ir.cpp: # 766| r0_5(glval) = FunctionAddress[Middle] : # 766| v0_6(void) = Call : func:r0_5, this:r0_4 # 766| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 766| mu0_8(Middle) = ^IndirectMayWriteSideEffect : &:r0_4 +# 766| mu0_8(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 # 766| r0_9(glval) = FieldAddress[derived_s] : r0_3 # 766| r0_10(glval) = FunctionAddress[String] : # 766| v0_11(void) = Call : func:r0_10, this:r0_9 # 766| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 766| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_9 +# 766| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 # 767| v0_14(void) = NoOp : # 766| v0_15(void) = ReturnVoid : # 766| v0_16(void) = UnmodeledUse : mu* @@ -3506,12 +3506,12 @@ ir.cpp: # 775| r0_5(glval) = FunctionAddress[Base] : # 775| v0_6(void) = Call : func:r0_5, this:r0_4 # 775| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 775| mu0_8(Base) = ^IndirectMayWriteSideEffect : &:r0_4 +# 775| mu0_8(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 # 775| r0_9(glval) = FieldAddress[middlevb1_s] : r0_3 # 775| r0_10(glval) = FunctionAddress[String] : # 775| v0_11(void) = Call : func:r0_10, this:r0_9 # 775| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 775| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_9 +# 775| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 # 776| v0_14(void) = NoOp : # 775| v0_15(void) = ReturnVoid : # 775| v0_16(void) = UnmodeledUse : mu* @@ -3546,12 +3546,12 @@ ir.cpp: # 784| r0_5(glval) = FunctionAddress[Base] : # 784| v0_6(void) = Call : func:r0_5, this:r0_4 # 784| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 784| mu0_8(Base) = ^IndirectMayWriteSideEffect : &:r0_4 +# 784| mu0_8(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 # 784| r0_9(glval) = FieldAddress[middlevb2_s] : r0_3 # 784| r0_10(glval) = FunctionAddress[String] : # 784| v0_11(void) = Call : func:r0_10, this:r0_9 # 784| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 784| mu0_13(String) = ^IndirectMayWriteSideEffect : &:r0_9 +# 784| mu0_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 # 785| v0_14(void) = NoOp : # 784| v0_15(void) = ReturnVoid : # 784| v0_16(void) = UnmodeledUse : mu* @@ -3586,22 +3586,22 @@ ir.cpp: # 793| r0_5(glval) = FunctionAddress[Base] : # 793| v0_6(void) = Call : func:r0_5, this:r0_4 # 793| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 793| mu0_8(Base) = ^IndirectMayWriteSideEffect : &:r0_4 +# 793| mu0_8(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 # 793| r0_9(glval) = ConvertToBase[DerivedVB : MiddleVB1] : r0_3 # 793| r0_10(glval) = FunctionAddress[MiddleVB1] : # 793| v0_11(void) = Call : func:r0_10, this:r0_9 # 793| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 793| mu0_13(MiddleVB1) = ^IndirectMayWriteSideEffect : &:r0_9 +# 793| mu0_13(MiddleVB1) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 # 793| r0_14(glval) = ConvertToBase[DerivedVB : MiddleVB2] : r0_3 # 793| r0_15(glval) = FunctionAddress[MiddleVB2] : # 793| v0_16(void) = Call : func:r0_15, this:r0_14 # 793| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 -# 793| mu0_18(MiddleVB2) = ^IndirectMayWriteSideEffect : &:r0_14 +# 793| mu0_18(MiddleVB2) = ^IndirectMayWriteSideEffect[-1] : &:r0_14 # 793| r0_19(glval) = FieldAddress[derivedvb_s] : r0_3 # 793| r0_20(glval) = FunctionAddress[String] : # 793| v0_21(void) = Call : func:r0_20, this:r0_19 # 793| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 -# 793| mu0_23(String) = ^IndirectMayWriteSideEffect : &:r0_19 +# 793| mu0_23(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_19 # 794| v0_24(void) = NoOp : # 793| v0_25(void) = ReturnVoid : # 793| v0_26(void) = UnmodeledUse : mu* @@ -3643,17 +3643,17 @@ ir.cpp: # 800| r0_4(glval) = FunctionAddress[Base] : # 800| v0_5(void) = Call : func:r0_4, this:r0_3 # 800| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 800| mu0_7(Base) = ^IndirectMayWriteSideEffect : &:r0_3 +# 800| mu0_7(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 # 801| r0_8(glval) = VariableAddress[m] : # 801| r0_9(glval) = FunctionAddress[Middle] : # 801| v0_10(void) = Call : func:r0_9, this:r0_8 # 801| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 801| mu0_12(Middle) = ^IndirectMayWriteSideEffect : &:r0_8 +# 801| mu0_12(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 # 802| r0_13(glval) = VariableAddress[d] : # 802| r0_14(glval) = FunctionAddress[Derived] : # 802| v0_15(void) = Call : func:r0_14, this:r0_13 # 802| mu0_16(unknown) = ^CallSideEffect : ~mu0_2 -# 802| mu0_17(Derived) = ^IndirectMayWriteSideEffect : &:r0_13 +# 802| mu0_17(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_13 # 804| r0_18(glval) = VariableAddress[pb] : # 804| r0_19(glval) = VariableAddress[b] : # 804| mu0_20(Base *) = Store : &:r0_18, r0_19 @@ -3680,7 +3680,7 @@ ir.cpp: # 809| r0_41(glval) = ConvertToBase[Middle : Base] : r0_40 # 809| v0_42(void) = Call : func:r0_39, 0:r0_41 # 809| mu0_43(unknown) = ^CallSideEffect : ~mu0_2 -# 809| mu0_44(Base) = ^IndirectMayWriteSideEffect : +# 809| mu0_44(Base) = ^IndirectMayWriteSideEffect[-1] : # 809| v0_45(void) = ^IndirectReadSideEffect[0] : &:r0_41, ~mu0_2 # 809| mu0_46(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_41 # 809| r0_47(glval) = Convert : v0_42 @@ -3697,7 +3697,7 @@ ir.cpp: # 810| r0_58(glval) = ConvertToBase[Middle : Base] : r0_57 # 810| v0_59(void) = Call : func:r0_56, 0:r0_58 # 810| mu0_60(unknown) = ^CallSideEffect : ~mu0_2 -# 810| mu0_61(Base) = ^IndirectMayWriteSideEffect : +# 810| mu0_61(Base) = ^IndirectMayWriteSideEffect[-1] : # 810| v0_62(void) = ^IndirectReadSideEffect[0] : &:r0_58, ~mu0_2 # 810| mu0_63(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_58 # 810| r0_64(glval) = Convert : v0_59 @@ -3783,7 +3783,7 @@ ir.cpp: # 823| r0_144(glval) = ConvertToBase[Middle : Base] : r0_143 # 823| v0_145(void) = Call : func:r0_141, 0:r0_144 # 823| mu0_146(unknown) = ^CallSideEffect : ~mu0_2 -# 823| mu0_147(Base) = ^IndirectMayWriteSideEffect : +# 823| mu0_147(Base) = ^IndirectMayWriteSideEffect[-1] : # 823| v0_148(void) = ^IndirectReadSideEffect[0] : &:r0_144, ~mu0_2 # 823| mu0_149(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_144 # 823| r0_150(glval) = Convert : v0_145 @@ -3801,7 +3801,7 @@ ir.cpp: # 824| r0_162(glval) = ConvertToBase[Middle : Base] : r0_161 # 824| v0_163(void) = Call : func:r0_159, 0:r0_162 # 824| mu0_164(unknown) = ^CallSideEffect : ~mu0_2 -# 824| mu0_165(Base) = ^IndirectMayWriteSideEffect : +# 824| mu0_165(Base) = ^IndirectMayWriteSideEffect[-1] : # 824| v0_166(void) = ^IndirectReadSideEffect[0] : &:r0_162, ~mu0_2 # 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_162 # 824| r0_168(glval) = Convert : v0_163 @@ -3917,7 +3917,7 @@ ir.cpp: # 846| r0_5(glval) = FunctionAddress[PolymorphicBase] : # 846| v0_6(void) = Call : func:r0_5, this:r0_4 # 846| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 846| mu0_8(PolymorphicBase) = ^IndirectMayWriteSideEffect : &:r0_4 +# 846| mu0_8(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 # 846| v0_9(void) = NoOp : # 846| v0_10(void) = ReturnVoid : # 846| v0_11(void) = UnmodeledUse : mu* @@ -3947,12 +3947,12 @@ ir.cpp: #-----| r0_4(glval) = FunctionAddress[PolymorphicBase] : #-----| v0_5(void) = Call : func:r0_4, this:r0_3 #-----| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -#-----| mu0_7(PolymorphicBase) = ^IndirectMayWriteSideEffect : &:r0_3 +#-----| mu0_7(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 # 851| r0_8(glval) = VariableAddress[d] : # 851| r0_9(glval) = FunctionAddress[PolymorphicDerived] : # 851| v0_10(void) = Call : func:r0_9, this:r0_8 # 851| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 851| mu0_12(PolymorphicDerived) = ^IndirectMayWriteSideEffect : &:r0_8 +# 851| mu0_12(PolymorphicDerived) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 # 853| r0_13(glval) = VariableAddress[pb] : # 853| r0_14(glval) = VariableAddress[b] : # 853| mu0_15(PolymorphicBase *) = Store : &:r0_13, r0_14 @@ -3994,22 +3994,22 @@ ir.cpp: # 867| void String::String() # 867| Block 0 -# 867| v0_0(void) = EnterFunction : -# 867| mu0_1(unknown) = AliasedDefinition : -# 867| mu0_2(unknown) = UnmodeledDefinition : -# 867| r0_3(glval) = InitializeThis : -# 868| r0_4(glval) = FunctionAddress[String] : -# 868| r0_5(glval) = StringConstant[""] : -# 868| r0_6(char *) = Convert : r0_5 -# 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 -# 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 868| mu0_9(String) = ^IndirectMayWriteSideEffect : &:r0_3 -# 868| v0_10(void) = ^IndirectReadSideEffect[0] : &:r0_6, ~mu0_2 -# 868| mu0_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6 -# 869| v0_12(void) = NoOp : -# 867| v0_13(void) = ReturnVoid : -# 867| v0_14(void) = UnmodeledUse : mu* -# 867| v0_15(void) = ExitFunction : +# 867| v0_0(void) = EnterFunction : +# 867| mu0_1(unknown) = AliasedDefinition : +# 867| mu0_2(unknown) = UnmodeledDefinition : +# 867| r0_3(glval) = InitializeThis : +# 868| r0_4(glval) = FunctionAddress[String] : +# 868| r0_5(glval) = StringConstant[""] : +# 868| r0_6(char *) = Convert : r0_5 +# 868| v0_7(void) = Call : func:r0_4, this:r0_3, 0:r0_6 +# 868| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 +# 868| mu0_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 +# 868| v0_10(void) = ^IndirectReadSideEffect[0] : &:r0_6, ~mu0_2 +# 868| mu0_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6 +# 869| v0_12(void) = NoOp : +# 867| v0_13(void) = ReturnVoid : +# 867| v0_14(void) = UnmodeledUse : mu* +# 867| v0_15(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 @@ -4181,69 +4181,69 @@ ir.cpp: # 940| void OperatorNew() # 940| Block 0 -# 940| v0_0(void) = EnterFunction : -# 940| mu0_1(unknown) = AliasedDefinition : -# 940| mu0_2(unknown) = UnmodeledDefinition : -# 941| r0_3(glval) = FunctionAddress[operator new] : -# 941| r0_4(unsigned long) = Constant[4] : -# 941| r0_5(void *) = Call : func:r0_3, 0:r0_4 -# 941| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 941| r0_7(int *) = Convert : r0_5 -# 942| r0_8(glval) = FunctionAddress[operator new] : -# 942| r0_9(unsigned long) = Constant[4] : -# 942| r0_10(float) = Constant[1.0] : -# 942| r0_11(void *) = Call : func:r0_8, 0:r0_9, 1:r0_10 -# 942| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 942| r0_13(int *) = Convert : r0_11 -# 943| r0_14(glval) = FunctionAddress[operator new] : -# 943| r0_15(unsigned long) = Constant[4] : -# 943| r0_16(void *) = Call : func:r0_14, 0:r0_15 -# 943| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 -# 943| r0_18(int *) = Convert : r0_16 -# 943| r0_19(int) = Constant[0] : -# 943| mu0_20(int) = Store : &:r0_18, r0_19 -# 944| r0_21(glval) = FunctionAddress[operator new] : -# 944| r0_22(unsigned long) = Constant[8] : -# 944| r0_23(void *) = Call : func:r0_21, 0:r0_22 -# 944| mu0_24(unknown) = ^CallSideEffect : ~mu0_2 -# 944| r0_25(String *) = Convert : r0_23 -# 944| r0_26(glval) = FunctionAddress[String] : -# 944| v0_27(void) = Call : func:r0_26, this:r0_25 -# 944| mu0_28(unknown) = ^CallSideEffect : ~mu0_2 -# 944| mu0_29(String) = ^IndirectMayWriteSideEffect : &:r0_25 -# 945| r0_30(glval) = FunctionAddress[operator new] : -# 945| r0_31(unsigned long) = Constant[8] : -# 945| r0_32(float) = Constant[1.0] : -# 945| r0_33(void *) = Call : func:r0_30, 0:r0_31, 1:r0_32 -# 945| mu0_34(unknown) = ^CallSideEffect : ~mu0_2 -# 945| r0_35(String *) = Convert : r0_33 -# 945| r0_36(glval) = FunctionAddress[String] : -# 945| r0_37(glval) = StringConstant["hello"] : -# 945| r0_38(char *) = Convert : r0_37 -# 945| v0_39(void) = Call : func:r0_36, this:r0_35, 0:r0_38 -# 945| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 -# 945| mu0_41(String) = ^IndirectMayWriteSideEffect : &:r0_35 -# 945| v0_42(void) = ^IndirectReadSideEffect[0] : &:r0_38, ~mu0_2 -# 945| mu0_43(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_38 -# 946| r0_44(glval) = FunctionAddress[operator new] : -# 946| r0_45(unsigned long) = Constant[256] : -# 946| r0_46(align_val_t) = Constant[128] : -# 946| r0_47(void *) = Call : func:r0_44, 0:r0_45, 1:r0_46 -# 946| mu0_48(unknown) = ^CallSideEffect : ~mu0_2 -# 946| r0_49(Overaligned *) = Convert : r0_47 -# 947| r0_50(glval) = FunctionAddress[operator new] : -# 947| r0_51(unsigned long) = Constant[256] : -# 947| r0_52(align_val_t) = Constant[128] : -# 947| r0_53(float) = Constant[1.0] : -# 947| r0_54(void *) = Call : func:r0_50, 0:r0_51, 1:r0_52, 2:r0_53 -# 947| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 -# 947| r0_56(Overaligned *) = Convert : r0_54 -# 947| r0_57(Overaligned) = Constant[0] : -# 947| mu0_58(Overaligned) = Store : &:r0_56, r0_57 -# 948| v0_59(void) = NoOp : -# 940| v0_60(void) = ReturnVoid : -# 940| v0_61(void) = UnmodeledUse : mu* -# 940| v0_62(void) = ExitFunction : +# 940| v0_0(void) = EnterFunction : +# 940| mu0_1(unknown) = AliasedDefinition : +# 940| mu0_2(unknown) = UnmodeledDefinition : +# 941| r0_3(glval) = FunctionAddress[operator new] : +# 941| r0_4(unsigned long) = Constant[4] : +# 941| r0_5(void *) = Call : func:r0_3, 0:r0_4 +# 941| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 +# 941| r0_7(int *) = Convert : r0_5 +# 942| r0_8(glval) = FunctionAddress[operator new] : +# 942| r0_9(unsigned long) = Constant[4] : +# 942| r0_10(float) = Constant[1.0] : +# 942| r0_11(void *) = Call : func:r0_8, 0:r0_9, 1:r0_10 +# 942| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 +# 942| r0_13(int *) = Convert : r0_11 +# 943| r0_14(glval) = FunctionAddress[operator new] : +# 943| r0_15(unsigned long) = Constant[4] : +# 943| r0_16(void *) = Call : func:r0_14, 0:r0_15 +# 943| mu0_17(unknown) = ^CallSideEffect : ~mu0_2 +# 943| r0_18(int *) = Convert : r0_16 +# 943| r0_19(int) = Constant[0] : +# 943| mu0_20(int) = Store : &:r0_18, r0_19 +# 944| r0_21(glval) = FunctionAddress[operator new] : +# 944| r0_22(unsigned long) = Constant[8] : +# 944| r0_23(void *) = Call : func:r0_21, 0:r0_22 +# 944| mu0_24(unknown) = ^CallSideEffect : ~mu0_2 +# 944| r0_25(String *) = Convert : r0_23 +# 944| r0_26(glval) = FunctionAddress[String] : +# 944| v0_27(void) = Call : func:r0_26, this:r0_25 +# 944| mu0_28(unknown) = ^CallSideEffect : ~mu0_2 +# 944| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_25 +# 945| r0_30(glval) = FunctionAddress[operator new] : +# 945| r0_31(unsigned long) = Constant[8] : +# 945| r0_32(float) = Constant[1.0] : +# 945| r0_33(void *) = Call : func:r0_30, 0:r0_31, 1:r0_32 +# 945| mu0_34(unknown) = ^CallSideEffect : ~mu0_2 +# 945| r0_35(String *) = Convert : r0_33 +# 945| r0_36(glval) = FunctionAddress[String] : +# 945| r0_37(glval) = StringConstant["hello"] : +# 945| r0_38(char *) = Convert : r0_37 +# 945| v0_39(void) = Call : func:r0_36, this:r0_35, 0:r0_38 +# 945| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 +# 945| mu0_41(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_35 +# 945| v0_42(void) = ^IndirectReadSideEffect[0] : &:r0_38, ~mu0_2 +# 945| mu0_43(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_38 +# 946| r0_44(glval) = FunctionAddress[operator new] : +# 946| r0_45(unsigned long) = Constant[256] : +# 946| r0_46(align_val_t) = Constant[128] : +# 946| r0_47(void *) = Call : func:r0_44, 0:r0_45, 1:r0_46 +# 946| mu0_48(unknown) = ^CallSideEffect : ~mu0_2 +# 946| r0_49(Overaligned *) = Convert : r0_47 +# 947| r0_50(glval) = FunctionAddress[operator new] : +# 947| r0_51(unsigned long) = Constant[256] : +# 947| r0_52(align_val_t) = Constant[128] : +# 947| r0_53(float) = Constant[1.0] : +# 947| r0_54(void *) = Call : func:r0_50, 0:r0_51, 1:r0_52, 2:r0_53 +# 947| mu0_55(unknown) = ^CallSideEffect : ~mu0_2 +# 947| r0_56(Overaligned *) = Convert : r0_54 +# 947| r0_57(Overaligned) = Constant[0] : +# 947| mu0_58(Overaligned) = Store : &:r0_56, r0_57 +# 948| v0_59(void) = NoOp : +# 940| v0_60(void) = ReturnVoid : +# 940| v0_61(void) = UnmodeledUse : mu* +# 940| v0_62(void) = ExitFunction : # 950| void OperatorNewArray(int) # 950| Block 0 @@ -4721,7 +4721,7 @@ ir.cpp: #-----| r0_38(glval) = FunctionAddress[String] : #-----| v0_39(void) = Call : func:r0_38, this:r0_37 #-----| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 -#-----| mu0_41(String) = ^IndirectMayWriteSideEffect : &:r0_37 +#-----| mu0_41(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_37 # 1036| r0_42(glval) = FieldAddress[x] : r0_35 #-----| r0_43(glval) = VariableAddress[x] : #-----| r0_44(int) = Load : &:r0_43, ~mu0_2 @@ -4729,7 +4729,7 @@ ir.cpp: # 1036| r0_46(decltype([...](...){...})) = Load : &:r0_35, ~mu0_2 # 1036| v0_47(void) = Call : func:r0_34, this:r0_33, 0:r0_46 # 1036| mu0_48(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| mu0_49(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_33 +# 1036| mu0_49(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_33 # 1036| v0_50(void) = ^IndirectReadSideEffect[0] : &:r0_46, ~mu0_2 # 1036| mu0_51(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_46 # 1037| r0_52(glval) = VariableAddress[lambda_val] : @@ -4765,11 +4765,11 @@ ir.cpp: #-----| r0_82(glval) = FunctionAddress[String] : #-----| v0_83(void) = Call : func:r0_82, this:r0_81 #-----| mu0_84(unknown) = ^CallSideEffect : ~mu0_2 -#-----| mu0_85(String) = ^IndirectMayWriteSideEffect : &:r0_81 +#-----| mu0_85(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_81 # 1040| r0_86(decltype([...](...){...})) = Load : &:r0_79, ~mu0_2 # 1040| v0_87(void) = Call : func:r0_78, this:r0_77, 0:r0_86 # 1040| mu0_88(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| mu0_89(decltype([...](...){...})) = ^IndirectMayWriteSideEffect : &:r0_77 +# 1040| mu0_89(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_77 # 1040| v0_90(void) = ^IndirectReadSideEffect[0] : &:r0_86, ~mu0_2 # 1040| mu0_91(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_86 # 1041| r0_92(glval) = VariableAddress[lambda_val_explicit] : @@ -4984,21 +4984,21 @@ ir.cpp: # 1040| void (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::(constructor)((void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)&&) # 1040| Block 0 -# 1040| v0_0(void) = EnterFunction : -# 1040| mu0_1(unknown) = AliasedDefinition : -# 1040| mu0_2(unknown) = UnmodeledDefinition : -# 1040| r0_3(glval) = InitializeThis : -#-----| r0_4(glval) = VariableAddress[p#0] : -#-----| mu0_5(lambda [] type at line 1040, col. 30 &&) = InitializeParameter[p#0] : &:r0_4 -# 1040| r0_6(glval) = FieldAddress[s] : r0_3 -# 1040| r0_7(glval) = FunctionAddress[String] : -# 1040| v0_8(void) = Call : func:r0_7, this:r0_6 -# 1040| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| mu0_10(String) = ^IndirectMayWriteSideEffect : &:r0_6 -# 1040| v0_11(void) = NoOp : -# 1040| v0_12(void) = ReturnVoid : -# 1040| v0_13(void) = UnmodeledUse : mu* -# 1040| v0_14(void) = ExitFunction : +# 1040| v0_0(void) = EnterFunction : +# 1040| mu0_1(unknown) = AliasedDefinition : +# 1040| mu0_2(unknown) = UnmodeledDefinition : +# 1040| r0_3(glval) = InitializeThis : +#-----| r0_4(glval) = VariableAddress[p#0] : +#-----| mu0_5(lambda [] type at line 1040, col. 30 &&) = InitializeParameter[p#0] : &:r0_4 +# 1040| r0_6(glval) = FieldAddress[s] : r0_3 +# 1040| r0_7(glval) = FunctionAddress[String] : +# 1040| v0_8(void) = Call : func:r0_7, this:r0_6 +# 1040| mu0_9(unknown) = ^CallSideEffect : ~mu0_2 +# 1040| mu0_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 +# 1040| v0_11(void) = NoOp : +# 1040| v0_12(void) = ReturnVoid : +# 1040| v0_13(void) = UnmodeledUse : mu* +# 1040| v0_14(void) = ExitFunction : # 1040| void (void Lambda(int, String const&))::(lambda [] type at line 1040, col. 30)::~() # 1040| Block 0 @@ -5417,7 +5417,7 @@ ir.cpp: # 1140| r7_3(char *) = Convert : r7_2 # 1140| v7_4(void) = Call : func:r7_1, this:r7_0, 0:r7_3 # 1140| mu7_5(unknown) = ^CallSideEffect : ~mu0_2 -# 1140| mu7_6(String) = ^IndirectMayWriteSideEffect : &:r7_0 +# 1140| mu7_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r7_0 # 1140| v7_7(void) = ^IndirectReadSideEffect[0] : &:r7_3, ~mu0_2 # 1140| mu7_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r7_3 # 1140| v7_9(void) = ThrowValue : &:r7_0, ~mu0_2 @@ -5435,18 +5435,18 @@ ir.cpp: #-----| Goto -> Block 10 # 1144| Block 10 -# 1144| r10_0(glval) = VariableAddress[s] : -# 1144| mu10_1(char *) = InitializeParameter[s] : &:r10_0 -# 1145| r10_2(glval) = VariableAddress[#throw1145:5] : -# 1145| r10_3(glval) = FunctionAddress[String] : -# 1145| r10_4(glval) = VariableAddress[s] : -# 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2 -# 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 -# 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 -# 1145| mu10_8(String) = ^IndirectMayWriteSideEffect : &:r10_2 -# 1145| v10_9(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 -# 1145| mu10_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 -# 1145| v10_11(void) = ThrowValue : &:r10_2, ~mu0_2 +# 1144| r10_0(glval) = VariableAddress[s] : +# 1144| mu10_1(char *) = InitializeParameter[s] : &:r10_0 +# 1145| r10_2(glval) = VariableAddress[#throw1145:5] : +# 1145| r10_3(glval) = FunctionAddress[String] : +# 1145| r10_4(glval) = VariableAddress[s] : +# 1145| r10_5(char *) = Load : &:r10_4, ~mu0_2 +# 1145| v10_6(void) = Call : func:r10_3, this:r10_2, 0:r10_5 +# 1145| mu10_7(unknown) = ^CallSideEffect : ~mu0_2 +# 1145| mu10_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r10_2 +# 1145| v10_9(void) = ^IndirectReadSideEffect[0] : &:r10_5, ~mu0_2 +# 1145| mu10_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_5 +# 1145| v10_11(void) = ThrowValue : &:r10_2, ~mu0_2 #-----| Exception -> Block 2 # 1147| Block 11 @@ -5573,24 +5573,24 @@ perf-regression.cpp: # 9| int main() # 9| Block 0 -# 9| v0_0(void) = EnterFunction : -# 9| mu0_1(unknown) = AliasedDefinition : -# 9| mu0_2(unknown) = UnmodeledDefinition : -# 10| r0_3(glval) = VariableAddress[big] : -# 10| r0_4(glval) = FunctionAddress[operator new] : -# 10| r0_5(unsigned long) = Constant[1073741824] : -# 10| r0_6(void *) = Call : func:r0_4, 0:r0_5 -# 10| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 10| r0_8(Big *) = Convert : r0_6 -# 10| r0_9(glval) = FunctionAddress[Big] : -# 10| v0_10(void) = Call : func:r0_9, this:r0_8 -# 10| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 10| mu0_12(Big) = ^IndirectMayWriteSideEffect : &:r0_8 -# 10| mu0_13(Big *) = Store : &:r0_3, r0_8 -# 12| r0_14(glval) = VariableAddress[#return] : -# 12| r0_15(int) = Constant[0] : -# 12| mu0_16(int) = Store : &:r0_14, r0_15 -# 9| r0_17(glval) = VariableAddress[#return] : -# 9| v0_18(void) = ReturnValue : &:r0_17, ~mu0_2 -# 9| v0_19(void) = UnmodeledUse : mu* -# 9| v0_20(void) = ExitFunction : +# 9| v0_0(void) = EnterFunction : +# 9| mu0_1(unknown) = AliasedDefinition : +# 9| mu0_2(unknown) = UnmodeledDefinition : +# 10| r0_3(glval) = VariableAddress[big] : +# 10| r0_4(glval) = FunctionAddress[operator new] : +# 10| r0_5(unsigned long) = Constant[1073741824] : +# 10| r0_6(void *) = Call : func:r0_4, 0:r0_5 +# 10| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +# 10| r0_8(Big *) = Convert : r0_6 +# 10| r0_9(glval) = FunctionAddress[Big] : +# 10| v0_10(void) = Call : func:r0_9, this:r0_8 +# 10| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 +# 10| mu0_12(Big) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 +# 10| mu0_13(Big *) = Store : &:r0_3, r0_8 +# 12| r0_14(glval) = VariableAddress[#return] : +# 12| r0_15(int) = Constant[0] : +# 12| mu0_16(int) = Store : &:r0_14, r0_15 +# 9| r0_17(glval) = VariableAddress[#return] : +# 9| v0_18(void) = ReturnValue : &:r0_17, ~mu0_2 +# 9| v0_19(void) = UnmodeledUse : mu* +# 9| v0_20(void) = ExitFunction : From 4a8e8fa0de4470aaeed94357f70b54b68c0b84a7 Mon Sep 17 00:00:00 2001 From: james Date: Fri, 4 Oct 2019 09:18:19 +0100 Subject: [PATCH 0366/1227] docs: semmle logo --- .../static/theme/css/default.css | 18 +-- .../_static-training/title-slide.svg | 149 +----------------- .../ql-training/cpp/bad-overflow-guard.rst | 4 - .../ql-training/cpp/control-flow-cpp.rst | 4 - .../ql-training/cpp/data-flow-cpp.rst | 4 - .../ql-training/cpp/global-data-flow-cpp.rst | 4 - .../language/ql-training/cpp/intro-ql-cpp.rst | 4 - .../cpp/program-representation-cpp.rst | 4 - docs/language/ql-training/cpp/snprintf.rst | 4 - docs/language/ql-training/index.rst | 4 - .../ql-training/java/apache-struts-java.rst | 4 - .../ql-training/java/data-flow-java.rst | 4 - .../java/global-data-flow-java.rst | 4 - .../ql-training/java/intro-ql-java.rst | 4 - .../java/program-representation-java.rst | 4 - .../ql-training/java/query-injection-java.rst | 4 - docs/language/ql-training/template.rst | 4 - 17 files changed, 4 insertions(+), 223 deletions(-) diff --git a/docs/language/ql-training/_static-training/slides-semmle-2/static/theme/css/default.css b/docs/language/ql-training/_static-training/slides-semmle-2/static/theme/css/default.css index e3664d42e06..83d3d94e3aa 100644 --- a/docs/language/ql-training/_static-training/slides-semmle-2/static/theme/css/default.css +++ b/docs/language/ql-training/_static-training/slides-semmle-2/static/theme/css/default.css @@ -1301,13 +1301,13 @@ aside.gdbar img { .title-slide hgroup h1 { font-size: 2em; line-height: 1.4; - /*letter-spacing: -3px;*/ color: white; margin: auto; display: block; position: absolute; top: 0; bottom: 10%; + left: 1.25em; height: 0; } /* line 898, ../scss/default.scss */ @@ -1431,31 +1431,19 @@ hgroup .pre { color: #5c31ff; } -/* title slide (deck title, subtitle, semmle logo)*/ +/* title slide (deck title, subtitle)*/ .title-slide { background-image: url("../../title-slide.svg"); background-size: cover; } -.semmle-logo sup { - vertical-align: super; - font-size: 0.3em; - font-weight: 100; -} - -.title-slide .semmle-logo { - color: white; - font-size: 1.2em; - position: absolute; - top: 10%; -} - .title-slide p { color: white; font-size: 1em; position: absolute; bottom: 30%; + left: 2.6em; } .title-slide hgroup .pre { diff --git a/docs/language/ql-training/_static-training/title-slide.svg b/docs/language/ql-training/_static-training/title-slide.svg index 6f9a19f4a1b..13eb2d34fef 100644 --- a/docs/language/ql-training/_static-training/title-slide.svg +++ b/docs/language/ql-training/_static-training/title-slide.svg @@ -1,148 +1 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/docs/language/ql-training/cpp/bad-overflow-guard.rst b/docs/language/ql-training/cpp/bad-overflow-guard.rst index 12f35440906..3ac9ee55f3b 100644 --- a/docs/language/ql-training/cpp/bad-overflow-guard.rst +++ b/docs/language/ql-training/cpp/bad-overflow-guard.rst @@ -4,10 +4,6 @@ Example: Bad overflow guard QL for C/C++ -.. container:: semmle-logo - - Semmle :sup:`TM` - .. rst-class:: setup Setup diff --git a/docs/language/ql-training/cpp/control-flow-cpp.rst b/docs/language/ql-training/cpp/control-flow-cpp.rst index ea8e2c1b158..e4d17fff844 100644 --- a/docs/language/ql-training/cpp/control-flow-cpp.rst +++ b/docs/language/ql-training/cpp/control-flow-cpp.rst @@ -4,10 +4,6 @@ Analyzing control flow QL for C/C++ -.. container:: semmle-logo - - Semmle :sup:`TM` - .. Include information slides here .. rst-class:: setup diff --git a/docs/language/ql-training/cpp/data-flow-cpp.rst b/docs/language/ql-training/cpp/data-flow-cpp.rst index 36b5eb6b525..6ece12d1525 100644 --- a/docs/language/ql-training/cpp/data-flow-cpp.rst +++ b/docs/language/ql-training/cpp/data-flow-cpp.rst @@ -4,10 +4,6 @@ Introduction to data flow Finding string formatting vulnerabilities in C/C++ -.. container:: semmle-logo - - Semmle :sup:`TM` - .. rst-class:: setup Setup diff --git a/docs/language/ql-training/cpp/global-data-flow-cpp.rst b/docs/language/ql-training/cpp/global-data-flow-cpp.rst index 6033581ffc3..02c37b5fb4c 100644 --- a/docs/language/ql-training/cpp/global-data-flow-cpp.rst +++ b/docs/language/ql-training/cpp/global-data-flow-cpp.rst @@ -3,10 +3,6 @@ Introduction to global data flow ================================ QL for C/C++ - -.. container:: semmle-logo - - Semmle :sup:`TM` .. rst-class:: setup diff --git a/docs/language/ql-training/cpp/intro-ql-cpp.rst b/docs/language/ql-training/cpp/intro-ql-cpp.rst index 82eb62a3ba8..fedbed7f0f5 100644 --- a/docs/language/ql-training/cpp/intro-ql-cpp.rst +++ b/docs/language/ql-training/cpp/intro-ql-cpp.rst @@ -4,10 +4,6 @@ Introduction to variant analysis QL for C/C++ -.. container:: semmle-logo - - Semmle :sup:`TM` - .. rst-class:: setup Setup diff --git a/docs/language/ql-training/cpp/program-representation-cpp.rst b/docs/language/ql-training/cpp/program-representation-cpp.rst index 1850e3e5671..4555d918822 100644 --- a/docs/language/ql-training/cpp/program-representation-cpp.rst +++ b/docs/language/ql-training/cpp/program-representation-cpp.rst @@ -4,10 +4,6 @@ Program representation QL for C/C++ -.. container:: semmle-logo - - Semmle :sup:`TM` - .. rst-class:: agenda Agenda diff --git a/docs/language/ql-training/cpp/snprintf.rst b/docs/language/ql-training/cpp/snprintf.rst index 77e46933fcb..5f1a27bf8db 100644 --- a/docs/language/ql-training/cpp/snprintf.rst +++ b/docs/language/ql-training/cpp/snprintf.rst @@ -4,10 +4,6 @@ Exercise: ``snprintf`` overflow QL for C/C++ -.. container:: semmle-logo - - Semmle :sup:`TM` - .. rst-class:: setup Setup diff --git a/docs/language/ql-training/index.rst b/docs/language/ql-training/index.rst index 0cc4ca9b024..6f3aea9a17a 100644 --- a/docs/language/ql-training/index.rst +++ b/docs/language/ql-training/index.rst @@ -1,10 +1,6 @@ QL training and variant analysis examples ========================================= -.. container:: semmle-logo - - Semmle :sup:`TM` - .. toctree:: :glob: :maxdepth: 1 diff --git a/docs/language/ql-training/java/apache-struts-java.rst b/docs/language/ql-training/java/apache-struts-java.rst index 7fcd2e003cd..c39652fa2a5 100644 --- a/docs/language/ql-training/java/apache-struts-java.rst +++ b/docs/language/ql-training/java/apache-struts-java.rst @@ -8,10 +8,6 @@ Exercise: Apache Struts CVE-2017-9805 -.. container:: semmle-logo - - Semmle :sup:`TM` - .. rst-class:: setup Setup diff --git a/docs/language/ql-training/java/data-flow-java.rst b/docs/language/ql-training/java/data-flow-java.rst index be9ba98456e..78e4bf54946 100644 --- a/docs/language/ql-training/java/data-flow-java.rst +++ b/docs/language/ql-training/java/data-flow-java.rst @@ -2,10 +2,6 @@ Introduction to data flow ========================= -.. container:: semmle-logo - - Semmle :sup:`TM` - Finding SPARQL injection vulnerabilities in Java .. rst-class:: setup diff --git a/docs/language/ql-training/java/global-data-flow-java.rst b/docs/language/ql-training/java/global-data-flow-java.rst index 665899f8459..6d821d60ea2 100644 --- a/docs/language/ql-training/java/global-data-flow-java.rst +++ b/docs/language/ql-training/java/global-data-flow-java.rst @@ -4,10 +4,6 @@ Introduction to global data flow QL for Java -.. container:: semmle-logo - - Semmle :sup:`TM` - .. rst-class:: setup Setup diff --git a/docs/language/ql-training/java/intro-ql-java.rst b/docs/language/ql-training/java/intro-ql-java.rst index 392c18309cb..611be7dfd6e 100644 --- a/docs/language/ql-training/java/intro-ql-java.rst +++ b/docs/language/ql-training/java/intro-ql-java.rst @@ -4,10 +4,6 @@ Introduction to variant analysis QL for Java -.. container:: semmle-logo - - Semmle :sup:`TM` - .. rst-class:: setup Setup diff --git a/docs/language/ql-training/java/program-representation-java.rst b/docs/language/ql-training/java/program-representation-java.rst index d090c30aebe..ddd8103454f 100644 --- a/docs/language/ql-training/java/program-representation-java.rst +++ b/docs/language/ql-training/java/program-representation-java.rst @@ -4,10 +4,6 @@ Program representation QL for Java -.. container:: semmle-logo - - Semmle :sup:`TM` - .. rst-class:: agenda Agenda diff --git a/docs/language/ql-training/java/query-injection-java.rst b/docs/language/ql-training/java/query-injection-java.rst index 67f7fe21a76..de5d9623bfc 100644 --- a/docs/language/ql-training/java/query-injection-java.rst +++ b/docs/language/ql-training/java/query-injection-java.rst @@ -4,10 +4,6 @@ Example: Query injection QL for Java -.. container:: semmle-logo - - Semmle :sup:`TM` - .. rst-class:: setup Setup diff --git a/docs/language/ql-training/template.rst b/docs/language/ql-training/template.rst index 0cce4a11435..21c5abef144 100644 --- a/docs/language/ql-training/template.rst +++ b/docs/language/ql-training/template.rst @@ -27,10 +27,6 @@ Template slide deck Second subheading -.. container:: semmle-logo - - Semmle :sup:`TM` - .. Set up slide. Include link to QL4E snapshots required for examples .. rst-class:: setup From ced5e3ea2935bfcd25609d2a507c341bd0487725 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <54990334+erik-krogh@users.noreply.github.com> Date: Fri, 4 Oct 2019 11:02:15 +0200 Subject: [PATCH 0367/1227] qhelp adjustment from code-review Co-Authored-By: Esben Sparre Andreasen <42067045+esben-semmle@users.noreply.github.com> --- .../ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp index f34fdda1639..67c3c67d213 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp @@ -4,7 +4,7 @@

    -In TypeScript the keywords constructor and new are +In TypeScript the keywords constructor and new for member declarations are used to declare constructors in classes and interfaces respectively. However, by using the wrong keyword a programmer can accidentally declare e.g. a method called constructor inside an interface. From 712a337bddc8c07bd61fda864a96e6efde149ee8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 4 Oct 2019 11:06:11 +0200 Subject: [PATCH 0368/1227] qhelp adjustments based on code-review --- .../SuspiciousMethodNameDeclaration.qhelp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp index 67c3c67d213..66e6e9404e2 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp @@ -4,13 +4,15 @@

    -In TypeScript the keywords constructor and new for member declarations are -used to declare constructors in classes and interfaces respectively. -However, by using the wrong keyword a programmer can accidentally declare e.g. -a method called constructor inside an interface. -Similarly the keyword function is used to declare functions in -some contexts, however, using the keyword function inside a class -or interface results in declaring a method called function. +In TypeScript the keywords constructor and new for +member declarations are used to declare constructors in classes and interfaces +respectively. +However, a member declaration with the name new in an interface +or constructor in a class, will declare ordinary methods named +new or constructor rather than constructors. +Similarly, the keyword function is used to declare functions in +some contexts, however, using the name function for a class +or interface member declaration declares a method named function.

    From 9b58d799cb7a4fd095152a6eaf34de01856b76e6 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 3 Oct 2019 18:19:14 +0200 Subject: [PATCH 0369/1227] Java/C++/C#: Tweak `AccessPathNil::toString()` Move the type annotation outside the brackets, to avoid prefixes such as `[ : T]`. --- .../cpp/dataflow/internal/DataFlowImpl.qll | 18 +++++++++--------- .../cpp/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++--------- .../cpp/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++--------- .../cpp/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++--------- .../dataflow/internal/DataFlowImplLocal.qll | 18 +++++++++--------- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 18 +++++++++--------- .../cpp/ir/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++--------- .../cpp/ir/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++--------- .../cpp/ir/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++--------- .../csharp/dataflow/internal/DataFlowImpl.qll | 18 +++++++++--------- .../csharp/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++--------- .../csharp/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++--------- .../csharp/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++--------- .../csharp/dataflow/internal/DataFlowImpl5.qll | 18 +++++++++--------- .../java/dataflow/internal/DataFlowImpl.qll | 18 +++++++++--------- .../java/dataflow/internal/DataFlowImpl2.qll | 18 +++++++++--------- .../java/dataflow/internal/DataFlowImpl3.qll | 18 +++++++++--------- .../java/dataflow/internal/DataFlowImpl4.qll | 18 +++++++++--------- .../java/dataflow/internal/DataFlowImpl5.qll | 18 +++++++++--------- 19 files changed, 171 insertions(+), 171 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index e0ca469bf78..ab2f43dea64 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index e0ca469bf78..ab2f43dea64 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index e0ca469bf78..ab2f43dea64 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index e0ca469bf78..ab2f43dea64 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index e0ca469bf78..ab2f43dea64 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index e0ca469bf78..ab2f43dea64 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index e0ca469bf78..ab2f43dea64 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index e0ca469bf78..ab2f43dea64 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index e0ca469bf78..ab2f43dea64 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index e0ca469bf78..ab2f43dea64 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index e0ca469bf78..ab2f43dea64 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index e0ca469bf78..ab2f43dea64 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index e0ca469bf78..ab2f43dea64 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index e0ca469bf78..ab2f43dea64 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index e0ca469bf78..ab2f43dea64 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index e0ca469bf78..ab2f43dea64 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index e0ca469bf78..ab2f43dea64 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index e0ca469bf78..ab2f43dea64 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index e0ca469bf78..ab2f43dea64 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -1261,7 +1261,7 @@ abstract private class AccessPath extends TAccessPath { private class AccessPathNil extends AccessPath, TNil { override string toString() { - exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -1277,7 +1277,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil { override string toString() { exists(Content f, DataFlowType t | this = TConsNil(f, t) | // The `concat` becomes "" if `ppReprType` has no result. - result = f.toString() + concat(" : " + ppReprType(t)) + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) ) } @@ -1294,8 +1294,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons { override string toString() { exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) | if len = 2 - then result = f1.toString() + ", " + f2.toString() - else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" ) } @@ -1626,7 +1626,7 @@ abstract class PathNode extends TPathNode { this instanceof PathNodeSink and result = "" or exists(string s | s = this.(PathNodeMid).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } @@ -2071,7 +2071,7 @@ private module FlowExploration { private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { override string toString() { - exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t))) + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) } override AccessPathFront getFront() { @@ -2083,8 +2083,8 @@ private module FlowExploration { override string toString() { exists(Content f, int len | this = TPartialCons(f, len) | if len = 1 - then result = f.toString() - else result = f.toString() + ", ... (" + len.toString() + ")" + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" ) } @@ -2161,7 +2161,7 @@ private module FlowExploration { private string ppAp() { exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | - if s = "" then result = "" else result = " [" + s + "]" + if s = "" then result = "" else result = " " + s ) } From 7f6e253425ecb582a3f02bc05cb99a303bd436fe Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 4 Oct 2019 09:38:17 +0200 Subject: [PATCH 0370/1227] Java: Update expected test output --- .../dataflow/partial/test.expected | 6 +- .../CWE-022/semmle/tests/TaintedPath.expected | 14 +- .../CWE-022/semmle/tests/ZipSlip.expected | 14 +- .../CWE-079/semmle/tests/XSS.expected | 24 +- .../semmle/examples/SqlTaintedLocal.expected | 46 +-- .../semmle/tests/ResponseSplitting.expected | 6 +- ...nOfArrayConstructionCodeSpecified.expected | 6 +- ...alidationOfArrayConstructionLocal.expected | 10 +- ...lidationOfArrayIndexCodeSpecified.expected | 14 +- ...properValidationOfArrayIndexLocal.expected | 6 +- .../ExternallyControlledFormatString.expected | 14 +- ...rnallyControlledFormatStringLocal.expected | 22 +- .../tests/ArithmeticTaintedLocal.expected | 88 +++--- .../tests/ArithmeticUncontrolled.expected | 10 +- .../ArithmeticWithExtremeValues.expected | 42 +-- .../CWE-502/UnsafeDeserialization.expected | 88 +++--- .../CWE-601/semmle/tests/UrlRedirect.expected | 6 +- .../query-tests/security/CWE-611/XXE.expected | 298 +++++++++--------- .../tests/NumericCastTaintedLocal.expected | 6 +- .../HardcodedCredentialsApiCall.expected | 116 +++---- .../HardcodedCredentialsSourceCall.expected | 12 +- .../semmle/tests/ConditionalBypass.expected | 32 +- .../tests/TaintedPermissionsCheck.expected | 6 +- 23 files changed, 443 insertions(+), 443 deletions(-) diff --git a/java/ql/test/library-tests/dataflow/partial/test.expected b/java/ql/test/library-tests/dataflow/partial/test.expected index 4c6f68397ac..392383fb638 100644 --- a/java/ql/test/library-tests/dataflow/partial/test.expected +++ b/java/ql/test/library-tests/dataflow/partial/test.expected @@ -1,13 +1,13 @@ edges | A.java:12:5:12:5 | b [post update] [elem] | A.java:13:12:13:12 | b [elem] | -| A.java:12:14:12:18 | src(...) [ : Object] | A.java:12:5:12:5 | b [post update] [elem] | -| A.java:12:14:12:18 | src(...) [ : Object] | A.java:12:5:12:18 | ...=... [ : Object] | +| A.java:12:14:12:18 | src(...) : Object | A.java:12:5:12:5 | b [post update] [elem] | +| A.java:12:14:12:18 | src(...) : Object | A.java:12:5:12:18 | ...=... : Object | | A.java:13:12:13:12 | b [elem] | A.java:17:13:17:16 | f1(...) [elem] | | A.java:17:13:17:16 | f1(...) [elem] | A.java:18:8:18:8 | b [elem] | | A.java:18:8:18:8 | b [elem] | A.java:21:11:21:15 | b [elem] | #select | 0 | A.java:12:5:12:5 | b [post update] [elem] | -| 0 | A.java:12:5:12:18 | ...=... [ : Object] | +| 0 | A.java:12:5:12:18 | ...=... : Object | | 0 | A.java:13:12:13:12 | b [elem] | | 1 | A.java:17:13:17:16 | f1(...) [elem] | | 1 | A.java:18:8:18:8 | b [elem] | diff --git a/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.expected b/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.expected index afb5a7d5af4..2f761c646ea 100644 --- a/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.expected +++ b/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.expected @@ -1,13 +1,13 @@ edges -| Test.java:19:18:19:38 | getHostName(...) [ : String] | Test.java:24:20:24:23 | temp | -| Test.java:19:18:19:38 | getHostName(...) [ : String] | Test.java:27:21:27:24 | temp | -| Test.java:19:18:19:38 | getHostName(...) [ : String] | Test.java:30:44:30:47 | temp | +| Test.java:19:18:19:38 | getHostName(...) : String | Test.java:24:20:24:23 | temp | +| Test.java:19:18:19:38 | getHostName(...) : String | Test.java:27:21:27:24 | temp | +| Test.java:19:18:19:38 | getHostName(...) : String | Test.java:30:44:30:47 | temp | nodes -| Test.java:19:18:19:38 | getHostName(...) [ : String] | semmle.label | getHostName(...) [ : String] | +| Test.java:19:18:19:38 | getHostName(...) : String | semmle.label | getHostName(...) : String | | Test.java:24:20:24:23 | temp | semmle.label | temp | | Test.java:27:21:27:24 | temp | semmle.label | temp | | Test.java:30:44:30:47 | temp | semmle.label | temp | #select -| Test.java:24:11:24:24 | new File(...) | Test.java:19:18:19:38 | getHostName(...) [ : String] | Test.java:24:20:24:23 | temp | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | -| Test.java:27:11:27:25 | get(...) | Test.java:19:18:19:38 | getHostName(...) [ : String] | Test.java:27:21:27:24 | temp | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | -| Test.java:30:11:30:48 | getPath(...) | Test.java:19:18:19:38 | getHostName(...) [ : String] | Test.java:30:44:30:47 | temp | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | +| Test.java:24:11:24:24 | new File(...) | Test.java:19:18:19:38 | getHostName(...) : String | Test.java:24:20:24:23 | temp | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | +| Test.java:27:11:27:25 | get(...) | Test.java:19:18:19:38 | getHostName(...) : String | Test.java:27:21:27:24 | temp | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | +| Test.java:30:11:30:48 | getPath(...) | Test.java:19:18:19:38 | getHostName(...) : String | Test.java:30:44:30:47 | temp | $@ flows to here and is used in a path. | Test.java:19:18:19:38 | getHostName(...) | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.expected b/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.expected index ff53b4d0a96..6b27b1ec84c 100644 --- a/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.expected +++ b/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.expected @@ -1,13 +1,13 @@ edges -| ZipTest.java:7:19:7:33 | getName(...) [ : String] | ZipTest.java:9:48:9:51 | file | -| ZipTest.java:7:19:7:33 | getName(...) [ : String] | ZipTest.java:10:49:10:52 | file | -| ZipTest.java:7:19:7:33 | getName(...) [ : String] | ZipTest.java:11:36:11:39 | file | +| ZipTest.java:7:19:7:33 | getName(...) : String | ZipTest.java:9:48:9:51 | file | +| ZipTest.java:7:19:7:33 | getName(...) : String | ZipTest.java:10:49:10:52 | file | +| ZipTest.java:7:19:7:33 | getName(...) : String | ZipTest.java:11:36:11:39 | file | nodes -| ZipTest.java:7:19:7:33 | getName(...) [ : String] | semmle.label | getName(...) [ : String] | +| ZipTest.java:7:19:7:33 | getName(...) : String | semmle.label | getName(...) : String | | ZipTest.java:9:48:9:51 | file | semmle.label | file | | ZipTest.java:10:49:10:52 | file | semmle.label | file | | ZipTest.java:11:36:11:39 | file | semmle.label | file | #select -| ZipTest.java:7:19:7:33 | getName(...) | ZipTest.java:7:19:7:33 | getName(...) [ : String] | ZipTest.java:9:48:9:51 | file | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:9:48:9:51 | file | file system operation | -| ZipTest.java:7:19:7:33 | getName(...) | ZipTest.java:7:19:7:33 | getName(...) [ : String] | ZipTest.java:10:49:10:52 | file | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:10:49:10:52 | file | file system operation | -| ZipTest.java:7:19:7:33 | getName(...) | ZipTest.java:7:19:7:33 | getName(...) [ : String] | ZipTest.java:11:36:11:39 | file | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:11:36:11:39 | file | file system operation | +| ZipTest.java:7:19:7:33 | getName(...) | ZipTest.java:7:19:7:33 | getName(...) : String | ZipTest.java:9:48:9:51 | file | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:9:48:9:51 | file | file system operation | +| ZipTest.java:7:19:7:33 | getName(...) | ZipTest.java:7:19:7:33 | getName(...) : String | ZipTest.java:10:49:10:52 | file | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:10:49:10:52 | file | file system operation | +| ZipTest.java:7:19:7:33 | getName(...) | ZipTest.java:7:19:7:33 | getName(...) : String | ZipTest.java:11:36:11:39 | file | Unsanitized archive entry, which may contain '..', is used in a $@. | ZipTest.java:11:36:11:39 | file | file system operation | diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected b/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected index 5615c087a34..ed67a987e84 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected @@ -1,19 +1,19 @@ edges -| XSS.java:23:21:23:48 | getParameter(...) [ : String] | XSS.java:23:5:23:70 | ... + ... | -| XSS.java:27:21:27:48 | getParameter(...) [ : String] | XSS.java:27:5:27:70 | ... + ... | -| XSS.java:38:67:38:87 | getPathInfo(...) [ : String] | XSS.java:38:30:38:87 | ... + ... | -| XSS.java:41:36:41:56 | getPathInfo(...) [ : String] | XSS.java:41:36:41:67 | getBytes(...) | +| XSS.java:23:21:23:48 | getParameter(...) : String | XSS.java:23:5:23:70 | ... + ... | +| XSS.java:27:21:27:48 | getParameter(...) : String | XSS.java:27:5:27:70 | ... + ... | +| XSS.java:38:67:38:87 | getPathInfo(...) : String | XSS.java:38:30:38:87 | ... + ... | +| XSS.java:41:36:41:56 | getPathInfo(...) : String | XSS.java:41:36:41:67 | getBytes(...) | nodes | XSS.java:23:5:23:70 | ... + ... | semmle.label | ... + ... | -| XSS.java:23:21:23:48 | getParameter(...) [ : String] | semmle.label | getParameter(...) [ : String] | +| XSS.java:23:21:23:48 | getParameter(...) : String | semmle.label | getParameter(...) : String | | XSS.java:27:5:27:70 | ... + ... | semmle.label | ... + ... | -| XSS.java:27:21:27:48 | getParameter(...) [ : String] | semmle.label | getParameter(...) [ : String] | +| XSS.java:27:21:27:48 | getParameter(...) : String | semmle.label | getParameter(...) : String | | XSS.java:38:30:38:87 | ... + ... | semmle.label | ... + ... | -| XSS.java:38:67:38:87 | getPathInfo(...) [ : String] | semmle.label | getPathInfo(...) [ : String] | -| XSS.java:41:36:41:56 | getPathInfo(...) [ : String] | semmle.label | getPathInfo(...) [ : String] | +| XSS.java:38:67:38:87 | getPathInfo(...) : String | semmle.label | getPathInfo(...) : String | +| XSS.java:41:36:41:56 | getPathInfo(...) : String | semmle.label | getPathInfo(...) : String | | XSS.java:41:36:41:67 | getBytes(...) | semmle.label | getBytes(...) | #select -| XSS.java:23:5:23:70 | ... + ... | XSS.java:23:21:23:48 | getParameter(...) [ : String] | XSS.java:23:5:23:70 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:23:21:23:48 | getParameter(...) | user-provided value | -| XSS.java:27:5:27:70 | ... + ... | XSS.java:27:21:27:48 | getParameter(...) [ : String] | XSS.java:27:5:27:70 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:27:21:27:48 | getParameter(...) | user-provided value | -| XSS.java:38:30:38:87 | ... + ... | XSS.java:38:67:38:87 | getPathInfo(...) [ : String] | XSS.java:38:30:38:87 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:38:67:38:87 | getPathInfo(...) | user-provided value | -| XSS.java:41:36:41:67 | getBytes(...) | XSS.java:41:36:41:56 | getPathInfo(...) [ : String] | XSS.java:41:36:41:67 | getBytes(...) | Cross-site scripting vulnerability due to $@. | XSS.java:41:36:41:56 | getPathInfo(...) | user-provided value | +| XSS.java:23:5:23:70 | ... + ... | XSS.java:23:21:23:48 | getParameter(...) : String | XSS.java:23:5:23:70 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:23:21:23:48 | getParameter(...) | user-provided value | +| XSS.java:27:5:27:70 | ... + ... | XSS.java:27:21:27:48 | getParameter(...) : String | XSS.java:27:5:27:70 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:27:21:27:48 | getParameter(...) | user-provided value | +| XSS.java:38:30:38:87 | ... + ... | XSS.java:38:67:38:87 | getPathInfo(...) : String | XSS.java:38:30:38:87 | ... + ... | Cross-site scripting vulnerability due to $@. | XSS.java:38:67:38:87 | getPathInfo(...) | user-provided value | +| XSS.java:41:36:41:67 | getBytes(...) | XSS.java:41:36:41:56 | getPathInfo(...) : String | XSS.java:41:36:41:67 | getBytes(...) | Cross-site scripting vulnerability due to $@. | XSS.java:41:36:41:56 | getPathInfo(...) | user-provided value | diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected index 3340935c3b2..b85657f771d 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected @@ -1,33 +1,33 @@ edges -| Test.java:29:30:29:42 | args [ : String[]] | Test.java:36:47:36:52 | query1 | -| Test.java:29:30:29:42 | args [ : String[]] | Test.java:42:57:42:62 | query2 | -| Test.java:29:30:29:42 | args [ : String[]] | Test.java:50:62:50:67 | query3 | -| Test.java:29:30:29:42 | args [ : String[]] | Test.java:62:47:62:61 | querySbToString | -| Test.java:29:30:29:42 | args [ : String[]] | Test.java:70:40:70:44 | query | -| Test.java:29:30:29:42 | args [ : String[]] | Test.java:78:46:78:50 | query | -| Test.java:183:33:183:45 | args [ : String[]] | Test.java:209:47:209:68 | queryWithUserTableName | -| Test.java:213:26:213:38 | args [ : String[]] | Test.java:214:11:214:14 | args [ : String[]] | -| Test.java:213:26:213:38 | args [ : String[]] | Test.java:218:14:218:17 | args [ : String[]] | -| Test.java:214:11:214:14 | args [ : String[]] | Test.java:29:30:29:42 | args [ : String[]] | -| Test.java:218:14:218:17 | args [ : String[]] | Test.java:183:33:183:45 | args [ : String[]] | +| Test.java:29:30:29:42 | args : String[] | Test.java:36:47:36:52 | query1 | +| Test.java:29:30:29:42 | args : String[] | Test.java:42:57:42:62 | query2 | +| Test.java:29:30:29:42 | args : String[] | Test.java:50:62:50:67 | query3 | +| Test.java:29:30:29:42 | args : String[] | Test.java:62:47:62:61 | querySbToString | +| Test.java:29:30:29:42 | args : String[] | Test.java:70:40:70:44 | query | +| Test.java:29:30:29:42 | args : String[] | Test.java:78:46:78:50 | query | +| Test.java:183:33:183:45 | args : String[] | Test.java:209:47:209:68 | queryWithUserTableName | +| Test.java:213:26:213:38 | args : String[] | Test.java:214:11:214:14 | args : String[] | +| Test.java:213:26:213:38 | args : String[] | Test.java:218:14:218:17 | args : String[] | +| Test.java:214:11:214:14 | args : String[] | Test.java:29:30:29:42 | args : String[] | +| Test.java:218:14:218:17 | args : String[] | Test.java:183:33:183:45 | args : String[] | nodes -| Test.java:29:30:29:42 | args [ : String[]] | semmle.label | args [ : String[]] | +| Test.java:29:30:29:42 | args : String[] | semmle.label | args : String[] | | Test.java:36:47:36:52 | query1 | semmle.label | query1 | | Test.java:42:57:42:62 | query2 | semmle.label | query2 | | Test.java:50:62:50:67 | query3 | semmle.label | query3 | | Test.java:62:47:62:61 | querySbToString | semmle.label | querySbToString | | Test.java:70:40:70:44 | query | semmle.label | query | | Test.java:78:46:78:50 | query | semmle.label | query | -| Test.java:183:33:183:45 | args [ : String[]] | semmle.label | args [ : String[]] | +| Test.java:183:33:183:45 | args : String[] | semmle.label | args : String[] | | Test.java:209:47:209:68 | queryWithUserTableName | semmle.label | queryWithUserTableName | -| Test.java:213:26:213:38 | args [ : String[]] | semmle.label | args [ : String[]] | -| Test.java:214:11:214:14 | args [ : String[]] | semmle.label | args [ : String[]] | -| Test.java:218:14:218:17 | args [ : String[]] | semmle.label | args [ : String[]] | +| Test.java:213:26:213:38 | args : String[] | semmle.label | args : String[] | +| Test.java:214:11:214:14 | args : String[] | semmle.label | args : String[] | +| Test.java:218:14:218:17 | args : String[] | semmle.label | args : String[] | #select -| Test.java:36:47:36:52 | query1 | Test.java:213:26:213:38 | args [ : String[]] | Test.java:36:47:36:52 | query1 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | -| Test.java:42:57:42:62 | query2 | Test.java:213:26:213:38 | args [ : String[]] | Test.java:42:57:42:62 | query2 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | -| Test.java:50:62:50:67 | query3 | Test.java:213:26:213:38 | args [ : String[]] | Test.java:50:62:50:67 | query3 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | -| Test.java:62:47:62:61 | querySbToString | Test.java:213:26:213:38 | args [ : String[]] | Test.java:62:47:62:61 | querySbToString | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | -| Test.java:70:40:70:44 | query | Test.java:213:26:213:38 | args [ : String[]] | Test.java:70:40:70:44 | query | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | -| Test.java:78:46:78:50 | query | Test.java:213:26:213:38 | args [ : String[]] | Test.java:78:46:78:50 | query | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | -| Test.java:209:47:209:68 | queryWithUserTableName | Test.java:213:26:213:38 | args [ : String[]] | Test.java:209:47:209:68 | queryWithUserTableName | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | +| Test.java:36:47:36:52 | query1 | Test.java:213:26:213:38 | args : String[] | Test.java:36:47:36:52 | query1 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | +| Test.java:42:57:42:62 | query2 | Test.java:213:26:213:38 | args : String[] | Test.java:42:57:42:62 | query2 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | +| Test.java:50:62:50:67 | query3 | Test.java:213:26:213:38 | args : String[] | Test.java:50:62:50:67 | query3 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | +| Test.java:62:47:62:61 | querySbToString | Test.java:213:26:213:38 | args : String[] | Test.java:62:47:62:61 | querySbToString | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | +| Test.java:70:40:70:44 | query | Test.java:213:26:213:38 | args : String[] | Test.java:70:40:70:44 | query | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | +| Test.java:78:46:78:50 | query | Test.java:213:26:213:38 | args : String[] | Test.java:78:46:78:50 | query | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | +| Test.java:209:47:209:68 | queryWithUserTableName | Test.java:213:26:213:38 | args : String[] | Test.java:209:47:209:68 | queryWithUserTableName | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | diff --git a/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.expected b/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.expected index 92817b9b14c..4a1a172bbf5 100644 --- a/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.expected +++ b/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.expected @@ -1,11 +1,11 @@ edges -| ResponseSplitting.java:22:39:22:66 | getParameter(...) [ : String] | ResponseSplitting.java:23:23:23:28 | cookie | +| ResponseSplitting.java:22:39:22:66 | getParameter(...) : String | ResponseSplitting.java:23:23:23:28 | cookie | nodes -| ResponseSplitting.java:22:39:22:66 | getParameter(...) [ : String] | semmle.label | getParameter(...) [ : String] | +| ResponseSplitting.java:22:39:22:66 | getParameter(...) : String | semmle.label | getParameter(...) : String | | ResponseSplitting.java:23:23:23:28 | cookie | semmle.label | cookie | | ResponseSplitting.java:28:38:28:72 | getParameter(...) | semmle.label | getParameter(...) | | ResponseSplitting.java:29:38:29:72 | getParameter(...) | semmle.label | getParameter(...) | #select -| ResponseSplitting.java:23:23:23:28 | cookie | ResponseSplitting.java:22:39:22:66 | getParameter(...) [ : String] | ResponseSplitting.java:23:23:23:28 | cookie | Response-splitting vulnerability due to this $@. | ResponseSplitting.java:22:39:22:66 | getParameter(...) | user-provided value | +| ResponseSplitting.java:23:23:23:28 | cookie | ResponseSplitting.java:22:39:22:66 | getParameter(...) : String | ResponseSplitting.java:23:23:23:28 | cookie | Response-splitting vulnerability due to this $@. | ResponseSplitting.java:22:39:22:66 | getParameter(...) | user-provided value | | ResponseSplitting.java:28:38:28:72 | getParameter(...) | ResponseSplitting.java:28:38:28:72 | getParameter(...) | ResponseSplitting.java:28:38:28:72 | getParameter(...) | Response-splitting vulnerability due to this $@. | ResponseSplitting.java:28:38:28:72 | getParameter(...) | user-provided value | | ResponseSplitting.java:29:38:29:72 | getParameter(...) | ResponseSplitting.java:29:38:29:72 | getParameter(...) | ResponseSplitting.java:29:38:29:72 | getParameter(...) | Response-splitting vulnerability due to this $@. | ResponseSplitting.java:29:38:29:72 | getParameter(...) | user-provided value | diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.expected b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.expected index 99c3b3d1528..78ae96824b3 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.expected +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.expected @@ -1,7 +1,7 @@ edges -| Test.java:86:16:86:16 | 0 [ : Number] | Test.java:88:27:88:30 | size | +| Test.java:86:16:86:16 | 0 : Number | Test.java:88:27:88:30 | size | nodes -| Test.java:86:16:86:16 | 0 [ : Number] | semmle.label | 0 [ : Number] | +| Test.java:86:16:86:16 | 0 : Number | semmle.label | 0 : Number | | Test.java:88:27:88:30 | size | semmle.label | size | #select -| Test.java:91:30:91:30 | 0 | Test.java:86:16:86:16 | 0 [ : Number] | Test.java:88:27:88:30 | size | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:88:19:88:31 | new int[] | array | Test.java:86:16:86:16 | 0 | literal value 0 | +| Test.java:91:30:91:30 | 0 | Test.java:86:16:86:16 | 0 : Number | Test.java:88:27:88:30 | size | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:88:19:88:31 | new int[] | array | Test.java:86:16:86:16 | 0 | literal value 0 | diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected index 1a9fc7390b1..9cc0144a320 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected @@ -1,10 +1,10 @@ edges -| Test.java:57:27:57:60 | getProperty(...) [ : String] | Test.java:61:31:61:34 | size | -| Test.java:57:27:57:60 | getProperty(...) [ : String] | Test.java:67:34:67:37 | size | +| Test.java:57:27:57:60 | getProperty(...) : String | Test.java:61:31:61:34 | size | +| Test.java:57:27:57:60 | getProperty(...) : String | Test.java:67:34:67:37 | size | nodes -| Test.java:57:27:57:60 | getProperty(...) [ : String] | semmle.label | getProperty(...) [ : String] | +| Test.java:57:27:57:60 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:61:31:61:34 | size | semmle.label | size | | Test.java:67:34:67:37 | size | semmle.label | size | #select -| Test.java:64:34:64:34 | 0 | Test.java:57:27:57:60 | getProperty(...) [ : String] | Test.java:61:31:61:34 | size | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:61:23:61:35 | new int[] | array | Test.java:57:27:57:60 | getProperty(...) | User-provided value | -| Test.java:70:37:70:37 | 0 | Test.java:57:27:57:60 | getProperty(...) [ : String] | Test.java:67:34:67:37 | size | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:67:26:67:38 | new int[] | array | Test.java:57:27:57:60 | getProperty(...) | User-provided value | +| Test.java:64:34:64:34 | 0 | Test.java:57:27:57:60 | getProperty(...) : String | Test.java:61:31:61:34 | size | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:61:23:61:35 | new int[] | array | Test.java:57:27:57:60 | getProperty(...) | User-provided value | +| Test.java:70:37:70:37 | 0 | Test.java:57:27:57:60 | getProperty(...) : String | Test.java:67:34:67:37 | size | The $@ is accessed here, but the array is initialized using $@ which may be zero. | Test.java:67:26:67:38 | new int[] | array | Test.java:57:27:57:60 | getProperty(...) | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.expected b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.expected index 110a767a459..e9c41cf77d3 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.expected +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.expected @@ -1,10 +1,10 @@ edges -| Test.java:40:17:40:48 | nextInt(...) [ : Number] | Test.java:43:30:43:34 | index | -| Test.java:40:17:40:48 | nextInt(...) [ : Number] | Test.java:47:32:47:36 | index | -| Test.java:40:17:40:48 | nextInt(...) [ : Number] | Test.java:51:39:51:43 | index | -| Test.java:93:17:93:17 | 0 [ : Number] | Test.java:96:32:96:36 | index | +| Test.java:40:17:40:48 | nextInt(...) : Number | Test.java:43:30:43:34 | index | +| Test.java:40:17:40:48 | nextInt(...) : Number | Test.java:47:32:47:36 | index | +| Test.java:40:17:40:48 | nextInt(...) : Number | Test.java:51:39:51:43 | index | +| Test.java:93:17:93:17 | 0 : Number | Test.java:96:32:96:36 | index | nodes -| Test.java:40:17:40:48 | nextInt(...) [ : Number] | semmle.label | nextInt(...) [ : Number] | +| Test.java:40:17:40:48 | nextInt(...) : Number | semmle.label | nextInt(...) : Number | | Test.java:43:30:43:34 | index | semmle.label | index | | Test.java:47:32:47:36 | index | semmle.label | index | | Test.java:51:39:51:43 | index | semmle.label | index | @@ -12,8 +12,8 @@ nodes | Test.java:70:37:70:37 | 0 | semmle.label | 0 | | Test.java:77:39:77:39 | 0 | semmle.label | 0 | | Test.java:91:30:91:30 | 0 | semmle.label | 0 | -| Test.java:93:17:93:17 | 0 [ : Number] | semmle.label | 0 [ : Number] | +| Test.java:93:17:93:17 | 0 : Number | semmle.label | 0 : Number | | Test.java:96:32:96:36 | index | semmle.label | index | | Test.java:102:30:102:30 | 0 | semmle.label | 0 | #select -| Test.java:43:30:43:34 | index | Test.java:40:17:40:48 | nextInt(...) [ : Number] | Test.java:43:30:43:34 | index | $@ flows to the index used in this array access, and may cause the operation to throw an ArrayIndexOutOfBoundsException. | Test.java:40:17:40:48 | nextInt(...) | Random value | +| Test.java:43:30:43:34 | index | Test.java:40:17:40:48 | nextInt(...) : Number | Test.java:43:30:43:34 | index | $@ flows to the index used in this array access, and may cause the operation to throw an ArrayIndexOutOfBoundsException. | Test.java:40:17:40:48 | nextInt(...) | Random value | diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected index 94799d07900..38afae1e205 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected @@ -1,7 +1,7 @@ edges -| Test.java:13:27:13:60 | getProperty(...) [ : String] | Test.java:18:34:18:38 | index | +| Test.java:13:27:13:60 | getProperty(...) : String | Test.java:18:34:18:38 | index | nodes -| Test.java:13:27:13:60 | getProperty(...) [ : String] | semmle.label | getProperty(...) [ : String] | +| Test.java:13:27:13:60 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:18:34:18:38 | index | semmle.label | index | #select -| Test.java:18:34:18:38 | index | Test.java:13:27:13:60 | getProperty(...) [ : String] | Test.java:18:34:18:38 | index | $@ flows to here and is used as an index causing an ArrayIndexOutOfBoundsException. | Test.java:13:27:13:60 | getProperty(...) | User-provided value | +| Test.java:18:34:18:38 | index | Test.java:13:27:13:60 | getProperty(...) : String | Test.java:18:34:18:38 | index | $@ flows to here and is used as an index causing an ArrayIndexOutOfBoundsException. | Test.java:13:27:13:60 | getProperty(...) | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.expected b/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.expected index b8700944571..6c7afc63831 100644 --- a/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.expected +++ b/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.expected @@ -1,11 +1,11 @@ edges -| Test.java:33:30:33:74 | getParameter(...) [ : String] | Test.java:34:20:34:32 | userParameter [ : String] | -| Test.java:34:20:34:32 | userParameter [ : String] | Test.java:37:31:37:43 | format [ : String] | -| Test.java:37:31:37:43 | format [ : String] | Test.java:39:25:39:30 | format | +| Test.java:33:30:33:74 | getParameter(...) : String | Test.java:34:20:34:32 | userParameter : String | +| Test.java:34:20:34:32 | userParameter : String | Test.java:37:31:37:43 | format : String | +| Test.java:37:31:37:43 | format : String | Test.java:39:25:39:30 | format | nodes -| Test.java:33:30:33:74 | getParameter(...) [ : String] | semmle.label | getParameter(...) [ : String] | -| Test.java:34:20:34:32 | userParameter [ : String] | semmle.label | userParameter [ : String] | -| Test.java:37:31:37:43 | format [ : String] | semmle.label | format [ : String] | +| Test.java:33:30:33:74 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| Test.java:34:20:34:32 | userParameter : String | semmle.label | userParameter : String | +| Test.java:37:31:37:43 | format : String | semmle.label | format : String | | Test.java:39:25:39:30 | format | semmle.label | format | #select -| Test.java:39:25:39:30 | format | Test.java:33:30:33:74 | getParameter(...) [ : String] | Test.java:39:25:39:30 | format | $@ flows to here and is used in a format string. | Test.java:33:30:33:74 | getParameter(...) | User-provided value | +| Test.java:39:25:39:30 | format | Test.java:33:30:33:74 | getParameter(...) : String | Test.java:39:25:39:30 | format | $@ flows to here and is used in a format string. | Test.java:33:30:33:74 | getParameter(...) | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatStringLocal.expected b/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatStringLocal.expected index 3421543b81a..4d3ea1db5bc 100644 --- a/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatStringLocal.expected +++ b/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatStringLocal.expected @@ -1,19 +1,19 @@ edges -| Test.java:17:27:17:60 | getProperty(...) [ : String] | Test.java:19:19:19:30 | userProperty | -| Test.java:17:27:17:60 | getProperty(...) [ : String] | Test.java:21:23:21:34 | userProperty | -| Test.java:17:27:17:60 | getProperty(...) [ : String] | Test.java:23:23:23:34 | userProperty | -| Test.java:17:27:17:60 | getProperty(...) [ : String] | Test.java:25:28:25:39 | userProperty | -| Test.java:17:27:17:60 | getProperty(...) [ : String] | Test.java:27:44:27:55 | userProperty | +| Test.java:17:27:17:60 | getProperty(...) : String | Test.java:19:19:19:30 | userProperty | +| Test.java:17:27:17:60 | getProperty(...) : String | Test.java:21:23:21:34 | userProperty | +| Test.java:17:27:17:60 | getProperty(...) : String | Test.java:23:23:23:34 | userProperty | +| Test.java:17:27:17:60 | getProperty(...) : String | Test.java:25:28:25:39 | userProperty | +| Test.java:17:27:17:60 | getProperty(...) : String | Test.java:27:44:27:55 | userProperty | nodes -| Test.java:17:27:17:60 | getProperty(...) [ : String] | semmle.label | getProperty(...) [ : String] | +| Test.java:17:27:17:60 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:19:19:19:30 | userProperty | semmle.label | userProperty | | Test.java:21:23:21:34 | userProperty | semmle.label | userProperty | | Test.java:23:23:23:34 | userProperty | semmle.label | userProperty | | Test.java:25:28:25:39 | userProperty | semmle.label | userProperty | | Test.java:27:44:27:55 | userProperty | semmle.label | userProperty | #select -| Test.java:19:19:19:30 | userProperty | Test.java:17:27:17:60 | getProperty(...) [ : String] | Test.java:19:19:19:30 | userProperty | $@ flows to here and is used in a format string. | Test.java:17:27:17:60 | getProperty(...) | User-provided value | -| Test.java:21:23:21:34 | userProperty | Test.java:17:27:17:60 | getProperty(...) [ : String] | Test.java:21:23:21:34 | userProperty | $@ flows to here and is used in a format string. | Test.java:17:27:17:60 | getProperty(...) | User-provided value | -| Test.java:23:23:23:34 | userProperty | Test.java:17:27:17:60 | getProperty(...) [ : String] | Test.java:23:23:23:34 | userProperty | $@ flows to here and is used in a format string. | Test.java:17:27:17:60 | getProperty(...) | User-provided value | -| Test.java:25:28:25:39 | userProperty | Test.java:17:27:17:60 | getProperty(...) [ : String] | Test.java:25:28:25:39 | userProperty | $@ flows to here and is used in a format string. | Test.java:17:27:17:60 | getProperty(...) | User-provided value | -| Test.java:27:44:27:55 | userProperty | Test.java:17:27:17:60 | getProperty(...) [ : String] | Test.java:27:44:27:55 | userProperty | $@ flows to here and is used in a format string. | Test.java:17:27:17:60 | getProperty(...) | User-provided value | +| Test.java:19:19:19:30 | userProperty | Test.java:17:27:17:60 | getProperty(...) : String | Test.java:19:19:19:30 | userProperty | $@ flows to here and is used in a format string. | Test.java:17:27:17:60 | getProperty(...) | User-provided value | +| Test.java:21:23:21:34 | userProperty | Test.java:17:27:17:60 | getProperty(...) : String | Test.java:21:23:21:34 | userProperty | $@ flows to here and is used in a format string. | Test.java:17:27:17:60 | getProperty(...) | User-provided value | +| Test.java:23:23:23:34 | userProperty | Test.java:17:27:17:60 | getProperty(...) : String | Test.java:23:23:23:34 | userProperty | $@ flows to here and is used in a format string. | Test.java:17:27:17:60 | getProperty(...) | User-provided value | +| Test.java:25:28:25:39 | userProperty | Test.java:17:27:17:60 | getProperty(...) : String | Test.java:25:28:25:39 | userProperty | $@ flows to here and is used in a format string. | Test.java:17:27:17:60 | getProperty(...) | User-provided value | +| Test.java:27:44:27:55 | userProperty | Test.java:17:27:17:60 | getProperty(...) : String | Test.java:27:44:27:55 | userProperty | $@ flows to here and is used in a format string. | Test.java:17:27:17:60 | getProperty(...) | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected index 08e8cc7c071..178de2e3dcd 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected @@ -1,56 +1,56 @@ edges -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:32:17:32:20 | data | -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:40:17:40:20 | data | -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:50:17:50:20 | data | -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:64:20:64:23 | data [ : Number] | -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:95:37:95:40 | data | -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:118:9:118:12 | data [ : Number] | -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:119:10:119:13 | data [ : Number] | -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:120:10:120:13 | data [ : Number] | -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:121:10:121:13 | data [ : Number] | -| ArithmeticTainted.java:64:4:64:10 | tainted [post update] [dat : Number] | ArithmeticTainted.java:66:18:66:24 | tainted [dat : Number] | -| ArithmeticTainted.java:64:20:64:23 | data [ : Number] | ArithmeticTainted.java:64:4:64:10 | tainted [post update] [dat : Number] | -| ArithmeticTainted.java:66:18:66:24 | tainted [dat : Number] | ArithmeticTainted.java:66:18:66:34 | getData(...) [ : Number] | -| ArithmeticTainted.java:66:18:66:34 | getData(...) [ : Number] | ArithmeticTainted.java:71:17:71:23 | herring | -| ArithmeticTainted.java:118:9:118:12 | data [ : Number] | ArithmeticTainted.java:125:26:125:33 | data [ : Number] | -| ArithmeticTainted.java:119:10:119:13 | data [ : Number] | ArithmeticTainted.java:129:27:129:34 | data [ : Number] | -| ArithmeticTainted.java:120:10:120:13 | data [ : Number] | ArithmeticTainted.java:133:27:133:34 | data [ : Number] | -| ArithmeticTainted.java:121:10:121:13 | data [ : Number] | ArithmeticTainted.java:137:27:137:34 | data [ : Number] | -| ArithmeticTainted.java:125:26:125:33 | data [ : Number] | ArithmeticTainted.java:127:3:127:6 | data | -| ArithmeticTainted.java:129:27:129:34 | data [ : Number] | ArithmeticTainted.java:131:5:131:8 | data | -| ArithmeticTainted.java:133:27:133:34 | data [ : Number] | ArithmeticTainted.java:135:3:135:6 | data | -| ArithmeticTainted.java:137:27:137:34 | data [ : Number] | ArithmeticTainted.java:139:5:139:8 | data | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:32:17:32:20 | data | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:40:17:40:20 | data | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:50:17:50:20 | data | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:64:20:64:23 | data : Number | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:95:37:95:40 | data | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:118:9:118:12 | data : Number | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:119:10:119:13 | data : Number | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:120:10:120:13 | data : Number | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:121:10:121:13 | data : Number | +| ArithmeticTainted.java:64:4:64:10 | tainted [post update] [dat] : Number | ArithmeticTainted.java:66:18:66:24 | tainted [dat] : Number | +| ArithmeticTainted.java:64:20:64:23 | data : Number | ArithmeticTainted.java:64:4:64:10 | tainted [post update] [dat] : Number | +| ArithmeticTainted.java:66:18:66:24 | tainted [dat] : Number | ArithmeticTainted.java:66:18:66:34 | getData(...) : Number | +| ArithmeticTainted.java:66:18:66:34 | getData(...) : Number | ArithmeticTainted.java:71:17:71:23 | herring | +| ArithmeticTainted.java:118:9:118:12 | data : Number | ArithmeticTainted.java:125:26:125:33 | data : Number | +| ArithmeticTainted.java:119:10:119:13 | data : Number | ArithmeticTainted.java:129:27:129:34 | data : Number | +| ArithmeticTainted.java:120:10:120:13 | data : Number | ArithmeticTainted.java:133:27:133:34 | data : Number | +| ArithmeticTainted.java:121:10:121:13 | data : Number | ArithmeticTainted.java:137:27:137:34 | data : Number | +| ArithmeticTainted.java:125:26:125:33 | data : Number | ArithmeticTainted.java:127:3:127:6 | data | +| ArithmeticTainted.java:129:27:129:34 | data : Number | ArithmeticTainted.java:131:5:131:8 | data | +| ArithmeticTainted.java:133:27:133:34 | data : Number | ArithmeticTainted.java:135:3:135:6 | data | +| ArithmeticTainted.java:137:27:137:34 | data : Number | ArithmeticTainted.java:139:5:139:8 | data | nodes -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | semmle.label | System.in [ : InputStream] | -| ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | semmle.label | System.in [ : InputStream] | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | semmle.label | System.in : InputStream | +| ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | semmle.label | System.in : InputStream | | ArithmeticTainted.java:32:17:32:20 | data | semmle.label | data | | ArithmeticTainted.java:40:17:40:20 | data | semmle.label | data | | ArithmeticTainted.java:50:17:50:20 | data | semmle.label | data | -| ArithmeticTainted.java:64:4:64:10 | tainted [post update] [dat : Number] | semmle.label | tainted [post update] [dat : Number] | -| ArithmeticTainted.java:64:20:64:23 | data [ : Number] | semmle.label | data [ : Number] | -| ArithmeticTainted.java:66:18:66:24 | tainted [dat : Number] | semmle.label | tainted [dat : Number] | -| ArithmeticTainted.java:66:18:66:34 | getData(...) [ : Number] | semmle.label | getData(...) [ : Number] | +| ArithmeticTainted.java:64:4:64:10 | tainted [post update] [dat] : Number | semmle.label | tainted [post update] [dat] : Number | +| ArithmeticTainted.java:64:20:64:23 | data : Number | semmle.label | data : Number | +| ArithmeticTainted.java:66:18:66:24 | tainted [dat] : Number | semmle.label | tainted [dat] : Number | +| ArithmeticTainted.java:66:18:66:34 | getData(...) : Number | semmle.label | getData(...) : Number | | ArithmeticTainted.java:71:17:71:23 | herring | semmle.label | herring | | ArithmeticTainted.java:95:37:95:40 | data | semmle.label | data | -| ArithmeticTainted.java:118:9:118:12 | data [ : Number] | semmle.label | data [ : Number] | -| ArithmeticTainted.java:119:10:119:13 | data [ : Number] | semmle.label | data [ : Number] | -| ArithmeticTainted.java:120:10:120:13 | data [ : Number] | semmle.label | data [ : Number] | -| ArithmeticTainted.java:121:10:121:13 | data [ : Number] | semmle.label | data [ : Number] | -| ArithmeticTainted.java:125:26:125:33 | data [ : Number] | semmle.label | data [ : Number] | +| ArithmeticTainted.java:118:9:118:12 | data : Number | semmle.label | data : Number | +| ArithmeticTainted.java:119:10:119:13 | data : Number | semmle.label | data : Number | +| ArithmeticTainted.java:120:10:120:13 | data : Number | semmle.label | data : Number | +| ArithmeticTainted.java:121:10:121:13 | data : Number | semmle.label | data : Number | +| ArithmeticTainted.java:125:26:125:33 | data : Number | semmle.label | data : Number | | ArithmeticTainted.java:127:3:127:6 | data | semmle.label | data | -| ArithmeticTainted.java:129:27:129:34 | data [ : Number] | semmle.label | data [ : Number] | +| ArithmeticTainted.java:129:27:129:34 | data : Number | semmle.label | data : Number | | ArithmeticTainted.java:131:5:131:8 | data | semmle.label | data | -| ArithmeticTainted.java:133:27:133:34 | data [ : Number] | semmle.label | data [ : Number] | +| ArithmeticTainted.java:133:27:133:34 | data : Number | semmle.label | data : Number | | ArithmeticTainted.java:135:3:135:6 | data | semmle.label | data | -| ArithmeticTainted.java:137:27:137:34 | data [ : Number] | semmle.label | data [ : Number] | +| ArithmeticTainted.java:137:27:137:34 | data : Number | semmle.label | data : Number | | ArithmeticTainted.java:139:5:139:8 | data | semmle.label | data | #select -| ArithmeticTainted.java:32:17:32:25 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:32:17:32:20 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:40:17:40:25 | ... - ... | ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:40:17:40:20 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:50:17:50:24 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:50:17:50:20 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:71:17:71:27 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:71:17:71:23 | herring | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:95:37:95:46 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:95:37:95:40 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:127:3:127:8 | ...++ | ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:127:3:127:6 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:131:3:131:8 | ++... | ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:131:5:131:8 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:135:3:135:8 | ...-- | ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:135:3:135:6 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | -| ArithmeticTainted.java:139:3:139:8 | --... | ArithmeticTainted.java:17:46:17:54 | System.in [ : InputStream] | ArithmeticTainted.java:139:5:139:8 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:32:17:32:25 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:32:17:32:20 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:40:17:40:25 | ... - ... | ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:40:17:40:20 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:50:17:50:24 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:50:17:50:20 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:71:17:71:27 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:71:17:71:23 | herring | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:95:37:95:46 | ... + ... | ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:95:37:95:40 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:127:3:127:8 | ...++ | ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:127:3:127:6 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:131:3:131:8 | ++... | ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:131:5:131:8 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:135:3:135:8 | ...-- | ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:135:3:135:6 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | +| ArithmeticTainted.java:139:3:139:8 | --... | ArithmeticTainted.java:17:46:17:54 | System.in : InputStream | ArithmeticTainted.java:139:5:139:8 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | ArithmeticTainted.java:17:46:17:54 | System.in | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.expected b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.expected index 810c3b3c93f..c078a5e72d6 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.expected +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.expected @@ -1,10 +1,10 @@ edges -| Test.java:205:14:205:57 | nextInt(...) [ : Number] | Test.java:209:17:209:20 | data | -| Test.java:205:14:205:57 | nextInt(...) [ : Number] | Test.java:240:37:240:40 | data | +| Test.java:205:14:205:57 | nextInt(...) : Number | Test.java:209:17:209:20 | data | +| Test.java:205:14:205:57 | nextInt(...) : Number | Test.java:240:37:240:40 | data | nodes -| Test.java:205:14:205:57 | nextInt(...) [ : Number] | semmle.label | nextInt(...) [ : Number] | +| Test.java:205:14:205:57 | nextInt(...) : Number | semmle.label | nextInt(...) : Number | | Test.java:209:17:209:20 | data | semmle.label | data | | Test.java:240:37:240:40 | data | semmle.label | data | #select -| Test.java:209:17:209:24 | ... + ... | Test.java:205:14:205:57 | nextInt(...) [ : Number] | Test.java:209:17:209:20 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | Test.java:205:14:205:57 | nextInt(...) | Uncontrolled value | -| Test.java:240:37:240:46 | ... + ... | Test.java:205:14:205:57 | nextInt(...) [ : Number] | Test.java:240:37:240:40 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | Test.java:205:14:205:57 | nextInt(...) | Uncontrolled value | +| Test.java:209:17:209:24 | ... + ... | Test.java:205:14:205:57 | nextInt(...) : Number | Test.java:209:17:209:20 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | Test.java:205:14:205:57 | nextInt(...) | Uncontrolled value | +| Test.java:240:37:240:46 | ... + ... | Test.java:205:14:205:57 | nextInt(...) : Number | Test.java:240:37:240:40 | data | $@ flows to here and is used in arithmetic, potentially causing an overflow. | Test.java:205:14:205:57 | nextInt(...) | Uncontrolled value | diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.expected b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.expected index 02afa7970da..6dd3ddb4c0a 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.expected +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.expected @@ -1,31 +1,31 @@ edges -| Test.java:92:8:92:24 | Integer.MAX_VALUE [ : Number] | Test.java:95:8:95:8 | i | -| Test.java:108:13:108:26 | Long.MIN_VALUE [ : Number] | Test.java:110:13:110:13 | i | -| Test.java:137:9:137:25 | Integer.MAX_VALUE [ : Number] | Test.java:138:14:138:14 | i | -| Test.java:143:12:143:28 | Integer.MAX_VALUE [ : Number] | Test.java:146:14:146:14 | i | -| Test.java:184:13:184:26 | Byte.MAX_VALUE [ : Number] | Test.java:187:39:187:39 | b | -| Test.java:191:14:191:28 | Short.MAX_VALUE [ : Number] | Test.java:194:41:194:41 | s | -| Test.java:198:12:198:28 | Integer.MAX_VALUE [ : Number] | Test.java:201:37:201:37 | i | +| Test.java:92:8:92:24 | Integer.MAX_VALUE : Number | Test.java:95:8:95:8 | i | +| Test.java:108:13:108:26 | Long.MIN_VALUE : Number | Test.java:110:13:110:13 | i | +| Test.java:137:9:137:25 | Integer.MAX_VALUE : Number | Test.java:138:14:138:14 | i | +| Test.java:143:12:143:28 | Integer.MAX_VALUE : Number | Test.java:146:14:146:14 | i | +| Test.java:184:13:184:26 | Byte.MAX_VALUE : Number | Test.java:187:39:187:39 | b | +| Test.java:191:14:191:28 | Short.MAX_VALUE : Number | Test.java:194:41:194:41 | s | +| Test.java:198:12:198:28 | Integer.MAX_VALUE : Number | Test.java:201:37:201:37 | i | nodes -| Test.java:92:8:92:24 | Integer.MAX_VALUE [ : Number] | semmle.label | Integer.MAX_VALUE [ : Number] | +| Test.java:92:8:92:24 | Integer.MAX_VALUE : Number | semmle.label | Integer.MAX_VALUE : Number | | Test.java:95:8:95:8 | i | semmle.label | i | -| Test.java:108:13:108:26 | Long.MIN_VALUE [ : Number] | semmle.label | Long.MIN_VALUE [ : Number] | +| Test.java:108:13:108:26 | Long.MIN_VALUE : Number | semmle.label | Long.MIN_VALUE : Number | | Test.java:110:13:110:13 | i | semmle.label | i | -| Test.java:137:9:137:25 | Integer.MAX_VALUE [ : Number] | semmle.label | Integer.MAX_VALUE [ : Number] | +| Test.java:137:9:137:25 | Integer.MAX_VALUE : Number | semmle.label | Integer.MAX_VALUE : Number | | Test.java:138:14:138:14 | i | semmle.label | i | -| Test.java:143:12:143:28 | Integer.MAX_VALUE [ : Number] | semmle.label | Integer.MAX_VALUE [ : Number] | +| Test.java:143:12:143:28 | Integer.MAX_VALUE : Number | semmle.label | Integer.MAX_VALUE : Number | | Test.java:146:14:146:14 | i | semmle.label | i | -| Test.java:184:13:184:26 | Byte.MAX_VALUE [ : Number] | semmle.label | Byte.MAX_VALUE [ : Number] | +| Test.java:184:13:184:26 | Byte.MAX_VALUE : Number | semmle.label | Byte.MAX_VALUE : Number | | Test.java:187:39:187:39 | b | semmle.label | b | -| Test.java:191:14:191:28 | Short.MAX_VALUE [ : Number] | semmle.label | Short.MAX_VALUE [ : Number] | +| Test.java:191:14:191:28 | Short.MAX_VALUE : Number | semmle.label | Short.MAX_VALUE : Number | | Test.java:194:41:194:41 | s | semmle.label | s | -| Test.java:198:12:198:28 | Integer.MAX_VALUE [ : Number] | semmle.label | Integer.MAX_VALUE [ : Number] | +| Test.java:198:12:198:28 | Integer.MAX_VALUE : Number | semmle.label | Integer.MAX_VALUE : Number | | Test.java:201:37:201:37 | i | semmle.label | i | #select -| Test.java:95:8:95:12 | ... + ... | Test.java:92:8:92:24 | Integer.MAX_VALUE [ : Number] | Test.java:95:8:95:8 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:92:8:92:24 | Integer.MAX_VALUE | MAX_VALUE | -| Test.java:110:13:110:17 | ... - ... | Test.java:108:13:108:26 | Long.MIN_VALUE [ : Number] | Test.java:110:13:110:13 | i | Variable i is assigned an extreme value $@, and may cause an underflow. | Test.java:108:13:108:26 | Long.MIN_VALUE | MIN_VALUE | -| Test.java:138:14:138:18 | ... + ... | Test.java:137:9:137:25 | Integer.MAX_VALUE [ : Number] | Test.java:138:14:138:14 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:137:9:137:25 | Integer.MAX_VALUE | MAX_VALUE | -| Test.java:146:14:146:18 | ... + ... | Test.java:143:12:143:28 | Integer.MAX_VALUE [ : Number] | Test.java:146:14:146:14 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:143:12:143:28 | Integer.MAX_VALUE | MAX_VALUE | -| Test.java:187:39:187:43 | ... + ... | Test.java:184:13:184:26 | Byte.MAX_VALUE [ : Number] | Test.java:187:39:187:39 | b | Variable b is assigned an extreme value $@, and may cause an overflow. | Test.java:184:13:184:26 | Byte.MAX_VALUE | MAX_VALUE | -| Test.java:194:41:194:45 | ... + ... | Test.java:191:14:191:28 | Short.MAX_VALUE [ : Number] | Test.java:194:41:194:41 | s | Variable s is assigned an extreme value $@, and may cause an overflow. | Test.java:191:14:191:28 | Short.MAX_VALUE | MAX_VALUE | -| Test.java:201:37:201:42 | ... + ... | Test.java:198:12:198:28 | Integer.MAX_VALUE [ : Number] | Test.java:201:37:201:37 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:198:12:198:28 | Integer.MAX_VALUE | MAX_VALUE | +| Test.java:95:8:95:12 | ... + ... | Test.java:92:8:92:24 | Integer.MAX_VALUE : Number | Test.java:95:8:95:8 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:92:8:92:24 | Integer.MAX_VALUE | MAX_VALUE | +| Test.java:110:13:110:17 | ... - ... | Test.java:108:13:108:26 | Long.MIN_VALUE : Number | Test.java:110:13:110:13 | i | Variable i is assigned an extreme value $@, and may cause an underflow. | Test.java:108:13:108:26 | Long.MIN_VALUE | MIN_VALUE | +| Test.java:138:14:138:18 | ... + ... | Test.java:137:9:137:25 | Integer.MAX_VALUE : Number | Test.java:138:14:138:14 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:137:9:137:25 | Integer.MAX_VALUE | MAX_VALUE | +| Test.java:146:14:146:18 | ... + ... | Test.java:143:12:143:28 | Integer.MAX_VALUE : Number | Test.java:146:14:146:14 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:143:12:143:28 | Integer.MAX_VALUE | MAX_VALUE | +| Test.java:187:39:187:43 | ... + ... | Test.java:184:13:184:26 | Byte.MAX_VALUE : Number | Test.java:187:39:187:39 | b | Variable b is assigned an extreme value $@, and may cause an overflow. | Test.java:184:13:184:26 | Byte.MAX_VALUE | MAX_VALUE | +| Test.java:194:41:194:45 | ... + ... | Test.java:191:14:191:28 | Short.MAX_VALUE : Number | Test.java:194:41:194:41 | s | Variable s is assigned an extreme value $@, and may cause an overflow. | Test.java:191:14:191:28 | Short.MAX_VALUE | MAX_VALUE | +| Test.java:201:37:201:42 | ... + ... | Test.java:198:12:198:28 | Integer.MAX_VALUE : Number | Test.java:201:37:201:37 | i | Variable i is assigned an extreme value $@, and may cause an overflow. | Test.java:198:12:198:28 | Integer.MAX_VALUE | MAX_VALUE | diff --git a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected index d10b37e3842..ee8e237cda1 100644 --- a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected +++ b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected @@ -1,65 +1,65 @@ edges -| A.java:13:31:13:51 | getInputStream(...) [ : InputStream] | A.java:15:12:15:13 | in | -| A.java:19:31:19:51 | getInputStream(...) [ : InputStream] | A.java:21:12:21:13 | in | -| A.java:25:31:25:51 | getInputStream(...) [ : InputStream] | A.java:27:12:27:12 | d | -| A.java:32:31:32:51 | getInputStream(...) [ : InputStream] | A.java:34:23:34:28 | reader | -| A.java:39:29:39:49 | getInputStream(...) [ : InputStream] | A.java:40:28:40:32 | input | -| A.java:39:29:39:49 | getInputStream(...) [ : InputStream] | A.java:41:34:41:38 | input | -| A.java:39:29:39:49 | getInputStream(...) [ : InputStream] | A.java:42:40:42:44 | input | -| A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | A.java:61:26:61:30 | input | -| A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | A.java:62:30:62:34 | input | -| A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | A.java:63:28:63:55 | new InputStreamReader(...) | -| A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | A.java:64:24:64:28 | input | -| A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | A.java:65:24:65:51 | new InputStreamReader(...) | -| A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | A.java:71:26:71:30 | input | -| A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | A.java:72:30:72:34 | input | -| A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | A.java:73:28:73:55 | new InputStreamReader(...) | -| A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | A.java:74:24:74:28 | input | -| A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | A.java:75:24:75:51 | new InputStreamReader(...) | -| TestMessageBodyReader.java:20:55:20:78 | entityStream [ : InputStream] | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | +| A.java:13:31:13:51 | getInputStream(...) : InputStream | A.java:15:12:15:13 | in | +| A.java:19:31:19:51 | getInputStream(...) : InputStream | A.java:21:12:21:13 | in | +| A.java:25:31:25:51 | getInputStream(...) : InputStream | A.java:27:12:27:12 | d | +| A.java:32:31:32:51 | getInputStream(...) : InputStream | A.java:34:23:34:28 | reader | +| A.java:39:29:39:49 | getInputStream(...) : InputStream | A.java:40:28:40:32 | input | +| A.java:39:29:39:49 | getInputStream(...) : InputStream | A.java:41:34:41:38 | input | +| A.java:39:29:39:49 | getInputStream(...) : InputStream | A.java:42:40:42:44 | input | +| A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:61:26:61:30 | input | +| A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:62:30:62:34 | input | +| A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:63:28:63:55 | new InputStreamReader(...) | +| A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:64:24:64:28 | input | +| A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:65:24:65:51 | new InputStreamReader(...) | +| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:71:26:71:30 | input | +| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:72:30:72:34 | input | +| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:73:28:73:55 | new InputStreamReader(...) | +| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:74:24:74:28 | input | +| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:75:24:75:51 | new InputStreamReader(...) | +| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | nodes -| A.java:13:31:13:51 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| A.java:13:31:13:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | A.java:15:12:15:13 | in | semmle.label | in | -| A.java:19:31:19:51 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| A.java:19:31:19:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | A.java:21:12:21:13 | in | semmle.label | in | -| A.java:25:31:25:51 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| A.java:25:31:25:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | A.java:27:12:27:12 | d | semmle.label | d | -| A.java:32:31:32:51 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| A.java:32:31:32:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | A.java:34:23:34:28 | reader | semmle.label | reader | -| A.java:39:29:39:49 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| A.java:39:29:39:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | A.java:40:28:40:32 | input | semmle.label | input | | A.java:41:34:41:38 | input | semmle.label | input | | A.java:42:40:42:44 | input | semmle.label | input | -| A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| A.java:60:25:60:45 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | A.java:61:26:61:30 | input | semmle.label | input | | A.java:62:30:62:34 | input | semmle.label | input | | A.java:63:28:63:55 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | | A.java:64:24:64:28 | input | semmle.label | input | | A.java:65:24:65:51 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| A.java:70:25:70:45 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | A.java:71:26:71:30 | input | semmle.label | input | | A.java:72:30:72:34 | input | semmle.label | input | | A.java:73:28:73:55 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | | A.java:74:24:74:28 | input | semmle.label | input | | A.java:75:24:75:51 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| TestMessageBodyReader.java:20:55:20:78 | entityStream [ : InputStream] | semmle.label | entityStream [ : InputStream] | +| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | semmle.label | entityStream : InputStream | | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | semmle.label | new ObjectInputStream(...) | #select -| A.java:15:12:15:26 | readObject(...) | A.java:13:31:13:51 | getInputStream(...) [ : InputStream] | A.java:15:12:15:13 | in | Unsafe deserialization of $@. | A.java:13:31:13:51 | getInputStream(...) | user input | -| A.java:21:12:21:28 | readUnshared(...) | A.java:19:31:19:51 | getInputStream(...) [ : InputStream] | A.java:21:12:21:13 | in | Unsafe deserialization of $@. | A.java:19:31:19:51 | getInputStream(...) | user input | -| A.java:27:12:27:25 | readObject(...) | A.java:25:31:25:51 | getInputStream(...) [ : InputStream] | A.java:27:12:27:12 | d | Unsafe deserialization of $@. | A.java:25:31:25:51 | getInputStream(...) | user input | -| A.java:34:12:34:29 | fromXML(...) | A.java:32:31:32:51 | getInputStream(...) [ : InputStream] | A.java:34:23:34:28 | reader | Unsafe deserialization of $@. | A.java:32:31:32:51 | getInputStream(...) | user input | -| A.java:40:12:40:42 | readObject(...) | A.java:39:29:39:49 | getInputStream(...) [ : InputStream] | A.java:40:28:40:32 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | -| A.java:41:12:41:48 | readObjectOrNull(...) | A.java:39:29:39:49 | getInputStream(...) [ : InputStream] | A.java:41:34:41:38 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | -| A.java:42:16:42:45 | readClassAndObject(...) | A.java:39:29:39:49 | getInputStream(...) [ : InputStream] | A.java:42:40:42:44 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | -| A.java:61:16:61:31 | load(...) | A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | A.java:61:26:61:30 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | -| A.java:62:17:62:35 | loadAll(...) | A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | A.java:62:30:62:34 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | -| A.java:63:17:63:56 | parse(...) | A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | A.java:63:28:63:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | -| A.java:64:12:64:38 | loadAs(...) | A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | A.java:64:24:64:28 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | -| A.java:65:12:65:61 | loadAs(...) | A.java:60:25:60:45 | getInputStream(...) [ : InputStream] | A.java:65:24:65:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | -| A.java:71:16:71:31 | load(...) | A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | A.java:71:26:71:30 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | -| A.java:72:17:72:35 | loadAll(...) | A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | A.java:72:30:72:34 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | -| A.java:73:17:73:56 | parse(...) | A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | A.java:73:28:73:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | -| A.java:74:12:74:38 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | A.java:74:24:74:28 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | -| A.java:75:12:75:61 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) [ : InputStream] | A.java:75:24:75:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | -| TestMessageBodyReader.java:22:18:22:65 | readObject(...) | TestMessageBodyReader.java:20:55:20:78 | entityStream [ : InputStream] | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | Unsafe deserialization of $@. | TestMessageBodyReader.java:20:55:20:78 | entityStream | user input | +| A.java:15:12:15:26 | readObject(...) | A.java:13:31:13:51 | getInputStream(...) : InputStream | A.java:15:12:15:13 | in | Unsafe deserialization of $@. | A.java:13:31:13:51 | getInputStream(...) | user input | +| A.java:21:12:21:28 | readUnshared(...) | A.java:19:31:19:51 | getInputStream(...) : InputStream | A.java:21:12:21:13 | in | Unsafe deserialization of $@. | A.java:19:31:19:51 | getInputStream(...) | user input | +| A.java:27:12:27:25 | readObject(...) | A.java:25:31:25:51 | getInputStream(...) : InputStream | A.java:27:12:27:12 | d | Unsafe deserialization of $@. | A.java:25:31:25:51 | getInputStream(...) | user input | +| A.java:34:12:34:29 | fromXML(...) | A.java:32:31:32:51 | getInputStream(...) : InputStream | A.java:34:23:34:28 | reader | Unsafe deserialization of $@. | A.java:32:31:32:51 | getInputStream(...) | user input | +| A.java:40:12:40:42 | readObject(...) | A.java:39:29:39:49 | getInputStream(...) : InputStream | A.java:40:28:40:32 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | +| A.java:41:12:41:48 | readObjectOrNull(...) | A.java:39:29:39:49 | getInputStream(...) : InputStream | A.java:41:34:41:38 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | +| A.java:42:16:42:45 | readClassAndObject(...) | A.java:39:29:39:49 | getInputStream(...) : InputStream | A.java:42:40:42:44 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input | +| A.java:61:16:61:31 | load(...) | A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:61:26:61:30 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | +| A.java:62:17:62:35 | loadAll(...) | A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:62:30:62:34 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | +| A.java:63:17:63:56 | parse(...) | A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:63:28:63:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | +| A.java:64:12:64:38 | loadAs(...) | A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:64:24:64:28 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | +| A.java:65:12:65:61 | loadAs(...) | A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:65:24:65:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input | +| A.java:71:16:71:31 | load(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:71:26:71:30 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| A.java:72:17:72:35 | loadAll(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:72:30:72:34 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| A.java:73:17:73:56 | parse(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:73:28:73:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| A.java:74:12:74:38 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:74:24:74:28 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| A.java:75:12:75:61 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:75:24:75:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| TestMessageBodyReader.java:22:18:22:65 | readObject(...) | TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | Unsafe deserialization of $@. | TestMessageBodyReader.java:20:55:20:78 | entityStream | user input | diff --git a/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.expected b/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.expected index e53eea7ff4d..21db09a43a8 100644 --- a/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.expected +++ b/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.expected @@ -1,13 +1,13 @@ edges -| UrlRedirect.java:36:58:36:89 | getParameter(...) [ : String] | UrlRedirect.java:36:25:36:89 | ... + ... | +| UrlRedirect.java:36:58:36:89 | getParameter(...) : String | UrlRedirect.java:36:25:36:89 | ... + ... | nodes | UrlRedirect.java:23:25:23:54 | getParameter(...) | semmle.label | getParameter(...) | | UrlRedirect.java:36:25:36:89 | ... + ... | semmle.label | ... + ... | -| UrlRedirect.java:36:58:36:89 | getParameter(...) [ : String] | semmle.label | getParameter(...) [ : String] | +| UrlRedirect.java:36:58:36:89 | getParameter(...) : String | semmle.label | getParameter(...) : String | | UrlRedirect.java:39:34:39:63 | getParameter(...) | semmle.label | getParameter(...) | | UrlRedirect.java:42:43:42:72 | getParameter(...) | semmle.label | getParameter(...) | #select | UrlRedirect.java:23:25:23:54 | getParameter(...) | UrlRedirect.java:23:25:23:54 | getParameter(...) | UrlRedirect.java:23:25:23:54 | getParameter(...) | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:23:25:23:54 | getParameter(...) | user-provided value | -| UrlRedirect.java:36:25:36:89 | ... + ... | UrlRedirect.java:36:58:36:89 | getParameter(...) [ : String] | UrlRedirect.java:36:25:36:89 | ... + ... | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:36:58:36:89 | getParameter(...) | user-provided value | +| UrlRedirect.java:36:25:36:89 | ... + ... | UrlRedirect.java:36:58:36:89 | getParameter(...) : String | UrlRedirect.java:36:25:36:89 | ... + ... | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:36:58:36:89 | getParameter(...) | user-provided value | | UrlRedirect.java:39:34:39:63 | getParameter(...) | UrlRedirect.java:39:34:39:63 | getParameter(...) | UrlRedirect.java:39:34:39:63 | getParameter(...) | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:39:34:39:63 | getParameter(...) | user-provided value | | UrlRedirect.java:42:43:42:72 | getParameter(...) | UrlRedirect.java:42:43:42:72 | getParameter(...) | UrlRedirect.java:42:43:42:72 | getParameter(...) | Potentially untrusted URL redirection due to $@. | UrlRedirect.java:42:43:42:72 | getParameter(...) | user-provided value | diff --git a/java/ql/test/query-tests/security/CWE-611/XXE.expected b/java/ql/test/query-tests/security/CWE-611/XXE.expected index 319c495be84..4cdedb8d0aa 100644 --- a/java/ql/test/query-tests/security/CWE-611/XXE.expected +++ b/java/ql/test/query-tests/security/CWE-611/XXE.expected @@ -1,54 +1,54 @@ edges -| DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) [ : InputStream] | DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | -| DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) [ : InputStream] | DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | -| DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) [ : InputStream] | DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | -| SchemaTests.java:12:56:12:76 | getInputStream(...) [ : InputStream] | SchemaTests.java:12:39:12:77 | new StreamSource(...) | -| SchemaTests.java:25:56:25:76 | getInputStream(...) [ : InputStream] | SchemaTests.java:25:39:25:77 | new StreamSource(...) | -| SchemaTests.java:31:56:31:76 | getInputStream(...) [ : InputStream] | SchemaTests.java:31:39:31:77 | new StreamSource(...) | -| SchemaTests.java:38:56:38:76 | getInputStream(...) [ : InputStream] | SchemaTests.java:38:39:38:77 | new StreamSource(...) | -| SchemaTests.java:45:56:45:76 | getInputStream(...) [ : InputStream] | SchemaTests.java:45:39:45:77 | new StreamSource(...) | -| SimpleXMLTests.java:24:63:24:83 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | -| SimpleXMLTests.java:30:5:30:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:31:41:31:53 | new String(...) | -| SimpleXMLTests.java:37:5:37:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:38:41:38:53 | new String(...) | -| SimpleXMLTests.java:43:63:43:83 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | -| SimpleXMLTests.java:68:59:68:79 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | -| SimpleXMLTests.java:73:59:73:79 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | -| SimpleXMLTests.java:78:48:78:68 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | -| SimpleXMLTests.java:83:48:83:68 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | -| SimpleXMLTests.java:89:5:89:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:90:37:90:49 | new String(...) | -| SimpleXMLTests.java:96:5:96:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:97:37:97:49 | new String(...) | -| SimpleXMLTests.java:103:5:103:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:104:26:104:38 | new String(...) | -| SimpleXMLTests.java:110:5:110:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:111:26:111:38 | new String(...) | -| SimpleXMLTests.java:119:44:119:64 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | -| SimpleXMLTests.java:129:44:129:64 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | -| SimpleXMLTests.java:139:44:139:64 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | -| SimpleXMLTests.java:145:5:145:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:146:22:146:34 | new String(...) | -| SimpleXMLTests.java:152:5:152:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:153:22:153:34 | new String(...) | -| TransformerTests.java:20:44:20:64 | getInputStream(...) [ : InputStream] | TransformerTests.java:20:27:20:65 | new StreamSource(...) | -| TransformerTests.java:21:40:21:60 | getInputStream(...) [ : InputStream] | TransformerTests.java:21:23:21:61 | new StreamSource(...) | -| TransformerTests.java:71:44:71:64 | getInputStream(...) [ : InputStream] | TransformerTests.java:71:27:71:65 | new StreamSource(...) | -| TransformerTests.java:72:40:72:60 | getInputStream(...) [ : InputStream] | TransformerTests.java:72:23:72:61 | new StreamSource(...) | -| TransformerTests.java:79:44:79:64 | getInputStream(...) [ : InputStream] | TransformerTests.java:79:27:79:65 | new StreamSource(...) | -| TransformerTests.java:80:40:80:60 | getInputStream(...) [ : InputStream] | TransformerTests.java:80:23:80:61 | new StreamSource(...) | -| TransformerTests.java:88:44:88:64 | getInputStream(...) [ : InputStream] | TransformerTests.java:88:27:88:65 | new StreamSource(...) | -| TransformerTests.java:89:40:89:60 | getInputStream(...) [ : InputStream] | TransformerTests.java:89:23:89:61 | new StreamSource(...) | -| TransformerTests.java:97:44:97:64 | getInputStream(...) [ : InputStream] | TransformerTests.java:97:27:97:65 | new StreamSource(...) | -| TransformerTests.java:98:40:98:60 | getInputStream(...) [ : InputStream] | TransformerTests.java:98:23:98:61 | new StreamSource(...) | -| TransformerTests.java:103:38:103:58 | getInputStream(...) [ : InputStream] | TransformerTests.java:103:21:103:59 | new StreamSource(...) | -| TransformerTests.java:116:38:116:58 | getInputStream(...) [ : InputStream] | TransformerTests.java:116:21:116:59 | new StreamSource(...) | -| TransformerTests.java:122:38:122:58 | getInputStream(...) [ : InputStream] | TransformerTests.java:122:21:122:59 | new StreamSource(...) | -| TransformerTests.java:129:38:129:58 | getInputStream(...) [ : InputStream] | TransformerTests.java:129:21:129:59 | new StreamSource(...) | -| TransformerTests.java:136:38:136:58 | getInputStream(...) [ : InputStream] | TransformerTests.java:136:21:136:59 | new StreamSource(...) | -| TransformerTests.java:141:48:141:68 | getInputStream(...) [ : InputStream] | TransformerTests.java:141:18:141:70 | new SAXSource(...) | -| XMLReaderTests.java:16:34:16:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | -| XMLReaderTests.java:56:34:56:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | -| XMLReaderTests.java:63:34:63:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | -| XMLReaderTests.java:70:34:70:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | -| XMLReaderTests.java:78:34:78:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | -| XMLReaderTests.java:86:34:86:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | -| XMLReaderTests.java:94:34:94:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | -| XMLReaderTests.java:100:34:100:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | -| XPathExpressionTests.java:27:37:27:57 | getInputStream(...) [ : InputStream] | XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | +| DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) : InputStream | DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | +| DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) : InputStream | DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | +| DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) : InputStream | DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | +| SchemaTests.java:12:56:12:76 | getInputStream(...) : InputStream | SchemaTests.java:12:39:12:77 | new StreamSource(...) | +| SchemaTests.java:25:56:25:76 | getInputStream(...) : InputStream | SchemaTests.java:25:39:25:77 | new StreamSource(...) | +| SchemaTests.java:31:56:31:76 | getInputStream(...) : InputStream | SchemaTests.java:31:39:31:77 | new StreamSource(...) | +| SchemaTests.java:38:56:38:76 | getInputStream(...) : InputStream | SchemaTests.java:38:39:38:77 | new StreamSource(...) | +| SchemaTests.java:45:56:45:76 | getInputStream(...) : InputStream | SchemaTests.java:45:39:45:77 | new StreamSource(...) | +| SimpleXMLTests.java:24:63:24:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | +| SimpleXMLTests.java:30:5:30:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:31:41:31:53 | new String(...) | +| SimpleXMLTests.java:37:5:37:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:38:41:38:53 | new String(...) | +| SimpleXMLTests.java:43:63:43:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | +| SimpleXMLTests.java:68:59:68:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | +| SimpleXMLTests.java:73:59:73:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | +| SimpleXMLTests.java:78:48:78:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | +| SimpleXMLTests.java:83:48:83:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | +| SimpleXMLTests.java:89:5:89:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:90:37:90:49 | new String(...) | +| SimpleXMLTests.java:96:5:96:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:97:37:97:49 | new String(...) | +| SimpleXMLTests.java:103:5:103:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:104:26:104:38 | new String(...) | +| SimpleXMLTests.java:110:5:110:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:111:26:111:38 | new String(...) | +| SimpleXMLTests.java:119:44:119:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | +| SimpleXMLTests.java:129:44:129:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | +| SimpleXMLTests.java:139:44:139:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | +| SimpleXMLTests.java:145:5:145:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:146:22:146:34 | new String(...) | +| SimpleXMLTests.java:152:5:152:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:153:22:153:34 | new String(...) | +| TransformerTests.java:20:44:20:64 | getInputStream(...) : InputStream | TransformerTests.java:20:27:20:65 | new StreamSource(...) | +| TransformerTests.java:21:40:21:60 | getInputStream(...) : InputStream | TransformerTests.java:21:23:21:61 | new StreamSource(...) | +| TransformerTests.java:71:44:71:64 | getInputStream(...) : InputStream | TransformerTests.java:71:27:71:65 | new StreamSource(...) | +| TransformerTests.java:72:40:72:60 | getInputStream(...) : InputStream | TransformerTests.java:72:23:72:61 | new StreamSource(...) | +| TransformerTests.java:79:44:79:64 | getInputStream(...) : InputStream | TransformerTests.java:79:27:79:65 | new StreamSource(...) | +| TransformerTests.java:80:40:80:60 | getInputStream(...) : InputStream | TransformerTests.java:80:23:80:61 | new StreamSource(...) | +| TransformerTests.java:88:44:88:64 | getInputStream(...) : InputStream | TransformerTests.java:88:27:88:65 | new StreamSource(...) | +| TransformerTests.java:89:40:89:60 | getInputStream(...) : InputStream | TransformerTests.java:89:23:89:61 | new StreamSource(...) | +| TransformerTests.java:97:44:97:64 | getInputStream(...) : InputStream | TransformerTests.java:97:27:97:65 | new StreamSource(...) | +| TransformerTests.java:98:40:98:60 | getInputStream(...) : InputStream | TransformerTests.java:98:23:98:61 | new StreamSource(...) | +| TransformerTests.java:103:38:103:58 | getInputStream(...) : InputStream | TransformerTests.java:103:21:103:59 | new StreamSource(...) | +| TransformerTests.java:116:38:116:58 | getInputStream(...) : InputStream | TransformerTests.java:116:21:116:59 | new StreamSource(...) | +| TransformerTests.java:122:38:122:58 | getInputStream(...) : InputStream | TransformerTests.java:122:21:122:59 | new StreamSource(...) | +| TransformerTests.java:129:38:129:58 | getInputStream(...) : InputStream | TransformerTests.java:129:21:129:59 | new StreamSource(...) | +| TransformerTests.java:136:38:136:58 | getInputStream(...) : InputStream | TransformerTests.java:136:21:136:59 | new StreamSource(...) | +| TransformerTests.java:141:48:141:68 | getInputStream(...) : InputStream | TransformerTests.java:141:18:141:70 | new SAXSource(...) | +| XMLReaderTests.java:16:34:16:54 | getInputStream(...) : InputStream | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | +| XMLReaderTests.java:56:34:56:54 | getInputStream(...) : InputStream | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | +| XMLReaderTests.java:63:34:63:54 | getInputStream(...) : InputStream | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | +| XMLReaderTests.java:70:34:70:54 | getInputStream(...) : InputStream | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | +| XMLReaderTests.java:78:34:78:54 | getInputStream(...) : InputStream | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | +| XMLReaderTests.java:86:34:86:54 | getInputStream(...) : InputStream | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | +| XMLReaderTests.java:94:34:94:54 | getInputStream(...) : InputStream | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | +| XMLReaderTests.java:100:34:100:54 | getInputStream(...) : InputStream | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | +| XPathExpressionTests.java:27:37:27:57 | getInputStream(...) : InputStream | XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | nodes | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | semmle.label | getInputStream(...) | | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | semmle.label | getInputStream(...) | @@ -57,9 +57,9 @@ nodes | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | semmle.label | getInputStream(...) | | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | semmle.label | getInputStream(...) | | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | semmle.label | getInputStream(...) | -| DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | semmle.label | getInputSource(...) | -| DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | semmle.label | sourceToInputSource(...) | | DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | semmle.label | getInputStream(...) | | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | semmle.label | getInputStream(...) | @@ -79,108 +79,108 @@ nodes | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | semmle.label | getInputStream(...) | | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | semmle.label | getInputStream(...) | | SchemaTests.java:12:39:12:77 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| SchemaTests.java:12:56:12:76 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SchemaTests.java:12:56:12:76 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SchemaTests.java:25:39:25:77 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| SchemaTests.java:25:56:25:76 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SchemaTests.java:25:56:25:76 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SchemaTests.java:31:39:31:77 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| SchemaTests.java:31:56:31:76 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SchemaTests.java:31:56:31:76 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SchemaTests.java:38:39:38:77 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| SchemaTests.java:38:56:38:76 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SchemaTests.java:38:56:38:76 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SchemaTests.java:45:39:45:77 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| SchemaTests.java:45:56:45:76 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SchemaTests.java:45:56:45:76 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | semmle.label | getInputStream(...) | | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | semmle.label | getInputStream(...) | | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| SimpleXMLTests.java:24:63:24:83 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | -| SimpleXMLTests.java:30:5:30:25 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:24:63:24:83 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SimpleXMLTests.java:30:5:30:25 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:31:41:31:53 | new String(...) | semmle.label | new String(...) | -| SimpleXMLTests.java:37:5:37:25 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:37:5:37:25 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:38:41:38:53 | new String(...) | semmle.label | new String(...) | | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| SimpleXMLTests.java:43:63:43:83 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:43:63:43:83 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | semmle.label | getInputStream(...) | | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | semmle.label | getInputStream(...) | | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | semmle.label | getInputStream(...) | | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | semmle.label | getInputStream(...) | | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| SimpleXMLTests.java:68:59:68:79 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:68:59:68:79 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| SimpleXMLTests.java:73:59:73:79 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:73:59:73:79 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| SimpleXMLTests.java:78:48:78:68 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:78:48:78:68 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| SimpleXMLTests.java:83:48:83:68 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | -| SimpleXMLTests.java:89:5:89:25 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:83:48:83:68 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SimpleXMLTests.java:89:5:89:25 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:90:37:90:49 | new String(...) | semmle.label | new String(...) | -| SimpleXMLTests.java:96:5:96:25 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:96:5:96:25 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:97:37:97:49 | new String(...) | semmle.label | new String(...) | -| SimpleXMLTests.java:103:5:103:25 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:103:5:103:25 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:104:26:104:38 | new String(...) | semmle.label | new String(...) | -| SimpleXMLTests.java:110:5:110:25 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:110:5:110:25 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:111:26:111:38 | new String(...) | semmle.label | new String(...) | | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | semmle.label | getInputStream(...) | | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| SimpleXMLTests.java:119:44:119:64 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:119:44:119:64 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | semmle.label | getInputStream(...) | | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| SimpleXMLTests.java:129:44:129:64 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:129:44:129:64 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | semmle.label | getInputStream(...) | | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | -| SimpleXMLTests.java:139:44:139:64 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | -| SimpleXMLTests.java:145:5:145:25 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:139:44:139:64 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SimpleXMLTests.java:145:5:145:25 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:146:22:146:34 | new String(...) | semmle.label | new String(...) | -| SimpleXMLTests.java:152:5:152:25 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| SimpleXMLTests.java:152:5:152:25 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | SimpleXMLTests.java:153:22:153:34 | new String(...) | semmle.label | new String(...) | | TransformerTests.java:20:27:20:65 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:20:44:20:64 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:20:44:20:64 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:21:23:21:61 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:21:40:21:60 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:21:40:21:60 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:71:27:71:65 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:71:44:71:64 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:71:44:71:64 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:72:23:72:61 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:72:40:72:60 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:72:40:72:60 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:79:27:79:65 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:79:44:79:64 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:79:44:79:64 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:80:23:80:61 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:80:40:80:60 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:80:40:80:60 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:88:27:88:65 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:88:44:88:64 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:88:44:88:64 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:89:23:89:61 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:89:40:89:60 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:89:40:89:60 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:97:27:97:65 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:97:44:97:64 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:97:44:97:64 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:98:23:98:61 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:98:40:98:60 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:98:40:98:60 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:103:21:103:59 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:103:38:103:58 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:103:38:103:58 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:116:21:116:59 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:116:38:116:58 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:116:38:116:58 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:122:21:122:59 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:122:38:122:58 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:122:38:122:58 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:129:21:129:59 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:129:38:129:58 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:129:38:129:58 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:136:21:136:59 | new StreamSource(...) | semmle.label | new StreamSource(...) | -| TransformerTests.java:136:38:136:58 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:136:38:136:58 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | TransformerTests.java:141:18:141:70 | new SAXSource(...) | semmle.label | new SAXSource(...) | -| TransformerTests.java:141:48:141:68 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| TransformerTests.java:141:48:141:68 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | semmle.label | new InputSource(...) | -| XMLReaderTests.java:16:34:16:54 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| XMLReaderTests.java:16:34:16:54 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | semmle.label | new InputSource(...) | -| XMLReaderTests.java:56:34:56:54 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| XMLReaderTests.java:56:34:56:54 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | semmle.label | new InputSource(...) | -| XMLReaderTests.java:63:34:63:54 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| XMLReaderTests.java:63:34:63:54 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | semmle.label | new InputSource(...) | -| XMLReaderTests.java:70:34:70:54 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| XMLReaderTests.java:70:34:70:54 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | semmle.label | new InputSource(...) | -| XMLReaderTests.java:78:34:78:54 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| XMLReaderTests.java:78:34:78:54 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | semmle.label | new InputSource(...) | -| XMLReaderTests.java:86:34:86:54 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| XMLReaderTests.java:86:34:86:54 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | semmle.label | new InputSource(...) | -| XMLReaderTests.java:94:34:94:54 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| XMLReaderTests.java:94:34:94:54 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | semmle.label | new InputSource(...) | -| XMLReaderTests.java:100:34:100:54 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| XMLReaderTests.java:100:34:100:54 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | semmle.label | new InputSource(...) | -| XPathExpressionTests.java:27:37:27:57 | getInputStream(...) [ : InputStream] | semmle.label | getInputStream(...) [ : InputStream] | +| XPathExpressionTests.java:27:37:27:57 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | semmle.label | getInputStream(...) | | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | semmle.label | getInputStream(...) | | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | semmle.label | getInputStream(...) | @@ -201,9 +201,9 @@ nodes | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | user input | | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | user input | | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | user input | -| DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) [ : InputStream] | DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) | user input | -| DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) [ : InputStream] | DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user input | -| DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) [ : InputStream] | DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user input | +| DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) : InputStream | DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) | user input | +| DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) : InputStream | DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user input | +| DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) : InputStream | DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user input | | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | user input | | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | user input | | SAXParserTests.java:13:18:13:38 | getInputStream(...) | SAXParserTests.java:13:18:13:38 | getInputStream(...) | SAXParserTests.java:13:18:13:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:13:18:13:38 | getInputStream(...) | user input | @@ -220,62 +220,62 @@ nodes | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | user input | | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | user input | | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | user input | -| SchemaTests.java:12:39:12:77 | new StreamSource(...) | SchemaTests.java:12:56:12:76 | getInputStream(...) [ : InputStream] | SchemaTests.java:12:39:12:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:12:56:12:76 | getInputStream(...) | user input | -| SchemaTests.java:25:39:25:77 | new StreamSource(...) | SchemaTests.java:25:56:25:76 | getInputStream(...) [ : InputStream] | SchemaTests.java:25:39:25:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:25:56:25:76 | getInputStream(...) | user input | -| SchemaTests.java:31:39:31:77 | new StreamSource(...) | SchemaTests.java:31:56:31:76 | getInputStream(...) [ : InputStream] | SchemaTests.java:31:39:31:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:31:56:31:76 | getInputStream(...) | user input | -| SchemaTests.java:38:39:38:77 | new StreamSource(...) | SchemaTests.java:38:56:38:76 | getInputStream(...) [ : InputStream] | SchemaTests.java:38:39:38:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:38:56:38:76 | getInputStream(...) | user input | -| SchemaTests.java:45:39:45:77 | new StreamSource(...) | SchemaTests.java:45:56:45:76 | getInputStream(...) [ : InputStream] | SchemaTests.java:45:39:45:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:45:56:45:76 | getInputStream(...) | user input | +| SchemaTests.java:12:39:12:77 | new StreamSource(...) | SchemaTests.java:12:56:12:76 | getInputStream(...) : InputStream | SchemaTests.java:12:39:12:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:12:56:12:76 | getInputStream(...) | user input | +| SchemaTests.java:25:39:25:77 | new StreamSource(...) | SchemaTests.java:25:56:25:76 | getInputStream(...) : InputStream | SchemaTests.java:25:39:25:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:25:56:25:76 | getInputStream(...) | user input | +| SchemaTests.java:31:39:31:77 | new StreamSource(...) | SchemaTests.java:31:56:31:76 | getInputStream(...) : InputStream | SchemaTests.java:31:39:31:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:31:56:31:76 | getInputStream(...) | user input | +| SchemaTests.java:38:39:38:77 | new StreamSource(...) | SchemaTests.java:38:56:38:76 | getInputStream(...) : InputStream | SchemaTests.java:38:39:38:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:38:56:38:76 | getInputStream(...) | user input | +| SchemaTests.java:45:39:45:77 | new StreamSource(...) | SchemaTests.java:45:56:45:76 | getInputStream(...) : InputStream | SchemaTests.java:45:39:45:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:45:56:45:76 | getInputStream(...) | user input | | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | user input | | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | user input | -| SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) | user input | -| SimpleXMLTests.java:31:41:31:53 | new String(...) | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:31:41:31:53 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:38:41:38:53 | new String(...) | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:38:41:38:53 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) | user input | +| SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) | user input | +| SimpleXMLTests.java:31:41:31:53 | new String(...) | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:31:41:31:53 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:38:41:38:53 | new String(...) | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:38:41:38:53 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) | user input | | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | user input | | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | user input | | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | user input | | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | user input | -| SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) | user input | -| SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) | user input | -| SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) | user input | -| SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) | user input | -| SimpleXMLTests.java:90:37:90:49 | new String(...) | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:90:37:90:49 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:97:37:97:49 | new String(...) | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:97:37:97:49 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:104:26:104:38 | new String(...) | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:104:26:104:38 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:111:26:111:38 | new String(...) | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:111:26:111:38 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) | user input | +| SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) | user input | +| SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) | user input | +| SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) | user input | +| SimpleXMLTests.java:90:37:90:49 | new String(...) | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:90:37:90:49 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:97:37:97:49 | new String(...) | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:97:37:97:49 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:104:26:104:38 | new String(...) | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:104:26:104:38 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:111:26:111:38 | new String(...) | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:111:26:111:38 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) | user input | | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | user input | -| SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) | user input | +| SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) | user input | | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | user input | -| SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) | user input | +| SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) | user input | | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | user input | -| SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) | user input | -| SimpleXMLTests.java:146:22:146:34 | new String(...) | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:146:22:146:34 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) | user input | -| SimpleXMLTests.java:153:22:153:34 | new String(...) | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) [ : InputStream] | SimpleXMLTests.java:153:22:153:34 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) | user input | -| TransformerTests.java:20:27:20:65 | new StreamSource(...) | TransformerTests.java:20:44:20:64 | getInputStream(...) [ : InputStream] | TransformerTests.java:20:27:20:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:20:44:20:64 | getInputStream(...) | user input | -| TransformerTests.java:21:23:21:61 | new StreamSource(...) | TransformerTests.java:21:40:21:60 | getInputStream(...) [ : InputStream] | TransformerTests.java:21:23:21:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:21:40:21:60 | getInputStream(...) | user input | -| TransformerTests.java:71:27:71:65 | new StreamSource(...) | TransformerTests.java:71:44:71:64 | getInputStream(...) [ : InputStream] | TransformerTests.java:71:27:71:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:71:44:71:64 | getInputStream(...) | user input | -| TransformerTests.java:72:23:72:61 | new StreamSource(...) | TransformerTests.java:72:40:72:60 | getInputStream(...) [ : InputStream] | TransformerTests.java:72:23:72:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:72:40:72:60 | getInputStream(...) | user input | -| TransformerTests.java:79:27:79:65 | new StreamSource(...) | TransformerTests.java:79:44:79:64 | getInputStream(...) [ : InputStream] | TransformerTests.java:79:27:79:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:79:44:79:64 | getInputStream(...) | user input | -| TransformerTests.java:80:23:80:61 | new StreamSource(...) | TransformerTests.java:80:40:80:60 | getInputStream(...) [ : InputStream] | TransformerTests.java:80:23:80:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:80:40:80:60 | getInputStream(...) | user input | -| TransformerTests.java:88:27:88:65 | new StreamSource(...) | TransformerTests.java:88:44:88:64 | getInputStream(...) [ : InputStream] | TransformerTests.java:88:27:88:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:88:44:88:64 | getInputStream(...) | user input | -| TransformerTests.java:89:23:89:61 | new StreamSource(...) | TransformerTests.java:89:40:89:60 | getInputStream(...) [ : InputStream] | TransformerTests.java:89:23:89:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:89:40:89:60 | getInputStream(...) | user input | -| TransformerTests.java:97:27:97:65 | new StreamSource(...) | TransformerTests.java:97:44:97:64 | getInputStream(...) [ : InputStream] | TransformerTests.java:97:27:97:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:97:44:97:64 | getInputStream(...) | user input | -| TransformerTests.java:98:23:98:61 | new StreamSource(...) | TransformerTests.java:98:40:98:60 | getInputStream(...) [ : InputStream] | TransformerTests.java:98:23:98:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:98:40:98:60 | getInputStream(...) | user input | -| TransformerTests.java:103:21:103:59 | new StreamSource(...) | TransformerTests.java:103:38:103:58 | getInputStream(...) [ : InputStream] | TransformerTests.java:103:21:103:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:103:38:103:58 | getInputStream(...) | user input | -| TransformerTests.java:116:21:116:59 | new StreamSource(...) | TransformerTests.java:116:38:116:58 | getInputStream(...) [ : InputStream] | TransformerTests.java:116:21:116:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:116:38:116:58 | getInputStream(...) | user input | -| TransformerTests.java:122:21:122:59 | new StreamSource(...) | TransformerTests.java:122:38:122:58 | getInputStream(...) [ : InputStream] | TransformerTests.java:122:21:122:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:122:38:122:58 | getInputStream(...) | user input | -| TransformerTests.java:129:21:129:59 | new StreamSource(...) | TransformerTests.java:129:38:129:58 | getInputStream(...) [ : InputStream] | TransformerTests.java:129:21:129:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:129:38:129:58 | getInputStream(...) | user input | -| TransformerTests.java:136:21:136:59 | new StreamSource(...) | TransformerTests.java:136:38:136:58 | getInputStream(...) [ : InputStream] | TransformerTests.java:136:21:136:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:136:38:136:58 | getInputStream(...) | user input | -| TransformerTests.java:141:18:141:70 | new SAXSource(...) | TransformerTests.java:141:48:141:68 | getInputStream(...) [ : InputStream] | TransformerTests.java:141:18:141:70 | new SAXSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:141:48:141:68 | getInputStream(...) | user input | -| XMLReaderTests.java:16:18:16:55 | new InputSource(...) | XMLReaderTests.java:16:34:16:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:16:34:16:54 | getInputStream(...) | user input | -| XMLReaderTests.java:56:18:56:55 | new InputSource(...) | XMLReaderTests.java:56:34:56:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:56:34:56:54 | getInputStream(...) | user input | -| XMLReaderTests.java:63:18:63:55 | new InputSource(...) | XMLReaderTests.java:63:34:63:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:63:34:63:54 | getInputStream(...) | user input | -| XMLReaderTests.java:70:18:70:55 | new InputSource(...) | XMLReaderTests.java:70:34:70:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:70:34:70:54 | getInputStream(...) | user input | -| XMLReaderTests.java:78:18:78:55 | new InputSource(...) | XMLReaderTests.java:78:34:78:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:78:34:78:54 | getInputStream(...) | user input | -| XMLReaderTests.java:86:18:86:55 | new InputSource(...) | XMLReaderTests.java:86:34:86:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:86:34:86:54 | getInputStream(...) | user input | -| XMLReaderTests.java:94:18:94:55 | new InputSource(...) | XMLReaderTests.java:94:34:94:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:94:34:94:54 | getInputStream(...) | user input | -| XMLReaderTests.java:100:18:100:55 | new InputSource(...) | XMLReaderTests.java:100:34:100:54 | getInputStream(...) [ : InputStream] | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:100:34:100:54 | getInputStream(...) | user input | -| XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) [ : InputStream] | XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | Unsafe parsing of XML file from $@. | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) | user input | +| SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) | user input | +| SimpleXMLTests.java:146:22:146:34 | new String(...) | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:146:22:146:34 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) | user input | +| SimpleXMLTests.java:153:22:153:34 | new String(...) | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:153:22:153:34 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) | user input | +| TransformerTests.java:20:27:20:65 | new StreamSource(...) | TransformerTests.java:20:44:20:64 | getInputStream(...) : InputStream | TransformerTests.java:20:27:20:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:20:44:20:64 | getInputStream(...) | user input | +| TransformerTests.java:21:23:21:61 | new StreamSource(...) | TransformerTests.java:21:40:21:60 | getInputStream(...) : InputStream | TransformerTests.java:21:23:21:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:21:40:21:60 | getInputStream(...) | user input | +| TransformerTests.java:71:27:71:65 | new StreamSource(...) | TransformerTests.java:71:44:71:64 | getInputStream(...) : InputStream | TransformerTests.java:71:27:71:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:71:44:71:64 | getInputStream(...) | user input | +| TransformerTests.java:72:23:72:61 | new StreamSource(...) | TransformerTests.java:72:40:72:60 | getInputStream(...) : InputStream | TransformerTests.java:72:23:72:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:72:40:72:60 | getInputStream(...) | user input | +| TransformerTests.java:79:27:79:65 | new StreamSource(...) | TransformerTests.java:79:44:79:64 | getInputStream(...) : InputStream | TransformerTests.java:79:27:79:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:79:44:79:64 | getInputStream(...) | user input | +| TransformerTests.java:80:23:80:61 | new StreamSource(...) | TransformerTests.java:80:40:80:60 | getInputStream(...) : InputStream | TransformerTests.java:80:23:80:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:80:40:80:60 | getInputStream(...) | user input | +| TransformerTests.java:88:27:88:65 | new StreamSource(...) | TransformerTests.java:88:44:88:64 | getInputStream(...) : InputStream | TransformerTests.java:88:27:88:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:88:44:88:64 | getInputStream(...) | user input | +| TransformerTests.java:89:23:89:61 | new StreamSource(...) | TransformerTests.java:89:40:89:60 | getInputStream(...) : InputStream | TransformerTests.java:89:23:89:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:89:40:89:60 | getInputStream(...) | user input | +| TransformerTests.java:97:27:97:65 | new StreamSource(...) | TransformerTests.java:97:44:97:64 | getInputStream(...) : InputStream | TransformerTests.java:97:27:97:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:97:44:97:64 | getInputStream(...) | user input | +| TransformerTests.java:98:23:98:61 | new StreamSource(...) | TransformerTests.java:98:40:98:60 | getInputStream(...) : InputStream | TransformerTests.java:98:23:98:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:98:40:98:60 | getInputStream(...) | user input | +| TransformerTests.java:103:21:103:59 | new StreamSource(...) | TransformerTests.java:103:38:103:58 | getInputStream(...) : InputStream | TransformerTests.java:103:21:103:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:103:38:103:58 | getInputStream(...) | user input | +| TransformerTests.java:116:21:116:59 | new StreamSource(...) | TransformerTests.java:116:38:116:58 | getInputStream(...) : InputStream | TransformerTests.java:116:21:116:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:116:38:116:58 | getInputStream(...) | user input | +| TransformerTests.java:122:21:122:59 | new StreamSource(...) | TransformerTests.java:122:38:122:58 | getInputStream(...) : InputStream | TransformerTests.java:122:21:122:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:122:38:122:58 | getInputStream(...) | user input | +| TransformerTests.java:129:21:129:59 | new StreamSource(...) | TransformerTests.java:129:38:129:58 | getInputStream(...) : InputStream | TransformerTests.java:129:21:129:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:129:38:129:58 | getInputStream(...) | user input | +| TransformerTests.java:136:21:136:59 | new StreamSource(...) | TransformerTests.java:136:38:136:58 | getInputStream(...) : InputStream | TransformerTests.java:136:21:136:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:136:38:136:58 | getInputStream(...) | user input | +| TransformerTests.java:141:18:141:70 | new SAXSource(...) | TransformerTests.java:141:48:141:68 | getInputStream(...) : InputStream | TransformerTests.java:141:18:141:70 | new SAXSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:141:48:141:68 | getInputStream(...) | user input | +| XMLReaderTests.java:16:18:16:55 | new InputSource(...) | XMLReaderTests.java:16:34:16:54 | getInputStream(...) : InputStream | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:16:34:16:54 | getInputStream(...) | user input | +| XMLReaderTests.java:56:18:56:55 | new InputSource(...) | XMLReaderTests.java:56:34:56:54 | getInputStream(...) : InputStream | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:56:34:56:54 | getInputStream(...) | user input | +| XMLReaderTests.java:63:18:63:55 | new InputSource(...) | XMLReaderTests.java:63:34:63:54 | getInputStream(...) : InputStream | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:63:34:63:54 | getInputStream(...) | user input | +| XMLReaderTests.java:70:18:70:55 | new InputSource(...) | XMLReaderTests.java:70:34:70:54 | getInputStream(...) : InputStream | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:70:34:70:54 | getInputStream(...) | user input | +| XMLReaderTests.java:78:18:78:55 | new InputSource(...) | XMLReaderTests.java:78:34:78:54 | getInputStream(...) : InputStream | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:78:34:78:54 | getInputStream(...) | user input | +| XMLReaderTests.java:86:18:86:55 | new InputSource(...) | XMLReaderTests.java:86:34:86:54 | getInputStream(...) : InputStream | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:86:34:86:54 | getInputStream(...) | user input | +| XMLReaderTests.java:94:18:94:55 | new InputSource(...) | XMLReaderTests.java:94:34:94:54 | getInputStream(...) : InputStream | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:94:34:94:54 | getInputStream(...) | user input | +| XMLReaderTests.java:100:18:100:55 | new InputSource(...) | XMLReaderTests.java:100:34:100:54 | getInputStream(...) : InputStream | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:100:34:100:54 | getInputStream(...) | user input | +| XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) : InputStream | XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | Unsafe parsing of XML file from $@. | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) | user input | | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | user input | | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | user input | | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | user input | diff --git a/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected index ba740c0bf59..0be574cad70 100644 --- a/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected +++ b/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected @@ -1,7 +1,7 @@ edges -| Test.java:11:28:11:36 | System.in [ : InputStream] | Test.java:21:22:21:25 | data | +| Test.java:11:28:11:36 | System.in : InputStream | Test.java:21:22:21:25 | data | nodes -| Test.java:11:28:11:36 | System.in [ : InputStream] | semmle.label | System.in [ : InputStream] | +| Test.java:11:28:11:36 | System.in : InputStream | semmle.label | System.in : InputStream | | Test.java:21:22:21:25 | data | semmle.label | data | #select -| Test.java:21:17:21:25 | (...)... | Test.java:11:28:11:36 | System.in [ : InputStream] | Test.java:21:22:21:25 | data | $@ flows to here and is cast to a narrower type, potentially causing truncation. | Test.java:11:28:11:36 | System.in | User-provided value | +| Test.java:21:17:21:25 | (...)... | Test.java:11:28:11:36 | System.in : InputStream | Test.java:21:22:21:25 | data | $@ flows to here and is cast to a narrower type, potentially causing truncation. | Test.java:11:28:11:36 | System.in | User-provided value | diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected index 3c74bf4a9ea..79e99b55479 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected @@ -1,82 +1,82 @@ edges -| CredentialsTest.java:7:34:7:41 | "123456" [ : String] | CredentialsTest.java:13:39:13:39 | p | -| CredentialsTest.java:7:34:7:41 | "123456" [ : String] | CredentialsTest.java:14:16:14:16 | p [ : String] | -| CredentialsTest.java:11:14:11:20 | "admin" [ : String] | CredentialsTest.java:13:36:13:36 | u | -| CredentialsTest.java:11:14:11:20 | "admin" [ : String] | CredentialsTest.java:14:13:14:13 | u [ : String] | -| CredentialsTest.java:14:13:14:13 | u [ : String] | CredentialsTest.java:17:38:17:45 | v [ : String] | -| CredentialsTest.java:14:16:14:16 | p [ : String] | CredentialsTest.java:17:48:17:55 | q [ : String] | -| CredentialsTest.java:17:38:17:45 | v [ : String] | CredentialsTest.java:18:36:18:36 | v | -| CredentialsTest.java:17:48:17:55 | q [ : String] | CredentialsTest.java:18:39:18:39 | q | -| FileCredentialTest.java:13:14:13:20 | "admin" [ : String] | FileCredentialTest.java:19:13:19:13 | u [ : String] | -| FileCredentialTest.java:19:13:19:13 | u [ : String] | FileCredentialTest.java:22:38:22:45 | v [ : String] | -| FileCredentialTest.java:22:38:22:45 | v [ : String] | FileCredentialTest.java:23:36:23:36 | v | -| Test.java:9:16:9:22 | "admin" [ : String] | Test.java:12:13:12:15 | usr [ : String] | -| Test.java:9:16:9:22 | "admin" [ : String] | Test.java:15:36:15:38 | usr | -| Test.java:9:16:9:22 | "admin" [ : String] | Test.java:17:39:17:41 | usr | -| Test.java:9:16:9:22 | "admin" [ : String] | Test.java:18:39:18:41 | usr | -| Test.java:10:17:10:24 | "123456" [ : String] | Test.java:12:18:12:21 | pass [ : String] | -| Test.java:10:17:10:24 | "123456" [ : String] | Test.java:15:41:15:44 | pass | -| Test.java:10:17:10:24 | "123456" [ : String] | Test.java:18:44:18:61 | toCharArray(...) | -| Test.java:12:13:12:15 | usr [ : String] | Test.java:29:38:29:48 | user [ : String] | -| Test.java:12:18:12:21 | pass [ : String] | Test.java:29:51:29:65 | password [ : String] | -| Test.java:17:44:17:51 | "123456" [ : String] | Test.java:17:44:17:65 | toCharArray(...) | -| Test.java:20:16:20:39 | new byte[] [ : byte[]] | Test.java:21:78:21:80 | key | -| Test.java:23:17:23:26 | "abcdefgh" [ : String] | Test.java:24:79:24:82 | key2 | -| Test.java:29:38:29:48 | user [ : String] | Test.java:30:36:30:39 | user | -| Test.java:29:51:29:65 | password [ : String] | Test.java:30:42:30:49 | password | +| CredentialsTest.java:7:34:7:41 | "123456" : String | CredentialsTest.java:13:39:13:39 | p | +| CredentialsTest.java:7:34:7:41 | "123456" : String | CredentialsTest.java:14:16:14:16 | p : String | +| CredentialsTest.java:11:14:11:20 | "admin" : String | CredentialsTest.java:13:36:13:36 | u | +| CredentialsTest.java:11:14:11:20 | "admin" : String | CredentialsTest.java:14:13:14:13 | u : String | +| CredentialsTest.java:14:13:14:13 | u : String | CredentialsTest.java:17:38:17:45 | v : String | +| CredentialsTest.java:14:16:14:16 | p : String | CredentialsTest.java:17:48:17:55 | q : String | +| CredentialsTest.java:17:38:17:45 | v : String | CredentialsTest.java:18:36:18:36 | v | +| CredentialsTest.java:17:48:17:55 | q : String | CredentialsTest.java:18:39:18:39 | q | +| FileCredentialTest.java:13:14:13:20 | "admin" : String | FileCredentialTest.java:19:13:19:13 | u : String | +| FileCredentialTest.java:19:13:19:13 | u : String | FileCredentialTest.java:22:38:22:45 | v : String | +| FileCredentialTest.java:22:38:22:45 | v : String | FileCredentialTest.java:23:36:23:36 | v | +| Test.java:9:16:9:22 | "admin" : String | Test.java:12:13:12:15 | usr : String | +| Test.java:9:16:9:22 | "admin" : String | Test.java:15:36:15:38 | usr | +| Test.java:9:16:9:22 | "admin" : String | Test.java:17:39:17:41 | usr | +| Test.java:9:16:9:22 | "admin" : String | Test.java:18:39:18:41 | usr | +| Test.java:10:17:10:24 | "123456" : String | Test.java:12:18:12:21 | pass : String | +| Test.java:10:17:10:24 | "123456" : String | Test.java:15:41:15:44 | pass | +| Test.java:10:17:10:24 | "123456" : String | Test.java:18:44:18:61 | toCharArray(...) | +| Test.java:12:13:12:15 | usr : String | Test.java:29:38:29:48 | user : String | +| Test.java:12:18:12:21 | pass : String | Test.java:29:51:29:65 | password : String | +| Test.java:17:44:17:51 | "123456" : String | Test.java:17:44:17:65 | toCharArray(...) | +| Test.java:20:16:20:39 | new byte[] : byte[] | Test.java:21:78:21:80 | key | +| Test.java:23:17:23:26 | "abcdefgh" : String | Test.java:24:79:24:82 | key2 | +| Test.java:29:38:29:48 | user : String | Test.java:30:36:30:39 | user | +| Test.java:29:51:29:65 | password : String | Test.java:30:42:30:49 | password | nodes -| CredentialsTest.java:7:34:7:41 | "123456" [ : String] | semmle.label | "123456" [ : String] | -| CredentialsTest.java:11:14:11:20 | "admin" [ : String] | semmle.label | "admin" [ : String] | +| CredentialsTest.java:7:34:7:41 | "123456" : String | semmle.label | "123456" : String | +| CredentialsTest.java:11:14:11:20 | "admin" : String | semmle.label | "admin" : String | | CredentialsTest.java:13:36:13:36 | u | semmle.label | u | | CredentialsTest.java:13:39:13:39 | p | semmle.label | p | -| CredentialsTest.java:14:13:14:13 | u [ : String] | semmle.label | u [ : String] | -| CredentialsTest.java:14:16:14:16 | p [ : String] | semmle.label | p [ : String] | -| CredentialsTest.java:17:38:17:45 | v [ : String] | semmle.label | v [ : String] | -| CredentialsTest.java:17:48:17:55 | q [ : String] | semmle.label | q [ : String] | +| CredentialsTest.java:14:13:14:13 | u : String | semmle.label | u : String | +| CredentialsTest.java:14:16:14:16 | p : String | semmle.label | p : String | +| CredentialsTest.java:17:38:17:45 | v : String | semmle.label | v : String | +| CredentialsTest.java:17:48:17:55 | q : String | semmle.label | q : String | | CredentialsTest.java:18:36:18:36 | v | semmle.label | v | | CredentialsTest.java:18:39:18:39 | q | semmle.label | q | -| FileCredentialTest.java:13:14:13:20 | "admin" [ : String] | semmle.label | "admin" [ : String] | +| FileCredentialTest.java:13:14:13:20 | "admin" : String | semmle.label | "admin" : String | | FileCredentialTest.java:18:35:18:41 | "admin" | semmle.label | "admin" | -| FileCredentialTest.java:19:13:19:13 | u [ : String] | semmle.label | u [ : String] | -| FileCredentialTest.java:22:38:22:45 | v [ : String] | semmle.label | v [ : String] | +| FileCredentialTest.java:19:13:19:13 | u : String | semmle.label | u : String | +| FileCredentialTest.java:22:38:22:45 | v : String | semmle.label | v : String | | FileCredentialTest.java:23:36:23:36 | v | semmle.label | v | -| Test.java:9:16:9:22 | "admin" [ : String] | semmle.label | "admin" [ : String] | -| Test.java:10:17:10:24 | "123456" [ : String] | semmle.label | "123456" [ : String] | -| Test.java:12:13:12:15 | usr [ : String] | semmle.label | usr [ : String] | -| Test.java:12:18:12:21 | pass [ : String] | semmle.label | pass [ : String] | +| Test.java:9:16:9:22 | "admin" : String | semmle.label | "admin" : String | +| Test.java:10:17:10:24 | "123456" : String | semmle.label | "123456" : String | +| Test.java:12:13:12:15 | usr : String | semmle.label | usr : String | +| Test.java:12:18:12:21 | pass : String | semmle.label | pass : String | | Test.java:14:36:14:42 | "admin" | semmle.label | "admin" | | Test.java:14:45:14:52 | "123456" | semmle.label | "123456" | | Test.java:15:36:15:38 | usr | semmle.label | usr | | Test.java:15:41:15:44 | pass | semmle.label | pass | | Test.java:17:39:17:41 | usr | semmle.label | usr | -| Test.java:17:44:17:51 | "123456" [ : String] | semmle.label | "123456" [ : String] | +| Test.java:17:44:17:51 | "123456" : String | semmle.label | "123456" : String | | Test.java:17:44:17:65 | toCharArray(...) | semmle.label | toCharArray(...) | | Test.java:18:39:18:41 | usr | semmle.label | usr | | Test.java:18:44:18:61 | toCharArray(...) | semmle.label | toCharArray(...) | -| Test.java:20:16:20:39 | new byte[] [ : byte[]] | semmle.label | new byte[] [ : byte[]] | +| Test.java:20:16:20:39 | new byte[] : byte[] | semmle.label | new byte[] : byte[] | | Test.java:21:78:21:80 | key | semmle.label | key | -| Test.java:23:17:23:26 | "abcdefgh" [ : String] | semmle.label | "abcdefgh" [ : String] | +| Test.java:23:17:23:26 | "abcdefgh" : String | semmle.label | "abcdefgh" : String | | Test.java:24:79:24:82 | key2 | semmle.label | key2 | -| Test.java:29:38:29:48 | user [ : String] | semmle.label | user [ : String] | -| Test.java:29:51:29:65 | password [ : String] | semmle.label | password [ : String] | +| Test.java:29:38:29:48 | user : String | semmle.label | user : String | +| Test.java:29:51:29:65 | password : String | semmle.label | password : String | | Test.java:30:36:30:39 | user | semmle.label | user | | Test.java:30:42:30:49 | password | semmle.label | password | #select -| CredentialsTest.java:7:34:7:41 | "123456" | CredentialsTest.java:7:34:7:41 | "123456" [ : String] | CredentialsTest.java:13:39:13:39 | p | Hard-coded value flows to $@. | CredentialsTest.java:13:39:13:39 | p | sensitive API call | -| CredentialsTest.java:7:34:7:41 | "123456" | CredentialsTest.java:7:34:7:41 | "123456" [ : String] | CredentialsTest.java:18:39:18:39 | q | Hard-coded value flows to $@. | CredentialsTest.java:18:39:18:39 | q | sensitive API call | -| CredentialsTest.java:11:14:11:20 | "admin" | CredentialsTest.java:11:14:11:20 | "admin" [ : String] | CredentialsTest.java:13:36:13:36 | u | Hard-coded value flows to $@. | CredentialsTest.java:13:36:13:36 | u | sensitive API call | -| CredentialsTest.java:11:14:11:20 | "admin" | CredentialsTest.java:11:14:11:20 | "admin" [ : String] | CredentialsTest.java:18:36:18:36 | v | Hard-coded value flows to $@. | CredentialsTest.java:18:36:18:36 | v | sensitive API call | -| FileCredentialTest.java:13:14:13:20 | "admin" | FileCredentialTest.java:13:14:13:20 | "admin" [ : String] | FileCredentialTest.java:23:36:23:36 | v | Hard-coded value flows to $@. | FileCredentialTest.java:23:36:23:36 | v | sensitive API call | +| CredentialsTest.java:7:34:7:41 | "123456" | CredentialsTest.java:7:34:7:41 | "123456" : String | CredentialsTest.java:13:39:13:39 | p | Hard-coded value flows to $@. | CredentialsTest.java:13:39:13:39 | p | sensitive API call | +| CredentialsTest.java:7:34:7:41 | "123456" | CredentialsTest.java:7:34:7:41 | "123456" : String | CredentialsTest.java:18:39:18:39 | q | Hard-coded value flows to $@. | CredentialsTest.java:18:39:18:39 | q | sensitive API call | +| CredentialsTest.java:11:14:11:20 | "admin" | CredentialsTest.java:11:14:11:20 | "admin" : String | CredentialsTest.java:13:36:13:36 | u | Hard-coded value flows to $@. | CredentialsTest.java:13:36:13:36 | u | sensitive API call | +| CredentialsTest.java:11:14:11:20 | "admin" | CredentialsTest.java:11:14:11:20 | "admin" : String | CredentialsTest.java:18:36:18:36 | v | Hard-coded value flows to $@. | CredentialsTest.java:18:36:18:36 | v | sensitive API call | +| FileCredentialTest.java:13:14:13:20 | "admin" | FileCredentialTest.java:13:14:13:20 | "admin" : String | FileCredentialTest.java:23:36:23:36 | v | Hard-coded value flows to $@. | FileCredentialTest.java:23:36:23:36 | v | sensitive API call | | FileCredentialTest.java:18:35:18:41 | "admin" | FileCredentialTest.java:18:35:18:41 | "admin" | FileCredentialTest.java:18:35:18:41 | "admin" | Hard-coded value flows to $@. | FileCredentialTest.java:18:35:18:41 | "admin" | sensitive API call | -| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" [ : String] | Test.java:15:36:15:38 | usr | Hard-coded value flows to $@. | Test.java:15:36:15:38 | usr | sensitive API call | -| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" [ : String] | Test.java:17:39:17:41 | usr | Hard-coded value flows to $@. | Test.java:17:39:17:41 | usr | sensitive API call | -| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" [ : String] | Test.java:18:39:18:41 | usr | Hard-coded value flows to $@. | Test.java:18:39:18:41 | usr | sensitive API call | -| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" [ : String] | Test.java:30:36:30:39 | user | Hard-coded value flows to $@. | Test.java:30:36:30:39 | user | sensitive API call | -| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" [ : String] | Test.java:15:41:15:44 | pass | Hard-coded value flows to $@. | Test.java:15:41:15:44 | pass | sensitive API call | -| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" [ : String] | Test.java:18:44:18:61 | toCharArray(...) | Hard-coded value flows to $@. | Test.java:18:44:18:61 | toCharArray(...) | sensitive API call | -| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" [ : String] | Test.java:30:42:30:49 | password | Hard-coded value flows to $@. | Test.java:30:42:30:49 | password | sensitive API call | +| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:15:36:15:38 | usr | Hard-coded value flows to $@. | Test.java:15:36:15:38 | usr | sensitive API call | +| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:17:39:17:41 | usr | Hard-coded value flows to $@. | Test.java:17:39:17:41 | usr | sensitive API call | +| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:18:39:18:41 | usr | Hard-coded value flows to $@. | Test.java:18:39:18:41 | usr | sensitive API call | +| Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:30:36:30:39 | user | Hard-coded value flows to $@. | Test.java:30:36:30:39 | user | sensitive API call | +| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" : String | Test.java:15:41:15:44 | pass | Hard-coded value flows to $@. | Test.java:15:41:15:44 | pass | sensitive API call | +| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" : String | Test.java:18:44:18:61 | toCharArray(...) | Hard-coded value flows to $@. | Test.java:18:44:18:61 | toCharArray(...) | sensitive API call | +| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" : String | Test.java:30:42:30:49 | password | Hard-coded value flows to $@. | Test.java:30:42:30:49 | password | sensitive API call | | Test.java:14:36:14:42 | "admin" | Test.java:14:36:14:42 | "admin" | Test.java:14:36:14:42 | "admin" | Hard-coded value flows to $@. | Test.java:14:36:14:42 | "admin" | sensitive API call | | Test.java:14:45:14:52 | "123456" | Test.java:14:45:14:52 | "123456" | Test.java:14:45:14:52 | "123456" | Hard-coded value flows to $@. | Test.java:14:45:14:52 | "123456" | sensitive API call | -| Test.java:17:44:17:51 | "123456" | Test.java:17:44:17:51 | "123456" [ : String] | Test.java:17:44:17:65 | toCharArray(...) | Hard-coded value flows to $@. | Test.java:17:44:17:65 | toCharArray(...) | sensitive API call | -| Test.java:20:16:20:39 | new byte[] | Test.java:20:16:20:39 | new byte[] [ : byte[]] | Test.java:21:78:21:80 | key | Hard-coded value flows to $@. | Test.java:21:78:21:80 | key | sensitive API call | -| Test.java:23:17:23:26 | "abcdefgh" | Test.java:23:17:23:26 | "abcdefgh" [ : String] | Test.java:24:79:24:82 | key2 | Hard-coded value flows to $@. | Test.java:24:79:24:82 | key2 | sensitive API call | +| Test.java:17:44:17:51 | "123456" | Test.java:17:44:17:51 | "123456" : String | Test.java:17:44:17:65 | toCharArray(...) | Hard-coded value flows to $@. | Test.java:17:44:17:65 | toCharArray(...) | sensitive API call | +| Test.java:20:16:20:39 | new byte[] | Test.java:20:16:20:39 | new byte[] : byte[] | Test.java:21:78:21:80 | key | Hard-coded value flows to $@. | Test.java:21:78:21:80 | key | sensitive API call | +| Test.java:23:17:23:26 | "abcdefgh" | Test.java:23:17:23:26 | "abcdefgh" : String | Test.java:24:79:24:82 | key2 | Hard-coded value flows to $@. | Test.java:24:79:24:82 | key2 | sensitive API call | diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected index fb2349a5500..05e47dacf3f 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected @@ -1,11 +1,11 @@ edges -| Test.java:10:17:10:24 | "123456" [ : String] | Test.java:26:17:26:20 | pass | -| User.java:2:43:2:50 | "123456" [ : String] | User.java:5:15:5:24 | DEFAULT_PW | +| Test.java:10:17:10:24 | "123456" : String | Test.java:26:17:26:20 | pass | +| User.java:2:43:2:50 | "123456" : String | User.java:5:15:5:24 | DEFAULT_PW | nodes -| Test.java:10:17:10:24 | "123456" [ : String] | semmle.label | "123456" [ : String] | +| Test.java:10:17:10:24 | "123456" : String | semmle.label | "123456" : String | | Test.java:26:17:26:20 | pass | semmle.label | pass | -| User.java:2:43:2:50 | "123456" [ : String] | semmle.label | "123456" [ : String] | +| User.java:2:43:2:50 | "123456" : String | semmle.label | "123456" : String | | User.java:5:15:5:24 | DEFAULT_PW | semmle.label | DEFAULT_PW | #select -| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" [ : String] | Test.java:26:17:26:20 | pass | Hard-coded value flows to $@. | Test.java:26:17:26:20 | pass | sensitive call | -| User.java:2:43:2:50 | "123456" | User.java:2:43:2:50 | "123456" [ : String] | User.java:5:15:5:24 | DEFAULT_PW | Hard-coded value flows to $@. | User.java:5:15:5:24 | DEFAULT_PW | sensitive call | +| Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" : String | Test.java:26:17:26:20 | pass | Hard-coded value flows to $@. | Test.java:26:17:26:20 | pass | sensitive call | +| User.java:2:43:2:50 | "123456" | User.java:2:43:2:50 | "123456" : String | User.java:5:15:5:24 | DEFAULT_PW | Hard-coded value flows to $@. | User.java:5:15:5:24 | DEFAULT_PW | sensitive call | diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected index 21f1d4fb027..efa1016bbb7 100644 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected @@ -1,24 +1,24 @@ edges -| Test.java:17:26:17:38 | args [ : String[]] | Test.java:25:6:25:21 | ... == ... | -| Test.java:31:6:31:27 | getValue(...) [ : String] | Test.java:31:6:31:43 | equals(...) | -| Test.java:36:6:36:27 | getValue(...) [ : String] | Test.java:36:6:36:36 | ... == ... | -| Test.java:81:6:81:27 | getValue(...) [ : String] | Test.java:81:6:81:36 | ... == ... | -| Test.java:91:6:91:27 | getValue(...) [ : String] | Test.java:91:6:91:36 | ... == ... | +| Test.java:17:26:17:38 | args : String[] | Test.java:25:6:25:21 | ... == ... | +| Test.java:31:6:31:27 | getValue(...) : String | Test.java:31:6:31:43 | equals(...) | +| Test.java:36:6:36:27 | getValue(...) : String | Test.java:36:6:36:36 | ... == ... | +| Test.java:81:6:81:27 | getValue(...) : String | Test.java:81:6:81:36 | ... == ... | +| Test.java:91:6:91:27 | getValue(...) : String | Test.java:91:6:91:36 | ... == ... | nodes -| Test.java:17:26:17:38 | args [ : String[]] | semmle.label | args [ : String[]] | +| Test.java:17:26:17:38 | args : String[] | semmle.label | args : String[] | | Test.java:25:6:25:21 | ... == ... | semmle.label | ... == ... | -| Test.java:31:6:31:27 | getValue(...) [ : String] | semmle.label | getValue(...) [ : String] | +| Test.java:31:6:31:27 | getValue(...) : String | semmle.label | getValue(...) : String | | Test.java:31:6:31:43 | equals(...) | semmle.label | equals(...) | -| Test.java:36:6:36:27 | getValue(...) [ : String] | semmle.label | getValue(...) [ : String] | +| Test.java:36:6:36:27 | getValue(...) : String | semmle.label | getValue(...) : String | | Test.java:36:6:36:36 | ... == ... | semmle.label | ... == ... | -| Test.java:81:6:81:27 | getValue(...) [ : String] | semmle.label | getValue(...) [ : String] | +| Test.java:81:6:81:27 | getValue(...) : String | semmle.label | getValue(...) : String | | Test.java:81:6:81:36 | ... == ... | semmle.label | ... == ... | -| Test.java:91:6:91:27 | getValue(...) [ : String] | semmle.label | getValue(...) [ : String] | +| Test.java:91:6:91:27 | getValue(...) : String | semmle.label | getValue(...) : String | | Test.java:91:6:91:36 | ... == ... | semmle.label | ... == ... | #select -| Test.java:26:4:26:24 | login(...) | Test.java:17:26:17:38 | args [ : String[]] | Test.java:25:6:25:21 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:25:6:25:21 | ... == ... | this condition | Test.java:17:26:17:38 | args | user input | -| Test.java:32:4:32:24 | login(...) | Test.java:31:6:31:27 | getValue(...) [ : String] | Test.java:31:6:31:43 | equals(...) | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:31:6:31:43 | equals(...) | this condition | Test.java:31:6:31:27 | getValue(...) | user input | -| Test.java:37:4:37:24 | login(...) | Test.java:36:6:36:27 | getValue(...) [ : String] | Test.java:36:6:36:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:36:6:36:36 | ... == ... | this condition | Test.java:36:6:36:27 | getValue(...) | user input | -| Test.java:39:4:39:30 | reCheckAuth(...) | Test.java:36:6:36:27 | getValue(...) [ : String] | Test.java:36:6:36:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:36:6:36:36 | ... == ... | this condition | Test.java:36:6:36:27 | getValue(...) | user input | -| Test.java:82:4:82:24 | login(...) | Test.java:81:6:81:27 | getValue(...) [ : String] | Test.java:81:6:81:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:81:6:81:36 | ... == ... | this condition | Test.java:81:6:81:27 | getValue(...) | user input | -| Test.java:92:4:92:24 | login(...) | Test.java:91:6:91:27 | getValue(...) [ : String] | Test.java:91:6:91:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:91:6:91:36 | ... == ... | this condition | Test.java:91:6:91:27 | getValue(...) | user input | +| Test.java:26:4:26:24 | login(...) | Test.java:17:26:17:38 | args : String[] | Test.java:25:6:25:21 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:25:6:25:21 | ... == ... | this condition | Test.java:17:26:17:38 | args | user input | +| Test.java:32:4:32:24 | login(...) | Test.java:31:6:31:27 | getValue(...) : String | Test.java:31:6:31:43 | equals(...) | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:31:6:31:43 | equals(...) | this condition | Test.java:31:6:31:27 | getValue(...) | user input | +| Test.java:37:4:37:24 | login(...) | Test.java:36:6:36:27 | getValue(...) : String | Test.java:36:6:36:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:36:6:36:36 | ... == ... | this condition | Test.java:36:6:36:27 | getValue(...) | user input | +| Test.java:39:4:39:30 | reCheckAuth(...) | Test.java:36:6:36:27 | getValue(...) : String | Test.java:36:6:36:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:36:6:36:36 | ... == ... | this condition | Test.java:36:6:36:27 | getValue(...) | user input | +| Test.java:82:4:82:24 | login(...) | Test.java:81:6:81:27 | getValue(...) : String | Test.java:81:6:81:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:81:6:81:36 | ... == ... | this condition | Test.java:81:6:81:27 | getValue(...) | user input | +| Test.java:92:4:92:24 | login(...) | Test.java:91:6:91:27 | getValue(...) : String | Test.java:91:6:91:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:91:6:91:36 | ... == ... | this condition | Test.java:91:6:91:27 | getValue(...) | user input | diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected index 7e861539eca..39d8074bf36 100644 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected @@ -1,7 +1,7 @@ edges -| Test.java:17:26:17:38 | args [ : String[]] | Test.java:50:26:50:64 | ... + ... | +| Test.java:17:26:17:38 | args : String[] | Test.java:50:26:50:64 | ... + ... | nodes -| Test.java:17:26:17:38 | args [ : String[]] | semmle.label | args [ : String[]] | +| Test.java:17:26:17:38 | args : String[] | semmle.label | args : String[] | | Test.java:50:26:50:64 | ... + ... | semmle.label | ... + ... | #select -| Test.java:50:6:50:65 | isPermitted(...) | Test.java:17:26:17:38 | args [ : String[]] | Test.java:50:26:50:64 | ... + ... | Permissions check uses user-controlled $@. | Test.java:17:26:17:38 | args | data | +| Test.java:50:6:50:65 | isPermitted(...) | Test.java:17:26:17:38 | args : String[] | Test.java:50:26:50:64 | ... + ... | Permissions check uses user-controlled $@. | Test.java:17:26:17:38 | args | data | From c8d60c9e2a14739b9554ff3649e25bd9188b0abc Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 4 Oct 2019 11:40:33 +0200 Subject: [PATCH 0371/1227] update @description of js/suspicious-method-name-declaration --- .../ql/src/Declarations/SuspiciousMethodNameDeclaration.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index a8a068ffa9f..0bc67bea817 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -1,7 +1,7 @@ /** * @name Suspicious method name declaration - * @description Declaring a class or interface method with a special name may cause a normal - * named method to be declared when a special type was expected. + * @description A method declaration with a name that would be a special keyword in another + * context is suspicious. * @kind problem * @problem.severity warning * @id js/suspicious-method-name-declaration From a7641a8765fe76fad127da84211588a3ff078a2f Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Fri, 4 Oct 2019 14:33:04 +0200 Subject: [PATCH 0372/1227] C++: Clarify OutNode and ReturnNode QLDoc --- .../src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index 7b180c183b2..eac7642cacd 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -70,7 +70,7 @@ class ReturnKind extends TReturnKind { } } -/** A data flow node that represents a returned value. */ +/** A data flow node that represents a returned value in the called function. */ abstract class ReturnNode extends Node { /** Gets the kind of this returned value. */ abstract ReturnKind getKind(); @@ -93,7 +93,7 @@ private class RefReturnNode extends ReturnNode, RefParameterFinalValueNode { override ReturnKind getKind() { result = TRefReturnKind(this.getParameter().getIndex()) } } -/** A data flow node that represents the output of a call. */ +/** A data flow node that represents the output of a call at the call site. */ abstract class OutNode extends Node { /** Gets the underlying call. */ abstract DataFlowCall getCall(); From b741a65e9bed1e416ad18dafc3f53c7505e000db Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <54990334+erik-krogh@users.noreply.github.com> Date: Fri, 4 Oct 2019 14:42:16 +0200 Subject: [PATCH 0373/1227] documentation changes based on review Co-Authored-By: shati-patel <42641846+shati-patel@users.noreply.github.com> --- .../Declarations/SuspiciousMethodNameDeclaration.qhelp | 10 +++++----- .../Declarations/SuspiciousMethodNameDeclaration.ql | 2 +- .../SuspiciousMethodNameDeclaration/tst.ts | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp index 66e6e9404e2..2987f5dab1e 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp @@ -8,10 +8,10 @@ In TypeScript the keywords constructor and new for member declarations are used to declare constructors in classes and interfaces respectively. However, a member declaration with the name new in an interface -or constructor in a class, will declare ordinary methods named -new or constructor rather than constructors. +or constructor in a class, will declare an ordinary method named +new or constructor rather than a constructor. Similarly, the keyword function is used to declare functions in -some contexts, however, using the name function for a class +some contexts. However, using the name function for a class or interface member declaration declares a method named function.

    @@ -48,8 +48,8 @@ in the first place. -
  • TypeScript specification: Constructor Type Literals
  • -
  • TypeScript specification: Constructor Parameters
  • +
  • TypeScript specification: Constructor Type Literals.
  • +
  • TypeScript specification: Constructor Parameters.
  • diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index 0bc67bea817..ae219bb2d27 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -1,6 +1,6 @@ /** * @name Suspicious method name declaration - * @description A method declaration with a name that would be a special keyword in another + * @description A method declaration with a name that is a special keyword in another * context is suspicious. * @kind problem * @problem.severity warning diff --git a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/tst.ts b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/tst.ts index daf9db3192c..2db4457c222 100644 --- a/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/tst.ts +++ b/javascript/ql/test/query-tests/Declarations/SuspiciousMethodNameDeclaration/tst.ts @@ -2,7 +2,7 @@ var foo: MyInterface = 123 as any; interface MyInterface { function (): number; // OK. Highly unlikely that it is an accident when there are other named methods in the interface. - (): number; // OK: What was probaly meant above. + (): number; // OK: What was probably meant above. new:() => void; // OK! This is a property, not a method, we ignore those. constructor(): string; // NOT OK! This a called "constructor" new(): Date; // OK! This a constructor signature. @@ -49,4 +49,4 @@ declare class Quz { } var bla = new Foo(); -var blab = new Baz(); \ No newline at end of file +var blab = new Baz(); From bf1fd838511fc065004e990cc8b381343e69a1b1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 4 Oct 2019 15:04:39 +0200 Subject: [PATCH 0374/1227] fix typo in predicate name --- .../ql/src/Declarations/SuspiciousMethodNameDeclaration.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index ae219bb2d27..79def98a0fd 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -16,7 +16,7 @@ import javascript /** * Holds if the method name on the given container is likely to be a mistake. */ -predicate isSuspisousMethodName(string name, ClassOrInterface container) { +predicate isSuspiciousMethodName(string name, ClassOrInterface container) { name = "function" or // "constructor" is only suspicious outside a class. @@ -30,7 +30,7 @@ from MethodDeclaration member, ClassOrInterface container, string name, string m where container.getLocation().getFile().getFileType().isTypeScript() and container.getMember(name) = member and - isSuspisousMethodName(name, container) and + isSuspiciousMethodName(name, container) and // Cases to ignore. not ( From 066a2f0d129511f26becddac560ee53b260c61e8 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 4 Oct 2019 14:28:46 +0200 Subject: [PATCH 0375/1227] Java: Add another overflow check pattern to UselessComparisonTest. --- .../Comparison/UselessComparisonTest.ql | 31 ++++++++++++------- .../query-tests/UselessComparisonTest/A.java | 20 ++++++++++++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql b/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql index d6c1e205668..4bb5287053b 100644 --- a/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql +++ b/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql @@ -134,34 +134,41 @@ Expr overFlowCand() { result.(LocalVariableDeclExpr).getInit() = overFlowCand() } -/** Gets an expression that equals `v` plus a positive value. */ -Expr increaseOfVar(SsaVariable v) { +predicate positiveOrNegative(Expr e) { positive(e) or negative(e) } + +/** Gets an expression that equals `v` plus a positive or negative value. */ +Expr increaseOrDecreaseOfVar(SsaVariable v) { exists(AssignAddExpr add | result = add and - positive(add.getDest()) and + positiveOrNegative(add.getDest()) and add.getRhs() = v.getAUse() ) or exists(AddExpr add, Expr e | result = add and add.hasOperands(v.getAUse(), e) and - positive(e) + positiveOrNegative(e) ) or - exists(SsaExplicitUpdate x | result = x.getAUse() and x.getDefiningExpr() = increaseOfVar(v)) + exists(SubExpr sub | + result = sub and + sub.getLeftOperand() = v.getAUse() and + positiveOrNegative(sub.getRightOperand()) + ) or - result.(ParExpr).getExpr() = increaseOfVar(v) + exists(SsaExplicitUpdate x | + result = x.getAUse() and x.getDefiningExpr() = increaseOrDecreaseOfVar(v) + ) or - result.(AssignExpr).getRhs() = increaseOfVar(v) + result.(ParExpr).getExpr() = increaseOrDecreaseOfVar(v) or - result.(LocalVariableDeclExpr).getInit() = increaseOfVar(v) + result.(AssignExpr).getRhs() = increaseOrDecreaseOfVar(v) + or + result.(LocalVariableDeclExpr).getInit() = increaseOrDecreaseOfVar(v) } predicate overFlowTest(ComparisonExpr comp) { - exists(SsaVariable v | - comp.getLesserOperand() = increaseOfVar(v) and - comp.getGreaterOperand() = v.getAUse() - ) + exists(SsaVariable v | comp.hasOperands(increaseOrDecreaseOfVar(v), v.getAUse())) or comp.getLesserOperand() = overFlowCand() and comp.getGreaterOperand().(IntegerLiteral).getIntValue() = 0 diff --git a/java/ql/test/query-tests/UselessComparisonTest/A.java b/java/ql/test/query-tests/UselessComparisonTest/A.java index 2165b6c452c..f2b473c2ee3 100644 --- a/java/ql/test/query-tests/UselessComparisonTest/A.java +++ b/java/ql/test/query-tests/UselessComparisonTest/A.java @@ -121,6 +121,26 @@ public class A { } } + static final long VAL = 100L; + + long overflowAwareIncrease(long x) { + if (x + VAL > x) { + return x + VAL; + } else { + overflow(); + return Long.MAX_VALUE; + } + } + + long overflowAwareDecrease(long x) { + if (x - VAL < x) { + return x - VAL; + } else { + overflow(); + return Long.MIN_VALUE; + } + } + void overflow() { } void unreachableCode() { From 144e83151594da9475b9fcd9728cab839e8be46a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 4 Oct 2019 15:05:11 +0200 Subject: [PATCH 0376/1227] mention that "function" should not be used when declaring a call signature in an interface --- .../ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp index 2987f5dab1e..d47f11d95f0 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.qhelp @@ -22,8 +22,8 @@ or interface member declaration declares a method named function. Declare classes as classes and not as interfaces. Use the keyword constructor to declare constructors in a class, use the keyword new to declare constructors inside interfaces, -and don't use function when declaring an interface that is a -function. +and don't use function when declaring a call signature in an +interface.

    From 14cc352bd95917fe6d892fcdf56b7599471bb5de Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 4 Oct 2019 15:26:32 +0200 Subject: [PATCH 0377/1227] small documentation change based on review --- .../ql/src/Declarations/SuspiciousMethodNameDeclaration.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql index 79def98a0fd..febdd7ab5ea 100644 --- a/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql +++ b/javascript/ql/src/Declarations/SuspiciousMethodNameDeclaration.ql @@ -60,7 +60,7 @@ where and ( - name = "constructor" and msg = "The member name 'constructor' does not declare a constructor in interface declarations, but it does in class declarations." + name = "constructor" and msg = "The member name 'constructor' does not declare a constructor in interfaces, but it does in classes." or name = "new" and msg = "The member name 'new' does not declare a constructor, but 'constructor' does in class declarations." or From ba6eb22cc9cb944176a6c9260ace86b3e1ab06a0 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 4 Oct 2019 16:28:28 +0100 Subject: [PATCH 0378/1227] C#: Roslyn workaround for when IPropertySymbol.IsIndexer seems to be working incorrectly. --- csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index 671f41cd266..27080f4cae9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -111,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities public static Property Create(Context cx, IPropertySymbol prop) { - bool isIndexer = prop.IsIndexer || prop.ExplicitInterfaceImplementations.Any(e => e.IsIndexer); + bool isIndexer = prop.IsIndexer || prop.ExplicitInterfaceImplementations.Any(e => e.IsIndexer) || prop.Parameters.Any(); return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntity(cx, prop); } From af25536648c2c74c77b236d89717687b6ada4676 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 4 Oct 2019 16:46:02 +0100 Subject: [PATCH 0379/1227] C#: Add localExprFlow and localExprTaint, and change notes. --- change-notes/1.23/analysis-csharp.md | 3 +++ .../code/csharp/dataflow/internal/DataFlowPublic.qll | 6 ++++++ .../code/csharp/dataflow/internal/TaintTrackingPublic.qll | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/change-notes/1.23/analysis-csharp.md b/change-notes/1.23/analysis-csharp.md index 7836345fdf6..7ec412a0eb2 100644 --- a/change-notes/1.23/analysis-csharp.md +++ b/change-notes/1.23/analysis-csharp.md @@ -40,5 +40,8 @@ The following changes in version 1.23 affect C# analysis in all applications. overriding `int explorationLimit()`. * `foreach` statements where the body is guaranteed to be executed at least once, such as `foreach (var x in new string[]{ "a", "b", "c" }) { ... }`, are now recognized by all analyses based on the control flow graph (such as SSA, data flow and taint tracking). * Fixed the control flow graph for `switch` statements where the `default` case was not the last case. This had caused the remaining cases to be unreachable. `SwitchStmt.getCase(int i)` now puts the `default` case last. +* There is now a `DataFlow::localExprFlow` predicate and a + `TaintTracking::localExprTaint` predicate to make it easy to use the most + common case of local data flow and taint: from one `Expr` to another. ## Changes to autobuilder diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index 46680761e35..4b28170e07a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -164,6 +164,12 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { */ predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } +/** + * Holds if data can flow from `e1` to `e2` in zero or more + * local (intra-procedural) steps. + */ +predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) } + /** * A data flow node that jumps between callables. This can be extended in * framework code to add additional data flow steps. diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll index 165172be2a6..eda33f2fcd9 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll @@ -7,6 +7,14 @@ private import TaintTrackingPrivate */ predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) } +/** + * Holds if taint can flow from `e1` to `e2` in zero or more + * local (intra-procedural) steps. + */ +predicate localExprTaint(Expr e1, Expr e2) { + localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2)) +} + /** A member (property or field) that is tainted if its containing object is tainted. */ abstract class TaintedMember extends AssignableMember { } From 27062384135af58f3e82259fd0c9026826f50fba Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 4 Oct 2019 16:53:02 +0100 Subject: [PATCH 0380/1227] C#: Update queries to use localExprFlow. --- .../Implementation Hiding/ExposeRepresentation.ql | 2 +- csharp/ql/src/Dead Code/DeadStoreOfLocal.ql | 2 +- .../CWE-119/LocalUnvalidatedArithmetic.ql | 4 ++-- csharp/ql/src/semmle/code/csharp/Property.qll | 2 +- csharp/ql/src/semmle/code/csharp/frameworks/system/Xml.qll | 2 +- .../csharp/frameworks/system/text/RegularExpressions.qll | 2 +- .../src/semmle/code/csharp/security/dataflow/ZipSlip.qll | 2 +- .../ql/src/semmle/code/csharp/security/xml/InsecureXML.qll | 7 ++----- 8 files changed, 10 insertions(+), 13 deletions(-) diff --git a/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql b/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql index 3847eae6e82..26327ed6d87 100644 --- a/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql +++ b/csharp/ql/src/Bad Practices/Implementation Hiding/ExposeRepresentation.ql @@ -32,7 +32,7 @@ predicate returnsCollection(Callable c, Field f) { predicate mayWriteToCollection(Expr modified) { modified instanceof CollectionModificationAccess or - exists(Expr mid | mayWriteToCollection(mid) | localFlow(exprNode(modified), exprNode(mid))) + exists(Expr mid | mayWriteToCollection(mid) | localExprFlow(modified, mid)) or exists(MethodCall mid, Callable c | mayWriteToCollection(mid) | mid.getTarget() = c and diff --git a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql index 74fa9b28c0e..ac6b258f0be 100644 --- a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql +++ b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql @@ -62,7 +62,7 @@ predicate nonEscapingCall(Call c) { predicate mayEscape(LocalVariable v) { exists(Callable c, Expr e, Expr succ | c = getACapturingCallableAncestor(v) | e = getADelegateExpr(c) and - DataFlow::localFlow(DataFlow::exprNode(e), DataFlow::exprNode(succ)) and + DataFlow::localExprFlow(e, succ) and not succ = any(DelegateCall dc).getDelegateExpr() and not succ = any(Cast cast).getExpr() and not succ = any(Call call | nonEscapingCall(call)).getAnArgument() and diff --git a/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql b/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql index 9dca3ce9781..d57bf934950 100644 --- a/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql +++ b/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql @@ -22,10 +22,10 @@ where // `add` is performing pointer arithmetic add.getType() instanceof PointerType and // one of the operands comes, in zero or more steps, from a virtual method call - DataFlow::localFlow(DataFlow::exprNode(taintSrc), DataFlow::exprNode(add.getAnOperand())) and + DataFlow::localExprFlow(taintSrc, add.getAnOperand()) and // virtual method call result has not been validated not exists(Expr check, ComparisonOperation cmp | - DataFlow::localFlow(DataFlow::exprNode(taintSrc), DataFlow::exprNode(check)) + DataFlow::localExprFlow(taintSrc, check) | cmp.getAnOperand() = check and add.getAnOperand().(GuardedExpr).isGuardedBy(cmp, check, _) diff --git a/csharp/ql/src/semmle/code/csharp/Property.qll b/csharp/ql/src/semmle/code/csharp/Property.qll index d1f15e1152a..d7013927846 100644 --- a/csharp/ql/src/semmle/code/csharp/Property.qll +++ b/csharp/ql/src/semmle/code/csharp/Property.qll @@ -520,7 +520,7 @@ class IndexerProperty extends Property { pragma[nomagic] private IndexerCall getAnIndexerCall0() { exists(Expr qualifier | qualifier = result.getQualifier() | - DataFlow::localFlow(DataFlow::exprNode(this.getAnAccess()), DataFlow::exprNode(qualifier)) + DataFlow::localExprFlow(this.getAnAccess(), qualifier) ) } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/Xml.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/Xml.qll index 38754f4251a..eee5ef27ae1 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/Xml.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/Xml.qll @@ -156,7 +156,7 @@ class XmlReaderSettingsCreation extends ObjectCreation { p = this.getType().(RefType).getAProperty() and exists(PropertyCall set, Expr arg | set.getTarget() = p.getSetter() and - DataFlow::localFlow(DataFlow::exprNode(this), DataFlow::exprNode(set.getQualifier())) and + DataFlow::localExprFlow(this, set.getQualifier()) and arg = set.getAnArgument() and result = getBitwiseOrOperand*(arg) ) diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll index 0914499fd0d..ce03f5275d9 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll @@ -71,7 +71,7 @@ class RegexOperation extends Call { | // e.g. `new Regex(...).Match(...)` // or `var r = new Regex(...); r.Match(...)` - DataFlow::localFlow(DataFlow::exprNode(this), DataFlow::exprNode(call.getQualifier())) + DataFlow::localExprFlow(this, call.getQualifier()) or // e.g. `private string r = new Regex(...); public void foo() { r.Match(...); }` call.getQualifier().(FieldAccess).getTarget().getInitializer() = this diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll index 30531b57f9e..c2785173be4 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll @@ -142,7 +142,7 @@ module ZipSlip { // not yet been resolved. not exists(MethodCall combineCall | combineCall.getTarget().hasQualifiedName("System.IO.Path", "Combine") and - DataFlow::localFlow(DataFlow::exprNode(combineCall), DataFlow::exprNode(q)) + DataFlow::localExprFlow(combineCall, q) ) } diff --git a/csharp/ql/src/semmle/code/csharp/security/xml/InsecureXML.qll b/csharp/ql/src/semmle/code/csharp/security/xml/InsecureXML.qll index e989f56e65f..c9f738ef997 100644 --- a/csharp/ql/src/semmle/code/csharp/security/xml/InsecureXML.qll +++ b/csharp/ql/src/semmle/code/csharp/security/xml/InsecureXML.qll @@ -87,8 +87,7 @@ module InsecureXML { or // values set on var that create is assigned to exists(Assignment propAssign | - DataFlow::localFlow(DataFlow::exprNode(create), - DataFlow::exprNode(propAssign.getLValue().(PropertyAccess).getQualifier())) and + DataFlow::localExprFlow(create, propAssign.getLValue().(PropertyAccess).getQualifier()) and propAssign.getLValue().(PropertyAccess).getTarget().hasName(prop) and result = propAssign.getRValue() ) @@ -253,9 +252,7 @@ module InsecureXML { } override predicate isUnsafe(string reason) { - exists(ObjectCreation creation | - DataFlow::localFlow(DataFlow::exprNode(creation), DataFlow::exprNode(this.getQualifier())) - | + exists(ObjectCreation creation | DataFlow::localExprFlow(creation, this.getQualifier()) | not exists(Expr xmlResolverVal | isSafeXmlResolver(xmlResolverVal) and xmlResolverVal = getAValueForProp(creation, "XmlResolver") From 050d99fa873026ec0568d4f609597273355184b1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Jul 2019 10:21:37 +0100 Subject: [PATCH 0381/1227] CPP: Add test cases. --- .../dataflow/taint-tests/localTaint.expected | 84 +++++++++++++++++ .../dataflow/taint-tests/taint.cpp | 94 +++++++++++++++++++ .../dataflow/taint-tests/taint.expected | 6 ++ .../dataflow/taint-tests/test_diff.expected | 1 + .../dataflow/taint-tests/test_ir.expected | 5 + 5 files changed, 190 insertions(+) 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 d93bbd617e2..d69cfda1b69 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -227,3 +227,87 @@ | taint.cpp:255:27:255:27 | b | taint.cpp:257:8:257:8 | b | | | taint.cpp:258:7:258:12 | call to source | taint.cpp:258:3:258:14 | ... = ... | | | taint.cpp:260:10:260:10 | ref arg w | taint.cpp:261:7:261:7 | w | | +| taint.cpp:266:12:266:12 | x | taint.cpp:268:9:268:9 | x | | +| taint.cpp:275:6:275:11 | call to source | taint.cpp:275:2:275:13 | ... = ... | | +| taint.cpp:275:6:275:11 | call to source | taint.cpp:280:7:280:7 | t | | +| taint.cpp:275:6:275:11 | call to source | taint.cpp:285:9:285:9 | t | | +| taint.cpp:275:6:275:11 | call to source | taint.cpp:286:12:286:12 | t | | +| taint.cpp:275:6:275:11 | call to source | taint.cpp:289:7:289:7 | t | | +| taint.cpp:276:6:276:6 | 0 | taint.cpp:276:2:276:6 | ... = ... | | +| taint.cpp:276:6:276:6 | 0 | taint.cpp:281:7:281:7 | x | | +| taint.cpp:277:6:277:6 | 0 | taint.cpp:277:2:277:6 | ... = ... | | +| taint.cpp:277:6:277:6 | 0 | taint.cpp:282:7:282:7 | y | | +| taint.cpp:278:6:278:6 | 0 | taint.cpp:278:2:278:6 | ... = ... | | +| taint.cpp:278:6:278:6 | 0 | taint.cpp:283:7:283:7 | z | | +| taint.cpp:278:6:278:6 | 0 | taint.cpp:287:9:287:9 | z | | +| taint.cpp:285:6:285:7 | call to id | taint.cpp:285:2:285:10 | ... = ... | | +| taint.cpp:285:6:285:7 | call to id | taint.cpp:290:7:290:7 | x | | +| taint.cpp:286:6:286:7 | call to id | taint.cpp:286:2:286:14 | ... = ... | | +| taint.cpp:286:6:286:7 | call to id | taint.cpp:291:7:291:7 | y | | +| taint.cpp:287:6:287:7 | call to id | taint.cpp:287:2:287:10 | ... = ... | | +| taint.cpp:287:6:287:7 | call to id | taint.cpp:292:7:292:7 | z | | +| taint.cpp:297:29:297:29 | b | taint.cpp:299:6:299:6 | b | | +| taint.cpp:299:6:299:6 | b | taint.cpp:299:2:299:6 | ... = ... | | +| taint.cpp:302:28:302:28 | b | taint.cpp:304:6:304:6 | b | | +| taint.cpp:304:6:304:6 | b | taint.cpp:304:2:304:6 | ... = ... | | +| taint.cpp:307:21:307:21 | a | taint.cpp:309:3:309:3 | a | | +| taint.cpp:307:28:307:28 | b | taint.cpp:309:7:309:7 | b | | +| taint.cpp:309:3:309:3 | a | taint.cpp:309:2:309:3 | * ... | TAINT | +| taint.cpp:309:7:309:7 | b | taint.cpp:309:2:309:7 | ... = ... | | +| taint.cpp:312:21:312:21 | a | taint.cpp:317:3:317:3 | a | | +| taint.cpp:312:28:312:28 | b | taint.cpp:316:6:316:6 | b | | +| taint.cpp:316:6:316:6 | b | taint.cpp:316:6:316:10 | ... + ... | TAINT | +| taint.cpp:316:6:316:10 | ... + ... | taint.cpp:316:2:316:10 | ... = ... | | +| taint.cpp:316:6:316:10 | ... + ... | taint.cpp:317:7:317:7 | c | | +| taint.cpp:316:10:316:10 | 1 | taint.cpp:316:6:316:10 | ... + ... | TAINT | +| taint.cpp:317:3:317:3 | a | taint.cpp:317:2:317:3 | * ... | TAINT | +| taint.cpp:317:7:317:7 | c | taint.cpp:317:2:317:7 | ... = ... | | +| taint.cpp:320:23:320:23 | a | taint.cpp:322:6:322:6 | a | | +| taint.cpp:320:31:320:31 | b | taint.cpp:323:6:323:6 | b | | +| taint.cpp:322:6:322:6 | a | taint.cpp:322:6:322:10 | ... + ... | TAINT | +| taint.cpp:322:6:322:10 | ... + ... | taint.cpp:322:2:322:10 | ... = ... | | +| taint.cpp:322:10:322:10 | 1 | taint.cpp:322:6:322:10 | ... + ... | TAINT | +| taint.cpp:323:6:323:6 | b | taint.cpp:323:6:323:10 | ... + ... | TAINT | +| taint.cpp:323:6:323:10 | ... + ... | taint.cpp:323:2:323:10 | ... = ... | | +| taint.cpp:323:10:323:10 | 1 | taint.cpp:323:6:323:10 | ... + ... | TAINT | +| taint.cpp:330:6:330:11 | call to source | taint.cpp:330:2:330:13 | ... = ... | | +| taint.cpp:330:6:330:11 | call to source | taint.cpp:337:7:337:7 | t | | +| taint.cpp:330:6:330:11 | call to source | taint.cpp:344:15:344:15 | t | | +| taint.cpp:330:6:330:11 | call to source | taint.cpp:345:15:345:15 | t | | +| taint.cpp:330:6:330:11 | call to source | taint.cpp:346:16:346:16 | t | | +| taint.cpp:330:6:330:11 | call to source | taint.cpp:347:16:347:16 | t | | +| taint.cpp:330:6:330:11 | call to source | taint.cpp:348:17:348:17 | t | | +| taint.cpp:330:6:330:11 | call to source | taint.cpp:350:7:350:7 | t | | +| taint.cpp:331:6:331:6 | 0 | taint.cpp:331:2:331:6 | ... = ... | | +| taint.cpp:331:6:331:6 | 0 | taint.cpp:338:7:338:7 | a | | +| taint.cpp:331:6:331:6 | 0 | taint.cpp:344:12:344:12 | a | | +| taint.cpp:331:6:331:6 | 0 | taint.cpp:351:7:351:7 | a | | +| taint.cpp:332:6:332:6 | 0 | taint.cpp:332:2:332:6 | ... = ... | | +| taint.cpp:332:6:332:6 | 0 | taint.cpp:339:7:339:7 | b | | +| taint.cpp:332:6:332:6 | 0 | taint.cpp:345:12:345:12 | b | | +| taint.cpp:332:6:332:6 | 0 | taint.cpp:352:7:352:7 | b | | +| taint.cpp:333:6:333:6 | 0 | taint.cpp:333:2:333:6 | ... = ... | | +| taint.cpp:333:6:333:6 | 0 | taint.cpp:340:7:340:7 | c | | +| taint.cpp:333:6:333:6 | 0 | taint.cpp:346:13:346:13 | c | | +| taint.cpp:333:6:333:6 | 0 | taint.cpp:353:7:353:7 | c | | +| taint.cpp:334:6:334:6 | 0 | taint.cpp:334:2:334:6 | ... = ... | | +| taint.cpp:334:6:334:6 | 0 | taint.cpp:341:7:341:7 | d | | +| taint.cpp:334:6:334:6 | 0 | taint.cpp:347:13:347:13 | d | | +| taint.cpp:334:6:334:6 | 0 | taint.cpp:354:7:354:7 | d | | +| taint.cpp:335:6:335:6 | 0 | taint.cpp:335:2:335:6 | ... = ... | | +| taint.cpp:335:6:335:6 | 0 | taint.cpp:342:7:342:7 | e | | +| taint.cpp:335:6:335:6 | 0 | taint.cpp:348:14:348:14 | e | | +| taint.cpp:335:6:335:6 | 0 | taint.cpp:355:7:355:7 | e | | +| taint.cpp:344:12:344:12 | ref arg a | taint.cpp:351:7:351:7 | a | | +| taint.cpp:344:15:344:15 | ref arg t | taint.cpp:345:15:345:15 | t | | +| taint.cpp:344:15:344:15 | ref arg t | taint.cpp:346:16:346:16 | t | | +| taint.cpp:344:15:344:15 | ref arg t | taint.cpp:347:16:347:16 | t | | +| taint.cpp:344:15:344:15 | ref arg t | taint.cpp:348:17:348:17 | t | | +| taint.cpp:344:15:344:15 | ref arg t | taint.cpp:350:7:350:7 | t | | +| taint.cpp:345:12:345:12 | ref arg b | taint.cpp:352:7:352:7 | b | | +| taint.cpp:346:12:346:13 | ref arg & ... | taint.cpp:353:7:353:7 | c | | +| taint.cpp:346:13:346:13 | c | taint.cpp:346:12:346:13 | & ... | | +| taint.cpp:347:12:347:13 | ref arg & ... | taint.cpp:354:7:354:7 | d | | +| taint.cpp:347:13:347:13 | d | taint.cpp:347:12:347:13 | & ... | | +| taint.cpp:348:14:348:14 | ref arg e | taint.cpp:355:7:355:7 | e | | +| taint.cpp:348:17:348:17 | ref arg t | taint.cpp:350:7:350:7 | t | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp index d29c45cd63e..ee943a800a1 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -260,3 +260,97 @@ void test_lambdas() e(t, u, w); sink(w); // tainted [NOT DETECTED] } + +// --- taint through return value --- + +int id(int x) +{ + return x; +} + +void test_return() +{ + int x, y, z, t; + + t = source(); + x = 0; + y = 0; + z = 0; + + sink(t); // tainted + sink(x); + sink(y); + sink(z); + + x = id(t); + y = id(id(t)); + z = id(z); + + sink(t); // tainted + sink(x); // tainted + sink(y); // tainted + sink(z); +} + +// --- taint through parameters --- + +void myAssign1(int &a, int &b) +{ + a = b; +} + +void myAssign2(int &a, int b) +{ + a = b; +} + +void myAssign3(int *a, int b) +{ + *a = b; +} + +void myAssign4(int *a, int b) +{ + int c; + + c = b + 1; + *a = c; +} + +void myNotAssign(int &a, int &b) +{ + a = a + 1; + b = b + 1; +} + +void test_outparams() +{ + int t, a, b, c, d, e; + + t = source(); + a = 0; + b = 0; + c = 0; + d = 0; + e = 0; + + sink(t); // tainted + sink(a); + sink(b); + sink(c); + sink(d); + sink(e); + + myAssign1(a, t); + myAssign2(b, t); + myAssign3(&c, t); + myAssign4(&d, t); + myNotAssign(e, t); + + sink(t); // tainted + sink(a); // tainted [NOT DETECTED] + sink(b); // tainted [NOT DETECTED] + sink(c); // tainted [NOT DETECTED] + sink(d); // tainted [NOT DETECTED] + sink(e); +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index 0793bf29e19..b8f204eecda 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -28,3 +28,9 @@ | taint.cpp:244:3:244:6 | t | taint.cpp:223:10:223:15 | call to source | | taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source | | taint.cpp:256:8:256:8 | a | taint.cpp:223:10:223:15 | call to source | +| taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source | +| taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source | +| taint.cpp:290:7:290:7 | x | taint.cpp:275:6:275:11 | call to source | +| taint.cpp:291:7:291:7 | y | taint.cpp:275:6:275:11 | call to source | +| taint.cpp:337:7:337:7 | t | taint.cpp:330:6:330:11 | call to source | +| taint.cpp:350:7:350:7 | t | taint.cpp:330:6:330:11 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index 45798f7ef06..beb908d2df4 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -21,3 +21,4 @@ | taint.cpp:244:3:244:6 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:250:8:250:8 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:256:8:256:8 | taint.cpp:223:10:223:15 | AST only | +| taint.cpp:350:7:350:7 | taint.cpp:330:6:330:11 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected index b08cc19d0df..2f2677401dc 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected @@ -9,3 +9,8 @@ | taint.cpp:167:8:167:13 | Call: call to source | taint.cpp:167:8:167:13 | Call: call to source | | taint.cpp:168:8:168:14 | Load: tainted | taint.cpp:164:19:164:24 | Call: call to source | | taint.cpp:210:7:210:7 | Load: x | taint.cpp:207:6:207:11 | Call: call to source | +| taint.cpp:280:7:280:7 | Load: t | taint.cpp:275:6:275:11 | Call: call to source | +| taint.cpp:289:7:289:7 | Load: t | taint.cpp:275:6:275:11 | Call: call to source | +| taint.cpp:290:7:290:7 | Load: x | taint.cpp:275:6:275:11 | Call: call to source | +| taint.cpp:291:7:291:7 | Load: y | taint.cpp:275:6:275:11 | Call: call to source | +| taint.cpp:337:7:337:7 | Load: t | taint.cpp:330:6:330:11 | Call: call to source | From 5f8a3054d126e4c9b04eb72ec43d71bdb0b79079 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 4 Oct 2019 11:25:54 -0700 Subject: [PATCH 0382/1227] C++: add UninitializedInstructions for direct init --- .../internal/TranslatedDeclarationEntry.qll | 3 +- .../ir/ssa/aliased_ssa_ir.expected | 78 ++++++++++--------- .../ir/ssa/unaliased_ssa_ir.expected | 68 ++++++++-------- 3 files changed, 77 insertions(+), 72 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll index 1efe8cf9f78..d42c1962660 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll @@ -123,7 +123,8 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali private predicate hasUninitializedInstruction() { not exists(getInitialization()) or - getInitialization() instanceof TranslatedListInitialization + getInitialization() instanceof TranslatedListInitialization or + getInitialization() instanceof TranslatedConstructorInitialization } } 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 be58a43a415..813d7a9bdcd 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 @@ -877,41 +877,43 @@ ssa.cpp: # 219| m0_1(unknown) = AliasedDefinition : # 219| mu0_2(unknown) = UnmodeledDefinition : # 220| r0_3(glval) = VariableAddress[c] : -# 220| r0_4(glval) = FunctionAddress[Constructible] : -# 220| r0_5(int) = Constant[1] : -# 220| v0_6(void) = Call : func:r0_4, this:r0_3, 0:r0_5 -# 220| m0_7(unknown) = ^CallSideEffect : ~m0_1 -# 220| m0_8(unknown) = Chi : total:m0_1, partial:m0_7 -# 220| m0_9(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 -# 221| r0_10(glval) = VariableAddress[c] : -# 221| r0_11(glval) = FunctionAddress[g] : -# 221| v0_12(void) = Call : func:r0_11, this:r0_10 -# 221| m0_13(unknown) = ^CallSideEffect : ~m0_8 -# 221| m0_14(unknown) = Chi : total:m0_8, partial:m0_13 -# 221| v0_15(void) = ^IndirectReadSideEffect[-1] : &:r0_10, m0_9 -# 221| m0_16(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_10 -# 222| r0_17(glval) = VariableAddress[c] : -# 222| r0_18(glval) = FunctionAddress[g] : -# 222| v0_19(void) = Call : func:r0_18, this:r0_17 -# 222| m0_20(unknown) = ^CallSideEffect : ~m0_14 -# 222| m0_21(unknown) = Chi : total:m0_14, partial:m0_20 -# 222| v0_22(void) = ^IndirectReadSideEffect[-1] : &:r0_17, m0_16 -# 222| m0_23(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_17 -# 223| r0_24(glval) = VariableAddress[c2] : -# 223| r0_25(glval) = FunctionAddress[Constructible] : -# 223| r0_26(int) = Constant[2] : -# 223| v0_27(void) = Call : func:r0_25, this:r0_24, 0:r0_26 -# 223| m0_28(unknown) = ^CallSideEffect : ~m0_21 -# 223| m0_29(unknown) = Chi : total:m0_21, partial:m0_28 -# 223| m0_30(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_24 -# 224| r0_31(glval) = VariableAddress[c2] : -# 224| r0_32(glval) = FunctionAddress[g] : -# 224| v0_33(void) = Call : func:r0_32, this:r0_31 -# 224| m0_34(unknown) = ^CallSideEffect : ~m0_29 -# 224| m0_35(unknown) = Chi : total:m0_29, partial:m0_34 -# 224| v0_36(void) = ^IndirectReadSideEffect[-1] : &:r0_31, m0_30 -# 224| m0_37(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_31 -# 225| v0_38(void) = NoOp : -# 219| v0_39(void) = ReturnVoid : -# 219| v0_40(void) = UnmodeledUse : mu* -# 219| v0_41(void) = ExitFunction : +# 220| m0_4(Constructible) = Uninitialized[c] : &:r0_3 +# 220| r0_5(glval) = FunctionAddress[Constructible] : +# 220| r0_6(int) = Constant[1] : +# 220| v0_7(void) = Call : func:r0_5, this:r0_3, 0:r0_6 +# 220| m0_8(unknown) = ^CallSideEffect : ~m0_1 +# 220| m0_9(unknown) = Chi : total:m0_1, partial:m0_8 +# 220| m0_10(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 +# 221| r0_11(glval) = VariableAddress[c] : +# 221| r0_12(glval) = FunctionAddress[g] : +# 221| v0_13(void) = Call : func:r0_12, this:r0_11 +# 221| m0_14(unknown) = ^CallSideEffect : ~m0_9 +# 221| m0_15(unknown) = Chi : total:m0_9, partial:m0_14 +# 221| v0_16(void) = ^IndirectReadSideEffect[-1] : &:r0_11, m0_10 +# 221| m0_17(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_11 +# 222| r0_18(glval) = VariableAddress[c] : +# 222| r0_19(glval) = FunctionAddress[g] : +# 222| v0_20(void) = Call : func:r0_19, this:r0_18 +# 222| m0_21(unknown) = ^CallSideEffect : ~m0_15 +# 222| m0_22(unknown) = Chi : total:m0_15, partial:m0_21 +# 222| v0_23(void) = ^IndirectReadSideEffect[-1] : &:r0_18, m0_17 +# 222| m0_24(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_18 +# 223| r0_25(glval) = VariableAddress[c2] : +# 223| m0_26(Constructible) = Uninitialized[c2] : &:r0_25 +# 223| r0_27(glval) = FunctionAddress[Constructible] : +# 223| r0_28(int) = Constant[2] : +# 223| v0_29(void) = Call : func:r0_27, this:r0_25, 0:r0_28 +# 223| m0_30(unknown) = ^CallSideEffect : ~m0_22 +# 223| m0_31(unknown) = Chi : total:m0_22, partial:m0_30 +# 223| m0_32(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_25 +# 224| r0_33(glval) = VariableAddress[c2] : +# 224| r0_34(glval) = FunctionAddress[g] : +# 224| v0_35(void) = Call : func:r0_34, this:r0_33 +# 224| m0_36(unknown) = ^CallSideEffect : ~m0_31 +# 224| m0_37(unknown) = Chi : total:m0_31, partial:m0_36 +# 224| v0_38(void) = ^IndirectReadSideEffect[-1] : &:r0_33, m0_32 +# 224| m0_39(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_33 +# 225| v0_40(void) = NoOp : +# 219| v0_41(void) = ReturnVoid : +# 219| v0_42(void) = UnmodeledUse : mu* +# 219| v0_43(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 6006ee38036..029c552f5d5 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -837,36 +837,38 @@ ssa.cpp: # 219| mu0_1(unknown) = AliasedDefinition : # 219| mu0_2(unknown) = UnmodeledDefinition : # 220| r0_3(glval) = VariableAddress[c] : -# 220| r0_4(glval) = FunctionAddress[Constructible] : -# 220| r0_5(int) = Constant[1] : -# 220| v0_6(void) = Call : func:r0_4, this:r0_3, 0:r0_5 -# 220| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 -# 220| m0_8(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 -# 221| r0_9(glval) = VariableAddress[c] : -# 221| r0_10(glval) = FunctionAddress[g] : -# 221| v0_11(void) = Call : func:r0_10, this:r0_9 -# 221| mu0_12(unknown) = ^CallSideEffect : ~mu0_2 -# 221| v0_13(void) = ^IndirectReadSideEffect[-1] : &:r0_9, m0_8 -# 221| m0_14(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 -# 222| r0_15(glval) = VariableAddress[c] : -# 222| r0_16(glval) = FunctionAddress[g] : -# 222| v0_17(void) = Call : func:r0_16, this:r0_15 -# 222| mu0_18(unknown) = ^CallSideEffect : ~mu0_2 -# 222| v0_19(void) = ^IndirectReadSideEffect[-1] : &:r0_15, m0_14 -# 222| m0_20(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_15 -# 223| r0_21(glval) = VariableAddress[c2] : -# 223| r0_22(glval) = FunctionAddress[Constructible] : -# 223| r0_23(int) = Constant[2] : -# 223| v0_24(void) = Call : func:r0_22, this:r0_21, 0:r0_23 -# 223| mu0_25(unknown) = ^CallSideEffect : ~mu0_2 -# 223| m0_26(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 -# 224| r0_27(glval) = VariableAddress[c2] : -# 224| r0_28(glval) = FunctionAddress[g] : -# 224| v0_29(void) = Call : func:r0_28, this:r0_27 -# 224| mu0_30(unknown) = ^CallSideEffect : ~mu0_2 -# 224| v0_31(void) = ^IndirectReadSideEffect[-1] : &:r0_27, m0_26 -# 224| m0_32(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_27 -# 225| v0_33(void) = NoOp : -# 219| v0_34(void) = ReturnVoid : -# 219| v0_35(void) = UnmodeledUse : mu* -# 219| v0_36(void) = ExitFunction : +# 220| m0_4(Constructible) = Uninitialized[c] : &:r0_3 +# 220| r0_5(glval) = FunctionAddress[Constructible] : +# 220| r0_6(int) = Constant[1] : +# 220| v0_7(void) = Call : func:r0_5, this:r0_3, 0:r0_6 +# 220| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 +# 220| m0_9(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 +# 221| r0_10(glval) = VariableAddress[c] : +# 221| r0_11(glval) = FunctionAddress[g] : +# 221| v0_12(void) = Call : func:r0_11, this:r0_10 +# 221| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +# 221| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_10, m0_9 +# 221| m0_15(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_10 +# 222| r0_16(glval) = VariableAddress[c] : +# 222| r0_17(glval) = FunctionAddress[g] : +# 222| v0_18(void) = Call : func:r0_17, this:r0_16 +# 222| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 +# 222| v0_20(void) = ^IndirectReadSideEffect[-1] : &:r0_16, m0_15 +# 222| m0_21(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_16 +# 223| r0_22(glval) = VariableAddress[c2] : +# 223| m0_23(Constructible) = Uninitialized[c2] : &:r0_22 +# 223| r0_24(glval) = FunctionAddress[Constructible] : +# 223| r0_25(int) = Constant[2] : +# 223| v0_26(void) = Call : func:r0_24, this:r0_22, 0:r0_25 +# 223| mu0_27(unknown) = ^CallSideEffect : ~mu0_2 +# 223| m0_28(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_22 +# 224| r0_29(glval) = VariableAddress[c2] : +# 224| r0_30(glval) = FunctionAddress[g] : +# 224| v0_31(void) = Call : func:r0_30, this:r0_29 +# 224| mu0_32(unknown) = ^CallSideEffect : ~mu0_2 +# 224| v0_33(void) = ^IndirectReadSideEffect[-1] : &:r0_29, m0_28 +# 224| m0_34(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_29 +# 225| v0_35(void) = NoOp : +# 219| v0_36(void) = ReturnVoid : +# 219| v0_37(void) = UnmodeledUse : mu* +# 219| v0_38(void) = ExitFunction : From 3377f88494c7a84569e91dff46eaf61bca7f3c94 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 4 Oct 2019 11:36:47 -0700 Subject: [PATCH 0383/1227] C++: generate Chi nodes on total IndirectMayWrites --- .../aliased_ssa/internal/SSAConstruction.qll | 9 +- .../internal/SSAConstruction.qll | 9 +- .../unaliased_ssa/internal/SimpleSSA.qll | 7 +- .../test/library-tests/ir/ir/raw_ir.expected | 930 +++++++++--------- .../ir/ssa/aliased_ssa_ir.expected | 71 +- .../ir/ssa/unaliased_ssa_ir.expected | 20 +- 6 files changed, 538 insertions(+), 508 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 0fb6676bb42..753cca6b955 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -422,7 +422,11 @@ private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) { defLocation.getVirtualVariable() = vvar and // If the definition totally (or exactly) overlaps the virtual variable, then there's no need for a `Chi` // instruction. - Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap + ( + Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap or + def.getResultMemoryAccess() instanceof IndirectMayMemoryAccess or + def.getResultMemoryAccess() instanceof BufferMayMemoryAccess + ) ) } @@ -735,7 +739,8 @@ module DefUse { defLocation = Alias::getResultMemoryLocation(def) and block.getInstruction(index) = def and overlap = Alias::getOverlap(defLocation, useLocation) and - if overlap instanceof MayPartiallyOverlap + if + overlap instanceof MayPartiallyOverlap then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction. else offset = index * 2 // The use will be connected to the definition on the original instruction. ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 0fb6676bb42..753cca6b955 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -422,7 +422,11 @@ private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) { defLocation.getVirtualVariable() = vvar and // If the definition totally (or exactly) overlaps the virtual variable, then there's no need for a `Chi` // instruction. - Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap + ( + Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap or + def.getResultMemoryAccess() instanceof IndirectMayMemoryAccess or + def.getResultMemoryAccess() instanceof BufferMayMemoryAccess + ) ) } @@ -735,7 +739,8 @@ module DefUse { defLocation = Alias::getResultMemoryLocation(def) and block.getInstruction(index) = def and overlap = Alias::getOverlap(defLocation, useLocation) and - if overlap instanceof MayPartiallyOverlap + if + overlap instanceof MayPartiallyOverlap then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction. else offset = index * 2 // The use will be connected to the definition on the original instruction. ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index 7cca5855a20..16ff83deb02 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -1,4 +1,5 @@ import AliasAnalysis +private import semmle.code.cpp.ir.implementation.MemoryAccessKind private import cpp private import semmle.code.cpp.ir.implementation.raw.IR private import semmle.code.cpp.ir.internal.IntegerConstant as Ints @@ -34,7 +35,11 @@ private predicate isVariableModeled(IRVariable var) { hasResultMemoryAccess(instr, var, type, bitOffset) | bitOffset = 0 and - type = var.getType() + type = var.getType() and + not ( + instr.getResultMemoryAccess() instanceof IndirectMayMemoryAccess or + instr.getResultMemoryAccess() instanceof BufferMayMemoryAccess + ) ) and forall(MemoryOperand operand, Type type, IntValue bitOffset | hasOperandMemoryAccess(operand, var, type, bitOffset) diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 933cd6bc2e3..aa1e2fa7bd6 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -2712,37 +2712,40 @@ ir.cpp: # 615| mu0_1(unknown) = AliasedDefinition : # 615| mu0_2(unknown) = UnmodeledDefinition : # 616| r0_3(glval) = VariableAddress[s1] : -# 616| r0_4(glval) = FunctionAddress[String] : -# 616| v0_5(void) = Call : func:r0_4, this:r0_3 -# 616| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 616| mu0_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 -# 617| r0_8(glval) = VariableAddress[s2] : -# 617| r0_9(glval) = FunctionAddress[String] : -# 617| r0_10(glval) = StringConstant["hello"] : -# 617| r0_11(char *) = Convert : r0_10 -# 617| v0_12(void) = Call : func:r0_9, this:r0_8, 0:r0_11 -# 617| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -# 617| mu0_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 -# 617| v0_15(void) = ^IndirectReadSideEffect[0] : &:r0_11, ~mu0_2 -# 617| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_11 -# 618| r0_17(glval) = VariableAddress[s3] : -# 618| r0_18(glval) = FunctionAddress[ReturnObject] : -# 618| r0_19(String) = Call : func:r0_18 -# 618| mu0_20(unknown) = ^CallSideEffect : ~mu0_2 -# 618| mu0_21(String) = Store : &:r0_17, r0_19 -# 619| r0_22(glval) = VariableAddress[s4] : -# 619| r0_23(glval) = FunctionAddress[String] : -# 619| r0_24(glval) = StringConstant["test"] : -# 619| r0_25(char *) = Convert : r0_24 -# 619| v0_26(void) = Call : func:r0_23, this:r0_22, 0:r0_25 -# 619| mu0_27(unknown) = ^CallSideEffect : ~mu0_2 -# 619| mu0_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_22 -# 619| v0_29(void) = ^IndirectReadSideEffect[0] : &:r0_25, ~mu0_2 -# 619| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_25 -# 620| v0_31(void) = NoOp : -# 615| v0_32(void) = ReturnVoid : -# 615| v0_33(void) = UnmodeledUse : mu* -# 615| v0_34(void) = ExitFunction : +# 616| mu0_4(String) = Uninitialized[s1] : &:r0_3 +# 616| r0_5(glval) = FunctionAddress[String] : +# 616| v0_6(void) = Call : func:r0_5, this:r0_3 +# 616| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +# 616| mu0_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 +# 617| r0_9(glval) = VariableAddress[s2] : +# 617| mu0_10(String) = Uninitialized[s2] : &:r0_9 +# 617| r0_11(glval) = FunctionAddress[String] : +# 617| r0_12(glval) = StringConstant["hello"] : +# 617| r0_13(char *) = Convert : r0_12 +# 617| v0_14(void) = Call : func:r0_11, this:r0_9, 0:r0_13 +# 617| mu0_15(unknown) = ^CallSideEffect : ~mu0_2 +# 617| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 +# 617| v0_17(void) = ^IndirectReadSideEffect[0] : &:r0_13, ~mu0_2 +# 617| mu0_18(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 +# 618| r0_19(glval) = VariableAddress[s3] : +# 618| r0_20(glval) = FunctionAddress[ReturnObject] : +# 618| r0_21(String) = Call : func:r0_20 +# 618| mu0_22(unknown) = ^CallSideEffect : ~mu0_2 +# 618| mu0_23(String) = Store : &:r0_19, r0_21 +# 619| r0_24(glval) = VariableAddress[s4] : +# 619| mu0_25(String) = Uninitialized[s4] : &:r0_24 +# 619| r0_26(glval) = FunctionAddress[String] : +# 619| r0_27(glval) = StringConstant["test"] : +# 619| r0_28(char *) = Convert : r0_27 +# 619| v0_29(void) = Call : func:r0_26, this:r0_24, 0:r0_28 +# 619| mu0_30(unknown) = ^CallSideEffect : ~mu0_2 +# 619| mu0_31(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_24 +# 619| v0_32(void) = ^IndirectReadSideEffect[0] : &:r0_28, ~mu0_2 +# 619| mu0_33(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_28 +# 620| v0_34(void) = NoOp : +# 615| v0_35(void) = ReturnVoid : +# 615| v0_36(void) = UnmodeledUse : mu* +# 615| v0_37(void) = ExitFunction : # 622| void CallMethods(String&, String*, String) # 622| Block 0 @@ -3640,261 +3643,264 @@ ir.cpp: # 799| mu0_1(unknown) = AliasedDefinition : # 799| mu0_2(unknown) = UnmodeledDefinition : # 800| r0_3(glval) = VariableAddress[b] : -# 800| r0_4(glval) = FunctionAddress[Base] : -# 800| v0_5(void) = Call : func:r0_4, this:r0_3 -# 800| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -# 800| mu0_7(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 -# 801| r0_8(glval) = VariableAddress[m] : -# 801| r0_9(glval) = FunctionAddress[Middle] : -# 801| v0_10(void) = Call : func:r0_9, this:r0_8 -# 801| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 801| mu0_12(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 -# 802| r0_13(glval) = VariableAddress[d] : -# 802| r0_14(glval) = FunctionAddress[Derived] : -# 802| v0_15(void) = Call : func:r0_14, this:r0_13 -# 802| mu0_16(unknown) = ^CallSideEffect : ~mu0_2 -# 802| mu0_17(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_13 -# 804| r0_18(glval) = VariableAddress[pb] : -# 804| r0_19(glval) = VariableAddress[b] : -# 804| mu0_20(Base *) = Store : &:r0_18, r0_19 -# 805| r0_21(glval) = VariableAddress[pm] : -# 805| r0_22(glval) = VariableAddress[m] : -# 805| mu0_23(Middle *) = Store : &:r0_21, r0_22 -# 806| r0_24(glval) = VariableAddress[pd] : -# 806| r0_25(glval) = VariableAddress[d] : -# 806| mu0_26(Derived *) = Store : &:r0_24, r0_25 -# 808| r0_27(glval) = VariableAddress[b] : -# 808| r0_28(glval) = FunctionAddress[operator=] : -# 808| r0_29(glval) = VariableAddress[m] : -# 808| r0_30(glval) = ConvertToBase[Middle : Base] : r0_29 -# 808| r0_31(Base &) = Call : func:r0_28, this:r0_27, 0:r0_30 -# 808| mu0_32(unknown) = ^CallSideEffect : ~mu0_2 -# 808| v0_33(void) = ^IndirectReadSideEffect[-1] : &:r0_27, ~mu0_2 -# 808| v0_34(void) = ^IndirectReadSideEffect[0] : &:r0_30, ~mu0_2 -# 808| mu0_35(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_27 -# 808| mu0_36(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_30 -# 809| r0_37(glval) = VariableAddress[b] : -# 809| r0_38(glval) = FunctionAddress[operator=] : -# 809| r0_39(glval) = FunctionAddress[Base] : -# 809| r0_40(glval) = VariableAddress[m] : -# 809| r0_41(glval) = ConvertToBase[Middle : Base] : r0_40 -# 809| v0_42(void) = Call : func:r0_39, 0:r0_41 -# 809| mu0_43(unknown) = ^CallSideEffect : ~mu0_2 -# 809| mu0_44(Base) = ^IndirectMayWriteSideEffect[-1] : -# 809| v0_45(void) = ^IndirectReadSideEffect[0] : &:r0_41, ~mu0_2 -# 809| mu0_46(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_41 -# 809| r0_47(glval) = Convert : v0_42 -# 809| r0_48(Base &) = Call : func:r0_38, this:r0_37, 0:r0_47 -# 809| mu0_49(unknown) = ^CallSideEffect : ~mu0_2 -# 809| v0_50(void) = ^IndirectReadSideEffect[-1] : &:r0_37, ~mu0_2 -# 809| v0_51(void) = ^IndirectReadSideEffect[0] : &:r0_47, ~mu0_2 -# 809| mu0_52(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_37 -# 809| mu0_53(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_47 -# 810| r0_54(glval) = VariableAddress[b] : -# 810| r0_55(glval) = FunctionAddress[operator=] : -# 810| r0_56(glval) = FunctionAddress[Base] : -# 810| r0_57(glval) = VariableAddress[m] : -# 810| r0_58(glval) = ConvertToBase[Middle : Base] : r0_57 -# 810| v0_59(void) = Call : func:r0_56, 0:r0_58 -# 810| mu0_60(unknown) = ^CallSideEffect : ~mu0_2 -# 810| mu0_61(Base) = ^IndirectMayWriteSideEffect[-1] : -# 810| v0_62(void) = ^IndirectReadSideEffect[0] : &:r0_58, ~mu0_2 -# 810| mu0_63(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_58 -# 810| r0_64(glval) = Convert : v0_59 -# 810| r0_65(Base &) = Call : func:r0_55, this:r0_54, 0:r0_64 -# 810| mu0_66(unknown) = ^CallSideEffect : ~mu0_2 -# 810| v0_67(void) = ^IndirectReadSideEffect[-1] : &:r0_54, ~mu0_2 -# 810| v0_68(void) = ^IndirectReadSideEffect[0] : &:r0_64, ~mu0_2 -# 810| mu0_69(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_54 -# 810| mu0_70(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_64 -# 811| r0_71(glval) = VariableAddress[pm] : -# 811| r0_72(Middle *) = Load : &:r0_71, ~mu0_2 -# 811| r0_73(Base *) = ConvertToBase[Middle : Base] : r0_72 -# 811| r0_74(glval) = VariableAddress[pb] : -# 811| mu0_75(Base *) = Store : &:r0_74, r0_73 -# 812| r0_76(glval) = VariableAddress[pm] : -# 812| r0_77(Middle *) = Load : &:r0_76, ~mu0_2 -# 812| r0_78(Base *) = ConvertToBase[Middle : Base] : r0_77 -# 812| r0_79(glval) = VariableAddress[pb] : -# 812| mu0_80(Base *) = Store : &:r0_79, r0_78 -# 813| r0_81(glval) = VariableAddress[pm] : -# 813| r0_82(Middle *) = Load : &:r0_81, ~mu0_2 -# 813| r0_83(Base *) = ConvertToBase[Middle : Base] : r0_82 -# 813| r0_84(glval) = VariableAddress[pb] : -# 813| mu0_85(Base *) = Store : &:r0_84, r0_83 -# 814| r0_86(glval) = VariableAddress[pm] : -# 814| r0_87(Middle *) = Load : &:r0_86, ~mu0_2 -# 814| r0_88(Base *) = Convert : r0_87 -# 814| r0_89(glval) = VariableAddress[pb] : -# 814| mu0_90(Base *) = Store : &:r0_89, r0_88 -# 816| r0_91(glval) = VariableAddress[m] : -# 816| r0_92(glval) = FunctionAddress[operator=] : -# 816| r0_93(glval) = VariableAddress[b] : -# 816| r0_94(glval) = ConvertToDerived[Middle : Base] : r0_93 -# 816| r0_95(glval) = Convert : r0_94 -# 816| r0_96(Middle &) = Call : func:r0_92, this:r0_91, 0:r0_95 -# 816| mu0_97(unknown) = ^CallSideEffect : ~mu0_2 -# 816| v0_98(void) = ^IndirectReadSideEffect[-1] : &:r0_91, ~mu0_2 -# 816| v0_99(void) = ^IndirectReadSideEffect[0] : &:r0_95, ~mu0_2 -# 816| mu0_100(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_91 -# 816| mu0_101(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_95 -# 817| r0_102(glval) = VariableAddress[m] : -# 817| r0_103(glval) = FunctionAddress[operator=] : -# 817| r0_104(glval) = VariableAddress[b] : -# 817| r0_105(glval) = ConvertToDerived[Middle : Base] : r0_104 -# 817| r0_106(glval) = Convert : r0_105 -# 817| r0_107(Middle &) = Call : func:r0_103, this:r0_102, 0:r0_106 -# 817| mu0_108(unknown) = ^CallSideEffect : ~mu0_2 -# 817| v0_109(void) = ^IndirectReadSideEffect[-1] : &:r0_102, ~mu0_2 -# 817| v0_110(void) = ^IndirectReadSideEffect[0] : &:r0_106, ~mu0_2 -# 817| mu0_111(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_102 -# 817| mu0_112(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_106 -# 818| r0_113(glval) = VariableAddress[pb] : -# 818| r0_114(Base *) = Load : &:r0_113, ~mu0_2 -# 818| r0_115(Middle *) = ConvertToDerived[Middle : Base] : r0_114 -# 818| r0_116(glval) = VariableAddress[pm] : -# 818| mu0_117(Middle *) = Store : &:r0_116, r0_115 -# 819| r0_118(glval) = VariableAddress[pb] : -# 819| r0_119(Base *) = Load : &:r0_118, ~mu0_2 -# 819| r0_120(Middle *) = ConvertToDerived[Middle : Base] : r0_119 -# 819| r0_121(glval) = VariableAddress[pm] : -# 819| mu0_122(Middle *) = Store : &:r0_121, r0_120 -# 820| r0_123(glval) = VariableAddress[pb] : -# 820| r0_124(Base *) = Load : &:r0_123, ~mu0_2 -# 820| r0_125(Middle *) = Convert : r0_124 -# 820| r0_126(glval) = VariableAddress[pm] : -# 820| mu0_127(Middle *) = Store : &:r0_126, r0_125 -# 822| r0_128(glval) = VariableAddress[b] : -# 822| r0_129(glval) = FunctionAddress[operator=] : -# 822| r0_130(glval) = VariableAddress[d] : -# 822| r0_131(glval) = ConvertToBase[Derived : Middle] : r0_130 -# 822| r0_132(glval) = ConvertToBase[Middle : Base] : r0_131 -# 822| r0_133(Base &) = Call : func:r0_129, this:r0_128, 0:r0_132 -# 822| mu0_134(unknown) = ^CallSideEffect : ~mu0_2 -# 822| v0_135(void) = ^IndirectReadSideEffect[-1] : &:r0_128, ~mu0_2 -# 822| v0_136(void) = ^IndirectReadSideEffect[0] : &:r0_132, ~mu0_2 -# 822| mu0_137(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_128 -# 822| mu0_138(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_132 -# 823| r0_139(glval) = VariableAddress[b] : -# 823| r0_140(glval) = FunctionAddress[operator=] : -# 823| r0_141(glval) = FunctionAddress[Base] : -# 823| r0_142(glval) = VariableAddress[d] : -# 823| r0_143(glval) = ConvertToBase[Derived : Middle] : r0_142 -# 823| r0_144(glval) = ConvertToBase[Middle : Base] : r0_143 -# 823| v0_145(void) = Call : func:r0_141, 0:r0_144 -# 823| mu0_146(unknown) = ^CallSideEffect : ~mu0_2 -# 823| mu0_147(Base) = ^IndirectMayWriteSideEffect[-1] : -# 823| v0_148(void) = ^IndirectReadSideEffect[0] : &:r0_144, ~mu0_2 -# 823| mu0_149(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_144 -# 823| r0_150(glval) = Convert : v0_145 -# 823| r0_151(Base &) = Call : func:r0_140, this:r0_139, 0:r0_150 -# 823| mu0_152(unknown) = ^CallSideEffect : ~mu0_2 -# 823| v0_153(void) = ^IndirectReadSideEffect[-1] : &:r0_139, ~mu0_2 -# 823| v0_154(void) = ^IndirectReadSideEffect[0] : &:r0_150, ~mu0_2 -# 823| mu0_155(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_139 -# 823| mu0_156(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_150 -# 824| r0_157(glval) = VariableAddress[b] : -# 824| r0_158(glval) = FunctionAddress[operator=] : -# 824| r0_159(glval) = FunctionAddress[Base] : -# 824| r0_160(glval) = VariableAddress[d] : -# 824| r0_161(glval) = ConvertToBase[Derived : Middle] : r0_160 -# 824| r0_162(glval) = ConvertToBase[Middle : Base] : r0_161 -# 824| v0_163(void) = Call : func:r0_159, 0:r0_162 -# 824| mu0_164(unknown) = ^CallSideEffect : ~mu0_2 -# 824| mu0_165(Base) = ^IndirectMayWriteSideEffect[-1] : -# 824| v0_166(void) = ^IndirectReadSideEffect[0] : &:r0_162, ~mu0_2 -# 824| mu0_167(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_162 -# 824| r0_168(glval) = Convert : v0_163 -# 824| r0_169(Base &) = Call : func:r0_158, this:r0_157, 0:r0_168 -# 824| mu0_170(unknown) = ^CallSideEffect : ~mu0_2 -# 824| v0_171(void) = ^IndirectReadSideEffect[-1] : &:r0_157, ~mu0_2 -# 824| v0_172(void) = ^IndirectReadSideEffect[0] : &:r0_168, ~mu0_2 -# 824| mu0_173(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_157 -# 824| mu0_174(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_168 -# 825| r0_175(glval) = VariableAddress[pd] : -# 825| r0_176(Derived *) = Load : &:r0_175, ~mu0_2 -# 825| r0_177(Middle *) = ConvertToBase[Derived : Middle] : r0_176 -# 825| r0_178(Base *) = ConvertToBase[Middle : Base] : r0_177 -# 825| r0_179(glval) = VariableAddress[pb] : -# 825| mu0_180(Base *) = Store : &:r0_179, r0_178 -# 826| r0_181(glval) = VariableAddress[pd] : -# 826| r0_182(Derived *) = Load : &:r0_181, ~mu0_2 -# 826| r0_183(Middle *) = ConvertToBase[Derived : Middle] : r0_182 -# 826| r0_184(Base *) = ConvertToBase[Middle : Base] : r0_183 -# 826| r0_185(glval) = VariableAddress[pb] : -# 826| mu0_186(Base *) = Store : &:r0_185, r0_184 -# 827| r0_187(glval) = VariableAddress[pd] : -# 827| r0_188(Derived *) = Load : &:r0_187, ~mu0_2 -# 827| r0_189(Middle *) = ConvertToBase[Derived : Middle] : r0_188 -# 827| r0_190(Base *) = ConvertToBase[Middle : Base] : r0_189 -# 827| r0_191(glval) = VariableAddress[pb] : -# 827| mu0_192(Base *) = Store : &:r0_191, r0_190 -# 828| r0_193(glval) = VariableAddress[pd] : -# 828| r0_194(Derived *) = Load : &:r0_193, ~mu0_2 -# 828| r0_195(Base *) = Convert : r0_194 -# 828| r0_196(glval) = VariableAddress[pb] : -# 828| mu0_197(Base *) = Store : &:r0_196, r0_195 -# 830| r0_198(glval) = VariableAddress[d] : -# 830| r0_199(glval) = FunctionAddress[operator=] : -# 830| r0_200(glval) = VariableAddress[b] : -# 830| r0_201(glval) = ConvertToDerived[Middle : Base] : r0_200 -# 830| r0_202(glval) = ConvertToDerived[Derived : Middle] : r0_201 -# 830| r0_203(glval) = Convert : r0_202 -# 830| r0_204(Derived &) = Call : func:r0_199, this:r0_198, 0:r0_203 -# 830| mu0_205(unknown) = ^CallSideEffect : ~mu0_2 -# 830| v0_206(void) = ^IndirectReadSideEffect[-1] : &:r0_198, ~mu0_2 -# 830| v0_207(void) = ^IndirectReadSideEffect[0] : &:r0_203, ~mu0_2 -# 830| mu0_208(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_198 -# 830| mu0_209(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_203 -# 831| r0_210(glval) = VariableAddress[d] : -# 831| r0_211(glval) = FunctionAddress[operator=] : -# 831| r0_212(glval) = VariableAddress[b] : -# 831| r0_213(glval) = ConvertToDerived[Middle : Base] : r0_212 -# 831| r0_214(glval) = ConvertToDerived[Derived : Middle] : r0_213 -# 831| r0_215(glval) = Convert : r0_214 -# 831| r0_216(Derived &) = Call : func:r0_211, this:r0_210, 0:r0_215 -# 831| mu0_217(unknown) = ^CallSideEffect : ~mu0_2 -# 831| v0_218(void) = ^IndirectReadSideEffect[-1] : &:r0_210, ~mu0_2 -# 831| v0_219(void) = ^IndirectReadSideEffect[0] : &:r0_215, ~mu0_2 -# 831| mu0_220(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_210 -# 831| mu0_221(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_215 -# 832| r0_222(glval) = VariableAddress[pb] : -# 832| r0_223(Base *) = Load : &:r0_222, ~mu0_2 -# 832| r0_224(Middle *) = ConvertToDerived[Middle : Base] : r0_223 -# 832| r0_225(Derived *) = ConvertToDerived[Derived : Middle] : r0_224 -# 832| r0_226(glval) = VariableAddress[pd] : -# 832| mu0_227(Derived *) = Store : &:r0_226, r0_225 -# 833| r0_228(glval) = VariableAddress[pb] : -# 833| r0_229(Base *) = Load : &:r0_228, ~mu0_2 -# 833| r0_230(Middle *) = ConvertToDerived[Middle : Base] : r0_229 -# 833| r0_231(Derived *) = ConvertToDerived[Derived : Middle] : r0_230 -# 833| r0_232(glval) = VariableAddress[pd] : -# 833| mu0_233(Derived *) = Store : &:r0_232, r0_231 -# 834| r0_234(glval) = VariableAddress[pb] : -# 834| r0_235(Base *) = Load : &:r0_234, ~mu0_2 -# 834| r0_236(Derived *) = Convert : r0_235 -# 834| r0_237(glval) = VariableAddress[pd] : -# 834| mu0_238(Derived *) = Store : &:r0_237, r0_236 -# 836| r0_239(glval) = VariableAddress[pmv] : -# 836| r0_240(MiddleVB1 *) = Constant[0] : -# 836| mu0_241(MiddleVB1 *) = Store : &:r0_239, r0_240 -# 837| r0_242(glval) = VariableAddress[pdv] : -# 837| r0_243(DerivedVB *) = Constant[0] : -# 837| mu0_244(DerivedVB *) = Store : &:r0_242, r0_243 -# 838| r0_245(glval) = VariableAddress[pmv] : -# 838| r0_246(MiddleVB1 *) = Load : &:r0_245, ~mu0_2 -# 838| r0_247(Base *) = ConvertToVirtualBase[MiddleVB1 : Base] : r0_246 -# 838| r0_248(glval) = VariableAddress[pb] : -# 838| mu0_249(Base *) = Store : &:r0_248, r0_247 -# 839| r0_250(glval) = VariableAddress[pdv] : -# 839| r0_251(DerivedVB *) = Load : &:r0_250, ~mu0_2 -# 839| r0_252(Base *) = ConvertToVirtualBase[DerivedVB : Base] : r0_251 -# 839| r0_253(glval) = VariableAddress[pb] : -# 839| mu0_254(Base *) = Store : &:r0_253, r0_252 -# 840| v0_255(void) = NoOp : -# 799| v0_256(void) = ReturnVoid : -# 799| v0_257(void) = UnmodeledUse : mu* -# 799| v0_258(void) = ExitFunction : +# 800| mu0_4(Base) = Uninitialized[b] : &:r0_3 +# 800| r0_5(glval) = FunctionAddress[Base] : +# 800| v0_6(void) = Call : func:r0_5, this:r0_3 +# 800| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +# 800| mu0_8(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 +# 801| r0_9(glval) = VariableAddress[m] : +# 801| mu0_10(Middle) = Uninitialized[m] : &:r0_9 +# 801| r0_11(glval) = FunctionAddress[Middle] : +# 801| v0_12(void) = Call : func:r0_11, this:r0_9 +# 801| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +# 801| mu0_14(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 +# 802| r0_15(glval) = VariableAddress[d] : +# 802| mu0_16(Derived) = Uninitialized[d] : &:r0_15 +# 802| r0_17(glval) = FunctionAddress[Derived] : +# 802| v0_18(void) = Call : func:r0_17, this:r0_15 +# 802| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 +# 802| mu0_20(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_15 +# 804| r0_21(glval) = VariableAddress[pb] : +# 804| r0_22(glval) = VariableAddress[b] : +# 804| mu0_23(Base *) = Store : &:r0_21, r0_22 +# 805| r0_24(glval) = VariableAddress[pm] : +# 805| r0_25(glval) = VariableAddress[m] : +# 805| mu0_26(Middle *) = Store : &:r0_24, r0_25 +# 806| r0_27(glval) = VariableAddress[pd] : +# 806| r0_28(glval) = VariableAddress[d] : +# 806| mu0_29(Derived *) = Store : &:r0_27, r0_28 +# 808| r0_30(glval) = VariableAddress[b] : +# 808| r0_31(glval) = FunctionAddress[operator=] : +# 808| r0_32(glval) = VariableAddress[m] : +# 808| r0_33(glval) = ConvertToBase[Middle : Base] : r0_32 +# 808| r0_34(Base &) = Call : func:r0_31, this:r0_30, 0:r0_33 +# 808| mu0_35(unknown) = ^CallSideEffect : ~mu0_2 +# 808| v0_36(void) = ^IndirectReadSideEffect[-1] : &:r0_30, ~mu0_2 +# 808| v0_37(void) = ^IndirectReadSideEffect[0] : &:r0_33, ~mu0_2 +# 808| mu0_38(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_30 +# 808| mu0_39(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_33 +# 809| r0_40(glval) = VariableAddress[b] : +# 809| r0_41(glval) = FunctionAddress[operator=] : +# 809| r0_42(glval) = FunctionAddress[Base] : +# 809| r0_43(glval) = VariableAddress[m] : +# 809| r0_44(glval) = ConvertToBase[Middle : Base] : r0_43 +# 809| v0_45(void) = Call : func:r0_42, 0:r0_44 +# 809| mu0_46(unknown) = ^CallSideEffect : ~mu0_2 +# 809| mu0_47(Base) = ^IndirectMayWriteSideEffect[-1] : +# 809| v0_48(void) = ^IndirectReadSideEffect[0] : &:r0_44, ~mu0_2 +# 809| mu0_49(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_44 +# 809| r0_50(glval) = Convert : v0_45 +# 809| r0_51(Base &) = Call : func:r0_41, this:r0_40, 0:r0_50 +# 809| mu0_52(unknown) = ^CallSideEffect : ~mu0_2 +# 809| v0_53(void) = ^IndirectReadSideEffect[-1] : &:r0_40, ~mu0_2 +# 809| v0_54(void) = ^IndirectReadSideEffect[0] : &:r0_50, ~mu0_2 +# 809| mu0_55(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_40 +# 809| mu0_56(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_50 +# 810| r0_57(glval) = VariableAddress[b] : +# 810| r0_58(glval) = FunctionAddress[operator=] : +# 810| r0_59(glval) = FunctionAddress[Base] : +# 810| r0_60(glval) = VariableAddress[m] : +# 810| r0_61(glval) = ConvertToBase[Middle : Base] : r0_60 +# 810| v0_62(void) = Call : func:r0_59, 0:r0_61 +# 810| mu0_63(unknown) = ^CallSideEffect : ~mu0_2 +# 810| mu0_64(Base) = ^IndirectMayWriteSideEffect[-1] : +# 810| v0_65(void) = ^IndirectReadSideEffect[0] : &:r0_61, ~mu0_2 +# 810| mu0_66(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_61 +# 810| r0_67(glval) = Convert : v0_62 +# 810| r0_68(Base &) = Call : func:r0_58, this:r0_57, 0:r0_67 +# 810| mu0_69(unknown) = ^CallSideEffect : ~mu0_2 +# 810| v0_70(void) = ^IndirectReadSideEffect[-1] : &:r0_57, ~mu0_2 +# 810| v0_71(void) = ^IndirectReadSideEffect[0] : &:r0_67, ~mu0_2 +# 810| mu0_72(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_57 +# 810| mu0_73(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_67 +# 811| r0_74(glval) = VariableAddress[pm] : +# 811| r0_75(Middle *) = Load : &:r0_74, ~mu0_2 +# 811| r0_76(Base *) = ConvertToBase[Middle : Base] : r0_75 +# 811| r0_77(glval) = VariableAddress[pb] : +# 811| mu0_78(Base *) = Store : &:r0_77, r0_76 +# 812| r0_79(glval) = VariableAddress[pm] : +# 812| r0_80(Middle *) = Load : &:r0_79, ~mu0_2 +# 812| r0_81(Base *) = ConvertToBase[Middle : Base] : r0_80 +# 812| r0_82(glval) = VariableAddress[pb] : +# 812| mu0_83(Base *) = Store : &:r0_82, r0_81 +# 813| r0_84(glval) = VariableAddress[pm] : +# 813| r0_85(Middle *) = Load : &:r0_84, ~mu0_2 +# 813| r0_86(Base *) = ConvertToBase[Middle : Base] : r0_85 +# 813| r0_87(glval) = VariableAddress[pb] : +# 813| mu0_88(Base *) = Store : &:r0_87, r0_86 +# 814| r0_89(glval) = VariableAddress[pm] : +# 814| r0_90(Middle *) = Load : &:r0_89, ~mu0_2 +# 814| r0_91(Base *) = Convert : r0_90 +# 814| r0_92(glval) = VariableAddress[pb] : +# 814| mu0_93(Base *) = Store : &:r0_92, r0_91 +# 816| r0_94(glval) = VariableAddress[m] : +# 816| r0_95(glval) = FunctionAddress[operator=] : +# 816| r0_96(glval) = VariableAddress[b] : +# 816| r0_97(glval) = ConvertToDerived[Middle : Base] : r0_96 +# 816| r0_98(glval) = Convert : r0_97 +# 816| r0_99(Middle &) = Call : func:r0_95, this:r0_94, 0:r0_98 +# 816| mu0_100(unknown) = ^CallSideEffect : ~mu0_2 +# 816| v0_101(void) = ^IndirectReadSideEffect[-1] : &:r0_94, ~mu0_2 +# 816| v0_102(void) = ^IndirectReadSideEffect[0] : &:r0_98, ~mu0_2 +# 816| mu0_103(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_94 +# 816| mu0_104(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_98 +# 817| r0_105(glval) = VariableAddress[m] : +# 817| r0_106(glval) = FunctionAddress[operator=] : +# 817| r0_107(glval) = VariableAddress[b] : +# 817| r0_108(glval) = ConvertToDerived[Middle : Base] : r0_107 +# 817| r0_109(glval) = Convert : r0_108 +# 817| r0_110(Middle &) = Call : func:r0_106, this:r0_105, 0:r0_109 +# 817| mu0_111(unknown) = ^CallSideEffect : ~mu0_2 +# 817| v0_112(void) = ^IndirectReadSideEffect[-1] : &:r0_105, ~mu0_2 +# 817| v0_113(void) = ^IndirectReadSideEffect[0] : &:r0_109, ~mu0_2 +# 817| mu0_114(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_105 +# 817| mu0_115(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_109 +# 818| r0_116(glval) = VariableAddress[pb] : +# 818| r0_117(Base *) = Load : &:r0_116, ~mu0_2 +# 818| r0_118(Middle *) = ConvertToDerived[Middle : Base] : r0_117 +# 818| r0_119(glval) = VariableAddress[pm] : +# 818| mu0_120(Middle *) = Store : &:r0_119, r0_118 +# 819| r0_121(glval) = VariableAddress[pb] : +# 819| r0_122(Base *) = Load : &:r0_121, ~mu0_2 +# 819| r0_123(Middle *) = ConvertToDerived[Middle : Base] : r0_122 +# 819| r0_124(glval) = VariableAddress[pm] : +# 819| mu0_125(Middle *) = Store : &:r0_124, r0_123 +# 820| r0_126(glval) = VariableAddress[pb] : +# 820| r0_127(Base *) = Load : &:r0_126, ~mu0_2 +# 820| r0_128(Middle *) = Convert : r0_127 +# 820| r0_129(glval) = VariableAddress[pm] : +# 820| mu0_130(Middle *) = Store : &:r0_129, r0_128 +# 822| r0_131(glval) = VariableAddress[b] : +# 822| r0_132(glval) = FunctionAddress[operator=] : +# 822| r0_133(glval) = VariableAddress[d] : +# 822| r0_134(glval) = ConvertToBase[Derived : Middle] : r0_133 +# 822| r0_135(glval) = ConvertToBase[Middle : Base] : r0_134 +# 822| r0_136(Base &) = Call : func:r0_132, this:r0_131, 0:r0_135 +# 822| mu0_137(unknown) = ^CallSideEffect : ~mu0_2 +# 822| v0_138(void) = ^IndirectReadSideEffect[-1] : &:r0_131, ~mu0_2 +# 822| v0_139(void) = ^IndirectReadSideEffect[0] : &:r0_135, ~mu0_2 +# 822| mu0_140(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_131 +# 822| mu0_141(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_135 +# 823| r0_142(glval) = VariableAddress[b] : +# 823| r0_143(glval) = FunctionAddress[operator=] : +# 823| r0_144(glval) = FunctionAddress[Base] : +# 823| r0_145(glval) = VariableAddress[d] : +# 823| r0_146(glval) = ConvertToBase[Derived : Middle] : r0_145 +# 823| r0_147(glval) = ConvertToBase[Middle : Base] : r0_146 +# 823| v0_148(void) = Call : func:r0_144, 0:r0_147 +# 823| mu0_149(unknown) = ^CallSideEffect : ~mu0_2 +# 823| mu0_150(Base) = ^IndirectMayWriteSideEffect[-1] : +# 823| v0_151(void) = ^IndirectReadSideEffect[0] : &:r0_147, ~mu0_2 +# 823| mu0_152(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_147 +# 823| r0_153(glval) = Convert : v0_148 +# 823| r0_154(Base &) = Call : func:r0_143, this:r0_142, 0:r0_153 +# 823| mu0_155(unknown) = ^CallSideEffect : ~mu0_2 +# 823| v0_156(void) = ^IndirectReadSideEffect[-1] : &:r0_142, ~mu0_2 +# 823| v0_157(void) = ^IndirectReadSideEffect[0] : &:r0_153, ~mu0_2 +# 823| mu0_158(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_142 +# 823| mu0_159(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_153 +# 824| r0_160(glval) = VariableAddress[b] : +# 824| r0_161(glval) = FunctionAddress[operator=] : +# 824| r0_162(glval) = FunctionAddress[Base] : +# 824| r0_163(glval) = VariableAddress[d] : +# 824| r0_164(glval) = ConvertToBase[Derived : Middle] : r0_163 +# 824| r0_165(glval) = ConvertToBase[Middle : Base] : r0_164 +# 824| v0_166(void) = Call : func:r0_162, 0:r0_165 +# 824| mu0_167(unknown) = ^CallSideEffect : ~mu0_2 +# 824| mu0_168(Base) = ^IndirectMayWriteSideEffect[-1] : +# 824| v0_169(void) = ^IndirectReadSideEffect[0] : &:r0_165, ~mu0_2 +# 824| mu0_170(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_165 +# 824| r0_171(glval) = Convert : v0_166 +# 824| r0_172(Base &) = Call : func:r0_161, this:r0_160, 0:r0_171 +# 824| mu0_173(unknown) = ^CallSideEffect : ~mu0_2 +# 824| v0_174(void) = ^IndirectReadSideEffect[-1] : &:r0_160, ~mu0_2 +# 824| v0_175(void) = ^IndirectReadSideEffect[0] : &:r0_171, ~mu0_2 +# 824| mu0_176(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_160 +# 824| mu0_177(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_171 +# 825| r0_178(glval) = VariableAddress[pd] : +# 825| r0_179(Derived *) = Load : &:r0_178, ~mu0_2 +# 825| r0_180(Middle *) = ConvertToBase[Derived : Middle] : r0_179 +# 825| r0_181(Base *) = ConvertToBase[Middle : Base] : r0_180 +# 825| r0_182(glval) = VariableAddress[pb] : +# 825| mu0_183(Base *) = Store : &:r0_182, r0_181 +# 826| r0_184(glval) = VariableAddress[pd] : +# 826| r0_185(Derived *) = Load : &:r0_184, ~mu0_2 +# 826| r0_186(Middle *) = ConvertToBase[Derived : Middle] : r0_185 +# 826| r0_187(Base *) = ConvertToBase[Middle : Base] : r0_186 +# 826| r0_188(glval) = VariableAddress[pb] : +# 826| mu0_189(Base *) = Store : &:r0_188, r0_187 +# 827| r0_190(glval) = VariableAddress[pd] : +# 827| r0_191(Derived *) = Load : &:r0_190, ~mu0_2 +# 827| r0_192(Middle *) = ConvertToBase[Derived : Middle] : r0_191 +# 827| r0_193(Base *) = ConvertToBase[Middle : Base] : r0_192 +# 827| r0_194(glval) = VariableAddress[pb] : +# 827| mu0_195(Base *) = Store : &:r0_194, r0_193 +# 828| r0_196(glval) = VariableAddress[pd] : +# 828| r0_197(Derived *) = Load : &:r0_196, ~mu0_2 +# 828| r0_198(Base *) = Convert : r0_197 +# 828| r0_199(glval) = VariableAddress[pb] : +# 828| mu0_200(Base *) = Store : &:r0_199, r0_198 +# 830| r0_201(glval) = VariableAddress[d] : +# 830| r0_202(glval) = FunctionAddress[operator=] : +# 830| r0_203(glval) = VariableAddress[b] : +# 830| r0_204(glval) = ConvertToDerived[Middle : Base] : r0_203 +# 830| r0_205(glval) = ConvertToDerived[Derived : Middle] : r0_204 +# 830| r0_206(glval) = Convert : r0_205 +# 830| r0_207(Derived &) = Call : func:r0_202, this:r0_201, 0:r0_206 +# 830| mu0_208(unknown) = ^CallSideEffect : ~mu0_2 +# 830| v0_209(void) = ^IndirectReadSideEffect[-1] : &:r0_201, ~mu0_2 +# 830| v0_210(void) = ^IndirectReadSideEffect[0] : &:r0_206, ~mu0_2 +# 830| mu0_211(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_201 +# 830| mu0_212(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_206 +# 831| r0_213(glval) = VariableAddress[d] : +# 831| r0_214(glval) = FunctionAddress[operator=] : +# 831| r0_215(glval) = VariableAddress[b] : +# 831| r0_216(glval) = ConvertToDerived[Middle : Base] : r0_215 +# 831| r0_217(glval) = ConvertToDerived[Derived : Middle] : r0_216 +# 831| r0_218(glval) = Convert : r0_217 +# 831| r0_219(Derived &) = Call : func:r0_214, this:r0_213, 0:r0_218 +# 831| mu0_220(unknown) = ^CallSideEffect : ~mu0_2 +# 831| v0_221(void) = ^IndirectReadSideEffect[-1] : &:r0_213, ~mu0_2 +# 831| v0_222(void) = ^IndirectReadSideEffect[0] : &:r0_218, ~mu0_2 +# 831| mu0_223(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r0_213 +# 831| mu0_224(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_218 +# 832| r0_225(glval) = VariableAddress[pb] : +# 832| r0_226(Base *) = Load : &:r0_225, ~mu0_2 +# 832| r0_227(Middle *) = ConvertToDerived[Middle : Base] : r0_226 +# 832| r0_228(Derived *) = ConvertToDerived[Derived : Middle] : r0_227 +# 832| r0_229(glval) = VariableAddress[pd] : +# 832| mu0_230(Derived *) = Store : &:r0_229, r0_228 +# 833| r0_231(glval) = VariableAddress[pb] : +# 833| r0_232(Base *) = Load : &:r0_231, ~mu0_2 +# 833| r0_233(Middle *) = ConvertToDerived[Middle : Base] : r0_232 +# 833| r0_234(Derived *) = ConvertToDerived[Derived : Middle] : r0_233 +# 833| r0_235(glval) = VariableAddress[pd] : +# 833| mu0_236(Derived *) = Store : &:r0_235, r0_234 +# 834| r0_237(glval) = VariableAddress[pb] : +# 834| r0_238(Base *) = Load : &:r0_237, ~mu0_2 +# 834| r0_239(Derived *) = Convert : r0_238 +# 834| r0_240(glval) = VariableAddress[pd] : +# 834| mu0_241(Derived *) = Store : &:r0_240, r0_239 +# 836| r0_242(glval) = VariableAddress[pmv] : +# 836| r0_243(MiddleVB1 *) = Constant[0] : +# 836| mu0_244(MiddleVB1 *) = Store : &:r0_242, r0_243 +# 837| r0_245(glval) = VariableAddress[pdv] : +# 837| r0_246(DerivedVB *) = Constant[0] : +# 837| mu0_247(DerivedVB *) = Store : &:r0_245, r0_246 +# 838| r0_248(glval) = VariableAddress[pmv] : +# 838| r0_249(MiddleVB1 *) = Load : &:r0_248, ~mu0_2 +# 838| r0_250(Base *) = ConvertToVirtualBase[MiddleVB1 : Base] : r0_249 +# 838| r0_251(glval) = VariableAddress[pb] : +# 838| mu0_252(Base *) = Store : &:r0_251, r0_250 +# 839| r0_253(glval) = VariableAddress[pdv] : +# 839| r0_254(DerivedVB *) = Load : &:r0_253, ~mu0_2 +# 839| r0_255(Base *) = ConvertToVirtualBase[DerivedVB : Base] : r0_254 +# 839| r0_256(glval) = VariableAddress[pb] : +# 839| mu0_257(Base *) = Store : &:r0_256, r0_255 +# 840| v0_258(void) = NoOp : +# 799| v0_259(void) = ReturnVoid : +# 799| v0_260(void) = UnmodeledUse : mu* +# 799| v0_261(void) = ExitFunction : # 842| void PolymorphicBase::PolymorphicBase() # 842| Block 0 @@ -3944,53 +3950,55 @@ ir.cpp: # 849| mu0_1(unknown) = AliasedDefinition : # 849| mu0_2(unknown) = UnmodeledDefinition : # 850| r0_3(glval) = VariableAddress[b] : -#-----| r0_4(glval) = FunctionAddress[PolymorphicBase] : -#-----| v0_5(void) = Call : func:r0_4, this:r0_3 -#-----| mu0_6(unknown) = ^CallSideEffect : ~mu0_2 -#-----| mu0_7(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 -# 851| r0_8(glval) = VariableAddress[d] : -# 851| r0_9(glval) = FunctionAddress[PolymorphicDerived] : -# 851| v0_10(void) = Call : func:r0_9, this:r0_8 -# 851| mu0_11(unknown) = ^CallSideEffect : ~mu0_2 -# 851| mu0_12(PolymorphicDerived) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 -# 853| r0_13(glval) = VariableAddress[pb] : -# 853| r0_14(glval) = VariableAddress[b] : -# 853| mu0_15(PolymorphicBase *) = Store : &:r0_13, r0_14 -# 854| r0_16(glval) = VariableAddress[pd] : -# 854| r0_17(glval) = VariableAddress[d] : -# 854| mu0_18(PolymorphicDerived *) = Store : &:r0_16, r0_17 -# 857| r0_19(glval) = VariableAddress[pd] : -# 857| r0_20(PolymorphicDerived *) = Load : &:r0_19, ~mu0_2 -# 857| r0_21(PolymorphicBase *) = CheckedConvertOrNull : r0_20 -# 857| r0_22(glval) = VariableAddress[pb] : -# 857| mu0_23(PolymorphicBase *) = Store : &:r0_22, r0_21 -# 858| r0_24(glval) = VariableAddress[rb] : -# 858| r0_25(glval) = VariableAddress[d] : -# 858| r0_26(glval) = CheckedConvertOrThrow : r0_25 -# 858| mu0_27(PolymorphicBase &) = Store : &:r0_24, r0_26 -# 860| r0_28(glval) = VariableAddress[pb] : -# 860| r0_29(PolymorphicBase *) = Load : &:r0_28, ~mu0_2 -# 860| r0_30(PolymorphicDerived *) = CheckedConvertOrNull : r0_29 -# 860| r0_31(glval) = VariableAddress[pd] : -# 860| mu0_32(PolymorphicDerived *) = Store : &:r0_31, r0_30 -# 861| r0_33(glval) = VariableAddress[rd] : -# 861| r0_34(glval) = VariableAddress[b] : -# 861| r0_35(glval) = CheckedConvertOrThrow : r0_34 -# 861| mu0_36(PolymorphicDerived &) = Store : &:r0_33, r0_35 -# 863| r0_37(glval) = VariableAddress[pv] : -# 863| r0_38(glval) = VariableAddress[pb] : -# 863| r0_39(PolymorphicBase *) = Load : &:r0_38, ~mu0_2 -# 863| r0_40(void *) = DynamicCastToVoid : r0_39 -# 863| mu0_41(void *) = Store : &:r0_37, r0_40 -# 864| r0_42(glval) = VariableAddress[pcv] : -# 864| r0_43(glval) = VariableAddress[pd] : -# 864| r0_44(PolymorphicDerived *) = Load : &:r0_43, ~mu0_2 -# 864| r0_45(void *) = DynamicCastToVoid : r0_44 -# 864| mu0_46(void *) = Store : &:r0_42, r0_45 -# 865| v0_47(void) = NoOp : -# 849| v0_48(void) = ReturnVoid : -# 849| v0_49(void) = UnmodeledUse : mu* -# 849| v0_50(void) = ExitFunction : +# 850| mu0_4(PolymorphicBase) = Uninitialized[b] : &:r0_3 +#-----| r0_5(glval) = FunctionAddress[PolymorphicBase] : +#-----| v0_6(void) = Call : func:r0_5, this:r0_3 +#-----| mu0_7(unknown) = ^CallSideEffect : ~mu0_2 +#-----| mu0_8(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 +# 851| r0_9(glval) = VariableAddress[d] : +# 851| mu0_10(PolymorphicDerived) = Uninitialized[d] : &:r0_9 +# 851| r0_11(glval) = FunctionAddress[PolymorphicDerived] : +# 851| v0_12(void) = Call : func:r0_11, this:r0_9 +# 851| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 +# 851| mu0_14(PolymorphicDerived) = ^IndirectMayWriteSideEffect[-1] : &:r0_9 +# 853| r0_15(glval) = VariableAddress[pb] : +# 853| r0_16(glval) = VariableAddress[b] : +# 853| mu0_17(PolymorphicBase *) = Store : &:r0_15, r0_16 +# 854| r0_18(glval) = VariableAddress[pd] : +# 854| r0_19(glval) = VariableAddress[d] : +# 854| mu0_20(PolymorphicDerived *) = Store : &:r0_18, r0_19 +# 857| r0_21(glval) = VariableAddress[pd] : +# 857| r0_22(PolymorphicDerived *) = Load : &:r0_21, ~mu0_2 +# 857| r0_23(PolymorphicBase *) = CheckedConvertOrNull : r0_22 +# 857| r0_24(glval) = VariableAddress[pb] : +# 857| mu0_25(PolymorphicBase *) = Store : &:r0_24, r0_23 +# 858| r0_26(glval) = VariableAddress[rb] : +# 858| r0_27(glval) = VariableAddress[d] : +# 858| r0_28(glval) = CheckedConvertOrThrow : r0_27 +# 858| mu0_29(PolymorphicBase &) = Store : &:r0_26, r0_28 +# 860| r0_30(glval) = VariableAddress[pb] : +# 860| r0_31(PolymorphicBase *) = Load : &:r0_30, ~mu0_2 +# 860| r0_32(PolymorphicDerived *) = CheckedConvertOrNull : r0_31 +# 860| r0_33(glval) = VariableAddress[pd] : +# 860| mu0_34(PolymorphicDerived *) = Store : &:r0_33, r0_32 +# 861| r0_35(glval) = VariableAddress[rd] : +# 861| r0_36(glval) = VariableAddress[b] : +# 861| r0_37(glval) = CheckedConvertOrThrow : r0_36 +# 861| mu0_38(PolymorphicDerived &) = Store : &:r0_35, r0_37 +# 863| r0_39(glval) = VariableAddress[pv] : +# 863| r0_40(glval) = VariableAddress[pb] : +# 863| r0_41(PolymorphicBase *) = Load : &:r0_40, ~mu0_2 +# 863| r0_42(void *) = DynamicCastToVoid : r0_41 +# 863| mu0_43(void *) = Store : &:r0_39, r0_42 +# 864| r0_44(glval) = VariableAddress[pcv] : +# 864| r0_45(glval) = VariableAddress[pd] : +# 864| r0_46(PolymorphicDerived *) = Load : &:r0_45, ~mu0_2 +# 864| r0_47(void *) = DynamicCastToVoid : r0_46 +# 864| mu0_48(void *) = Store : &:r0_44, r0_47 +# 865| v0_49(void) = NoOp : +# 849| v0_50(void) = ReturnVoid : +# 849| v0_51(void) = UnmodeledUse : mu* +# 849| v0_52(void) = ExitFunction : # 867| void String::String() # 867| Block 0 @@ -4714,133 +4722,135 @@ ir.cpp: # 1035| v0_31(void) = ^IndirectReadSideEffect[-1] : &:r0_26, ~mu0_2 # 1035| mu0_32(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_26 # 1036| r0_33(glval) = VariableAddress[lambda_val] : -# 1036| r0_34(glval) = FunctionAddress[(constructor)] : -# 1036| r0_35(glval) = VariableAddress[#temp1036:21] : -# 1036| mu0_36(decltype([...](...){...})) = Uninitialized[#temp1036:21] : &:r0_35 -# 1036| r0_37(glval) = FieldAddress[s] : r0_35 -#-----| r0_38(glval) = FunctionAddress[String] : -#-----| v0_39(void) = Call : func:r0_38, this:r0_37 -#-----| mu0_40(unknown) = ^CallSideEffect : ~mu0_2 -#-----| mu0_41(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_37 -# 1036| r0_42(glval) = FieldAddress[x] : r0_35 -#-----| r0_43(glval) = VariableAddress[x] : -#-----| r0_44(int) = Load : &:r0_43, ~mu0_2 -#-----| mu0_45(int) = Store : &:r0_42, r0_44 -# 1036| r0_46(decltype([...](...){...})) = Load : &:r0_35, ~mu0_2 -# 1036| v0_47(void) = Call : func:r0_34, this:r0_33, 0:r0_46 -# 1036| mu0_48(unknown) = ^CallSideEffect : ~mu0_2 -# 1036| mu0_49(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_33 -# 1036| v0_50(void) = ^IndirectReadSideEffect[0] : &:r0_46, ~mu0_2 -# 1036| mu0_51(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_46 -# 1037| r0_52(glval) = VariableAddress[lambda_val] : -# 1037| r0_53(glval) = Convert : r0_52 -# 1037| r0_54(glval) = FunctionAddress[operator()] : -# 1037| r0_55(float) = Constant[2.0] : -# 1037| r0_56(char) = Call : func:r0_54, this:r0_53, 0:r0_55 -# 1037| mu0_57(unknown) = ^CallSideEffect : ~mu0_2 -# 1037| v0_58(void) = ^IndirectReadSideEffect[-1] : &:r0_53, ~mu0_2 -# 1037| mu0_59(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_53 -# 1038| r0_60(glval) = VariableAddress[lambda_ref_explicit] : -# 1038| r0_61(glval) = VariableAddress[#temp1038:30] : -# 1038| mu0_62(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_61 -# 1038| r0_63(glval) = FieldAddress[s] : r0_61 -# 1038| r0_64(glval) = VariableAddress[s] : -# 1038| r0_65(String &) = Load : &:r0_64, ~mu0_2 -# 1038| mu0_66(String &) = Store : &:r0_63, r0_65 -# 1038| r0_67(decltype([...](...){...})) = Load : &:r0_61, ~mu0_2 -# 1038| mu0_68(decltype([...](...){...})) = Store : &:r0_60, r0_67 -# 1039| r0_69(glval) = VariableAddress[lambda_ref_explicit] : -# 1039| r0_70(glval) = Convert : r0_69 -# 1039| r0_71(glval) = FunctionAddress[operator()] : -# 1039| r0_72(float) = Constant[3.0] : -# 1039| r0_73(char) = Call : func:r0_71, this:r0_70, 0:r0_72 -# 1039| mu0_74(unknown) = ^CallSideEffect : ~mu0_2 -# 1039| v0_75(void) = ^IndirectReadSideEffect[-1] : &:r0_70, ~mu0_2 -# 1039| mu0_76(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_70 -# 1040| r0_77(glval) = VariableAddress[lambda_val_explicit] : -# 1040| r0_78(glval) = FunctionAddress[(constructor)] : -# 1040| r0_79(glval) = VariableAddress[#temp1040:30] : -# 1040| mu0_80(decltype([...](...){...})) = Uninitialized[#temp1040:30] : &:r0_79 -# 1040| r0_81(glval) = FieldAddress[s] : r0_79 -#-----| r0_82(glval) = FunctionAddress[String] : -#-----| v0_83(void) = Call : func:r0_82, this:r0_81 -#-----| mu0_84(unknown) = ^CallSideEffect : ~mu0_2 -#-----| mu0_85(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_81 -# 1040| r0_86(decltype([...](...){...})) = Load : &:r0_79, ~mu0_2 -# 1040| v0_87(void) = Call : func:r0_78, this:r0_77, 0:r0_86 -# 1040| mu0_88(unknown) = ^CallSideEffect : ~mu0_2 -# 1040| mu0_89(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_77 -# 1040| v0_90(void) = ^IndirectReadSideEffect[0] : &:r0_86, ~mu0_2 -# 1040| mu0_91(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_86 -# 1041| r0_92(glval) = VariableAddress[lambda_val_explicit] : -# 1041| r0_93(glval) = Convert : r0_92 -# 1041| r0_94(glval) = FunctionAddress[operator()] : -# 1041| r0_95(float) = Constant[4.0] : -# 1041| r0_96(char) = Call : func:r0_94, this:r0_93, 0:r0_95 -# 1041| mu0_97(unknown) = ^CallSideEffect : ~mu0_2 -# 1041| v0_98(void) = ^IndirectReadSideEffect[-1] : &:r0_93, ~mu0_2 -# 1041| mu0_99(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_93 -# 1042| r0_100(glval) = VariableAddress[lambda_mixed_explicit] : -# 1042| r0_101(glval) = VariableAddress[#temp1042:32] : -# 1042| mu0_102(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_101 -# 1042| r0_103(glval) = FieldAddress[s] : r0_101 -# 1042| r0_104(glval) = VariableAddress[s] : -# 1042| r0_105(String &) = Load : &:r0_104, ~mu0_2 -# 1042| mu0_106(String &) = Store : &:r0_103, r0_105 -# 1042| r0_107(glval) = FieldAddress[x] : r0_101 -# 1042| r0_108(glval) = VariableAddress[x] : -# 1042| r0_109(int) = Load : &:r0_108, ~mu0_2 -# 1042| mu0_110(int) = Store : &:r0_107, r0_109 -# 1042| r0_111(decltype([...](...){...})) = Load : &:r0_101, ~mu0_2 -# 1042| mu0_112(decltype([...](...){...})) = Store : &:r0_100, r0_111 -# 1043| r0_113(glval) = VariableAddress[lambda_mixed_explicit] : -# 1043| r0_114(glval) = Convert : r0_113 -# 1043| r0_115(glval) = FunctionAddress[operator()] : -# 1043| r0_116(float) = Constant[5.0] : -# 1043| r0_117(char) = Call : func:r0_115, this:r0_114, 0:r0_116 -# 1043| mu0_118(unknown) = ^CallSideEffect : ~mu0_2 -# 1043| v0_119(void) = ^IndirectReadSideEffect[-1] : &:r0_114, ~mu0_2 -# 1043| mu0_120(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_114 -# 1044| r0_121(glval) = VariableAddress[r] : -# 1044| r0_122(glval) = VariableAddress[x] : -# 1044| r0_123(int) = Load : &:r0_122, ~mu0_2 -# 1044| r0_124(int) = Constant[1] : -# 1044| r0_125(int) = Sub : r0_123, r0_124 -# 1044| mu0_126(int) = Store : &:r0_121, r0_125 -# 1045| r0_127(glval) = VariableAddress[lambda_inits] : -# 1045| r0_128(glval) = VariableAddress[#temp1045:23] : -# 1045| mu0_129(decltype([...](...){...})) = Uninitialized[#temp1045:23] : &:r0_128 -# 1045| r0_130(glval) = FieldAddress[s] : r0_128 -# 1045| r0_131(glval) = VariableAddress[s] : -# 1045| r0_132(String &) = Load : &:r0_131, ~mu0_2 -# 1045| mu0_133(String &) = Store : &:r0_130, r0_132 -# 1045| r0_134(glval) = FieldAddress[x] : r0_128 -# 1045| r0_135(glval) = VariableAddress[x] : -# 1045| r0_136(int) = Load : &:r0_135, ~mu0_2 -# 1045| mu0_137(int) = Store : &:r0_134, r0_136 -# 1045| r0_138(glval) = FieldAddress[i] : r0_128 -# 1045| r0_139(glval) = VariableAddress[x] : -# 1045| r0_140(int) = Load : &:r0_139, ~mu0_2 -# 1045| r0_141(int) = Constant[1] : -# 1045| r0_142(int) = Add : r0_140, r0_141 -# 1045| mu0_143(int) = Store : &:r0_138, r0_142 -# 1045| r0_144(glval) = FieldAddress[j] : r0_128 -# 1045| r0_145(glval) = VariableAddress[r] : -# 1045| mu0_146(int &) = Store : &:r0_144, r0_145 -# 1045| r0_147(decltype([...](...){...})) = Load : &:r0_128, ~mu0_2 -# 1045| mu0_148(decltype([...](...){...})) = Store : &:r0_127, r0_147 -# 1046| r0_149(glval) = VariableAddress[lambda_inits] : -# 1046| r0_150(glval) = Convert : r0_149 -# 1046| r0_151(glval) = FunctionAddress[operator()] : -# 1046| r0_152(float) = Constant[6.0] : -# 1046| r0_153(char) = Call : func:r0_151, this:r0_150, 0:r0_152 -# 1046| mu0_154(unknown) = ^CallSideEffect : ~mu0_2 -# 1046| v0_155(void) = ^IndirectReadSideEffect[-1] : &:r0_150, ~mu0_2 -# 1046| mu0_156(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_150 -# 1047| v0_157(void) = NoOp : -# 1031| v0_158(void) = ReturnVoid : -# 1031| v0_159(void) = UnmodeledUse : mu* -# 1031| v0_160(void) = ExitFunction : +# 1036| mu0_34(decltype([...](...){...})) = Uninitialized[lambda_val] : &:r0_33 +# 1036| r0_35(glval) = FunctionAddress[(constructor)] : +# 1036| r0_36(glval) = VariableAddress[#temp1036:21] : +# 1036| mu0_37(decltype([...](...){...})) = Uninitialized[#temp1036:21] : &:r0_36 +# 1036| r0_38(glval) = FieldAddress[s] : r0_36 +#-----| r0_39(glval) = FunctionAddress[String] : +#-----| v0_40(void) = Call : func:r0_39, this:r0_38 +#-----| mu0_41(unknown) = ^CallSideEffect : ~mu0_2 +#-----| mu0_42(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_38 +# 1036| r0_43(glval) = FieldAddress[x] : r0_36 +#-----| r0_44(glval) = VariableAddress[x] : +#-----| r0_45(int) = Load : &:r0_44, ~mu0_2 +#-----| mu0_46(int) = Store : &:r0_43, r0_45 +# 1036| r0_47(decltype([...](...){...})) = Load : &:r0_36, ~mu0_2 +# 1036| v0_48(void) = Call : func:r0_35, this:r0_33, 0:r0_47 +# 1036| mu0_49(unknown) = ^CallSideEffect : ~mu0_2 +# 1036| mu0_50(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_33 +# 1036| v0_51(void) = ^IndirectReadSideEffect[0] : &:r0_47, ~mu0_2 +# 1036| mu0_52(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_47 +# 1037| r0_53(glval) = VariableAddress[lambda_val] : +# 1037| r0_54(glval) = Convert : r0_53 +# 1037| r0_55(glval) = FunctionAddress[operator()] : +# 1037| r0_56(float) = Constant[2.0] : +# 1037| r0_57(char) = Call : func:r0_55, this:r0_54, 0:r0_56 +# 1037| mu0_58(unknown) = ^CallSideEffect : ~mu0_2 +# 1037| v0_59(void) = ^IndirectReadSideEffect[-1] : &:r0_54, ~mu0_2 +# 1037| mu0_60(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_54 +# 1038| r0_61(glval) = VariableAddress[lambda_ref_explicit] : +# 1038| r0_62(glval) = VariableAddress[#temp1038:30] : +# 1038| mu0_63(decltype([...](...){...})) = Uninitialized[#temp1038:30] : &:r0_62 +# 1038| r0_64(glval) = FieldAddress[s] : r0_62 +# 1038| r0_65(glval) = VariableAddress[s] : +# 1038| r0_66(String &) = Load : &:r0_65, ~mu0_2 +# 1038| mu0_67(String &) = Store : &:r0_64, r0_66 +# 1038| r0_68(decltype([...](...){...})) = Load : &:r0_62, ~mu0_2 +# 1038| mu0_69(decltype([...](...){...})) = Store : &:r0_61, r0_68 +# 1039| r0_70(glval) = VariableAddress[lambda_ref_explicit] : +# 1039| r0_71(glval) = Convert : r0_70 +# 1039| r0_72(glval) = FunctionAddress[operator()] : +# 1039| r0_73(float) = Constant[3.0] : +# 1039| r0_74(char) = Call : func:r0_72, this:r0_71, 0:r0_73 +# 1039| mu0_75(unknown) = ^CallSideEffect : ~mu0_2 +# 1039| v0_76(void) = ^IndirectReadSideEffect[-1] : &:r0_71, ~mu0_2 +# 1039| mu0_77(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_71 +# 1040| r0_78(glval) = VariableAddress[lambda_val_explicit] : +# 1040| mu0_79(decltype([...](...){...})) = Uninitialized[lambda_val_explicit] : &:r0_78 +# 1040| r0_80(glval) = FunctionAddress[(constructor)] : +# 1040| r0_81(glval) = VariableAddress[#temp1040:30] : +# 1040| mu0_82(decltype([...](...){...})) = Uninitialized[#temp1040:30] : &:r0_81 +# 1040| r0_83(glval) = FieldAddress[s] : r0_81 +#-----| r0_84(glval) = FunctionAddress[String] : +#-----| v0_85(void) = Call : func:r0_84, this:r0_83 +#-----| mu0_86(unknown) = ^CallSideEffect : ~mu0_2 +#-----| mu0_87(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_83 +# 1040| r0_88(decltype([...](...){...})) = Load : &:r0_81, ~mu0_2 +# 1040| v0_89(void) = Call : func:r0_80, this:r0_78, 0:r0_88 +# 1040| mu0_90(unknown) = ^CallSideEffect : ~mu0_2 +# 1040| mu0_91(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_78 +# 1040| v0_92(void) = ^IndirectReadSideEffect[0] : &:r0_88, ~mu0_2 +# 1040| mu0_93(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_88 +# 1041| r0_94(glval) = VariableAddress[lambda_val_explicit] : +# 1041| r0_95(glval) = Convert : r0_94 +# 1041| r0_96(glval) = FunctionAddress[operator()] : +# 1041| r0_97(float) = Constant[4.0] : +# 1041| r0_98(char) = Call : func:r0_96, this:r0_95, 0:r0_97 +# 1041| mu0_99(unknown) = ^CallSideEffect : ~mu0_2 +# 1041| v0_100(void) = ^IndirectReadSideEffect[-1] : &:r0_95, ~mu0_2 +# 1041| mu0_101(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_95 +# 1042| r0_102(glval) = VariableAddress[lambda_mixed_explicit] : +# 1042| r0_103(glval) = VariableAddress[#temp1042:32] : +# 1042| mu0_104(decltype([...](...){...})) = Uninitialized[#temp1042:32] : &:r0_103 +# 1042| r0_105(glval) = FieldAddress[s] : r0_103 +# 1042| r0_106(glval) = VariableAddress[s] : +# 1042| r0_107(String &) = Load : &:r0_106, ~mu0_2 +# 1042| mu0_108(String &) = Store : &:r0_105, r0_107 +# 1042| r0_109(glval) = FieldAddress[x] : r0_103 +# 1042| r0_110(glval) = VariableAddress[x] : +# 1042| r0_111(int) = Load : &:r0_110, ~mu0_2 +# 1042| mu0_112(int) = Store : &:r0_109, r0_111 +# 1042| r0_113(decltype([...](...){...})) = Load : &:r0_103, ~mu0_2 +# 1042| mu0_114(decltype([...](...){...})) = Store : &:r0_102, r0_113 +# 1043| r0_115(glval) = VariableAddress[lambda_mixed_explicit] : +# 1043| r0_116(glval) = Convert : r0_115 +# 1043| r0_117(glval) = FunctionAddress[operator()] : +# 1043| r0_118(float) = Constant[5.0] : +# 1043| r0_119(char) = Call : func:r0_117, this:r0_116, 0:r0_118 +# 1043| mu0_120(unknown) = ^CallSideEffect : ~mu0_2 +# 1043| v0_121(void) = ^IndirectReadSideEffect[-1] : &:r0_116, ~mu0_2 +# 1043| mu0_122(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_116 +# 1044| r0_123(glval) = VariableAddress[r] : +# 1044| r0_124(glval) = VariableAddress[x] : +# 1044| r0_125(int) = Load : &:r0_124, ~mu0_2 +# 1044| r0_126(int) = Constant[1] : +# 1044| r0_127(int) = Sub : r0_125, r0_126 +# 1044| mu0_128(int) = Store : &:r0_123, r0_127 +# 1045| r0_129(glval) = VariableAddress[lambda_inits] : +# 1045| r0_130(glval) = VariableAddress[#temp1045:23] : +# 1045| mu0_131(decltype([...](...){...})) = Uninitialized[#temp1045:23] : &:r0_130 +# 1045| r0_132(glval) = FieldAddress[s] : r0_130 +# 1045| r0_133(glval) = VariableAddress[s] : +# 1045| r0_134(String &) = Load : &:r0_133, ~mu0_2 +# 1045| mu0_135(String &) = Store : &:r0_132, r0_134 +# 1045| r0_136(glval) = FieldAddress[x] : r0_130 +# 1045| r0_137(glval) = VariableAddress[x] : +# 1045| r0_138(int) = Load : &:r0_137, ~mu0_2 +# 1045| mu0_139(int) = Store : &:r0_136, r0_138 +# 1045| r0_140(glval) = FieldAddress[i] : r0_130 +# 1045| r0_141(glval) = VariableAddress[x] : +# 1045| r0_142(int) = Load : &:r0_141, ~mu0_2 +# 1045| r0_143(int) = Constant[1] : +# 1045| r0_144(int) = Add : r0_142, r0_143 +# 1045| mu0_145(int) = Store : &:r0_140, r0_144 +# 1045| r0_146(glval) = FieldAddress[j] : r0_130 +# 1045| r0_147(glval) = VariableAddress[r] : +# 1045| mu0_148(int &) = Store : &:r0_146, r0_147 +# 1045| r0_149(decltype([...](...){...})) = Load : &:r0_130, ~mu0_2 +# 1045| mu0_150(decltype([...](...){...})) = Store : &:r0_129, r0_149 +# 1046| r0_151(glval) = VariableAddress[lambda_inits] : +# 1046| r0_152(glval) = Convert : r0_151 +# 1046| r0_153(glval) = FunctionAddress[operator()] : +# 1046| r0_154(float) = Constant[6.0] : +# 1046| r0_155(char) = Call : func:r0_153, this:r0_152, 0:r0_154 +# 1046| mu0_156(unknown) = ^CallSideEffect : ~mu0_2 +# 1046| v0_157(void) = ^IndirectReadSideEffect[-1] : &:r0_152, ~mu0_2 +# 1046| mu0_158(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r0_152 +# 1047| v0_159(void) = NoOp : +# 1031| v0_160(void) = ReturnVoid : +# 1031| v0_161(void) = UnmodeledUse : mu* +# 1031| v0_162(void) = ExitFunction : # 1032| void (void Lambda(int, String const&))::(lambda [] type at line 1032, col. 23)::(constructor)((void Lambda(int, String const&))::(lambda [] type at line 1032, col. 23)&&) # 1032| Block 0 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 813d7a9bdcd..84dca076691 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 @@ -884,36 +884,41 @@ ssa.cpp: # 220| m0_8(unknown) = ^CallSideEffect : ~m0_1 # 220| m0_9(unknown) = Chi : total:m0_1, partial:m0_8 # 220| m0_10(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 -# 221| r0_11(glval) = VariableAddress[c] : -# 221| r0_12(glval) = FunctionAddress[g] : -# 221| v0_13(void) = Call : func:r0_12, this:r0_11 -# 221| m0_14(unknown) = ^CallSideEffect : ~m0_9 -# 221| m0_15(unknown) = Chi : total:m0_9, partial:m0_14 -# 221| v0_16(void) = ^IndirectReadSideEffect[-1] : &:r0_11, m0_10 -# 221| m0_17(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_11 -# 222| r0_18(glval) = VariableAddress[c] : -# 222| r0_19(glval) = FunctionAddress[g] : -# 222| v0_20(void) = Call : func:r0_19, this:r0_18 -# 222| m0_21(unknown) = ^CallSideEffect : ~m0_15 -# 222| m0_22(unknown) = Chi : total:m0_15, partial:m0_21 -# 222| v0_23(void) = ^IndirectReadSideEffect[-1] : &:r0_18, m0_17 -# 222| m0_24(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_18 -# 223| r0_25(glval) = VariableAddress[c2] : -# 223| m0_26(Constructible) = Uninitialized[c2] : &:r0_25 -# 223| r0_27(glval) = FunctionAddress[Constructible] : -# 223| r0_28(int) = Constant[2] : -# 223| v0_29(void) = Call : func:r0_27, this:r0_25, 0:r0_28 -# 223| m0_30(unknown) = ^CallSideEffect : ~m0_22 -# 223| m0_31(unknown) = Chi : total:m0_22, partial:m0_30 -# 223| m0_32(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_25 -# 224| r0_33(glval) = VariableAddress[c2] : -# 224| r0_34(glval) = FunctionAddress[g] : -# 224| v0_35(void) = Call : func:r0_34, this:r0_33 -# 224| m0_36(unknown) = ^CallSideEffect : ~m0_31 -# 224| m0_37(unknown) = Chi : total:m0_31, partial:m0_36 -# 224| v0_38(void) = ^IndirectReadSideEffect[-1] : &:r0_33, m0_32 -# 224| m0_39(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_33 -# 225| v0_40(void) = NoOp : -# 219| v0_41(void) = ReturnVoid : -# 219| v0_42(void) = UnmodeledUse : mu* -# 219| v0_43(void) = ExitFunction : +# 220| m0_11(Constructible) = Chi : total:m0_10, partial:m0_10 +# 221| r0_12(glval) = VariableAddress[c] : +# 221| r0_13(glval) = FunctionAddress[g] : +# 221| v0_14(void) = Call : func:r0_13, this:r0_12 +# 221| m0_15(unknown) = ^CallSideEffect : ~m0_9 +# 221| m0_16(unknown) = Chi : total:m0_9, partial:m0_15 +# 221| v0_17(void) = ^IndirectReadSideEffect[-1] : &:r0_12, m0_10 +# 221| m0_18(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_12 +# 221| m0_19(Constructible) = Chi : total:m0_18, partial:m0_18 +# 222| r0_20(glval) = VariableAddress[c] : +# 222| r0_21(glval) = FunctionAddress[g] : +# 222| v0_22(void) = Call : func:r0_21, this:r0_20 +# 222| m0_23(unknown) = ^CallSideEffect : ~m0_16 +# 222| m0_24(unknown) = Chi : total:m0_16, partial:m0_23 +# 222| v0_25(void) = ^IndirectReadSideEffect[-1] : &:r0_20, m0_18 +# 222| m0_26(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_20 +# 222| m0_27(Constructible) = Chi : total:m0_26, partial:m0_26 +# 223| r0_28(glval) = VariableAddress[c2] : +# 223| m0_29(Constructible) = Uninitialized[c2] : &:r0_28 +# 223| r0_30(glval) = FunctionAddress[Constructible] : +# 223| r0_31(int) = Constant[2] : +# 223| v0_32(void) = Call : func:r0_30, this:r0_28, 0:r0_31 +# 223| m0_33(unknown) = ^CallSideEffect : ~m0_24 +# 223| m0_34(unknown) = Chi : total:m0_24, partial:m0_33 +# 223| m0_35(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_28 +# 223| m0_36(Constructible) = Chi : total:m0_35, partial:m0_35 +# 224| r0_37(glval) = VariableAddress[c2] : +# 224| r0_38(glval) = FunctionAddress[g] : +# 224| v0_39(void) = Call : func:r0_38, this:r0_37 +# 224| m0_40(unknown) = ^CallSideEffect : ~m0_34 +# 224| m0_41(unknown) = Chi : total:m0_34, partial:m0_40 +# 224| v0_42(void) = ^IndirectReadSideEffect[-1] : &:r0_37, m0_35 +# 224| m0_43(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_37 +# 224| m0_44(Constructible) = Chi : total:m0_43, partial:m0_43 +# 225| v0_45(void) = NoOp : +# 219| v0_46(void) = ReturnVoid : +# 219| v0_47(void) = UnmodeledUse : mu* +# 219| v0_48(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 029c552f5d5..a94e99610b1 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -837,37 +837,37 @@ ssa.cpp: # 219| mu0_1(unknown) = AliasedDefinition : # 219| mu0_2(unknown) = UnmodeledDefinition : # 220| r0_3(glval) = VariableAddress[c] : -# 220| m0_4(Constructible) = Uninitialized[c] : &:r0_3 +# 220| mu0_4(Constructible) = Uninitialized[c] : &:r0_3 # 220| r0_5(glval) = FunctionAddress[Constructible] : # 220| r0_6(int) = Constant[1] : # 220| v0_7(void) = Call : func:r0_5, this:r0_3, 0:r0_6 # 220| mu0_8(unknown) = ^CallSideEffect : ~mu0_2 -# 220| m0_9(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 +# 220| mu0_9(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 # 221| r0_10(glval) = VariableAddress[c] : # 221| r0_11(glval) = FunctionAddress[g] : # 221| v0_12(void) = Call : func:r0_11, this:r0_10 # 221| mu0_13(unknown) = ^CallSideEffect : ~mu0_2 -# 221| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_10, m0_9 -# 221| m0_15(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_10 +# 221| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_10, ~mu0_2 +# 221| mu0_15(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_10 # 222| r0_16(glval) = VariableAddress[c] : # 222| r0_17(glval) = FunctionAddress[g] : # 222| v0_18(void) = Call : func:r0_17, this:r0_16 # 222| mu0_19(unknown) = ^CallSideEffect : ~mu0_2 -# 222| v0_20(void) = ^IndirectReadSideEffect[-1] : &:r0_16, m0_15 -# 222| m0_21(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_16 +# 222| v0_20(void) = ^IndirectReadSideEffect[-1] : &:r0_16, ~mu0_2 +# 222| mu0_21(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_16 # 223| r0_22(glval) = VariableAddress[c2] : -# 223| m0_23(Constructible) = Uninitialized[c2] : &:r0_22 +# 223| mu0_23(Constructible) = Uninitialized[c2] : &:r0_22 # 223| r0_24(glval) = FunctionAddress[Constructible] : # 223| r0_25(int) = Constant[2] : # 223| v0_26(void) = Call : func:r0_24, this:r0_22, 0:r0_25 # 223| mu0_27(unknown) = ^CallSideEffect : ~mu0_2 -# 223| m0_28(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_22 +# 223| mu0_28(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_22 # 224| r0_29(glval) = VariableAddress[c2] : # 224| r0_30(glval) = FunctionAddress[g] : # 224| v0_31(void) = Call : func:r0_30, this:r0_29 # 224| mu0_32(unknown) = ^CallSideEffect : ~mu0_2 -# 224| v0_33(void) = ^IndirectReadSideEffect[-1] : &:r0_29, m0_28 -# 224| m0_34(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_29 +# 224| v0_33(void) = ^IndirectReadSideEffect[-1] : &:r0_29, ~mu0_2 +# 224| mu0_34(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_29 # 225| v0_35(void) = NoOp : # 219| v0_36(void) = ReturnVoid : # 219| v0_37(void) = UnmodeledUse : mu* From 17e14348d5d51978903f4f3688363756df7e60b7 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 4 Oct 2019 11:37:56 -0700 Subject: [PATCH 0384/1227] C++: sanity test for identical Chi node operands --- .../code/cpp/ir/implementation/aliased_ssa/Instruction.qll | 4 ++++ .../semmle/code/cpp/ir/implementation/raw/Instruction.qll | 4 ++++ .../cpp/ir/implementation/unaliased_ssa/Instruction.qll | 4 ++++ cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected | 5 +++++ cpp/ql/test/library-tests/ir/ir/raw_sanity.expected | 1 + .../test/library-tests/ir/ir/unaliased_ssa_sanity.expected | 1 + .../test/library-tests/ir/ssa/aliased_ssa_sanity.expected | 6 ++++++ .../test/library-tests/ir/ssa/unaliased_ssa_sanity.expected | 1 + .../code/csharp/ir/implementation/raw/Instruction.qll | 4 ++++ .../csharp/ir/implementation/unaliased_ssa/Instruction.qll | 4 ++++ 10 files changed, 34 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index efc873b8f44..acaf7569439 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -120,6 +120,10 @@ module InstructionSanity { ) } + query predicate duplicateChiOperand(ChiInstruction chi) { + chi.getTotal() = chi.getPartial() + } + /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index efc873b8f44..acaf7569439 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -120,6 +120,10 @@ module InstructionSanity { ) } + query predicate duplicateChiOperand(ChiInstruction chi) { + chi.getTotal() = chi.getPartial() + } + /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index efc873b8f44..acaf7569439 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -120,6 +120,10 @@ module InstructionSanity { ) } + query predicate duplicateChiOperand(ChiInstruction chi) { + chi.getTotal() = chi.getPartial() + } + /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected index d86f9a05334..5fece7284c9 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected @@ -7,6 +7,11 @@ unexpectedOperand duplicateOperand missingPhiOperand missingOperandType +duplicateChiOperand +| ir.cpp:1035:3:1035:12 | Chi: (const lambda [] type at line 1034, col. 21)... | +| ir.cpp:1039:3:1039:21 | Chi: (const lambda [] type at line 1038, col. 30)... | +| ir.cpp:1043:3:1043:23 | Chi: (const lambda [] type at line 1042, col. 32)... | +| ir.cpp:1046:3:1046:14 | Chi: (const lambda [] type at line 1045, col. 23)... | instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected index d86f9a05334..ff4f9c7af57 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected @@ -7,6 +7,7 @@ unexpectedOperand duplicateOperand missingPhiOperand missingOperandType +duplicateChiOperand instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected index d86f9a05334..ff4f9c7af57 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -7,6 +7,7 @@ unexpectedOperand duplicateOperand missingPhiOperand missingOperandType +duplicateChiOperand instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected index ae680785ce6..7cd6618fc2b 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected @@ -3,6 +3,12 @@ unexpectedOperand duplicateOperand missingPhiOperand missingOperandType +duplicateChiOperand +| ssa.cpp:220:19:220:20 | Chi: call to Constructible | +| ssa.cpp:221:3:221:3 | Chi: c | +| ssa.cpp:222:3:222:3 | Chi: c | +| ssa.cpp:223:21:223:37 | Chi: call to Constructible | +| ssa.cpp:224:3:224:4 | Chi: c2 | instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected index ae680785ce6..47daae9bc6f 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected @@ -3,6 +3,7 @@ unexpectedOperand duplicateOperand missingPhiOperand missingOperandType +duplicateChiOperand instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index efc873b8f44..acaf7569439 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -120,6 +120,10 @@ module InstructionSanity { ) } + query predicate duplicateChiOperand(ChiInstruction chi) { + chi.getTotal() = chi.getPartial() + } + /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index efc873b8f44..acaf7569439 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -120,6 +120,10 @@ module InstructionSanity { ) } + query predicate duplicateChiOperand(ChiInstruction chi) { + chi.getTotal() = chi.getPartial() + } + /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ From 057c634fe425d8371a2c75b30f0a09e215de5ba1 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 4 Oct 2019 13:05:47 -0700 Subject: [PATCH 0385/1227] C++: fix identical chi node operands --- .../aliased_ssa/internal/SSAConstruction.qll | 4 +++- .../unaliased_ssa/internal/SSAConstruction.qll | 4 +++- .../ir/ir/aliased_ssa_sanity.expected | 4 ---- .../library-tests/ir/ssa/aliased_ssa_ir.expected | 16 ++++++++-------- .../ir/ssa/aliased_ssa_sanity.expected | 5 ----- 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 753cca6b955..df82ed10f3a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -740,7 +740,9 @@ module DefUse { block.getInstruction(index) = def and overlap = Alias::getOverlap(defLocation, useLocation) and if - overlap instanceof MayPartiallyOverlap + overlap instanceof MayPartiallyOverlap or + def.getResultMemoryAccess() instanceof IndirectMayMemoryAccess or + def.getResultMemoryAccess() instanceof BufferMayMemoryAccess then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction. else offset = index * 2 // The use will be connected to the definition on the original instruction. ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 753cca6b955..df82ed10f3a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -740,7 +740,9 @@ module DefUse { block.getInstruction(index) = def and overlap = Alias::getOverlap(defLocation, useLocation) and if - overlap instanceof MayPartiallyOverlap + overlap instanceof MayPartiallyOverlap or + def.getResultMemoryAccess() instanceof IndirectMayMemoryAccess or + def.getResultMemoryAccess() instanceof BufferMayMemoryAccess then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction. else offset = index * 2 // The use will be connected to the definition on the original instruction. ) diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected index 5fece7284c9..ff4f9c7af57 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected @@ -8,10 +8,6 @@ duplicateOperand missingPhiOperand missingOperandType duplicateChiOperand -| ir.cpp:1035:3:1035:12 | Chi: (const lambda [] type at line 1034, col. 21)... | -| ir.cpp:1039:3:1039:21 | Chi: (const lambda [] type at line 1038, col. 30)... | -| ir.cpp:1043:3:1043:23 | Chi: (const lambda [] type at line 1042, col. 32)... | -| ir.cpp:1046:3:1046:14 | Chi: (const lambda [] type at line 1045, col. 23)... | instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop 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 84dca076691..c11dd129637 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 @@ -884,23 +884,23 @@ ssa.cpp: # 220| m0_8(unknown) = ^CallSideEffect : ~m0_1 # 220| m0_9(unknown) = Chi : total:m0_1, partial:m0_8 # 220| m0_10(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 -# 220| m0_11(Constructible) = Chi : total:m0_10, partial:m0_10 +# 220| m0_11(Constructible) = Chi : total:m0_4, partial:m0_10 # 221| r0_12(glval) = VariableAddress[c] : # 221| r0_13(glval) = FunctionAddress[g] : # 221| v0_14(void) = Call : func:r0_13, this:r0_12 # 221| m0_15(unknown) = ^CallSideEffect : ~m0_9 # 221| m0_16(unknown) = Chi : total:m0_9, partial:m0_15 -# 221| v0_17(void) = ^IndirectReadSideEffect[-1] : &:r0_12, m0_10 +# 221| v0_17(void) = ^IndirectReadSideEffect[-1] : &:r0_12, m0_11 # 221| m0_18(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_12 -# 221| m0_19(Constructible) = Chi : total:m0_18, partial:m0_18 +# 221| m0_19(Constructible) = Chi : total:m0_11, partial:m0_18 # 222| r0_20(glval) = VariableAddress[c] : # 222| r0_21(glval) = FunctionAddress[g] : # 222| v0_22(void) = Call : func:r0_21, this:r0_20 # 222| m0_23(unknown) = ^CallSideEffect : ~m0_16 # 222| m0_24(unknown) = Chi : total:m0_16, partial:m0_23 -# 222| v0_25(void) = ^IndirectReadSideEffect[-1] : &:r0_20, m0_18 +# 222| v0_25(void) = ^IndirectReadSideEffect[-1] : &:r0_20, m0_19 # 222| m0_26(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_20 -# 222| m0_27(Constructible) = Chi : total:m0_26, partial:m0_26 +# 222| m0_27(Constructible) = Chi : total:m0_19, partial:m0_26 # 223| r0_28(glval) = VariableAddress[c2] : # 223| m0_29(Constructible) = Uninitialized[c2] : &:r0_28 # 223| r0_30(glval) = FunctionAddress[Constructible] : @@ -909,15 +909,15 @@ ssa.cpp: # 223| m0_33(unknown) = ^CallSideEffect : ~m0_24 # 223| m0_34(unknown) = Chi : total:m0_24, partial:m0_33 # 223| m0_35(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_28 -# 223| m0_36(Constructible) = Chi : total:m0_35, partial:m0_35 +# 223| m0_36(Constructible) = Chi : total:m0_29, partial:m0_35 # 224| r0_37(glval) = VariableAddress[c2] : # 224| r0_38(glval) = FunctionAddress[g] : # 224| v0_39(void) = Call : func:r0_38, this:r0_37 # 224| m0_40(unknown) = ^CallSideEffect : ~m0_34 # 224| m0_41(unknown) = Chi : total:m0_34, partial:m0_40 -# 224| v0_42(void) = ^IndirectReadSideEffect[-1] : &:r0_37, m0_35 +# 224| v0_42(void) = ^IndirectReadSideEffect[-1] : &:r0_37, m0_36 # 224| m0_43(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_37 -# 224| m0_44(Constructible) = Chi : total:m0_43, partial:m0_43 +# 224| m0_44(Constructible) = Chi : total:m0_36, partial:m0_43 # 225| v0_45(void) = NoOp : # 219| v0_46(void) = ReturnVoid : # 219| v0_47(void) = UnmodeledUse : mu* diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected index 7cd6618fc2b..47daae9bc6f 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected @@ -4,11 +4,6 @@ duplicateOperand missingPhiOperand missingOperandType duplicateChiOperand -| ssa.cpp:220:19:220:20 | Chi: call to Constructible | -| ssa.cpp:221:3:221:3 | Chi: c | -| ssa.cpp:222:3:222:3 | Chi: c | -| ssa.cpp:223:21:223:37 | Chi: call to Constructible | -| ssa.cpp:224:3:224:4 | Chi: c2 | instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop From 28021d67152460f6441863b780c29e4bef1733e3 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Sun, 6 Oct 2019 20:50:14 +0200 Subject: [PATCH 0386/1227] C#: Add test for local function in lambda --- csharp/ql/test/library-tests/csharp7/CSharp7.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/library-tests/csharp7/CSharp7.cs b/csharp/ql/test/library-tests/csharp7/CSharp7.cs index 05d5896f4a9..0b42403f6c0 100644 --- a/csharp/ql/test/library-tests/csharp7/CSharp7.cs +++ b/csharp/ql/test/library-tests/csharp7/CSharp7.cs @@ -148,9 +148,9 @@ class LocalFunctions return f9(1); } - { + Action a = () => { int f9() => 0; - } + }; return f1(2); } From 8ba94140b1b082c75ab1e197eb1ffdb63d821565 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Sun, 6 Oct 2019 20:53:01 +0200 Subject: [PATCH 0387/1227] C#: Use containing type instead of containing method in local function TRAP label This is in order to handle the case where the enclosing callable of a local function is a lambda expression. --- .../Semmle.Extraction.CSharp/Entities/LocalFunction.cs | 10 ++-------- .../test/library-tests/csharp7/LocalFunctions.expected | 2 +- .../test/library-tests/csharp7/LocalVariables.expected | 1 + 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs index 64a2c1e3eac..f58c027eca5 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs @@ -11,17 +11,11 @@ namespace Semmle.Extraction.CSharp.Entities { } - Method ContainingMethod => - symbol.OriginalDefinition.ContainingSymbol is IMethodSymbol m - ? Method.Create(Context, m) - : throw new InternalError(symbol, "Unable to determine local function's containing callable"); - public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(ContainingMethod); - trapFile.Write(".("); + trapFile.WriteSubId(ContainingType); + trapFile.Write("."); trapFile.WriteSubId(Location); - trapFile.Write(')'); if (symbol.IsGenericMethod && !IsSourceDeclaration) { trapFile.Write('<'); diff --git a/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected b/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected index ad990659314..89c25f6102d 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalFunctions.expected @@ -5,7 +5,7 @@ | CSharp7.cs:143:9:143:31 | f7 | f7 | Int32 | CSharp7.cs:130:5:156:5 | {...} | CSharp7.cs:143:9:143:31 | f7(...) | f7(int) | | CSharp7.cs:145:9:149:9 | f8 | f8 | Int32 | CSharp7.cs:130:5:156:5 | {...} | CSharp7.cs:145:9:149:9 | f8(...) | f8() | | CSharp7.cs:147:13:147:35 | f9 | f9 | Int32 | CSharp7.cs:146:9:149:9 | {...} | CSharp7.cs:147:13:147:35 | f9(...) | f9(int) | -| CSharp7.cs:152:13:152:26 | f9 | f9 | Int32 | CSharp7.cs:151:9:153:9 | {...} | CSharp7.cs:152:13:152:26 | f9(...) | f9() | +| CSharp7.cs:152:13:152:26 | f9 | f9 | Int32 | CSharp7.cs:151:26:153:9 | {...} | CSharp7.cs:152:13:152:26 | f9(...) | f9() | | CSharp7.cs:160:9:160:24 | f | f | Int32 | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:160:9:160:24 | f(...) | f() | | CSharp7.cs:160:9:160:24 | f | f | Int32 | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:160:9:160:24 | f(...) | f() | | CSharp7.cs:161:9:161:25 | g | g | T | CSharp7.cs:159:5:172:5 | {...} | CSharp7.cs:161:9:161:25 | g(...) | g(T) | diff --git a/csharp/ql/test/library-tests/csharp7/LocalVariables.expected b/csharp/ql/test/library-tests/csharp7/LocalVariables.expected index 1e04aeafd00..33514e8f6a3 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalVariables.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalVariables.expected @@ -35,6 +35,7 @@ | CSharp7.cs:123:16:123:18 | m13 | string | | CSharp7.cs:135:19:135:20 | f4 | Func | | CSharp7.cs:139:24:139:25 | f5 | Func | +| CSharp7.cs:151:16:151:16 | a | Action | | CSharp7.cs:176:16:176:18 | src | string | | CSharp7.cs:181:13:181:17 | sink1 | string | | CSharp7.cs:182:13:182:17 | sink2 | string | From fb181c2d147b790744760867e2b4d41a42203d55 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Aug 2019 12:21:08 +0100 Subject: [PATCH 0388/1227] JS: Use type info and type tracking in jQuery --- .../ql/src/semmle/javascript/Extend.qll | 4 +- .../semmle/javascript/frameworks/jQuery.qll | 197 ++++++++++++++---- .../jQuery/JQueryMethodCall.expected | 6 + .../jQuery/interpretsArgumentAsHtml.expected | 6 + .../frameworks/jQuery/jquery.d.ts | 5 + .../frameworks/jQuery/tracking.js | 18 ++ .../frameworks/jQuery/ts_global_types.ts | 7 + .../frameworks/jQuery/ts_import.ts | 7 + .../frameworks/jQuery/tsconfig.json | 1 + 9 files changed, 210 insertions(+), 41 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/jQuery/jquery.d.ts create mode 100644 javascript/ql/test/library-tests/frameworks/jQuery/tracking.js create mode 100644 javascript/ql/test/library-tests/frameworks/jQuery/ts_global_types.ts create mode 100644 javascript/ql/test/library-tests/frameworks/jQuery/ts_import.ts create mode 100644 javascript/ql/test/library-tests/frameworks/jQuery/tsconfig.json diff --git a/javascript/ql/src/semmle/javascript/Extend.qll b/javascript/ql/src/semmle/javascript/Extend.qll index 6519cb70075..47124948797 100644 --- a/javascript/ql/src/semmle/javascript/Extend.qll +++ b/javascript/ql/src/semmle/javascript/Extend.qll @@ -47,7 +47,9 @@ private class ExtendCallWithFlag extends ExtendCall { name = "node.extend" ) or - this = jquery().getAPropertyRead("extend").getACall() + // Match $.extend using the source of `$` only, as ExtendCall should not + // depend on type tracking. + this = JQuery::dollarSource().getAMemberCall("extend") } /** diff --git a/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll b/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll index f5c7bd1a1bb..359190570ec 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll @@ -7,29 +7,36 @@ import javascript /** * Gets a data flow node that may refer to the jQuery `$` function. */ -DataFlow::SourceNode jquery() { - // either a reference to a global variable `$` or `jQuery` - result = DataFlow::globalVarRef(any(string jq | jq = "$" or jq = "jQuery")) - or - // or imported from a module named `jquery` - result = DataFlow::moduleImport("jquery") -} +predicate jquery = JQuery::dollar/0; /** + * DEPRECATED. In most cases, `JQuery::Object` should be used instead. + * Alternatively, if used as a base class, and the intent is to extend the model of + * jQuery objects with more nodes, extend `JQuery::ObjectSource::Range` instead. + * * An expression that may refer to a jQuery object. * * Note that this class is an over-approximation: `nd instanceof JQueryObject` * may hold for nodes `nd` that cannot, in fact, refer to a jQuery object. */ -abstract class JQueryObject extends Expr { } +deprecated class JQueryObject = JQueryObjectInternal; + +/** + * An internal version of `JQueryObject` that may be used to retain + * backwards compatibility without triggering a deprecation warning. + */ +abstract private class JQueryObjectInternal extends Expr { } /** * A jQuery object created from a jQuery method. + * + * This class is defined using the legacy API in order to retain the + * behavior of `JQueryObject`. */ -private class OrdinaryJQueryObject extends JQueryObject { +private class OrdinaryJQueryObject extends JQueryObjectInternal { OrdinaryJQueryObject() { - exists(JQueryMethodCall jq | - this.flow().getALocalSource().asExpr() = jq and + exists(JQuery::MethodCall jq | + this.flow().getALocalSource() = jq and // `jQuery.val()` does _not_ return a jQuery object jq.getMethodName() != "val" ) @@ -37,20 +44,14 @@ private class OrdinaryJQueryObject extends JQueryObject { } /** + * DEPRECATED. Use `JQuery::MethodCall` instead. + * * A (possibly chained) call to a jQuery method. */ -class JQueryMethodCall extends CallExpr { +deprecated class JQueryMethodCall extends CallExpr { string name; - JQueryMethodCall() { - this = jquery().getACall().asExpr() and name = "$" - or - // initial call - this = jquery().getAMemberCall(name).asExpr() - or - // chained call - this.(MethodCallExpr).calls(any(JQueryObject jq), name) - } + JQueryMethodCall() { name = this.flow().(JQuery::MethodCall).getMethodName() } /** * Gets the name of the jQuery method this call invokes. @@ -65,13 +66,7 @@ class JQueryMethodCall extends CallExpr { * `interpretsArgumentAsSelector` below overlap. */ predicate interpretsArgumentAsHtml(Expr e) { - // some methods interpret all their arguments as (potential) HTML - JQuery::isMethodArgumentInterpretedAsHtml(name) and - e = getAnArgument() - or - // for `$, it's only the first one - name = "$" and - e = getArgument(0) + this.flow().(JQuery::MethodCall).interpretsArgumentAsHtml(e.flow()) } /** @@ -82,13 +77,7 @@ class JQueryMethodCall extends CallExpr { * `interpretsArgumentAsHtml` above overlap. */ predicate interpretsArgumentAsSelector(Expr e) { - // some methods interpret all their arguments as (potential) selectors - JQuery::isMethodArgumentInterpretedAsSelector(name) and - e = getAnArgument() - or - // for `$, it's only the first one - name = "$" and - e = getArgument(0) + this.flow().(JQuery::MethodCall).interpretsArgumentAsSelector(e.flow()) } } @@ -96,7 +85,7 @@ class JQueryMethodCall extends CallExpr { * A call to `jQuery.parseXML`. */ private class JQueryParseXmlCall extends XML::ParserInvocation { - JQueryParseXmlCall() { this.(JQueryMethodCall).getMethodName() = "parseXML" } + JQueryParseXmlCall() { flow().(JQuery::MethodCall).getMethodName() = "parseXML" } override Expr getSourceArgument() { result = getArgument(0) } @@ -249,13 +238,12 @@ private class JQueryAttr3Call extends JQueryAttributeDefinition, @callexpr { * For example, the call `$(" -semmle-extractor-options: --tolerate-parse-errors diff --git a/javascript/ql/test/query-tests/filters/ClassifyFiles/templ.js b/javascript/ql/test/query-tests/filters/ClassifyFiles/templ.js index 1a42f3cf925..cda21380525 100644 --- a/javascript/ql/test/query-tests/filters/ClassifyFiles/templ.js +++ b/javascript/ql/test/query-tests/filters/ClassifyFiles/templ.js @@ -3,4 +3,3 @@ common.autofocus('#id_password'); {% else %} common.autofocus('#id_username'); {% endif %} -// semmle-extractor-options: --tolerate-parse-errors diff --git a/javascript/ql/test/query-tests/filters/ClassifyFiles/tmpl.html b/javascript/ql/test/query-tests/filters/ClassifyFiles/tmpl.html index c21d85208f5..e3bdc744425 100644 --- a/javascript/ql/test/query-tests/filters/ClassifyFiles/tmpl.html +++ b/javascript/ql/test/query-tests/filters/ClassifyFiles/tmpl.html @@ -5,4 +5,3 @@ common.autofocus('#id_password'); common.autofocus('#id_username'); {% endif %} -semmle-extractor-options: --tolerate-parse-errors diff --git a/javascript/ql/test/query-tests/filters/ClassifyFiles/tmpl2.html b/javascript/ql/test/query-tests/filters/ClassifyFiles/tmpl2.html index 8e96a8b41f4..700fe9c08d2 100644 --- a/javascript/ql/test/query-tests/filters/ClassifyFiles/tmpl2.html +++ b/javascript/ql/test/query-tests/filters/ClassifyFiles/tmpl2.html @@ -5,4 +5,3 @@ {{/config}} } -semmle-extractor-options: --tolerate-parse-errors diff --git a/javascript/ql/test/tutorials/Introducing the JavaScript libraries/options b/javascript/ql/test/tutorials/Introducing the JavaScript libraries/options new file mode 100644 index 00000000000..a1b2b21840f --- /dev/null +++ b/javascript/ql/test/tutorials/Introducing the JavaScript libraries/options @@ -0,0 +1 @@ +semmle-extractor-options: --tolerate-parse-errors \ No newline at end of file From 3ad5af7ceff7a942277bb5ef0a42b09cdf21c1a2 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 5 Nov 2019 16:44:57 +0000 Subject: [PATCH 0928/1227] JavaScript: Move `--extract-program-text` extractor options into `options` files. --- .../test/library-tests/Lines/Lines.expected | 10 ++-- .../ql/test/library-tests/Lines/options | 1 + .../ql/test/library-tests/Lines/tst1.js | 4 +- .../ql/test/library-tests/Lines/tst2.js | 2 +- .../ql/test/library-tests/Lines/tst3.js | 4 +- .../TypeScript/Modifiers/options | 1 + .../library-tests/TypeScript/Modifiers/tst.ts | 2 - .../test/library-tests/stmts/conditionals.js | 2 +- .../ql/test/library-tests/stmts/es2015.js | 2 +- .../ql/test/library-tests/stmts/functions.js | 2 +- .../ql/test/library-tests/stmts/loops.js | 2 +- .../ql/test/library-tests/stmts/options | 2 +- .../ql/test/library-tests/stmts/others.js | 2 +- .../test/library-tests/stmts/tests.expected | 51 +++++++++---------- javascript/ql/test/library-tests/stmts/try.js | 2 +- 15 files changed, 43 insertions(+), 46 deletions(-) create mode 100644 javascript/ql/test/library-tests/Lines/options create mode 100644 javascript/ql/test/library-tests/TypeScript/Modifiers/options diff --git a/javascript/ql/test/library-tests/Lines/Lines.expected b/javascript/ql/test/library-tests/Lines/Lines.expected index 552c1b8ff0e..e3c7973c9b8 100644 --- a/javascript/ql/test/library-tests/Lines/Lines.expected +++ b/javascript/ql/test/library-tests/Lines/Lines.expected @@ -1,4 +1,4 @@ -| tst1.js:1:1:1:55 | abc // semmle-extractor-options: --extract-program-text | abc // semmle-extractor-options: --extract-program-text | \n | +| tst1.js:1:1:1:3 | abc | abc | \n | | tst1.js:2:1:2:3 | def | def | \r | | tst1.js:3:1:3:3 | ghi | ghi | \r\n | | tst1.js:4:1:4:3 | jkl | jkl | \n | @@ -6,13 +6,13 @@ | tst1.js:6:1:6:3 | mno | mno | \u2028 | | tst1.js:7:1:7:0 | | | \n | | tst1.js:8:1:8:3 | pqr | pqr | \u2029 | -| tst1.js:9:1:9:3 | stu | stu | | -| tst2.js:1:1:1:63 | first_line // semmle-extractor-options: --extract-program-text | first_line // semmle-extractor-options: --extract-program-text | \n | -| tst3.js:1:1:1:56 | 42; // semmle-extractor-options: --extract-program-text | 42; // semmle-extractor-options: --extract-program-text | \n | +| tst1.js:9:1:9:3 | stu | stu | \n | +| tst2.js:1:1:1:10 | first_line | first_line | \n | +| tst3.js:1:1:1:3 | 42; | 42; | \n | | tst3.js:2:1:2:4 | \t42; | \t42; | \n | | tst3.js:3:1:3:5 | \t\t42; | \t\t42; | \n | | tst3.js:4:1:4:6 | \t\t\t42; | \t\t\t42; | \n | | tst3.js:5:1:5:6 | \t\t 42; | \t\t 42; | \n | | tst3.js:6:1:6:6 | \t \t42; | \t \t42; | \n | | tst3.js:7:1:7:7 | 42; | 42; | \n | -| tst3.js:8:1:8:5 | 42; | 42; | | +| tst3.js:8:1:8:5 | 42; | 42; | \n | diff --git a/javascript/ql/test/library-tests/Lines/options b/javascript/ql/test/library-tests/Lines/options new file mode 100644 index 00000000000..d51f2d49be2 --- /dev/null +++ b/javascript/ql/test/library-tests/Lines/options @@ -0,0 +1 @@ +semmle-extractor-options: --extract-program-text diff --git a/javascript/ql/test/library-tests/Lines/tst1.js b/javascript/ql/test/library-tests/Lines/tst1.js index f10f44a7440..d5fa50c5f3a 100644 --- a/javascript/ql/test/library-tests/Lines/tst1.js +++ b/javascript/ql/test/library-tests/Lines/tst1.js @@ -1,5 +1,5 @@ -abc // semmle-extractor-options: --extract-program-text +abc def ghi jkl mno
 -pqr
stu \ No newline at end of file +pqr
stu diff --git a/javascript/ql/test/library-tests/Lines/tst2.js b/javascript/ql/test/library-tests/Lines/tst2.js index d3c77609145..c380edd400c 100644 --- a/javascript/ql/test/library-tests/Lines/tst2.js +++ b/javascript/ql/test/library-tests/Lines/tst2.js @@ -1 +1 @@ -first_line // semmle-extractor-options: --extract-program-text +first_line diff --git a/javascript/ql/test/library-tests/Lines/tst3.js b/javascript/ql/test/library-tests/Lines/tst3.js index ad0059d91ea..8c8468ffab2 100644 --- a/javascript/ql/test/library-tests/Lines/tst3.js +++ b/javascript/ql/test/library-tests/Lines/tst3.js @@ -1,8 +1,8 @@ -42; // semmle-extractor-options: --extract-program-text +42; 42; 42; 42; 42; 42; 42; - 42; \ No newline at end of file + 42; diff --git a/javascript/ql/test/library-tests/TypeScript/Modifiers/options b/javascript/ql/test/library-tests/TypeScript/Modifiers/options new file mode 100644 index 00000000000..d51f2d49be2 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Modifiers/options @@ -0,0 +1 @@ +semmle-extractor-options: --extract-program-text diff --git a/javascript/ql/test/library-tests/TypeScript/Modifiers/tst.ts b/javascript/ql/test/library-tests/TypeScript/Modifiers/tst.ts index a56c724cf57..615a36ae6e5 100644 --- a/javascript/ql/test/library-tests/TypeScript/Modifiers/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/Modifiers/tst.ts @@ -113,5 +113,3 @@ interface InterfaceFields { z?: number; readonly w?: number; } - -// semmle-extractor-options: --extract-program-text \ No newline at end of file diff --git a/javascript/ql/test/library-tests/stmts/conditionals.js b/javascript/ql/test/library-tests/stmts/conditionals.js index 12562b2881f..e21a4299f87 100644 --- a/javascript/ql/test/library-tests/stmts/conditionals.js +++ b/javascript/ql/test/library-tests/stmts/conditionals.js @@ -1,4 +1,4 @@ -if (true) // semmle-extractor-options: --extract-program-text +if (true) ; if (b) ; diff --git a/javascript/ql/test/library-tests/stmts/es2015.js b/javascript/ql/test/library-tests/stmts/es2015.js index 6264c54a04f..09a501be36b 100644 --- a/javascript/ql/test/library-tests/stmts/es2015.js +++ b/javascript/ql/test/library-tests/stmts/es2015.js @@ -1,2 +1,2 @@ -for (var x of [1, 2, 3]) // semmle-extractor-options: --extract-program-text +for (var x of [1, 2, 3]) console.log(x); diff --git a/javascript/ql/test/library-tests/stmts/functions.js b/javascript/ql/test/library-tests/stmts/functions.js index f1ac615a040..20ecacefad5 100644 --- a/javascript/ql/test/library-tests/stmts/functions.js +++ b/javascript/ql/test/library-tests/stmts/functions.js @@ -1,4 +1,4 @@ -function g(x, y) { // semmle-extractor-options: --extract-program-text +function g(x, y) { return x+y; } diff --git a/javascript/ql/test/library-tests/stmts/loops.js b/javascript/ql/test/library-tests/stmts/loops.js index e2a63b3e3f9..6d424254d74 100644 --- a/javascript/ql/test/library-tests/stmts/loops.js +++ b/javascript/ql/test/library-tests/stmts/loops.js @@ -1,4 +1,4 @@ -while(true) // semmle-extractor-options: --extract-program-text +while(true) ; outer: for(a; b; c) { for(;;) diff --git a/javascript/ql/test/library-tests/stmts/options b/javascript/ql/test/library-tests/stmts/options index ae107b46f9e..7b186f72cc5 100644 --- a/javascript/ql/test/library-tests/stmts/options +++ b/javascript/ql/test/library-tests/stmts/options @@ -1 +1 @@ -semmle-extractor-options: --experimental +semmle-extractor-options: --experimental --extract-program-text diff --git a/javascript/ql/test/library-tests/stmts/others.js b/javascript/ql/test/library-tests/stmts/others.js index 58d6c5c1709..3b2a62a47bf 100644 --- a/javascript/ql/test/library-tests/stmts/others.js +++ b/javascript/ql/test/library-tests/stmts/others.js @@ -1,4 +1,4 @@ -with(a) { // semmle-extractor-options: --extract-program-text +with(a) { } debugger; var x = 23, y; \ No newline at end of file diff --git a/javascript/ql/test/library-tests/stmts/tests.expected b/javascript/ql/test/library-tests/stmts/tests.expected index c4632fbc065..75d6f0a24b4 100644 --- a/javascript/ql/test/library-tests/stmts/tests.expected +++ b/javascript/ql/test/library-tests/stmts/tests.expected @@ -4,14 +4,11 @@ test_LetStmt test_LineTerminators | conditionals.js:12:1:12:1 | } | | functions.js:9:1:9:1 | } | -| guardedCatch.js:11:1:11:65 | //semmle-extractor-options: --experimental --extract-program-text | -| jscript.js:5:1:5:65 | //semmle-extractor-options: --experimental --extract-program-text | -| legacyletstmt.js:5:1:5:65 | //semmle-extractor-options: --experimental --extract-program-text | | loops.js:22:1:22:18 | for (x = 0 in xs); | | others.js:4:1:4:14 | var x = 23, y; | | try.js:5:1:5:29 | try {} catch(x) {} finally {} | test_EnclosingStmt -| conditionals.js:1:5:1:8 | true | conditionals.js:1:1:2:5 | if (tru ... t\\n ; | +| conditionals.js:1:5:1:8 | true | conditionals.js:1:1:2:5 | if (true)\\n ; | | conditionals.js:3:5:3:5 | b | conditionals.js:3:1:6:5 | if (b)\\n ... e\\n ; | | conditionals.js:7:9:7:9 | b | conditionals.js:7:1:12:1 | switch ... ault:\\n} | | conditionals.js:8:6:8:7 | 23 | conditionals.js:8:1:8:8 | case 23: | @@ -96,7 +93,7 @@ test_EnclosingStmt | legacyletstmt.js:2:15:2:15 | x | legacyletstmt.js:2:3:2:21 | console.log(x + y); | | legacyletstmt.js:2:15:2:19 | x + y | legacyletstmt.js:2:3:2:21 | console.log(x + y); | | legacyletstmt.js:2:19:2:19 | y | legacyletstmt.js:2:3:2:21 | console.log(x + y); | -| loops.js:1:7:1:10 | true | loops.js:1:1:2:5 | while(t ... t\\n ; | +| loops.js:1:7:1:10 | true | loops.js:1:1:2:5 | while(true)\\n ; | | loops.js:3:1:3:5 | outer | loops.js:3:1:11:1 | outer: ... inue;\\n} | | loops.js:3:12:3:12 | a | loops.js:3:8:11:1 | for(a; ... inue;\\n} | | loops.js:3:15:3:15 | b | loops.js:3:8:11:1 | for(a; ... inue;\\n} | @@ -129,7 +126,7 @@ test_EnclosingStmt | loops.js:22:6:22:6 | x | loops.js:22:1:22:18 | for (x = 0 in xs); | | loops.js:22:10:22:10 | 0 | loops.js:22:1:22:18 | for (x = 0 in xs); | | loops.js:22:15:22:16 | xs | loops.js:22:1:22:18 | for (x = 0 in xs); | -| others.js:1:6:1:6 | a | others.js:1:1:2:1 | with(a) ... -text\\n} | +| others.js:1:6:1:6 | a | others.js:1:1:2:1 | with(a) {\\n} | | others.js:4:5:4:5 | x | others.js:4:1:4:14 | var x = 23, y; | | others.js:4:5:4:10 | x = 23 | others.js:4:1:4:14 | var x = 23, y; | | others.js:4:9:4:10 | 23 | others.js:4:1:4:14 | var x = 23, y; | @@ -140,7 +137,7 @@ test_EnclosingStmt | try.js:5:14:5:14 | x | try.js:5:8:5:18 | catch(x) {} | test_NumCatchClauses | guardedCatch.js:2:2:8:2 | try {\\n\\t ... !");\\n\\t} | 2 | -| try.js:1:1:3:16 | try { / ... ) { ; } | 1 | +| try.js:1:1:3:16 | try {\\n ... ) { ; } | 1 | | try.js:4:1:4:20 | try {} finally { ; } | 0 | | try.js:5:1:5:29 | try {} ... ally {} | 1 | test_DoubleColonMethods @@ -151,7 +148,7 @@ test_SemicolonInsertion test_getGuard | guardedCatch.js:4:4:6:2 | catch ( ... !");\\n\\t} | guardedCatch.js:4:16:4:33 | e instanceof Error | test_Containers -| conditionals.js:1:1:2:5 | if (tru ... t\\n ; | conditionals.js:1:1:12:1 | | +| conditionals.js:1:1:2:5 | if (true)\\n ; | conditionals.js:1:1:12:1 | | | conditionals.js:2:5:2:5 | ; | conditionals.js:1:1:12:1 | | | conditionals.js:3:1:6:5 | if (b)\\n ... e\\n ; | conditionals.js:1:1:12:1 | | | conditionals.js:4:5:4:5 | ; | conditionals.js:1:1:12:1 | | @@ -164,22 +161,22 @@ test_Containers | es2015.js:1:1:2:16 | for (va ... log(x); | es2015.js:1:1:3:0 | | | es2015.js:1:6:1:10 | var x | es2015.js:1:1:3:0 | | | es2015.js:2:2:2:16 | console.log(x); | es2015.js:1:1:3:0 | | -| foreach.js:1:1:1:12 | var sum = 0; | foreach.js:1:1:11:0 | | -| foreach.js:2:1:2:42 | var obj ... p3: 8}; | foreach.js:1:1:11:0 | | -| foreach.js:4:1:6:1 | for eac ... item;\\n} | foreach.js:1:1:11:0 | | -| foreach.js:4:11:4:18 | var item | foreach.js:1:1:11:0 | | -| foreach.js:4:28:6:1 | {\\n sum += item;\\n} | foreach.js:1:1:11:0 | | -| foreach.js:5:3:5:14 | sum += item; | foreach.js:1:1:11:0 | | -| foreach.js:8:1:8:17 | console.log(sum); | foreach.js:1:1:11:0 | | +| foreach.js:1:1:1:12 | var sum = 0; | foreach.js:1:1:9:0 | | +| foreach.js:2:1:2:42 | var obj ... p3: 8}; | foreach.js:1:1:9:0 | | +| foreach.js:4:1:6:1 | for eac ... item;\\n} | foreach.js:1:1:9:0 | | +| foreach.js:4:11:4:18 | var item | foreach.js:1:1:9:0 | | +| foreach.js:4:28:6:1 | {\\n sum += item;\\n} | foreach.js:1:1:9:0 | | +| foreach.js:5:3:5:14 | sum += item; | foreach.js:1:1:9:0 | | +| foreach.js:8:1:8:17 | console.log(sum); | foreach.js:1:1:9:0 | | | functions.js:1:1:3:1 | functio ... x+y;\\n} | functions.js:1:1:9:1 | | -| functions.js:1:18:3:1 | { // se ... x+y;\\n} | functions.js:1:1:3:1 | functio ... x+y;\\n} | +| functions.js:1:18:3:1 | {\\n return x+y;\\n} | functions.js:1:1:3:1 | functio ... x+y;\\n} | | functions.js:2:5:2:15 | return x+y; | functions.js:1:1:3:1 | functio ... x+y;\\n} | | functions.js:5:1:5:15 | function h() {} | functions.js:1:1:9:1 | | | functions.js:5:14:5:15 | {} | functions.js:5:1:5:15 | function h() {} | | functions.js:7:1:9:1 | k = fun ... turn;\\n} | functions.js:1:1:9:1 | | | functions.js:7:16:9:1 | {\\n return;\\n} | functions.js:7:5:9:1 | functio ... turn;\\n} | | functions.js:8:5:8:11 | return; | functions.js:7:5:9:1 | functio ... turn;\\n} | -| guardedCatch.js:1:1:9:1 | functio ... );\\n\\t}\\n} | guardedCatch.js:1:1:11:65 | | +| guardedCatch.js:1:1:9:1 | functio ... );\\n\\t}\\n} | guardedCatch.js:1:1:10:0 | | | guardedCatch.js:1:15:9:1 | {\\n\\ttry ... );\\n\\t}\\n} | guardedCatch.js:1:1:9:1 | functio ... );\\n\\t}\\n} | | guardedCatch.js:2:2:8:2 | try {\\n\\t ... !");\\n\\t} | guardedCatch.js:1:1:9:1 | functio ... );\\n\\t}\\n} | | guardedCatch.js:2:6:4:2 | {\\n\\t\\tg();\\n\\t} | guardedCatch.js:1:1:9:1 | functio ... );\\n\\t}\\n} | @@ -190,14 +187,14 @@ test_Containers | guardedCatch.js:6:4:8:2 | catch ( ... !");\\n\\t} | guardedCatch.js:1:1:9:1 | functio ... );\\n\\t}\\n} | | guardedCatch.js:6:14:8:2 | {\\n\\t\\tcon ... !");\\n\\t} | guardedCatch.js:1:1:9:1 | functio ... );\\n\\t}\\n} | | guardedCatch.js:7:3:7:33 | console ... lse!"); | guardedCatch.js:1:1:9:1 | functio ... );\\n\\t}\\n} | -| jscript.js:1:1:1:28 | functio ... ad() {} | jscript.js:1:1:5:65 | | +| jscript.js:1:1:1:28 | functio ... ad() {} | jscript.js:1:1:4:0 | | | jscript.js:1:27:1:28 | {} | jscript.js:1:1:1:28 | functio ... ad() {} | -| jscript.js:3:1:3:36 | window. ... ad() {} | jscript.js:1:1:5:65 | | +| jscript.js:3:1:3:36 | window. ... ad() {} | jscript.js:1:1:4:0 | | | jscript.js:3:35:3:36 | {} | jscript.js:3:17:3:36 | function onload() {} | -| legacyletstmt.js:1:1:3:1 | let (x ... + y);\\n} | legacyletstmt.js:1:1:5:65 | | -| legacyletstmt.js:1:22:3:1 | {\\n con ... + y);\\n} | legacyletstmt.js:1:1:5:65 | | -| legacyletstmt.js:2:3:2:21 | console.log(x + y); | legacyletstmt.js:1:1:5:65 | | -| loops.js:1:1:2:5 | while(t ... t\\n ; | loops.js:1:1:22:18 | | +| legacyletstmt.js:1:1:3:1 | let (x ... + y);\\n} | legacyletstmt.js:1:1:4:0 | | +| legacyletstmt.js:1:22:3:1 | {\\n con ... + y);\\n} | legacyletstmt.js:1:1:4:0 | | +| legacyletstmt.js:2:3:2:21 | console.log(x + y); | legacyletstmt.js:1:1:4:0 | | +| loops.js:1:1:2:5 | while(true)\\n ; | loops.js:1:1:22:18 | | | loops.js:2:5:2:5 | ; | loops.js:1:1:22:18 | | | loops.js:3:1:11:1 | outer: ... inue;\\n} | loops.js:1:1:22:18 | | | loops.js:3:8:11:1 | for(a; ... inue;\\n} | loops.js:1:1:22:18 | | @@ -223,12 +220,12 @@ test_Containers | loops.js:21:16:21:16 | ; | loops.js:1:1:22:18 | | | loops.js:22:1:22:18 | for (x = 0 in xs); | loops.js:1:1:22:18 | | | loops.js:22:18:22:18 | ; | loops.js:1:1:22:18 | | -| others.js:1:1:2:1 | with(a) ... -text\\n} | others.js:1:1:4:14 | | -| others.js:1:9:2:1 | { // se ... -text\\n} | others.js:1:1:4:14 | | +| others.js:1:1:2:1 | with(a) {\\n} | others.js:1:1:4:14 | | +| others.js:1:9:2:1 | {\\n} | others.js:1:1:4:14 | | | others.js:3:1:3:9 | debugger; | others.js:1:1:4:14 | | | others.js:4:1:4:14 | var x = 23, y; | others.js:1:1:4:14 | | -| try.js:1:1:3:16 | try { / ... ) { ; } | try.js:1:1:5:29 | | -| try.js:1:5:3:1 | { // se ... "!";\\n} | try.js:1:1:5:29 | | +| try.js:1:1:3:16 | try {\\n ... ) { ; } | try.js:1:1:5:29 | | +| try.js:1:5:3:1 | {\\n throw "!";\\n} | try.js:1:1:5:29 | | | try.js:2:5:2:14 | throw "!"; | try.js:1:1:5:29 | | | try.js:3:3:3:16 | catch(x) { ; } | try.js:1:1:5:29 | | | try.js:3:12:3:16 | { ; } | try.js:1:1:5:29 | | diff --git a/javascript/ql/test/library-tests/stmts/try.js b/javascript/ql/test/library-tests/stmts/try.js index 2d82952fbd3..0151114bf84 100644 --- a/javascript/ql/test/library-tests/stmts/try.js +++ b/javascript/ql/test/library-tests/stmts/try.js @@ -1,4 +1,4 @@ -try { // semmle-extractor-options: --extract-program-text +try { throw "!"; } catch(x) { ; } try {} finally { ; } From 725059deea8abccc6a38531fed27e7db47d7a2a7 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 6 Nov 2019 12:08:33 +0000 Subject: [PATCH 0929/1227] JavaScript: Remove `--source-type module` extractor options. --- .../library-tests/DataFlow/flowStep.expected | 8 ++++---- javascript/ql/test/library-tests/DataFlow/tst.ts | 4 +--- .../library-tests/Flow/AbstractValues.expected | 16 ++++++++-------- javascript/ql/test/library-tests/Flow/tst.ts | 4 +--- .../InterProceduralFlow/callback.js | 2 +- .../InterProceduralFlow/properties2.js | 2 +- .../library-tests/NPM/ImportedModule.expected | 10 +++++----- .../ql/test/library-tests/NPM/Modules.expected | 6 +++--- .../NPM/NPMPackage_getMainModule.expected | 4 ++-- .../ql/test/library-tests/NPM/src/index.js | 3 +-- .../ql/test/library-tests/NPM/src/lib/tst.js | 3 +-- .../src/node_modules/third-party-module/fancy.js | 3 +-- .../NodeJS/Module_getAnImport.expected | 1 + .../NodeJS/Module_getAnImportedModule.expected | 2 +- .../test/library-tests/NodeJS/Modules.expected | 2 +- .../test/library-tests/NodeJS/Require.expected | 1 + .../library-tests/NodeJS/RequireImport.expected | 2 +- javascript/ql/test/library-tests/NodeJS/e.js | 3 +-- 18 files changed, 35 insertions(+), 41 deletions(-) diff --git a/javascript/ql/test/library-tests/DataFlow/flowStep.expected b/javascript/ql/test/library-tests/DataFlow/flowStep.expected index a6446732fbe..ad843094a5e 100644 --- a/javascript/ql/test/library-tests/DataFlow/flowStep.expected +++ b/javascript/ql/test/library-tests/DataFlow/flowStep.expected @@ -142,11 +142,11 @@ | tst.js:111:29:111:31 | o2c | tst.js:111:6:111:38 | v2c | | tst.js:111:36:111:38 | o2d | tst.js:111:6:111:32 | [v2a, v ... = o2c] | | tst.js:115:1:115:12 | reflective call | tst.js:115:1:115:12 | Array.call() | -| tst.ts:1:1:1:1 | A | tst.ts:1:11:1:11 | A | +| tst.ts:1:1:1:1 | A | tst.ts:1:18:1:18 | A | | tst.ts:1:1:1:1 | A | tst.ts:7:1:7:0 | A | -| tst.ts:1:1:5:1 | A | tst.ts:7:1:7:0 | A | -| tst.ts:1:1:5:1 | A | tst.ts:11:11:11:11 | A | -| tst.ts:1:1:5:1 | namespa ... lysed\\n} | tst.ts:1:1:5:1 | A | +| tst.ts:1:8:5:1 | A | tst.ts:7:1:7:0 | A | +| tst.ts:1:8:5:1 | A | tst.ts:11:11:11:11 | A | +| tst.ts:1:8:5:1 | namespa ... lysed\\n} | tst.ts:1:8:5:1 | A | | tst.ts:2:14:2:19 | x | tst.ts:4:3:4:3 | x | | tst.ts:2:18:2:19 | 42 | tst.ts:2:14:2:19 | x | | tst.ts:7:1:7:0 | A | tst.ts:8:3:8:3 | A | diff --git a/javascript/ql/test/library-tests/DataFlow/tst.ts b/javascript/ql/test/library-tests/DataFlow/tst.ts index dca2ee632b7..29c85cba933 100644 --- a/javascript/ql/test/library-tests/DataFlow/tst.ts +++ b/javascript/ql/test/library-tests/DataFlow/tst.ts @@ -1,4 +1,4 @@ -namespace A { +export namespace A { export let x = 42; setX(); x; // global namespace exports are incompletely analysed @@ -11,5 +11,3 @@ function setX() { var nd2 = A.x as number; // flow through type assertions class StringList extends List {} // flow through expressions with type arguments - -// semmle-extractor-options: --source-type module diff --git a/javascript/ql/test/library-tests/Flow/AbstractValues.expected b/javascript/ql/test/library-tests/Flow/AbstractValues.expected index 42117cac98a..531faf562bd 100644 --- a/javascript/ql/test/library-tests/Flow/AbstractValues.expected +++ b/javascript/ql/test/library-tests/Flow/AbstractValues.expected @@ -194,8 +194,8 @@ | n.js:2:1:2:15 | function g | | n.js:2:1:2:15 | instance of function g | | n.js:3:16:3:23 | object literal | -| namespace-reexport.js:1:1:4:0 | exports object of module namespace-reexport | -| namespace-reexport.js:1:1:4:0 | module object of module namespace-reexport | +| namespace-reexport.js:1:1:2:0 | exports object of module namespace-reexport | +| namespace-reexport.js:1:1:2:0 | module object of module namespace-reexport | | nestedImport.js:1:1:13:0 | exports object of module nestedImport | | nestedImport.js:1:1:13:0 | module object of module nestedImport | | nestedImport.js:9:1:12:1 | function tst | @@ -235,14 +235,14 @@ | objlit.js:43:12:45:3 | object literal | | reexport-d.js:1:1:2:0 | exports object of module reexport-d | | reexport-d.js:1:1:2:0 | module object of module reexport-d | -| reexport-mixins.js:1:1:4:0 | exports object of module reexport-mixins | -| reexport-mixins.js:1:1:4:0 | module object of module reexport-mixins | +| reexport-mixins.js:1:1:2:0 | exports object of module reexport-mixins | +| reexport-mixins.js:1:1:2:0 | module object of module reexport-mixins | | reexport-unknown.js:1:1:2:0 | exports object of module reexport-unknown | | reexport-unknown.js:1:1:2:0 | module object of module reexport-unknown | | reexport/client/src/index.js:1:1:3:0 | exports object of module index | | reexport/client/src/index.js:1:1:3:0 | module object of module index | -| reexport/lib/index.js:1:1:4:0 | exports object of module index | -| reexport/lib/index.js:1:1:4:0 | module object of module index | +| reexport/lib/index.js:1:1:2:0 | exports object of module index | +| reexport/lib/index.js:1:1:2:0 | module object of module index | | reexport/lib/src/utils/util.js:1:1:3:0 | exports object of module util | | reexport/lib/src/utils/util.js:1:1:3:0 | module object of module util | | refinements.js:1:1:8:1 | function f1 | @@ -341,8 +341,8 @@ | tst.js:174:1:183:1 | function awaitFlow | | tst.mjs:1:1:4:0 | exports object of module tst | | tst.mjs:1:1:4:0 | module object of module tst | -| tst.ts:1:1:15:0 | exports object of module tst | -| tst.ts:1:1:15:0 | module object of module tst | +| tst.ts:1:1:13:0 | exports object of module tst | +| tst.ts:1:1:13:0 | module object of module tst | | tst.ts:8:1:10:1 | function setX | | tst.ts:8:1:10:1 | instance of function setX | | with.js:1:1:17:1 | function f | diff --git a/javascript/ql/test/library-tests/Flow/tst.ts b/javascript/ql/test/library-tests/Flow/tst.ts index 615efbb7103..63e329f75c0 100644 --- a/javascript/ql/test/library-tests/Flow/tst.ts +++ b/javascript/ql/test/library-tests/Flow/tst.ts @@ -1,4 +1,4 @@ -namespace A { +export namespace A { export let x = 42; setX(); let x2 = x; @@ -10,5 +10,3 @@ function setX() { } let a = A; - -// semmle-extractor-options: --source-type module diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/callback.js b/javascript/ql/test/library-tests/InterProceduralFlow/callback.js index 8ba9bd12fee..1e4d7aed2e8 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/callback.js +++ b/javascript/ql/test/library-tests/InterProceduralFlow/callback.js @@ -28,4 +28,4 @@ let source3 = "source3"; call2(source3, store); call2(source3, confounder); -// semmle-extractor-options: --source-type module +export default 0; diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/properties2.js b/javascript/ql/test/library-tests/InterProceduralFlow/properties2.js index 849516d57bb..9f1b0c9ba07 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/properties2.js +++ b/javascript/ql/test/library-tests/InterProceduralFlow/properties2.js @@ -42,4 +42,4 @@ var o5 = {}; setP(o5, "not a source"); var sink10 = getP(o5); -// semmle-extractor-options: --source-type module +export default 0; diff --git a/javascript/ql/test/library-tests/NPM/ImportedModule.expected b/javascript/ql/test/library-tests/NPM/ImportedModule.expected index 2a89dfeb394..ce2a65d591f 100644 --- a/javascript/ql/test/library-tests/NPM/ImportedModule.expected +++ b/javascript/ql/test/library-tests/NPM/ImportedModule.expected @@ -1,6 +1,6 @@ -| src/lib/tst2.js:1:1:1:13 | require("..") | src/index.js:1:1:5:0 | | -| src/node_modules/nested/tst3.js:1:1:1:29 | require ... odule') | src/node_modules/third-party-module/fancy.js:1:1:5:0 | | +| src/lib/tst2.js:1:1:1:13 | require("..") | src/index.js:1:1:4:0 | | +| src/node_modules/nested/tst3.js:1:1:1:29 | require ... odule') | src/node_modules/third-party-module/fancy.js:1:1:4:0 | | | src/node_modules/nested/tst3.js:2:1:2:12 | require('a') | src/node_modules/nested/node_modules/a/index.js:1:1:1:25 | | -| src/node_modules/tst2.js:1:1:1:38 | require ... cy.js') | src/node_modules/third-party-module/fancy.js:1:1:5:0 | | -| src/tst2.js:1:1:1:12 | require(".") | src/index.js:1:1:5:0 | | -| src/tst.js:1:1:1:38 | require ... cy.js') | src/node_modules/third-party-module/fancy.js:1:1:5:0 | | +| src/node_modules/tst2.js:1:1:1:38 | require ... cy.js') | src/node_modules/third-party-module/fancy.js:1:1:4:0 | | +| src/tst2.js:1:1:1:12 | require(".") | src/index.js:1:1:4:0 | | +| src/tst.js:1:1:1:38 | require ... cy.js') | src/node_modules/third-party-module/fancy.js:1:1:4:0 | | diff --git a/javascript/ql/test/library-tests/NPM/Modules.expected b/javascript/ql/test/library-tests/NPM/Modules.expected index 4d0dde9c33e..e7fa54d6f9a 100644 --- a/javascript/ql/test/library-tests/NPM/Modules.expected +++ b/javascript/ql/test/library-tests/NPM/Modules.expected @@ -1,9 +1,9 @@ | b | src/node_modules/b/lib/index.js:1:1:2:0 | | | b | src/node_modules/b/lib/index.ts:1:1:2:0 | | | c | src/node_modules/c/src/index.js:1:1:2:0 | | -| test-package | src/index.js:1:1:5:0 | | +| test-package | src/index.js:1:1:4:0 | | | test-package | src/lib/tst2.js:1:1:1:14 | | -| test-package | src/lib/tst.js:1:1:5:0 | | +| test-package | src/lib/tst.js:1:1:4:0 | | | test-package | src/tst2.js:1:1:1:13 | | | test-package | src/tst.js:1:1:2:38 | | -| third-party-module | src/node_modules/third-party-module/fancy.js:1:1:5:0 | | +| third-party-module | src/node_modules/third-party-module/fancy.js:1:1:4:0 | | diff --git a/javascript/ql/test/library-tests/NPM/NPMPackage_getMainModule.expected b/javascript/ql/test/library-tests/NPM/NPMPackage_getMainModule.expected index 67fd1880bf0..a8b7753abae 100644 --- a/javascript/ql/test/library-tests/NPM/NPMPackage_getMainModule.expected +++ b/javascript/ql/test/library-tests/NPM/NPMPackage_getMainModule.expected @@ -1,4 +1,4 @@ | b | src/node_modules/b/lib/index.ts:1:1:2:0 | | | c | src/node_modules/c/src/index.js:1:1:2:0 | | -| test-package | src/index.js:1:1:5:0 | | -| third-party-module | src/node_modules/third-party-module/fancy.js:1:1:5:0 | | +| test-package | src/index.js:1:1:4:0 | | +| third-party-module | src/node_modules/third-party-module/fancy.js:1:1:4:0 | | diff --git a/javascript/ql/test/library-tests/NPM/src/index.js b/javascript/ql/test/library-tests/NPM/src/index.js index b875bfd3a10..e99778b633f 100644 --- a/javascript/ql/test/library-tests/NPM/src/index.js +++ b/javascript/ql/test/library-tests/NPM/src/index.js @@ -1,4 +1,3 @@ alert("Hello"); -// semmle-extractor-options: --platform -// semmle-extractor-options: node +require("process"); diff --git a/javascript/ql/test/library-tests/NPM/src/lib/tst.js b/javascript/ql/test/library-tests/NPM/src/lib/tst.js index 840fb76057b..d8fc422959c 100644 --- a/javascript/ql/test/library-tests/NPM/src/lib/tst.js +++ b/javascript/ql/test/library-tests/NPM/src/lib/tst.js @@ -1,4 +1,3 @@ alert("world"); -// semmle-extractor-options: --platform -// semmle-extractor-options: node +require("process"); diff --git a/javascript/ql/test/library-tests/NPM/src/node_modules/third-party-module/fancy.js b/javascript/ql/test/library-tests/NPM/src/node_modules/third-party-module/fancy.js index f53610fe05c..7dfe5aea1d2 100644 --- a/javascript/ql/test/library-tests/NPM/src/node_modules/third-party-module/fancy.js +++ b/javascript/ql/test/library-tests/NPM/src/node_modules/third-party-module/fancy.js @@ -1,4 +1,3 @@ ('alert' in this ? alert : console.log)("Hello"); -// semmle-extractor-options: --platform -// semmle-extractor-options: node +require("process"); diff --git a/javascript/ql/test/library-tests/NodeJS/Module_getAnImport.expected b/javascript/ql/test/library-tests/NodeJS/Module_getAnImport.expected index 9f2e4dba88e..d1cc2576141 100644 --- a/javascript/ql/test/library-tests/NodeJS/Module_getAnImport.expected +++ b/javascript/ql/test/library-tests/NodeJS/Module_getAnImport.expected @@ -9,6 +9,7 @@ | b.js:1:1:8:0 | | b.js:1:1:1:18 | require('./sub/c') | | d.js:1:1:7:15 | | d.js:1:1:1:38 | require ... s/ini') | | d.js:1:1:7:15 | | d.js:7:1:7:14 | require('foo') | +| e.js:1:1:6:0 | | e.js:5:1:5:18 | require("process") | | index.js:1:1:3:0 | | index.js:1:12:1:26 | require('path') | | index.js:1:1:3:0 | | index.js:2:1:2:41 | require ... b.js")) | | mjs-files/require-from-js.js:1:1:4:0 | | mjs-files/require-from-js.js:1:12:1:36 | require ... on-me') | diff --git a/javascript/ql/test/library-tests/NodeJS/Module_getAnImportedModule.expected b/javascript/ql/test/library-tests/NodeJS/Module_getAnImportedModule.expected index c038d8f9031..0fa0e65f359 100644 --- a/javascript/ql/test/library-tests/NodeJS/Module_getAnImportedModule.expected +++ b/javascript/ql/test/library-tests/NodeJS/Module_getAnImportedModule.expected @@ -1,6 +1,6 @@ | a.js:1:1:14:0 | | b.js:1:1:8:0 | | | a.js:1:1:14:0 | | d.js:1:1:7:15 | | -| a.js:1:1:14:0 | | e.js:1:1:7:0 | | +| a.js:1:1:14:0 | | e.js:1:1:6:0 | | | a.js:1:1:14:0 | | index.js:1:1:3:0 | | | a.js:1:1:14:0 | | sub/c.js:1:1:4:0 | | | b.js:1:1:8:0 | | sub/c.js:1:1:4:0 | | diff --git a/javascript/ql/test/library-tests/NodeJS/Modules.expected b/javascript/ql/test/library-tests/NodeJS/Modules.expected index 05306ec82c5..1ef82d0328e 100644 --- a/javascript/ql/test/library-tests/NodeJS/Modules.expected +++ b/javascript/ql/test/library-tests/NodeJS/Modules.expected @@ -1,7 +1,7 @@ | a.js:1:1:14:0 | | a.js:0:0:0:0 | a.js | a.js | a | | b.js:1:1:8:0 | | b.js:0:0:0:0 | b.js | b.js | b | | d.js:1:1:7:15 | | d.js:0:0:0:0 | d.js | d.js | d | -| e.js:1:1:7:0 | | e.js:0:0:0:0 | e.js | e.js | e | +| e.js:1:1:6:0 | | e.js:0:0:0:0 | e.js | e.js | e | | index.js:1:1:3:0 | | index.js:0:0:0:0 | index.js | index.js | index | | mjs-files/require-from-js.js:1:1:4:0 | | mjs-files/require-from-js.js:0:0:0:0 | mjs-files/require-from-js.js | mjs-files/require-from-js.js | require-from-js | | sub/c.js:1:1:4:0 | | sub/c.js:0:0:0:0 | sub/c.js | sub/c.js | c | diff --git a/javascript/ql/test/library-tests/NodeJS/Require.expected b/javascript/ql/test/library-tests/NodeJS/Require.expected index 491c80a9a87..7e9a50685ab 100644 --- a/javascript/ql/test/library-tests/NodeJS/Require.expected +++ b/javascript/ql/test/library-tests/NodeJS/Require.expected @@ -9,6 +9,7 @@ | b.js:1:1:1:18 | require('./sub/c') | | d.js:1:1:1:38 | require ... s/ini') | | d.js:7:1:7:14 | require('foo') | +| e.js:5:1:5:18 | require("process") | | f.js:2:1:2:7 | r("fs") | | index.js:1:12:1:26 | require('path') | | index.js:2:1:2:41 | require ... b.js")) | diff --git a/javascript/ql/test/library-tests/NodeJS/RequireImport.expected b/javascript/ql/test/library-tests/NodeJS/RequireImport.expected index a7ec65d67a2..e01527d2784 100644 --- a/javascript/ql/test/library-tests/NodeJS/RequireImport.expected +++ b/javascript/ql/test/library-tests/NodeJS/RequireImport.expected @@ -3,7 +3,7 @@ | a.js:4:6:4:29 | require ... /d.js') | ./sub/../d.js | d.js:1:1:7:15 | | | a.js:7:1:7:18 | require('./sub/c') | ./sub/c | sub/c.js:1:1:4:0 | | | a.js:10:1:10:18 | require(__dirname) | | index.js:1:1:3:0 | | -| a.js:11:1:11:25 | require ... + '/e') | /e | e.js:1:1:7:0 | | +| a.js:11:1:11:25 | require ... + '/e') | /e | e.js:1:1:6:0 | | | a.js:12:1:12:28 | require ... + 'c') | ./sub/c | sub/c.js:1:1:4:0 | | | b.js:1:1:1:18 | require('./sub/c') | ./sub/c | sub/c.js:1:1:4:0 | | | d.js:7:1:7:14 | require('foo') | foo | sub/f.js:1:1:4:17 | | diff --git a/javascript/ql/test/library-tests/NodeJS/e.js b/javascript/ql/test/library-tests/NodeJS/e.js index 0a3f338f7d0..22254c56326 100644 --- a/javascript/ql/test/library-tests/NodeJS/e.js +++ b/javascript/ql/test/library-tests/NodeJS/e.js @@ -2,5 +2,4 @@ require('./a.js'); })(); -// semmle-extractor-options: --platform -// semmle-extractor-options: node +require("process"); From 49008c9ff5923efbe3f29ccf66901eec67c40aa7 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 5 Nov 2019 14:20:10 +0100 Subject: [PATCH 0930/1227] C++: IR data flow local virtual dispatch This is just good enough to cause no performance regressions and pass the virtual-dispatch tests we have for `security.TaintTracking`. In particular, it fixes the tests for `UncontrolledProcessOperation.ql` when enabling `DefaultTaintTracking.qll`. --- .../ir/dataflow/internal/DataFlowDispatch.qll | 53 +++++++++++++++++++ .../dataflow/dataflow-tests/dispatch.cpp | 46 ++++++++++++++++ .../dataflow/dataflow-tests/test.expected | 6 +++ .../dataflow-tests/test_diff.expected | 2 + .../dataflow/dataflow-tests/test_ir.expected | 8 +++ 5 files changed, 115 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/dataflow-tests/dispatch.cpp diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll index d0325a28d3e..9572639de59 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll @@ -1,5 +1,6 @@ private import cpp private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.ir.dataflow.DataFlow Function viableImpl(CallInstruction call) { result = viableCallable(call) } @@ -20,6 +21,58 @@ Function viableCallable(CallInstruction call) { functionSignatureWithBody(qualifiedName, nparams, result) and strictcount(Function other | functionSignatureWithBody(qualifiedName, nparams, other)) = 1 ) + or + // Rudimentary virtual dispatch support. It's essentially local data flow + // where the source is a derived-to-base conversion and the target is the + // qualifier of a call. + exists(Class derived, DataFlow::Node thisArgument | + nodeMayHaveClass(derived, thisArgument) and + overrideMayAffectCall(derived, thisArgument, _, result, call) + ) +} + +/** + * Holds if `call` is a virtual function call with qualifier `thisArgument` in + * `enclosingFunction`, whose static target is overridden by + * `overridingFunction` in `overridingClass`. + */ +pragma[noinline] +private predicate overrideMayAffectCall( + Class overridingClass, DataFlow::Node thisArgument, Function enclosingFunction, + MemberFunction overridingFunction, CallInstruction call +) { + call.getEnclosingFunction() = enclosingFunction and + overridingFunction.getAnOverriddenFunction+() = call.getStaticCallTarget() and + overridingFunction.getDeclaringType() = overridingClass and + thisArgument = DataFlow::instructionNode(call.getThisArgument()) +} + +/** + * Holds if `node` may have dynamic class `derived`, where `derived` is a class + * that may affect virtual dispatch within the enclosing function. + * + * For the sake of performance, this recursion is written out manually to make + * it a relation on `Class x Node` rather than `Node x Node` or `MemberFunction + * x Node`, both of which would be larger. It's a forward search since there + * should usually be fewer classes than calls. + * + * If a value is cast several classes up in the hierarchy, that will be modeled + * as a chain of `ConvertToBaseInstruction`s and will cause the search to start + * from each of them and pass through subsequent ones. There might be + * performance to gain by stopping before a second upcast and reconstructing + * the full chain in a "big-step" recursion after this one. + */ +private predicate nodeMayHaveClass(Class derived, DataFlow::Node node) { + exists(ConvertToBaseInstruction toBase | + derived = toBase.getDerivedClass() and + overrideMayAffectCall(derived, _, toBase.getEnclosingFunction(), _, _) and + node.asInstruction() = toBase + ) + or + exists(DataFlow::Node prev | + nodeMayHaveClass(derived, prev) and + DataFlow::localFlowStep(prev, node) + ) } /** diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dispatch.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dispatch.cpp new file mode 100644 index 00000000000..f37eb4e9cbe --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dispatch.cpp @@ -0,0 +1,46 @@ +int source(); +void sink(int); + +// This class has the opposite behavior of what the member function names suggest. +struct Top { + virtual int isSource1() { return 0; } + virtual int isSource2() { return 0; } + virtual void isSink(int x) { } + virtual int notSource1() { return source(); } + virtual int notSource2() { return source(); } + virtual void notSink(int x) { sink(x); } +}; + +// This class has the correct behavior for just the functions ending in 2. +struct Middle : Top { + int isSource2() override { return source(); } + int notSource2() override { return 0; } +}; + +// This class has all the behavior suggested by the function names. +struct Bottom : Middle { + int isSource1() override { return source(); } + void isSink(int x) override { sink(x); } + int notSource1() override { return 0; } + void notSink(int x) override { } +}; + +void VirtualDispatch(Bottom *bottomPtr, Bottom &bottomRef) { + Top *topPtr = bottomPtr, &topRef = bottomRef; + + sink(topPtr->isSource1()); // flow [NOT DETECTED] + sink(topPtr->isSource2()); // flow [NOT DETECTED by AST] + topPtr->isSink(source()); // flow [NOT DETECTED] + + sink(topPtr->notSource1()); // no flow [FALSE POSITIVE] + sink(topPtr->notSource2()); // no flow [FALSE POSITIVE] + topPtr->notSink(source()); // no flow [FALSE POSITIVE] + + sink(topRef.isSource1()); // flow [NOT DETECTED] + sink(topRef.isSource2()); // flow [NOT DETECTED by AST] + topRef.isSink(source()); // flow [NOT DETECTED] + + sink(topRef.notSource1()); // no flow [FALSE POSITIVE] + sink(topRef.notSource2()); // no flow [FALSE POSITIVE] + topRef.notSink(source()); // no flow [FALSE POSITIVE] +} diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected index 6527db4b77e..24fa6fdb5bd 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected @@ -15,6 +15,12 @@ | clang.cpp:30:27:30:34 | call to getFirst | clang.cpp:28:27:28:32 | call to source | | clang.cpp:37:10:37:11 | m2 | clang.cpp:34:32:34:37 | call to source | | clang.cpp:45:17:45:18 | m2 | clang.cpp:43:35:43:40 | call to source | +| dispatch.cpp:11:38:11:38 | x | dispatch.cpp:37:19:37:24 | call to source | +| dispatch.cpp:11:38:11:38 | x | dispatch.cpp:45:18:45:23 | call to source | +| dispatch.cpp:35:16:35:25 | call to notSource1 | dispatch.cpp:9:37:9:42 | call to source | +| dispatch.cpp:36:16:36:25 | call to notSource2 | dispatch.cpp:10:37:10:42 | call to source | +| dispatch.cpp:43:15:43:24 | call to notSource1 | dispatch.cpp:9:37:9:42 | call to source | +| dispatch.cpp:44:15:44:24 | call to notSource2 | dispatch.cpp:10:37:10:42 | call to source | | lambdas.cpp:14:3:14:6 | t | lambdas.cpp:8:10:8:15 | call to source | | lambdas.cpp:18:8:18:8 | call to operator() | lambdas.cpp:8:10:8:15 | call to source | | lambdas.cpp:21:3:21:6 | t | lambdas.cpp:8:10:8:15 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected index 7d0d4e7d72e..8e914d53337 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected @@ -5,6 +5,8 @@ | clang.cpp:28:27:28:32 | clang.cpp:29:27:29:28 | AST only | | clang.cpp:28:27:28:32 | clang.cpp:30:27:30:34 | AST only | | clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only | +| dispatch.cpp:16:37:16:42 | dispatch.cpp:32:16:32:24 | IR only | +| dispatch.cpp:16:37:16:42 | dispatch.cpp:40:15:40:23 | IR only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:14:3:14:6 | AST only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected index 9b67a013a58..8d21837510e 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected @@ -12,6 +12,14 @@ | clang.cpp:37:10:37:11 | Load: m2 | clang.cpp:34:32:34:37 | Call: call to source | | clang.cpp:41:18:41:19 | Load: m2 | clang.cpp:39:42:39:47 | Call: call to source | | clang.cpp:45:17:45:18 | Load: m2 | clang.cpp:43:35:43:40 | Call: call to source | +| dispatch.cpp:11:38:11:38 | Load: x | dispatch.cpp:37:19:37:24 | Call: call to source | +| dispatch.cpp:11:38:11:38 | Load: x | dispatch.cpp:45:18:45:23 | Call: call to source | +| dispatch.cpp:32:16:32:24 | Call: call to isSource2 | dispatch.cpp:16:37:16:42 | Call: call to source | +| dispatch.cpp:35:16:35:25 | Call: call to notSource1 | dispatch.cpp:9:37:9:42 | Call: call to source | +| dispatch.cpp:36:16:36:25 | Call: call to notSource2 | dispatch.cpp:10:37:10:42 | Call: call to source | +| dispatch.cpp:40:15:40:23 | Call: call to isSource2 | dispatch.cpp:16:37:16:42 | Call: call to source | +| dispatch.cpp:43:15:43:24 | Call: call to notSource1 | dispatch.cpp:9:37:9:42 | Call: call to source | +| dispatch.cpp:44:15:44:24 | Call: call to notSource2 | dispatch.cpp:10:37:10:42 | Call: call to source | | test.cpp:7:8:7:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source | | test.cpp:9:8:9:9 | Load: t1 | test.cpp:6:12:6:17 | Call: call to source | | test.cpp:10:8:10:9 | Load: t2 | test.cpp:6:12:6:17 | Call: call to source | From ec9ef334864e59dc9e95fda9ab8267b99e7f29dd Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 6 Nov 2019 13:59:52 +0100 Subject: [PATCH 0931/1227] C++: IR data flow through inheritance conversions This makes IR data flow behave more like AST data flow, and it makes IR virtual dispatch work without further changes. --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 3 ++- .../library-tests/dataflow/dataflow-tests/dispatch.cpp | 8 ++++---- .../dataflow/dataflow-tests/test_diff.expected | 4 ++++ .../dataflow/dataflow-tests/test_ir.expected | 4 ++++ 4 files changed, 14 insertions(+), 5 deletions(-) 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 cd989c94710..4e84424fcb7 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 @@ -205,7 +205,8 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo.(CopyInstruction).getSourceValue() = iFrom or iTo.(PhiInstruction).getAnOperand().getDef() = iFrom or // Treat all conversions as flow, even conversions between different numeric types. - iTo.(ConvertInstruction).getUnary() = iFrom + iTo.(ConvertInstruction).getUnary() = iFrom or + iTo.(InheritanceConversionInstruction).getUnary() = iFrom } /** diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dispatch.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dispatch.cpp index f37eb4e9cbe..5e4f2f97f46 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dispatch.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dispatch.cpp @@ -28,17 +28,17 @@ struct Bottom : Middle { void VirtualDispatch(Bottom *bottomPtr, Bottom &bottomRef) { Top *topPtr = bottomPtr, &topRef = bottomRef; - sink(topPtr->isSource1()); // flow [NOT DETECTED] + sink(topPtr->isSource1()); // flow [NOT DETECTED by AST] sink(topPtr->isSource2()); // flow [NOT DETECTED by AST] - topPtr->isSink(source()); // flow [NOT DETECTED] + topPtr->isSink(source()); // flow [NOT DETECTED by AST] sink(topPtr->notSource1()); // no flow [FALSE POSITIVE] sink(topPtr->notSource2()); // no flow [FALSE POSITIVE] topPtr->notSink(source()); // no flow [FALSE POSITIVE] - sink(topRef.isSource1()); // flow [NOT DETECTED] + sink(topRef.isSource1()); // flow [NOT DETECTED by AST] sink(topRef.isSource2()); // flow [NOT DETECTED by AST] - topRef.isSink(source()); // flow [NOT DETECTED] + topRef.isSink(source()); // flow [NOT DETECTED by AST] sink(topRef.notSource1()); // no flow [FALSE POSITIVE] sink(topRef.notSource2()); // no flow [FALSE POSITIVE] diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected index 8e914d53337..9b8be3abd1e 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected @@ -7,6 +7,10 @@ | clang.cpp:39:42:39:47 | clang.cpp:41:18:41:19 | IR only | | dispatch.cpp:16:37:16:42 | dispatch.cpp:32:16:32:24 | IR only | | dispatch.cpp:16:37:16:42 | dispatch.cpp:40:15:40:23 | IR only | +| dispatch.cpp:22:37:22:42 | dispatch.cpp:31:16:31:24 | IR only | +| dispatch.cpp:22:37:22:42 | dispatch.cpp:39:15:39:23 | IR only | +| dispatch.cpp:33:18:33:23 | dispatch.cpp:23:38:23:38 | IR only | +| dispatch.cpp:41:17:41:22 | dispatch.cpp:23:38:23:38 | IR only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:14:3:14:6 | AST only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected index 8d21837510e..651e580a105 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected @@ -14,9 +14,13 @@ | clang.cpp:45:17:45:18 | Load: m2 | clang.cpp:43:35:43:40 | Call: call to source | | dispatch.cpp:11:38:11:38 | Load: x | dispatch.cpp:37:19:37:24 | Call: call to source | | dispatch.cpp:11:38:11:38 | Load: x | dispatch.cpp:45:18:45:23 | Call: call to source | +| dispatch.cpp:23:38:23:38 | Load: x | dispatch.cpp:33:18:33:23 | Call: call to source | +| dispatch.cpp:23:38:23:38 | Load: x | dispatch.cpp:41:17:41:22 | Call: call to source | +| dispatch.cpp:31:16:31:24 | Call: call to isSource1 | dispatch.cpp:22:37:22:42 | Call: call to source | | dispatch.cpp:32:16:32:24 | Call: call to isSource2 | dispatch.cpp:16:37:16:42 | Call: call to source | | dispatch.cpp:35:16:35:25 | Call: call to notSource1 | dispatch.cpp:9:37:9:42 | Call: call to source | | dispatch.cpp:36:16:36:25 | Call: call to notSource2 | dispatch.cpp:10:37:10:42 | Call: call to source | +| dispatch.cpp:39:15:39:23 | Call: call to isSource1 | dispatch.cpp:22:37:22:42 | Call: call to source | | dispatch.cpp:40:15:40:23 | Call: call to isSource2 | dispatch.cpp:16:37:16:42 | Call: call to source | | dispatch.cpp:43:15:43:24 | Call: call to notSource1 | dispatch.cpp:9:37:9:42 | Call: call to source | | dispatch.cpp:44:15:44:24 | Call: call to notSource2 | dispatch.cpp:10:37:10:42 | Call: call to source | From aa841c306dd0a2ca2e732a29df4883ace4bba4ad Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 5 Nov 2019 14:48:31 +0100 Subject: [PATCH 0932/1227] C++: Use virtual dispatch in DefaultTaintTracking This bit is only used by the compatibility code that sends flow into parameters of functions without body. --- .../semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 0753dfd266e..e0135e0ad2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -2,6 +2,7 @@ import cpp import semmle.code.cpp.security.Security private import semmle.code.cpp.ir.dataflow.DataFlow private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch /** * A predictable instruction is one where an external user can predict @@ -145,7 +146,8 @@ GlobalOrNamespaceVariable globalVarFromId(string id) { } Function resolveCall(Call call) { - // TODO: improve virtual dispatch. This will help in the test for - // `UncontrolledProcessOperation.ql`. - result = call.getTarget() + exists(CallInstruction callInstruction | + callInstruction.getAST() = call and + result = Dispatch::viableCallable(callInstruction) + ) } From f9feb05a727bf9640636ca89ae68d0fcbacd25cf Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 Nov 2019 17:05:38 +0000 Subject: [PATCH 0933/1227] CPP: Add a test of NtohlArrayNoBoundOpenSource.ql. --- .../NtohlArrayNoBound.expected | 8 ++ .../NtohlArrayNoBound/NtohlArrayNoBound.qlref | 1 + .../NtohlArrayNoBound/test.cpp | 100 ++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/NtohlArrayNoBound.expected create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/NtohlArrayNoBound.qlref create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/test.cpp diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/NtohlArrayNoBound.expected b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/NtohlArrayNoBound.expected new file mode 100644 index 00000000000..6c2fa97858c --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/NtohlArrayNoBound.expected @@ -0,0 +1,8 @@ +| test.cpp:12:25:12:29 | call to ntohl | Unchecked use of data from network function $@ | test.cpp:12:25:12:29 | call to ntohl | call to ntohl | +| test.cpp:21:26:21:29 | len2 | Unchecked use of data from network function $@ | test.cpp:10:16:10:20 | call to ntohl | call to ntohl | +| test.cpp:31:26:31:29 | len2 | Unchecked use of data from network function $@ | test.cpp:10:16:10:20 | call to ntohl | call to ntohl | +| test.cpp:61:26:61:29 | len2 | Unchecked use of data from network function $@ | test.cpp:10:16:10:20 | call to ntohl | call to ntohl | +| test.cpp:64:9:64:12 | len2 | Unchecked use of data from network function $@ | test.cpp:10:16:10:20 | call to ntohl | call to ntohl | +| test.cpp:73:10:73:13 | lens | Unchecked use of data from network function $@ | test.cpp:10:16:10:20 | call to ntohl | call to ntohl | +| test.cpp:86:10:86:13 | len3 | Unchecked use of data from network function $@ | test.cpp:85:10:85:14 | call to ntohl | call to ntohl | +| test.cpp:94:9:94:11 | len | Unchecked use of data from network function $@ | test.cpp:99:8:99:12 | call to ntohl | call to ntohl | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/NtohlArrayNoBound.qlref b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/NtohlArrayNoBound.qlref new file mode 100644 index 00000000000..2647a5479f2 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/NtohlArrayNoBound.qlref @@ -0,0 +1 @@ +Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBoundOpenSource.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/test.cpp new file mode 100644 index 00000000000..e3f01f9ae77 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/Buffer Overflow/NtohlArrayNoBound/test.cpp @@ -0,0 +1,100 @@ + +typedef unsigned int size_t; +void *memcpy(void *s1, const void *s2, size_t n); +size_t strlen(const char *s); +int ntohl(int x); + +void test1(const char *source, size_t len) +{ + char buffer[256]; + size_t len2 = ntohl(len); + + memcpy(buffer, source, ntohl(len)); // BAD + + if (len2 < 256) + { + memcpy(buffer, source, len2); // GOOD + } + + if (source != 0) + { + memcpy(buffer, source, len2); // BAD + } + + if ((len2 < 256) && (source != 0)) + { + memcpy(buffer, source, len2); // GOOD + } + + if ((len2 < 256) || (source != 0)) + { + memcpy(buffer, source, len2); // BAD + } + + if (len2 < 256) + { + if (source != 0) + { + memcpy(buffer, source, len2); // GOOD + } + } + + if (len2 >= 256) + { + // fail + } else { + memcpy(buffer, source, len2); // GOOD + } + + if (len2 + 1 < 256) + { + memcpy(buffer, source, len2 + 1); // GOOD + } + + if (strlen(source) < 256) + { + memcpy(buffer, source, strlen(source)); // GOOD + } + + if (strlen(source) < 256) + { + memcpy(buffer, source, len2); // BAD + } + + buffer[len2] = 0; // BAD + + if (len2 < 256) + { + buffer[len2] = 0; // GOOD + } + + { + unsigned short lens = len2; + buffer[lens] = 0; // BAD + } + + if (len2 < 256) + { + unsigned short lens = len2; + buffer[lens] = 0; // GOOD + } + + size_t len3 = 0; + if (len3 < 256) + { + len3 = ntohl(len); + buffer[len3] = 0; // BAD + } +} + +void test2(size_t len) +{ + char buffer[256]; + + buffer[len] = 0; // BAD +} + +void test3(size_t len) +{ + test2(ntohl(len)); +} From b6f16dee81a97f6f50d047beb9a90c0e9f9ee1c5 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 6 Nov 2019 15:14:48 +0100 Subject: [PATCH 0934/1227] Python: Fix bad join order in `py/unused-import` --- python/ql/src/Imports/UnusedImport.ql | 59 +++++++++++++++++---------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/python/ql/src/Imports/UnusedImport.ql b/python/ql/src/Imports/UnusedImport.ql index 3ac04e2e4d2..4049f3d5e41 100644 --- a/python/ql/src/Imports/UnusedImport.ql +++ b/python/ql/src/Imports/UnusedImport.ql @@ -41,41 +41,58 @@ predicate all_not_understood(Module m) { } predicate imported_module_used_in_doctest(Import imp) { - exists(string modname | + exists(string modname, string docstring | imp.getAName().getAsname().(Name).getId() = modname and // Look for doctests containing the patterns: // >>> …name… // ... …name… - exists(StrConst doc | - doc.getEnclosingModule() = imp.getScope() and - doc.isDocString() and - doc.getText().regexpMatch("[\\s\\S]*(>>>|\\.\\.\\.).*" + modname + "[\\s\\S]*") - ) + docstring = doctest_in_scope(imp.getScope()) and + docstring.regexpMatch("[\\s\\S]*(>>>|\\.\\.\\.).*" + modname + "[\\s\\S]*") + ) +} + +pragma[noinline] +private string doctest_in_scope(Scope scope) { + exists(StrConst doc | + doc.getEnclosingModule() = scope and + doc.isDocString() and + result = doc.getText() and + result.regexpMatch("[\\s\\S]*(>>>|\\.\\.\\.)[\\s\\S]*") + ) +} + +pragma[noinline] +private string typehint_annotation_in_file(File file) { + exists(StrConst annotation | + annotation = any(Arguments a).getAnAnnotation() + or + annotation = any(AnnAssign a).getAnnotation() + | + annotation.pointsTo(Value::forString(result)) and + file = annotation.getLocation().getFile() + ) +} + +pragma[noinline] +private string typehint_comment_in_file(File file) { + exists(Comment typehint | + file = typehint.getLocation().getFile() and + result = typehint.getText() and + result.matches("# type:%") ) } predicate imported_module_used_in_typehint(Import imp) { - exists(string modname, Location loc | + exists(string modname, File file | imp.getAName().getAsname().(Name).getId() = modname and - loc.getFile() = imp.getScope().(Module).getFile() + file = imp.getScope().(Module).getFile() | // Look for type hints containing the patterns: // # type: …name… - exists(Comment typehint | - loc = typehint.getLocation() and - typehint.getText().regexpMatch("# type:.*" + modname + ".*") - ) + typehint_comment_in_file(file).regexpMatch("# type:.*" + modname + ".*") or // Type hint is inside a string annotation, as needed for forward references - exists(string typehint, Expr annotation | - annotation = any(Arguments a).getAnAnnotation() - or - annotation = any(AnnAssign a).getAnnotation() - | - annotation.pointsTo(Value::forString(typehint)) and - loc = annotation.getLocation() and - typehint.regexpMatch(".*\\b" + modname + "\\b.*") - ) + typehint_annotation_in_file(file).regexpMatch(".*\\b" + modname + "\\b.*") ) } From 217ecd3551753708e146d46957d4765842adc3b7 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 6 Nov 2019 15:50:08 +0100 Subject: [PATCH 0935/1227] C++: Add

    tags to split text into paragraphs Without this, the rendered output is one big paragraph. --- .../Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp index 4d5dfabef14..621ae3273fd 100644 --- a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp +++ b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp @@ -21,7 +21,9 @@ Solutions to this problem can be thought of as falling into one of two categories: (1) rewrite the signed expression so that overflow cannot occur but the signedness remains, or (2) rewrite (or cast) the signed expression into unsigned form. +

    +

    Below we list examples of expressions where signed overflow may occur, along with proposed solutions. The list should not be considered exhaustive. @@ -31,21 +33,29 @@ considered exhaustive. Given unsigned short i, delta and i + delta < i, it is possible to rewrite it as (unsigned short)(i + delta) < i. Note that i + deltadoes not actually overflow, due to int promotion +

    +

    Given unsigned short i, delta and i + delta < i, it is also possible to rewrite it as USHORT_MAX - delta. It must be true that delta > 0 and the limits.h or climits header has been included. +

    +

    Given int i, delta and i + delta < i, it is possible to rewrite it as INT_MAX - delta. It must be true that delta > 0 and the limits.h or climits header has been included. +

    +

    Given int i, delta and i + delta < i, it is also possible to rewrite it as (unsigned)i + delta < i. Note that program semantics are affected by this change. +

    +

    Given int i, delta and i + delta < i, it is also possible to rewrite it as unsigned int i, delta and i + delta < i. Note that program semantics are From 43148083ebf7ca19832a5017b88f0853f5559ab9 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 6 Nov 2019 16:36:28 +0100 Subject: [PATCH 0936/1227] Python: Fix bad join order for `global_name_used`. As it turns out, there was a further bad join-order in the `global_name_used` predicate. In this case, there was a common subexpression in the RA that was being factored out and evaluated separately, producing a large number of tuples. --- python/ql/src/Imports/UnusedImport.ql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/Imports/UnusedImport.ql b/python/ql/src/Imports/UnusedImport.ql index 3ac04e2e4d2..3d9163f9320 100644 --- a/python/ql/src/Imports/UnusedImport.ql +++ b/python/ql/src/Imports/UnusedImport.ql @@ -13,17 +13,17 @@ import python import Variables.Definition -predicate global_name_used(Module m, Variable name) { +predicate global_name_used(Module m, string name) { exists(Name u, GlobalVariable v | u.uses(v) and - v.getId() = name.getId() and + v.getId() = name and u.getEnclosingModule() = m ) or // A use of an undefined class local variable, will use the global variable exists(Name u, LocalVariable v | u.uses(v) and - v.getId() = name.getId() and + v.getId() = name and u.getEnclosingModule() = m and not v.getScope().getEnclosingScope*() instanceof Function ) @@ -84,7 +84,7 @@ predicate unused_import(Import imp, Variable name) { not imp.getAnImportedModuleName() = "__future__" and not imp.getEnclosingModule().declaredInAll(name.getId()) and imp.getScope() = imp.getEnclosingModule() and - not global_name_used(imp.getScope(), name) and + not global_name_used(imp.getScope(), name.getId()) and // Imports in `__init__.py` are used to force module loading not imp.getEnclosingModule().isPackageInit() and // Name may be imported for use in epytext documentation From 399ac1f11297d24231ee8daab34daafd7618db0f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 Nov 2019 15:57:44 +0000 Subject: [PATCH 0937/1227] CPP: Rename 'getAssertedFalseCondition' to something less misleading. --- .../Security/CWE/CWE-457/InitializationFunctions.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll index 240bd7aa25e..1c299b9ad51 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll +++ b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll @@ -89,9 +89,9 @@ class ParameterNullCheck extends ParameterCheck { ( va = this.(NotExpr).getOperand() or va = any(EQExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or - va = getAssertedFalseCondition(this) or + va = getCheckedFalseCondition(this) or va = any(NEExpr eq | - eq = getAssertedFalseCondition(this) and eq.getAnOperand().getValue() = "0" + eq = getCheckedFalseCondition(this) and eq.getAnOperand().getValue() = "0" ).getAnOperand() ) or @@ -101,7 +101,7 @@ class ParameterNullCheck extends ParameterCheck { va = this or va = any(NEExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or va = any(EQExpr eq | - eq = getAssertedFalseCondition(this) and eq.getAnOperand().getValue() = "0" + eq = getCheckedFalseCondition(this) and eq.getAnOperand().getValue() = "0" ).getAnOperand() ) ) @@ -669,7 +669,7 @@ FieldAccess getAFieldAccess(Variable v) { } /** - * Gets a condition which is asserted to be false by the given `ne` expression, according to this pattern: + * Gets a condition which is checked to be false by the given `ne` expression, according to this pattern: * ``` * int a = !!result; * if (!a) { // <- ne @@ -677,7 +677,7 @@ FieldAccess getAFieldAccess(Variable v) { * } * ``` */ -Expr getAssertedFalseCondition(NotExpr ne) { +private Expr getCheckedFalseCondition(NotExpr ne) { exists(LocalVariable v | result = v.getInitializer().getExpr().(NotExpr).getOperand().(NotExpr).getOperand() and ne.getOperand() = v.getAnAccess() and From 0c3f4e530f62ce1340c022948f5a2a84108e6353 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 Nov 2019 16:07:28 +0000 Subject: [PATCH 0938/1227] CPP: Make some library predicates private. --- .../src/Security/CWE/CWE-457/InitializationFunctions.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll index 1c299b9ad51..276b6043901 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll +++ b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll @@ -567,7 +567,7 @@ Expr getAnInitializedArgument(Call call) { result = call.getArgument(initialized * the call, under the given context and evidence. */ pragma[nomagic] -int conditionallyInitializedArgument( +private int conditionallyInitializedArgument( Call call, ConditionalInitializationFunction target, Context c, Evidence e ) { target = getTarget(call) and @@ -588,7 +588,7 @@ Expr getAConditionallyInitializedArgument( /** * Gets the type signature for the functions parameters. */ -string typeSig(Function f) { +private string typeSig(Function f) { result = concat(int i, Type pt | pt = f.getParameter(i).getType() | @@ -599,7 +599,7 @@ string typeSig(Function f) { /** * Holds where qualifiedName and typeSig make up the signature for the function. */ -predicate functionSignature(Function f, string qualifiedName, string typeSig) { +private predicate functionSignature(Function f, string qualifiedName, string typeSig) { qualifiedName = f.getQualifiedName() and typeSig = typeSig(f) } @@ -611,7 +611,7 @@ predicate functionSignature(Function f, string qualifiedName, string typeSig) { * This is useful for identifying call to target dependencies across libraries, where the libraries * are never statically linked together. */ -Function getAPossibleDefinition(Function undefinedFunction) { +private Function getAPossibleDefinition(Function undefinedFunction) { not undefinedFunction.isDefined() and exists(string qn, string typeSig | functionSignature(undefinedFunction, qn, typeSig) and functionSignature(result, qn, typeSig) From 81c58d5a64cdda985da83f0395cca56230b9477c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 Nov 2019 16:17:33 +0000 Subject: [PATCH 0939/1227] CPP: Improve QLDoc comments. --- cpp/ql/src/semmle/code/cpp/NestedFields.qll | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/NestedFields.qll b/cpp/ql/src/semmle/code/cpp/NestedFields.qll index 12109be8ece..c4be8b8b9ff 100644 --- a/cpp/ql/src/semmle/code/cpp/NestedFields.qll +++ b/cpp/ql/src/semmle/code/cpp/NestedFields.qll @@ -1,9 +1,8 @@ import cpp /** - * Gets a `Field` that is nested within the given `Struct`. - * - * This identifies `Field`s which are located in the same memory + * Gets a `Field` that is within the given `Struct`, either directly or nested + * inside one or more levels of member structs. */ private Field getANestedField(Struct s) { result = s.getAField() @@ -15,7 +14,7 @@ private Field getANestedField(Struct s) { } /** - * Unwraps a series of field accesses to determine the inner-most qualifier. + * Unwraps a series of field accesses to determine the outer-most qualifier. */ private Expr getUltimateQualifier(FieldAccess fa) { exists(Expr qualifier | qualifier = fa.getQualifier() | From 2b24eb2e7083c7c776dd68b59289b8b6ea0ae479 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 6 Nov 2019 17:14:05 +0100 Subject: [PATCH 0940/1227] Python: Fix bad join order for `py/multiple-calls-to-init`. The `multiple_invocation_paths` predicate had a bad join order where we (essentially) joined `i1` with `i2` and only then joined `i1` and `i2` separately to reduce the number of tuples. The join coming from `i1 != i2` had little impact, but `i1.getFunction() = multi` made a big difference (and similarly for `i2`). I factored out the code so that these joins would be done more eagerly. Thus, we went from ``` [2019-11-06 16:53:05] (38s) Starting to evaluate predicate MethodCallOrder::multiple_invocation_paths#ffff/4@2ce75a [2019-11-06 16:53:35] (68s) Tuple counts for MethodCallOrder::multiple_invocation_paths#ffff: 134547 ~9% {2} r1 = SCAN CallGraph::TInvocation#fff AS I OUTPUT I.<0>, I.<2> 235284431 ~3% {4} r2 = JOIN r1 WITH CallGraph::TInvocation#fff AS R ON FIRST 1 OUTPUT r1.<0>, r1.<1>, R.<1>, R.<2> 235149884 ~3% {4} r3 = SELECT r2 ON r2.<3> != r2.<1> 235149884 ~4% {3} r4 = SCAN r3 OUTPUT r3.<1>, r3.<0>, r3.<3> 166753634 ~5% {4} r5 = JOIN r4 WITH #CallGraph::FunctionInvocation::getACallee_dispred#ffPlus#swapped AS R ON FIRST 1 OUTPUT R.<1>, r4.<2>, r4.<1>, r4.<0> 129778 ~0% {4} r6 = JOIN r5 WITH #CallGraph::FunctionInvocation::getACallee_dispred#ffPlus AS R ON FIRST 2 OUTPUT r5.<0>, r5.<3>, r5.<1>, r5.<2> return r6 [2019-11-06 16:53:35] (68s) Registering MethodCallOrder::multiple_invocation_paths#ffff + [] with content 1705dcbc08kd9aa40rp2g2e9civhv [2019-11-06 16:53:35] (68s) >>> Wrote relation MethodCallOrder::multiple_invocation_paths#ffff with 129778 rows and 4 columns. ``` to ``` [2019-11-06 17:22:22] (25s) Starting to evaluate predicate MethodCallOrder::multiple_invocation_paths_helper#ffff/4@586aec [2019-11-06 17:22:22] (25s) Tuple counts for MethodCallOrder::multiple_invocation_paths_helper#ffff: 134547 ~0% {2} r1 = SCAN CallGraph::TInvocation#fff AS I OUTPUT I.<2>, I.<0> 88111 ~4% {3} r2 = JOIN r1 WITH #CallGraph::FunctionInvocation::getACallee_dispred#ffPlus#swapped AS R ON FIRST 1 OUTPUT R.<1>, r1.<1>, r1.<0> 761305 ~0% {4} r3 = JOIN r2 WITH #CallGraph::FunctionInvocation::getACallee_dispred#ffPlus AS R ON FIRST 1 OUTPUT r2.<1>, r2.<2>, r2.<0>, R.<1> 673194 ~0% {4} r4 = SELECT r3 ON r3.<3> != r3.<1> 673194 ~0% {4} r5 = SCAN r4 OUTPUT r4.<2>, r4.<1>, r4.<3>, r4.<0> return r5 [2019-11-06 17:22:22] (25s) Registering MethodCallOrder::multiple_invocation_paths_helper#ffff + [] with content 20edaaecf25nldgp24d9c4et8m3kv [2019-11-06 17:22:22] (25s) >>> Wrote relation MethodCallOrder::multiple_invocation_paths_helper#ffff with 673194 rows and 4 columns. [2019-11-06 17:22:22] (25s) Starting to evaluate predicate MethodCallOrder::multiple_invocation_paths_helper#ffff_2301#join_rhs/4@9e5441 [2019-11-06 17:22:22] (25s) Tuple counts for MethodCallOrder::multiple_invocation_paths_helper#ffff_2301#join_rhs: 673194 ~0% {4} r1 = SCAN MethodCallOrder::multiple_invocation_paths_helper#ffff AS I OUTPUT I.<2>, I.<3>, I.<0>, I.<1> return r1 [2019-11-06 17:22:22] (25s) Registering MethodCallOrder::multiple_invocation_paths_helper#ffff_2301#join_rhs + [] with content 2069301e655fi9mcovngg9hetfqas [2019-11-06 17:22:22] (25s) >>> Wrote relation MethodCallOrder::multiple_invocation_paths_helper#ffff_2301#join_rhs with 673194 rows and 4 columns. [2019-11-06 17:22:22] (25s) Starting to evaluate predicate MethodCallOrder::multiple_invocation_paths#ffff/4@2f7c34 [2019-11-06 17:22:22] (25s) Tuple counts for MethodCallOrder::multiple_invocation_paths#ffff: 134547 ~0% {2} r1 = SCAN CallGraph::TInvocation#fff AS I OUTPUT I.<2>, I.<0> 129778 ~0% {4} r2 = JOIN r1 WITH MethodCallOrder::multiple_invocation_paths_helper#ffff_2301#join_rhs AS R ON FIRST 2 OUTPUT R.<2>, R.<3>, r1.<0>, r1.<1> return r2 [2019-11-06 17:22:22] (25s) Registering MethodCallOrder::multiple_invocation_paths#ffff + [] with content 1705dcbc08kd9aa40rp2g2e9civhv [2019-11-06 17:22:22] (25s) >>> Wrote relation MethodCallOrder::multiple_invocation_paths#ffff with 129778 rows and 4 columns. [2019-11-06 17:22:22] (25s) Starting to evaluate predicate MethodCallOrder::multiple_invocation_paths#ffff_0312#join_rhs/4@9f9146 [2019-11-06 17:22:22] (25s) Tuple counts for MethodCallOrder::multiple_invocation_paths#ffff_0312#join_rhs: 129778 ~0% {4} r1 = SCAN MethodCallOrder::multiple_invocation_paths#ffff AS I OUTPUT I.<0>, I.<3>, I.<1>, I.<2> return r1 [2019-11-06 17:22:22] (25s) Registering MethodCallOrder::multiple_invocation_paths#ffff_0312#join_rhs + [] with content 17c3fe1fcbf6ghhdr7hiukqp41rst [2019-11-06 17:22:22] (25s) >>> Wrote relation MethodCallOrder::multiple_invocation_paths#ffff_0312#join_rhs with 129778 rows and 4 columns. ``` Execution time on `salt` went from 29.5s to somewhere below 299ms (the predicate was not listed in the timing report). --- python/ql/src/Classes/MethodCallOrder.qll | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/python/ql/src/Classes/MethodCallOrder.qll b/python/ql/src/Classes/MethodCallOrder.qll index fe6ef07266a..5073cefc134 100644 --- a/python/ql/src/Classes/MethodCallOrder.qll +++ b/python/ql/src/Classes/MethodCallOrder.qll @@ -3,11 +3,16 @@ import python // Helper predicates for multiple call to __init__/__del__ queries. pragma [noinline] -private predicate multiple_invocation_paths(FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2, FunctionObject multi) { +private predicate multiple_invocation_paths_helper(FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2, FunctionObject multi) { i1 != i2 and i1 = top.getACallee+() and i2 = top.getACallee+() and - i1.getFunction() = multi and + i1.getFunction() = multi +} + +pragma [noinline] +private predicate multiple_invocation_paths(FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2, FunctionObject multi) { + multiple_invocation_paths_helper(top, i1, i2, multi) and i2.getFunction() = multi } From e886cf729773f9e1f86ff35805e596e5f4274d9f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 Nov 2019 16:27:06 +0000 Subject: [PATCH 0941/1227] CPP: 'i.e.' -> 'that is'. --- cpp/ql/src/Microsoft/SAL.qll | 2 +- cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll | 2 +- .../src/semmle/code/cpp/security/boostorg/asio/protocols.qll | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/Microsoft/SAL.qll b/cpp/ql/src/Microsoft/SAL.qll index fe6b455fa9b..963a726ae54 100644 --- a/cpp/ql/src/Microsoft/SAL.qll +++ b/cpp/ql/src/Microsoft/SAL.qll @@ -126,7 +126,7 @@ class SALParameter extends Parameter { } /** - * A SAL element, i.e. a SAL annotation or a declaration entry + * A SAL element, that is, a SAL annotation or a declaration entry * that may have SAL annotations. */ library class SALElement extends Element { diff --git a/cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll b/cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll index 2fa9322843e..a181c9bb543 100644 --- a/cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll @@ -63,7 +63,7 @@ module VirtualDispatch { /** * Holds if `c` cannot inherit the member function `f`, - * i.e. `c` or one of its supertypes overrides `f`. + * that is, `c` or one of its supertypes overrides `f`. */ private predicate cannotInherit(Class c, MemberFunction f) { exists(Class overridingType, MemberFunction override | diff --git a/cpp/ql/src/semmle/code/cpp/security/boostorg/asio/protocols.qll b/cpp/ql/src/semmle/code/cpp/security/boostorg/asio/protocols.qll index ae3733473ad..af1a8eaf8e7 100644 --- a/cpp/ql/src/semmle/code/cpp/security/boostorg/asio/protocols.qll +++ b/cpp/ql/src/semmle/code/cpp/security/boostorg/asio/protocols.qll @@ -56,7 +56,8 @@ module BoostorgAsio { } /** - * returns the value for a approved protocols, but that are hard-coded (i.e. no protocol negotiation) + * returns the value for an approved protocol, but that are hard-coded + * (that is, no protocol negotiation) */ EnumConstant getAnApprovedButHardcodedProtocolConstant() { result = this.getATls12ProtocolConstant() From 54e40a8977f50173dbfd0befae900fa5080208af Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 6 Nov 2019 12:19:09 +0000 Subject: [PATCH 0942/1227] JavaScript: Move `--html all` extractor options into `options` file. --- javascript/ql/test/library-tests/HTML/HtmlText/HtmlText.html | 2 +- javascript/ql/test/library-tests/HTML/HtmlText/options | 1 + .../frameworks/AngularJS/expressions/scopes/options | 1 + .../frameworks/AngularJS/expressions/scopes/tst.html | 1 - .../frameworks/AngularJS/expressions/sources/HtmlText.html | 1 - .../frameworks/AngularJS/expressions/sources/options | 1 + 6 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 javascript/ql/test/library-tests/HTML/HtmlText/options create mode 100644 javascript/ql/test/library-tests/frameworks/AngularJS/expressions/scopes/options create mode 100644 javascript/ql/test/library-tests/frameworks/AngularJS/expressions/sources/options diff --git a/javascript/ql/test/library-tests/HTML/HtmlText/HtmlText.html b/javascript/ql/test/library-tests/HTML/HtmlText/HtmlText.html index 6cf4bfc564f..0b571650c40 100644 --- a/javascript/ql/test/library-tests/HTML/HtmlText/HtmlText.html +++ b/javascript/ql/test/library-tests/HTML/HtmlText/HtmlText.html @@ -1,4 +1,4 @@ -// semmle-extractor-options: --html all + (1) as child #0 diff --git a/javascript/ql/test/library-tests/HTML/HtmlText/options b/javascript/ql/test/library-tests/HTML/HtmlText/options new file mode 100644 index 00000000000..46bf0192945 --- /dev/null +++ b/javascript/ql/test/library-tests/HTML/HtmlText/options @@ -0,0 +1 @@ +semmle-extractor-options: --html all diff --git a/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/scopes/options b/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/scopes/options new file mode 100644 index 00000000000..46bf0192945 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/scopes/options @@ -0,0 +1 @@ +semmle-extractor-options: --html all diff --git a/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/scopes/tst.html b/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/scopes/tst.html index 23449e03c0e..29608f2da53 100644 --- a/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/scopes/tst.html +++ b/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/scopes/tst.html @@ -17,4 +17,3 @@ -// semmle-extractor-options: --html all diff --git a/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/sources/HtmlText.html b/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/sources/HtmlText.html index 9678f75e0cc..87bb928ac4c 100644 --- a/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/sources/HtmlText.html +++ b/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/sources/HtmlText.html @@ -7,4 +7,3 @@

    {{myExpr3}}
    -semmle-extractor-options: --html all diff --git a/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/sources/options b/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/sources/options new file mode 100644 index 00000000000..46bf0192945 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/sources/options @@ -0,0 +1 @@ +semmle-extractor-options: --html all From 6c38f55e28aa4b9ebff51ccddd6a414fa03f45de Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 Nov 2019 16:31:21 +0000 Subject: [PATCH 0943/1227] CPP: QLDoc protocols.qll. --- .../cpp/security/boostorg/asio/protocols.qll | 61 ++++++++++--------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/boostorg/asio/protocols.qll b/cpp/ql/src/semmle/code/cpp/security/boostorg/asio/protocols.qll index af1a8eaf8e7..73ccd49e2f8 100644 --- a/cpp/ql/src/semmle/code/cpp/security/boostorg/asio/protocols.qll +++ b/cpp/ql/src/semmle/code/cpp/security/boostorg/asio/protocols.qll @@ -3,7 +3,7 @@ import semmle.code.cpp.dataflow.DataFlow module BoostorgAsio { /** - * Represents boost::asio::ssl::context enum + * Represents the `boost::asio::ssl::context` enum. */ class SslContextMethod extends Enum { SslContextMethod() { @@ -12,7 +12,7 @@ module BoostorgAsio { } /** - * returns the value for a banned protocol + * Gets an enumeration constant for a banned protocol. */ EnumConstant getABannedProtocolConstant() { result = this.getAnEnumConstant() and @@ -56,15 +56,15 @@ module BoostorgAsio { } /** - * returns the value for an approved protocol, but that are hard-coded - * (that is, no protocol negotiation) + * Gets an enumeration constant for an approved protocol, that is hard-coded + * (no protocol negotiation). */ EnumConstant getAnApprovedButHardcodedProtocolConstant() { result = this.getATls12ProtocolConstant() } /** - * returns the value for a TLS v1.2 protocol + * Gets an enumeration constant for a TLS v1.2 protocol. */ EnumConstant getATls12ProtocolConstant() { result = this.getAnEnumConstant() and @@ -81,7 +81,7 @@ module BoostorgAsio { } /** - * returns the value for a TLS v1.3 protocol + * Gets an enumeration constant for a TLS v1.3 protocol. */ EnumConstant getATls13ProtocolConstant() { result = this.getAnEnumConstant() and @@ -98,7 +98,7 @@ module BoostorgAsio { } /** - * returns the value of a generic TLS or SSL/TLS protocol + * Gets an enumeration constant for a generic TLS or SSL/TLS protocol. */ EnumConstant getAGenericTlsProtocolConstant() { result = this.getAnEnumConstant() and @@ -117,7 +117,7 @@ module BoostorgAsio { } /** - * returns the value of a generic SSL/TLS protocol + * Gets an enumeration constant for a generic SSL/TLS protocol. */ EnumConstant getASslv23ProtocolConstant() { result = this.getAnEnumConstant() and @@ -136,7 +136,9 @@ module BoostorgAsio { } /** - * NOTE: ignore - Modern versions of OpenSSL do not support SSL v2 anymore, so this option is for backwards compatibility only + * Gets the value for the no_sslv2 constant, right shifted by 16 bits. + * + * Note that modern versions of OpelSSL do not support SSL v2, so this option is for backwards compatibility only. */ int getShiftedSslOptionsNoSsl2() { // SSL_OP_NO_SSLv2 was removed from modern OpenSSL versions @@ -144,7 +146,7 @@ module BoostorgAsio { } /** - * RightShift(16) value for no_sslv3 constant + * Gets the value for the no_sslv3 constant, right shifted by 16 bits. */ int getShiftedSslOptionsNoSsl3() { // SSL_OP_NO_SSLv3 == 0x02000000U @@ -152,7 +154,7 @@ module BoostorgAsio { } /** - * RightShift(16) value for no_tlsv1 constant + * Gets the value for the no_tlsv1 constant, right shifted by 16 bits. */ int getShiftedSslOptionsNoTls1() { // SSL_OP_NO_TLSv1 == 0x04000000U @@ -160,7 +162,7 @@ module BoostorgAsio { } /** - * RightShift(16) value for no_tlsv1_1 constant + * Gets the value for the no_tlsv1_1 constant, right shifted by 16 bits. */ int getShiftedSslOptionsNoTls1_1() { // SSL_OP_NO_TLSv1_1 == 0x10000000U @@ -168,7 +170,7 @@ module BoostorgAsio { } /** - * RightShift(16) value for no_tlsv1_2 constant + * Gets the value for the no_tlsv1_2 constant, right shifted by 16 bits. */ int getShiftedSslOptionsNoTls1_2() { // SSL_OP_NO_TLSv1_2 == 0x08000000U @@ -176,7 +178,7 @@ module BoostorgAsio { } /** - * RightShift(16) value for no_tlsv1_3 constant + * Gets the value for the no_tlsv1_3 constant, right shifted by 16 bits. */ int getShiftedSslOptionsNoTls1_3() { // SSL_OP_NO_TLSv1_2 == 0x20000000U @@ -184,7 +186,7 @@ module BoostorgAsio { } /** - * Represents boost::asio::ssl::context class + * Represents the `boost::asio::ssl::context` class. */ class SslContextClass extends Class { SslContextClass() { this.getQualifiedName() = "boost::asio::ssl::context" } @@ -197,7 +199,7 @@ module BoostorgAsio { } /** - * Represents boost::asio::ssl::context::set_options member function + * Represents `boost::asio::ssl::context::set_options` member function. */ class SslSetOptionsFunction extends Function { SslSetOptionsFunction() { @@ -206,7 +208,7 @@ module BoostorgAsio { } /** - * holds if the expression represents a banned protocol + * Holds if the expression represents a banned protocol. */ predicate isExprBannedBoostProtocol(Expr e) { exists(Literal va | va = e | @@ -245,7 +247,7 @@ module BoostorgAsio { } /** - * holds if the expression represents a TLS v1.2 protocol + * Holds if the expression represents a TLS v1.2 protocol. */ predicate isExprTls12BoostProtocol(Expr e) { exists(Literal va | va = e | @@ -270,7 +272,7 @@ module BoostorgAsio { } /** - * holds if the expression represents a protocol that requires Crypto Board approval + * Holds if the expression represents a protocol that requires Crypto Board approval. */ predicate isExprTls13BoostProtocol(Expr e) { exists(Literal va | va = e | @@ -295,7 +297,7 @@ module BoostorgAsio { } /** - * holds if the expression represents a generic TLS or SSL/TLS protocol + * Holds if the expression represents a generic TLS or SSL/TLS protocol. */ predicate isExprTlsBoostProtocol(Expr e) { exists(Literal va | va = e | @@ -326,7 +328,7 @@ module BoostorgAsio { } /** - * holds if the expression represents a generic SSl/TLS protocol + * Holds if the expression represents a generic SSl/TLS protocol. */ predicate isExprSslV23BoostProtocol(Expr e) { exists(Literal va | va = e | @@ -352,7 +354,8 @@ module BoostorgAsio { //////////////////////// Dataflow ///////////////////// /** - * Abstract - Protocol value Flows to the first argument of the context constructor + * Abstract class for flows of protocol values to the first argument of a context + * constructor. */ abstract class SslContextCallAbstractConfig extends DataFlow::Configuration { bindingset[this] @@ -367,7 +370,7 @@ module BoostorgAsio { } /** - * any Protocol value Flows to the first argument of the context constructor + * Any protocol value that flows to the first argument of a context constructor. */ class SslContextCallConfig extends SslContextCallAbstractConfig { SslContextCallConfig() { this = "SslContextCallConfig" } @@ -381,7 +384,7 @@ module BoostorgAsio { } /** - * a banned protocol value Flows to the first argument of the context constructor + * A banned protocol value that flows to the first argument of a context constructor. */ class SslContextCallBannedProtocolConfig extends SslContextCallAbstractConfig { SslContextCallBannedProtocolConfig() { this = "SslContextCallBannedProtocolConfig" } @@ -396,7 +399,7 @@ module BoostorgAsio { } /** - * a TLS 1.2 protocol value Flows to the first argument of the context constructor + * A TLS 1.2 protocol value that flows to the first argument of a context constructor. */ class SslContextCallTls12ProtocolConfig extends SslContextCallAbstractConfig { SslContextCallTls12ProtocolConfig() { this = "SslContextCallTls12ProtocolConfig" } @@ -411,7 +414,7 @@ module BoostorgAsio { } /** - * a TLS 1.3 protocol value Flows to the first argument of the context constructor + * A TLS 1.3 protocol value that flows to the first argument of a context constructor. */ class SslContextCallTls13ProtocolConfig extends SslContextCallAbstractConfig { SslContextCallTls13ProtocolConfig() { this = "SslContextCallTls12ProtocolConfig" } @@ -426,7 +429,7 @@ module BoostorgAsio { } /** - * a generic TLS protocol value Flows to the first argument of the context constructor + * A generic TLS protocol value that flows to the first argument of a context constructor. */ class SslContextCallTlsProtocolConfig extends SslContextCallAbstractConfig { SslContextCallTlsProtocolConfig() { this = "SslContextCallTlsProtocolConfig" } @@ -441,7 +444,7 @@ module BoostorgAsio { } /** - * a context constructor call flows to a call calling SetOptions() + * A context constructor call that flows to a call to `SetOptions()`. */ class SslContextFlowsToSetOptionConfig extends DataFlow::Configuration { SslContextFlowsToSetOptionConfig() { this = "SslContextFlowsToSetOptionConfig" } @@ -465,7 +468,7 @@ module BoostorgAsio { } /** - * an option value flows to the 1st parameter of SetOptions() + * An option value that flows to the first parameter of a call to `SetOptions()`. */ class SslOptionConfig extends DataFlow::Configuration { SslOptionConfig() { this = "SslOptionConfig" } From 7850d67a782db5160f22122a4b36fc3645635c98 Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Wed, 6 Nov 2019 17:47:02 +0000 Subject: [PATCH 0944/1227] Remove TODO comment I've checked Hamcrest versions 1.3, 2.0, 2.1 and 2.2 --- java/ql/src/semmle/code/java/frameworks/Assertions.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/frameworks/Assertions.qll b/java/ql/src/semmle/code/java/frameworks/Assertions.qll index aac514a26bd..eb210d5e0d7 100644 --- a/java/ql/src/semmle/code/java/frameworks/Assertions.qll +++ b/java/ql/src/semmle/code/java/frameworks/Assertions.qll @@ -30,7 +30,7 @@ private predicate assertionMethod(Method m, AssertKind kind) { or exists(RefType hamcrest | m.getDeclaringType() = hamcrest and - hamcrest.hasQualifiedName("org.hamcrest", "MatcherAssert") // TODO: Check some older versions of hamcrest + hamcrest.hasQualifiedName("org.hamcrest", "MatcherAssert") | m.hasName("assertThat") and kind = AssertKindThat() ) From a9e3bfbd11476210ff72c95f15866b7f745bae8e Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 6 Nov 2019 13:08:28 -0700 Subject: [PATCH 0945/1227] C++/C#: Treat string literals like read-only global variables for alias purposes. Previously, we didn't track string literals as known memory locations at all, so they all just got marked as `UnknownMemoryLocation`, just like an aribtrary read from a random pointer. This led to some confusing def-use chains, where it would look like the contents of a string literal were being written to by the side effect of an earlier function call, which of course is impossible. To fix this, I've made two changes. First, each string literal is now given a corresponding `IRVariable` (specifically `IRStringLiteral`), since a string literal behaves more or less as a read-only global variable. Second, the `IRVariable` for each string literal is now marked `isReadOnly()`, which the alias analysis uses to determine that an arbitrary write to aliased memory will not overwrite the contents of a string literal. I originally planned to treat all string literals with the same value as being the same memory location, since this is the usual behavior of modern compilers. However, this made implementing `IRVariable.getAST()` tricky for string literals, so I left them unpooled. --- .../implementation/aliased_ssa/IRVariable.qll | 57 ++++++++++++++----- .../aliased_ssa/Instruction.qll | 10 ++-- .../aliased_ssa/internal/AliasAnalysis.qll | 4 ++ .../aliased_ssa/internal/AliasedSSA.qll | 12 ++-- .../aliased_ssa/internal/SSAConstruction.qll | 5 -- .../implementation/internal/TIRVariable.qll | 6 ++ .../cpp/ir/implementation/raw/IRVariable.qll | 57 ++++++++++++++----- .../cpp/ir/implementation/raw/Instruction.qll | 10 ++-- .../raw/internal/IRConstruction.qll | 23 +++++--- .../unaliased_ssa/IRVariable.qll | 57 ++++++++++++++----- .../unaliased_ssa/Instruction.qll | 10 ++-- .../unaliased_ssa/internal/AliasAnalysis.qll | 4 ++ .../internal/SSAConstruction.qll | 5 -- .../ir/ssa/aliased_ssa_ir.expected | 26 +++++++++ cpp/ql/test/library-tests/ir/ssa/ssa.cpp | 8 +++ .../ir/ssa/unaliased_ssa_ir.expected | 25 ++++++++ .../implementation/internal/TIRVariable.qll | 6 ++ .../ir/implementation/raw/IRVariable.qll | 57 ++++++++++++++----- .../ir/implementation/raw/Instruction.qll | 10 ++-- .../raw/internal/IRConstruction.qll | 25 +++++--- .../unaliased_ssa/IRVariable.qll | 57 ++++++++++++++----- .../unaliased_ssa/Instruction.qll | 10 ++-- .../internal/SSAConstruction.qll | 5 -- 23 files changed, 359 insertions(+), 130 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 1a607f82c29..e10e266b2ab 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable { abstract string toString(); + /** + * Holds if this variable's value cannot be changed within a function. Currently used for string + * literals, but could also apply to `const` global and static variables. + */ + predicate isReadOnly() { none() } + /** * Gets the type of the variable. */ @@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable { final override Language::StaticVariable getVariable() { result = var } } +abstract class IRGeneratedVariable extends IRVariable { + Language::AST ast; + Language::LanguageType type; + + final override Language::LanguageType getLanguageType() { result = type } + + final override Language::AST getAST() { result = ast } + + override string toString() { result = getBaseString() + getLocationString() } + + override string getUniqueId() { none() } + + final string getLocationString() { + result = ast.getLocation().getStartLine().toString() + ":" + + ast.getLocation().getStartColumn().toString() + } + + string getBaseString() { none() } +} + IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { result.getAST() = ast and result.getTag() = tag } -class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { - Language::AST ast; +class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; - Language::LanguageType type; IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - final override Language::LanguageType getLanguageType() { result = type } - - final override Language::AST getAST() { result = ast } - final override string getUniqueId() { result = "Temp: " + Construction::getTempVariableUniqueId(this) } final TempVariableTag getTag() { result = tag } - override string toString() { - result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" + - ast.getLocation().getStartColumn().toString() - } - - string getBaseString() { result = "#temp" } + override string getBaseString() { result = "#temp" } } class IRReturnVariable extends IRTempVariable { @@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable { override string getBaseString() { result = "#throw" } } + +class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { + Language::StringLiteral literal; + + IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) } + + final override predicate isReadOnly() { any() } + + final override string getUniqueId() { + result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal) + } + + override string getBaseString() { result = "#string" } + + final Language::StringLiteral getLiteral() { result = literal } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 049983c9126..9f7cf68b065 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -808,14 +808,12 @@ class FloatConstantInstruction extends ConstantInstruction { FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } } -class StringConstantInstruction extends Instruction { - Language::StringLiteral value; +class StringConstantInstruction extends VariableInstruction { + override IRStringLiteral var; - StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) } + final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } - final override string getImmediateString() { result = Language::getStringLiteralText(value) } - - final Language::StringLiteral getValue() { result = value } + final Language::StringLiteral getValue() { result = var.getLiteral() } } class BinaryInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index b9aa07c1b36..0923ec8f994 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -308,6 +308,10 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) instr.(VariableAddressInstruction).getIRVariable() = var and bitOffset = 0 or + // A string literal is just a special read-only global variable. + instr.(StringConstantInstruction).getIRVariable() = var and + bitOffset = 0 + or exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset | operand = instr.getAnOperand() and // If an operand is propagated, then the result points to the same variable, diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll index 955d422cf9a..0835ffb7da6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll @@ -210,17 +210,21 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) { def instanceof UnknownVirtualVariable and result instanceof MustTotallyOverlap or - // An UnknownMemoryLocation may partially overlap any Location within the same virtual variable. + // An UnknownMemoryLocation may partially overlap any Location within the same virtual variable, + // unless the location is read-only. def.getVirtualVariable() = use.getVirtualVariable() and def instanceof UnknownMemoryLocation and - result instanceof MayPartiallyOverlap + result instanceof MayPartiallyOverlap and + not use.(VariableMemoryLocation).getVariable().isReadOnly() or // An UnknownNonLocalMemoryLocation may partially overlap any location within the same virtual - // variable, except a local variable. + // variable, except a local variable or read-only variable. def.getVirtualVariable() = use.getVirtualVariable() and def instanceof UnknownNonLocalMemoryLocation and result instanceof MayPartiallyOverlap and - not use.(VariableMemoryLocation).getVariable() instanceof IRAutomaticVariable + not exists(IRVariable var | var = use.(VariableMemoryLocation).getVariable() | + var instanceof IRAutomaticVariable or var.isReadOnly() + ) or exists(VariableMemoryLocation defVariableLocation | defVariableLocation = def and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 7152dec5c4a..c8362098295 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -341,11 +341,6 @@ private module Cached { result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() } - cached - Language::StringLiteral getInstructionStringLiteral(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue() - } - cached Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { result = getOldInstruction(instruction) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll index fea67ef5ecd..01c135abf13 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll @@ -9,4 +9,10 @@ newtype TIRVariable = Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type ) { Construction::hasTempVariable(func, ast, tag, type) + } or + TIRStringLiteral( + Language::Function func, Language::AST ast, Language::LanguageType type, + Language::StringLiteral literal + ) { + Construction::hasStringLiteral(func, ast, type, literal) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 1a607f82c29..e10e266b2ab 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable { abstract string toString(); + /** + * Holds if this variable's value cannot be changed within a function. Currently used for string + * literals, but could also apply to `const` global and static variables. + */ + predicate isReadOnly() { none() } + /** * Gets the type of the variable. */ @@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable { final override Language::StaticVariable getVariable() { result = var } } +abstract class IRGeneratedVariable extends IRVariable { + Language::AST ast; + Language::LanguageType type; + + final override Language::LanguageType getLanguageType() { result = type } + + final override Language::AST getAST() { result = ast } + + override string toString() { result = getBaseString() + getLocationString() } + + override string getUniqueId() { none() } + + final string getLocationString() { + result = ast.getLocation().getStartLine().toString() + ":" + + ast.getLocation().getStartColumn().toString() + } + + string getBaseString() { none() } +} + IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { result.getAST() = ast and result.getTag() = tag } -class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { - Language::AST ast; +class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; - Language::LanguageType type; IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - final override Language::LanguageType getLanguageType() { result = type } - - final override Language::AST getAST() { result = ast } - final override string getUniqueId() { result = "Temp: " + Construction::getTempVariableUniqueId(this) } final TempVariableTag getTag() { result = tag } - override string toString() { - result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" + - ast.getLocation().getStartColumn().toString() - } - - string getBaseString() { result = "#temp" } + override string getBaseString() { result = "#temp" } } class IRReturnVariable extends IRTempVariable { @@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable { override string getBaseString() { result = "#throw" } } + +class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { + Language::StringLiteral literal; + + IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) } + + final override predicate isReadOnly() { any() } + + final override string getUniqueId() { + result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal) + } + + override string getBaseString() { result = "#string" } + + final Language::StringLiteral getLiteral() { result = literal } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 049983c9126..9f7cf68b065 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -808,14 +808,12 @@ class FloatConstantInstruction extends ConstantInstruction { FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } } -class StringConstantInstruction extends Instruction { - Language::StringLiteral value; +class StringConstantInstruction extends VariableInstruction { + override IRStringLiteral var; - StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) } + final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } - final override string getImmediateString() { result = Language::getStringLiteralText(value) } - - final Language::StringLiteral getValue() { result = value } + final Language::StringLiteral getValue() { result = var.getLiteral() } } class BinaryInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index fbf6b7e3d08..fe161e5196a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -44,6 +44,13 @@ private module Cached { ) } + cached + predicate hasStringLiteral(Function func, Locatable ast, CppType type, StringLiteral literal) { + literal = ast and + literal.getEnclosingFunction() = func and + getTypeForPRValue(literal.getType()) = type + } + cached predicate hasModeledMemoryResult(Instruction instruction) { none() } @@ -231,8 +238,14 @@ private module Cached { cached IRVariable getInstructionVariable(Instruction instruction) { - result = getInstructionTranslatedElement(instruction) - .getInstructionVariable(getInstructionTag(instruction)) + exists(TranslatedElement element, InstructionTag tag | + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) and + ( + result = element.getInstructionVariable(tag) or + result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) + ) + ) } cached @@ -263,12 +276,6 @@ private module Cached { ) } - cached - StringLiteral getInstructionStringLiteral(Instruction instruction) { - result = getInstructionTranslatedElement(instruction) - .getInstructionStringLiteral(getInstructionTag(instruction)) - } - cached BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { result = getInstructionTranslatedElement(instruction) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 1a607f82c29..e10e266b2ab 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable { abstract string toString(); + /** + * Holds if this variable's value cannot be changed within a function. Currently used for string + * literals, but could also apply to `const` global and static variables. + */ + predicate isReadOnly() { none() } + /** * Gets the type of the variable. */ @@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable { final override Language::StaticVariable getVariable() { result = var } } +abstract class IRGeneratedVariable extends IRVariable { + Language::AST ast; + Language::LanguageType type; + + final override Language::LanguageType getLanguageType() { result = type } + + final override Language::AST getAST() { result = ast } + + override string toString() { result = getBaseString() + getLocationString() } + + override string getUniqueId() { none() } + + final string getLocationString() { + result = ast.getLocation().getStartLine().toString() + ":" + + ast.getLocation().getStartColumn().toString() + } + + string getBaseString() { none() } +} + IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { result.getAST() = ast and result.getTag() = tag } -class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { - Language::AST ast; +class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; - Language::LanguageType type; IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - final override Language::LanguageType getLanguageType() { result = type } - - final override Language::AST getAST() { result = ast } - final override string getUniqueId() { result = "Temp: " + Construction::getTempVariableUniqueId(this) } final TempVariableTag getTag() { result = tag } - override string toString() { - result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" + - ast.getLocation().getStartColumn().toString() - } - - string getBaseString() { result = "#temp" } + override string getBaseString() { result = "#temp" } } class IRReturnVariable extends IRTempVariable { @@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable { override string getBaseString() { result = "#throw" } } + +class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { + Language::StringLiteral literal; + + IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) } + + final override predicate isReadOnly() { any() } + + final override string getUniqueId() { + result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal) + } + + override string getBaseString() { result = "#string" } + + final Language::StringLiteral getLiteral() { result = literal } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 049983c9126..9f7cf68b065 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -808,14 +808,12 @@ class FloatConstantInstruction extends ConstantInstruction { FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } } -class StringConstantInstruction extends Instruction { - Language::StringLiteral value; +class StringConstantInstruction extends VariableInstruction { + override IRStringLiteral var; - StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) } + final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } - final override string getImmediateString() { result = Language::getStringLiteralText(value) } - - final Language::StringLiteral getValue() { result = value } + final Language::StringLiteral getValue() { result = var.getLiteral() } } class BinaryInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index b9aa07c1b36..0923ec8f994 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -308,6 +308,10 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) instr.(VariableAddressInstruction).getIRVariable() = var and bitOffset = 0 or + // A string literal is just a special read-only global variable. + instr.(StringConstantInstruction).getIRVariable() = var and + bitOffset = 0 + or exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset | operand = instr.getAnOperand() and // If an operand is propagated, then the result points to the same variable, diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 7152dec5c4a..c8362098295 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -341,11 +341,6 @@ private module Cached { result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() } - cached - Language::StringLiteral getInstructionStringLiteral(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue() - } - cached Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { result = getOldInstruction(instruction) 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 98786207c45..07faf581d3e 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 @@ -869,3 +869,29 @@ ssa.cpp: # 207| v0_25(void) = UnmodeledUse : mu* # 207| v0_26(void) = AliasedUse : ~m0_1 # 207| v0_27(void) = ExitFunction : + +# 215| char StringLiteralAliasing() +# 215| Block 0 +# 215| v0_0(void) = EnterFunction : +# 215| m0_1(unknown) = AliasedDefinition : +# 215| mu0_2(unknown) = UnmodeledDefinition : +# 216| r0_3(glval) = FunctionAddress[ExternalFunc] : +# 216| v0_4(void) = Call : func:r0_3 +# 216| m0_5(unknown) = ^CallSideEffect : ~m0_1 +# 216| m0_6(unknown) = Chi : total:m0_1, partial:m0_5 +# 218| r0_7(glval) = VariableAddress[s] : +# 218| r0_8(glval) = StringConstant["Literal"] : +# 218| r0_9(char *) = Convert : r0_8 +# 218| m0_10(char *) = Store : &:r0_7, r0_9 +# 219| r0_11(glval) = VariableAddress[#return] : +# 219| r0_12(glval) = VariableAddress[s] : +# 219| r0_13(char *) = Load : &:r0_12, m0_10 +# 219| r0_14(int) = Constant[2] : +# 219| r0_15(glval) = PointerAdd[1] : r0_13, r0_14 +# 219| r0_16(char) = Load : &:r0_15, ~m0_1 +# 219| m0_17(char) = Store : &:r0_11, r0_16 +# 215| r0_18(glval) = VariableAddress[#return] : +# 215| v0_19(void) = ReturnValue : &:r0_18, m0_17 +# 215| v0_20(void) = UnmodeledUse : mu* +# 215| v0_21(void) = AliasedUse : ~m0_6 +# 215| v0_22(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp index 4dfb0a2f6cd..8ce2b8900d8 100644 --- a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp +++ b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp @@ -210,3 +210,11 @@ int ModeledCallTarget(int x) { return y; } +extern void ExternalFunc(); + +char StringLiteralAliasing() { + ExternalFunc(); + + const char* s = "Literal"; + return s[2]; // Should be defined by `AliasedDefinition`, not `Chi` or `CallSideEffect`. +} diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 5ac06cadb55..03cf52c2ad6 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -833,3 +833,28 @@ ssa.cpp: # 207| v0_22(void) = UnmodeledUse : mu* # 207| v0_23(void) = AliasedUse : ~mu0_2 # 207| v0_24(void) = ExitFunction : + +# 215| char StringLiteralAliasing() +# 215| Block 0 +# 215| v0_0(void) = EnterFunction : +# 215| mu0_1(unknown) = AliasedDefinition : +# 215| mu0_2(unknown) = UnmodeledDefinition : +# 216| r0_3(glval) = FunctionAddress[ExternalFunc] : +# 216| v0_4(void) = Call : func:r0_3 +# 216| mu0_5(unknown) = ^CallSideEffect : ~mu0_2 +# 218| r0_6(glval) = VariableAddress[s] : +# 218| r0_7(glval) = StringConstant["Literal"] : +# 218| r0_8(char *) = Convert : r0_7 +# 218| m0_9(char *) = Store : &:r0_6, r0_8 +# 219| r0_10(glval) = VariableAddress[#return] : +# 219| r0_11(glval) = VariableAddress[s] : +# 219| r0_12(char *) = Load : &:r0_11, m0_9 +# 219| r0_13(int) = Constant[2] : +# 219| r0_14(glval) = PointerAdd[1] : r0_12, r0_13 +# 219| r0_15(char) = Load : &:r0_14, ~mu0_2 +# 219| m0_16(char) = Store : &:r0_10, r0_15 +# 215| r0_17(glval) = VariableAddress[#return] : +# 215| v0_18(void) = ReturnValue : &:r0_17, m0_16 +# 215| v0_19(void) = UnmodeledUse : mu* +# 215| v0_20(void) = AliasedUse : ~mu0_2 +# 215| v0_21(void) = ExitFunction : diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll index fea67ef5ecd..01c135abf13 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll @@ -9,4 +9,10 @@ newtype TIRVariable = Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type ) { Construction::hasTempVariable(func, ast, tag, type) + } or + TIRStringLiteral( + Language::Function func, Language::AST ast, Language::LanguageType type, + Language::StringLiteral literal + ) { + Construction::hasStringLiteral(func, ast, type, literal) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll index 1a607f82c29..e10e266b2ab 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll @@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable { abstract string toString(); + /** + * Holds if this variable's value cannot be changed within a function. Currently used for string + * literals, but could also apply to `const` global and static variables. + */ + predicate isReadOnly() { none() } + /** * Gets the type of the variable. */ @@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable { final override Language::StaticVariable getVariable() { result = var } } +abstract class IRGeneratedVariable extends IRVariable { + Language::AST ast; + Language::LanguageType type; + + final override Language::LanguageType getLanguageType() { result = type } + + final override Language::AST getAST() { result = ast } + + override string toString() { result = getBaseString() + getLocationString() } + + override string getUniqueId() { none() } + + final string getLocationString() { + result = ast.getLocation().getStartLine().toString() + ":" + + ast.getLocation().getStartColumn().toString() + } + + string getBaseString() { none() } +} + IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { result.getAST() = ast and result.getTag() = tag } -class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { - Language::AST ast; +class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; - Language::LanguageType type; IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - final override Language::LanguageType getLanguageType() { result = type } - - final override Language::AST getAST() { result = ast } - final override string getUniqueId() { result = "Temp: " + Construction::getTempVariableUniqueId(this) } final TempVariableTag getTag() { result = tag } - override string toString() { - result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" + - ast.getLocation().getStartColumn().toString() - } - - string getBaseString() { result = "#temp" } + override string getBaseString() { result = "#temp" } } class IRReturnVariable extends IRTempVariable { @@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable { override string getBaseString() { result = "#throw" } } + +class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { + Language::StringLiteral literal; + + IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) } + + final override predicate isReadOnly() { any() } + + final override string getUniqueId() { + result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal) + } + + override string getBaseString() { result = "#string" } + + final Language::StringLiteral getLiteral() { result = literal } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 049983c9126..9f7cf68b065 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -808,14 +808,12 @@ class FloatConstantInstruction extends ConstantInstruction { FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } } -class StringConstantInstruction extends Instruction { - Language::StringLiteral value; +class StringConstantInstruction extends VariableInstruction { + override IRStringLiteral var; - StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) } + final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } - final override string getImmediateString() { result = Language::getStringLiteralText(value) } - - final Language::StringLiteral getValue() { result = value } + final Language::StringLiteral getValue() { result = var.getLiteral() } } class BinaryInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll index 0d2627e183f..72881a7c720 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll @@ -52,6 +52,15 @@ private module Cached { ) } + cached + predicate hasStringLiteral( + Callable callable, Language::AST ast, CSharpType type, StringLiteral literal + ) { + literal = ast and + literal.getEnclosingCallable() = callable and + getTypeForPRValue(literal.getType()) = type + } + cached predicate hasModeledMemoryResult(Instruction instruction) { none() } @@ -232,8 +241,14 @@ private module Cached { cached IRVariable getInstructionVariable(Instruction instruction) { - result = getInstructionTranslatedElement(instruction) - .getInstructionVariable(getInstructionTag(instruction)) + exists(TranslatedElement element, InstructionTag tag | + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) and + ( + result = element.getInstructionVariable(tag) or + result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) + ) + ) } cached @@ -265,12 +280,6 @@ private module Cached { .getInstructionConstantValue(getInstructionTag(instruction)) } - cached - StringLiteral getInstructionStringLiteral(Instruction instruction) { - result = getInstructionTranslatedElement(instruction) - .getInstructionStringLiteral(getInstructionTag(instruction)) - } - cached CSharpType getInstructionExceptionType(Instruction instruction) { result = getInstructionTranslatedElement(instruction) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll index 1a607f82c29..e10e266b2ab 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable { abstract string toString(); + /** + * Holds if this variable's value cannot be changed within a function. Currently used for string + * literals, but could also apply to `const` global and static variables. + */ + predicate isReadOnly() { none() } + /** * Gets the type of the variable. */ @@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable { final override Language::StaticVariable getVariable() { result = var } } +abstract class IRGeneratedVariable extends IRVariable { + Language::AST ast; + Language::LanguageType type; + + final override Language::LanguageType getLanguageType() { result = type } + + final override Language::AST getAST() { result = ast } + + override string toString() { result = getBaseString() + getLocationString() } + + override string getUniqueId() { none() } + + final string getLocationString() { + result = ast.getLocation().getStartLine().toString() + ":" + + ast.getLocation().getStartColumn().toString() + } + + string getBaseString() { none() } +} + IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { result.getAST() = ast and result.getTag() = tag } -class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { - Language::AST ast; +class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable { TempVariableTag tag; - Language::LanguageType type; IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } - final override Language::LanguageType getLanguageType() { result = type } - - final override Language::AST getAST() { result = ast } - final override string getUniqueId() { result = "Temp: " + Construction::getTempVariableUniqueId(this) } final TempVariableTag getTag() { result = tag } - override string toString() { - result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" + - ast.getLocation().getStartColumn().toString() - } - - string getBaseString() { result = "#temp" } + override string getBaseString() { result = "#temp" } } class IRReturnVariable extends IRTempVariable { @@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable { override string getBaseString() { result = "#throw" } } + +class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { + Language::StringLiteral literal; + + IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) } + + final override predicate isReadOnly() { any() } + + final override string getUniqueId() { + result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal) + } + + override string getBaseString() { result = "#string" } + + final Language::StringLiteral getLiteral() { result = literal } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 049983c9126..9f7cf68b065 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -808,14 +808,12 @@ class FloatConstantInstruction extends ConstantInstruction { FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } } -class StringConstantInstruction extends Instruction { - Language::StringLiteral value; +class StringConstantInstruction extends VariableInstruction { + override IRStringLiteral var; - StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) } + final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } - final override string getImmediateString() { result = Language::getStringLiteralText(value) } - - final Language::StringLiteral getValue() { result = value } + final Language::StringLiteral getValue() { result = var.getLiteral() } } class BinaryInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 7152dec5c4a..c8362098295 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -341,11 +341,6 @@ private module Cached { result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() } - cached - Language::StringLiteral getInstructionStringLiteral(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue() - } - cached Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { result = getOldInstruction(instruction) From 51c4ef4f7f20f22d45dd90f48f24957c2d885008 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 6 Nov 2019 13:32:35 -0800 Subject: [PATCH 0946/1227] C++: add SSA IR test for array initializers --- .../ir/ssa/aliased_ssa_ir.expected | 71 +++++++++++++++++++ cpp/ql/test/library-tests/ir/ssa/ssa.cpp | 10 +++ .../ir/ssa/unaliased_ssa_ir.expected | 65 +++++++++++++++++ 3 files changed, 146 insertions(+) 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 98786207c45..7345c6a5204 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 @@ -869,3 +869,74 @@ ssa.cpp: # 207| v0_25(void) = UnmodeledUse : mu* # 207| v0_26(void) = AliasedUse : ~m0_1 # 207| v0_27(void) = ExitFunction : + +# 213| void InitArray() +# 213| Block 0 +# 213| v0_0(void) = EnterFunction : +# 213| m0_1(unknown) = AliasedDefinition : +# 213| mu0_2(unknown) = UnmodeledDefinition : +# 214| r0_3(glval) = VariableAddress[a_pad] : +# 214| r0_4(glval) = StringConstant[""] : +# 214| r0_5(char[1]) = Load : &:r0_4, ~m0_1 +# 214| m0_6(char[1]) = Store : &:r0_3, r0_5 +# 214| r0_7(unknown[31]) = Constant[0] : +# 214| r0_8(int) = Constant[1] : +# 214| r0_9(glval) = PointerAdd[1] : r0_3, r0_8 +# 214| m0_10(unknown[31]) = Store : &:r0_9, r0_7 +# 215| r0_11(glval) = VariableAddress[a_nopad] : +# 215| r0_12(glval) = StringConstant["foo"] : +# 215| r0_13(char[4]) = Load : &:r0_12, ~m0_1 +# 215| m0_14(char[4]) = Store : &:r0_11, r0_13 +# 216| r0_15(glval) = VariableAddress[a_infer] : +# 216| r0_16(glval) = StringConstant["blah"] : +# 216| r0_17(char[5]) = Load : &:r0_16, ~m0_1 +# 216| m0_18(char[5]) = Store : &:r0_15, r0_17 +# 217| r0_19(glval) = VariableAddress[b] : +# 217| m0_20(char[2]) = Uninitialized[b] : &:r0_19 +# 218| r0_21(glval) = VariableAddress[c] : +# 218| m0_22(char[2]) = Uninitialized[c] : &:r0_21 +# 218| r0_23(int) = Constant[0] : +# 218| r0_24(glval) = PointerAdd[1] : r0_21, r0_23 +# 218| r0_25(unknown[2]) = Constant[0] : +# 218| m0_26(unknown[2]) = Store : &:r0_24, r0_25 +# 219| r0_27(glval) = VariableAddress[d] : +# 219| m0_28(char[2]) = Uninitialized[d] : &:r0_27 +# 219| r0_29(int) = Constant[0] : +# 219| r0_30(glval) = PointerAdd[1] : r0_27, r0_29 +# 219| r0_31(char) = Constant[0] : +# 219| m0_32(char) = Store : &:r0_30, r0_31 +# 219| m0_33(char[2]) = Chi : total:m0_28, partial:m0_32 +# 219| r0_34(int) = Constant[1] : +# 219| r0_35(glval) = PointerAdd[1] : r0_27, r0_34 +# 219| r0_36(char) = Constant[0] : +# 219| m0_37(char) = Store : &:r0_35, r0_36 +# 219| m0_38(char[2]) = Chi : total:m0_33, partial:m0_37 +# 220| r0_39(glval) = VariableAddress[e] : +# 220| m0_40(char[2]) = Uninitialized[e] : &:r0_39 +# 220| r0_41(int) = Constant[0] : +# 220| r0_42(glval) = PointerAdd[1] : r0_39, r0_41 +# 220| r0_43(char) = Constant[0] : +# 220| m0_44(char) = Store : &:r0_42, r0_43 +# 220| m0_45(char[2]) = Chi : total:m0_40, partial:m0_44 +# 220| r0_46(int) = Constant[1] : +# 220| r0_47(glval) = PointerAdd[1] : r0_39, r0_46 +# 220| r0_48(char) = Constant[1] : +# 220| m0_49(char) = Store : &:r0_47, r0_48 +# 220| m0_50(char[2]) = Chi : total:m0_45, partial:m0_49 +# 221| r0_51(glval) = VariableAddress[f] : +# 221| m0_52(char[3]) = Uninitialized[f] : &:r0_51 +# 221| r0_53(int) = Constant[0] : +# 221| r0_54(glval) = PointerAdd[1] : r0_51, r0_53 +# 221| r0_55(char) = Constant[0] : +# 221| m0_56(char) = Store : &:r0_54, r0_55 +# 221| m0_57(char[3]) = Chi : total:m0_52, partial:m0_56 +# 221| r0_58(int) = Constant[1] : +# 221| r0_59(glval) = PointerAdd[1] : r0_51, r0_58 +# 221| r0_60(unknown[2]) = Constant[0] : +# 221| m0_61(unknown[2]) = Store : &:r0_59, r0_60 +# 221| m0_62(char[3]) = Chi : total:m0_57, partial:m0_61 +# 222| v0_63(void) = NoOp : +# 213| v0_64(void) = ReturnVoid : +# 213| v0_65(void) = UnmodeledUse : mu* +# 213| v0_66(void) = AliasedUse : ~m0_1 +# 213| v0_67(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp index 4dfb0a2f6cd..a38c66dcaf8 100644 --- a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp +++ b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp @@ -210,3 +210,13 @@ int ModeledCallTarget(int x) { return y; } +void InitArray() { + char a_pad[32] = ""; + char a_nopad[4] = "foo"; + char a_infer[] = "blah"; + char b[2]; + char c[2] = {}; + char d[2] = { 0 }; + char e[2] = { 0, 1 }; + char f[3] = { 0 }; +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 5ac06cadb55..056b0cd5ac7 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -833,3 +833,68 @@ ssa.cpp: # 207| v0_22(void) = UnmodeledUse : mu* # 207| v0_23(void) = AliasedUse : ~mu0_2 # 207| v0_24(void) = ExitFunction : + +# 213| void InitArray() +# 213| Block 0 +# 213| v0_0(void) = EnterFunction : +# 213| mu0_1(unknown) = AliasedDefinition : +# 213| mu0_2(unknown) = UnmodeledDefinition : +# 214| r0_3(glval) = VariableAddress[a_pad] : +# 214| r0_4(glval) = StringConstant[""] : +# 214| r0_5(char[1]) = Load : &:r0_4, ~mu0_2 +# 214| mu0_6(char[1]) = Store : &:r0_3, r0_5 +# 214| r0_7(unknown[31]) = Constant[0] : +# 214| r0_8(int) = Constant[1] : +# 214| r0_9(glval) = PointerAdd[1] : r0_3, r0_8 +# 214| mu0_10(unknown[31]) = Store : &:r0_9, r0_7 +# 215| r0_11(glval) = VariableAddress[a_nopad] : +# 215| r0_12(glval) = StringConstant["foo"] : +# 215| r0_13(char[4]) = Load : &:r0_12, ~mu0_2 +# 215| m0_14(char[4]) = Store : &:r0_11, r0_13 +# 216| r0_15(glval) = VariableAddress[a_infer] : +# 216| r0_16(glval) = StringConstant["blah"] : +# 216| r0_17(char[5]) = Load : &:r0_16, ~mu0_2 +# 216| m0_18(char[5]) = Store : &:r0_15, r0_17 +# 217| r0_19(glval) = VariableAddress[b] : +# 217| m0_20(char[2]) = Uninitialized[b] : &:r0_19 +# 218| r0_21(glval) = VariableAddress[c] : +# 218| mu0_22(char[2]) = Uninitialized[c] : &:r0_21 +# 218| r0_23(int) = Constant[0] : +# 218| r0_24(glval) = PointerAdd[1] : r0_21, r0_23 +# 218| r0_25(unknown[2]) = Constant[0] : +# 218| mu0_26(unknown[2]) = Store : &:r0_24, r0_25 +# 219| r0_27(glval) = VariableAddress[d] : +# 219| mu0_28(char[2]) = Uninitialized[d] : &:r0_27 +# 219| r0_29(int) = Constant[0] : +# 219| r0_30(glval) = PointerAdd[1] : r0_27, r0_29 +# 219| r0_31(char) = Constant[0] : +# 219| mu0_32(char) = Store : &:r0_30, r0_31 +# 219| r0_33(int) = Constant[1] : +# 219| r0_34(glval) = PointerAdd[1] : r0_27, r0_33 +# 219| r0_35(char) = Constant[0] : +# 219| mu0_36(char) = Store : &:r0_34, r0_35 +# 220| r0_37(glval) = VariableAddress[e] : +# 220| mu0_38(char[2]) = Uninitialized[e] : &:r0_37 +# 220| r0_39(int) = Constant[0] : +# 220| r0_40(glval) = PointerAdd[1] : r0_37, r0_39 +# 220| r0_41(char) = Constant[0] : +# 220| mu0_42(char) = Store : &:r0_40, r0_41 +# 220| r0_43(int) = Constant[1] : +# 220| r0_44(glval) = PointerAdd[1] : r0_37, r0_43 +# 220| r0_45(char) = Constant[1] : +# 220| mu0_46(char) = Store : &:r0_44, r0_45 +# 221| r0_47(glval) = VariableAddress[f] : +# 221| mu0_48(char[3]) = Uninitialized[f] : &:r0_47 +# 221| r0_49(int) = Constant[0] : +# 221| r0_50(glval) = PointerAdd[1] : r0_47, r0_49 +# 221| r0_51(char) = Constant[0] : +# 221| mu0_52(char) = Store : &:r0_50, r0_51 +# 221| r0_53(int) = Constant[1] : +# 221| r0_54(glval) = PointerAdd[1] : r0_47, r0_53 +# 221| r0_55(unknown[2]) = Constant[0] : +# 221| mu0_56(unknown[2]) = Store : &:r0_54, r0_55 +# 222| v0_57(void) = NoOp : +# 213| v0_58(void) = ReturnVoid : +# 213| v0_59(void) = UnmodeledUse : mu* +# 213| v0_60(void) = AliasedUse : ~mu0_2 +# 213| v0_61(void) = ExitFunction : From 81ad11090ed4291a1671f40b7be8cb32d258bb24 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 6 Nov 2019 10:54:43 -0800 Subject: [PATCH 0947/1227] C++: uninit instr for string literal initializers --- .../internal/TranslatedDeclarationEntry.qll | 3 +- .../test/library-tests/ir/ir/raw_ir.expected | 119 ++++++++--------- .../ir/ssa/aliased_ssa_ir.expected | 121 +++++++++--------- .../ir/ssa/unaliased_ssa_ir.expected | 119 ++++++++--------- 4 files changed, 187 insertions(+), 175 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll index 294a539ec31..c3572bd0e79 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll @@ -120,7 +120,8 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali private predicate hasUninitializedInstruction() { not exists(getInitialization()) or - getInitialization() instanceof TranslatedListInitialization + getInitialization() instanceof TranslatedListInitialization or + getInitialization() instanceof TranslatedStringLiteralInitialization } } diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 90c3061114e..b4480e1c580 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -2666,64 +2666,67 @@ ir.cpp: # 571| mu0_1(unknown) = AliasedDefinition : # 571| mu0_2(unknown) = UnmodeledDefinition : # 572| r0_3(glval) = VariableAddress[a_pad] : -# 572| r0_4(glval) = StringConstant[""] : -# 572| r0_5(char[1]) = Load : &:r0_4, ~mu0_2 -# 572| mu0_6(char[1]) = Store : &:r0_3, r0_5 -# 572| r0_7(unknown[31]) = Constant[0] : -# 572| r0_8(int) = Constant[1] : -# 572| r0_9(glval) = PointerAdd[1] : r0_3, r0_8 -# 572| mu0_10(unknown[31]) = Store : &:r0_9, r0_7 -# 573| r0_11(glval) = VariableAddress[a_nopad] : -# 573| r0_12(glval) = StringConstant["foo"] : -# 573| r0_13(char[4]) = Load : &:r0_12, ~mu0_2 -# 573| mu0_14(char[4]) = Store : &:r0_11, r0_13 -# 574| r0_15(glval) = VariableAddress[a_infer] : -# 574| r0_16(glval) = StringConstant["blah"] : -# 574| r0_17(char[5]) = Load : &:r0_16, ~mu0_2 -# 574| mu0_18(char[5]) = Store : &:r0_15, r0_17 -# 575| r0_19(glval) = VariableAddress[b] : -# 575| mu0_20(char[2]) = Uninitialized[b] : &:r0_19 -# 576| r0_21(glval) = VariableAddress[c] : -# 576| mu0_22(char[2]) = Uninitialized[c] : &:r0_21 -# 576| r0_23(int) = Constant[0] : -# 576| r0_24(glval) = PointerAdd[1] : r0_21, r0_23 -# 576| r0_25(unknown[2]) = Constant[0] : -# 576| mu0_26(unknown[2]) = Store : &:r0_24, r0_25 -# 577| r0_27(glval) = VariableAddress[d] : -# 577| mu0_28(char[2]) = Uninitialized[d] : &:r0_27 -# 577| r0_29(int) = Constant[0] : -# 577| r0_30(glval) = PointerAdd[1] : r0_27, r0_29 -# 577| r0_31(char) = Constant[0] : -# 577| mu0_32(char) = Store : &:r0_30, r0_31 -# 577| r0_33(int) = Constant[1] : -# 577| r0_34(glval) = PointerAdd[1] : r0_27, r0_33 -# 577| r0_35(char) = Constant[0] : -# 577| mu0_36(char) = Store : &:r0_34, r0_35 -# 578| r0_37(glval) = VariableAddress[e] : -# 578| mu0_38(char[2]) = Uninitialized[e] : &:r0_37 -# 578| r0_39(int) = Constant[0] : -# 578| r0_40(glval) = PointerAdd[1] : r0_37, r0_39 -# 578| r0_41(char) = Constant[0] : -# 578| mu0_42(char) = Store : &:r0_40, r0_41 -# 578| r0_43(int) = Constant[1] : -# 578| r0_44(glval) = PointerAdd[1] : r0_37, r0_43 -# 578| r0_45(char) = Constant[1] : -# 578| mu0_46(char) = Store : &:r0_44, r0_45 -# 579| r0_47(glval) = VariableAddress[f] : -# 579| mu0_48(char[3]) = Uninitialized[f] : &:r0_47 -# 579| r0_49(int) = Constant[0] : -# 579| r0_50(glval) = PointerAdd[1] : r0_47, r0_49 -# 579| r0_51(char) = Constant[0] : -# 579| mu0_52(char) = Store : &:r0_50, r0_51 -# 579| r0_53(int) = Constant[1] : -# 579| r0_54(glval) = PointerAdd[1] : r0_47, r0_53 -# 579| r0_55(unknown[2]) = Constant[0] : -# 579| mu0_56(unknown[2]) = Store : &:r0_54, r0_55 -# 580| v0_57(void) = NoOp : -# 571| v0_58(void) = ReturnVoid : -# 571| v0_59(void) = UnmodeledUse : mu* -# 571| v0_60(void) = AliasedUse : ~mu0_2 -# 571| v0_61(void) = ExitFunction : +# 572| mu0_4(char[32]) = Uninitialized[a_pad] : &:r0_3 +# 572| r0_5(glval) = StringConstant[""] : +# 572| r0_6(char[1]) = Load : &:r0_5, ~mu0_2 +# 572| mu0_7(char[1]) = Store : &:r0_3, r0_6 +# 572| r0_8(unknown[31]) = Constant[0] : +# 572| r0_9(int) = Constant[1] : +# 572| r0_10(glval) = PointerAdd[1] : r0_3, r0_9 +# 572| mu0_11(unknown[31]) = Store : &:r0_10, r0_8 +# 573| r0_12(glval) = VariableAddress[a_nopad] : +# 573| mu0_13(char[4]) = Uninitialized[a_nopad] : &:r0_12 +# 573| r0_14(glval) = StringConstant["foo"] : +# 573| r0_15(char[4]) = Load : &:r0_14, ~mu0_2 +# 573| mu0_16(char[4]) = Store : &:r0_12, r0_15 +# 574| r0_17(glval) = VariableAddress[a_infer] : +# 574| mu0_18(char[5]) = Uninitialized[a_infer] : &:r0_17 +# 574| r0_19(glval) = StringConstant["blah"] : +# 574| r0_20(char[5]) = Load : &:r0_19, ~mu0_2 +# 574| mu0_21(char[5]) = Store : &:r0_17, r0_20 +# 575| r0_22(glval) = VariableAddress[b] : +# 575| mu0_23(char[2]) = Uninitialized[b] : &:r0_22 +# 576| r0_24(glval) = VariableAddress[c] : +# 576| mu0_25(char[2]) = Uninitialized[c] : &:r0_24 +# 576| r0_26(int) = Constant[0] : +# 576| r0_27(glval) = PointerAdd[1] : r0_24, r0_26 +# 576| r0_28(unknown[2]) = Constant[0] : +# 576| mu0_29(unknown[2]) = Store : &:r0_27, r0_28 +# 577| r0_30(glval) = VariableAddress[d] : +# 577| mu0_31(char[2]) = Uninitialized[d] : &:r0_30 +# 577| r0_32(int) = Constant[0] : +# 577| r0_33(glval) = PointerAdd[1] : r0_30, r0_32 +# 577| r0_34(char) = Constant[0] : +# 577| mu0_35(char) = Store : &:r0_33, r0_34 +# 577| r0_36(int) = Constant[1] : +# 577| r0_37(glval) = PointerAdd[1] : r0_30, r0_36 +# 577| r0_38(char) = Constant[0] : +# 577| mu0_39(char) = Store : &:r0_37, r0_38 +# 578| r0_40(glval) = VariableAddress[e] : +# 578| mu0_41(char[2]) = Uninitialized[e] : &:r0_40 +# 578| r0_42(int) = Constant[0] : +# 578| r0_43(glval) = PointerAdd[1] : r0_40, r0_42 +# 578| r0_44(char) = Constant[0] : +# 578| mu0_45(char) = Store : &:r0_43, r0_44 +# 578| r0_46(int) = Constant[1] : +# 578| r0_47(glval) = PointerAdd[1] : r0_40, r0_46 +# 578| r0_48(char) = Constant[1] : +# 578| mu0_49(char) = Store : &:r0_47, r0_48 +# 579| r0_50(glval) = VariableAddress[f] : +# 579| mu0_51(char[3]) = Uninitialized[f] : &:r0_50 +# 579| r0_52(int) = Constant[0] : +# 579| r0_53(glval) = PointerAdd[1] : r0_50, r0_52 +# 579| r0_54(char) = Constant[0] : +# 579| mu0_55(char) = Store : &:r0_53, r0_54 +# 579| r0_56(int) = Constant[1] : +# 579| r0_57(glval) = PointerAdd[1] : r0_50, r0_56 +# 579| r0_58(unknown[2]) = Constant[0] : +# 579| mu0_59(unknown[2]) = Store : &:r0_57, r0_58 +# 580| v0_60(void) = NoOp : +# 571| v0_61(void) = ReturnVoid : +# 571| v0_62(void) = UnmodeledUse : mu* +# 571| v0_63(void) = AliasedUse : ~mu0_2 +# 571| v0_64(void) = ExitFunction : # 584| void VarArgs() # 584| Block 0 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 7345c6a5204..bc2bea75e11 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 @@ -876,67 +876,72 @@ ssa.cpp: # 213| m0_1(unknown) = AliasedDefinition : # 213| mu0_2(unknown) = UnmodeledDefinition : # 214| r0_3(glval) = VariableAddress[a_pad] : -# 214| r0_4(glval) = StringConstant[""] : -# 214| r0_5(char[1]) = Load : &:r0_4, ~m0_1 -# 214| m0_6(char[1]) = Store : &:r0_3, r0_5 -# 214| r0_7(unknown[31]) = Constant[0] : -# 214| r0_8(int) = Constant[1] : -# 214| r0_9(glval) = PointerAdd[1] : r0_3, r0_8 -# 214| m0_10(unknown[31]) = Store : &:r0_9, r0_7 -# 215| r0_11(glval) = VariableAddress[a_nopad] : -# 215| r0_12(glval) = StringConstant["foo"] : -# 215| r0_13(char[4]) = Load : &:r0_12, ~m0_1 -# 215| m0_14(char[4]) = Store : &:r0_11, r0_13 -# 216| r0_15(glval) = VariableAddress[a_infer] : -# 216| r0_16(glval) = StringConstant["blah"] : -# 216| r0_17(char[5]) = Load : &:r0_16, ~m0_1 -# 216| m0_18(char[5]) = Store : &:r0_15, r0_17 -# 217| r0_19(glval) = VariableAddress[b] : -# 217| m0_20(char[2]) = Uninitialized[b] : &:r0_19 -# 218| r0_21(glval) = VariableAddress[c] : -# 218| m0_22(char[2]) = Uninitialized[c] : &:r0_21 -# 218| r0_23(int) = Constant[0] : -# 218| r0_24(glval) = PointerAdd[1] : r0_21, r0_23 -# 218| r0_25(unknown[2]) = Constant[0] : -# 218| m0_26(unknown[2]) = Store : &:r0_24, r0_25 -# 219| r0_27(glval) = VariableAddress[d] : -# 219| m0_28(char[2]) = Uninitialized[d] : &:r0_27 -# 219| r0_29(int) = Constant[0] : -# 219| r0_30(glval) = PointerAdd[1] : r0_27, r0_29 -# 219| r0_31(char) = Constant[0] : -# 219| m0_32(char) = Store : &:r0_30, r0_31 -# 219| m0_33(char[2]) = Chi : total:m0_28, partial:m0_32 -# 219| r0_34(int) = Constant[1] : -# 219| r0_35(glval) = PointerAdd[1] : r0_27, r0_34 +# 214| m0_4(char[32]) = Uninitialized[a_pad] : &:r0_3 +# 214| r0_5(glval) = StringConstant[""] : +# 214| r0_6(char[1]) = Load : &:r0_5, ~m0_1 +# 214| m0_7(char[1]) = Store : &:r0_3, r0_6 +# 214| m0_8(char[32]) = Chi : total:m0_4, partial:m0_7 +# 214| r0_9(unknown[31]) = Constant[0] : +# 214| r0_10(int) = Constant[1] : +# 214| r0_11(glval) = PointerAdd[1] : r0_3, r0_10 +# 214| m0_12(unknown[31]) = Store : &:r0_11, r0_9 +# 214| m0_13(char[32]) = Chi : total:m0_8, partial:m0_12 +# 215| r0_14(glval) = VariableAddress[a_nopad] : +# 215| m0_15(char[4]) = Uninitialized[a_nopad] : &:r0_14 +# 215| r0_16(glval) = StringConstant["foo"] : +# 215| r0_17(char[4]) = Load : &:r0_16, ~m0_1 +# 215| m0_18(char[4]) = Store : &:r0_14, r0_17 +# 216| r0_19(glval) = VariableAddress[a_infer] : +# 216| m0_20(char[5]) = Uninitialized[a_infer] : &:r0_19 +# 216| r0_21(glval) = StringConstant["blah"] : +# 216| r0_22(char[5]) = Load : &:r0_21, ~m0_1 +# 216| m0_23(char[5]) = Store : &:r0_19, r0_22 +# 217| r0_24(glval) = VariableAddress[b] : +# 217| m0_25(char[2]) = Uninitialized[b] : &:r0_24 +# 218| r0_26(glval) = VariableAddress[c] : +# 218| m0_27(char[2]) = Uninitialized[c] : &:r0_26 +# 218| r0_28(int) = Constant[0] : +# 218| r0_29(glval) = PointerAdd[1] : r0_26, r0_28 +# 218| r0_30(unknown[2]) = Constant[0] : +# 218| m0_31(unknown[2]) = Store : &:r0_29, r0_30 +# 219| r0_32(glval) = VariableAddress[d] : +# 219| m0_33(char[2]) = Uninitialized[d] : &:r0_32 +# 219| r0_34(int) = Constant[0] : +# 219| r0_35(glval) = PointerAdd[1] : r0_32, r0_34 # 219| r0_36(char) = Constant[0] : # 219| m0_37(char) = Store : &:r0_35, r0_36 # 219| m0_38(char[2]) = Chi : total:m0_33, partial:m0_37 -# 220| r0_39(glval) = VariableAddress[e] : -# 220| m0_40(char[2]) = Uninitialized[e] : &:r0_39 -# 220| r0_41(int) = Constant[0] : -# 220| r0_42(glval) = PointerAdd[1] : r0_39, r0_41 -# 220| r0_43(char) = Constant[0] : -# 220| m0_44(char) = Store : &:r0_42, r0_43 -# 220| m0_45(char[2]) = Chi : total:m0_40, partial:m0_44 -# 220| r0_46(int) = Constant[1] : -# 220| r0_47(glval) = PointerAdd[1] : r0_39, r0_46 -# 220| r0_48(char) = Constant[1] : +# 219| r0_39(int) = Constant[1] : +# 219| r0_40(glval) = PointerAdd[1] : r0_32, r0_39 +# 219| r0_41(char) = Constant[0] : +# 219| m0_42(char) = Store : &:r0_40, r0_41 +# 219| m0_43(char[2]) = Chi : total:m0_38, partial:m0_42 +# 220| r0_44(glval) = VariableAddress[e] : +# 220| m0_45(char[2]) = Uninitialized[e] : &:r0_44 +# 220| r0_46(int) = Constant[0] : +# 220| r0_47(glval) = PointerAdd[1] : r0_44, r0_46 +# 220| r0_48(char) = Constant[0] : # 220| m0_49(char) = Store : &:r0_47, r0_48 # 220| m0_50(char[2]) = Chi : total:m0_45, partial:m0_49 -# 221| r0_51(glval) = VariableAddress[f] : -# 221| m0_52(char[3]) = Uninitialized[f] : &:r0_51 -# 221| r0_53(int) = Constant[0] : -# 221| r0_54(glval) = PointerAdd[1] : r0_51, r0_53 -# 221| r0_55(char) = Constant[0] : -# 221| m0_56(char) = Store : &:r0_54, r0_55 -# 221| m0_57(char[3]) = Chi : total:m0_52, partial:m0_56 -# 221| r0_58(int) = Constant[1] : -# 221| r0_59(glval) = PointerAdd[1] : r0_51, r0_58 -# 221| r0_60(unknown[2]) = Constant[0] : -# 221| m0_61(unknown[2]) = Store : &:r0_59, r0_60 +# 220| r0_51(int) = Constant[1] : +# 220| r0_52(glval) = PointerAdd[1] : r0_44, r0_51 +# 220| r0_53(char) = Constant[1] : +# 220| m0_54(char) = Store : &:r0_52, r0_53 +# 220| m0_55(char[2]) = Chi : total:m0_50, partial:m0_54 +# 221| r0_56(glval) = VariableAddress[f] : +# 221| m0_57(char[3]) = Uninitialized[f] : &:r0_56 +# 221| r0_58(int) = Constant[0] : +# 221| r0_59(glval) = PointerAdd[1] : r0_56, r0_58 +# 221| r0_60(char) = Constant[0] : +# 221| m0_61(char) = Store : &:r0_59, r0_60 # 221| m0_62(char[3]) = Chi : total:m0_57, partial:m0_61 -# 222| v0_63(void) = NoOp : -# 213| v0_64(void) = ReturnVoid : -# 213| v0_65(void) = UnmodeledUse : mu* -# 213| v0_66(void) = AliasedUse : ~m0_1 -# 213| v0_67(void) = ExitFunction : +# 221| r0_63(int) = Constant[1] : +# 221| r0_64(glval) = PointerAdd[1] : r0_56, r0_63 +# 221| r0_65(unknown[2]) = Constant[0] : +# 221| m0_66(unknown[2]) = Store : &:r0_64, r0_65 +# 221| m0_67(char[3]) = Chi : total:m0_62, partial:m0_66 +# 222| v0_68(void) = NoOp : +# 213| v0_69(void) = ReturnVoid : +# 213| v0_70(void) = UnmodeledUse : mu* +# 213| v0_71(void) = AliasedUse : ~m0_1 +# 213| v0_72(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 056b0cd5ac7..93f27b13f02 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -840,61 +840,64 @@ ssa.cpp: # 213| mu0_1(unknown) = AliasedDefinition : # 213| mu0_2(unknown) = UnmodeledDefinition : # 214| r0_3(glval) = VariableAddress[a_pad] : -# 214| r0_4(glval) = StringConstant[""] : -# 214| r0_5(char[1]) = Load : &:r0_4, ~mu0_2 -# 214| mu0_6(char[1]) = Store : &:r0_3, r0_5 -# 214| r0_7(unknown[31]) = Constant[0] : -# 214| r0_8(int) = Constant[1] : -# 214| r0_9(glval) = PointerAdd[1] : r0_3, r0_8 -# 214| mu0_10(unknown[31]) = Store : &:r0_9, r0_7 -# 215| r0_11(glval) = VariableAddress[a_nopad] : -# 215| r0_12(glval) = StringConstant["foo"] : -# 215| r0_13(char[4]) = Load : &:r0_12, ~mu0_2 -# 215| m0_14(char[4]) = Store : &:r0_11, r0_13 -# 216| r0_15(glval) = VariableAddress[a_infer] : -# 216| r0_16(glval) = StringConstant["blah"] : -# 216| r0_17(char[5]) = Load : &:r0_16, ~mu0_2 -# 216| m0_18(char[5]) = Store : &:r0_15, r0_17 -# 217| r0_19(glval) = VariableAddress[b] : -# 217| m0_20(char[2]) = Uninitialized[b] : &:r0_19 -# 218| r0_21(glval) = VariableAddress[c] : -# 218| mu0_22(char[2]) = Uninitialized[c] : &:r0_21 -# 218| r0_23(int) = Constant[0] : -# 218| r0_24(glval) = PointerAdd[1] : r0_21, r0_23 -# 218| r0_25(unknown[2]) = Constant[0] : -# 218| mu0_26(unknown[2]) = Store : &:r0_24, r0_25 -# 219| r0_27(glval) = VariableAddress[d] : -# 219| mu0_28(char[2]) = Uninitialized[d] : &:r0_27 -# 219| r0_29(int) = Constant[0] : -# 219| r0_30(glval) = PointerAdd[1] : r0_27, r0_29 -# 219| r0_31(char) = Constant[0] : -# 219| mu0_32(char) = Store : &:r0_30, r0_31 -# 219| r0_33(int) = Constant[1] : -# 219| r0_34(glval) = PointerAdd[1] : r0_27, r0_33 -# 219| r0_35(char) = Constant[0] : -# 219| mu0_36(char) = Store : &:r0_34, r0_35 -# 220| r0_37(glval) = VariableAddress[e] : -# 220| mu0_38(char[2]) = Uninitialized[e] : &:r0_37 -# 220| r0_39(int) = Constant[0] : -# 220| r0_40(glval) = PointerAdd[1] : r0_37, r0_39 -# 220| r0_41(char) = Constant[0] : -# 220| mu0_42(char) = Store : &:r0_40, r0_41 -# 220| r0_43(int) = Constant[1] : -# 220| r0_44(glval) = PointerAdd[1] : r0_37, r0_43 -# 220| r0_45(char) = Constant[1] : -# 220| mu0_46(char) = Store : &:r0_44, r0_45 -# 221| r0_47(glval) = VariableAddress[f] : -# 221| mu0_48(char[3]) = Uninitialized[f] : &:r0_47 -# 221| r0_49(int) = Constant[0] : -# 221| r0_50(glval) = PointerAdd[1] : r0_47, r0_49 -# 221| r0_51(char) = Constant[0] : -# 221| mu0_52(char) = Store : &:r0_50, r0_51 -# 221| r0_53(int) = Constant[1] : -# 221| r0_54(glval) = PointerAdd[1] : r0_47, r0_53 -# 221| r0_55(unknown[2]) = Constant[0] : -# 221| mu0_56(unknown[2]) = Store : &:r0_54, r0_55 -# 222| v0_57(void) = NoOp : -# 213| v0_58(void) = ReturnVoid : -# 213| v0_59(void) = UnmodeledUse : mu* -# 213| v0_60(void) = AliasedUse : ~mu0_2 -# 213| v0_61(void) = ExitFunction : +# 214| mu0_4(char[32]) = Uninitialized[a_pad] : &:r0_3 +# 214| r0_5(glval) = StringConstant[""] : +# 214| r0_6(char[1]) = Load : &:r0_5, ~mu0_2 +# 214| mu0_7(char[1]) = Store : &:r0_3, r0_6 +# 214| r0_8(unknown[31]) = Constant[0] : +# 214| r0_9(int) = Constant[1] : +# 214| r0_10(glval) = PointerAdd[1] : r0_3, r0_9 +# 214| mu0_11(unknown[31]) = Store : &:r0_10, r0_8 +# 215| r0_12(glval) = VariableAddress[a_nopad] : +# 215| m0_13(char[4]) = Uninitialized[a_nopad] : &:r0_12 +# 215| r0_14(glval) = StringConstant["foo"] : +# 215| r0_15(char[4]) = Load : &:r0_14, ~mu0_2 +# 215| m0_16(char[4]) = Store : &:r0_12, r0_15 +# 216| r0_17(glval) = VariableAddress[a_infer] : +# 216| m0_18(char[5]) = Uninitialized[a_infer] : &:r0_17 +# 216| r0_19(glval) = StringConstant["blah"] : +# 216| r0_20(char[5]) = Load : &:r0_19, ~mu0_2 +# 216| m0_21(char[5]) = Store : &:r0_17, r0_20 +# 217| r0_22(glval) = VariableAddress[b] : +# 217| m0_23(char[2]) = Uninitialized[b] : &:r0_22 +# 218| r0_24(glval) = VariableAddress[c] : +# 218| mu0_25(char[2]) = Uninitialized[c] : &:r0_24 +# 218| r0_26(int) = Constant[0] : +# 218| r0_27(glval) = PointerAdd[1] : r0_24, r0_26 +# 218| r0_28(unknown[2]) = Constant[0] : +# 218| mu0_29(unknown[2]) = Store : &:r0_27, r0_28 +# 219| r0_30(glval) = VariableAddress[d] : +# 219| mu0_31(char[2]) = Uninitialized[d] : &:r0_30 +# 219| r0_32(int) = Constant[0] : +# 219| r0_33(glval) = PointerAdd[1] : r0_30, r0_32 +# 219| r0_34(char) = Constant[0] : +# 219| mu0_35(char) = Store : &:r0_33, r0_34 +# 219| r0_36(int) = Constant[1] : +# 219| r0_37(glval) = PointerAdd[1] : r0_30, r0_36 +# 219| r0_38(char) = Constant[0] : +# 219| mu0_39(char) = Store : &:r0_37, r0_38 +# 220| r0_40(glval) = VariableAddress[e] : +# 220| mu0_41(char[2]) = Uninitialized[e] : &:r0_40 +# 220| r0_42(int) = Constant[0] : +# 220| r0_43(glval) = PointerAdd[1] : r0_40, r0_42 +# 220| r0_44(char) = Constant[0] : +# 220| mu0_45(char) = Store : &:r0_43, r0_44 +# 220| r0_46(int) = Constant[1] : +# 220| r0_47(glval) = PointerAdd[1] : r0_40, r0_46 +# 220| r0_48(char) = Constant[1] : +# 220| mu0_49(char) = Store : &:r0_47, r0_48 +# 221| r0_50(glval) = VariableAddress[f] : +# 221| mu0_51(char[3]) = Uninitialized[f] : &:r0_50 +# 221| r0_52(int) = Constant[0] : +# 221| r0_53(glval) = PointerAdd[1] : r0_50, r0_52 +# 221| r0_54(char) = Constant[0] : +# 221| mu0_55(char) = Store : &:r0_53, r0_54 +# 221| r0_56(int) = Constant[1] : +# 221| r0_57(glval) = PointerAdd[1] : r0_50, r0_56 +# 221| r0_58(unknown[2]) = Constant[0] : +# 221| mu0_59(unknown[2]) = Store : &:r0_57, r0_58 +# 222| v0_60(void) = NoOp : +# 213| v0_61(void) = ReturnVoid : +# 213| v0_62(void) = UnmodeledUse : mu* +# 213| v0_63(void) = AliasedUse : ~mu0_2 +# 213| v0_64(void) = ExitFunction : From 0040c9fb4c1defdc206d9558b4e87925f8ca2ce0 Mon Sep 17 00:00:00 2001 From: Sauyon Lee Date: Wed, 6 Nov 2019 05:42:59 -0800 Subject: [PATCH 0948/1227] Update links to OWASP cheat sheet --- cpp/ql/src/Security/CWE/CWE-079/CgiXss.qhelp | 2 +- .../src/Security Features/CWE-079/XSS.qhelp | 2 +- .../CWE-090/LDAPInjection.qhelp | 2 +- .../CWE-451/MissingXFrameOptions.qhelp | 2 +- .../CWE-601/UrlRedirect.qhelp | 2 +- .../CWE-611/UseXmlSecureResolver.qhelp | 2 +- java/ql/src/Security/CWE/CWE-079/XSS.qhelp | 2 +- .../src/Security/CWE/CWE-089/SqlTainted.qhelp | 2 +- .../Security/CWE/CWE-089/SqlUnescaped.qhelp | 2 +- .../src/Security/CWE/CWE-319/HttpsUrls.qhelp | 2 +- java/ql/src/Security/CWE/CWE-319/UseSSL.qhelp | 2 +- .../CWE/CWE-319/UseSSLSocketFactories.qhelp | 2 +- .../CWE/CWE-502/UnsafeDeserialization.qhelp | 2 +- java/ql/src/Security/CWE/CWE-611/XXE.qhelp | 2 +- .../semmle/code/java/security/XmlParsers.qll | 24 +++++++++---------- .../CWE-020/IncompleteHostnameRegExp.qhelp | 2 +- .../IncompleteUrlSubstringSanitization.qhelp | 2 +- .../CWE-020/MissingRegExpAnchor.qhelp | 2 +- .../src/Security/CWE-079/ReflectedXss.qhelp | 2 +- .../ql/src/Security/CWE-079/StoredXss.qhelp | 2 +- javascript/ql/src/Security/CWE-079/Xss.qhelp | 4 ++-- .../CWE-327/BrokenCryptoAlgorithm.qhelp | 2 +- .../CWE-451/MissingXFrameOptions.qhelp | 2 +- .../CWE-502/UnsafeDeserialization.qhelp | 2 +- .../CWE-601/ClientSideUrlRedirect.qhelp | 2 +- .../CWE-601/ServerSideUrlRedirect.qhelp | 2 +- .../CWE-770/MissingRateLimiting.qhelp | 2 +- .../CWE-916/InsufficientPasswordHash.qhelp | 2 +- .../CWE-020/IncompleteHostnameRegExp.qhelp | 2 +- .../IncompleteUrlSubstringSanitization.qhelp | 2 +- .../CWE-079/Jinja2WithoutEscaping.qhelp | 2 +- .../src/Security/CWE-079/ReflectedXss.qhelp | 2 +- .../src/Security/CWE-089/SqlInjection.qhelp | 2 +- .../CWE-327/BrokenCryptoAlgorithm.qhelp | 2 +- .../CWE-502/UnsafeDeserialization.qhelp | 2 +- .../ql/src/Security/CWE-601/UrlRedirect.qhelp | 2 +- 36 files changed, 48 insertions(+), 48 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.qhelp b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.qhelp index ccd297c3b36..4ad7a40fed6 100644 --- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.qhelp +++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.qhelp @@ -34,7 +34,7 @@ characters before writing to the HTML page.

  • OWASP: -XSS +XSS (Cross Site Scripting) Prevention Cheat Sheet.
  • diff --git a/csharp/ql/src/Security Features/CWE-079/XSS.qhelp b/csharp/ql/src/Security Features/CWE-079/XSS.qhelp index 9a71290694d..409be1030e7 100644 --- a/csharp/ql/src/Security Features/CWE-079/XSS.qhelp +++ b/csharp/ql/src/Security Features/CWE-079/XSS.qhelp @@ -29,7 +29,7 @@ leaving the website vulnerable to cross-site scripting.

  • OWASP: -XSS +XSS (Cross Site Scripting) Prevention Cheat Sheet.
  • diff --git a/csharp/ql/src/Security Features/CWE-090/LDAPInjection.qhelp b/csharp/ql/src/Security Features/CWE-090/LDAPInjection.qhelp index 118e91ed4d9..04f01720ce6 100644 --- a/csharp/ql/src/Security Features/CWE-090/LDAPInjection.qhelp +++ b/csharp/ql/src/Security Features/CWE-090/LDAPInjection.qhelp @@ -33,7 +33,7 @@ the query cannot be changed by a malicious user.

    -
  • OWASP: LDAP Injection Prevention Cheat Sheet.
  • +
  • OWASP: LDAP Injection Prevention Cheat Sheet.
  • OWASP: Preventing LDAP Injection in Java.
  • AntiXSS doc: LdapFilterEncode.
  • AntiXSS doc: LdapDistinguishedNameEncode.
  • diff --git a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.qhelp b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.qhelp index 7df415aff5b..6d5d298c8e4 100644 --- a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.qhelp +++ b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.qhelp @@ -51,7 +51,7 @@ This next example shows how to specify the X-Frame-Options header w
  • OWASP: -Clickjacking Defense Cheat Sheet. +Clickjacking Defense Cheat Sheet.
  • Mozilla: diff --git a/csharp/ql/src/Security Features/CWE-601/UrlRedirect.qhelp b/csharp/ql/src/Security Features/CWE-601/UrlRedirect.qhelp index 989796b6738..3cf3cdaba6e 100644 --- a/csharp/ql/src/Security Features/CWE-601/UrlRedirect.qhelp +++ b/csharp/ql/src/Security Features/CWE-601/UrlRedirect.qhelp @@ -32,7 +32,7 @@ It also shows how to remedy the problem by validating the user input against a k
  • OWASP: -XSS +XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • diff --git a/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.qhelp b/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.qhelp index 2e8e4fcf272..11b1136db4d 100644 --- a/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.qhelp +++ b/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.qhelp @@ -38,7 +38,7 @@ The solution is to set the DtdProcessing property to DtdProce
  • OWASP: -XML External Entity (XXE) Prevention Cheat Sheet. +XML External Entity (XXE) Prevention Cheat Sheet.
  • Microsoft Docs: System.XML: Security considerations. diff --git a/java/ql/src/Security/CWE/CWE-079/XSS.qhelp b/java/ql/src/Security/CWE/CWE-079/XSS.qhelp index 85bdfb130fd..428b44c8db9 100644 --- a/java/ql/src/Security/CWE/CWE-079/XSS.qhelp +++ b/java/ql/src/Security/CWE/CWE-079/XSS.qhelp @@ -29,7 +29,7 @@ leaving the website vulnerable to cross-site scripting.

  • OWASP: -XSS +XSS (Cross Site Scripting) Prevention Cheat Sheet.
  • diff --git a/java/ql/src/Security/CWE/CWE-089/SqlTainted.qhelp b/java/ql/src/Security/CWE/CWE-089/SqlTainted.qhelp index cab60173a62..f1ba450d4a0 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlTainted.qhelp +++ b/java/ql/src/Security/CWE/CWE-089/SqlTainted.qhelp @@ -67,7 +67,7 @@ in the environment variable or user-supplied value are not given any special tre
  • OWASP: -SQL +SQL Injection Prevention Cheat Sheet.
  • The CERT Oracle Secure Coding Standard for Java: diff --git a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.qhelp b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.qhelp index 7415235610c..e469415d683 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.qhelp +++ b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.qhelp @@ -39,7 +39,7 @@ treatment.

  • OWASP: -SQL +SQL Injection Prevention Cheat Sheet.
  • The CERT Oracle Secure Coding Standard for Java: diff --git a/java/ql/src/Security/CWE/CWE-319/HttpsUrls.qhelp b/java/ql/src/Security/CWE/CWE-319/HttpsUrls.qhelp index 8b8b0eff847..2cfdca624fb 100644 --- a/java/ql/src/Security/CWE/CWE-319/HttpsUrls.qhelp +++ b/java/ql/src/Security/CWE/CWE-319/HttpsUrls.qhelp @@ -37,7 +37,7 @@ connection is a secure SSL connection.

    Class HttpsURLConnection.
  • OWASP: -Transport Layer Protection Cheat Sheet. +Transport Layer Protection Cheat Sheet.
  • diff --git a/java/ql/src/Security/CWE/CWE-319/UseSSL.qhelp b/java/ql/src/Security/CWE/CWE-319/UseSSL.qhelp index 5856086330f..cec4937c8f7 100644 --- a/java/ql/src/Security/CWE/CWE-319/UseSSL.qhelp +++ b/java/ql/src/Security/CWE/CWE-319/UseSSL.qhelp @@ -38,7 +38,7 @@ Class HttpsURLConnection. Class SSLSocket.
  • OWASP: -Transport Layer Protection Cheat Sheet. +Transport Layer Protection Cheat Sheet.
  • diff --git a/java/ql/src/Security/CWE/CWE-319/UseSSLSocketFactories.qhelp b/java/ql/src/Security/CWE/CWE-319/UseSSLSocketFactories.qhelp index 56e9be97345..bf0dbc0bcac 100644 --- a/java/ql/src/Security/CWE/CWE-319/UseSSLSocketFactories.qhelp +++ b/java/ql/src/Security/CWE/CWE-319/UseSSLSocketFactories.qhelp @@ -33,7 +33,7 @@ uses explicit SSL factories, which are preferable.

    Class SSLSocketFactory.
  • OWASP: -Transport Layer Protection Cheat Sheet. +Transport Layer Protection Cheat Sheet.
  • diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp index 4fb0ad88b45..61b50a986e3 100644 --- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp +++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp @@ -58,7 +58,7 @@ OWASP vulnerability description:
  • OWASP guidance on deserializing objects: -Deserialization Cheat Sheet. +Deserialization Cheat Sheet.
  • Talks by Chris Frohoff & Gabriel Lawrence: diff --git a/java/ql/src/Security/CWE/CWE-611/XXE.qhelp b/java/ql/src/Security/CWE/CWE-611/XXE.qhelp index 75c5a2d4d7a..93d420f7495 100644 --- a/java/ql/src/Security/CWE/CWE-611/XXE.qhelp +++ b/java/ql/src/Security/CWE/CWE-611/XXE.qhelp @@ -52,7 +52,7 @@ OWASP vulnerability description:
  • OWASP guidance on parsing xml files: -XXE Prevention Cheat Sheet. +XXE Prevention Cheat Sheet.
  • Paper by Timothy Morgen: diff --git a/java/ql/src/semmle/code/java/security/XmlParsers.qll b/java/ql/src/semmle/code/java/security/XmlParsers.qll index 37a72f8128e..1f582489497 100644 --- a/java/ql/src/semmle/code/java/security/XmlParsers.qll +++ b/java/ql/src/semmle/code/java/security/XmlParsers.qll @@ -49,7 +49,7 @@ abstract class ParserConfig extends MethodAccess { } /* - * https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#DocumentBuilder + * https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxp-documentbuilderfactory-saxparserfactory-and-dom4j */ /** The class `javax.xml.parsers.DocumentBuilderFactory`. */ @@ -227,7 +227,7 @@ class SafeDocumentBuilder extends DocumentBuilderConstruction { } /* - * https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#XMLInputFactory_.28a_StAX_parser.29 + * https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#xmlinputfactory-a-stax-parser */ /** The class `javax.xml.stream.XMLInputFactory`. */ @@ -353,7 +353,7 @@ class SafeXmlInputFactory extends VarAccess { } /* - * https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#SAXBuilder + * https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#saxbuilder */ /** @@ -429,7 +429,7 @@ class SafeSAXBuilder extends VarAccess { /* * The case in - * https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#Unmarshaller + * https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller * will be split into two, one covers a SAXParser as a sink, the other the SAXSource as a sink. */ @@ -545,7 +545,7 @@ class SafeSAXParser extends MethodAccess { } } -/* SAXReader: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#SAXReader */ +/* SAXReader: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#saxreader */ /** * The class `org.dom4j.io.SAXReader`. */ @@ -621,7 +621,7 @@ class SafeSAXReader extends VarAccess { } } -/* https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#XMLReader */ +/* https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#xmlreader */ /** The class `org.xml.sax.XMLReader`. */ class XMLReader extends RefType { XMLReader() { this.hasQualifiedName("org.xml.sax", "XMLReader") } @@ -756,7 +756,7 @@ class CreatedSafeXMLReader extends Call { /* * SAXSource in - * https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#Unmarshaller + * https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller */ /** The class `javax.xml.transform.sax.SAXSource` */ @@ -811,7 +811,7 @@ class SafeSAXSource extends Expr { } } -/* Transformer: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#TransformerFactory */ +/* Transformer: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#transformerfactory */ /** An access to a method use for configuring a transformer or schema. */ abstract class TransformerConfig extends MethodAccess { /** Holds if the configuration is disabled */ @@ -975,7 +975,7 @@ class SafeTransformer extends MethodAccess { } /* - * SAXTransformer: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#SAXTransformerFactory + * SAXTransformer: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#saxtransformerfactory * Has an extra method called newFilter. */ @@ -996,7 +996,7 @@ class SAXTransformerFactoryNewXMLFilter extends XmlParserCall { } } -/* Schema: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#SchemaFactory */ +/* Schema: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#schemafactory */ /** The class `javax.xml.validation.SchemaFactory`. */ class SchemaFactory extends RefType { SchemaFactory() { this.hasQualifiedName("javax.xml.validation", "SchemaFactory") } @@ -1060,7 +1060,7 @@ class SafeSchemaFactory extends VarAccess { } } -/* Unmarshaller: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#Unmarshaller */ +/* Unmarshaller: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller */ /** The class `javax.xml.bind.Unmarshaller`. */ class XmlUnmarshaller extends RefType { XmlUnmarshaller() { this.hasQualifiedName("javax.xml.bind", "Unmarshaller") } @@ -1081,7 +1081,7 @@ class XmlUnmarshal extends XmlParserCall { override predicate isSafe() { none() } } -/* XPathExpression: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#XPathExpression */ +/* XPathExpression: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#xpathexpression */ /** The class `javax.xml.xpath.XPathExpression`. */ class XPathExpression extends RefType { XPathExpression() { this.hasQualifiedName("javax.xml.xpath", "XPathExpression") } diff --git a/javascript/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp b/javascript/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp index 771c446c66f..a5e0a78b8cc 100644 --- a/javascript/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp +++ b/javascript/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp @@ -68,6 +68,6 @@
  • MDN: Regular Expressions
  • OWASP: SSRF
  • -
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • +
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • diff --git a/javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp b/javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp index b23557aa557..90e6f2762e2 100644 --- a/javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp +++ b/javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp @@ -83,6 +83,6 @@
  • OWASP: SSRF
  • -
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • +
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • diff --git a/javascript/ql/src/Security/CWE-020/MissingRegExpAnchor.qhelp b/javascript/ql/src/Security/CWE-020/MissingRegExpAnchor.qhelp index 807574c5898..015e510f0fb 100644 --- a/javascript/ql/src/Security/CWE-020/MissingRegExpAnchor.qhelp +++ b/javascript/ql/src/Security/CWE-020/MissingRegExpAnchor.qhelp @@ -71,6 +71,6 @@
  • MDN: Regular Expressions
  • OWASP: SSRF
  • -
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • +
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • diff --git a/javascript/ql/src/Security/CWE-079/ReflectedXss.qhelp b/javascript/ql/src/Security/CWE-079/ReflectedXss.qhelp index 0502889fba0..dcbf0ba6f07 100644 --- a/javascript/ql/src/Security/CWE-079/ReflectedXss.qhelp +++ b/javascript/ql/src/Security/CWE-079/ReflectedXss.qhelp @@ -37,7 +37,7 @@ Sanitizing the user-controlled data prevents the vulnerability:
  • OWASP: -XSS +XSS (Cross Site Scripting) Prevention Cheat Sheet.
  • diff --git a/javascript/ql/src/Security/CWE-079/StoredXss.qhelp b/javascript/ql/src/Security/CWE-079/StoredXss.qhelp index 1c3fde01798..0e6ed6456c9 100644 --- a/javascript/ql/src/Security/CWE-079/StoredXss.qhelp +++ b/javascript/ql/src/Security/CWE-079/StoredXss.qhelp @@ -48,7 +48,7 @@
  • OWASP: - XSS + XSS (Cross Site Scripting) Prevention Cheat Sheet.
  • diff --git a/javascript/ql/src/Security/CWE-079/Xss.qhelp b/javascript/ql/src/Security/CWE-079/Xss.qhelp index 34ea1d821b6..c974c87b188 100644 --- a/javascript/ql/src/Security/CWE-079/Xss.qhelp +++ b/javascript/ql/src/Security/CWE-079/Xss.qhelp @@ -33,12 +33,12 @@ leaving the website vulnerable to cross-site scripting.
  • OWASP: -DOM based +DOM based XSS Prevention Cheat Sheet.
  • OWASP: -XSS +XSS (Cross Site Scripting) Prevention Cheat Sheet.
  • diff --git a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp index 9b230852919..e0ccf71572f 100644 --- a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp +++ b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp @@ -45,7 +45,7 @@
  • NIST, FIPS 140 Annex a: Approved Security Functions.
  • NIST, SP 800-131A: Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths.
  • OWASP: Rule + href="https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption">Rule - Use strong approved cryptographic algorithms.
  • diff --git a/javascript/ql/src/Security/CWE-451/MissingXFrameOptions.qhelp b/javascript/ql/src/Security/CWE-451/MissingXFrameOptions.qhelp index ad659015d67..e73ea063b5d 100644 --- a/javascript/ql/src/Security/CWE-451/MissingXFrameOptions.qhelp +++ b/javascript/ql/src/Security/CWE-451/MissingXFrameOptions.qhelp @@ -67,7 +67,7 @@
  • OWASP: - Clickjacking Defense Cheat Sheet. + Clickjacking Defense Cheat Sheet.
  • Mozilla: diff --git a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp index e7b956b10f4..5f5b77cbd7d 100644 --- a/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp +++ b/javascript/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp @@ -41,7 +41,7 @@ OWASP vulnerability description:
  • OWASP guidance on deserializing objects: -Deserialization Cheat Sheet. +Deserialization Cheat Sheet.
  • Neal Poole: diff --git a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.qhelp b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.qhelp index d4d36fe09bc..392df3e6cbd 100644 --- a/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.qhelp +++ b/javascript/ql/src/Security/CWE-601/ClientSideUrlRedirect.qhelp @@ -31,7 +31,7 @@ website of their choosing, which facilitates phishing attacks: -
  • OWASP: +
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • diff --git a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.qhelp b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.qhelp index cb54477dde5..2052f16146b 100644 --- a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.qhelp +++ b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.qhelp @@ -35,7 +35,7 @@ before doing the redirection: -
  • OWASP: +
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • diff --git a/javascript/ql/src/Security/CWE-770/MissingRateLimiting.qhelp b/javascript/ql/src/Security/CWE-770/MissingRateLimiting.qhelp index 1832a803a77..8d4bc0ab5d0 100644 --- a/javascript/ql/src/Security/CWE-770/MissingRateLimiting.qhelp +++ b/javascript/ql/src/Security/CWE-770/MissingRateLimiting.qhelp @@ -36,7 +36,7 @@ can be used:
  • OWASP: -Denial of Service Cheat Sheet. +Denial of Service Cheat Sheet.
  • Wikipedia: Denial-of-service attack. diff --git a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.qhelp b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.qhelp index 2b1d2b02a31..1efdbe694b1 100644 --- a/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.qhelp +++ b/javascript/ql/src/Security/CWE-916/InsufficientPasswordHash.qhelp @@ -50,6 +50,6 @@ -
  • OWASP: Password storage.
  • +
  • OWASP: Password storage.
  • diff --git a/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp b/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp index b542ae252eb..8eb0f43eb01 100644 --- a/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp +++ b/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp @@ -64,6 +64,6 @@
  • OWASP: SSRF
  • -
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • +
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • diff --git a/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp b/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp index 6c783a4f729..828c71153b5 100644 --- a/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp +++ b/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp @@ -80,6 +80,6 @@
  • OWASP: SSRF
  • -
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • +
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • diff --git a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.qhelp b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.qhelp index 4497437aac1..5b4d21bb37e 100644 --- a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.qhelp +++ b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.qhelp @@ -38,7 +38,7 @@ Jinja2: API. Wikipedia: Cross-site scripting.
  • -OWASP: XSS (Cross Site Scripting) Prevention Cheat Sheet. +OWASP: XSS (Cross Site Scripting) Prevention Cheat Sheet.
  • diff --git a/python/ql/src/Security/CWE-079/ReflectedXss.qhelp b/python/ql/src/Security/CWE-079/ReflectedXss.qhelp index 8cdeb4d3e79..04a83fba6b4 100644 --- a/python/ql/src/Security/CWE-079/ReflectedXss.qhelp +++ b/python/ql/src/Security/CWE-079/ReflectedXss.qhelp @@ -31,7 +31,7 @@ The second view is safe as first_name is escaped, so it is not vuln
  • OWASP: -XSS +XSS (Cross Site Scripting) Prevention Cheat Sheet.
  • diff --git a/python/ql/src/Security/CWE-089/SqlInjection.qhelp b/python/ql/src/Security/CWE-089/SqlInjection.qhelp index 286b71a6047..63941706e84 100644 --- a/python/ql/src/Security/CWE-089/SqlInjection.qhelp +++ b/python/ql/src/Security/CWE-089/SqlInjection.qhelp @@ -51,6 +51,6 @@ vulnerable to SQL injection attacks. In this example, if username w
  • Wikipedia: SQL injection.
  • -
  • OWASP: SQL Injection Prevention Cheat Sheet.
  • +
  • OWASP: SQL Injection Prevention Cheat Sheet.
  • diff --git a/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp b/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp index 6cc787e52e4..1b4031b1cc5 100644 --- a/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp +++ b/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp @@ -49,7 +49,7 @@
  • NIST, FIPS 140 Annex a: Approved Security Functions.
  • NIST, SP 800-131A: Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths.
  • OWASP: Rule + href="https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption">Rule - Use strong approved cryptographic algorithms.
  • diff --git a/python/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp b/python/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp index f298e62695f..8c2660b9865 100644 --- a/python/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp +++ b/python/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp @@ -49,7 +49,7 @@ OWASP vulnerability description:
  • OWASP guidance on deserializing objects: -Deserialization Cheat Sheet. +Deserialization Cheat Sheet.
  • Talks by Chris Frohoff & Gabriel Lawrence: diff --git a/python/ql/src/Security/CWE-601/UrlRedirect.qhelp b/python/ql/src/Security/CWE-601/UrlRedirect.qhelp index c2e053f030b..756a43cc106 100644 --- a/python/ql/src/Security/CWE-601/UrlRedirect.qhelp +++ b/python/ql/src/Security/CWE-601/UrlRedirect.qhelp @@ -35,7 +35,7 @@ before doing the redirection: -
  • OWASP: +
  • OWASP: XSS Unvalidated Redirects and Forwards Cheat Sheet.
  • From e314869e5cb134670d63119749abf286489af670 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 6 Nov 2019 09:06:39 +0000 Subject: [PATCH 0949/1227] JavaScript: Classify files with names ending in `_min` as minified. We already do the same for `-min` and `.min`. [Here](https://github.com/antoniogarrote/rdfstore-js/blob/master/dist/rdfstore_min.js) is a real-world example. --- change-notes/1.23/analysis-javascript.md | 4 ++-- javascript/ql/src/semmle/javascript/AST.qll | 2 +- .../query-tests/filters/ClassifyFiles/ClassifyFiles.expected | 3 +++ .../ql/test/query-tests/filters/ClassifyFiles/tst-min.js | 0 .../ql/test/query-tests/filters/ClassifyFiles/tst.min.js | 0 .../ql/test/query-tests/filters/ClassifyFiles/tst_min.js | 0 6 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 javascript/ql/test/query-tests/filters/ClassifyFiles/tst-min.js create mode 100644 javascript/ql/test/query-tests/filters/ClassifyFiles/tst.min.js create mode 100644 javascript/ql/test/query-tests/filters/ClassifyFiles/tst_min.js diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md index 49f527af424..a7f41473eea 100644 --- a/change-notes/1.23/analysis-javascript.md +++ b/change-notes/1.23/analysis-javascript.md @@ -2,6 +2,8 @@ ## General improvements +* Automatic classification of generated and minified files has been improved, in particular files generated by Doxygen are now recognized. + * Support for `globalThis` has been added. * Support for the following frameworks and libraries has been improved: @@ -14,8 +16,6 @@ * TypeScript 3.6 and 3.7 features are now supported. -* Automatic classification of generated files has been improved, in particular files generated by Doxygen are now recognized. - ## New queries | **Query** | **Tags** | **Purpose** | diff --git a/javascript/ql/src/semmle/javascript/AST.qll b/javascript/ql/src/semmle/javascript/AST.qll index efc9ef53af3..66a5155458c 100644 --- a/javascript/ql/src/semmle/javascript/AST.qll +++ b/javascript/ql/src/semmle/javascript/AST.qll @@ -150,7 +150,7 @@ class TopLevel extends @toplevel, StmtContainer { /** Holds if this toplevel is minified. */ predicate isMinified() { // file name contains 'min' (not as part of a longer word) - getFile().getBaseName().regexpMatch(".*[^-.]*[-.]min([-.].*)?\\.\\w+") + getFile().getBaseName().regexpMatch(".*[^-._]*[-._]min([-._].*)?\\.\\w+") or exists(int numstmt | numstmt = strictcount(Stmt s | s.getTopLevel() = this) | // there are more than two statements per line on average diff --git a/javascript/ql/test/query-tests/filters/ClassifyFiles/ClassifyFiles.expected b/javascript/ql/test/query-tests/filters/ClassifyFiles/ClassifyFiles.expected index 7c583b1bf39..da235c205ee 100644 --- a/javascript/ql/test/query-tests/filters/ClassifyFiles/ClassifyFiles.expected +++ b/javascript/ql/test/query-tests/filters/ClassifyFiles/ClassifyFiles.expected @@ -39,8 +39,11 @@ | textmate.html:0:0:0:0 | textmate.html | generated | | tmpl2.html:0:0:0:0 | tmpl2.html | template | | tmpl.html:0:0:0:0 | tmpl.html | template | +| tst-min.js:0:0:0:0 | tst-min.js | generated | | tst.browserify.js:0:0:0:0 | tst.browserify.js | generated | | tst.dart.js:0:0:0:0 | tst.dart.js | generated | +| tst.min.js:0:0:0:0 | tst.min.js | generated | +| tst_min.js:0:0:0:0 | tst_min.js | generated | | twitter-text.js:0:0:0:0 | twitter-text.js | library | | twitter_text.js:0:0:0:0 | twitter_text.js | library | | unannotated-externs-1.js:0:0:0:0 | unannotated-externs-1.js | externs | diff --git a/javascript/ql/test/query-tests/filters/ClassifyFiles/tst-min.js b/javascript/ql/test/query-tests/filters/ClassifyFiles/tst-min.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/javascript/ql/test/query-tests/filters/ClassifyFiles/tst.min.js b/javascript/ql/test/query-tests/filters/ClassifyFiles/tst.min.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/javascript/ql/test/query-tests/filters/ClassifyFiles/tst_min.js b/javascript/ql/test/query-tests/filters/ClassifyFiles/tst_min.js new file mode 100644 index 00000000000..e69de29bb2d From 6385528d5fe939df63bf03314206ada09ed4cc19 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 7 Nov 2019 11:30:18 +0100 Subject: [PATCH 0950/1227] C++/C#: Fix getIRTypeForPRValue join order This predicate was taking 39s on a snapshot of Facebook Fizz because it had disjuncts like this: 43685 ~0% {1} r34 = JOIN Type::FunctionPointerIshType#f AS L WITH Type::Type::getUnspecifiedType_dispred#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1> 43685 ~1% {2} r35 = JOIN r34 WITH CppType::getTypeSize#ff AS R ON FIRST 1 OUTPUT R.<1>, r34.<0> 170371500 ~2% {2} r36 = JOIN r35 WITH IRType::IRSizedType#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, r35.<1> 43685 ~6% {2} r37 = JOIN r36 WITH IRType::IRFunctionAddressType#class#ff AS R ON FIRST 1 OUTPUT r36.<1>, r36.<0> Instead of fixing the joins in `getIRTypeForPRValue` itself, I've changed the `IRType::getByteSize` predicate such that the optimiser knows how to join with it efficiently. The disjunct shown above now looks like this instead: 43685 ~0% {1} r26 = JOIN Type::FunctionPointerIshType#f AS L WITH Type::Type::getUnspecifiedType_dispred#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1> 43685 ~1% {2} r27 = JOIN r26 WITH CppType::getTypeSize#ff AS R ON FIRST 1 OUTPUT R.<1>, r26.<0> 43685 ~6% {2} r28 = JOIN r27 WITH IRType::IRFunctionAddressType::getByteSize#ff_10#join_rhs AS R ON FIRST 1 OUTPUT r27.<1>, R.<1> --- .../code/cpp/ir/implementation/IRType.qll | 27 +++++++++++++++++-- .../code/csharp/ir/implementation/IRType.qll | 27 +++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) 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 0abfa14023d..cb652230d2a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -42,6 +42,10 @@ class IRType extends TIRType { * * This will hold for all `IRType` objects except `IRUnknownType`. */ + // This predicate is overridden with `pragma[noinline]` in every leaf subclass. + // This allows callers to ask for things like _the_ floating-point type of + // size 4 without getting a join that first finds all types of size 4 and + // _then_ restricts them to floating-point types. int getByteSize() { none() } /** @@ -104,8 +108,6 @@ private class IRSizedType extends IRType { this = TIRFunctionAddressType(byteSize) or this = TIROpaqueType(_, byteSize) } - - final override int getByteSize() { result = byteSize } } /** @@ -117,6 +119,9 @@ class IRBooleanType extends IRSizedType, TIRBooleanType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalBooleanType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -141,6 +146,9 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalSignedIntegerType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -153,6 +161,9 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalUnsignedIntegerType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -164,6 +175,9 @@ class IRFloatingPointType extends IRNumericType, TIRFloatingPointType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalFloatingPointType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -178,6 +192,9 @@ class IRAddressType extends IRSizedType, TIRAddressType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalAddressType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -190,6 +207,9 @@ class IRFunctionAddressType extends IRSizedType, TIRFunctionAddressType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalFunctionAddressType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -218,6 +238,9 @@ class IROpaqueType extends IRSizedType, TIROpaqueType { * same size. */ final Language::OpaqueTypeTag getTag() { result = tag } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } module IRTypeSanity { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll index 0abfa14023d..cb652230d2a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll @@ -42,6 +42,10 @@ class IRType extends TIRType { * * This will hold for all `IRType` objects except `IRUnknownType`. */ + // This predicate is overridden with `pragma[noinline]` in every leaf subclass. + // This allows callers to ask for things like _the_ floating-point type of + // size 4 without getting a join that first finds all types of size 4 and + // _then_ restricts them to floating-point types. int getByteSize() { none() } /** @@ -104,8 +108,6 @@ private class IRSizedType extends IRType { this = TIRFunctionAddressType(byteSize) or this = TIROpaqueType(_, byteSize) } - - final override int getByteSize() { result = byteSize } } /** @@ -117,6 +119,9 @@ class IRBooleanType extends IRSizedType, TIRBooleanType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalBooleanType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -141,6 +146,9 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalSignedIntegerType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -153,6 +161,9 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalUnsignedIntegerType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -164,6 +175,9 @@ class IRFloatingPointType extends IRNumericType, TIRFloatingPointType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalFloatingPointType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -178,6 +192,9 @@ class IRAddressType extends IRSizedType, TIRAddressType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalAddressType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -190,6 +207,9 @@ class IRFunctionAddressType extends IRSizedType, TIRFunctionAddressType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalFunctionAddressType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -218,6 +238,9 @@ class IROpaqueType extends IRSizedType, TIROpaqueType { * same size. */ final Language::OpaqueTypeTag getTag() { result = tag } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } module IRTypeSanity { From e4f6f41634924e31f37072e9103edf85eefa13ee Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 6 Nov 2019 09:49:43 +0100 Subject: [PATCH 0951/1227] add DataFlow::getEnclosingExpr to get the an Expr from a potentially reflective call --- .../src/Statements/UseOfReturnlessFunction.ql | 4 ++-- .../semmle/javascript/dataflow/DataFlow.qll | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql index 123515a7cbd..7fa8e6ddf90 100644 --- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql +++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql @@ -211,9 +211,9 @@ where msg = "the $@ does not return anything, yet the return value from the call to " + call.getCalleeName() + " is used." and name = "callback function" ) and - not benignContext(call.asExpr()) and + not benignContext(call.getEnclosingExpr()) and not lastStatementHasNoEffect(func) and // anonymous one-shot closure. Those are used in weird ways and we ignore them. - not oneshotClosure(call.asExpr()) + not oneshotClosure(call.getEnclosingExpr()) select call, msg, func, name diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 07920cba3c9..1cd8286447f 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -85,6 +85,18 @@ module DataFlow { /** Gets the expression corresponding to this data flow node, if any. */ Expr asExpr() { this = TValueNode(result) } + /** + * Gets the expression enclosing this data flow node. + * In most cases the result is the same as `asExpr()`, however this method + * additionally the `InvokeExpr` corresponding to reflective calls, and the `Parameter` + * for a `DataFlow::ParameterNode`. + */ + Expr getEnclosingExpr() { + result = asExpr() or + this = DataFlow::reflectiveCallNode(result) or + result = this.(ParameterNode).getParameter() + } + /** Gets the AST node corresponding to this data flow node, if any. */ ASTNode getAstNode() { none() } @@ -950,6 +962,16 @@ module DataFlow { * Gets a pseudo-node representing the root of a global access path. */ DataFlow::Node globalAccessPathRootPseudoNode() { result instanceof TGlobalAccessPathRoot } + + /** + * Gets a data flow node representing the underlying call performed by the given + * call to `Function.prototype.call` or `Function.prototype.apply`. + * + * For example, for an expression `fn.call(x, y)`, this gets a call node with `fn` as the + * callee, `x` as the receiver, and `y` as the first argument. + */ + DataFlow::InvokeNode reflectiveCallNode(InvokeExpr expr) { result = TReflectiveCallNode(expr, _) } + /** * Provides classes representing various kinds of calls. From 232e875274bd1c66b8da6a9a0ff63878fe3c57b3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 7 Nov 2019 10:59:55 +0100 Subject: [PATCH 0952/1227] add test for getEnclosingExpr --- .../DataFlow/enclosingExpr.expected | 308 ++++++++++++++++++ .../library-tests/DataFlow/enclosingExpr.ql | 4 + 2 files changed, 312 insertions(+) create mode 100644 javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected create mode 100644 javascript/ql/test/library-tests/DataFlow/enclosingExpr.ql diff --git a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected new file mode 100644 index 00000000000..eb50988eacb --- /dev/null +++ b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected @@ -0,0 +1,308 @@ +| eval.js:1:10:1:10 | k | eval.js:1:10:1:10 | k | +| eval.js:2:7:2:7 | x | eval.js:2:7:2:7 | x | +| eval.js:2:7:2:12 | x = 42 | eval.js:2:7:2:12 | x = 42 | +| eval.js:2:11:2:12 | 42 | eval.js:2:11:2:12 | 42 | +| eval.js:3:3:3:6 | eval | eval.js:3:3:3:6 | eval | +| eval.js:3:3:3:16 | eval("x = 23") | eval.js:3:3:3:16 | eval("x = 23") | +| eval.js:3:8:3:15 | "x = 23" | eval.js:3:8:3:15 | "x = 23" | +| eval.js:4:3:4:3 | x | eval.js:4:3:4:3 | x | +| sources.js:1:1:1:12 | new (x => x) | sources.js:1:1:1:12 | new (x => x) | +| sources.js:1:5:1:12 | (x => x) | sources.js:1:5:1:12 | (x => x) | +| sources.js:1:6:1:6 | x | sources.js:1:6:1:6 | x | +| sources.js:1:6:1:6 | x | sources.js:1:6:1:6 | x | +| sources.js:1:6:1:11 | x => x | sources.js:1:6:1:11 | x => x | +| sources.js:1:11:1:11 | x | sources.js:1:11:1:11 | x | +| sources.js:3:1:5:2 | (functi ... +19;\\n}) | sources.js:3:1:5:2 | (functi ... +19;\\n}) | +| sources.js:3:1:5:6 | (functi ... \\n})(23) | sources.js:3:1:5:6 | (functi ... \\n})(23) | +| sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:3:2:5:1 | functio ... x+19;\\n} | +| sources.js:3:11:3:11 | x | sources.js:3:11:3:11 | x | +| sources.js:3:11:3:11 | x | sources.js:3:11:3:11 | x | +| sources.js:4:10:4:10 | x | sources.js:4:10:4:10 | x | +| sources.js:4:10:4:13 | x+19 | sources.js:4:10:4:13 | x+19 | +| sources.js:4:12:4:13 | 19 | sources.js:4:12:4:13 | 19 | +| sources.js:5:4:5:5 | 23 | sources.js:5:4:5:5 | 23 | +| sources.js:7:1:7:3 | /x/ | sources.js:7:1:7:3 | /x/ | +| tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs | +| tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs | +| tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs | +| tst.js:1:20:1:23 | 'fs' | tst.js:1:20:1:23 | 'fs' | +| tst.js:3:5:3:5 | x | tst.js:3:5:3:5 | x | +| tst.js:3:5:3:10 | x = 42 | tst.js:3:5:3:10 | x = 42 | +| tst.js:3:9:3:10 | 42 | tst.js:3:9:3:10 | 42 | +| tst.js:4:5:4:5 | y | tst.js:4:5:4:5 | y | +| tst.js:4:5:4:12 | y = "hi" | tst.js:4:5:4:12 | y = "hi" | +| tst.js:4:9:4:12 | "hi" | tst.js:4:9:4:12 | "hi" | +| tst.js:5:5:5:5 | z | tst.js:5:5:5:5 | z | +| tst.js:5:5:5:5 | z | tst.js:5:5:5:5 | z | +| tst.js:7:1:7:2 | fs | tst.js:7:1:7:2 | fs | +| tst.js:8:1:8:1 | x | tst.js:8:1:8:1 | x | +| tst.js:9:1:9:3 | (x) | tst.js:9:1:9:3 | (x) | +| tst.js:9:2:9:2 | x | tst.js:9:2:9:2 | x | +| tst.js:10:1:10:1 | x | tst.js:10:1:10:1 | x | +| tst.js:10:1:10:4 | x, y | tst.js:10:1:10:4 | x, y | +| tst.js:10:4:10:4 | y | tst.js:10:4:10:4 | y | +| tst.js:11:1:11:1 | x | tst.js:11:1:11:1 | x | +| tst.js:11:1:11:6 | x && y | tst.js:11:1:11:6 | x && y | +| tst.js:11:6:11:6 | y | tst.js:11:6:11:6 | y | +| tst.js:12:1:12:1 | x | tst.js:12:1:12:1 | x | +| tst.js:12:1:12:6 | x \|\| y | tst.js:12:1:12:6 | x \|\| y | +| tst.js:12:6:12:6 | y | tst.js:12:6:12:6 | y | +| tst.js:13:1:13:1 | z | tst.js:13:1:13:1 | z | +| tst.js:13:1:13:5 | z = y | tst.js:13:1:13:5 | z = y | +| tst.js:13:5:13:5 | y | tst.js:13:5:13:5 | y | +| tst.js:14:1:14:1 | z | tst.js:14:1:14:1 | z | +| tst.js:14:1:14:9 | z ? x : y | tst.js:14:1:14:9 | z ? x : y | +| tst.js:14:5:14:5 | x | tst.js:14:5:14:5 | x | +| tst.js:14:9:14:9 | y | tst.js:14:9:14:9 | y | +| tst.js:16:1:20:2 | (functi ... "";\\n}) | tst.js:16:1:20:2 | (functi ... "";\\n}) | +| tst.js:16:1:20:9 | (functi ... ("arg") | tst.js:16:1:20:9 | (functi ... ("arg") | +| tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:2:20:1 | functio ... n "";\\n} | +| tst.js:16:11:16:11 | f | tst.js:16:11:16:11 | f | +| tst.js:16:13:16:13 | a | tst.js:16:13:16:13 | a | +| tst.js:16:13:16:13 | a | tst.js:16:13:16:13 | a | +| tst.js:17:7:17:10 | Math | tst.js:17:7:17:10 | Math | +| tst.js:17:7:17:17 | Math.random | tst.js:17:7:17:17 | Math.random | +| tst.js:17:7:17:19 | Math.random() | tst.js:17:7:17:19 | Math.random() | +| tst.js:17:7:17:25 | Math.random() > 0.5 | tst.js:17:7:17:25 | Math.random() > 0.5 | +| tst.js:17:12:17:17 | random | tst.js:17:12:17:17 | random | +| tst.js:17:23:17:25 | 0.5 | tst.js:17:23:17:25 | 0.5 | +| tst.js:18:12:18:12 | a | tst.js:18:12:18:12 | a | +| tst.js:19:10:19:11 | "" | tst.js:19:10:19:11 | "" | +| tst.js:20:4:20:8 | "arg" | tst.js:20:4:20:8 | "arg" | +| tst.js:22:5:22:20 | { readFileSync } | tst.js:22:5:22:20 | { readFileSync } | +| tst.js:22:5:22:25 | { readF ... } = fs | tst.js:22:5:22:25 | { readF ... } = fs | +| tst.js:22:7:22:18 | readFileSync | tst.js:22:7:22:18 | readFileSync | +| tst.js:22:7:22:18 | readFileSync | tst.js:22:7:22:18 | readFileSync | +| tst.js:22:24:22:25 | fs | tst.js:22:24:22:25 | fs | +| tst.js:23:1:23:12 | readFileSync | tst.js:23:1:23:12 | readFileSync | +| tst.js:25:1:25:3 | ++x | tst.js:25:1:25:3 | ++x | +| tst.js:25:3:25:3 | x | tst.js:25:3:25:3 | x | +| tst.js:26:1:26:1 | x | tst.js:26:1:26:1 | x | +| tst.js:28:1:30:1 | (() =>\\n ... ables\\n) | tst.js:28:1:30:1 | (() =>\\n ... ables\\n) | +| tst.js:28:1:30:3 | (() =>\\n ... les\\n)() | tst.js:28:1:30:3 | (() =>\\n ... les\\n)() | +| tst.js:28:2:29:3 | () =>\\n x | tst.js:28:2:29:3 | () =>\\n x | +| tst.js:29:3:29:3 | x | tst.js:29:3:29:3 | x | +| tst.js:32:10:32:10 | g | tst.js:32:10:32:10 | g | +| tst.js:32:12:32:12 | b | tst.js:32:12:32:12 | b | +| tst.js:32:12:32:12 | b | tst.js:32:12:32:12 | b | +| tst.js:33:10:33:10 | x | tst.js:33:10:33:10 | x | +| tst.js:35:1:35:1 | g | tst.js:35:1:35:1 | g | +| tst.js:35:1:35:7 | g(true) | tst.js:35:1:35:7 | g(true) | +| tst.js:35:3:35:6 | true | tst.js:35:3:35:6 | true | +| tst.js:37:5:37:5 | o | tst.js:37:5:37:5 | o | +| tst.js:37:5:42:1 | o = {\\n ... ;\\n }\\n} | tst.js:37:5:42:1 | o = {\\n ... ;\\n }\\n} | +| tst.js:37:9:42:1 | {\\n x: ... ;\\n }\\n} | tst.js:37:9:42:1 | {\\n x: ... ;\\n }\\n} | +| tst.js:38:3:38:3 | x | tst.js:38:3:38:3 | x | +| tst.js:38:6:38:9 | null | tst.js:38:6:38:9 | null | +| tst.js:39:3:39:3 | m | tst.js:39:3:39:3 | m | +| tst.js:39:4:41:3 | () {\\n this;\\n } | tst.js:39:4:41:3 | () {\\n this;\\n } | +| tst.js:40:5:40:8 | this | tst.js:40:5:40:8 | this | +| tst.js:43:1:43:1 | o | tst.js:43:1:43:1 | o | +| tst.js:43:1:43:3 | o.x | tst.js:43:1:43:3 | o.x | +| tst.js:43:3:43:3 | x | tst.js:43:3:43:3 | x | +| tst.js:44:1:44:1 | o | tst.js:44:1:44:1 | o | +| tst.js:44:1:44:3 | o.m | tst.js:44:1:44:3 | o.m | +| tst.js:44:1:44:5 | o.m() | tst.js:44:1:44:5 | o.m() | +| tst.js:44:3:44:3 | m | tst.js:44:3:44:3 | m | +| tst.js:46:1:46:6 | global | tst.js:46:1:46:6 | global | +| tst.js:46:1:46:11 | global = "" | tst.js:46:1:46:11 | global = "" | +| tst.js:46:10:46:11 | "" | tst.js:46:10:46:11 | "" | +| tst.js:47:1:47:6 | global | tst.js:47:1:47:6 | global | +| tst.js:49:7:49:7 | A | tst.js:49:7:49:7 | A | +| tst.js:49:17:49:17 | B | tst.js:49:17:49:17 | B | +| tst.js:50:3:50:13 | constructor | tst.js:50:3:50:13 | constructor | +| tst.js:50:14:53:3 | () {\\n ... et`\\n } | tst.js:50:14:53:3 | () {\\n ... et`\\n } | +| tst.js:51:5:51:9 | super | tst.js:51:5:51:9 | super | +| tst.js:51:5:51:13 | super(42) | tst.js:51:5:51:13 | super(42) | +| tst.js:51:11:51:12 | 42 | tst.js:51:11:51:12 | 42 | +| tst.js:52:5:52:14 | new.target | tst.js:52:5:52:14 | new.target | +| tst.js:55:1:55:1 | A | tst.js:55:1:55:1 | A | +| tst.js:57:1:57:9 | `x: ${x}` | tst.js:57:1:57:9 | `x: ${x}` | +| tst.js:57:2:57:4 | x: | tst.js:57:2:57:4 | x: | +| tst.js:57:7:57:7 | x | tst.js:57:7:57:7 | x | +| tst.js:58:1:58:3 | tag | tst.js:58:1:58:3 | tag | +| tst.js:58:1:58:13 | tag `x: ${x}` | tst.js:58:1:58:13 | tag `x: ${x}` | +| tst.js:58:5:58:13 | `x: ${x}` | tst.js:58:5:58:13 | `x: ${x}` | +| tst.js:58:6:58:8 | x: | tst.js:58:6:58:8 | x: | +| tst.js:58:11:58:11 | x | tst.js:58:11:58:11 | x | +| tst.js:60:1:60:1 | g | tst.js:60:1:60:1 | g | +| tst.js:61:1:61:5 | ::o.m | tst.js:61:1:61:5 | ::o.m | +| tst.js:61:3:61:3 | o | tst.js:61:3:61:3 | o | +| tst.js:61:3:61:5 | o.m | tst.js:61:3:61:5 | o.m | +| tst.js:61:5:61:5 | m | tst.js:61:5:61:5 | m | +| tst.js:62:1:62:1 | o | tst.js:62:1:62:1 | o | +| tst.js:62:1:62:4 | o::g | tst.js:62:1:62:4 | o::g | +| tst.js:62:4:62:4 | g | tst.js:62:4:62:4 | g | +| tst.js:64:11:64:11 | h | tst.js:64:11:64:11 | h | +| tst.js:65:3:65:10 | yield 42 | tst.js:65:3:65:10 | yield 42 | +| tst.js:65:9:65:10 | 42 | tst.js:65:9:65:10 | 42 | +| tst.js:66:7:66:9 | tmp | tst.js:66:7:66:9 | tmp | +| tst.js:66:7:66:25 | tmp = function.sent | tst.js:66:7:66:25 | tmp = function.sent | +| tst.js:66:13:66:25 | function.sent | tst.js:66:13:66:25 | function.sent | +| tst.js:68:5:68:8 | iter | tst.js:68:5:68:8 | iter | +| tst.js:68:5:68:14 | iter = h() | tst.js:68:5:68:14 | iter = h() | +| tst.js:68:12:68:12 | h | tst.js:68:12:68:12 | h | +| tst.js:68:12:68:14 | h() | tst.js:68:12:68:14 | h() | +| tst.js:69:1:69:4 | iter | tst.js:69:1:69:4 | iter | +| tst.js:69:1:69:9 | iter.next | tst.js:69:1:69:9 | iter.next | +| tst.js:69:1:69:13 | iter.next(23) | tst.js:69:1:69:13 | iter.next(23) | +| tst.js:69:6:69:9 | next | tst.js:69:6:69:9 | next | +| tst.js:69:11:69:12 | 23 | tst.js:69:11:69:12 | 23 | +| tst.js:71:16:71:16 | k | tst.js:71:16:71:16 | k | +| tst.js:72:3:72:11 | await p() | tst.js:72:3:72:11 | await p() | +| tst.js:72:9:72:9 | p | tst.js:72:9:72:9 | p | +| tst.js:72:9:72:11 | p() | tst.js:72:9:72:11 | p() | +| tst.js:75:5:75:5 | m | tst.js:75:5:75:5 | m | +| tst.js:75:5:75:21 | m = import('foo') | tst.js:75:5:75:21 | m = import('foo') | +| tst.js:75:9:75:21 | import('foo') | tst.js:75:9:75:21 | import('foo') | +| tst.js:75:16:75:20 | 'foo' | tst.js:75:16:75:20 | 'foo' | +| tst.js:77:10:77:10 | i | tst.js:77:10:77:10 | i | +| tst.js:77:10:77:10 | i | tst.js:77:10:77:10 | i | +| tst.js:77:15:77:15 | o | tst.js:77:15:77:15 | o | +| tst.js:78:3:78:3 | i | tst.js:78:3:78:3 | i | +| tst.js:80:10:80:10 | v | tst.js:80:10:80:10 | v | +| tst.js:80:10:80:10 | v | tst.js:80:10:80:10 | v | +| tst.js:80:15:80:15 | o | tst.js:80:15:80:15 | o | +| tst.js:81:3:81:3 | v | tst.js:81:3:81:3 | v | +| tst.js:83:5:83:7 | vs1 | tst.js:83:5:83:7 | vs1 | +| tst.js:83:5:83:28 | vs1 = [ ... o) v ] | tst.js:83:5:83:28 | vs1 = [ ... o) v ] | +| tst.js:83:11:83:28 | [ for (v of o) v ] | tst.js:83:11:83:28 | [ for (v of o) v ] | +| tst.js:83:13:83:24 | for (v of o) | tst.js:83:13:83:24 | for (v of o) | +| tst.js:83:18:83:18 | v | tst.js:83:18:83:18 | v | +| tst.js:83:23:83:23 | o | tst.js:83:23:83:23 | o | +| tst.js:83:26:83:26 | v | tst.js:83:26:83:26 | v | +| tst.js:85:5:85:7 | vs2 | tst.js:85:5:85:7 | vs2 | +| tst.js:85:5:85:28 | vs2 = ( ... o) v ) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) | +| tst.js:85:11:85:28 | ( for (v of o) v ) | tst.js:85:11:85:28 | ( for (v of o) v ) | +| tst.js:85:13:85:24 | for (v of o) | tst.js:85:13:85:24 | for (v of o) | +| tst.js:85:18:85:18 | v | tst.js:85:18:85:18 | v | +| tst.js:85:23:85:23 | o | tst.js:85:23:85:23 | o | +| tst.js:85:26:85:26 | v | tst.js:85:26:85:26 | v | +| tst.js:87:1:92:2 | (functi ... + z;\\n}) | tst.js:87:1:92:2 | (functi ... + z;\\n}) | +| tst.js:87:1:96:2 | (functi ... r: 0\\n}) | tst.js:87:1:96:2 | (functi ... r: 0\\n}) | +| tst.js:87:2:92:1 | functio ... + z;\\n} | tst.js:87:2:92:1 | functio ... + z;\\n} | +| tst.js:87:11:87:24 | { p: x, ...o } | tst.js:87:11:87:24 | { p: x, ...o } | +| tst.js:87:11:87:24 | { p: x, ...o } | tst.js:87:11:87:24 | { p: x, ...o } | +| tst.js:87:13:87:13 | p | tst.js:87:13:87:13 | p | +| tst.js:87:16:87:16 | x | tst.js:87:16:87:16 | x | +| tst.js:87:22:87:22 | o | tst.js:87:22:87:22 | o | +| tst.js:88:7:88:14 | { q: y } | tst.js:88:7:88:14 | { q: y } | +| tst.js:88:7:88:18 | { q: y } = o | tst.js:88:7:88:18 | { q: y } = o | +| tst.js:88:9:88:9 | q | tst.js:88:9:88:9 | q | +| tst.js:88:12:88:12 | y | tst.js:88:12:88:12 | y | +| tst.js:88:18:88:18 | o | tst.js:88:18:88:18 | o | +| tst.js:89:7:89:7 | z | tst.js:89:7:89:7 | z | +| tst.js:89:7:89:7 | z | tst.js:89:7:89:7 | z | +| tst.js:90:3:90:16 | ({ r: z } = o) | tst.js:90:3:90:16 | ({ r: z } = o) | +| tst.js:90:4:90:11 | { r: z } | tst.js:90:4:90:11 | { r: z } | +| tst.js:90:4:90:15 | { r: z } = o | tst.js:90:4:90:15 | { r: z } = o | +| tst.js:90:6:90:6 | r | tst.js:90:6:90:6 | r | +| tst.js:90:9:90:9 | z | tst.js:90:9:90:9 | z | +| tst.js:90:15:90:15 | o | tst.js:90:15:90:15 | o | +| tst.js:91:10:91:10 | x | tst.js:91:10:91:10 | x | +| tst.js:91:10:91:14 | x + y | tst.js:91:10:91:14 | x + y | +| tst.js:91:10:91:18 | x + y + z | tst.js:91:10:91:18 | x + y + z | +| tst.js:91:14:91:14 | y | tst.js:91:14:91:14 | y | +| tst.js:91:18:91:18 | z | tst.js:91:18:91:18 | z | +| tst.js:92:4:96:1 | {\\n p: ... r: 0\\n} | tst.js:92:4:96:1 | {\\n p: ... r: 0\\n} | +| tst.js:93:3:93:3 | p | tst.js:93:3:93:3 | p | +| tst.js:93:6:93:7 | 19 | tst.js:93:6:93:7 | 19 | +| tst.js:94:3:94:3 | q | tst.js:94:3:94:3 | q | +| tst.js:94:6:94:7 | 23 | tst.js:94:6:94:7 | 23 | +| tst.js:95:3:95:3 | r | tst.js:95:3:95:3 | r | +| tst.js:95:6:95:6 | 0 | tst.js:95:6:95:6 | 0 | +| tst.js:98:1:103:2 | (functi ... + z;\\n}) | tst.js:98:1:103:2 | (functi ... + z;\\n}) | +| tst.js:98:1:103:17 | (functi ... 3, 0 ]) | tst.js:98:1:103:17 | (functi ... 3, 0 ]) | +| tst.js:98:2:103:1 | functio ... + z;\\n} | tst.js:98:2:103:1 | functio ... + z;\\n} | +| tst.js:98:11:98:24 | [ x, ...rest ] | tst.js:98:11:98:24 | [ x, ...rest ] | +| tst.js:98:11:98:24 | [ x, ...rest ] | tst.js:98:11:98:24 | [ x, ...rest ] | +| tst.js:98:13:98:13 | x | tst.js:98:13:98:13 | x | +| tst.js:98:19:98:22 | rest | tst.js:98:19:98:22 | rest | +| tst.js:99:7:99:11 | [ y ] | tst.js:99:7:99:11 | [ y ] | +| tst.js:99:7:99:18 | [ y ] = rest | tst.js:99:7:99:18 | [ y ] = rest | +| tst.js:99:9:99:9 | y | tst.js:99:9:99:9 | y | +| tst.js:99:15:99:18 | rest | tst.js:99:15:99:18 | rest | +| tst.js:100:7:100:7 | z | tst.js:100:7:100:7 | z | +| tst.js:100:7:100:7 | z | tst.js:100:7:100:7 | z | +| tst.js:101:3:101:9 | [ , z ] | tst.js:101:3:101:9 | [ , z ] | +| tst.js:101:3:101:16 | [ , z ] = rest | tst.js:101:3:101:16 | [ , z ] = rest | +| tst.js:101:7:101:7 | z | tst.js:101:7:101:7 | z | +| tst.js:101:13:101:16 | rest | tst.js:101:13:101:16 | rest | +| tst.js:102:10:102:10 | x | tst.js:102:10:102:10 | x | +| tst.js:102:10:102:14 | x + y | tst.js:102:10:102:14 | x + y | +| tst.js:102:10:102:18 | x + y + z | tst.js:102:10:102:18 | x + y + z | +| tst.js:102:14:102:14 | y | tst.js:102:14:102:14 | y | +| tst.js:102:18:102:18 | z | tst.js:102:18:102:18 | z | +| tst.js:103:4:103:16 | [ 19, 23, 0 ] | tst.js:103:4:103:16 | [ 19, 23, 0 ] | +| tst.js:103:6:103:7 | 19 | tst.js:103:6:103:7 | 19 | +| tst.js:103:10:103:11 | 23 | tst.js:103:10:103:11 | 23 | +| tst.js:103:14:103:14 | 0 | tst.js:103:14:103:14 | 0 | +| tst.js:105:1:105:1 | x | tst.js:105:1:105:1 | x | +| tst.js:105:1:105:6 | x ?? y | tst.js:105:1:105:6 | x ?? y | +| tst.js:105:6:105:6 | y | tst.js:105:6:105:6 | y | +| tst.js:107:1:113:2 | (functi ... v2c;\\n}) | tst.js:107:1:113:2 | (functi ... v2c;\\n}) | +| tst.js:107:2:113:1 | functio ... v2c;\\n} | tst.js:107:2:113:1 | functio ... v2c;\\n} | +| tst.js:108:6:108:32 | {v1a, v ... = o1c} | tst.js:108:6:108:32 | {v1a, v ... = o1c} | +| tst.js:108:6:108:38 | {v1a, v ... } = o1d | tst.js:108:6:108:38 | {v1a, v ... } = o1d | +| tst.js:108:7:108:9 | v1a | tst.js:108:7:108:9 | v1a | +| tst.js:108:7:108:9 | v1a | tst.js:108:7:108:9 | v1a | +| tst.js:108:12:108:14 | v1b | tst.js:108:12:108:14 | v1b | +| tst.js:108:12:108:14 | v1b | tst.js:108:12:108:14 | v1b | +| tst.js:108:18:108:20 | o1b | tst.js:108:18:108:20 | o1b | +| tst.js:108:23:108:25 | v1c | tst.js:108:23:108:25 | v1c | +| tst.js:108:23:108:25 | v1c | tst.js:108:23:108:25 | v1c | +| tst.js:108:29:108:31 | o1c | tst.js:108:29:108:31 | o1c | +| tst.js:108:36:108:38 | o1d | tst.js:108:36:108:38 | o1d | +| tst.js:109:2:109:4 | v1a | tst.js:109:2:109:4 | v1a | +| tst.js:109:2:109:10 | v1a + v1b | tst.js:109:2:109:10 | v1a + v1b | +| tst.js:109:2:109:16 | v1a + v1b + v1c | tst.js:109:2:109:16 | v1a + v1b + v1c | +| tst.js:109:8:109:10 | v1b | tst.js:109:8:109:10 | v1b | +| tst.js:109:14:109:16 | v1c | tst.js:109:14:109:16 | v1c | +| tst.js:111:6:111:32 | [v2a, v ... = o2c] | tst.js:111:6:111:32 | [v2a, v ... = o2c] | +| tst.js:111:6:111:38 | [v2a, v ... ] = o2d | tst.js:111:6:111:38 | [v2a, v ... ] = o2d | +| tst.js:111:7:111:9 | v2a | tst.js:111:7:111:9 | v2a | +| tst.js:111:12:111:14 | v2b | tst.js:111:12:111:14 | v2b | +| tst.js:111:18:111:20 | o2b | tst.js:111:18:111:20 | o2b | +| tst.js:111:23:111:25 | v2c | tst.js:111:23:111:25 | v2c | +| tst.js:111:29:111:31 | o2c | tst.js:111:29:111:31 | o2c | +| tst.js:111:36:111:38 | o2d | tst.js:111:36:111:38 | o2d | +| tst.js:112:2:112:4 | v2a | tst.js:112:2:112:4 | v2a | +| tst.js:112:2:112:10 | v2a + v2b | tst.js:112:2:112:10 | v2a + v2b | +| tst.js:112:2:112:16 | v2a + v2b + v2c | tst.js:112:2:112:16 | v2a + v2b + v2c | +| tst.js:112:8:112:10 | v2b | tst.js:112:8:112:10 | v2b | +| tst.js:112:14:112:16 | v2c | tst.js:112:14:112:16 | v2c | +| tst.js:115:1:115:5 | Array | tst.js:115:1:115:5 | Array | +| tst.js:115:1:115:10 | Array.call | tst.js:115:1:115:10 | Array.call | +| tst.js:115:1:115:12 | Array.call() | tst.js:115:1:115:12 | Array.call() | +| tst.js:115:1:115:12 | reflective call | tst.js:115:1:115:12 | Array.call() | +| tst.js:115:7:115:10 | call | tst.js:115:7:115:10 | call | +| tst.ts:1:11:1:11 | A | tst.ts:1:11:1:11 | A | +| tst.ts:2:14:2:14 | x | tst.ts:2:14:2:14 | x | +| tst.ts:2:14:2:19 | x = 42 | tst.ts:2:14:2:19 | x = 42 | +| tst.ts:2:18:2:19 | 42 | tst.ts:2:18:2:19 | 42 | +| tst.ts:3:3:3:6 | setX | tst.ts:3:3:3:6 | setX | +| tst.ts:3:3:3:8 | setX() | tst.ts:3:3:3:8 | setX() | +| tst.ts:4:3:4:3 | x | tst.ts:4:3:4:3 | x | +| tst.ts:7:10:7:13 | setX | tst.ts:7:10:7:13 | setX | +| tst.ts:8:3:8:3 | A | tst.ts:8:3:8:3 | A | +| tst.ts:8:3:8:5 | A.x | tst.ts:8:3:8:5 | A.x | +| tst.ts:8:3:8:10 | A.x = 23 | tst.ts:8:3:8:10 | A.x = 23 | +| tst.ts:8:5:8:5 | x | tst.ts:8:5:8:5 | x | +| tst.ts:8:9:8:10 | 23 | tst.ts:8:9:8:10 | 23 | +| tst.ts:11:5:11:7 | nd2 | tst.ts:11:5:11:7 | nd2 | +| tst.ts:11:5:11:23 | nd2 = A.x as number | tst.ts:11:5:11:23 | nd2 = A.x as number | +| tst.ts:11:11:11:11 | A | tst.ts:11:11:11:11 | A | +| tst.ts:11:11:11:13 | A.x | tst.ts:11:11:11:13 | A.x | +| tst.ts:11:11:11:23 | A.x as number | tst.ts:11:11:11:23 | A.x as number | +| tst.ts:11:13:11:13 | x | tst.ts:11:13:11:13 | x | +| tst.ts:13:7:13:16 | StringList | tst.ts:13:7:13:16 | StringList | +| tst.ts:13:26:13:29 | List | tst.ts:13:26:13:29 | List | +| tst.ts:13:26:13:37 | List | tst.ts:13:26:13:37 | List | +| tst.ts:13:39:13:38 | (...arg ... rgs); } | tst.ts:13:39:13:38 | (...arg ... rgs); } | +| tst.ts:13:39:13:38 | ...args | tst.ts:13:39:13:38 | ...args | +| tst.ts:13:39:13:38 | args | tst.ts:13:39:13:38 | args | +| tst.ts:13:39:13:38 | args | tst.ts:13:39:13:38 | args | +| tst.ts:13:39:13:38 | args | tst.ts:13:39:13:38 | args | +| tst.ts:13:39:13:38 | constructor | tst.ts:13:39:13:38 | constructor | +| tst.ts:13:39:13:38 | super | tst.ts:13:39:13:38 | super | +| tst.ts:13:39:13:38 | super(...args) | tst.ts:13:39:13:38 | super(...args) | diff --git a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.ql b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.ql new file mode 100644 index 00000000000..6b0a506ce79 --- /dev/null +++ b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.ql @@ -0,0 +1,4 @@ +import javascript + +from DataFlow::Node node +select node, node.getEnclosingExpr() From 0c080a82be1baf0f6d60ccf845fa0de61823cfb0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 7 Nov 2019 14:31:09 +0100 Subject: [PATCH 0953/1227] fix expected output --- .../library-tests/DataFlow/enclosingExpr.expected | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected index eb50988eacb..b7da1347fce 100644 --- a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected +++ b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected @@ -22,6 +22,19 @@ | sources.js:4:12:4:13 | 19 | sources.js:4:12:4:13 | 19 | | sources.js:5:4:5:5 | 23 | sources.js:5:4:5:5 | 23 | | sources.js:7:1:7:3 | /x/ | sources.js:7:1:7:3 | /x/ | +| sources.js:9:10:9:12 | foo | sources.js:9:10:9:12 | foo | +| sources.js:9:14:9:18 | array | sources.js:9:14:9:18 | array | +| sources.js:9:14:9:18 | array | sources.js:9:14:9:18 | array | +| sources.js:10:12:10:14 | key | sources.js:10:12:10:14 | key | +| sources.js:10:12:10:14 | key | sources.js:10:12:10:14 | key | +| sources.js:10:19:10:23 | array | sources.js:10:19:10:23 | array | +| sources.js:10:28:10:30 | key | sources.js:10:28:10:30 | key | +| sources.js:11:12:11:18 | { key } | sources.js:11:12:11:18 | { key } | +| sources.js:11:12:11:18 | { key } | sources.js:11:12:11:18 | { key } | +| sources.js:11:14:11:16 | key | sources.js:11:14:11:16 | key | +| sources.js:11:14:11:16 | key | sources.js:11:14:11:16 | key | +| sources.js:11:23:11:27 | array | sources.js:11:23:11:27 | array | +| sources.js:11:32:11:34 | key | sources.js:11:32:11:34 | key | | tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs | | tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs | | tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs | @@ -276,7 +289,7 @@ | tst.js:115:1:115:12 | Array.call() | tst.js:115:1:115:12 | Array.call() | | tst.js:115:1:115:12 | reflective call | tst.js:115:1:115:12 | Array.call() | | tst.js:115:7:115:10 | call | tst.js:115:7:115:10 | call | -| tst.ts:1:11:1:11 | A | tst.ts:1:11:1:11 | A | +| tst.ts:1:18:1:18 | A | tst.ts:1:18:1:18 | A | | tst.ts:2:14:2:14 | x | tst.ts:2:14:2:14 | x | | tst.ts:2:14:2:19 | x = 42 | tst.ts:2:14:2:19 | x = 42 | | tst.ts:2:18:2:19 | 42 | tst.ts:2:18:2:19 | 42 | From c0884e9a888ea8fcde2bb01a85a080533efcdaad Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Thu, 7 Nov 2019 10:34:59 +0000 Subject: [PATCH 0954/1227] C++: Update expected results. --- .../copy_from_prototype.expected | 2 +- .../syntax-zoo/drawDifferent.expected | 161 ++++++++++++------ .../syntax-zoo/tellDifferent.expected | 11 ++ .../elements.expected | 4 +- 4 files changed, 122 insertions(+), 56 deletions(-) diff --git a/cpp/ql/test/library-tests/noexcept/copy_from_prototype/copy_from_prototype.expected b/cpp/ql/test/library-tests/noexcept/copy_from_prototype/copy_from_prototype.expected index 9d77efe772f..f5ef2d77c98 100644 --- a/cpp/ql/test/library-tests/noexcept/copy_from_prototype/copy_from_prototype.expected +++ b/cpp/ql/test/library-tests/noexcept/copy_from_prototype/copy_from_prototype.expected @@ -13,7 +13,7 @@ | copy_from_prototype.cpp:13:7:13:7 | c | c::c(const c &) -> void | copy_from_prototype.cpp:13:7:13:7 | c | | | copy_from_prototype.cpp:13:7:13:7 | operator= | c::operator=(c &&) -> c & | copy_from_prototype.cpp:13:7:13:7 | c | | | copy_from_prototype.cpp:13:7:13:7 | operator= | c::operator=(const c &) -> c & | copy_from_prototype.cpp:13:7:13:7 | c | | -| copy_from_prototype.cpp:14:26:14:26 | c | c::c<(unnamed)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c | Unknown literal | +| copy_from_prototype.cpp:14:26:14:26 | c | c::c<(unnamed)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c | X | | copy_from_prototype.cpp:14:26:14:26 | c | c::c<(unnamed)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c | | | copy_from_prototype.cpp:17:7:17:7 | d | d::d() -> void | copy_from_prototype.cpp:17:7:17:7 | d | | | copy_from_prototype.cpp:17:7:17:7 | d | d::d(const d &) -> void | copy_from_prototype.cpp:17:7:17:7 | d | | diff --git a/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected b/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected index 00cdd21f9ed..6e255ec81b2 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected @@ -1,53 +1,108 @@ -| staticlocals__staticlocals_f2_extractor | false | 22465 | 22465 | f2 | -| staticlocals__staticlocals_f2_extractor | false | 22470 | 22470 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 22472 | 22472 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 22474 | 22474 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 22476 | 22476 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 22478 | 22478 | return ... | -| staticlocals__staticlocals_f2_extractor | false | 22480 | 22480 | { ... } | -| staticlocals__staticlocals_f2_extractor | false | 22482 | 22482 | call to C | -| staticlocals__staticlocals_f2_extractor | false | 22484 | 22484 | initializer for c | -| staticlocals__staticlocals_f2_extractor | false | 22486 | 22486 | call to addOne | -| staticlocals__staticlocals_f2_extractor | false | 22490 | 22490 | 2 | -| staticlocals__staticlocals_f2_extractor | false | 22493 | 22493 | initializer for j | -| staticlocals__staticlocals_f2_extractor | false | 22494 | 22494 | call to addOne | -| staticlocals__staticlocals_f2_extractor | false | 22499 | 22499 | 2 | -| staticlocals__staticlocals_f2_extractor | false | 22500 | 22500 | initializer for two | -| staticlocals__staticlocals_f2_extractor | false | 22503 | 22503 | two | -| staticlocals__staticlocals_f2_extractor | false | 22508 | 22508 | initializer for i | -| staticlocals__staticlocals_f2_extractor | true | 22470 | 22500 | | -| staticlocals__staticlocals_f2_extractor | true | 22472 | 22474 | | -| staticlocals__staticlocals_f2_extractor | true | 22474 | 22476 | | -| staticlocals__staticlocals_f2_extractor | true | 22476 | 22478 | | -| staticlocals__staticlocals_f2_extractor | true | 22478 | 22465 | | -| staticlocals__staticlocals_f2_extractor | true | 22480 | 22470 | | -| staticlocals__staticlocals_f2_extractor | true | 22499 | 22472 | | -| staticlocals__staticlocals_f2_extractor | true | 22500 | 22499 | | -| staticlocals__staticlocals_f2_ql | false | 22465 | 22465 | f2 | -| staticlocals__staticlocals_f2_ql | false | 22470 | 22470 | declaration | -| staticlocals__staticlocals_f2_ql | false | 22472 | 22472 | declaration | -| staticlocals__staticlocals_f2_ql | false | 22474 | 22474 | declaration | -| staticlocals__staticlocals_f2_ql | false | 22476 | 22476 | declaration | -| staticlocals__staticlocals_f2_ql | false | 22478 | 22478 | return ... | -| staticlocals__staticlocals_f2_ql | false | 22480 | 22480 | { ... } | -| staticlocals__staticlocals_f2_ql | false | 22482 | 22482 | call to C | -| staticlocals__staticlocals_f2_ql | false | 22484 | 22484 | initializer for c | -| staticlocals__staticlocals_f2_ql | false | 22486 | 22486 | call to addOne | -| staticlocals__staticlocals_f2_ql | false | 22490 | 22490 | 2 | -| staticlocals__staticlocals_f2_ql | false | 22493 | 22493 | initializer for j | -| staticlocals__staticlocals_f2_ql | false | 22494 | 22494 | call to addOne | -| staticlocals__staticlocals_f2_ql | false | 22499 | 22499 | 2 | -| staticlocals__staticlocals_f2_ql | false | 22500 | 22500 | initializer for two | -| staticlocals__staticlocals_f2_ql | false | 22503 | 22503 | two | -| staticlocals__staticlocals_f2_ql | false | 22508 | 22508 | initializer for i | -| staticlocals__staticlocals_f2_ql | true | 22470 | 22500 | | -| staticlocals__staticlocals_f2_ql | true | 22472 | 22474 | | -| staticlocals__staticlocals_f2_ql | true | 22474 | 22476 | | -| staticlocals__staticlocals_f2_ql | true | 22476 | 22478 | | -| staticlocals__staticlocals_f2_ql | true | 22476 | 22484 | | -| staticlocals__staticlocals_f2_ql | true | 22478 | 22465 | | -| staticlocals__staticlocals_f2_ql | true | 22480 | 22470 | | -| staticlocals__staticlocals_f2_ql | true | 22482 | 22478 | | -| staticlocals__staticlocals_f2_ql | true | 22484 | 22482 | | -| staticlocals__staticlocals_f2_ql | true | 22499 | 22472 | | -| staticlocals__staticlocals_f2_ql | true | 22500 | 22499 | | +| pointer_to_member__pmIsConstT_extractor | false | 21747 | 21747 | pmIsConstT | +| pointer_to_member__pmIsConstT_extractor | false | 21756 | 21756 | declaration | +| pointer_to_member__pmIsConstT_extractor | false | 21759 | 21759 | return ... | +| pointer_to_member__pmIsConstT_extractor | false | 21762 | 21762 | { ... } | +| pointer_to_member__pmIsConstT_extractor | false | 21766 | 21766 | {...} | +| pointer_to_member__pmIsConstT_extractor | false | 21773 | 21773 | x1 | +| pointer_to_member__pmIsConstT_extractor | false | 21777 | 21777 | & ... | +| pointer_to_member__pmIsConstT_extractor | false | 21784 | 21784 | f1 | +| pointer_to_member__pmIsConstT_extractor | false | 21788 | 21788 | & ... | +| pointer_to_member__pmIsConstT_extractor | false | 21791 | 21791 | initializer for pms | +| pointer_to_member__pmIsConstT_extractor | true | 21756 | 21759 | | +| pointer_to_member__pmIsConstT_extractor | true | 21759 | 21747 | | +| pointer_to_member__pmIsConstT_extractor | true | 21762 | 21756 | | +| pointer_to_member__pmIsConstT_ql | false | 21747 | 21747 | pmIsConstT | +| pointer_to_member__pmIsConstT_ql | false | 21756 | 21756 | declaration | +| pointer_to_member__pmIsConstT_ql | false | 21759 | 21759 | return ... | +| pointer_to_member__pmIsConstT_ql | false | 21762 | 21762 | { ... } | +| pointer_to_member__pmIsConstT_ql | false | 21766 | 21766 | {...} | +| pointer_to_member__pmIsConstT_ql | false | 21773 | 21773 | x1 | +| pointer_to_member__pmIsConstT_ql | false | 21777 | 21777 | & ... | +| pointer_to_member__pmIsConstT_ql | false | 21784 | 21784 | f1 | +| pointer_to_member__pmIsConstT_ql | false | 21788 | 21788 | & ... | +| pointer_to_member__pmIsConstT_ql | false | 21791 | 21791 | initializer for pms | +| pointer_to_member__pmIsConstT_ql | true | 21756 | 21791 | | +| pointer_to_member__pmIsConstT_ql | true | 21759 | 21747 | | +| pointer_to_member__pmIsConstT_ql | true | 21762 | 21756 | | +| pointer_to_member__pmIsConstT_ql | true | 21766 | 21759 | | +| pointer_to_member__pmIsConstT_ql | true | 21773 | 21777 | | +| pointer_to_member__pmIsConstT_ql | true | 21777 | 21784 | | +| pointer_to_member__pmIsConstT_ql | true | 21784 | 21788 | | +| pointer_to_member__pmIsConstT_ql | true | 21788 | 21766 | | +| pointer_to_member__pmIsConstT_ql | true | 21791 | 21773 | | +| staticlocals__staticlocals_f2_extractor | false | 31503 | 31503 | f2 | +| staticlocals__staticlocals_f2_extractor | false | 31509 | 31509 | declaration | +| staticlocals__staticlocals_f2_extractor | false | 31512 | 31512 | declaration | +| staticlocals__staticlocals_f2_extractor | false | 31515 | 31515 | declaration | +| staticlocals__staticlocals_f2_extractor | false | 31518 | 31518 | declaration | +| staticlocals__staticlocals_f2_extractor | false | 31521 | 31521 | return ... | +| staticlocals__staticlocals_f2_extractor | false | 31524 | 31524 | { ... } | +| staticlocals__staticlocals_f2_extractor | false | 31527 | 31527 | call to C | +| staticlocals__staticlocals_f2_extractor | false | 31530 | 31530 | initializer for c | +| staticlocals__staticlocals_f2_extractor | false | 31533 | 31533 | call to addOne | +| staticlocals__staticlocals_f2_extractor | false | 31539 | 31539 | 2 | +| staticlocals__staticlocals_f2_extractor | false | 31544 | 31544 | initializer for j | +| staticlocals__staticlocals_f2_extractor | false | 31546 | 31546 | call to addOne | +| staticlocals__staticlocals_f2_extractor | false | 31554 | 31554 | 2 | +| staticlocals__staticlocals_f2_extractor | false | 31556 | 31556 | initializer for two | +| staticlocals__staticlocals_f2_extractor | false | 31560 | 31560 | two | +| staticlocals__staticlocals_f2_extractor | false | 31568 | 31568 | initializer for i | +| staticlocals__staticlocals_f2_extractor | true | 31509 | 31556 | | +| staticlocals__staticlocals_f2_extractor | true | 31512 | 31515 | | +| staticlocals__staticlocals_f2_extractor | true | 31515 | 31518 | | +| staticlocals__staticlocals_f2_extractor | true | 31518 | 31521 | | +| staticlocals__staticlocals_f2_extractor | true | 31521 | 31503 | | +| staticlocals__staticlocals_f2_extractor | true | 31524 | 31509 | | +| staticlocals__staticlocals_f2_extractor | true | 31554 | 31512 | | +| staticlocals__staticlocals_f2_extractor | true | 31556 | 31554 | | +| staticlocals__staticlocals_f2_ql | false | 31503 | 31503 | f2 | +| staticlocals__staticlocals_f2_ql | false | 31509 | 31509 | declaration | +| staticlocals__staticlocals_f2_ql | false | 31512 | 31512 | declaration | +| staticlocals__staticlocals_f2_ql | false | 31515 | 31515 | declaration | +| staticlocals__staticlocals_f2_ql | false | 31518 | 31518 | declaration | +| staticlocals__staticlocals_f2_ql | false | 31521 | 31521 | return ... | +| staticlocals__staticlocals_f2_ql | false | 31524 | 31524 | { ... } | +| staticlocals__staticlocals_f2_ql | false | 31527 | 31527 | call to C | +| staticlocals__staticlocals_f2_ql | false | 31530 | 31530 | initializer for c | +| staticlocals__staticlocals_f2_ql | false | 31533 | 31533 | call to addOne | +| staticlocals__staticlocals_f2_ql | false | 31539 | 31539 | 2 | +| staticlocals__staticlocals_f2_ql | false | 31544 | 31544 | initializer for j | +| staticlocals__staticlocals_f2_ql | false | 31546 | 31546 | call to addOne | +| staticlocals__staticlocals_f2_ql | false | 31554 | 31554 | 2 | +| staticlocals__staticlocals_f2_ql | false | 31556 | 31556 | initializer for two | +| staticlocals__staticlocals_f2_ql | false | 31560 | 31560 | two | +| staticlocals__staticlocals_f2_ql | false | 31568 | 31568 | initializer for i | +| staticlocals__staticlocals_f2_ql | true | 31509 | 31556 | | +| staticlocals__staticlocals_f2_ql | true | 31512 | 31515 | | +| staticlocals__staticlocals_f2_ql | true | 31515 | 31518 | | +| staticlocals__staticlocals_f2_ql | true | 31518 | 31521 | | +| staticlocals__staticlocals_f2_ql | true | 31518 | 31530 | | +| staticlocals__staticlocals_f2_ql | true | 31521 | 31503 | | +| staticlocals__staticlocals_f2_ql | true | 31524 | 31509 | | +| staticlocals__staticlocals_f2_ql | true | 31527 | 31521 | | +| staticlocals__staticlocals_f2_ql | true | 31530 | 31527 | | +| staticlocals__staticlocals_f2_ql | true | 31554 | 31512 | | +| staticlocals__staticlocals_f2_ql | true | 31556 | 31554 | | +| staticlocals__staticlocals_f3_extractor | false | 31473 | 31473 | f3 | +| staticlocals__staticlocals_f3_extractor | false | 31477 | 31477 | declaration | +| staticlocals__staticlocals_f3_extractor | false | 31480 | 31480 | return ... | +| staticlocals__staticlocals_f3_extractor | false | 31483 | 31483 | { ... } | +| staticlocals__staticlocals_f3_extractor | false | 31492 | 31492 | value | +| staticlocals__staticlocals_f3_extractor | false | 31496 | 31496 | (int)... | +| staticlocals__staticlocals_f3_extractor | false | 31498 | 31498 | initializer for i | +| staticlocals__staticlocals_f3_extractor | true | 31477 | 31480 | | +| staticlocals__staticlocals_f3_extractor | true | 31480 | 31473 | | +| staticlocals__staticlocals_f3_extractor | true | 31483 | 31477 | | +| staticlocals__staticlocals_f3_ql | false | 31473 | 31473 | f3 | +| staticlocals__staticlocals_f3_ql | false | 31477 | 31477 | declaration | +| staticlocals__staticlocals_f3_ql | false | 31480 | 31480 | return ... | +| staticlocals__staticlocals_f3_ql | false | 31483 | 31483 | { ... } | +| staticlocals__staticlocals_f3_ql | false | 31492 | 31492 | value | +| staticlocals__staticlocals_f3_ql | false | 31496 | 31496 | (int)... | +| staticlocals__staticlocals_f3_ql | false | 31498 | 31498 | initializer for i | +| staticlocals__staticlocals_f3_ql | true | 31477 | 31480 | | +| staticlocals__staticlocals_f3_ql | true | 31477 | 31498 | | +| staticlocals__staticlocals_f3_ql | true | 31480 | 31473 | | +| staticlocals__staticlocals_f3_ql | true | 31483 | 31477 | | +| staticlocals__staticlocals_f3_ql | true | 31492 | 31480 | | +| staticlocals__staticlocals_f3_ql | true | 31498 | 31492 | | diff --git a/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected b/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected index 0e06bb202c4..ae6f3429892 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected @@ -1,3 +1,14 @@ +| pointer_to_member__pmIsConstT | pointer_to_member.cpp:41:3:44:29 | declaration | pointer_to_member.cpp:44:11:44:28 | initializer for pms | Standard edge, only from QL | uninstantiated | +| pointer_to_member__pmIsConstT | pointer_to_member.cpp:41:3:44:29 | declaration | pointer_to_member.cpp:45:1:45:1 | return ... | Standard edge, only from extractor | uninstantiated | +| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:11:44:28 | initializer for pms | pointer_to_member.cpp:44:14:44:18 | x1 | Standard edge, only from QL | uninstantiated | +| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:11:44:28 | {...} | pointer_to_member.cpp:45:1:45:1 | return ... | Standard edge, only from QL | uninstantiated | +| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:13:44:18 | & ... | pointer_to_member.cpp:44:22:44:26 | f1 | Standard edge, only from QL | uninstantiated | +| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:14:44:18 | x1 | pointer_to_member.cpp:44:13:44:18 | & ... | Standard edge, only from QL | uninstantiated | +| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:21:44:26 | & ... | pointer_to_member.cpp:44:11:44:28 | {...} | Standard edge, only from QL | uninstantiated | +| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:22:44:26 | f1 | pointer_to_member.cpp:44:21:44:26 | & ... | Standard edge, only from QL | uninstantiated | | staticlocals__staticlocals_f2 | file://:0:0:0:0 | call to C | staticlocals.cpp:30:1:30:1 | return ... | Standard edge, only from QL | | | staticlocals__staticlocals_f2 | file://:0:0:0:0 | initializer for c | file://:0:0:0:0 | call to C | Standard edge, only from QL | | | staticlocals__staticlocals_f2 | staticlocals.cpp:29:5:29:17 | declaration | file://:0:0:0:0 | initializer for c | Standard edge, only from QL | | +| staticlocals__staticlocals_f3 | staticlocals.cpp:39:3:39:34 | declaration | staticlocals.cpp:39:18:39:33 | initializer for i | Standard edge, only from QL | uninstantiated | +| staticlocals__staticlocals_f3 | staticlocals.cpp:39:18:39:33 | initializer for i | staticlocals.cpp:39:18:39:33 | value | Standard edge, only from QL | uninstantiated | +| staticlocals__staticlocals_f3 | staticlocals.cpp:39:18:39:33 | value | staticlocals.cpp:40:1:40:1 | return ... | Standard edge, only from QL | uninstantiated | diff --git a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected index 802903a40b6..99a6201c59c 100644 --- a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected +++ b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected @@ -317,8 +317,8 @@ | test.cpp:19:9:19:24 | call to expression | | test.cpp:19:9:19:25 | ExprStmt | | test.cpp:19:9:19:25 | ExprStmt | -| test.cpp:19:15:19:18 | Unknown literal | | test.cpp:19:15:19:18 | call to funx | +| test.cpp:19:15:19:18 | funx | | test.cpp:19:20:19:23 | (reference to) | | test.cpp:19:20:19:23 | valx | | test.cpp:19:20:19:23 | valx | @@ -356,8 +356,8 @@ | test.cpp:30:13:30:22 | call to expression | | test.cpp:30:13:30:23 | ExprStmt | | test.cpp:30:13:30:23 | ExprStmt | -| test.cpp:30:15:30:20 | Unknown literal | | test.cpp:30:15:30:20 | call to eparse | +| test.cpp:30:15:30:20 | eparse | | test.cpp:31:9:31:9 | return ... | | test.cpp:31:9:31:9 | return ... | | test.cpp:34:6:34:11 | define | From ddf1ef8a7d65ceb869fae56b83be92da6a768c0c Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Thu, 7 Nov 2019 10:35:26 +0000 Subject: [PATCH 0955/1227] C++: Add new test case for template member change We now output literals for accesses to members of template parameters: So for `foo` in the following example: ``` template void bar(T& t) { T.foo(1) } ``` --- .../CPP-172-template-members/test.cpp | 19 +++++++++++++++++++ .../CPP-172-template-members/test.expected | 2 ++ .../CPP-172-template-members/test.ql | 4 ++++ 3 files changed, 25 insertions(+) create mode 100644 cpp/ql/test/library-tests/templates/CPP-172-template-members/test.cpp create mode 100644 cpp/ql/test/library-tests/templates/CPP-172-template-members/test.expected create mode 100644 cpp/ql/test/library-tests/templates/CPP-172-template-members/test.ql diff --git a/cpp/ql/test/library-tests/templates/CPP-172-template-members/test.cpp b/cpp/ql/test/library-tests/templates/CPP-172-template-members/test.cpp new file mode 100644 index 00000000000..9a624d5d9f0 --- /dev/null +++ b/cpp/ql/test/library-tests/templates/CPP-172-template-members/test.cpp @@ -0,0 +1,19 @@ + + +class A { +public: + void foo(); + int k; +}; + +class B { +public: + template + B(T x) { + int k = x.k; + x.foo(); + } +}; + +A a; +B b(a); diff --git a/cpp/ql/test/library-tests/templates/CPP-172-template-members/test.expected b/cpp/ql/test/library-tests/templates/CPP-172-template-members/test.expected new file mode 100644 index 00000000000..29d00dc147a --- /dev/null +++ b/cpp/ql/test/library-tests/templates/CPP-172-template-members/test.expected @@ -0,0 +1,2 @@ +| test.cpp:13:15:13:15 | k | +| test.cpp:14:7:14:9 | foo | diff --git a/cpp/ql/test/library-tests/templates/CPP-172-template-members/test.ql b/cpp/ql/test/library-tests/templates/CPP-172-template-members/test.ql new file mode 100644 index 00000000000..233c7cdce8d --- /dev/null +++ b/cpp/ql/test/library-tests/templates/CPP-172-template-members/test.ql @@ -0,0 +1,4 @@ +import cpp + +from Literal l +select l From db2039d8a75cdd76bc31c35be122d579d9015584 Mon Sep 17 00:00:00 2001 From: james Date: Thu, 7 Nov 2019 13:17:57 +0000 Subject: [PATCH 0956/1227] docs: learn codeql terminology note --- docs/language/learn-ql/index.rst | 12 +++++++++ docs/language/learn-ql/terminology-note.rst | 27 +++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 docs/language/learn-ql/terminology-note.rst diff --git a/docs/language/learn-ql/index.rst b/docs/language/learn-ql/index.rst index 76649890131..5a3c70c4580 100644 --- a/docs/language/learn-ql/index.rst +++ b/docs/language/learn-ql/index.rst @@ -9,6 +9,18 @@ Here, you can query open source projects directly, without having to download Co CodeQL is based on a powerful query language called QL. The following topics help you understand QL in general, as well as how to use it when analyzing code with CodeQL. +.. pull-quote:: + + Important + + If you've previously used QL, you may notice some slight changes in terms we use to describe some important concepts. For more information, see our note about :doc:`Recent terminology changes `. + +.. toctree:: + :hidden: + + terminology-note + + .. _getting-started: Getting started diff --git a/docs/language/learn-ql/terminology-note.rst b/docs/language/learn-ql/terminology-note.rst new file mode 100644 index 00000000000..794106d5705 --- /dev/null +++ b/docs/language/learn-ql/terminology-note.rst @@ -0,0 +1,27 @@ +Recent terminology changes +=========================== + +We recently started using new terminology to make it clearer to users what our products do. +This note gives some information about what has changed. + +CodeQL +------ + +CodeQL is the code analysis platform formerly known as QL. +CodeQL treats code as data, and CodeQL analysis is based on running queries against your code to check for errors and find bugs and vulnerabilities. +The CodeQL product includes the tools, scripts, queries, and libraries used in CodeQL analysis. + +QL +--- + +Previously we used the term QL to refer to the whole code analysis platform, which has been renamed CodeQL. +The name QL now only refers to the query language that powers CodeQL analysis. + +The CodeQL queries and libraries used to analyze source code are written in QL. +These queries and libraries are open source, and can be found in the `CodeQL repository `__. +QL is a general-purpose, object-oriented language that can be used to query any kind of data. + +CodeQL databases +---------------- + +QL snapshots have been renamed CodeQL databases. CodeQL databases contain relational data created and analyzed using CodeQL. They are the equivalent of QL snapshots, but have been optimized for use with the CodeQL tools. From 8544850945898dee993de50e7f909e22f711f79c Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 5 Nov 2019 12:00:50 +0000 Subject: [PATCH 0957/1227] JS: Generalize StringOps::Includes to ::InclusionTest --- javascript/ql/src/javascript.qll | 1 + .../src/semmle/javascript/InclusionTests.qll | 173 ++++++++++++++++++ .../ql/src/semmle/javascript/StringOps.qll | 157 +--------------- .../javascript/dataflow/TaintTracking.qll | 15 +- 4 files changed, 188 insertions(+), 158 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/InclusionTests.qll diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index 9e75e032b1c..a6df138c592 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -28,6 +28,7 @@ import semmle.javascript.Functions import semmle.javascript.GlobalAccessPaths import semmle.javascript.HTML import semmle.javascript.HtmlSanitizers +import semmle.javascript.InclusionTests import semmle.javascript.JSDoc import semmle.javascript.JSON import semmle.javascript.JsonParsers diff --git a/javascript/ql/src/semmle/javascript/InclusionTests.qll b/javascript/ql/src/semmle/javascript/InclusionTests.qll new file mode 100644 index 00000000000..7a90dbf1583 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/InclusionTests.qll @@ -0,0 +1,173 @@ +/** + * Contains classes for recognizing array and string inclusion tests. + */ +private import javascript + +/** + * A expression that checks if an element is contained in an array + * or is a substring of another string. + * + * Examples: + * ``` + * A.includes(B) + * A.indexOf(B) !== -1 + * A.indexOf(B) >= 0 + * ~A.indexOf(B) + * ``` + */ +class InclusionTest extends DataFlow::Node { + InclusionTest::Range range; + + InclusionTest() { this = range } + + /** Gets the `A` in `A.includes(B)`. */ + DataFlow::Node getContainerNode() { result = range.getContainerNode() } + + /** Gets the `B` in `A.includes(B)`. */ + DataFlow::Node getContainedNode() { result = range.getContainedNode() } + + /** + * Gets the polarity of the check. + * + * If the polarity is `false` the check returns `true` if the container does not contain + * the given element. + */ + boolean getPolarity() { result = range.getPolarity() } +} + +module InclusionTest { + /** + * A expression that is equivalent to `A.includes(B)` or `!A.includes(B)`. + * + * Note that this also includes calls to the array method named `includes`. + */ + abstract class Range extends DataFlow::Node { + /** Gets the `A` in `A.includes(B)`. */ + abstract DataFlow::Node getContainerNode(); + + /** Gets the `B` in `A.includes(B)`. */ + abstract DataFlow::Node getContainedNode(); + + /** + * Gets the polarity of the check. + * + * If the polarity is `false` the check returns `true` if the container does not contain + * the given element. + */ + boolean getPolarity() { result = true } + } + + /** + * A call to a method named `includes`, assumed to refer to `String.prototype.includes` + * or `Array.prototype.includes`. + */ + private class Includes_Native extends Range, DataFlow::MethodCallNode { + Includes_Native() { + getMethodName() = "includes" and + getNumArgument() = 1 + } + + override DataFlow::Node getContainerNode() { result = getReceiver() } + + override DataFlow::Node getContainedNode() { result = getArgument(0) } + } + + /** + * A call to `_.includes` or similar, assumed to operate on strings. + */ + private class Includes_Library extends Range, DataFlow::CallNode { + Includes_Library() { + exists(string name | + this = LodashUnderscore::member(name).getACall() and + (name = "includes" or name = "include" or name = "contains") + or + this = Closure::moduleImport("goog.string." + name).getACall() and + (name = "contains" or name = "caseInsensitiveContains") + ) + } + + override DataFlow::Node getContainerNode() { result = getArgument(0) } + + override DataFlow::Node getContainedNode() { result = getArgument(1) } + } + + /** + * A check of form `A.indexOf(B) !== -1` or similar. + */ + private class Includes_IndexOfEquals extends Range, DataFlow::ValueNode { + MethodCallExpr indexOf; + override EqualityTest astNode; + + Includes_IndexOfEquals() { + exists(Expr index | astNode.hasOperands(indexOf, index) | + // one operand is of the form `whitelist.indexOf(x)` + indexOf.getMethodName() = "indexOf" and + // and the other one is -1 + index.getIntValue() = -1 + ) + } + + override DataFlow::Node getContainerNode() { result = indexOf.getReceiver().flow() } + + override DataFlow::Node getContainedNode() { result = indexOf.getArgument(0).flow() } + + override boolean getPolarity() { result = astNode.getPolarity().booleanNot() } + } + + /** + * A check of form `A.indexOf(B) >= 0` or similar. + */ + private class Includes_IndexOfRelational extends Range, DataFlow::ValueNode { + MethodCallExpr indexOf; + override RelationalComparison astNode; + boolean polarity; + + Includes_IndexOfRelational() { + exists(Expr lesser, Expr greater | + astNode.getLesserOperand() = lesser and + astNode.getGreaterOperand() = greater and + indexOf.getMethodName() = "indexOf" and + indexOf.getNumArgument() = 1 + | + polarity = true and + greater = indexOf and + ( + lesser.getIntValue() = 0 and astNode.isInclusive() + or + lesser.getIntValue() = -1 and not astNode.isInclusive() + ) + or + polarity = false and + lesser = indexOf and + ( + greater.getIntValue() = -1 and astNode.isInclusive() + or + greater.getIntValue() = 0 and not astNode.isInclusive() + ) + ) + } + + override DataFlow::Node getContainerNode() { result = indexOf.getReceiver().flow() } + + override DataFlow::Node getContainedNode() { result = indexOf.getArgument(0).flow() } + + override boolean getPolarity() { result = polarity } + } + + /** + * An expression of form `~A.indexOf(B)` which, when coerced to a boolean, is equivalent to `A.includes(B)`. + */ + private class Includes_IndexOfBitwise extends Range, DataFlow::ValueNode { + MethodCallExpr indexOf; + override BitNotExpr astNode; + + Includes_IndexOfBitwise() { + astNode.getOperand() = indexOf and + indexOf.getMethodName() = "indexOf" + } + + override DataFlow::Node getContainerNode() { result = indexOf.getReceiver().flow() } + + override DataFlow::Node getContainedNode() { result = indexOf.getArgument(0).flow() } + } +} diff --git a/javascript/ql/src/semmle/javascript/StringOps.qll b/javascript/ql/src/semmle/javascript/StringOps.qll index f33dbd9f74d..d916e8e469d 100644 --- a/javascript/ql/src/semmle/javascript/StringOps.qll +++ b/javascript/ql/src/semmle/javascript/StringOps.qll @@ -185,162 +185,15 @@ module StringOps { /** * A expression that is equivalent to `A.includes(B)` or `!A.includes(B)`. * - * Note that this also includes calls to the array method named `includes`. + * Note that this class is equivalent to `InclusionTest`, which also matches + * inclusion tests on array objects. */ - class Includes extends DataFlow::Node { - Includes::Range range; - - Includes() { this = range } - + class Includes extends InclusionTest { /** Gets the `A` in `A.includes(B)`. */ - DataFlow::Node getBaseString() { result = range.getBaseString() } + DataFlow::Node getBaseString() { result = getContainerNode() } /** Gets the `B` in `A.includes(B)`. */ - DataFlow::Node getSubstring() { result = range.getSubstring() } - - /** - * Gets the polarity of the check. - * - * If the polarity is `false` the check returns `true` if the string does not contain - * the given substring. - */ - boolean getPolarity() { result = range.getPolarity() } - } - - module Includes { - /** - * A expression that is equivalent to `A.includes(B)` or `!A.includes(B)`. - * - * Note that this also includes calls to the array method named `includes`. - */ - abstract class Range extends DataFlow::Node { - /** Gets the `A` in `A.includes(B)`. */ - abstract DataFlow::Node getBaseString(); - - /** Gets the `B` in `A.includes(B)`. */ - abstract DataFlow::Node getSubstring(); - - /** - * Gets the polarity of the check. - * - * If the polarity is `false` the check returns `true` if the string does not contain - * the given substring. - */ - boolean getPolarity() { result = true } - } - - /** - * A call to a method named `includes`, assumed to refer to `String.prototype.includes`. - */ - private class Includes_Native extends Range, DataFlow::MethodCallNode { - Includes_Native() { - getMethodName() = "includes" and - getNumArgument() = 1 - } - - override DataFlow::Node getBaseString() { result = getReceiver() } - - override DataFlow::Node getSubstring() { result = getArgument(0) } - } - - /** - * A call to `_.includes` or similar, assumed to operate on strings. - */ - private class Includes_Library extends Range, DataFlow::CallNode { - Includes_Library() { - exists(string name | - this = LodashUnderscore::member(name).getACall() and - (name = "includes" or name = "include" or name = "contains") - or - this = Closure::moduleImport("goog.string." + name).getACall() and - (name = "contains" or name = "caseInsensitiveContains") - ) - } - - override DataFlow::Node getBaseString() { result = getArgument(0) } - - override DataFlow::Node getSubstring() { result = getArgument(1) } - } - - /** - * A check of form `A.indexOf(B) !== -1` or similar. - */ - private class Includes_IndexOfEquals extends Range, DataFlow::ValueNode { - MethodCallExpr indexOf; - override EqualityTest astNode; - - Includes_IndexOfEquals() { - exists(Expr index | astNode.hasOperands(indexOf, index) | - // one operand is of the form `whitelist.indexOf(x)` - indexOf.getMethodName() = "indexOf" and - // and the other one is -1 - index.getIntValue() = -1 - ) - } - - override DataFlow::Node getBaseString() { result = indexOf.getReceiver().flow() } - - override DataFlow::Node getSubstring() { result = indexOf.getArgument(0).flow() } - - override boolean getPolarity() { result = astNode.getPolarity().booleanNot() } - } - - /** - * A check of form `A.indexOf(B) >= 0` or similar. - */ - private class Includes_IndexOfRelational extends Range, DataFlow::ValueNode { - MethodCallExpr indexOf; - override RelationalComparison astNode; - boolean polarity; - - Includes_IndexOfRelational() { - exists(Expr lesser, Expr greater | - astNode.getLesserOperand() = lesser and - astNode.getGreaterOperand() = greater and - indexOf.getMethodName() = "indexOf" and - indexOf.getNumArgument() = 1 - | - polarity = true and - greater = indexOf and - ( - lesser.getIntValue() = 0 and astNode.isInclusive() - or - lesser.getIntValue() = -1 and not astNode.isInclusive() - ) - or - polarity = false and - lesser = indexOf and - ( - greater.getIntValue() = -1 and astNode.isInclusive() - or - greater.getIntValue() = 0 and not astNode.isInclusive() - ) - ) - } - - override DataFlow::Node getBaseString() { result = indexOf.getReceiver().flow() } - - override DataFlow::Node getSubstring() { result = indexOf.getArgument(0).flow() } - - override boolean getPolarity() { result = polarity } - } - - /** - * An expression of form `~A.indexOf(B)` which, when coerced to a boolean, is equivalent to `A.includes(B)`. - */ - private class Includes_IndexOfBitwise extends Range, DataFlow::ValueNode { - MethodCallExpr indexOf; - override BitNotExpr astNode; - - Includes_IndexOfBitwise() { - astNode.getOperand() = indexOf and - indexOf.getMethodName() = "indexOf" - } - - override DataFlow::Node getBaseString() { result = indexOf.getReceiver().flow() } - - override DataFlow::Node getSubstring() { result = indexOf.getArgument(0).flow() } - } + DataFlow::Node getSubstring() { result = getContainedNode() } } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 06a0d904261..a8a8356e6e2 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -781,15 +781,18 @@ module TaintTracking { override predicate appliesTo(Configuration cfg) { any() } } - /** A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. */ - class StringInclusionSanitizer extends AdditionalSanitizerGuardNode { - StringOps::Includes includes; + /** DEPRECATED. This class has been renamed to `InclusionSanitizer`. */ + deprecated class StringInclusionSanitizer = InclusionSanitizer; - StringInclusionSanitizer() { this = includes } + /** A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. */ + class InclusionSanitizer extends AdditionalSanitizerGuardNode { + InclusionTest inclusion; + + InclusionSanitizer() { this = inclusion } override predicate sanitizes(boolean outcome, Expr e) { - outcome = includes.getPolarity() and - e = includes.getSubstring().asExpr() + outcome = inclusion.getPolarity() and + e = inclusion.getContainedNode().asExpr() } override predicate appliesTo(Configuration cfg) { any() } From d31ec56ea68b5354d458924a360b36675222935a Mon Sep 17 00:00:00 2001 From: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Thu, 7 Nov 2019 14:39:52 +0000 Subject: [PATCH 0958/1227] Update docs/language/learn-ql/index.rst Co-Authored-By: shati-patel <42641846+shati-patel@users.noreply.github.com> --- docs/language/learn-ql/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/learn-ql/index.rst b/docs/language/learn-ql/index.rst index 5a3c70c4580..add850f5806 100644 --- a/docs/language/learn-ql/index.rst +++ b/docs/language/learn-ql/index.rst @@ -13,7 +13,7 @@ CodeQL is based on a powerful query language called QL. The following topics hel Important - If you've previously used QL, you may notice some slight changes in terms we use to describe some important concepts. For more information, see our note about :doc:`Recent terminology changes `. + If you've previously used QL, you may notice slight changes in terms we use to describe some important concepts. For more information, see our note about :doc:`Recent terminology changes `. .. toctree:: :hidden: @@ -98,4 +98,4 @@ Search .. * :ref:`genindex` remove index for the time being as we currently have no tags -* :ref:`search` \ No newline at end of file +* :ref:`search` From 8178e3e67117ed4af20b7a2c5320a01ae86c811f Mon Sep 17 00:00:00 2001 From: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Thu, 7 Nov 2019 14:40:04 +0000 Subject: [PATCH 0959/1227] Update docs/language/learn-ql/terminology-note.rst Co-Authored-By: shati-patel <42641846+shati-patel@users.noreply.github.com> --- docs/language/learn-ql/terminology-note.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/terminology-note.rst b/docs/language/learn-ql/terminology-note.rst index 794106d5705..552d7b2789c 100644 --- a/docs/language/learn-ql/terminology-note.rst +++ b/docs/language/learn-ql/terminology-note.rst @@ -24,4 +24,4 @@ QL is a general-purpose, object-oriented language that can be used to query any CodeQL databases ---------------- -QL snapshots have been renamed CodeQL databases. CodeQL databases contain relational data created and analyzed using CodeQL. They are the equivalent of QL snapshots, but have been optimized for use with the CodeQL tools. +QL snapshots have been renamed CodeQL databases. :doc:`CodeQL databases ` contain relational data created and analyzed using CodeQL. They are the equivalent of QL snapshots, but have been optimized for use with the CodeQL tools. From 812ee34bbc14ecefee6d09024e4907479e666678 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 7 Nov 2019 15:53:29 +0000 Subject: [PATCH 0960/1227] JS: Use Files.exists() instead --- javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index e67c4095e19..0f5c4ffbfd6 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -666,7 +666,7 @@ public class AutoBuild { throws IOException { if (!dir.equals(currentRoot[0]) && (excludes.contains(dir) || dir.toFile().isHidden())) return FileVisitResult.SKIP_SUBTREE; - if (dir.resolve("codeql-database.yml").toFile().exists()) { + if (Files.exists(dir.resolve("codeql-database.yml"))) { return FileVisitResult.SKIP_SUBTREE; } return super.preVisitDirectory(dir, attrs); From b5af4e5acd50d5cd19c22c398247fc8a99b11c31 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Thu, 7 Nov 2019 16:32:18 +0000 Subject: [PATCH 0961/1227] C++: Remove tests for CFG differences Now that we have switched over, they are no longer interesting. --- .../syntax-zoo/drawDifferent.expected | 108 ------------------ .../library-tests/syntax-zoo/drawDifferent.ql | 10 -- .../syntax-zoo/tellDifferent.expected | 14 --- .../library-tests/syntax-zoo/tellDifferent.ql | 13 --- 4 files changed, 145 deletions(-) delete mode 100644 cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected delete mode 100644 cpp/ql/test/library-tests/syntax-zoo/drawDifferent.ql delete mode 100644 cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected delete mode 100644 cpp/ql/test/library-tests/syntax-zoo/tellDifferent.ql diff --git a/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected b/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected deleted file mode 100644 index 6e255ec81b2..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected +++ /dev/null @@ -1,108 +0,0 @@ -| pointer_to_member__pmIsConstT_extractor | false | 21747 | 21747 | pmIsConstT | -| pointer_to_member__pmIsConstT_extractor | false | 21756 | 21756 | declaration | -| pointer_to_member__pmIsConstT_extractor | false | 21759 | 21759 | return ... | -| pointer_to_member__pmIsConstT_extractor | false | 21762 | 21762 | { ... } | -| pointer_to_member__pmIsConstT_extractor | false | 21766 | 21766 | {...} | -| pointer_to_member__pmIsConstT_extractor | false | 21773 | 21773 | x1 | -| pointer_to_member__pmIsConstT_extractor | false | 21777 | 21777 | & ... | -| pointer_to_member__pmIsConstT_extractor | false | 21784 | 21784 | f1 | -| pointer_to_member__pmIsConstT_extractor | false | 21788 | 21788 | & ... | -| pointer_to_member__pmIsConstT_extractor | false | 21791 | 21791 | initializer for pms | -| pointer_to_member__pmIsConstT_extractor | true | 21756 | 21759 | | -| pointer_to_member__pmIsConstT_extractor | true | 21759 | 21747 | | -| pointer_to_member__pmIsConstT_extractor | true | 21762 | 21756 | | -| pointer_to_member__pmIsConstT_ql | false | 21747 | 21747 | pmIsConstT | -| pointer_to_member__pmIsConstT_ql | false | 21756 | 21756 | declaration | -| pointer_to_member__pmIsConstT_ql | false | 21759 | 21759 | return ... | -| pointer_to_member__pmIsConstT_ql | false | 21762 | 21762 | { ... } | -| pointer_to_member__pmIsConstT_ql | false | 21766 | 21766 | {...} | -| pointer_to_member__pmIsConstT_ql | false | 21773 | 21773 | x1 | -| pointer_to_member__pmIsConstT_ql | false | 21777 | 21777 | & ... | -| pointer_to_member__pmIsConstT_ql | false | 21784 | 21784 | f1 | -| pointer_to_member__pmIsConstT_ql | false | 21788 | 21788 | & ... | -| pointer_to_member__pmIsConstT_ql | false | 21791 | 21791 | initializer for pms | -| pointer_to_member__pmIsConstT_ql | true | 21756 | 21791 | | -| pointer_to_member__pmIsConstT_ql | true | 21759 | 21747 | | -| pointer_to_member__pmIsConstT_ql | true | 21762 | 21756 | | -| pointer_to_member__pmIsConstT_ql | true | 21766 | 21759 | | -| pointer_to_member__pmIsConstT_ql | true | 21773 | 21777 | | -| pointer_to_member__pmIsConstT_ql | true | 21777 | 21784 | | -| pointer_to_member__pmIsConstT_ql | true | 21784 | 21788 | | -| pointer_to_member__pmIsConstT_ql | true | 21788 | 21766 | | -| pointer_to_member__pmIsConstT_ql | true | 21791 | 21773 | | -| staticlocals__staticlocals_f2_extractor | false | 31503 | 31503 | f2 | -| staticlocals__staticlocals_f2_extractor | false | 31509 | 31509 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 31512 | 31512 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 31515 | 31515 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 31518 | 31518 | declaration | -| staticlocals__staticlocals_f2_extractor | false | 31521 | 31521 | return ... | -| staticlocals__staticlocals_f2_extractor | false | 31524 | 31524 | { ... } | -| staticlocals__staticlocals_f2_extractor | false | 31527 | 31527 | call to C | -| staticlocals__staticlocals_f2_extractor | false | 31530 | 31530 | initializer for c | -| staticlocals__staticlocals_f2_extractor | false | 31533 | 31533 | call to addOne | -| staticlocals__staticlocals_f2_extractor | false | 31539 | 31539 | 2 | -| staticlocals__staticlocals_f2_extractor | false | 31544 | 31544 | initializer for j | -| staticlocals__staticlocals_f2_extractor | false | 31546 | 31546 | call to addOne | -| staticlocals__staticlocals_f2_extractor | false | 31554 | 31554 | 2 | -| staticlocals__staticlocals_f2_extractor | false | 31556 | 31556 | initializer for two | -| staticlocals__staticlocals_f2_extractor | false | 31560 | 31560 | two | -| staticlocals__staticlocals_f2_extractor | false | 31568 | 31568 | initializer for i | -| staticlocals__staticlocals_f2_extractor | true | 31509 | 31556 | | -| staticlocals__staticlocals_f2_extractor | true | 31512 | 31515 | | -| staticlocals__staticlocals_f2_extractor | true | 31515 | 31518 | | -| staticlocals__staticlocals_f2_extractor | true | 31518 | 31521 | | -| staticlocals__staticlocals_f2_extractor | true | 31521 | 31503 | | -| staticlocals__staticlocals_f2_extractor | true | 31524 | 31509 | | -| staticlocals__staticlocals_f2_extractor | true | 31554 | 31512 | | -| staticlocals__staticlocals_f2_extractor | true | 31556 | 31554 | | -| staticlocals__staticlocals_f2_ql | false | 31503 | 31503 | f2 | -| staticlocals__staticlocals_f2_ql | false | 31509 | 31509 | declaration | -| staticlocals__staticlocals_f2_ql | false | 31512 | 31512 | declaration | -| staticlocals__staticlocals_f2_ql | false | 31515 | 31515 | declaration | -| staticlocals__staticlocals_f2_ql | false | 31518 | 31518 | declaration | -| staticlocals__staticlocals_f2_ql | false | 31521 | 31521 | return ... | -| staticlocals__staticlocals_f2_ql | false | 31524 | 31524 | { ... } | -| staticlocals__staticlocals_f2_ql | false | 31527 | 31527 | call to C | -| staticlocals__staticlocals_f2_ql | false | 31530 | 31530 | initializer for c | -| staticlocals__staticlocals_f2_ql | false | 31533 | 31533 | call to addOne | -| staticlocals__staticlocals_f2_ql | false | 31539 | 31539 | 2 | -| staticlocals__staticlocals_f2_ql | false | 31544 | 31544 | initializer for j | -| staticlocals__staticlocals_f2_ql | false | 31546 | 31546 | call to addOne | -| staticlocals__staticlocals_f2_ql | false | 31554 | 31554 | 2 | -| staticlocals__staticlocals_f2_ql | false | 31556 | 31556 | initializer for two | -| staticlocals__staticlocals_f2_ql | false | 31560 | 31560 | two | -| staticlocals__staticlocals_f2_ql | false | 31568 | 31568 | initializer for i | -| staticlocals__staticlocals_f2_ql | true | 31509 | 31556 | | -| staticlocals__staticlocals_f2_ql | true | 31512 | 31515 | | -| staticlocals__staticlocals_f2_ql | true | 31515 | 31518 | | -| staticlocals__staticlocals_f2_ql | true | 31518 | 31521 | | -| staticlocals__staticlocals_f2_ql | true | 31518 | 31530 | | -| staticlocals__staticlocals_f2_ql | true | 31521 | 31503 | | -| staticlocals__staticlocals_f2_ql | true | 31524 | 31509 | | -| staticlocals__staticlocals_f2_ql | true | 31527 | 31521 | | -| staticlocals__staticlocals_f2_ql | true | 31530 | 31527 | | -| staticlocals__staticlocals_f2_ql | true | 31554 | 31512 | | -| staticlocals__staticlocals_f2_ql | true | 31556 | 31554 | | -| staticlocals__staticlocals_f3_extractor | false | 31473 | 31473 | f3 | -| staticlocals__staticlocals_f3_extractor | false | 31477 | 31477 | declaration | -| staticlocals__staticlocals_f3_extractor | false | 31480 | 31480 | return ... | -| staticlocals__staticlocals_f3_extractor | false | 31483 | 31483 | { ... } | -| staticlocals__staticlocals_f3_extractor | false | 31492 | 31492 | value | -| staticlocals__staticlocals_f3_extractor | false | 31496 | 31496 | (int)... | -| staticlocals__staticlocals_f3_extractor | false | 31498 | 31498 | initializer for i | -| staticlocals__staticlocals_f3_extractor | true | 31477 | 31480 | | -| staticlocals__staticlocals_f3_extractor | true | 31480 | 31473 | | -| staticlocals__staticlocals_f3_extractor | true | 31483 | 31477 | | -| staticlocals__staticlocals_f3_ql | false | 31473 | 31473 | f3 | -| staticlocals__staticlocals_f3_ql | false | 31477 | 31477 | declaration | -| staticlocals__staticlocals_f3_ql | false | 31480 | 31480 | return ... | -| staticlocals__staticlocals_f3_ql | false | 31483 | 31483 | { ... } | -| staticlocals__staticlocals_f3_ql | false | 31492 | 31492 | value | -| staticlocals__staticlocals_f3_ql | false | 31496 | 31496 | (int)... | -| staticlocals__staticlocals_f3_ql | false | 31498 | 31498 | initializer for i | -| staticlocals__staticlocals_f3_ql | true | 31477 | 31480 | | -| staticlocals__staticlocals_f3_ql | true | 31477 | 31498 | | -| staticlocals__staticlocals_f3_ql | true | 31480 | 31473 | | -| staticlocals__staticlocals_f3_ql | true | 31483 | 31477 | | -| staticlocals__staticlocals_f3_ql | true | 31492 | 31480 | | -| staticlocals__staticlocals_f3_ql | true | 31498 | 31492 | | diff --git a/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.ql b/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.ql deleted file mode 100644 index 5b80f3c92a0..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.ql +++ /dev/null @@ -1,10 +0,0 @@ -// query-type: graph -import Compare - -from - Element scopeElement, string scopeString, boolean isEdge, ControlFlowNode x, ControlFlowNode y, - string label -where - AllCFG::qltestGraph(scopeElement, scopeString, isEdge, x, y, label) and - differentScope(scopeElement) -select scopeString, isEdge, x, y, label diff --git a/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected b/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected deleted file mode 100644 index ae6f3429892..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected +++ /dev/null @@ -1,14 +0,0 @@ -| pointer_to_member__pmIsConstT | pointer_to_member.cpp:41:3:44:29 | declaration | pointer_to_member.cpp:44:11:44:28 | initializer for pms | Standard edge, only from QL | uninstantiated | -| pointer_to_member__pmIsConstT | pointer_to_member.cpp:41:3:44:29 | declaration | pointer_to_member.cpp:45:1:45:1 | return ... | Standard edge, only from extractor | uninstantiated | -| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:11:44:28 | initializer for pms | pointer_to_member.cpp:44:14:44:18 | x1 | Standard edge, only from QL | uninstantiated | -| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:11:44:28 | {...} | pointer_to_member.cpp:45:1:45:1 | return ... | Standard edge, only from QL | uninstantiated | -| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:13:44:18 | & ... | pointer_to_member.cpp:44:22:44:26 | f1 | Standard edge, only from QL | uninstantiated | -| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:14:44:18 | x1 | pointer_to_member.cpp:44:13:44:18 | & ... | Standard edge, only from QL | uninstantiated | -| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:21:44:26 | & ... | pointer_to_member.cpp:44:11:44:28 | {...} | Standard edge, only from QL | uninstantiated | -| pointer_to_member__pmIsConstT | pointer_to_member.cpp:44:22:44:26 | f1 | pointer_to_member.cpp:44:21:44:26 | & ... | Standard edge, only from QL | uninstantiated | -| staticlocals__staticlocals_f2 | file://:0:0:0:0 | call to C | staticlocals.cpp:30:1:30:1 | return ... | Standard edge, only from QL | | -| staticlocals__staticlocals_f2 | file://:0:0:0:0 | initializer for c | file://:0:0:0:0 | call to C | Standard edge, only from QL | | -| staticlocals__staticlocals_f2 | staticlocals.cpp:29:5:29:17 | declaration | file://:0:0:0:0 | initializer for c | Standard edge, only from QL | | -| staticlocals__staticlocals_f3 | staticlocals.cpp:39:3:39:34 | declaration | staticlocals.cpp:39:18:39:33 | initializer for i | Standard edge, only from QL | uninstantiated | -| staticlocals__staticlocals_f3 | staticlocals.cpp:39:18:39:33 | initializer for i | staticlocals.cpp:39:18:39:33 | value | Standard edge, only from QL | uninstantiated | -| staticlocals__staticlocals_f3 | staticlocals.cpp:39:18:39:33 | value | staticlocals.cpp:40:1:40:1 | return ... | Standard edge, only from QL | uninstantiated | diff --git a/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.ql b/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.ql deleted file mode 100644 index f4b2509c17b..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.ql +++ /dev/null @@ -1,13 +0,0 @@ -import Compare - -string describeTemplate(ControlFlowNode node) { - node.isFromTemplateInstantiation(_) and - result = "instantiation" - or - node.isFromUninstantiatedTemplate(_) and - result = "uninstantiated" -} - -from ControlFlowNode n1, ControlFlowNode n2, string msg -where differentEdge(n1, n2, msg) -select getScopeName(n1), n1, n2, msg, concat(describeTemplate(n1), ", ") From ae1377447e925f17a4b61db23f8231dcae1f6915 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 7 Nov 2019 13:55:49 -0800 Subject: [PATCH 0962/1227] C++: only generate uninits when needed --- .../internal/TranslatedDeclarationEntry.qll | 2 +- .../raw/internal/TranslatedInitialization.qll | 2 +- .../test/library-tests/ir/ir/raw_ir.expected | 102 ++++++++-------- .../ir/ssa/aliased_ssa_ir.expected | 114 +++++++++--------- .../ir/ssa/unaliased_ssa_ir.expected | 102 ++++++++-------- 5 files changed, 158 insertions(+), 164 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll index c3572bd0e79..15b5db3ef74 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll @@ -121,7 +121,7 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali private predicate hasUninitializedInstruction() { not exists(getInitialization()) or getInitialization() instanceof TranslatedListInitialization or - getInitialization() instanceof TranslatedStringLiteralInitialization + getInitialization().(TranslatedStringLiteralInitialization).zeroInitRange(_, _) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll index 21ad11513bd..c6911a048c7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -340,7 +340,7 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati * Holds if the `elementCount` array elements starting at `startIndex` must be * zero initialized. */ - private predicate zeroInitRange(int startIndex, int elementCount) { + predicate zeroInitRange(int startIndex, int elementCount) { exists(int targetCount | startIndex = expr.getUnspecifiedType().(ArrayType).getArraySize() and targetCount = getContext().getTargetType().getUnspecifiedType().(ArrayType).getArraySize() and diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index b4480e1c580..e763b3c1263 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -2675,58 +2675,56 @@ ir.cpp: # 572| r0_10(glval) = PointerAdd[1] : r0_3, r0_9 # 572| mu0_11(unknown[31]) = Store : &:r0_10, r0_8 # 573| r0_12(glval) = VariableAddress[a_nopad] : -# 573| mu0_13(char[4]) = Uninitialized[a_nopad] : &:r0_12 -# 573| r0_14(glval) = StringConstant["foo"] : -# 573| r0_15(char[4]) = Load : &:r0_14, ~mu0_2 -# 573| mu0_16(char[4]) = Store : &:r0_12, r0_15 -# 574| r0_17(glval) = VariableAddress[a_infer] : -# 574| mu0_18(char[5]) = Uninitialized[a_infer] : &:r0_17 -# 574| r0_19(glval) = StringConstant["blah"] : -# 574| r0_20(char[5]) = Load : &:r0_19, ~mu0_2 -# 574| mu0_21(char[5]) = Store : &:r0_17, r0_20 -# 575| r0_22(glval) = VariableAddress[b] : -# 575| mu0_23(char[2]) = Uninitialized[b] : &:r0_22 -# 576| r0_24(glval) = VariableAddress[c] : -# 576| mu0_25(char[2]) = Uninitialized[c] : &:r0_24 -# 576| r0_26(int) = Constant[0] : -# 576| r0_27(glval) = PointerAdd[1] : r0_24, r0_26 -# 576| r0_28(unknown[2]) = Constant[0] : -# 576| mu0_29(unknown[2]) = Store : &:r0_27, r0_28 -# 577| r0_30(glval) = VariableAddress[d] : -# 577| mu0_31(char[2]) = Uninitialized[d] : &:r0_30 -# 577| r0_32(int) = Constant[0] : -# 577| r0_33(glval) = PointerAdd[1] : r0_30, r0_32 -# 577| r0_34(char) = Constant[0] : -# 577| mu0_35(char) = Store : &:r0_33, r0_34 -# 577| r0_36(int) = Constant[1] : -# 577| r0_37(glval) = PointerAdd[1] : r0_30, r0_36 -# 577| r0_38(char) = Constant[0] : -# 577| mu0_39(char) = Store : &:r0_37, r0_38 -# 578| r0_40(glval) = VariableAddress[e] : -# 578| mu0_41(char[2]) = Uninitialized[e] : &:r0_40 -# 578| r0_42(int) = Constant[0] : -# 578| r0_43(glval) = PointerAdd[1] : r0_40, r0_42 -# 578| r0_44(char) = Constant[0] : -# 578| mu0_45(char) = Store : &:r0_43, r0_44 -# 578| r0_46(int) = Constant[1] : -# 578| r0_47(glval) = PointerAdd[1] : r0_40, r0_46 -# 578| r0_48(char) = Constant[1] : -# 578| mu0_49(char) = Store : &:r0_47, r0_48 -# 579| r0_50(glval) = VariableAddress[f] : -# 579| mu0_51(char[3]) = Uninitialized[f] : &:r0_50 -# 579| r0_52(int) = Constant[0] : -# 579| r0_53(glval) = PointerAdd[1] : r0_50, r0_52 -# 579| r0_54(char) = Constant[0] : -# 579| mu0_55(char) = Store : &:r0_53, r0_54 -# 579| r0_56(int) = Constant[1] : -# 579| r0_57(glval) = PointerAdd[1] : r0_50, r0_56 -# 579| r0_58(unknown[2]) = Constant[0] : -# 579| mu0_59(unknown[2]) = Store : &:r0_57, r0_58 -# 580| v0_60(void) = NoOp : -# 571| v0_61(void) = ReturnVoid : -# 571| v0_62(void) = UnmodeledUse : mu* -# 571| v0_63(void) = AliasedUse : ~mu0_2 -# 571| v0_64(void) = ExitFunction : +# 573| r0_13(glval) = StringConstant["foo"] : +# 573| r0_14(char[4]) = Load : &:r0_13, ~mu0_2 +# 573| mu0_15(char[4]) = Store : &:r0_12, r0_14 +# 574| r0_16(glval) = VariableAddress[a_infer] : +# 574| r0_17(glval) = StringConstant["blah"] : +# 574| r0_18(char[5]) = Load : &:r0_17, ~mu0_2 +# 574| mu0_19(char[5]) = Store : &:r0_16, r0_18 +# 575| r0_20(glval) = VariableAddress[b] : +# 575| mu0_21(char[2]) = Uninitialized[b] : &:r0_20 +# 576| r0_22(glval) = VariableAddress[c] : +# 576| mu0_23(char[2]) = Uninitialized[c] : &:r0_22 +# 576| r0_24(int) = Constant[0] : +# 576| r0_25(glval) = PointerAdd[1] : r0_22, r0_24 +# 576| r0_26(unknown[2]) = Constant[0] : +# 576| mu0_27(unknown[2]) = Store : &:r0_25, r0_26 +# 577| r0_28(glval) = VariableAddress[d] : +# 577| mu0_29(char[2]) = Uninitialized[d] : &:r0_28 +# 577| r0_30(int) = Constant[0] : +# 577| r0_31(glval) = PointerAdd[1] : r0_28, r0_30 +# 577| r0_32(char) = Constant[0] : +# 577| mu0_33(char) = Store : &:r0_31, r0_32 +# 577| r0_34(int) = Constant[1] : +# 577| r0_35(glval) = PointerAdd[1] : r0_28, r0_34 +# 577| r0_36(char) = Constant[0] : +# 577| mu0_37(char) = Store : &:r0_35, r0_36 +# 578| r0_38(glval) = VariableAddress[e] : +# 578| mu0_39(char[2]) = Uninitialized[e] : &:r0_38 +# 578| r0_40(int) = Constant[0] : +# 578| r0_41(glval) = PointerAdd[1] : r0_38, r0_40 +# 578| r0_42(char) = Constant[0] : +# 578| mu0_43(char) = Store : &:r0_41, r0_42 +# 578| r0_44(int) = Constant[1] : +# 578| r0_45(glval) = PointerAdd[1] : r0_38, r0_44 +# 578| r0_46(char) = Constant[1] : +# 578| mu0_47(char) = Store : &:r0_45, r0_46 +# 579| r0_48(glval) = VariableAddress[f] : +# 579| mu0_49(char[3]) = Uninitialized[f] : &:r0_48 +# 579| r0_50(int) = Constant[0] : +# 579| r0_51(glval) = PointerAdd[1] : r0_48, r0_50 +# 579| r0_52(char) = Constant[0] : +# 579| mu0_53(char) = Store : &:r0_51, r0_52 +# 579| r0_54(int) = Constant[1] : +# 579| r0_55(glval) = PointerAdd[1] : r0_48, r0_54 +# 579| r0_56(unknown[2]) = Constant[0] : +# 579| mu0_57(unknown[2]) = Store : &:r0_55, r0_56 +# 580| v0_58(void) = NoOp : +# 571| v0_59(void) = ReturnVoid : +# 571| v0_60(void) = UnmodeledUse : mu* +# 571| v0_61(void) = AliasedUse : ~mu0_2 +# 571| v0_62(void) = ExitFunction : # 584| void VarArgs() # 584| Block 0 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 bc2bea75e11..893f1a1dd19 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 @@ -887,61 +887,59 @@ ssa.cpp: # 214| m0_12(unknown[31]) = Store : &:r0_11, r0_9 # 214| m0_13(char[32]) = Chi : total:m0_8, partial:m0_12 # 215| r0_14(glval) = VariableAddress[a_nopad] : -# 215| m0_15(char[4]) = Uninitialized[a_nopad] : &:r0_14 -# 215| r0_16(glval) = StringConstant["foo"] : -# 215| r0_17(char[4]) = Load : &:r0_16, ~m0_1 -# 215| m0_18(char[4]) = Store : &:r0_14, r0_17 -# 216| r0_19(glval) = VariableAddress[a_infer] : -# 216| m0_20(char[5]) = Uninitialized[a_infer] : &:r0_19 -# 216| r0_21(glval) = StringConstant["blah"] : -# 216| r0_22(char[5]) = Load : &:r0_21, ~m0_1 -# 216| m0_23(char[5]) = Store : &:r0_19, r0_22 -# 217| r0_24(glval) = VariableAddress[b] : -# 217| m0_25(char[2]) = Uninitialized[b] : &:r0_24 -# 218| r0_26(glval) = VariableAddress[c] : -# 218| m0_27(char[2]) = Uninitialized[c] : &:r0_26 -# 218| r0_28(int) = Constant[0] : -# 218| r0_29(glval) = PointerAdd[1] : r0_26, r0_28 -# 218| r0_30(unknown[2]) = Constant[0] : -# 218| m0_31(unknown[2]) = Store : &:r0_29, r0_30 -# 219| r0_32(glval) = VariableAddress[d] : -# 219| m0_33(char[2]) = Uninitialized[d] : &:r0_32 -# 219| r0_34(int) = Constant[0] : -# 219| r0_35(glval) = PointerAdd[1] : r0_32, r0_34 -# 219| r0_36(char) = Constant[0] : -# 219| m0_37(char) = Store : &:r0_35, r0_36 -# 219| m0_38(char[2]) = Chi : total:m0_33, partial:m0_37 -# 219| r0_39(int) = Constant[1] : -# 219| r0_40(glval) = PointerAdd[1] : r0_32, r0_39 -# 219| r0_41(char) = Constant[0] : -# 219| m0_42(char) = Store : &:r0_40, r0_41 -# 219| m0_43(char[2]) = Chi : total:m0_38, partial:m0_42 -# 220| r0_44(glval) = VariableAddress[e] : -# 220| m0_45(char[2]) = Uninitialized[e] : &:r0_44 -# 220| r0_46(int) = Constant[0] : -# 220| r0_47(glval) = PointerAdd[1] : r0_44, r0_46 -# 220| r0_48(char) = Constant[0] : -# 220| m0_49(char) = Store : &:r0_47, r0_48 -# 220| m0_50(char[2]) = Chi : total:m0_45, partial:m0_49 -# 220| r0_51(int) = Constant[1] : -# 220| r0_52(glval) = PointerAdd[1] : r0_44, r0_51 -# 220| r0_53(char) = Constant[1] : -# 220| m0_54(char) = Store : &:r0_52, r0_53 -# 220| m0_55(char[2]) = Chi : total:m0_50, partial:m0_54 -# 221| r0_56(glval) = VariableAddress[f] : -# 221| m0_57(char[3]) = Uninitialized[f] : &:r0_56 -# 221| r0_58(int) = Constant[0] : -# 221| r0_59(glval) = PointerAdd[1] : r0_56, r0_58 -# 221| r0_60(char) = Constant[0] : -# 221| m0_61(char) = Store : &:r0_59, r0_60 -# 221| m0_62(char[3]) = Chi : total:m0_57, partial:m0_61 -# 221| r0_63(int) = Constant[1] : -# 221| r0_64(glval) = PointerAdd[1] : r0_56, r0_63 -# 221| r0_65(unknown[2]) = Constant[0] : -# 221| m0_66(unknown[2]) = Store : &:r0_64, r0_65 -# 221| m0_67(char[3]) = Chi : total:m0_62, partial:m0_66 -# 222| v0_68(void) = NoOp : -# 213| v0_69(void) = ReturnVoid : -# 213| v0_70(void) = UnmodeledUse : mu* -# 213| v0_71(void) = AliasedUse : ~m0_1 -# 213| v0_72(void) = ExitFunction : +# 215| r0_15(glval) = StringConstant["foo"] : +# 215| r0_16(char[4]) = Load : &:r0_15, ~m0_1 +# 215| m0_17(char[4]) = Store : &:r0_14, r0_16 +# 216| r0_18(glval) = VariableAddress[a_infer] : +# 216| r0_19(glval) = StringConstant["blah"] : +# 216| r0_20(char[5]) = Load : &:r0_19, ~m0_1 +# 216| m0_21(char[5]) = Store : &:r0_18, r0_20 +# 217| r0_22(glval) = VariableAddress[b] : +# 217| m0_23(char[2]) = Uninitialized[b] : &:r0_22 +# 218| r0_24(glval) = VariableAddress[c] : +# 218| m0_25(char[2]) = Uninitialized[c] : &:r0_24 +# 218| r0_26(int) = Constant[0] : +# 218| r0_27(glval) = PointerAdd[1] : r0_24, r0_26 +# 218| r0_28(unknown[2]) = Constant[0] : +# 218| m0_29(unknown[2]) = Store : &:r0_27, r0_28 +# 219| r0_30(glval) = VariableAddress[d] : +# 219| m0_31(char[2]) = Uninitialized[d] : &:r0_30 +# 219| r0_32(int) = Constant[0] : +# 219| r0_33(glval) = PointerAdd[1] : r0_30, r0_32 +# 219| r0_34(char) = Constant[0] : +# 219| m0_35(char) = Store : &:r0_33, r0_34 +# 219| m0_36(char[2]) = Chi : total:m0_31, partial:m0_35 +# 219| r0_37(int) = Constant[1] : +# 219| r0_38(glval) = PointerAdd[1] : r0_30, r0_37 +# 219| r0_39(char) = Constant[0] : +# 219| m0_40(char) = Store : &:r0_38, r0_39 +# 219| m0_41(char[2]) = Chi : total:m0_36, partial:m0_40 +# 220| r0_42(glval) = VariableAddress[e] : +# 220| m0_43(char[2]) = Uninitialized[e] : &:r0_42 +# 220| r0_44(int) = Constant[0] : +# 220| r0_45(glval) = PointerAdd[1] : r0_42, r0_44 +# 220| r0_46(char) = Constant[0] : +# 220| m0_47(char) = Store : &:r0_45, r0_46 +# 220| m0_48(char[2]) = Chi : total:m0_43, partial:m0_47 +# 220| r0_49(int) = Constant[1] : +# 220| r0_50(glval) = PointerAdd[1] : r0_42, r0_49 +# 220| r0_51(char) = Constant[1] : +# 220| m0_52(char) = Store : &:r0_50, r0_51 +# 220| m0_53(char[2]) = Chi : total:m0_48, partial:m0_52 +# 221| r0_54(glval) = VariableAddress[f] : +# 221| m0_55(char[3]) = Uninitialized[f] : &:r0_54 +# 221| r0_56(int) = Constant[0] : +# 221| r0_57(glval) = PointerAdd[1] : r0_54, r0_56 +# 221| r0_58(char) = Constant[0] : +# 221| m0_59(char) = Store : &:r0_57, r0_58 +# 221| m0_60(char[3]) = Chi : total:m0_55, partial:m0_59 +# 221| r0_61(int) = Constant[1] : +# 221| r0_62(glval) = PointerAdd[1] : r0_54, r0_61 +# 221| r0_63(unknown[2]) = Constant[0] : +# 221| m0_64(unknown[2]) = Store : &:r0_62, r0_63 +# 221| m0_65(char[3]) = Chi : total:m0_60, partial:m0_64 +# 222| v0_66(void) = NoOp : +# 213| v0_67(void) = ReturnVoid : +# 213| v0_68(void) = UnmodeledUse : mu* +# 213| v0_69(void) = AliasedUse : ~m0_1 +# 213| v0_70(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 93f27b13f02..0014e15c784 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -849,55 +849,53 @@ ssa.cpp: # 214| r0_10(glval) = PointerAdd[1] : r0_3, r0_9 # 214| mu0_11(unknown[31]) = Store : &:r0_10, r0_8 # 215| r0_12(glval) = VariableAddress[a_nopad] : -# 215| m0_13(char[4]) = Uninitialized[a_nopad] : &:r0_12 -# 215| r0_14(glval) = StringConstant["foo"] : -# 215| r0_15(char[4]) = Load : &:r0_14, ~mu0_2 -# 215| m0_16(char[4]) = Store : &:r0_12, r0_15 -# 216| r0_17(glval) = VariableAddress[a_infer] : -# 216| m0_18(char[5]) = Uninitialized[a_infer] : &:r0_17 -# 216| r0_19(glval) = StringConstant["blah"] : -# 216| r0_20(char[5]) = Load : &:r0_19, ~mu0_2 -# 216| m0_21(char[5]) = Store : &:r0_17, r0_20 -# 217| r0_22(glval) = VariableAddress[b] : -# 217| m0_23(char[2]) = Uninitialized[b] : &:r0_22 -# 218| r0_24(glval) = VariableAddress[c] : -# 218| mu0_25(char[2]) = Uninitialized[c] : &:r0_24 -# 218| r0_26(int) = Constant[0] : -# 218| r0_27(glval) = PointerAdd[1] : r0_24, r0_26 -# 218| r0_28(unknown[2]) = Constant[0] : -# 218| mu0_29(unknown[2]) = Store : &:r0_27, r0_28 -# 219| r0_30(glval) = VariableAddress[d] : -# 219| mu0_31(char[2]) = Uninitialized[d] : &:r0_30 -# 219| r0_32(int) = Constant[0] : -# 219| r0_33(glval) = PointerAdd[1] : r0_30, r0_32 -# 219| r0_34(char) = Constant[0] : -# 219| mu0_35(char) = Store : &:r0_33, r0_34 -# 219| r0_36(int) = Constant[1] : -# 219| r0_37(glval) = PointerAdd[1] : r0_30, r0_36 -# 219| r0_38(char) = Constant[0] : -# 219| mu0_39(char) = Store : &:r0_37, r0_38 -# 220| r0_40(glval) = VariableAddress[e] : -# 220| mu0_41(char[2]) = Uninitialized[e] : &:r0_40 -# 220| r0_42(int) = Constant[0] : -# 220| r0_43(glval) = PointerAdd[1] : r0_40, r0_42 -# 220| r0_44(char) = Constant[0] : -# 220| mu0_45(char) = Store : &:r0_43, r0_44 -# 220| r0_46(int) = Constant[1] : -# 220| r0_47(glval) = PointerAdd[1] : r0_40, r0_46 -# 220| r0_48(char) = Constant[1] : -# 220| mu0_49(char) = Store : &:r0_47, r0_48 -# 221| r0_50(glval) = VariableAddress[f] : -# 221| mu0_51(char[3]) = Uninitialized[f] : &:r0_50 -# 221| r0_52(int) = Constant[0] : -# 221| r0_53(glval) = PointerAdd[1] : r0_50, r0_52 -# 221| r0_54(char) = Constant[0] : -# 221| mu0_55(char) = Store : &:r0_53, r0_54 -# 221| r0_56(int) = Constant[1] : -# 221| r0_57(glval) = PointerAdd[1] : r0_50, r0_56 -# 221| r0_58(unknown[2]) = Constant[0] : -# 221| mu0_59(unknown[2]) = Store : &:r0_57, r0_58 -# 222| v0_60(void) = NoOp : -# 213| v0_61(void) = ReturnVoid : -# 213| v0_62(void) = UnmodeledUse : mu* -# 213| v0_63(void) = AliasedUse : ~mu0_2 -# 213| v0_64(void) = ExitFunction : +# 215| r0_13(glval) = StringConstant["foo"] : +# 215| r0_14(char[4]) = Load : &:r0_13, ~mu0_2 +# 215| m0_15(char[4]) = Store : &:r0_12, r0_14 +# 216| r0_16(glval) = VariableAddress[a_infer] : +# 216| r0_17(glval) = StringConstant["blah"] : +# 216| r0_18(char[5]) = Load : &:r0_17, ~mu0_2 +# 216| m0_19(char[5]) = Store : &:r0_16, r0_18 +# 217| r0_20(glval) = VariableAddress[b] : +# 217| m0_21(char[2]) = Uninitialized[b] : &:r0_20 +# 218| r0_22(glval) = VariableAddress[c] : +# 218| mu0_23(char[2]) = Uninitialized[c] : &:r0_22 +# 218| r0_24(int) = Constant[0] : +# 218| r0_25(glval) = PointerAdd[1] : r0_22, r0_24 +# 218| r0_26(unknown[2]) = Constant[0] : +# 218| mu0_27(unknown[2]) = Store : &:r0_25, r0_26 +# 219| r0_28(glval) = VariableAddress[d] : +# 219| mu0_29(char[2]) = Uninitialized[d] : &:r0_28 +# 219| r0_30(int) = Constant[0] : +# 219| r0_31(glval) = PointerAdd[1] : r0_28, r0_30 +# 219| r0_32(char) = Constant[0] : +# 219| mu0_33(char) = Store : &:r0_31, r0_32 +# 219| r0_34(int) = Constant[1] : +# 219| r0_35(glval) = PointerAdd[1] : r0_28, r0_34 +# 219| r0_36(char) = Constant[0] : +# 219| mu0_37(char) = Store : &:r0_35, r0_36 +# 220| r0_38(glval) = VariableAddress[e] : +# 220| mu0_39(char[2]) = Uninitialized[e] : &:r0_38 +# 220| r0_40(int) = Constant[0] : +# 220| r0_41(glval) = PointerAdd[1] : r0_38, r0_40 +# 220| r0_42(char) = Constant[0] : +# 220| mu0_43(char) = Store : &:r0_41, r0_42 +# 220| r0_44(int) = Constant[1] : +# 220| r0_45(glval) = PointerAdd[1] : r0_38, r0_44 +# 220| r0_46(char) = Constant[1] : +# 220| mu0_47(char) = Store : &:r0_45, r0_46 +# 221| r0_48(glval) = VariableAddress[f] : +# 221| mu0_49(char[3]) = Uninitialized[f] : &:r0_48 +# 221| r0_50(int) = Constant[0] : +# 221| r0_51(glval) = PointerAdd[1] : r0_48, r0_50 +# 221| r0_52(char) = Constant[0] : +# 221| mu0_53(char) = Store : &:r0_51, r0_52 +# 221| r0_54(int) = Constant[1] : +# 221| r0_55(glval) = PointerAdd[1] : r0_48, r0_54 +# 221| r0_56(unknown[2]) = Constant[0] : +# 221| mu0_57(unknown[2]) = Store : &:r0_55, r0_56 +# 222| v0_58(void) = NoOp : +# 213| v0_59(void) = ReturnVoid : +# 213| v0_60(void) = UnmodeledUse : mu* +# 213| v0_61(void) = AliasedUse : ~mu0_2 +# 213| v0_62(void) = ExitFunction : From 4ea8569081e003e4fb274c3d03e709ea7ba86fe4 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Thu, 7 Nov 2019 16:40:03 -0800 Subject: [PATCH 0963/1227] [CPP-434] Squelch query alerts if ALL files were compiled with `-fwrapv` or `-fno-strict-overflow` --- cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql index bd79a114172..648846a7dc1 100644 --- a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql +++ b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql @@ -23,5 +23,9 @@ where globalValueNumber(expr1) = globalValueNumber(expr2) and add.getUnspecifiedType().(IntegralType).isSigned() and not exists(MacroInvocation mi | mi.getAnAffectedElement() = add) and - exprMightOverflowPositively(add) + exprMightOverflowPositively(add) and + exists(Compilation c | c.getAFileCompiled() = ro.getFile() | + not c.getAnArgument() = "-fwrapv" and + not c.getAnArgument() = "-fno-strict-overflow" + ) select ro, "Testing for signed overflow may produce undefined results." From 17f76c251679acdb09ff7dc30ccc71aa6c2aa7c2 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 7 Nov 2019 22:02:15 -0700 Subject: [PATCH 0964/1227] C++: Fix merge conflicts --- .../ir/ssa/aliased_ssa_ir.expected | 26 +++++++++++++++++++ .../ir/ssa/unaliased_ssa_ir.expected | 25 ++++++++++++++++++ 2 files changed, 51 insertions(+) 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 46f8cf19aea..f306d3e14c2 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 @@ -877,3 +877,29 @@ ssa.cpp: # 207| v0_27(void) = UnmodeledUse : mu* # 207| v0_28(void) = AliasedUse : ~m0_1 # 207| v0_29(void) = ExitFunction : + +# 215| char StringLiteralAliasing() +# 215| Block 0 +# 215| v0_0(void) = EnterFunction : +# 215| m0_1(unknown) = AliasedDefinition : +# 215| mu0_2(unknown) = UnmodeledDefinition : +# 216| r0_3(glval) = FunctionAddress[ExternalFunc] : +# 216| v0_4(void) = Call : func:r0_3 +# 216| m0_5(unknown) = ^CallSideEffect : ~m0_1 +# 216| m0_6(unknown) = Chi : total:m0_1, partial:m0_5 +# 218| r0_7(glval) = VariableAddress[s] : +# 218| r0_8(glval) = StringConstant["Literal"] : +# 218| r0_9(char *) = Convert : r0_8 +# 218| m0_10(char *) = Store : &:r0_7, r0_9 +# 219| r0_11(glval) = VariableAddress[#return] : +# 219| r0_12(glval) = VariableAddress[s] : +# 219| r0_13(char *) = Load : &:r0_12, m0_10 +# 219| r0_14(int) = Constant[2] : +# 219| r0_15(glval) = PointerAdd[1] : r0_13, r0_14 +# 219| r0_16(char) = Load : &:r0_15, ~m0_1 +# 219| m0_17(char) = Store : &:r0_11, r0_16 +# 215| r0_18(glval) = VariableAddress[#return] : +# 215| v0_19(void) = ReturnValue : &:r0_18, m0_17 +# 215| v0_20(void) = UnmodeledUse : mu* +# 215| v0_21(void) = AliasedUse : ~m0_6 +# 215| v0_22(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 7aae6b70dfd..48d698a1291 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -841,3 +841,28 @@ ssa.cpp: # 207| v0_24(void) = UnmodeledUse : mu* # 207| v0_25(void) = AliasedUse : ~mu0_2 # 207| v0_26(void) = ExitFunction : + +# 215| char StringLiteralAliasing() +# 215| Block 0 +# 215| v0_0(void) = EnterFunction : +# 215| mu0_1(unknown) = AliasedDefinition : +# 215| mu0_2(unknown) = UnmodeledDefinition : +# 216| r0_3(glval) = FunctionAddress[ExternalFunc] : +# 216| v0_4(void) = Call : func:r0_3 +# 216| mu0_5(unknown) = ^CallSideEffect : ~mu0_2 +# 218| r0_6(glval) = VariableAddress[s] : +# 218| r0_7(glval) = StringConstant["Literal"] : +# 218| r0_8(char *) = Convert : r0_7 +# 218| m0_9(char *) = Store : &:r0_6, r0_8 +# 219| r0_10(glval) = VariableAddress[#return] : +# 219| r0_11(glval) = VariableAddress[s] : +# 219| r0_12(char *) = Load : &:r0_11, m0_9 +# 219| r0_13(int) = Constant[2] : +# 219| r0_14(glval) = PointerAdd[1] : r0_12, r0_13 +# 219| r0_15(char) = Load : &:r0_14, ~mu0_2 +# 219| m0_16(char) = Store : &:r0_10, r0_15 +# 215| r0_17(glval) = VariableAddress[#return] : +# 215| v0_18(void) = ReturnValue : &:r0_17, m0_16 +# 215| v0_19(void) = UnmodeledUse : mu* +# 215| v0_20(void) = AliasedUse : ~mu0_2 +# 215| v0_21(void) = ExitFunction : From e8510fe71a3c4fc1eab65e9a1f6095213dacb3b2 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 8 Nov 2019 09:17:05 +0000 Subject: [PATCH 0965/1227] TypeScript: Skip Touchstone files. --- .../semmle/js/extractor/FileExtractor.java | 28 +++++++++++++------ .../tests/ts/input/touchstone-file.ts | 2 ++ .../tests/ts/input/touchstone-file2.ts | 1 + 3 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 javascript/extractor/tests/ts/input/touchstone-file.ts create mode 100644 javascript/extractor/tests/ts/input/touchstone-file2.ts diff --git a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java index d80ddeaf303..278a7ec2e63 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java @@ -1,5 +1,16 @@ package com.semmle.js.extractor; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.regex.Pattern; + import com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase; import com.semmle.js.extractor.trapcache.CachingTrapWriter; import com.semmle.js.extractor.trapcache.ITrapCache; @@ -10,15 +21,6 @@ import com.semmle.util.files.FileUtil; import com.semmle.util.io.WholeIO; import com.semmle.util.trap.TrapWriter; import com.semmle.util.trap.TrapWriter.Label; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileReader; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.regex.Pattern; /** * The file extractor extracts a single file and handles source archive population and TRAP caching; @@ -167,6 +169,9 @@ public class FileExtractor { return true; } + // Avoid Touchstone files + if (isTouchstone(bytes, length)) return true; + return false; } catch (IOException e) { Exceptions.ignore(e, "Let extractor handle this one."); @@ -198,6 +203,11 @@ public class FileExtractor { return false; } + private boolean isTouchstone(byte[] bytes, int length) { + String s = new String(bytes, 0, length, StandardCharsets.US_ASCII); + return s.startsWith("! TOUCHSTONE file ") || s.startsWith("[Version] 2.0"); + } + /** * Returns true if the byte sequence contains invalid UTF-8 or unprintable ASCII characters. */ diff --git a/javascript/extractor/tests/ts/input/touchstone-file.ts b/javascript/extractor/tests/ts/input/touchstone-file.ts new file mode 100644 index 00000000000..a72a1dc56af --- /dev/null +++ b/javascript/extractor/tests/ts/input/touchstone-file.ts @@ -0,0 +1,2 @@ +! TOUCHSTONE file generated by me +[Version] 2.0 diff --git a/javascript/extractor/tests/ts/input/touchstone-file2.ts b/javascript/extractor/tests/ts/input/touchstone-file2.ts new file mode 100644 index 00000000000..d642e0260b1 --- /dev/null +++ b/javascript/extractor/tests/ts/input/touchstone-file2.ts @@ -0,0 +1 @@ +[Version] 2.0 From 0554de06a13b5ded396d693a8f218f310587f790 Mon Sep 17 00:00:00 2001 From: james Date: Fri, 8 Nov 2019 09:32:20 +0000 Subject: [PATCH 0966/1227] docs: update banner links --- docs/language/global-sphinx-files/_templates/layout.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/global-sphinx-files/_templates/layout.html b/docs/language/global-sphinx-files/_templates/layout.html index de3b189e1ee..000503e5798 100644 --- a/docs/language/global-sphinx-files/_templates/layout.html +++ b/docs/language/global-sphinx-files/_templates/layout.html @@ -62,8 +62,8 @@
    protected static void BuildMethodId(Method m, TextWriter trapFile) { + // AddSignatureTypeToId(m.Context, trapFile, m.symbol, m.ContainingType.symbol, false); trapFile.WriteSubId(m.ContainingType); AddExplicitInterfaceQualifierToId(m.Context, trapFile, m.symbol.ExplicitInterfaceImplementations); @@ -129,7 +130,7 @@ namespace Semmle.Extraction.CSharp.Entities // Type arguments with different nullability can result in // a constructed method with different nullability of its parameters and return type, // so we need to create a distinct database entity for it. - trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); trapFile.Write((int)ta.Nullability); }); + trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol, TypeNameContext.MethodName); trapFile.Write((int)ta.Nullability); }); trapFile.Write('>'); } } @@ -199,12 +200,12 @@ namespace Semmle.Extraction.CSharp.Entities /// to make the reference to #3 in the label definition #4 for /// T valid. /// - protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type) + protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type, TypeNameContext assemblyPrefix) { if (type.ContainsTypeParameters(cx, method)) - type.BuildTypeId(cx, trapFile, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0)); + type.BuildTypeId(cx, trapFile, (cx0, tb0, type0, _) => AddSignatureTypeToId(cx, tb0, method, type0, assemblyPrefix), assemblyPrefix, method); else - trapFile.WriteSubId(Type.Create(cx, type)); + trapFile.WriteSubId(Type.Create(cx, type).TypeRef); } protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method) @@ -215,13 +216,13 @@ namespace Semmle.Extraction.CSharp.Entities if (method.MethodKind == MethodKind.ReducedExtension) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType); + AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, TypeNameContext.MethodParam); } foreach (var param in method.Parameters) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, param.Type); + AddSignatureTypeToId(cx, trapFile, method, param.Type, TypeNameContext.MethodParam); switch (param.RefKind) { case RefKind.Out: @@ -345,11 +346,10 @@ namespace Semmle.Extraction.CSharp.Entities foreach (var tp in symbol.GetAnnotatedTypeArguments()) { trapFile.type_arguments(Type.Create(Context, tp.Symbol), child, this); - var ta = tp.Nullability.GetTypeAnnotation(); - if (ta != Kinds.TypeAnnotation.None) - trapFile.type_argument_annotation(this, child, ta); child++; } + + trapFile.type_nullability(this, NullabilityEntity.Create(Context, new Nullability(symbol))); } else { @@ -380,7 +380,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulateMethodBody(trapFile); PopulateGenerics(trapFile); PopulateMetadataHandle(trapFile); - PopulateNullability(trapFile, symbol.ReturnNullableAnnotation); + PopulateNullability(trapFile, symbol.GetAnnotatedReturnType()); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.PushesLabel; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index efb88840e03..c353ea34c16 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -86,7 +86,8 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.Write(";parameter"); } - public override bool NeedsPopulation => true; + // If we don't have the type of the parameter, do not populate it. + public override bool NeedsPopulation => symbol.Type.TypeKind != TypeKind.Error; string Name { @@ -103,7 +104,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate(TextWriter trapFile) { PopulateAttributes(); - PopulateNullability(trapFile, symbol.NullableAnnotation); + PopulateNullability(trapFile, symbol.GetAnnotatedType()); PopulateRefKind(trapFile, symbol.RefKind); if (symbol.Name != Original.symbol.Name) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index 900a313fe92..e1822504120 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -15,6 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { + // trapFile.WriteSubId(ContainingType.TypeRef); trapFile.WriteSubId(ContainingType); trapFile.Write('.'); Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations); @@ -28,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulateAttributes(); PopulateModifiers(trapFile); BindComments(); - PopulateNullability(trapFile, symbol.NullableAnnotation); + PopulateNullability(trapFile, symbol.GetAnnotatedType()); PopulateRefKind(trapFile, symbol.RefKind); var type = Type.Create(Context, symbol.Type); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs index ddd1c79faf8..4d37d4f1d38 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs @@ -28,11 +28,14 @@ namespace Semmle.Extraction.CSharp.Entities Attribute.ExtractAttributes(Context, symbol, this); } - protected void PopulateNullability(TextWriter trapFile, NullableAnnotation annotation) + protected void PopulateNullability(TextWriter trapFile, AnnotatedTypeSymbol type) { - var ta = annotation.GetTypeAnnotation(); - if (ta != Kinds.TypeAnnotation.None) - trapFile.type_annotation(this, ta); + var ta = type.Nullability.GetTypeAnnotation(); + var n = NullabilityEntity.Create(Context, Nullability.Create(type)); + if (ta != Kinds.TypeAnnotation.None || !type.HasConsistentNullability()) + { + trapFile.type_nullability(this, n); + } } protected void PopulateRefKind(TextWriter trapFile, RefKind kind) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs index 6e7b6f4d92c..c4a79a7764b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/ArrayType.cs @@ -27,13 +27,11 @@ namespace Semmle.Extraction.CSharp.Entities { trapFile.array_element_type(this, Dimension, Rank, element.Type.TypeRef); PopulateType(trapFile); - PopulateNullability(trapFile, symbol.ElementNullableAnnotation); } public override void WriteId(TextWriter trapFile) { trapFile.WriteSubId(element.Type); - trapFile.Write((int)symbol.ElementNullableAnnotation); symbol.BuildArraySuffix(trapFile); trapFile.Write(";type"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index 416fb34f224..ca82da2ecc4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -57,9 +57,6 @@ namespace Semmle.Extraction.CSharp.Entities for (int i = 0; i < symbol.TypeArguments.Length; ++i) { - var ta = symbol.TypeArgumentsNullableAnnotations[i].GetTypeAnnotation(); - if (ta != Kinds.TypeAnnotation.None) - trapFile.type_argument_annotation(this, i, ta); trapFile.type_arguments(TypeArguments[i].TypeRef, i, this); } } @@ -114,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); + symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeNameContext.TypeName, symbol); trapFile.Write(";type"); } @@ -154,33 +151,40 @@ namespace Semmle.Extraction.CSharp.Entities public NamedType Create(Context cx, INamedTypeSymbol init) => new NamedType(cx, init); } - public override Type TypeRef => NamedTypeRef.Create(Context, symbol); + public override Type TypeRef => NamedTypeRef.Create(Context, this, symbol); } - class NamedTypeRef : Type + class NamedTypeRef : Type { readonly Type referencedType; - public NamedTypeRef(Context cx, INamedTypeSymbol symbol) : base(cx, symbol) + public NamedTypeRef(Context cx, Type type, ITypeSymbol symbol) : base(cx, symbol) { - referencedType = Type.Create(cx, symbol); + referencedType = type; } - public static NamedTypeRef Create(Context cx, INamedTypeSymbol type) => NamedTypeRefFactory.Instance.CreateEntity2(cx, type); + public static NamedTypeRef Create(Context cx, Type referencedType, ITypeSymbol type) => + NamedTypeRefFactory.Instance.CreateEntity2(cx, (referencedType, type)); - class NamedTypeRefFactory : ICachedEntityFactory + class NamedTypeRefFactory : ICachedEntityFactory<(Type, ITypeSymbol), NamedTypeRef> { public static readonly NamedTypeRefFactory Instance = new NamedTypeRefFactory(); - public NamedTypeRef Create(Context cx, INamedTypeSymbol init) => new NamedTypeRef(cx, init); + public NamedTypeRef Create(Context cx, (Type, ITypeSymbol) init) => new NamedTypeRef(cx, init.Item1, init.Item2); } public override bool NeedsPopulation => true; public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(referencedType); - trapFile.Write(";typeRef"); + void ExpandType(Context cx0, TextWriter tb0, ITypeSymbol sub, ISymbol gc) + { + sub.BuildTypeId(cx0, tb0, ExpandType, TypeNameContext.TypeRef, gc); + } + + // Prefix anonymous types because they shouldn't be visible outside of the current assembly. + symbol.BuildTypeId(Context, trapFile, ExpandType, TypeNameContext.TypeRef, symbol); + trapFile.Write(";typeref"); } public override void Populate(TextWriter trapFile) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index de6ea217084..7adfa6ab8e7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); + symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeNameContext.TypeName, symbol); trapFile.Write(";tuple"); } @@ -42,7 +42,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulateGenerics(); var underlyingType = NamedType.Create(Context, symbol.TupleUnderlyingType); - trapFile.tuple_underlying_type(this, underlyingType); + trapFile.tuple_underlying_type(this, underlyingType.TypeRef); int index = 0; foreach (var element in TupleElements) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 4b4a8f919ec..d541febee6d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -95,6 +95,7 @@ namespace Semmle.Extraction.CSharp.Entities var baseTypes = new List(); if (symbol.BaseType != null) { + // !! Do not extend "object" if the base type is missing :-( Type baseKey = Create(Context, symbol.BaseType); trapFile.extend(this, baseKey.TypeRef); if (symbol.TypeKind != TypeKind.Struct) @@ -268,6 +269,10 @@ namespace Semmle.Extraction.CSharp.Entities public static Type Create(Context cx, ITypeSymbol type) { type = type.DisambiguateType(); + + if (type is INamedTypeSymbol nt && nt.IsEvilTwin()) + type = nt.ConstructedFrom; + const bool errorTypeIsNull = false; return type == null || (errorTypeIsNull && type.TypeKind == TypeKind.Error) ? NullType.Create(cx).Type : (Type)cx.CreateEntity(type); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index 2a64a29fa0d..1e9d1c214f7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -51,7 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType); // Needed for op_explicit(), which differs only by return type. + AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType, TypeNameContext.MethodParam); // Needed for op_explicit(), which differs only by return type. trapFile.Write(' '); BuildMethodId(this, trapFile); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs index 7ca12e00f26..fadcbd8127b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs @@ -120,7 +120,8 @@ namespace Semmle.Extraction.CSharp var syntaxTrees = new List(); var syntaxTreeTasks = ReadSyntaxTrees( compilerArguments.SourceFiles. - Select(src => canonicalPathCache.GetCanonicalPath(src.Path)), + Select(src => canonicalPathCache.GetCanonicalPath(src.Path)). + Where(f => !f.EndsWith(".dll")), analyser, compilerArguments.ParseOptions, compilerArguments.Encoding, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index 5bd9c90cc76..f22d5137f6a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security.Cryptography; +using System.Text; namespace Semmle.Extraction.CSharp { @@ -25,6 +27,16 @@ namespace Semmle.Extraction.CSharp } } + public enum TypeNameContext + { + TypeName, + TypeRef, + AnonymousType, + MethodName, + MethodParam + } + + static class SymbolExtensions { /// @@ -131,17 +143,36 @@ namespace Semmle.Extraction.CSharp /// The extraction context. /// The trap builder used to store the result. /// The action to apply to syntactic sub terms of this type. - public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction) + public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, TypeNameContext assemblyPrefix, ISymbol genericContext) { - if (type.SpecialType != SpecialType.None) + switch(type.SpecialType) { - /* - * Use the keyword ("int" etc) for the built-in types. - * This makes the IDs shorter and means that all built-in types map to - * the same entities (even when using multiple versions of mscorlib). - */ - trapFile.Write(type.ToDisplayString()); - return; + case SpecialType.System_Object: + case SpecialType.System_Void: + case SpecialType.System_Boolean: + case SpecialType.System_Char: + case SpecialType.System_SByte: + case SpecialType.System_Byte: + case SpecialType.System_Int16: + case SpecialType.System_UInt16: + case SpecialType.System_Int32: + case SpecialType.System_UInt32: + case SpecialType.System_Int64: + case SpecialType.System_UInt64: + case SpecialType.System_Decimal: + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_String: + case SpecialType.System_IntPtr: + case SpecialType.System_UIntPtr: + + /* + * Use the keyword ("int" etc) for the built-in types. + * This makes the IDs shorter and means that all built-in types map to + * the same entities (even when using multiple versions of mscorlib). + */ + trapFile.Write(type.ToDisplayString()); + return; } using (cx.StackGuard) @@ -150,7 +181,9 @@ namespace Semmle.Extraction.CSharp { case TypeKind.Array: var array = (IArrayTypeSymbol)type; - subTermAction(cx, trapFile, array.ElementType); + subTermAction(cx, trapFile, array.ElementType, genericContext); + if(assemblyPrefix == TypeNameContext.TypeName) + trapFile.Write((int)array.ElementNullableAnnotation); array.BuildArraySuffix(trapFile); return; case TypeKind.Class: @@ -160,16 +193,29 @@ namespace Semmle.Extraction.CSharp case TypeKind.Delegate: case TypeKind.Error: var named = (INamedTypeSymbol)type; - named.BuildNamedTypeId(cx, trapFile, subTermAction); + named.BuildNamedTypeId(cx, trapFile, subTermAction, assemblyPrefix, genericContext); return; case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; - subTermAction(cx, trapFile, ptr.PointedAtType); - trapFile.Write('*'); + subTermAction(cx, trapFile, ptr.PointedAtType, genericContext); + trapFile.Write("*"); return; case TypeKind.TypeParameter: var tp = (ITypeParameterSymbol)type; - trapFile.Write(tp.Name); + switch(tp.TypeParameterKind) + { + case TypeParameterKind.Method: + if(!Equals(genericContext, tp.DeclaringMethod)) + trapFile.WriteSubId(Method.Create(cx, tp.DeclaringMethod)); + trapFile.Write("!!"); + break; + case TypeParameterKind.Type: + if(!Equals(genericContext,tp.DeclaringType)) + subTermAction(cx, trapFile, tp.DeclaringType, genericContext); + trapFile.Write("!"); + break; + } + trapFile.Write(tp.Ordinal); return; case TypeKind.Dynamic: trapFile.Write("dynamic"); @@ -193,8 +239,34 @@ namespace Semmle.Extraction.CSharp trapFile.Write(']'); } - static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction) + private static void BuildAssembly(IAssemblySymbol asm, TextWriter trapFile, bool extraPrecise = false) { + var assembly = asm.Identity; + trapFile.Write(assembly.Name); + trapFile.Write('_'); + trapFile.Write(assembly.Version.Major); + trapFile.Write('.'); + trapFile.Write(assembly.Version.Minor); + trapFile.Write('.'); + trapFile.Write(assembly.Version.Build); + if (extraPrecise) + { + trapFile.Write('.'); + trapFile.Write(assembly.Version.Revision); + } + trapFile.Write("::"); + } + + public static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction, TypeNameContext assemblyPrefix, ISymbol genericContext) + { + bool prefixAssembly = false; + if (named.IsAnonymous()) prefixAssembly = true; + else if(assemblyPrefix == TypeNameContext.TypeName && cx.Extractor.Identifiers != IdentifierMode.Imprecise) prefixAssembly = true; + if (named.ContainingAssembly is null) prefixAssembly = false; + + if (prefixAssembly) + BuildAssembly(named.ContainingAssembly, trapFile); + if (named.IsTupleType) { trapFile.Write('('); @@ -203,7 +275,7 @@ namespace Semmle.Extraction.CSharp { trapFile.Write(f.Name); trapFile.Write(":"); - subTermAction(cx, tb0, f.Type); + subTermAction(cx, tb0, f.Type, genericContext); } ); trapFile.Write(")"); @@ -212,16 +284,16 @@ namespace Semmle.Extraction.CSharp if (named.ContainingType != null) { - subTermAction(cx, trapFile, named.ContainingType); + subTermAction(cx, trapFile, named.ContainingType, genericContext); trapFile.Write('.'); } - else if (named.ContainingNamespace != null) + else if (named.ContainingNamespace != null && !named.IsConstructedGeneric()) { named.ContainingNamespace.BuildNamespace(cx, trapFile); } if (named.IsAnonymousType) - named.BuildAnonymousName(cx, trapFile, subTermAction, true); + named.BuildAnonymousName(cx, trapFile, subTermAction, true, genericContext); else if (named.TypeParameters.IsEmpty) trapFile.Write(named.Name); else if (IsReallyUnbound(named)) @@ -232,7 +304,7 @@ namespace Semmle.Extraction.CSharp } else { - subTermAction(cx, trapFile, named.ConstructedFrom); + subTermAction(cx, trapFile, named.ConstructedFrom, genericContext); trapFile.Write('<'); // Encode the nullability of the type arguments in the label. // Type arguments with different nullability can result in @@ -245,40 +317,20 @@ namespace Semmle.Extraction.CSharp static void BuildNamespace(this INamespaceSymbol ns, Context cx, TextWriter trapFile) { - // Only include the assembly information in each type ID - // for normal extractions. This is because standalone extractions - // lack assembly information or may be ambiguous. - bool prependAssemblyToTypeId = !cx.Extractor.Standalone && ns.ContainingAssembly != null; - - if (prependAssemblyToTypeId) - { - // Note that we exclude the revision number as this has - // been observed to be unstable. - var assembly = ns.ContainingAssembly.Identity; - trapFile.Write(assembly.Name); - trapFile.Write('_'); - trapFile.Write(assembly.Version.Major); - trapFile.Write('.'); - trapFile.Write(assembly.Version.Minor); - trapFile.Write('.'); - trapFile.Write(assembly.Version.Build); - trapFile.Write("::"); - } - trapFile.WriteSubId(Namespace.Create(cx, ns)); trapFile.Write('.'); } - static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, bool includeParamName) + static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, bool includeParamName, ISymbol genericContext) { var buildParam = includeParamName ? (prop, tb0) => { tb0.Write(prop.Name); - trapFile.Write(' '); - subTermAction(cx, tb0, prop.Type); + tb0.Write(' '); + subTermAction(cx, tb0, prop.Type, genericContext); } - : (Action)((prop, tb0) => subTermAction(cx, tb0, prop.Type)); + : (Action)((prop, tb0) => subTermAction(cx, tb0, prop.Type, genericContext)); int memberCount = type.GetMembers().OfType().Count(); int hackTypeNumber = memberCount == 1 ? 1 : 0; trapFile.Write("<>__AnonType"); @@ -350,15 +402,16 @@ namespace Semmle.Extraction.CSharp if (namedType.IsAnonymousType) { - namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false); + namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub, _) => sub.BuildDisplayName(cx0, tb0), false, namedType); } trapFile.Write(namedType.Name); - if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any()) + if (namedType.IsGenericType && /* namedType.TypeKind != TypeKind.Error && */ namedType.TypeArguments.Any()) { trapFile.Write('<'); trapFile.BuildList(",", namedType.TypeArguments, (p, tb0) => { + // tb0.Write(p.Name); if (IsReallyBound(namedType)) p.BuildDisplayName(cx, tb0); }); @@ -490,12 +543,6 @@ namespace Semmle.Extraction.CSharp return new AnnotatedTypeSymbol(info.Type.DisambiguateType(), info.Nullability.Annotation); } - /// - /// Gets the annotated type of an ILocalSymbol. - /// This has not yet been exposed on the public API. - /// - public static AnnotatedTypeSymbol GetAnnotatedType(this ILocalSymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation); - /// /// Gets the annotated type of an IPropertySymbol. /// This has not yet been exposed on the public API. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 836a21312fb..96639dd9bee 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -381,6 +381,16 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("nullable_underlying_type", nullableType, underlyingType); } + internal static void nullability(this TextWriter trapFile, NullabilityEntity nullability, int annotation) + { + trapFile.WriteTuple("nullability", nullability, annotation); + } + + internal static void nullability_member(this TextWriter trapFile, NullabilityEntity nullability, int index, NullabilityEntity child) + { + trapFile.WriteTuple(nameof(nullability_member), nullability, index, child); + } + internal static void numlines(this TextWriter trapFile, IEntity label, LineCounts lineCounts) { trapFile.WriteTuple("numlines", label, lineCounts.Total, lineCounts.Code, lineCounts.Comment); @@ -471,7 +481,7 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("tuple_element", type, index, field); } - internal static void tuple_underlying_type(this TextWriter trapFile, TupleType type, NamedType underlying) + internal static void tuple_underlying_type(this TextWriter trapFile, TupleType type, Type underlying) { trapFile.WriteTuple("tuple_underlying_type", type, underlying); } @@ -481,9 +491,14 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("type_annotation", element, (int)annotation); } - internal static void type_argument_annotation(this TextWriter trapFile, IEntity element, int index, Kinds.TypeAnnotation annotation) + internal static void type_arguments(this TextWriter trapFile, Type arg, int n, IEntity typeOrMethod) { - trapFile.WriteTuple("type_argument_annotation", element, index, (int)annotation); + trapFile.WriteTuple("type_arguments", arg, n, typeOrMethod); + } + + internal static void type_location(this TextWriter trapFile, Type type, Location location) + { + trapFile.WriteTuple("type_location", type, location); } internal static void type_mention(this TextWriter trapFile, TypeMention ta, Type type, IEntity parent) @@ -496,14 +511,9 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("type_mention_location", ta, loc); } - internal static void type_arguments(this TextWriter trapFile, Type arg, int n, IEntity typeOrMethod) + internal static void type_nullability(this TextWriter trapFile, IEntity element, NullabilityEntity nullability) { - trapFile.WriteTuple("type_arguments", arg, n, typeOrMethod); - } - - internal static void type_location(this TextWriter trapFile, Type type, Location location) - { - trapFile.WriteTuple("type_location", type, location); + trapFile.WriteTuple("type_nullability", element, nullability); } internal static void type_parameter_constraints(this TextWriter trapFile, TypeParameterConstraints constraints, TypeParameter typeParam) diff --git a/csharp/extractor/Semmle.Extraction/Extractor.cs b/csharp/extractor/Semmle.Extraction/Extractor.cs index e470d3258ec..449f8e18304 100644 --- a/csharp/extractor/Semmle.Extraction/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction/Extractor.cs @@ -87,6 +87,16 @@ namespace Semmle.Extraction /// The extraction scope (what to include in this trap file). /// Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope); + + IdentifierMode Identifiers { get; } + } + + public enum IdentifierMode + { + Imprecise, + Flexible, + Precise, + ExtraPrecise } /// @@ -112,6 +122,7 @@ namespace Semmle.Extraction public Extractor(bool standalone, string outputPath, ILogger logger) { Standalone = standalone; + if (Standalone) Identifiers = IdentifierMode.Imprecise; OutputPath = outputPath; Logger = logger; } @@ -197,5 +208,7 @@ namespace Semmle.Extraction public ILogger Logger { get; private set; } public static string Version => $"{ThisAssembly.Git.BaseTag} ({ThisAssembly.Git.Sha})"; + + public IdentifierMode Identifiers { get; } = IdentifierMode.Imprecise; } } diff --git a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll index 14a88830ad2..80c4d1250ca 100644 --- a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll +++ b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll @@ -8,7 +8,8 @@ import csharp -private module Annotations { +// private +module Annotations { newtype TAnnotation = TNotNullableRefType() or TNullableRefType() or @@ -77,24 +78,28 @@ private module Annotations { } newtype TAnnotations = - TAnnotationFlags(int flags) { - flags = getElementTypeFlags(_) or - flags = getTypeArgumentFlags(_, _) or - flags = getTypeParameterFlags(_, _) + TAnnotationFlags(int flags, Nullability n) { + exists(Element e | flags = getElementTypeFlags(e) and n = getElementNullability(e)) + or + flags = getTypeParameterFlags(_, _) and n instanceof DefaultOblivious + or + flags = 0 // n is unbound } - /** A set of annotations on a type. */ class TypeAnnotations extends TAnnotations { int flags; - TypeAnnotations() { this = TAnnotationFlags(flags) } + Nullability nullability; - /** Gets an annotation in this set of annotations. */ - TypeAnnotation getAnAnnotation() { isSet(result.getBit()) } + TypeAnnotations() { this = TAnnotationFlags(flags, nullability) } - private predicate isSet(int bit) { - isBit(bit) and - exists(int mask | mask = getBitMask(bit) | flags.bitAnd(mask) = mask) + int getFlags() { result = flags } + + Nullability getNullability() { result = nullability } + + bindingset[i] + TypeAnnotations getChild(int i) { + result.getFlags() = 0 and result.getNullability() = this.getNullability().getMember(i) } /** Gets text to be displayed before the type. */ @@ -117,13 +122,53 @@ private module Annotations { /** Gets a textual representation of this type annotation. */ string toString() { result = getTypePrefix() + getTypeSuffix() } + + private predicate isSet(int bit) { + isBit(bit) and + exists(int mask | mask = getBitMask(bit) | flags.bitAnd(mask) = mask) + } + + /** Gets an annotation in this set of annotations. */ + TypeAnnotation getAnAnnotation() { + isSet(result.getBit()) + or + nullability instanceof AnnotatedNullability and result instanceof NullableRefType + or + nullability instanceof NotAnnotatedNullability and result instanceof NonNullableRefType + } + } + + // A structure to encode the nullability of various types. For example + class Nullability extends @nullability { + abstract string toString(); + + bindingset[i] + Nullability getMember(int i) { + if nullability_member(this, i, _) then nullability_member(this, i, result) else result = this + } + } + + class ObliviousNullability extends Nullability, @oblivious { + override string toString() { result = "oblivious" } + } + + class DefaultOblivious extends ObliviousNullability { + DefaultOblivious() { not nullability_member(this, _, _) } + } + + class AnnotatedNullability extends Nullability, @annotated { + override string toString() { result = "annotated" } + } + + class NotAnnotatedNullability extends Nullability, @not_annotated { + override string toString() { result = "not annotated" } } /** Holds if the type annotations `annotations` apply to type `type` on element `element`. */ predicate elementTypeAnnotations( @has_type_annotation element, Type type, TypeAnnotations annotations ) { - annotations = TAnnotationFlags(getElementTypeFlags(element)) and + annotations = TAnnotationFlags(getElementTypeFlags(element), getElementNullability(element)) and ( type = element.(Assignable).getType() or @@ -131,8 +176,8 @@ private module Annotations { or type = element.(Expr).getType() or - type = element.(ArrayType).getElementType() - or + // or + // type = element.(ArrayType).getElementType() type = element.(DelegateType).getReturnType() ) } @@ -150,26 +195,37 @@ private int getElementTypeFlags(@has_type_annotation element) { result = sum(int b | type_annotation(element, b) | b) } -private int getTypeArgumentFlags(ConstructedGeneric generic, int argument) { - exists(generic.getTypeArgument(argument)) and - result = sum(int b | type_argument_annotation(generic, argument, b) | b) -} - private int getTypeParameterFlags(TypeParameterConstraints constraints, Type type) { specific_type_parameter_annotation(constraints, getTypeRef(type), _) and result = sum(int b | specific_type_parameter_annotation(constraints, getTypeRef(type), b) | b) } +private Annotations::Nullability getElementNullability(@has_type_annotation element) { + if type_nullability(element, _) + then type_nullability(element, result) + else result instanceof Annotations::DefaultOblivious +} + private newtype TAnnotatedType = TAnnotatedTypeNullability(Type type, Annotations::TypeAnnotations annotations) { Annotations::elementTypeAnnotations(_, type, annotations) or - exists(ConstructedGeneric c, int i | - type = c.getTypeArgument(i) and - annotations = Annotations::TAnnotationFlags(getTypeArgumentFlags(c, i)) + exists(AnnotatedConstructedType c, int i | + type = c.getType().(ConstructedType).getTypeArgument(i) and + annotations = c.getAnnotations().getChild(i) ) or - annotations = Annotations::TAnnotationFlags(getTypeParameterFlags(_, type)) + annotations.getFlags() = getTypeParameterFlags(_, type) and + annotations.getNullability() instanceof Annotations::DefaultOblivious + or + // All types + annotations.getFlags() = 0 and + annotations.getNullability() instanceof Annotations::DefaultOblivious + or + exists(AnnotatedArrayType at | + type = at.getType().(ArrayType).getElementType() and + annotations = at.getAnnotations().getChild(0) + ) } /** A type with additional information. */ @@ -192,7 +248,7 @@ class AnnotatedType extends TAnnotatedType { * Gets the unannotated type, for example `string` in `string?`. * Note that this might be a nullable value type (`System.Nullable`). */ - final Type getType() { result = type } + Type getType() { result = type } /** * Gets the underlying type, for example `string` in `string?` @@ -206,7 +262,7 @@ class AnnotatedType extends TAnnotatedType { } /** Gets the type annotation set of this annotated type. */ - private Annotations::TypeAnnotations getAnnotations() { result = annotations } + Annotations::TypeAnnotations getAnnotations() { result = annotations } /** Gets a type annotation of this annotated type. */ private Annotations::TypeAnnotation getAnAnnotation() { @@ -233,14 +289,70 @@ class AnnotatedType extends TAnnotatedType { /** Holds if this annotated type applies to element `e`. */ predicate appliesTo(Element e) { Annotations::elementTypeAnnotations(e, type, annotations) } - /** Holds if this annotated type applies to type parameter constraints `constraints`. */ - predicate appliesToTypeConstraint(TypeParameterConstraints constraints) { - annotations = Annotations::TAnnotationFlags(getTypeParameterFlags(constraints, type)) + /** Holds if this annotated type is the type argument 'i' of constructed generic 'g'. */ + predicate appliesToTypeArgument(ConstructedGeneric g, int i) { + this.getAnnotations().getFlags() = 0 and + this.getAnnotations().getNullability() = getElementNullability(g).getMember(i) and + this.getType() = g.getTypeArgument(i) } - /** Holds if this annotated type applies to the `i`th type argument of constructed generic `g`. */ - predicate appliesToTypeArgument(ConstructedGeneric g, int i) { - type = g.getTypeArgument(i) and - this.getAnnotations() = Annotations::TAnnotationFlags(getTypeArgumentFlags(g, i)) + /** Holds if this annotated type applies to type parameter constraints `constraints`. */ + predicate appliesToTypeConstraint(TypeParameterConstraints constraints) { + annotations.getFlags() = getTypeParameterFlags(constraints, type) + } +} + +/** An array type with additional information. */ +class AnnotatedArrayType extends AnnotatedType { + override ArrayType type; + + /** Gets the annotated element type of this array, for example `int?` in `int?[]`. */ + final AnnotatedType getElementType() { + result.getType() = type.getElementType() and + result.getAnnotations() = this.getAnnotations().getChild(0) + } + + private string getDimensionString(AnnotatedType elementType) { + exists(AnnotatedType et, string res | + et = getElementType() and + res = "[" + type.getRankString(0) + "]" and + if et.getUnderlyingType() instanceof ArrayType and not et.isNullableRefType() + then result = res + et.(AnnotatedArrayType).getDimensionString(elementType) + else ( + result = res and elementType = et + ) + ) + } + + override string toString() { + exists(AnnotatedType elementType | + result = annotations.getTypePrefix() + elementType.toString() + + this.getDimensionString(elementType) + annotations.getTypeSuffix() + ) + } +} + +/** A constructed type with additional information. */ +class AnnotatedConstructedType extends AnnotatedType { + override ConstructedType type; + + /** Gets the `i`th type argument of this constructed type. */ + AnnotatedType getTypeArgument(int i) { + result.getType() = type.getTypeArgument(i) and + result.getAnnotations() = this.getAnnotations().getChild(i) + } + + override string toString() { + result = annotations.getTypePrefix() + type.getUnboundGeneric().getNameWithoutBrackets() + "<" + + this.getTypeArgumentsString() + ">" + annotations.getTypeSuffix() + } + + language[monotonicAggregates] + private string getTypeArgumentsString() { + result = concat(int i | + exists(this.getTypeArgument(i)) + | + this.getTypeArgument(i).toString(), ", " order by i + ) } } diff --git a/csharp/ql/src/semmle/code/csharp/Generics.qll b/csharp/ql/src/semmle/code/csharp/Generics.qll index cab7a520df4..29fd083aec5 100644 --- a/csharp/ql/src/semmle/code/csharp/Generics.qll +++ b/csharp/ql/src/semmle/code/csharp/Generics.qll @@ -370,21 +370,21 @@ class ConstructedType extends ValueOrRefType, ConstructedGeneric { override UnboundGenericType getUnboundGeneric() { constructed_generic(this, getTypeRef(result)) } - language[monotonicAggregates] - private string annotatedTypeArgumentsToString() { - result = concat(int i | - exists(this.getAnnotatedTypeArgument(i)) - | - this.getAnnotatedTypeArgument(i).toString(), ", " order by i - ) - } - override string toStringWithTypes() { - result = getUnboundGeneric().getNameWithoutBrackets() + "<" + - this.annotatedTypeArgumentsToString() + ">" + result = getUnboundGeneric().getNameWithoutBrackets() + "<" + this.getTypeArgumentsString() + + ">" } final override Type getChild(int n) { result = getTypeArgument(n) } + + language[monotonicAggregates] + private string getTypeArgumentsString() { + result = concat(int i | + exists(this.getTypeArgument(i)) + | + this.getTypeArgument(i).toString(), ", " order by i + ) + } } /** diff --git a/csharp/ql/src/semmle/code/csharp/Type.qll b/csharp/ql/src/semmle/code/csharp/Type.qll index bdd28d8a0af..c723cc9fc0e 100644 --- a/csharp/ql/src/semmle/code/csharp/Type.qll +++ b/csharp/ql/src/semmle/code/csharp/Type.qll @@ -821,26 +821,23 @@ class ArrayType extends DotNet::ArrayType, RefType, @array_type { /** Gets the element type of this array, for example `int` in `int[]`. */ override Type getElementType() { array_element_type(this, _, _, getTypeRef(result)) } - /** Gets the annotated element type of this array, for example `int?` in `int?[]`. */ - final AnnotatedType getAnnotatedElementType() { result.appliesTo(this) } - /** Holds if this array type has the same shape (dimension and rank) as `that` array type. */ predicate hasSameShapeAs(ArrayType that) { getDimension() = that.getDimension() and getRank() = that.getRank() } - private string getRankString(int i) { + string getRankString(int i) { i in [0 .. getRank() - 1] and if i = getRank() - 1 then result = "" else result = "," + getRankString(i + 1) } - private string getDimensionString(AnnotatedType elementType) { - exists(AnnotatedType et, string res | - et = getAnnotatedElementType() and + private string getDimensionString(Type elementType) { + exists(Type et, string res | + et = this.getElementType() and res = "[" + getRankString(0) + "]" and - if et.getUnderlyingType() instanceof ArrayType and not et.isNullableRefType() - then result = res + et.getUnderlyingType().(ArrayType).getDimensionString(elementType) + if et instanceof ArrayType + then result = res + et.(ArrayType).getDimensionString(elementType) else ( result = res and elementType = et ) @@ -848,7 +845,7 @@ class ArrayType extends DotNet::ArrayType, RefType, @array_type { } override string toStringWithTypes() { - exists(AnnotatedType elementType | + exists(Type elementType | result = elementType.toString() + this.getDimensionString(elementType) ) } @@ -905,7 +902,7 @@ class UnknownType extends Type, @unknown_type { } */ class TupleType extends ValueType, @tuple_type { /** Gets the underlying type of this tuple, which is of type `System.ValueTuple`. */ - ConstructedStruct getUnderlyingType() { tuple_underlying_type(this, result) } + ConstructedStruct getUnderlyingType() { tuple_underlying_type(this, getTypeRef(result)) } /** * Gets the `n`th element of this tuple, indexed from 0. diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index f93793ee5f6..e8b3d5aca88 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -244,7 +244,7 @@ locations_default( @sourceline = @file | @callable | @xmllocatable; numlines( - unique int element_id: @sourceline ref, + int element_id: @sourceline ref, int num_lines: int ref, int num_code: int ref, int num_comment: int ref); @@ -381,7 +381,7 @@ typerefs( varchar(900) name: string ref); typeref_type( - unique int id: @typeref ref, + int id: @typeref ref, unique int typeId: @type ref); @type_or_ref = @type | @typeref; @@ -424,7 +424,7 @@ type_location( tuple_underlying_type( unique int tuple: @tuple_type ref, - int struct: @struct_type ref); + int struct: @type_or_ref ref); #keyset[tuple, index] tuple_element( @@ -452,7 +452,7 @@ type_mention_location( unique int id: @type_mention ref, int loc: @location ref); -@has_type_annotation = @assignable | @type_parameter | @callable | @array_type | @expr | @delegate_type; +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic; /** * A direct annotation on an entity, for example `string? x;`. @@ -472,8 +472,18 @@ type_mention_location( */ type_annotation(int id: @has_type_annotation ref, int annotation: int ref); -/** The annotation of type arguments of a constructed type or method. */ -type_argument_annotation(int constructedgeneric: @generic ref, int position: int ref, int annotation: int ref); +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[nullability, index] +nullability_member(int nullability: @nullability ref, int index: int ref, int child: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref) /** GENERICS **/ @@ -633,8 +643,8 @@ operator_location( int loc: @location ref); constant_value( - unique int id: @variable ref, - varchar(900) value: string ref); + int id: @variable ref, + string value: string ref); /** CALLABLES **/ @@ -674,7 +684,7 @@ destructor_location( int loc: @location ref); overrides( - unique int id: @callable ref, + int id: @callable ref, int base_id: @callable ref); explicitly_implements( diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql index f9bda91b349..c0febaa2afa 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql @@ -28,10 +28,10 @@ query predicate assignableTypes(Assignable a, AnnotatedType t) { t = a.getAnnotatedType() } -query predicate arrayElements(Variable v, ArrayType array, AnnotatedType elementType) { +query predicate arrayElements(Variable v, AnnotatedArrayType array, AnnotatedType elementType) { v.getFile().getBaseName() = "NullableRefTypes.cs" and - array = v.getType() and - elementType = array.getAnnotatedElementType() + array = v.getAnnotatedType() and + elementType = array.getElementType() } query predicate returnTypes(Callable c, string t) { @@ -39,13 +39,13 @@ query predicate returnTypes(Callable c, string t) { t = c.getAnnotatedReturnType().toString() } -query predicate typeArguments(ConstructedGeneric generic, int arg, string argument) { +query predicate typeArguments(AnnotatedConstructedType generic, int arg, string argument) { ( - generic = any(Variable v | v.fromSource()).getType() - or - generic = any(MethodCall mc).getTarget() + generic.getType() = any(Variable v | v.fromSource()).getType() + //or + // generic.getType() = any(MethodCall mc).getTarget() ) and - argument = generic.getAnnotatedTypeArgument(arg).toString() + argument = generic.getTypeArgument(arg).toString() } query predicate nullableTypeParameters(TypeParameter p) { @@ -56,3 +56,5 @@ query predicate annotatedTypeConstraints(TypeParameter p, AnnotatedType t) { t = p.getConstraints().getAnAnnotatedTypeConstraint() and t.getLocation() instanceof SourceLocation } + +query predicate typeNotAnnotated(Type type) { not exists(AnnotatedType at | at.getType() = type) } From 9fd4a9ceb65131cc0a0c407d08e0d802c73d3a33 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 27 Sep 2019 14:52:55 +0100 Subject: [PATCH 1033/1227] C#: Implement NullabilityEntity to model structured nullability on the side --- .../Semmle.Extraction.CIL/Entities/Type.cs | 2 +- .../Semmle.Extraction.CSharp/Analyser.cs | 4 +- .../Entities/LocalFunction.cs | 2 +- .../Entities/Method.cs | 11 +- .../Entities/Property.cs | 1 - .../Entities/Symbol.cs | 2 +- .../Entities/Types/NamedType.cs | 21 +- .../Entities/Types/TupleType.cs | 2 +- .../Entities/Types/TypeParameter.cs | 8 +- .../Entities/UserOperator.cs | 2 +- .../SymbolExtensions.cs | 33 +- .../Semmle.Extraction.CSharp/Tuples.cs | 8 +- .../extractor/Semmle.Extraction/Extractor.cs | 22 +- .../src/semmle/code/csharp/AnnotatedType.qll | 100 +++-- csharp/ql/src/semmlecode.csharp.dbscheme | 4 +- .../csharp8/NullCoalescingAssignment.expected | 2 +- .../library-tests/csharp8/NullableRefTypes.cs | 6 + .../csharp8/NullableRefTypes.expected | 360 ++++++++++-------- .../library-tests/csharp8/NullableRefTypes.ql | 23 +- 19 files changed, 353 insertions(+), 260 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs index 1f6f07023f7..04b25553b6b 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs @@ -1208,7 +1208,7 @@ namespace Semmle.Extraction.CIL.Entities { elementType.WriteId(trapFile, gc); trapFile.Write('['); - for(int i=1; i AddSignatureTypeToId(Context, tb0, symbol, ta, TypeNameContext.MethodName)); + trapFile.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta, TypeIdentifierContext.MethodName)); trapFile.Write('>'); } trapFile.Write(";localfunction"); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index dac490f98b2..18aec3b05ec 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -108,7 +108,6 @@ namespace Semmle.Extraction.CSharp.Entities /// protected static void BuildMethodId(Method m, TextWriter trapFile) { - // AddSignatureTypeToId(m.Context, trapFile, m.symbol, m.ContainingType.symbol, false); trapFile.WriteSubId(m.ContainingType); AddExplicitInterfaceQualifierToId(m.Context, trapFile, m.symbol.ExplicitInterfaceImplementations); @@ -130,7 +129,7 @@ namespace Semmle.Extraction.CSharp.Entities // Type arguments with different nullability can result in // a constructed method with different nullability of its parameters and return type, // so we need to create a distinct database entity for it. - trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol, TypeNameContext.MethodName); trapFile.Write((int)ta.Nullability); }); + trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol, TypeIdentifierContext.MethodName); trapFile.Write((int)ta.Nullability); }); trapFile.Write('>'); } } @@ -200,10 +199,10 @@ namespace Semmle.Extraction.CSharp.Entities /// to make the reference to #3 in the label definition #4 for /// T valid. /// - protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type, TypeNameContext assemblyPrefix) + protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type, TypeIdentifierContext tic) { if (type.ContainsTypeParameters(cx, method)) - type.BuildTypeId(cx, trapFile, (cx0, tb0, type0, _) => AddSignatureTypeToId(cx, tb0, method, type0, assemblyPrefix), assemblyPrefix, method); + type.BuildTypeId(cx, trapFile, (cx0, tb0, type0, _) => AddSignatureTypeToId(cx, tb0, method, type0, tic), tic, method); else trapFile.WriteSubId(Type.Create(cx, type).TypeRef); } @@ -216,13 +215,13 @@ namespace Semmle.Extraction.CSharp.Entities if (method.MethodKind == MethodKind.ReducedExtension) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, TypeNameContext.MethodParam); + AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, TypeIdentifierContext.MethodParam); } foreach (var param in method.Parameters) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, param.Type, TypeNameContext.MethodParam); + AddSignatureTypeToId(cx, trapFile, method, param.Type, TypeIdentifierContext.MethodParam); switch (param.RefKind) { case RefKind.Out: diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index e1822504120..bcb971ae799 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -15,7 +15,6 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - // trapFile.WriteSubId(ContainingType.TypeRef); trapFile.WriteSubId(ContainingType); trapFile.Write('.'); Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs index 4d37d4f1d38..6d0f5dd80c8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities { var ta = type.Nullability.GetTypeAnnotation(); var n = NullabilityEntity.Create(Context, Nullability.Create(type)); - if (ta != Kinds.TypeAnnotation.None || !type.HasConsistentNullability()) + if (!type.HasObliviousNullability()) { trapFile.type_nullability(this, n); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index ca82da2ecc4..28b1e37514a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities return; } - trapFile.typeref_type((NamedTypeRef)TypeRef, this); + trapFile.typeref_type((TypeRef)TypeRef, this); if (symbol.IsGenericType) { @@ -111,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeNameContext.TypeName, symbol); + symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeIdentifierContext.TypeName, symbol); trapFile.Write(";type"); } @@ -151,26 +151,26 @@ namespace Semmle.Extraction.CSharp.Entities public NamedType Create(Context cx, INamedTypeSymbol init) => new NamedType(cx, init); } - public override Type TypeRef => NamedTypeRef.Create(Context, this, symbol); + public override Type TypeRef => Entities.TypeRef.Create(Context, this, symbol); } - class NamedTypeRef : Type + class TypeRef : Type { readonly Type referencedType; - public NamedTypeRef(Context cx, Type type, ITypeSymbol symbol) : base(cx, symbol) + public TypeRef(Context cx, Type type, ITypeSymbol symbol) : base(cx, symbol) { referencedType = type; } - public static NamedTypeRef Create(Context cx, Type referencedType, ITypeSymbol type) => + public static TypeRef Create(Context cx, Type referencedType, ITypeSymbol type) => NamedTypeRefFactory.Instance.CreateEntity2(cx, (referencedType, type)); - class NamedTypeRefFactory : ICachedEntityFactory<(Type, ITypeSymbol), NamedTypeRef> + class NamedTypeRefFactory : ICachedEntityFactory<(Type, ITypeSymbol), TypeRef> { public static readonly NamedTypeRefFactory Instance = new NamedTypeRefFactory(); - public NamedTypeRef Create(Context cx, (Type, ITypeSymbol) init) => new NamedTypeRef(cx, init.Item1, init.Item2); + public TypeRef Create(Context cx, (Type, ITypeSymbol) init) => new TypeRef(cx, init.Item1, init.Item2); } public override bool NeedsPopulation => true; @@ -179,11 +179,10 @@ namespace Semmle.Extraction.CSharp.Entities { void ExpandType(Context cx0, TextWriter tb0, ITypeSymbol sub, ISymbol gc) { - sub.BuildTypeId(cx0, tb0, ExpandType, TypeNameContext.TypeRef, gc); + sub.BuildTypeId(cx0, tb0, ExpandType, TypeIdentifierContext.TypeRef, gc); } - // Prefix anonymous types because they shouldn't be visible outside of the current assembly. - symbol.BuildTypeId(Context, trapFile, ExpandType, TypeNameContext.TypeRef, symbol); + symbol.BuildTypeId(Context, trapFile, ExpandType, TypeIdentifierContext.TypeRef, symbol); trapFile.Write(";typeref"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index 7adfa6ab8e7..8da87ba318d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeNameContext.TypeName, symbol); + symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeIdentifierContext.TypeName, symbol); trapFile.Write(";tuple"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs index 6377c5d49c7..2fdb8cd3a83 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs @@ -51,11 +51,11 @@ namespace Semmle.Extraction.CSharp.Entities baseType = abase.Symbol; var t = Create(Context, abase.Symbol); trapFile.specific_type_parameter_constraints(constraints, t.TypeRef); - if (abase.Nullability.GetTypeAnnotation() != Kinds.TypeAnnotation.None) - trapFile.specific_type_parameter_annotation(constraints, t.TypeRef, abase.Nullability.GetTypeAnnotation()); + if (!abase.HasObliviousNullability()) + trapFile.specific_type_parameter_nullability(constraints, t.TypeRef, NullabilityEntity.Create(Context, Nullability.Create(abase))); } - trapFile.types(this, Semmle.Extraction.Kinds.TypeKind.TYPE_PARAMETER, symbol.Name); + trapFile.types(this, Kinds.TypeKind.TYPE_PARAMETER, symbol.Name); trapFile.extend(this, Create(Context, baseType).TypeRef); Namespace parentNs = Namespace.Create(Context, symbol.TypeParameterKind == TypeParameterKind.Method ? Context.Compilation.GlobalNamespace : symbol.ContainingNamespace); @@ -66,7 +66,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.type_location(this, Context.Create(l)); } - if (this.IsSourceDeclaration) + if (IsSourceDeclaration) { var declSyntaxReferences = symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()). Select(s => s.Parent).Where(p => p != null).Select(p => p.Parent).ToArray(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index 1e9d1c214f7..5ac9c3015e0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -51,7 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType, TypeNameContext.MethodParam); // Needed for op_explicit(), which differs only by return type. + AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType, TypeIdentifierContext.MethodParam); // Needed for op_explicit(), which differs only by return type. trapFile.Write(' '); BuildMethodId(this, trapFile); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index f22d5137f6a..a5a5dc3aa83 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -27,7 +27,11 @@ namespace Semmle.Extraction.CSharp } } - public enum TypeNameContext + /// + /// Marks where a type identifier is being generated, which could change + /// the way that the identifier is generated. + /// + public enum TypeIdentifierContext { TypeName, TypeRef, @@ -36,7 +40,6 @@ namespace Semmle.Extraction.CSharp MethodParam } - static class SymbolExtensions { /// @@ -143,7 +146,7 @@ namespace Semmle.Extraction.CSharp /// The extraction context. /// The trap builder used to store the result. /// The action to apply to syntactic sub terms of this type. - public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, TypeNameContext assemblyPrefix, ISymbol genericContext) + public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, TypeIdentifierContext tic, ISymbol genericContext) { switch(type.SpecialType) { @@ -182,8 +185,6 @@ namespace Semmle.Extraction.CSharp case TypeKind.Array: var array = (IArrayTypeSymbol)type; subTermAction(cx, trapFile, array.ElementType, genericContext); - if(assemblyPrefix == TypeNameContext.TypeName) - trapFile.Write((int)array.ElementNullableAnnotation); array.BuildArraySuffix(trapFile); return; case TypeKind.Class: @@ -193,7 +194,7 @@ namespace Semmle.Extraction.CSharp case TypeKind.Delegate: case TypeKind.Error: var named = (INamedTypeSymbol)type; - named.BuildNamedTypeId(cx, trapFile, subTermAction, assemblyPrefix, genericContext); + named.BuildNamedTypeId(cx, trapFile, subTermAction, tic, genericContext); return; case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; @@ -205,12 +206,12 @@ namespace Semmle.Extraction.CSharp switch(tp.TypeParameterKind) { case TypeParameterKind.Method: - if(!Equals(genericContext, tp.DeclaringMethod)) + if (!Equals(genericContext, tp.DeclaringMethod)) trapFile.WriteSubId(Method.Create(cx, tp.DeclaringMethod)); trapFile.Write("!!"); break; case TypeParameterKind.Type: - if(!Equals(genericContext,tp.DeclaringType)) + if (!Equals(genericContext,tp.DeclaringType)) subTermAction(cx, trapFile, tp.DeclaringType, genericContext); trapFile.Write("!"); break; @@ -257,11 +258,11 @@ namespace Semmle.Extraction.CSharp trapFile.Write("::"); } - public static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction, TypeNameContext assemblyPrefix, ISymbol genericContext) + public static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction, TypeIdentifierContext tic, ISymbol genericContext) { bool prefixAssembly = false; if (named.IsAnonymous()) prefixAssembly = true; - else if(assemblyPrefix == TypeNameContext.TypeName && cx.Extractor.Identifiers != IdentifierMode.Imprecise) prefixAssembly = true; + else if(tic == TypeIdentifierContext.TypeName && cx.Extractor.TrapIdentifiers != TrapIdenfierMode.Imprecise) prefixAssembly = true; if (named.ContainingAssembly is null) prefixAssembly = false; if (prefixAssembly) @@ -310,7 +311,9 @@ namespace Semmle.Extraction.CSharp // Type arguments with different nullability can result in // a constructed type with different nullability of its members and methods, // so we need to create a distinct database entity for it. - trapFile.BuildList(",", named.GetAnnotatedTypeArguments(), (ta, tb0) => { subTermAction(cx, tb0, ta.Symbol); trapFile.Write((int)ta.Nullability); }); + trapFile.BuildList(",", named.GetAnnotatedTypeArguments(), + (ta, tb0) => subTermAction(cx, tb0, ta.Symbol, genericContext) + ); trapFile.Write('>'); } } @@ -406,12 +409,11 @@ namespace Semmle.Extraction.CSharp } trapFile.Write(namedType.Name); - if (namedType.IsGenericType && /* namedType.TypeKind != TypeKind.Error && */ namedType.TypeArguments.Any()) + if (namedType.IsGenericType && namedType.TypeArguments.Any()) { trapFile.Write('<'); trapFile.BuildList(",", namedType.TypeArguments, (p, tb0) => { - // tb0.Write(p.Name); if (IsReallyBound(namedType)) p.BuildDisplayName(cx, tb0); }); @@ -554,6 +556,10 @@ namespace Semmle.Extraction.CSharp /// This has not yet been exposed on the public API. /// public static AnnotatedTypeSymbol GetAnnotatedType(this IFieldSymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation); + private static bool IsSpecialized(this IMethodSymbol method) => + method.IsGenericMethod && + !ReferenceEquals(method, method.OriginalDefinition) && + method.TypeParameters.Zip(method.TypeArguments, (a, b) => !ReferenceEquals(a, b)).Any(b => b); /// /// Gets the annotated return type of an IMethodSymbol. @@ -607,6 +613,7 @@ namespace Semmle.Extraction.CSharp /// /// Creates an AnnotatedTypeSymbol from an ITypeSymbol. + /// Note: not currently used but might be useful. /// public static AnnotatedTypeSymbol WithAnnotation(this ITypeSymbol symbol, NullableAnnotation annotation) => new AnnotatedTypeSymbol(symbol, annotation); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 96639dd9bee..c239d4f0bb2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -456,9 +456,9 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("specific_type_parameter_constraints", constraints, baseType); } - internal static void specific_type_parameter_annotation(this TextWriter trapFile, TypeParameterConstraints constraints, Type baseType, TypeAnnotation annotation) + internal static void specific_type_parameter_nullability(this TextWriter trapFile, TypeParameterConstraints constraints, Type baseType, NullabilityEntity nullability) { - trapFile.WriteTuple("specific_type_parameter_annotation", constraints, baseType, (int)annotation); + trapFile.WriteTuple("specific_type_parameter_nullability", constraints, baseType, nullability); } internal static void stmt_location(this TextWriter trapFile, Statement stmt, Location location) @@ -526,12 +526,12 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("type_parameters", param, child, typeOrMethod, (int)param.Variance); } - internal static void typeref_type(this TextWriter trapFile, NamedTypeRef typeref, Type type) + internal static void typeref_type(this TextWriter trapFile, TypeRef typeref, Type type) { trapFile.WriteTuple("typeref_type", typeref, type); } - internal static void typerefs(this TextWriter trapFile, NamedTypeRef type, string name) + internal static void typerefs(this TextWriter trapFile, TypeRef type, string name) { trapFile.WriteTuple("typerefs", type, name); } diff --git a/csharp/extractor/Semmle.Extraction/Extractor.cs b/csharp/extractor/Semmle.Extraction/Extractor.cs index 449f8e18304..fd8aee723e3 100644 --- a/csharp/extractor/Semmle.Extraction/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction/Extractor.cs @@ -88,15 +88,21 @@ namespace Semmle.Extraction /// Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope); - IdentifierMode Identifiers { get; } + /// + /// Adjusts the algorithm used to generate identifiers in trap files. + /// + TrapIdenfierMode TrapIdentifiers { get; } } - public enum IdentifierMode + /// + /// Configures how to generate identifiers in trap files. + /// + public enum TrapIdenfierMode { - Imprecise, - Flexible, - Precise, - ExtraPrecise + Imprecise, // Names are not qualified by assembly version + Flexible, // Some names are qualified by assembly versions - typerefs are not however. + Precise, // All names are qualified by their partial assembly version (excludes build number) + ExtraPrecise // All names are qualified by their full assembly version. } /// @@ -122,7 +128,7 @@ namespace Semmle.Extraction public Extractor(bool standalone, string outputPath, ILogger logger) { Standalone = standalone; - if (Standalone) Identifiers = IdentifierMode.Imprecise; + if (Standalone) TrapIdentifiers = TrapIdenfierMode.Imprecise; OutputPath = outputPath; Logger = logger; } @@ -209,6 +215,6 @@ namespace Semmle.Extraction public static string Version => $"{ThisAssembly.Git.BaseTag} ({ThisAssembly.Git.Sha})"; - public IdentifierMode Identifiers { get; } = IdentifierMode.Imprecise; + public TrapIdenfierMode TrapIdentifiers { get; } = TrapIdenfierMode.Imprecise; } } diff --git a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll index 80c4d1250ca..afa80c43ae6 100644 --- a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll +++ b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll @@ -8,8 +8,7 @@ import csharp -// private -module Annotations { +private module Annotations { newtype TAnnotation = TNotNullableRefType() or TNullableRefType() or @@ -81,8 +80,6 @@ module Annotations { TAnnotationFlags(int flags, Nullability n) { exists(Element e | flags = getElementTypeFlags(e) and n = getElementNullability(e)) or - flags = getTypeParameterFlags(_, _) and n instanceof DefaultOblivious - or flags = 0 // n is unbound } @@ -93,10 +90,17 @@ module Annotations { TypeAnnotations() { this = TAnnotationFlags(flags, nullability) } + /** Gets the flags (as a bitset) of this type annotation. */ int getFlags() { result = flags } + /** Gets the nullability of this type annotation. */ Nullability getNullability() { result = nullability } + /** + * Gets the `i`th "child" of this type annotation. + * This is used to represent structured datatypes, where the structure + * of the type annotation mirrors the structure of the annotated type. + */ bindingset[i] TypeAnnotations getChild(int i) { result.getFlags() = 0 and result.getNullability() = this.getNullability().getMember(i) @@ -138,30 +142,68 @@ module Annotations { } } - // A structure to encode the nullability of various types. For example + /** + * A structured type annotation representing type nullability. + * For example, `IDictionary?` has nullability `?`. + */ class Nullability extends @nullability { - abstract string toString(); + string toString() { result = getMemberString() + getSelfNullability() } + language[monotonicAggregates] + private string getMemberString() { + if nullability_member(this, _, _) + then + result = "<" + + concat(int i, Nullability child | + nullability_member(this, i, child) + | + child.toString(), "," order by i + ) + ">" + else result = "" + } + + /** + * Gets the `i`th member of this annotation. + * Returns `this` if the nullability is not explicitly + * stored in the database, since many type annotations will have consistent + * nullability. + */ bindingset[i] Nullability getMember(int i) { if nullability_member(this, i, _) then nullability_member(this, i, result) else result = this } + + /** Gets a string representing the nullability. */ + abstract string getSelfNullability(); } + /** + * A type that is "oblivious", either because nullability is not + * applicable, because the code was not compiled in a nullable context, or + * because the C# language version is less than 8. + */ class ObliviousNullability extends Nullability, @oblivious { - override string toString() { result = "oblivious" } + override string getSelfNullability() { result = "_" } } - class DefaultOblivious extends ObliviousNullability { - DefaultOblivious() { not nullability_member(this, _, _) } + /** + * A type that is "fully" oblivious. The type itself is oblivious + * and all type arguments are oblivious. + */ + class NoNullability extends ObliviousNullability { + NoNullability() { not nullability_member(this, _, _) } } + /** A type with annotated nullablity, `?`. */ class AnnotatedNullability extends Nullability, @annotated { - override string toString() { result = "annotated" } + override string getSelfNullability() { result = "?" } } + /** + * A ref type not annotated with `?` in a nullable context. + */ class NotAnnotatedNullability extends Nullability, @not_annotated { - override string toString() { result = "not annotated" } + override string getSelfNullability() { result = "!" } } /** Holds if the type annotations `annotations` apply to type `type` on element `element`. */ @@ -176,8 +218,6 @@ module Annotations { or type = element.(Expr).getType() or - // or - // type = element.(ArrayType).getElementType() type = element.(DelegateType).getReturnType() ) } @@ -195,15 +235,21 @@ private int getElementTypeFlags(@has_type_annotation element) { result = sum(int b | type_annotation(element, b) | b) } -private int getTypeParameterFlags(TypeParameterConstraints constraints, Type type) { - specific_type_parameter_annotation(constraints, getTypeRef(type), _) and - result = sum(int b | specific_type_parameter_annotation(constraints, getTypeRef(type), b) | b) +private Annotations::Nullability getTypeParameterNullability( + TypeParameterConstraints constraints, Type type +) { + if specific_type_parameter_nullability(constraints, getTypeRef(type), _) + then specific_type_parameter_nullability(constraints, getTypeRef(type), result) + else ( + specific_type_parameter_constraints(constraints, type) and + result instanceof Annotations::NoNullability + ) } private Annotations::Nullability getElementNullability(@has_type_annotation element) { if type_nullability(element, _) then type_nullability(element, result) - else result instanceof Annotations::DefaultOblivious + else result instanceof Annotations::NoNullability } private newtype TAnnotatedType = @@ -215,12 +261,12 @@ private newtype TAnnotatedType = annotations = c.getAnnotations().getChild(i) ) or - annotations.getFlags() = getTypeParameterFlags(_, type) and - annotations.getNullability() instanceof Annotations::DefaultOblivious - or - // All types annotations.getFlags() = 0 and - annotations.getNullability() instanceof Annotations::DefaultOblivious + annotations.getNullability() = getTypeParameterNullability(_, type) + or + // All types exist as AnnotatedTypes with NoNullability. + annotations.getFlags() = 0 and + annotations.getNullability() instanceof Annotations::NoNullability or exists(AnnotatedArrayType at | type = at.getType().(ArrayType).getElementType() and @@ -228,9 +274,10 @@ private newtype TAnnotatedType = ) } -/** A type with additional information. */ +/** A type with additional type information. */ class AnnotatedType extends TAnnotatedType { Type type; + Annotations::TypeAnnotations annotations; AnnotatedType() { this = TAnnotatedTypeNullability(type, annotations) } @@ -298,11 +345,12 @@ class AnnotatedType extends TAnnotatedType { /** Holds if this annotated type applies to type parameter constraints `constraints`. */ predicate appliesToTypeConstraint(TypeParameterConstraints constraints) { - annotations.getFlags() = getTypeParameterFlags(constraints, type) + this.getAnnotations().getFlags() = 0 and + this.getAnnotations().getNullability() = getTypeParameterNullability(constraints, type) } } -/** An array type with additional information. */ +/** An array type with additional type information. */ class AnnotatedArrayType extends AnnotatedType { override ArrayType type; @@ -332,7 +380,7 @@ class AnnotatedArrayType extends AnnotatedType { } } -/** A constructed type with additional information. */ +/** A constructed type with additional type information. */ class AnnotatedConstructedType extends AnnotatedType { override ConstructedType type; diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index e8b3d5aca88..a26548ca242 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -527,10 +527,10 @@ specific_type_parameter_constraints( int id: @type_parameter_constraints ref, int base_id: @type_or_ref ref); -specific_type_parameter_annotation( +specific_type_parameter_nullability( int id: @type_parameter_constraints ref, int base_id: @type_or_ref ref, - int annotation: int ref); + int nullability: @nullability ref); /** MODIFIERS */ diff --git a/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.expected b/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.expected index 04ae7641c05..d388d2fdb7c 100644 --- a/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.expected +++ b/csharp/ql/test/library-tests/csharp8/NullCoalescingAssignment.expected @@ -1,5 +1,5 @@ nullcoalescing | NullCoalescingAssignment.cs:8:9:8:18 | ... ?? ... | -| NullableRefTypes.cs:88:17:88:25 | ... ?? ... | +| NullableRefTypes.cs:94:17:94:25 | ... ?? ... | assignments | NullCoalescingAssignment.cs:8:9:8:18 | ... ??= ... | NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.cs b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.cs index 21847241a06..0d1a12ccfee 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.cs +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.cs @@ -55,6 +55,12 @@ class MyClass { } + class Generic2 + where T1: MyClass + where T2: Generic, MyClass> + { + } + // Nullable type arguments Generic items2; diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected index b310a0f52d5..4ea99349aa8 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected @@ -1,150 +1,150 @@ suppressNullableWarnings -| NullableRefTypes.cs:79:20:79:21 | ...! | NullableRefTypes.cs:79:20:79:20 | access to local variable x | -| NullableRefTypes.cs:80:13:80:14 | ...! | NullableRefTypes.cs:80:13:80:13 | access to local variable x | -| NullableRefTypes.cs:80:13:80:15 | ...! | NullableRefTypes.cs:80:13:80:14 | ...! | -| NullableRefTypes.cs:82:13:82:14 | ...! | NullableRefTypes.cs:82:13:82:13 | access to local variable x | -| NullableRefTypes.cs:107:36:107:44 | ...! | NullableRefTypes.cs:107:36:107:43 | access to field Property | +| NullableRefTypes.cs:85:20:85:21 | ...! | NullableRefTypes.cs:85:20:85:20 | access to local variable x | +| NullableRefTypes.cs:86:13:86:14 | ...! | NullableRefTypes.cs:86:13:86:13 | access to local variable x | +| NullableRefTypes.cs:86:13:86:15 | ...! | NullableRefTypes.cs:86:13:86:14 | ...! | +| NullableRefTypes.cs:88:13:88:14 | ...! | NullableRefTypes.cs:88:13:88:13 | access to local variable x | +| NullableRefTypes.cs:113:36:113:44 | ...! | NullableRefTypes.cs:113:36:113:43 | access to field Property | nullableDataFlow -| NullableRefTypes.cs:78:17:78:28 | SSA def(x) | NullableRefTypes.cs:79:20:79:20 | access to local variable x | -| NullableRefTypes.cs:78:21:78:28 | "source" | NullableRefTypes.cs:78:17:78:28 | SSA def(x) | -| NullableRefTypes.cs:79:20:79:20 | access to local variable x | NullableRefTypes.cs:79:20:79:21 | ...! | -| NullableRefTypes.cs:79:20:79:20 | access to local variable x | NullableRefTypes.cs:80:13:80:13 | access to local variable x | -| NullableRefTypes.cs:80:13:80:13 | access to local variable x | NullableRefTypes.cs:80:13:80:14 | ...! | -| NullableRefTypes.cs:80:13:80:14 | ...! | NullableRefTypes.cs:80:13:80:15 | ...! | -| NullableRefTypes.cs:81:9:81:16 | SSA def(x) | NullableRefTypes.cs:82:13:82:13 | access to local variable x | -| NullableRefTypes.cs:81:13:81:16 | null | NullableRefTypes.cs:81:9:81:16 | SSA def(x) | -| NullableRefTypes.cs:82:13:82:13 | access to local variable x | NullableRefTypes.cs:82:13:82:14 | ...! | +| NullableRefTypes.cs:84:17:84:28 | SSA def(x) | NullableRefTypes.cs:85:20:85:20 | access to local variable x | +| NullableRefTypes.cs:84:21:84:28 | "source" | NullableRefTypes.cs:84:17:84:28 | SSA def(x) | +| NullableRefTypes.cs:85:20:85:20 | access to local variable x | NullableRefTypes.cs:85:20:85:21 | ...! | +| NullableRefTypes.cs:85:20:85:20 | access to local variable x | NullableRefTypes.cs:86:13:86:13 | access to local variable x | +| NullableRefTypes.cs:86:13:86:13 | access to local variable x | NullableRefTypes.cs:86:13:86:14 | ...! | +| NullableRefTypes.cs:86:13:86:14 | ...! | NullableRefTypes.cs:86:13:86:15 | ...! | +| NullableRefTypes.cs:87:9:87:16 | SSA def(x) | NullableRefTypes.cs:88:13:88:13 | access to local variable x | +| NullableRefTypes.cs:87:13:87:16 | null | NullableRefTypes.cs:87:9:87:16 | SSA def(x) | +| NullableRefTypes.cs:88:13:88:13 | access to local variable x | NullableRefTypes.cs:88:13:88:14 | ...! | nullableControlFlow -| NullableRefTypes.cs:76:10:76:40 | enter TestSuppressNullableWarningExpr | NullableRefTypes.cs:77:5:83:5 | {...} | successor | -| NullableRefTypes.cs:77:5:83:5 | {...} | NullableRefTypes.cs:78:9:78:29 | ... ...; | successor | -| NullableRefTypes.cs:78:9:78:29 | ... ...; | NullableRefTypes.cs:78:21:78:28 | "source" | successor | -| NullableRefTypes.cs:78:17:78:28 | String x = ... | NullableRefTypes.cs:79:9:79:22 | ... ...; | successor | -| NullableRefTypes.cs:78:21:78:28 | "source" | NullableRefTypes.cs:78:17:78:28 | String x = ... | successor | -| NullableRefTypes.cs:79:9:79:22 | ... ...; | NullableRefTypes.cs:79:20:79:20 | access to local variable x | successor | -| NullableRefTypes.cs:79:16:79:21 | String y = ... | NullableRefTypes.cs:80:9:80:16 | ...; | successor | -| NullableRefTypes.cs:79:20:79:20 | access to local variable x | NullableRefTypes.cs:79:20:79:21 | ...! | successor | -| NullableRefTypes.cs:79:20:79:21 | ...! | NullableRefTypes.cs:79:16:79:21 | String y = ... | successor | -| NullableRefTypes.cs:80:9:80:15 | ... = ... | NullableRefTypes.cs:81:9:81:17 | ...; | successor | -| NullableRefTypes.cs:80:9:80:16 | ...; | NullableRefTypes.cs:80:13:80:13 | access to local variable x | successor | -| NullableRefTypes.cs:80:13:80:13 | access to local variable x | NullableRefTypes.cs:80:13:80:14 | ...! | successor | -| NullableRefTypes.cs:80:13:80:14 | ...! | NullableRefTypes.cs:80:13:80:15 | ...! | successor | -| NullableRefTypes.cs:80:13:80:15 | ...! | NullableRefTypes.cs:80:9:80:15 | ... = ... | successor | -| NullableRefTypes.cs:81:9:81:16 | ... = ... | NullableRefTypes.cs:82:9:82:15 | ...; | successor | -| NullableRefTypes.cs:81:9:81:17 | ...; | NullableRefTypes.cs:81:13:81:16 | null | successor | -| NullableRefTypes.cs:81:13:81:16 | null | NullableRefTypes.cs:81:9:81:16 | ... = ... | successor | -| NullableRefTypes.cs:82:9:82:14 | ... = ... | NullableRefTypes.cs:76:10:76:40 | exit TestSuppressNullableWarningExpr | successor | -| NullableRefTypes.cs:82:9:82:15 | ...; | NullableRefTypes.cs:82:13:82:13 | access to local variable x | successor | -| NullableRefTypes.cs:82:13:82:13 | access to local variable x | NullableRefTypes.cs:82:13:82:14 | ...! | successor | -| NullableRefTypes.cs:82:13:82:14 | ...! | NullableRefTypes.cs:82:9:82:14 | ... = ... | successor | +| NullableRefTypes.cs:82:10:82:40 | enter TestSuppressNullableWarningExpr | NullableRefTypes.cs:83:5:89:5 | {...} | successor | +| NullableRefTypes.cs:83:5:89:5 | {...} | NullableRefTypes.cs:84:9:84:29 | ... ...; | successor | +| NullableRefTypes.cs:84:9:84:29 | ... ...; | NullableRefTypes.cs:84:21:84:28 | "source" | successor | +| NullableRefTypes.cs:84:17:84:28 | String x = ... | NullableRefTypes.cs:85:9:85:22 | ... ...; | successor | +| NullableRefTypes.cs:84:21:84:28 | "source" | NullableRefTypes.cs:84:17:84:28 | String x = ... | successor | +| NullableRefTypes.cs:85:9:85:22 | ... ...; | NullableRefTypes.cs:85:20:85:20 | access to local variable x | successor | +| NullableRefTypes.cs:85:16:85:21 | String y = ... | NullableRefTypes.cs:86:9:86:16 | ...; | successor | +| NullableRefTypes.cs:85:20:85:20 | access to local variable x | NullableRefTypes.cs:85:20:85:21 | ...! | successor | +| NullableRefTypes.cs:85:20:85:21 | ...! | NullableRefTypes.cs:85:16:85:21 | String y = ... | successor | +| NullableRefTypes.cs:86:9:86:15 | ... = ... | NullableRefTypes.cs:87:9:87:17 | ...; | successor | +| NullableRefTypes.cs:86:9:86:16 | ...; | NullableRefTypes.cs:86:13:86:13 | access to local variable x | successor | +| NullableRefTypes.cs:86:13:86:13 | access to local variable x | NullableRefTypes.cs:86:13:86:14 | ...! | successor | +| NullableRefTypes.cs:86:13:86:14 | ...! | NullableRefTypes.cs:86:13:86:15 | ...! | successor | +| NullableRefTypes.cs:86:13:86:15 | ...! | NullableRefTypes.cs:86:9:86:15 | ... = ... | successor | +| NullableRefTypes.cs:87:9:87:16 | ... = ... | NullableRefTypes.cs:88:9:88:15 | ...; | successor | +| NullableRefTypes.cs:87:9:87:17 | ...; | NullableRefTypes.cs:87:13:87:16 | null | successor | +| NullableRefTypes.cs:87:13:87:16 | null | NullableRefTypes.cs:87:9:87:16 | ... = ... | successor | +| NullableRefTypes.cs:88:9:88:14 | ... = ... | NullableRefTypes.cs:82:10:82:40 | exit TestSuppressNullableWarningExpr | successor | +| NullableRefTypes.cs:88:9:88:15 | ...; | NullableRefTypes.cs:88:13:88:13 | access to local variable x | successor | +| NullableRefTypes.cs:88:13:88:13 | access to local variable x | NullableRefTypes.cs:88:13:88:14 | ...! | successor | +| NullableRefTypes.cs:88:13:88:14 | ...! | NullableRefTypes.cs:88:9:88:14 | ... = ... | successor | nonNullExpressions -| NullableRefTypes.cs:78:21:78:28 | "source" | -| NullableRefTypes.cs:79:20:79:20 | access to local variable x | -| NullableRefTypes.cs:79:20:79:21 | ...! | -| NullableRefTypes.cs:80:9:80:15 | ... = ... | -| NullableRefTypes.cs:80:13:80:13 | access to local variable x | -| NullableRefTypes.cs:80:13:80:14 | ...! | -| NullableRefTypes.cs:80:13:80:15 | ...! | -| NullableRefTypes.cs:82:9:82:14 | ... = ... | -| NullableRefTypes.cs:82:13:82:14 | ...! | +| NullableRefTypes.cs:84:21:84:28 | "source" | +| NullableRefTypes.cs:85:20:85:20 | access to local variable x | +| NullableRefTypes.cs:85:20:85:21 | ...! | +| NullableRefTypes.cs:86:9:86:15 | ... = ... | +| NullableRefTypes.cs:86:13:86:13 | access to local variable x | +| NullableRefTypes.cs:86:13:86:14 | ...! | +| NullableRefTypes.cs:86:13:86:15 | ...! | +| NullableRefTypes.cs:88:9:88:14 | ... = ... | +| NullableRefTypes.cs:88:13:88:14 | ...! | assignableTypes -| NullableRefTypes.cs:9:14:9:14 | A | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:10:13:10:13 | B | NullableRefTypes.cs:6:7:6:13 | MyClass! | -| NullableRefTypes.cs:13:14:13:14 | C | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:14:13:14:13 | D | NullableRefTypes.cs:6:7:6:13 | MyClass! | -| NullableRefTypes.cs:17:14:17:17 | Item | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:18:13:18:16 | Item | NullableRefTypes.cs:6:7:6:13 | MyClass! | -| NullableRefTypes.cs:19:13:19:16 | Item | NullableRefTypes.cs:6:7:6:13 | MyClass! | -| NullableRefTypes.cs:19:27:19:27 | i | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:19:27:19:27 | i | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:22:16:22:17 | G1 | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | -| NullableRefTypes.cs:23:17:23:18 | G2 | NullableRefTypes.cs:6:7:6:13 | MyClass?[]? | -| NullableRefTypes.cs:24:16:24:17 | G3 | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | -| NullableRefTypes.cs:25:18:25:18 | H | NullableRefTypes.cs:6:7:6:13 | MyClass?[][]! | -| NullableRefTypes.cs:26:38:26:38 | x | NullableRefTypes.cs:6:7:6:13 | MyClass![]?[]! | -| NullableRefTypes.cs:27:38:27:38 | x | NullableRefTypes.cs:6:7:6:13 | MyClass?[][]! | -| NullableRefTypes.cs:32:20:32:20 | a | NullableRefTypes.cs:6:7:6:13 | MyClass! | -| NullableRefTypes.cs:32:31:32:31 | b | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:37:17:37:17 | a | NullableRefTypes.cs:6:7:6:13 | MyClass! | -| NullableRefTypes.cs:38:18:38:18 | b | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:39:21:39:21 | c | NullableRefTypes.cs:6:7:6:13 | ref MyClass! | -| NullableRefTypes.cs:40:22:40:22 | d | NullableRefTypes.cs:6:7:6:13 | ref MyClass? | -| NullableRefTypes.cs:47:35:47:35 | x | NullableRefTypes.cs:6:7:6:13 | MyClass! | -| NullableRefTypes.cs:47:35:47:35 | x | NullableRefTypes.cs:6:7:6:13 | MyClass! | -| NullableRefTypes.cs:47:35:47:35 | x | NullableRefTypes.cs:6:7:6:13 | MyClass! | -| NullableRefTypes.cs:48:16:48:16 | P | NullableRefTypes.cs:47:23:47:25 | Del? | -| NullableRefTypes.cs:48:16:48:16 | value | NullableRefTypes.cs:47:23:47:25 | Del? | -| NullableRefTypes.cs:48:16:48:16 | value | NullableRefTypes.cs:47:23:47:25 | Del? | -| NullableRefTypes.cs:51:19:51:19 | t | NullableRefTypes.cs:6:7:6:13 | MyClass | -| NullableRefTypes.cs:51:19:51:19 | t | NullableRefTypes.cs:51:14:51:14 | T! | -| NullableRefTypes.cs:59:54:59:59 | items2 | NullableRefTypes.cs:54:11:54:33 | Generic! | -| NullableRefTypes.cs:61:25:61:25 | x | NullableRefTypes.cs:6:7:6:13 | MyClass | -| NullableRefTypes.cs:61:25:61:25 | x | NullableRefTypes.cs:61:20:61:20 | T! | -| NullableRefTypes.cs:67:18:67:18 | x | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:97:42:97:42 | r | NullableRefTypes.cs:6:7:6:13 | ref MyClass! | -| NullableRefTypes.cs:98:42:98:42 | r | NullableRefTypes.cs:6:7:6:13 | ref MyClass? | -| NullableRefTypes.cs:99:51:99:51 | r | NullableRefTypes.cs:6:7:6:13 | readonly MyClass? | -| NullableRefTypes.cs:100:50:100:50 | r | NullableRefTypes.cs:6:7:6:13 | readonly MyClass! | -| NullableRefTypes.cs:101:49:101:49 | r | NullableRefTypes.cs:6:7:6:13 | readonly MyClass! | -| NullableRefTypes.cs:102:50:102:50 | r | NullableRefTypes.cs:6:7:6:13 | readonly MyClass? | -| NullableRefTypes.cs:104:34:104:35 | p1 | NullableRefTypes.cs:6:7:6:13 | ref MyClass! | -| NullableRefTypes.cs:104:51:104:52 | p2 | NullableRefTypes.cs:6:7:6:13 | out MyClass? | -| NullableRefTypes.cs:106:14:106:21 | Property | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:107:17:107:27 | RefProperty | NullableRefTypes.cs:6:7:6:13 | ref MyClass! | -| NullableRefTypes.cs:112:15:112:15 | a | NullableRefTypes.cs:159:8:159:15 | MyStruct? | -| NullableRefTypes.cs:113:17:113:17 | b | NullableRefTypes.cs:159:8:159:15 | MyStruct![]? | -| NullableRefTypes.cs:114:17:114:17 | c | NullableRefTypes.cs:159:8:159:15 | MyStruct?[]! | -| NullableRefTypes.cs:115:18:115:18 | d | NullableRefTypes.cs:159:8:159:15 | MyStruct?[]? | -| NullableRefTypes.cs:117:14:117:14 | e | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:118:16:118:16 | f | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | -| NullableRefTypes.cs:119:16:119:16 | g | NullableRefTypes.cs:6:7:6:13 | MyClass![]? | -| NullableRefTypes.cs:120:17:120:17 | h | NullableRefTypes.cs:6:7:6:13 | MyClass?[]? | -| NullableRefTypes.cs:122:23:122:23 | i | NullableRefTypes.cs:6:7:6:13 | MyClass![,,]?[,][]! | -| NullableRefTypes.cs:123:22:123:22 | j | NullableRefTypes.cs:6:7:6:13 | MyClass![,,][,][]! | -| NullableRefTypes.cs:124:27:124:27 | k | NullableRefTypes.cs:6:7:6:13 | MyClass![,,,][][,][,,]! | -| NullableRefTypes.cs:125:29:125:29 | l | NullableRefTypes.cs:6:7:6:13 | MyClass?[,,,][][,]?[,,]! | -| NullableRefTypes.cs:132:15:132:15 | a | NullableRefTypes.cs:159:8:159:15 | MyStruct? | -| NullableRefTypes.cs:133:17:133:17 | b | NullableRefTypes.cs:159:8:159:15 | MyStruct![]? | -| NullableRefTypes.cs:134:17:134:17 | c | NullableRefTypes.cs:159:8:159:15 | MyStruct?[] | -| NullableRefTypes.cs:135:18:135:18 | d | NullableRefTypes.cs:159:8:159:15 | MyStruct?[]? | -| NullableRefTypes.cs:137:14:137:14 | e | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:138:16:138:16 | f | NullableRefTypes.cs:6:7:6:13 | MyClass?[] | -| NullableRefTypes.cs:139:16:139:16 | g | NullableRefTypes.cs:6:7:6:13 | MyClass[]? | -| NullableRefTypes.cs:140:17:140:17 | h | NullableRefTypes.cs:6:7:6:13 | MyClass?[]? | -| NullableRefTypes.cs:142:23:142:23 | i | NullableRefTypes.cs:6:7:6:13 | MyClass[,,]?[,][] | -| NullableRefTypes.cs:143:22:143:22 | j | NullableRefTypes.cs:6:7:6:13 | MyClass[,,][,][] | -| NullableRefTypes.cs:144:27:144:27 | k | NullableRefTypes.cs:6:7:6:13 | MyClass[,,,][][,][,,] | -| NullableRefTypes.cs:145:29:145:29 | l | NullableRefTypes.cs:6:7:6:13 | MyClass?[,,,][][,]?[,,] | -| NullableRefTypes.cs:150:13:150:14 | f1 | NullableRefTypes.cs:6:7:6:13 | MyClass | -| NullableRefTypes.cs:151:13:151:13 | P | NullableRefTypes.cs:6:7:6:13 | MyClass | -| NullableRefTypes.cs:152:24:152:24 | p | NullableRefTypes.cs:6:7:6:13 | MyClass | -| NullableRefTypes.cs:154:17:154:17 | a | NullableRefTypes.cs:6:7:6:13 | MyClass | +| NullableRefTypes.cs:9:14:9:14 | A | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:10:13:10:13 | B | NullableRefTypes.cs:6:7:6:13 | MyClass! | ! | +| NullableRefTypes.cs:13:14:13:14 | C | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:14:13:14:13 | D | NullableRefTypes.cs:6:7:6:13 | MyClass! | ! | +| NullableRefTypes.cs:17:14:17:17 | Item | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:18:13:18:16 | Item | NullableRefTypes.cs:6:7:6:13 | MyClass! | ! | +| NullableRefTypes.cs:19:13:19:16 | Item | NullableRefTypes.cs:6:7:6:13 | MyClass! | ! | +| NullableRefTypes.cs:19:27:19:27 | i | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:19:27:19:27 | i | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:22:16:22:17 | G1 | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | ! | +| NullableRefTypes.cs:23:17:23:18 | G2 | NullableRefTypes.cs:6:7:6:13 | MyClass?[]? | ? | +| NullableRefTypes.cs:24:16:24:17 | G3 | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | ! | +| NullableRefTypes.cs:25:18:25:18 | H | NullableRefTypes.cs:6:7:6:13 | MyClass?[][]! | <!>! | +| NullableRefTypes.cs:26:38:26:38 | x | NullableRefTypes.cs:6:7:6:13 | MyClass![]?[]! | <?>! | +| NullableRefTypes.cs:27:38:27:38 | x | NullableRefTypes.cs:6:7:6:13 | MyClass?[][]! | <!>! | +| NullableRefTypes.cs:32:20:32:20 | a | NullableRefTypes.cs:6:7:6:13 | MyClass! | ! | +| NullableRefTypes.cs:32:31:32:31 | b | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:37:17:37:17 | a | NullableRefTypes.cs:6:7:6:13 | MyClass! | ! | +| NullableRefTypes.cs:38:18:38:18 | b | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:39:21:39:21 | c | NullableRefTypes.cs:6:7:6:13 | ref MyClass! | ! | +| NullableRefTypes.cs:40:22:40:22 | d | NullableRefTypes.cs:6:7:6:13 | ref MyClass? | ? | +| NullableRefTypes.cs:47:35:47:35 | x | NullableRefTypes.cs:6:7:6:13 | MyClass! | ! | +| NullableRefTypes.cs:47:35:47:35 | x | NullableRefTypes.cs:6:7:6:13 | MyClass! | ! | +| NullableRefTypes.cs:47:35:47:35 | x | NullableRefTypes.cs:6:7:6:13 | MyClass! | ! | +| NullableRefTypes.cs:48:16:48:16 | P | NullableRefTypes.cs:47:23:47:25 | Del? | ? | +| NullableRefTypes.cs:48:16:48:16 | value | NullableRefTypes.cs:47:23:47:25 | Del? | ? | +| NullableRefTypes.cs:48:16:48:16 | value | NullableRefTypes.cs:47:23:47:25 | Del? | ? | +| NullableRefTypes.cs:51:19:51:19 | t | NullableRefTypes.cs:6:7:6:13 | MyClass | _ | +| NullableRefTypes.cs:51:19:51:19 | t | NullableRefTypes.cs:51:14:51:14 | T! | ! | +| NullableRefTypes.cs:65:54:65:59 | items2 | NullableRefTypes.cs:54:11:54:33 | Generic! | ! | +| NullableRefTypes.cs:67:25:67:25 | x | NullableRefTypes.cs:6:7:6:13 | MyClass | _ | +| NullableRefTypes.cs:67:25:67:25 | x | NullableRefTypes.cs:67:20:67:20 | T! | ! | +| NullableRefTypes.cs:73:18:73:18 | x | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:103:42:103:42 | r | NullableRefTypes.cs:6:7:6:13 | ref MyClass! | ! | +| NullableRefTypes.cs:104:42:104:42 | r | NullableRefTypes.cs:6:7:6:13 | ref MyClass? | ? | +| NullableRefTypes.cs:105:51:105:51 | r | NullableRefTypes.cs:6:7:6:13 | readonly MyClass? | ? | +| NullableRefTypes.cs:106:50:106:50 | r | NullableRefTypes.cs:6:7:6:13 | readonly MyClass! | ! | +| NullableRefTypes.cs:107:49:107:49 | r | NullableRefTypes.cs:6:7:6:13 | readonly MyClass! | ! | +| NullableRefTypes.cs:108:50:108:50 | r | NullableRefTypes.cs:6:7:6:13 | readonly MyClass? | ? | +| NullableRefTypes.cs:110:34:110:35 | p1 | NullableRefTypes.cs:6:7:6:13 | ref MyClass! | ! | +| NullableRefTypes.cs:110:51:110:52 | p2 | NullableRefTypes.cs:6:7:6:13 | out MyClass? | ? | +| NullableRefTypes.cs:112:14:112:21 | Property | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:113:17:113:27 | RefProperty | NullableRefTypes.cs:6:7:6:13 | ref MyClass! | ! | +| NullableRefTypes.cs:118:15:118:15 | a | NullableRefTypes.cs:165:8:165:15 | MyStruct? | <_>? | +| NullableRefTypes.cs:119:17:119:17 | b | NullableRefTypes.cs:165:8:165:15 | MyStruct![]? | ? | +| NullableRefTypes.cs:120:17:120:17 | c | NullableRefTypes.cs:165:8:165:15 | MyStruct?[]! | <<_>?>! | +| NullableRefTypes.cs:121:18:121:18 | d | NullableRefTypes.cs:165:8:165:15 | MyStruct?[]? | <<_>?>? | +| NullableRefTypes.cs:123:14:123:14 | e | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:124:16:124:16 | f | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | ! | +| NullableRefTypes.cs:125:16:125:16 | g | NullableRefTypes.cs:6:7:6:13 | MyClass![]? | ? | +| NullableRefTypes.cs:126:17:126:17 | h | NullableRefTypes.cs:6:7:6:13 | MyClass?[]? | ? | +| NullableRefTypes.cs:128:23:128:23 | i | NullableRefTypes.cs:6:7:6:13 | MyClass![,,]?[,][]! | <<?>!>! | +| NullableRefTypes.cs:129:22:129:22 | j | NullableRefTypes.cs:6:7:6:13 | MyClass![,,][,][]! | ! | +| NullableRefTypes.cs:130:27:130:27 | k | NullableRefTypes.cs:6:7:6:13 | MyClass![,,,][][,][,,]! | ! | +| NullableRefTypes.cs:131:29:131:29 | l | NullableRefTypes.cs:6:7:6:13 | MyClass?[,,,][][,]?[,,]! | <<<!>!>?>! | +| NullableRefTypes.cs:138:15:138:15 | a | NullableRefTypes.cs:165:8:165:15 | MyStruct? | <_>? | +| NullableRefTypes.cs:139:17:139:17 | b | NullableRefTypes.cs:165:8:165:15 | MyStruct[]? | <_>? | +| NullableRefTypes.cs:140:17:140:17 | c | NullableRefTypes.cs:165:8:165:15 | MyStruct?[] | <<_>?>_ | +| NullableRefTypes.cs:141:18:141:18 | d | NullableRefTypes.cs:165:8:165:15 | MyStruct?[]? | <<_>?>? | +| NullableRefTypes.cs:143:14:143:14 | e | NullableRefTypes.cs:6:7:6:13 | MyClass? | ? | +| NullableRefTypes.cs:144:16:144:16 | f | NullableRefTypes.cs:6:7:6:13 | MyClass?[] | _ | +| NullableRefTypes.cs:145:16:145:16 | g | NullableRefTypes.cs:6:7:6:13 | MyClass[]? | <_>? | +| NullableRefTypes.cs:146:17:146:17 | h | NullableRefTypes.cs:6:7:6:13 | MyClass?[]? | ? | +| NullableRefTypes.cs:148:23:148:23 | i | NullableRefTypes.cs:6:7:6:13 | MyClass[,,]?[,][] | <<<_>?>_>_ | +| NullableRefTypes.cs:149:22:149:22 | j | NullableRefTypes.cs:6:7:6:13 | MyClass[,,][,][] | _ | +| NullableRefTypes.cs:150:27:150:27 | k | NullableRefTypes.cs:6:7:6:13 | MyClass[,,,][][,][,,] | _ | +| NullableRefTypes.cs:151:29:151:29 | l | NullableRefTypes.cs:6:7:6:13 | MyClass?[,,,][][,]?[,,] | <<<_>_>?>_ | +| NullableRefTypes.cs:156:13:156:14 | f1 | NullableRefTypes.cs:6:7:6:13 | MyClass | _ | +| NullableRefTypes.cs:157:13:157:13 | P | NullableRefTypes.cs:6:7:6:13 | MyClass | _ | +| NullableRefTypes.cs:158:24:158:24 | p | NullableRefTypes.cs:6:7:6:13 | MyClass | _ | +| NullableRefTypes.cs:160:17:160:17 | a | NullableRefTypes.cs:6:7:6:13 | MyClass | _ | arrayElements -| NullableRefTypes.cs:22:16:22:17 | G1 | NullableRefTypes.cs:6:7:6:13 | MyClass[] | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:23:17:23:18 | G2 | NullableRefTypes.cs:6:7:6:13 | MyClass[] | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:24:16:24:17 | G3 | NullableRefTypes.cs:6:7:6:13 | MyClass[] | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:25:18:25:18 | H | NullableRefTypes.cs:6:7:6:13 | MyClass[][] | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | -| NullableRefTypes.cs:26:38:26:38 | x | NullableRefTypes.cs:6:7:6:13 | MyClass[][] | NullableRefTypes.cs:6:7:6:13 | MyClass![]? | -| NullableRefTypes.cs:27:38:27:38 | x | NullableRefTypes.cs:6:7:6:13 | MyClass[][] | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | -| NullableRefTypes.cs:113:17:113:17 | b | NullableRefTypes.cs:159:8:159:15 | MyStruct[] | NullableRefTypes.cs:159:8:159:15 | MyStruct! | -| NullableRefTypes.cs:114:17:114:17 | c | NullableRefTypes.cs:159:8:159:15 | Nullable | NullableRefTypes.cs:159:8:159:15 | MyStruct? | -| NullableRefTypes.cs:115:18:115:18 | d | NullableRefTypes.cs:159:8:159:15 | Nullable | NullableRefTypes.cs:159:8:159:15 | MyStruct? | -| NullableRefTypes.cs:118:16:118:16 | f | NullableRefTypes.cs:6:7:6:13 | MyClass[] | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:119:16:119:16 | g | NullableRefTypes.cs:6:7:6:13 | MyClass[] | NullableRefTypes.cs:6:7:6:13 | MyClass! | -| NullableRefTypes.cs:120:17:120:17 | h | NullableRefTypes.cs:6:7:6:13 | MyClass[] | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:122:23:122:23 | i | NullableRefTypes.cs:6:7:6:13 | MyClass[,,][][,] | NullableRefTypes.cs:6:7:6:13 | MyClass![,,]?[]! | -| NullableRefTypes.cs:123:22:123:22 | j | NullableRefTypes.cs:6:7:6:13 | MyClass[][,][,,] | NullableRefTypes.cs:6:7:6:13 | MyClass![,][]! | -| NullableRefTypes.cs:124:27:124:27 | k | NullableRefTypes.cs:6:7:6:13 | MyClass[,,][,][][,,,] | NullableRefTypes.cs:6:7:6:13 | MyClass![][,][,,]! | -| NullableRefTypes.cs:125:29:125:29 | l | NullableRefTypes.cs:6:7:6:13 | MyClass[,][][,,,][,,] | NullableRefTypes.cs:6:7:6:13 | MyClass?[,,,][][,]? | -| NullableRefTypes.cs:133:17:133:17 | b | NullableRefTypes.cs:159:8:159:15 | MyStruct[] | NullableRefTypes.cs:159:8:159:15 | MyStruct! | -| NullableRefTypes.cs:134:17:134:17 | c | NullableRefTypes.cs:159:8:159:15 | Nullable | NullableRefTypes.cs:159:8:159:15 | MyStruct? | -| NullableRefTypes.cs:135:18:135:18 | d | NullableRefTypes.cs:159:8:159:15 | Nullable | NullableRefTypes.cs:159:8:159:15 | MyStruct? | -| NullableRefTypes.cs:138:16:138:16 | f | NullableRefTypes.cs:6:7:6:13 | MyClass[] | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:139:16:139:16 | g | NullableRefTypes.cs:6:7:6:13 | MyClass[] | NullableRefTypes.cs:6:7:6:13 | MyClass | -| NullableRefTypes.cs:140:17:140:17 | h | NullableRefTypes.cs:6:7:6:13 | MyClass[] | NullableRefTypes.cs:6:7:6:13 | MyClass? | -| NullableRefTypes.cs:142:23:142:23 | i | NullableRefTypes.cs:6:7:6:13 | MyClass[,,][][,] | NullableRefTypes.cs:6:7:6:13 | MyClass[,,]?[] | -| NullableRefTypes.cs:143:22:143:22 | j | NullableRefTypes.cs:6:7:6:13 | MyClass[][,][,,] | NullableRefTypes.cs:6:7:6:13 | MyClass[,][] | -| NullableRefTypes.cs:144:27:144:27 | k | NullableRefTypes.cs:6:7:6:13 | MyClass[,,][,][][,,,] | NullableRefTypes.cs:6:7:6:13 | MyClass[][,][,,] | -| NullableRefTypes.cs:145:29:145:29 | l | NullableRefTypes.cs:6:7:6:13 | MyClass[,][][,,,][,,] | NullableRefTypes.cs:6:7:6:13 | MyClass?[,,,][][,]? | +| NullableRefTypes.cs:22:16:22:17 | G1 | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | NullableRefTypes.cs:6:7:6:13 | MyClass? | +| NullableRefTypes.cs:23:17:23:18 | G2 | NullableRefTypes.cs:6:7:6:13 | MyClass?[]? | NullableRefTypes.cs:6:7:6:13 | MyClass? | +| NullableRefTypes.cs:24:16:24:17 | G3 | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | NullableRefTypes.cs:6:7:6:13 | MyClass? | +| NullableRefTypes.cs:25:18:25:18 | H | NullableRefTypes.cs:6:7:6:13 | MyClass?[][]! | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | +| NullableRefTypes.cs:26:38:26:38 | x | NullableRefTypes.cs:6:7:6:13 | MyClass![]?[]! | NullableRefTypes.cs:6:7:6:13 | MyClass![]? | +| NullableRefTypes.cs:27:38:27:38 | x | NullableRefTypes.cs:6:7:6:13 | MyClass?[][]! | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | +| NullableRefTypes.cs:119:17:119:17 | b | NullableRefTypes.cs:165:8:165:15 | MyStruct![]? | NullableRefTypes.cs:165:8:165:15 | MyStruct! | +| NullableRefTypes.cs:120:17:120:17 | c | NullableRefTypes.cs:165:8:165:15 | MyStruct?[]! | NullableRefTypes.cs:165:8:165:15 | MyStruct? | +| NullableRefTypes.cs:121:18:121:18 | d | NullableRefTypes.cs:165:8:165:15 | MyStruct?[]? | NullableRefTypes.cs:165:8:165:15 | MyStruct? | +| NullableRefTypes.cs:124:16:124:16 | f | NullableRefTypes.cs:6:7:6:13 | MyClass?[]! | NullableRefTypes.cs:6:7:6:13 | MyClass? | +| NullableRefTypes.cs:125:16:125:16 | g | NullableRefTypes.cs:6:7:6:13 | MyClass![]? | NullableRefTypes.cs:6:7:6:13 | MyClass! | +| NullableRefTypes.cs:126:17:126:17 | h | NullableRefTypes.cs:6:7:6:13 | MyClass?[]? | NullableRefTypes.cs:6:7:6:13 | MyClass? | +| NullableRefTypes.cs:128:23:128:23 | i | NullableRefTypes.cs:6:7:6:13 | MyClass![,,]?[,][]! | NullableRefTypes.cs:6:7:6:13 | MyClass![,,]?[]! | +| NullableRefTypes.cs:129:22:129:22 | j | NullableRefTypes.cs:6:7:6:13 | MyClass![,,][,][]! | NullableRefTypes.cs:6:7:6:13 | MyClass![,][]! | +| NullableRefTypes.cs:130:27:130:27 | k | NullableRefTypes.cs:6:7:6:13 | MyClass![,,,][][,][,,]! | NullableRefTypes.cs:6:7:6:13 | MyClass![][,][,,]! | +| NullableRefTypes.cs:131:29:131:29 | l | NullableRefTypes.cs:6:7:6:13 | MyClass?[,,,][][,]?[,,]! | NullableRefTypes.cs:6:7:6:13 | MyClass?[,,,][][,]? | +| NullableRefTypes.cs:139:17:139:17 | b | NullableRefTypes.cs:165:8:165:15 | MyStruct[]? | NullableRefTypes.cs:165:8:165:15 | MyStruct | +| NullableRefTypes.cs:140:17:140:17 | c | NullableRefTypes.cs:165:8:165:15 | MyStruct?[] | NullableRefTypes.cs:165:8:165:15 | MyStruct? | +| NullableRefTypes.cs:141:18:141:18 | d | NullableRefTypes.cs:165:8:165:15 | MyStruct?[]? | NullableRefTypes.cs:165:8:165:15 | MyStruct? | +| NullableRefTypes.cs:144:16:144:16 | f | NullableRefTypes.cs:6:7:6:13 | MyClass?[] | NullableRefTypes.cs:6:7:6:13 | MyClass? | +| NullableRefTypes.cs:145:16:145:16 | g | NullableRefTypes.cs:6:7:6:13 | MyClass[]? | NullableRefTypes.cs:6:7:6:13 | MyClass | +| NullableRefTypes.cs:146:17:146:17 | h | NullableRefTypes.cs:6:7:6:13 | MyClass?[]? | NullableRefTypes.cs:6:7:6:13 | MyClass? | +| NullableRefTypes.cs:148:23:148:23 | i | NullableRefTypes.cs:6:7:6:13 | MyClass[,,]?[,][] | NullableRefTypes.cs:6:7:6:13 | MyClass[,,]?[] | +| NullableRefTypes.cs:149:22:149:22 | j | NullableRefTypes.cs:6:7:6:13 | MyClass[,,][,][] | NullableRefTypes.cs:6:7:6:13 | MyClass[,][] | +| NullableRefTypes.cs:150:27:150:27 | k | NullableRefTypes.cs:6:7:6:13 | MyClass[,,,][][,][,,] | NullableRefTypes.cs:6:7:6:13 | MyClass[][,][,,] | +| NullableRefTypes.cs:151:29:151:29 | l | NullableRefTypes.cs:6:7:6:13 | MyClass?[,,,][][,]?[,,] | NullableRefTypes.cs:6:7:6:13 | MyClass?[,,,][][,]? | returnTypes | NullableRefTypes.cs:6:7:6:13 | MyClass | Void | | NullableRefTypes.cs:13:19:13:22 | get_C | MyClass? | @@ -168,40 +168,64 @@ returnTypes | NullableRefTypes.cs:47:23:47:25 | Invoke | MyClass? | | NullableRefTypes.cs:48:16:48:16 | add_P | Void | | NullableRefTypes.cs:48:16:48:16 | remove_P | Void | +| NullableRefTypes.cs:51:12:51:15 | Q | object | | NullableRefTypes.cs:51:12:51:15 | Q | object! | | NullableRefTypes.cs:51:12:51:15 | Q | object! | | NullableRefTypes.cs:54:11:54:33 | Generic | Void | -| NullableRefTypes.cs:61:10:61:21 | GenericFn | Void! | -| NullableRefTypes.cs:61:10:61:21 | GenericFn | Void! | -| NullableRefTypes.cs:65:14:65:18 | CallF | MyStruct! | -| NullableRefTypes.cs:74:7:74:22 | NullableRefTypes | Void | -| NullableRefTypes.cs:76:10:76:40 | TestSuppressNullableWarningExpr | Void! | -| NullableRefTypes.cs:85:10:85:34 | FunctionInNullableContext | Void! | -| NullableRefTypes.cs:94:7:94:14 | RefTypes | Void | -| NullableRefTypes.cs:97:18:97:28 | ReturnsRef1 | ref MyClass? | -| NullableRefTypes.cs:98:17:98:27 | ReturnsRef2 | ref MyClass! | -| NullableRefTypes.cs:99:27:99:37 | ReturnsRef3 | readonly MyClass? | -| NullableRefTypes.cs:100:27:100:37 | ReturnsRef4 | readonly MyClass? | -| NullableRefTypes.cs:101:26:101:36 | ReturnsRef5 | readonly MyClass! | -| NullableRefTypes.cs:102:26:102:36 | ReturnsRef6 | readonly MyClass! | -| NullableRefTypes.cs:104:10:104:20 | Parameters1 | Void! | -| NullableRefTypes.cs:107:32:107:44 | get_RefProperty | MyClass! | -| NullableRefTypes.cs:110:7:110:23 | ToStringWithTypes | Void | -| NullableRefTypes.cs:130:7:130:24 | ToStringWithTypes2 | Void | -| NullableRefTypes.cs:148:7:148:25 | DisabledNullability | Void | -| NullableRefTypes.cs:151:18:151:30 | get_P | MyClass | -| NullableRefTypes.cs:152:13:152:14 | Fn | MyClass | -| NullableRefTypes.cs:159:8:159:15 | MyStruct | Void | -typeArguments +| NullableRefTypes.cs:58:11:58:26 | Generic2 | Void | +| NullableRefTypes.cs:67:10:67:21 | GenericFn | Void | +| NullableRefTypes.cs:67:10:67:21 | GenericFn | Void! | +| NullableRefTypes.cs:67:10:67:21 | GenericFn | Void! | +| NullableRefTypes.cs:71:14:71:18 | CallF | MyStruct! | +| NullableRefTypes.cs:80:7:80:22 | NullableRefTypes | Void | +| NullableRefTypes.cs:82:10:82:40 | TestSuppressNullableWarningExpr | Void! | +| NullableRefTypes.cs:91:10:91:34 | FunctionInNullableContext | Void! | +| NullableRefTypes.cs:100:7:100:14 | RefTypes | Void | +| NullableRefTypes.cs:103:18:103:28 | ReturnsRef1 | ref MyClass? | +| NullableRefTypes.cs:104:17:104:27 | ReturnsRef2 | ref MyClass! | +| NullableRefTypes.cs:105:27:105:37 | ReturnsRef3 | readonly MyClass? | +| NullableRefTypes.cs:106:27:106:37 | ReturnsRef4 | readonly MyClass? | +| NullableRefTypes.cs:107:26:107:36 | ReturnsRef5 | readonly MyClass! | +| NullableRefTypes.cs:108:26:108:36 | ReturnsRef6 | readonly MyClass! | +| NullableRefTypes.cs:110:10:110:20 | Parameters1 | Void! | +| NullableRefTypes.cs:113:32:113:44 | get_RefProperty | MyClass! | +| NullableRefTypes.cs:116:7:116:23 | ToStringWithTypes | Void | +| NullableRefTypes.cs:136:7:136:24 | ToStringWithTypes2 | Void | +| NullableRefTypes.cs:154:7:154:25 | DisabledNullability | Void | +| NullableRefTypes.cs:157:18:157:30 | get_P | MyClass | +| NullableRefTypes.cs:158:13:158:14 | Fn | MyClass | +| NullableRefTypes.cs:165:8:165:15 | MyStruct | Void | +methodTypeArguments | NullableRefTypes.cs:51:12:51:15 | Q | 0 | MyClass | -| NullableRefTypes.cs:54:11:54:33 | Generic | 0 | MyClass? | -| NullableRefTypes.cs:54:11:54:33 | Generic | 1 | MyClass! | -| NullableRefTypes.cs:54:11:54:33 | Generic | 2 | IDisposable! | -| NullableRefTypes.cs:54:11:54:33 | Generic | 3 | MyClass! | -| NullableRefTypes.cs:61:10:61:21 | GenericFn | 0 | MyClass | +| NullableRefTypes.cs:51:12:51:15 | Q | 0 | MyClass! | +| NullableRefTypes.cs:67:10:67:21 | GenericFn | 0 | MyClass | +| NullableRefTypes.cs:67:10:67:21 | GenericFn | 0 | MyClass! | +constructedTypes +| AsyncStreams.cs:34:15:34:37 | IAsyncEnumerable | 0 | int | _ | +| AsyncStreams.cs:39:15:39:37 | IAsyncEnumerator | 0 | T | _ | +| AsyncStreams.cs:39:15:39:37 | IAsyncEnumerator | 0 | int | _ | +| NullableRefTypes.cs:54:11:54:33 | Generic | 0 | MyClass | _ | +| NullableRefTypes.cs:54:11:54:33 | Generic | 1 | MyClass | _ | +| NullableRefTypes.cs:54:11:54:33 | Generic | 2 | IDisposable | _ | +| NullableRefTypes.cs:54:11:54:33 | Generic | 3 | MyClass | _ | +| NullableRefTypes.cs:54:11:54:33 | Generic! | 0 | MyClass? | ! | +| NullableRefTypes.cs:54:11:54:33 | Generic! | 1 | MyClass! | ! | +| NullableRefTypes.cs:54:11:54:33 | Generic! | 2 | IDisposable! | ! | +| NullableRefTypes.cs:54:11:54:33 | Generic! | 3 | MyClass! | ! | +| NullableRefTypes.cs:54:11:54:33 | Generic, MyClass> | 0 | string | _ | +| NullableRefTypes.cs:54:11:54:33 | Generic, MyClass> | 1 | T1 | _ | +| NullableRefTypes.cs:54:11:54:33 | Generic, MyClass> | 2 | IEnumerable | _ | +| NullableRefTypes.cs:54:11:54:33 | Generic, MyClass> | 3 | MyClass | _ | +| NullableRefTypes.cs:54:11:54:33 | Generic!, MyClass!>! | 0 | string? | !,!>! | +| NullableRefTypes.cs:54:11:54:33 | Generic!, MyClass!>! | 1 | T1? | !,!>! | +| NullableRefTypes.cs:54:11:54:33 | Generic!, MyClass!>! | 2 | IEnumerable! | !,!>! | +| NullableRefTypes.cs:54:11:54:33 | Generic!, MyClass!>! | 3 | MyClass! | !,!>! | nullableTypeParameters | NullableRefTypes.cs:54:19:54:20 | T1 | annotatedTypeConstraints | NullableRefTypes.cs:51:14:51:14 | T | NullableRefTypes.cs:6:7:6:13 | MyClass? | | NullableRefTypes.cs:54:23:54:24 | T2 | NullableRefTypes.cs:6:7:6:13 | MyClass? | | NullableRefTypes.cs:54:31:54:32 | T4 | NullableRefTypes.cs:6:7:6:13 | MyClass! | +| NullableRefTypes.cs:58:20:58:21 | T1 | NullableRefTypes.cs:6:7:6:13 | MyClass! | +| NullableRefTypes.cs:58:24:58:25 | T2 | NullableRefTypes.cs:54:11:54:33 | Generic!, MyClass!>! | +typeNotAnnotated diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql index c0febaa2afa..cf5d320ca91 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql @@ -21,11 +21,12 @@ query predicate nonNullExpressions(NonNullExpr e) { e.getEnclosingCallable().getName() = "TestSuppressNullableWarningExpr" } -query predicate assignableTypes(Assignable a, AnnotatedType t) { +query predicate assignableTypes(Assignable a, AnnotatedType t, string n) { a.getFile().getBaseName() = "NullableRefTypes.cs" and t.getLocation() instanceof SourceLocation and a.getLocation() instanceof SourceLocation and - t = a.getAnnotatedType() + t = a.getAnnotatedType() and + n = t.getAnnotations().getNullability().toString() } query predicate arrayElements(Variable v, AnnotatedArrayType array, AnnotatedType elementType) { @@ -39,13 +40,17 @@ query predicate returnTypes(Callable c, string t) { t = c.getAnnotatedReturnType().toString() } -query predicate typeArguments(AnnotatedConstructedType generic, int arg, string argument) { - ( - generic.getType() = any(Variable v | v.fromSource()).getType() - //or - // generic.getType() = any(MethodCall mc).getTarget() - ) and - argument = generic.getTypeArgument(arg).toString() +query predicate methodTypeArguments(ConstructedGeneric generic, int arg, string argument) { + generic = any(MethodCall mc).getTarget() and + argument = generic.getAnnotatedTypeArgument(arg).toString() +} + +query predicate constructedTypes( + AnnotatedConstructedType at, int i, string arg, string nullability +) { + arg = at.getTypeArgument(i).toString() and + at.getLocation() instanceof SourceLocation and + nullability = at.getAnnotations().getNullability().toString() } query predicate nullableTypeParameters(TypeParameter p) { From 163b931d49040d9c461cdd745d99524323d69349 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Tue, 1 Oct 2019 15:16:39 +0100 Subject: [PATCH 1034/1227] C#: Update db stats --- .../ql/src/semmlecode.csharp.dbscheme.stats | 21139 ++++++++-------- 1 file changed, 10761 insertions(+), 10378 deletions(-) diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme.stats b/csharp/ql/src/semmlecode.csharp.dbscheme.stats index 5e5b32342cc..426949c2061 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme.stats +++ b/csharp/ql/src/semmlecode.csharp.dbscheme.stats @@ -1,15 +1,15 @@ @compilation -641 +1057 @diagnostic -7036 +12070 @extractor_message -264 +57 @externalDefect @@ -21,47 +21,47 @@ @externalDataElement -8 +9 @duplication -13480 +20134 @similarity -124007 +149289 @location_default -7339237 +11787435 @assembly -1870 +2863 @file -15550 +24954 @folder -4611 +7016 @namespace -5457 +6505 @namespace_declaration -14700 +22696 @using_namespace_directive -85929 +106992 @using_static_directive -253 +321 @bool_type @@ -117,23 +117,23 @@ @enum_type -8356 +8073 @struct_type -37594 +31632 @class_type -142002 +126692 @interface_type -176859 +137173 @delegate_type -49262 +40645 @null_type @@ -141,19 +141,19 @@ @type_parameter -80545 +58090 @pointer_type -272 +383 @nullable_type -2027 +1382 @array_type -7951 +7961 @void_type @@ -168,36 +168,48 @@ 1 -@arglist_type -1 - - @tuple_type -2476 +1768 @uint_ptr_type 0 +@arglist_type +0 + + @unknown_type 0 @typeref -427553 +349451 @attribute -120784 +152979 @type_mention -1477122 +2269573 + + +@oblivious +58 + + +@not_annotated +47 + + +@annotated +11 @type_parameter_constraints -330908 +389563 @modifier @@ -205,531 +217,535 @@ @property -277986 +268986 @indexer -23786 +25314 @getter -291486 +286438 @setter -45608 +50195 @event -6046 +8976 @add_event_accessor -6013 +7857 @remove_event_accessor -6013 +7857 @operator -14355 +13320 @method -1076961 +990339 @constructor -154830 +149144 @destructor -461 +388 @local_function -1174 +1201 @addressable_field -160511 +178578 @constant -122762 +106769 @addressable_local_variable -238799 +307769 @local_constant -1223 +1627 @local_variable_ref -11 - - -@parameter -1873820 - - -@block_stmt -262647 - - -@expr_stmt -328762 - - -@if_stmt -71396 - - -@switch_stmt -5510 - - -@while_stmt -1696 - - -@do_stmt -179 - - -@for_stmt -3370 - - -@foreach_stmt -9035 - - -@break_stmt -7981 - - -@continue_stmt -1828 - - -@goto_stmt -115 - - -@goto_case_stmt -95 - - -@goto_default_stmt -148 - - -@throw_stmt -10708 - - -@return_stmt -107422 - - -@yield_stmt -1155 - - -@try_stmt -2439 - - -@checked_stmt -8 - - -@unchecked_stmt -76 - - -@lock_stmt -656 - - -@using_block_stmt -5182 - - -@var_decl_stmt -213042 - - -@const_decl_stmt -1222 - - -@empty_stmt -149 - - -@unsafe_stmt -22 - - -@fixed_stmt 54 -@label_stmt -69 +@parameter +1662795 -@catch -2055 +@block_stmt +483215 -@case_stmt -34567 +@expr_stmt +510339 -@local_function_stmt -1305 +@if_stmt +158006 -@using_decl_stmt -17 +@switch_stmt +8021 -@bool_literal_expr -51125 +@while_stmt +4304 -@char_literal_expr -6799 +@do_stmt +794 -@decimal_literal_expr -126 +@for_stmt +8189 -@int_literal_expr -183666 +@foreach_stmt +11629 -@long_literal_expr -83 +@break_stmt +17068 -@uint_literal_expr -239 +@continue_stmt +3270 -@ulong_literal_expr -165 +@goto_stmt +1200 -@float_literal_expr -64 +@goto_case_stmt +330 -@double_literal_expr -319 - - -@string_literal_expr -342808 - - -@null_literal_expr -58357 - - -@this_access_expr -266101 - - -@base_access_expr -2766 - - -@local_variable_access_expr -756875 - - -@parameter_access_expr -348197 - - -@field_access_expr -387345 - - -@property_access_expr -331895 - - -@method_access_expr -5754 - - -@event_access_expr -1952 - - -@indexer_access_expr -20850 - - -@array_access_expr -10320 - - -@type_access_expr -496066 - - -@typeof_expr -7384 - - -@method_invocation_expr -726337 - - -@delegate_invocation_expr -2920 - - -@operator_invocation_expr -30533 - - -@cast_expr -138001 - - -@object_creation_expr -62254 - - -@explicit_delegate_creation_expr -200 - - -@implicit_delegate_creation_expr -3424 - - -@array_creation_expr -17336 - - -@default_expr -5647 - - -@plus_expr -40 - - -@minus_expr -2712 - - -@bit_not_expr -257 - - -@log_not_expr -14848 - - -@post_incr_expr -4717 - - -@post_decr_expr -363 - - -@pre_incr_expr -321 - - -@pre_decr_expr -48 - - -@mul_expr -700 - - -@div_expr -278 - - -@rem_expr -174 - - -@add_expr -15490 - - -@sub_expr -3359 - - -@lshift_expr +@goto_default_stmt 252 +@throw_stmt +62807 + + +@return_stmt +172166 + + +@yield_stmt +1334 + + +@try_stmt +6286 + + +@checked_stmt +234 + + +@unchecked_stmt +186 + + +@lock_stmt +1831 + + +@using_block_stmt +6120 + + +@var_decl_stmt +269815 + + +@const_decl_stmt +1623 + + +@empty_stmt +349 + + +@unsafe_stmt +301 + + +@fixed_stmt +783 + + +@label_stmt +439 + + +@catch +4711 + + +@case_stmt +53160 + + +@local_function_stmt +1199 + + +@using_decl_stmt +18 + + +@bool_literal_expr +83252 + + +@char_literal_expr +16894 + + +@decimal_literal_expr +134 + + +@int_literal_expr +268458 + + +@long_literal_expr +178 + + +@uint_literal_expr +2083 + + +@ulong_literal_expr +227 + + +@float_literal_expr +631 + + +@double_literal_expr +656 + + +@string_literal_expr +402840 + + +@null_literal_expr +141562 + + +@this_access_expr +489938 + + +@base_access_expr +5239 + + +@local_variable_access_expr +1050542 + + +@parameter_access_expr +579372 + + +@field_access_expr +712366 + + +@property_access_expr +473246 + + +@method_access_expr +7270 + + +@event_access_expr +2309 + + +@indexer_access_expr +31604 + + +@array_access_expr +25694 + + +@type_access_expr +724742 + + +@typeof_expr +26440 + + +@method_invocation_expr +928336 + + +@delegate_invocation_expr +4558 + + +@operator_invocation_expr +41161 + + +@cast_expr +212776 + + +@object_creation_expr +104367 + + +@explicit_delegate_creation_expr +1190 + + +@implicit_delegate_creation_expr +3755 + + +@array_creation_expr +22244 + + +@default_expr +8135 + + +@plus_expr +73 + + +@minus_expr +6795 + + +@bit_not_expr +715 + + +@log_not_expr +27569 + + +@post_incr_expr +12713 + + +@post_decr_expr +1368 + + +@pre_incr_expr +1215 + + +@pre_decr_expr +294 + + +@mul_expr +4053 + + +@div_expr +1258 + + +@rem_expr +573 + + +@add_expr +32765 + + +@sub_expr +10607 + + +@lshift_expr +1678 + + @rshift_expr -160 +1075 @lt_expr -4871 +15042 @gt_expr -4360 +10187 @le_expr -1131 +3530 @ge_expr -2035 +5467 @eq_expr -38255 +78231 @ne_expr -24659 +53191 @bit_and_expr -1845 +5903 @bit_xor_expr -165 +507 @bit_or_expr -3840 +11954 @log_and_expr -16596 +31285 @log_or_expr -11990 +21875 @is_expr -4906 +8517 @as_expr -4522 +7102 @null_coalescing_expr -2632 +4350 @conditional_expr -8632 +14417 @simple_assign_expr -87603 +207337 @assign_add_expr -1029 +3522 @assign_sub_expr -111 +619 @assign_mul_expr -20 +123 @assign_div_expr -4 +49 -@assign_and_expr -152 - - -@assign_xor_expr +@assign_rem_expr 8 +@assign_and_expr +374 + + +@assign_xor_expr +88 + + @assign_or_expr -687 +1706 @assign_lshift_expr -6 +69 @assign_rshift_expr -7 +97 @object_init_expr -4760 +5120 @collection_init_expr -1260 +1313 @array_init_expr -16761 +19188 @checked_expr -37 +369 @unchecked_expr -255 +1872 @constructor_init_expr -5737 +9978 @add_event_expr -736 +877 @remove_event_expr -306 +408 @local_var_decl_expr -240135 +309563 @lambda_expr -23385 +24042 @anonymous_method_expr -118 +192 @dynamic_element_access_expr @@ -741,55 +757,51 @@ @pointer_indirection_expr -54 +2768 @address_of_expr -31 +717 @sizeof_expr -120 +746 @await_expr -26351 +27405 @nameof_expr -7589 - - -@namespace_access_expr -1000 +18016 @interpolated_string_expr -3470 +4321 @unknown_expr -22558 +22532 @throw_expr -381 +917 @tuple_expr -1841 +2152 @local_function_invocation_expr -2365 +2317 @ref_expr -31 +108 @discard_expr -372 +471 @switch_expr @@ -809,15 +821,19 @@ @switch_case_expr -135 +142 @assign_coalesce_expr 14 -@assign_rem_expr -0 +@suppress_nullable_warning_expr +252 + + +@namespace_access_expr +435 @par_expr @@ -836,10 +852,6 @@ 0 -@suppress_nullable_warning_expr -0 - - @xmldtd 2 @@ -865,19 +877,19 @@ @singlelinecomment -190700 +330391 @xmldoccomment -155568 +276055 @multilinecomment -2025 +12000 @commentblock -142586 +247138 @asp_close_tag @@ -921,31 +933,31 @@ @cil_ceq -71085 +150958 @cil_cgt -5097 +14265 @cil_cgt_un -29102 +58842 @cil_clt -6821 +21999 @cil_clt_un -152 +760 @cil_ldftn -31039 +34640 @cil_ldvirtftn -452 +572 @cil_ldarg @@ -965,219 +977,219 @@ @cil_localloc -158 +1296 @cil_endfilter -742 +901 @cil_volatile -4322 +8933 @cil_initobj -42348 +50442 @cil_constrained -10563 +13699 @cil_rethrow -1557 +2702 @cil_sizeof -509 +1663 @cil_refanytype -3 +9 @cil_readonly -22 +55 @cil_stsfld -39335 +50533 @cil_stobj -3560 +5663 @cil_conv_ovf_i1_un -11 +12 @cil_conv_ovf_i2_un -9 - - -@cil_conv_ovf_i4_un -18 - - -@cil_conv_ovf_i8_un -9 - - -@cil_conv_ovf_u1_un -13 - - -@cil_conv_ovf_u2_un -9 - - -@cil_conv_ovf_u4_un -7 - - -@cil_conv_ovf_i_un -27 - - -@cil_conv_ovf_u_un -1 - - -@cil_box -34001 - - -@cil_newarr -30964 - - -@cil_ldlen -16074 - - -@cil_ldelema -3250 - - -@cil_ldelem_i1 -16 - - -@cil_ldelem_u1 -1746 - - -@cil_ldelem_i2 -39 - - -@cil_ldelem_u2 -716 - - -@cil_ldelem_i4 -1404 - - -@cil_ldelem_u4 -249 - - -@cil_ldelem_i8 -156 - - -@cil_ldelem_i -30 - - -@cil_ldelem_r4 -6 - - -@cil_ldelem_r8 -72 - - -@cil_ldelem_ref -8789 - - -@cil_stelem_i -28 - - -@cil_stelem_i1 -2283 - - -@cil_stelem_i2 -2131 - - -@cil_stelem_i4 -1186 - - -@cil_stelem_i8 -82 - - -@cil_stelem_r4 -7 - - -@cil_stelem_r8 -49 - - -@cil_stelem_ref -52243 - - -@cil_ldelem -1244 - - -@cil_stelem -2784 - - -@cil_unbox_any -7679 - - -@cil_conv_ovf_i1 -16 - - -@cil_conv_ovf_u1 -74 - - -@cil_conv_ovf_i2 10 +@cil_conv_ovf_i4_un +46 + + +@cil_conv_ovf_i8_un +18 + + +@cil_conv_ovf_u1_un +16 + + +@cil_conv_ovf_u2_un +11 + + +@cil_conv_ovf_u4_un +12 + + +@cil_conv_ovf_i_un +30 + + +@cil_conv_ovf_u_un +3 + + +@cil_box +49494 + + +@cil_newarr +42488 + + +@cil_ldlen +29621 + + +@cil_ldelema +7817 + + +@cil_ldelem_i1 +43 + + +@cil_ldelem_u1 +3997 + + +@cil_ldelem_i2 +96 + + +@cil_ldelem_u2 +2501 + + +@cil_ldelem_i4 +3022 + + +@cil_ldelem_u4 +725 + + +@cil_ldelem_i8 +271 + + +@cil_ldelem_i +56 + + +@cil_ldelem_r4 +80 + + +@cil_ldelem_r8 +136 + + +@cil_ldelem_ref +17540 + + +@cil_stelem_i +51 + + +@cil_stelem_i1 +4466 + + +@cil_stelem_i2 +3032 + + +@cil_stelem_i4 +2382 + + +@cil_stelem_i8 +112 + + +@cil_stelem_r4 +48 + + +@cil_stelem_r8 +68 + + +@cil_stelem_ref +72262 + + +@cil_ldelem +2491 + + +@cil_stelem +5239 + + +@cil_unbox_any +12659 + + +@cil_conv_ovf_i1 +27 + + +@cil_conv_ovf_u1 +116 + + +@cil_conv_ovf_i2 +34 + + @cil_conv_ovf_u2 -36 +73 @cil_conv_ovf_i4 -25 +97 @cil_conv_ovf_u4 -37 +43 @cil_conv_ovf_i8 -5 +13 @cil_conv_ovf_u8 -20 +46 @cil_mkrefany @@ -1185,23 +1197,23 @@ @cil_ldtoken -16408 +30884 @cil_conv_u2 -1623 +3231 @cil_conv_u1 -2397 +5205 @cil_conv_i -2539 +6279 @cil_conv_ovf_i -83 +151 @cil_conv_ovf_u @@ -1209,531 +1221,531 @@ @cil_add_ovf -576 +1079 @cil_add_ovf_un -67 +107 @cil_mul_ovf -112 +302 @cil_mul_ovf_un -160 +572 @cil_sub_ovf -127 +197 @cil_sub_ovf_un -16 +20 @cil_endfinally -27093 +36918 @cil_leave -12636 +16770 @cil_leave_s -52174 +71780 @cil_stind_i -170 +372 @cil_conv_u -2784 +11293 @cil_nop -421589 +1058352 @cil_ldarg_0 -1219505 +1761435 @cil_ldarg_1 -470021 +666051 @cil_ldarg_2 -179471 +260505 @cil_ldarg_3 -87409 +124504 @cil_ldloc_0 -370059 +552028 @cil_ldloc_1 -198298 +295756 @cil_ldloc_2 -132619 +198557 @cil_ldloc_3 -89670 +138205 @cil_stloc_0 -249999 +366179 @cil_stloc_1 -128061 +199127 @cil_stloc_2 -93078 +148560 @cil_stloc_3 -64772 +104523 @cil_ldarg_s -108039 +141946 @cil_ldarga_s -41249 +60259 @cil_starg_s -8831 +15145 @cil_ldloc_s -322360 +554029 @cil_ldloca_s -248663 +306809 @cil_stloc_s -242364 +421486 @cil_ldnull -367434 +527874 @cil_ldc_i4_m1 -25408 +37403 @cil_ldc_i4_0 -286505 +452737 @cil_ldc_i4_1 -180607 +273764 @cil_ldc_i4_2 -38368 +61963 @cil_ldc_i4_3 -16972 +26360 @cil_ldc_i4_4 -15394 +25516 @cil_ldc_i4_5 -10633 +15555 @cil_ldc_i4_6 -5988 +9146 @cil_ldc_i4_7 -4801 +7875 @cil_ldc_i4_8 -6847 +12587 @cil_ldc_i4_s -93556 +153320 @cil_ldc_i4 -101313 +127757 @cil_ldc_i8 -804 +1844 @cil_ldc_r4 -391 +1819 @cil_ldc_r8 -2592 +4211 @cil_dup -133065 +175646 @cil_pop -63274 +84451 @cil_call -1032059 +1478944 @cil_ret -629053 +867422 @cil_br_s -278770 +460982 @cil_brfalse_s -241287 +397704 @cil_brtrue_s -157059 +202600 @cil_beq_s -41579 +55540 @cil_bge_s -9364 +13561 @cil_bgt_s -4692 +7322 @cil_ble_s -10134 +13335 @cil_blt_s -15628 +23707 @cil_bne_un_s -36167 +44432 @cil_bge_un_s -462 +1087 @cil_bgt_un_s -3796 +5045 @cil_ble_un_s -4164 +5587 @cil_blt_un_s -402 +833 @cil_br -48655 +80292 @cil_brfalse -14223 +23259 @cil_brtrue -11832 +16446 @cil_beq -8957 +11212 @cil_bge -460 +568 @cil_bgt -531 +638 @cil_ble -1040 +1163 @cil_blt -1840 +2379 @cil_bne_un -2234 +2606 @cil_bge_un -76 +351 @cil_bgt_un -649 +726 @cil_ble_un -1094 +1209 @cil_blt_un -68 +157 @cil_switch -8423 +11344 @cil_ldind_i1 -66 +171 @cil_ldind_u1 -1972 +4812 @cil_ldind_i2 -47 - - -@cil_ldind_u2 -882 - - -@cil_ldind_i4 -3656 - - -@cil_ldind_u4 -419 - - -@cil_ldind_i8 -338 - - -@cil_ldind_i -240 - - -@cil_ldind_r4 -52 - - -@cil_ldind_r8 -79 - - -@cil_ldind_ref -6458 - - -@cil_stind_ref -10649 - - -@cil_stind_i1 -3593 - - -@cil_stind_i2 -435 - - -@cil_stind_i4 -5789 - - -@cil_stind_i8 -419 - - -@cil_stind_r4 -28 - - -@cil_stind_r8 135 +@cil_ldind_u2 +3540 + + +@cil_ldind_i4 +6599 + + +@cil_ldind_u4 +857 + + +@cil_ldind_i8 +786 + + +@cil_ldind_i +602 + + +@cil_ldind_r4 +166 + + +@cil_ldind_r8 +173 + + +@cil_ldind_ref +9006 + + +@cil_stind_ref +14083 + + +@cil_stind_i1 +7192 + + +@cil_stind_i2 +2098 + + +@cil_stind_i4 +11327 + + +@cil_stind_i8 +974 + + +@cil_stind_r4 +213 + + +@cil_stind_r8 +291 + + @cil_add -45802 +91505 @cil_sub -27733 +48903 @cil_mul -6208 +15702 @cil_div -1845 +4122 @cil_div_un -62 +298 @cil_rem -927 +1798 @cil_rem_un -60 +183 @cil_and -12636 +22304 @cil_or -7591 +12425 @cil_xor -1069 +1745 @cil_shl -2632 +4680 @cil_shr -972 +2069 @cil_shr_un -1202 +2226 @cil_neg -440 +1101 @cil_not -346 +562 @cil_conv_i1 -229 +594 @cil_conv_i2 -368 +846 @cil_conv_i4 -14947 +29360 @cil_conv_i8 -7691 +17068 @cil_conv_r4 -264 +612 @cil_conv_r8 -1003 +1987 @cil_conv_u4 -441 +1227 @cil_conv_u8 -1780 +4327 @cil_callvirt -767609 +1047788 @cil_ldobj -2907 +5059 @cil_ldstr -170165 +267378 @cil_newobj -204904 +283677 @cil_castclass -54510 +68061 @cil_isinst -31244 +42709 @cil_conv_r_un -103 +209 @cil_unbox -179 +263 @cil_throw -267455 +387689 @cil_ldfld -483765 +733616 @cil_ldflda -66802 +96244 @cil_stfld -269151 +373661 @cil_ldsfld -115160 +153187 @cil_ldsflda -1318 +2353 @cil_break @@ -1789,80 +1801,80 @@ @cil_valueorreftype -236158 +249378 @cil_typeparameter -98272 +53658 @cil_array_type -8222 +6961 @cil_pointer_type -440 +638 @cil_method -982868 +1164170 @cil_method_implementation -1040241 +1351436 @cil_field -373454 +459117 @cil_parameter -1904597 +2241273 @cil_property -166215 +232995 @cil_event -3719 +6340 @cil_local_variable -624672 +989635 @cil_catch_handler -10888 +16252 @cil_filter_handler -742 +901 @cil_finally_handler -26292 +35985 @cil_fault_handler -799 +931 @cil_attribute -140634 +248346 compilations -641 +1057 id -641 +1057 cwd -129 +494 @@ -1876,7 +1888,7 @@ 1 2 -641 +1057 @@ -1892,27 +1904,22 @@ 1 2 -71 +409 2 3 -21 +45 3 -14 -10 +24 +38 -14 -15 -23 - - -15 +28 29 -4 +2 @@ -1922,11 +1929,11 @@ compilation_args -2574 +4654 id -641 +1057 num @@ -1934,7 +1941,7 @@ arg -645 +1058 @@ -1951,6 +1958,11 @@ 636 +5 +6 +416 + + 6 7 5 @@ -1972,6 +1984,11 @@ 636 +5 +6 +416 + + 6 7 5 @@ -1990,11 +2007,16 @@ 5 6 -2 +1 -641 -642 +421 +422 +1 + + +1057 +1058 4 @@ -2009,14 +2031,14 @@ 12 -1 -2 -1 - - 2 3 -3 +2 + + +3 +4 +1 5 @@ -2024,8 +2046,13 @@ 1 -635 -636 +413 +414 +1 + + +637 +638 1 @@ -2042,12 +2069,12 @@ 1 2 -637 +1045 2 -642 -8 +1058 +13 @@ -2063,12 +2090,12 @@ 1 2 -643 +1054 2 3 -2 +4 @@ -2078,11 +2105,11 @@ compilation_compiling_files -11459 +21036 id -641 +1057 num @@ -2090,7 +2117,7 @@ file -9738 +18151 @@ -2108,18 +2135,33 @@ 2 -11 -50 +3 +11 -11 -50 -49 +3 +4 +224 -54 +4 +6 +82 + + +6 +18 +80 + + +18 +64 +80 + + +64 1094 -41 +79 @@ -2139,18 +2181,33 @@ 2 -11 -50 +3 +11 -11 -50 -49 +3 +4 +224 -54 +4 +6 +82 + + +6 +18 +80 + + +18 +64 +80 + + +64 1094 -41 +79 @@ -2176,37 +2233,47 @@ 4 5 -313 +213 5 -7 -38 +6 +100 -7 +6 8 -95 +38 8 9 -212 +95 9 -21 -86 +10 +151 -21 -47 -88 +10 +20 +90 -48 -642 -37 +20 +55 +83 + + +56 +160 +82 + + +165 +1058 +17 @@ -2232,37 +2299,47 @@ 4 5 -313 +213 5 -7 -38 +6 +100 -7 +6 8 -95 +38 8 9 -212 +95 9 -21 -86 +10 +151 -21 -46 +10 +20 +90 + + +20 +54 82 -46 -635 -43 +54 +152 +82 + + +156 +1042 +18 @@ -2278,17 +2355,17 @@ 1 2 -8450 +16413 2 -3 -1005 +4 +1541 -3 -12 -283 +4 +129 +197 @@ -2304,17 +2381,17 @@ 1 2 -8531 +16536 2 -3 -961 +4 +1447 -3 -11 -246 +4 +77 +168 @@ -2324,11 +2401,11 @@ compilation_referencing_files -86469 +94271 id -641 +1056 num @@ -2336,7 +2413,7 @@ file -1126 +1701 @@ -2348,74 +2425,69 @@ 12 +1 +2 +70 + + +2 +3 +82 + + 3 -71 -55 +5 +96 -72 -76 -41 +5 +11 +84 -79 -120 -47 +11 +46 +90 -121 -123 -43 +46 +80 +88 -123 -126 -37 +100 +124 +84 -126 -129 -48 +124 +130 +94 -129 -131 -59 - - -132 +130 137 -56 +85 138 -153 -57 +157 +77 -153 -158 -49 +157 +181 +80 -161 -184 -49 +181 +219 +86 -184 -212 -46 - - -218 -234 -49 - - -241 +219 272 -5 +40 @@ -2429,74 +2501,69 @@ 12 +1 +2 +70 + + +2 +3 +82 + + 3 -71 -55 +5 +96 -72 -75 -41 +5 +11 +84 -78 -120 -47 +11 +46 +90 -121 -123 -43 +46 +79 +88 -123 -126 -51 +100 +124 +84 -126 -129 -34 +124 +130 +94 -129 -131 -59 - - -132 +130 137 -56 +85 138 -153 -57 +157 +78 -153 -158 -49 +157 +182 +80 -161 -183 -49 +182 +219 +85 -184 -212 -46 - - -218 -234 -49 - - -241 +219 272 -5 +40 @@ -2526,53 +2593,58 @@ 55 -98 -25 - - -98 -148 -24 - - -148 -252 +112 21 -252 -499 -22 - - -499 -518 -19 - - -518 -519 +112 +172 21 +173 +270 +21 + + +270 +401 +21 + + +416 +545 +14 + + 545 -603 +546 +13 + + +546 +547 +21 + + +573 +631 18 -603 -621 -17 +631 +651 +22 -621 -622 -37 +651 +679 +21 -623 -642 -7 +681 +1057 +18 @@ -2588,66 +2660,66 @@ 1 4 -20 +17 4 -8 +6 21 -8 -27 +6 +28 +21 + + +28 +49 +21 + + +49 +79 +21 + + +79 +101 +21 + + +101 +141 +21 + + +146 +168 23 -27 -39 +168 +180 21 -39 -64 -21 +180 +191 +24 -64 -94 -21 - - -95 -136 -21 - - -138 -155 +191 +196 22 -155 -165 -22 +196 +203 +23 -165 -172 -21 - - -172 -187 -21 - - -187 -193 -22 - - -193 -201 +203 +226 15 @@ -2664,27 +2736,37 @@ 1 2 -240 +323 2 3 -110 +142 3 -11 -86 +4 +84 -11 +4 +5 +214 + + +5 +23 +130 + + +23 28 -85 +132 28 47 -50 +101 47 @@ -2693,38 +2775,23 @@ 48 -100 -66 +106 +128 -100 -176 -85 - - -177 +108 181 -7 +50 184 -185 -115 +219 +128 -187 -284 -23 - - -284 -285 -107 - - -332 +253 478 -7 +124 @@ -2740,57 +2807,57 @@ 1 2 -243 +332 2 3 -124 +173 3 -7 -85 +4 +164 -7 -16 -95 +4 +5 +130 -16 -20 -85 +5 +12 +129 -20 -23 -85 +12 +17 +144 -23 -29 -89 +17 +21 +145 -29 -38 -97 +21 +26 +134 -38 -52 -85 +26 +35 +141 -52 -104 -90 +35 +96 +132 -104 -120 -48 +96 +116 +77 @@ -2800,11 +2867,11 @@ compilation_time -4487 +7399 id -641 +1057 num @@ -2816,7 +2883,7 @@ seconds -2410 +3864 @@ -2830,7 +2897,7 @@ 1 2 -641 +1057 @@ -2846,7 +2913,7 @@ 7 8 -641 +1057 @@ -2862,12 +2929,12 @@ 6 7 -17 +6 7 8 -624 +1051 @@ -2881,8 +2948,8 @@ 12 -641 -642 +1057 +1058 1 @@ -2913,8 +2980,8 @@ 12 -2410 -2411 +3864 +3865 1 @@ -2929,8 +2996,8 @@ 12 -641 -642 +1057 +1058 7 @@ -2961,39 +3028,34 @@ 12 -171 -172 +312 +313 1 -173 -174 +328 +329 1 -188 -189 +369 +370 1 -202 -203 +416 +417 1 -616 -617 +1005 +1006 1 -639 -640 -1 - - -641 -642 -1 +1056 +1057 +2 @@ -3009,17 +3071,17 @@ 1 2 -2169 +3350 2 -14 -184 +6 +321 -14 -78 -57 +6 +71 +193 @@ -3035,7 +3097,7 @@ 1 2 -2410 +3864 @@ -3051,12 +3113,17 @@ 1 2 -2240 +3460 2 +4 +336 + + +4 5 -170 +68 @@ -3066,15 +3133,15 @@ diagnostic_for -7036 +12070 diagnostic -7036 +12070 compilation -138 +328 file_number @@ -3082,7 +3149,7 @@ file_number_diagnostic_number -1028 +1099 @@ -3096,7 +3163,7 @@ 1 2 -7036 +12070 @@ -3112,7 +3179,7 @@ 1 2 -7036 +12070 @@ -3128,7 +3195,7 @@ 1 2 -7036 +12070 @@ -3142,69 +3209,64 @@ 12 +1 +2 +2 + + 2 3 -2 +53 + + +3 +4 +27 4 5 -26 +41 5 -6 -5 - - -6 7 -12 +29 7 -8 -7 +9 +25 -8 -11 -11 +9 +13 +28 -11 -14 -11 +13 +19 +26 -15 -20 -12 +19 +28 +26 -20 -32 -11 - - -33 +28 57 -12 +25 -59 -106 -11 +57 +154 +25 -123 -193 -12 - - -232 -1029 -6 +160 +1100 +21 @@ -3220,7 +3282,7 @@ 1 2 -138 +328 @@ -3234,69 +3296,64 @@ 12 +1 +2 +2 + + 2 3 -2 +53 + + +3 +4 +27 4 5 -26 +41 5 -6 -5 - - -6 7 -12 +29 7 -8 -7 +9 +25 -8 -11 -11 +9 +13 +28 -11 -14 -11 +13 +19 +26 -15 -20 -12 +19 +28 +26 -20 -32 -11 - - -33 +28 57 -12 +25 -59 -106 -11 +57 +154 +25 -123 -193 -12 - - -232 -1029 -6 +160 +1100 +21 @@ -3310,8 +3367,8 @@ 12 -7036 -7037 +12070 +12071 1 @@ -3326,8 +3383,8 @@ 12 -138 -139 +328 +329 1 @@ -3342,8 +3399,8 @@ 12 -1028 -1029 +1099 +1100 1 @@ -3360,32 +3417,42 @@ 1 2 -488 +71 2 3 -147 +488 3 4 -150 +147 4 -10 -79 +5 +82 -10 -26 -90 +5 +12 +88 -26 -139 -74 +12 +24 +89 + + +25 +52 +84 + + +52 +329 +50 @@ -3401,32 +3468,42 @@ 1 2 -488 +71 2 3 -147 +488 3 4 -150 +147 4 -10 -79 +5 +82 -10 -26 -90 +5 +12 +88 -26 -139 -74 +12 +24 +89 + + +25 +52 +84 + + +52 +329 +50 @@ -3442,7 +3519,7 @@ 1 2 -1028 +1099 @@ -3452,31 +3529,31 @@ diagnostics -7036 +12070 id -7036 +12070 severity -1 +2 error_tag -2 +6 error_message -2 +6 full_error_message -2 +27 location -5748 +10395 @@ -3490,7 +3567,7 @@ 1 2 -7036 +12070 @@ -3506,7 +3583,7 @@ 1 2 -7036 +12070 @@ -3522,7 +3599,7 @@ 1 2 -7036 +12070 @@ -3538,7 +3615,7 @@ 1 2 -7036 +12070 @@ -3554,7 +3631,7 @@ 1 2 -7036 +12070 @@ -3568,8 +3645,13 @@ 12 -7036 -7037 +242 +243 +1 + + +11828 +11829 1 @@ -3588,6 +3670,11 @@ 3 1 + +4 +5 +1 + @@ -3604,6 +3691,11 @@ 3 1 + +4 +5 +1 + @@ -3620,917 +3712,6 @@ 3 1 - - - - - -severity -location - - -12 - - -5748 -5749 -1 - - - - - - -error_tag -id - - -12 - - -4 -5 -1 - - -7032 -7033 -1 - - - - - - -error_tag -severity - - -12 - - -1 -2 -2 - - - - - - -error_tag -error_message - - -12 - - -1 -2 -2 - - - - - - -error_tag -full_error_message - - -12 - - -1 -2 -2 - - - - - - -error_tag -location - - -12 - - -2 -3 -1 - - -5746 -5747 -1 - - - - - - -error_message -id - - -12 - - -4 -5 -1 - - -7032 -7033 -1 - - - - - - -error_message -severity - - -12 - - -1 -2 -2 - - - - - - -error_message -error_tag - - -12 - - -1 -2 -2 - - - - - - -error_message -full_error_message - - -12 - - -1 -2 -2 - - - - - - -error_message -location - - -12 - - -2 -3 -1 - - -5746 -5747 -1 - - - - - - -full_error_message -id - - -12 - - -4 -5 -1 - - -7032 -7033 -1 - - - - - - -full_error_message -severity - - -12 - - -1 -2 -2 - - - - - - -full_error_message -error_tag - - -12 - - -1 -2 -2 - - - - - - -full_error_message -error_message - - -12 - - -1 -2 -2 - - - - - - -full_error_message -location - - -12 - - -2 -3 -1 - - -5746 -5747 -1 - - - - - - -location -id - - -12 - - -1 -2 -4674 - - -2 -3 -920 - - -3 -12 -154 - - - - - - -location -severity - - -12 - - -1 -2 -5748 - - - - - - -location -error_tag - - -12 - - -1 -2 -5748 - - - - - - -location -error_message - - -12 - - -1 -2 -5748 - - - - - - -location -full_error_message - - -12 - - -1 -2 -5748 - - - - - - - - -extractor_messages -264 - - -id -264 - - -severity -3 - - -origin -1 - - -text -8 - - -entity -143 - - -location -241 - - -stack_trace -30 - - - - -id -severity - - -12 - - -1 -2 -264 - - - - - - -id -origin - - -12 - - -1 -2 -264 - - - - - - -id -text - - -12 - - -1 -2 -264 - - - - - - -id -entity - - -12 - - -1 -2 -264 - - - - - - -id -location - - -12 - - -1 -2 -264 - - - - - - -id -stack_trace - - -12 - - -1 -2 -264 - - - - - - -severity -id - - -12 - - -15 -16 -1 - - -35 -36 -1 - - -214 -215 -1 - - - - - - -severity -origin - - -12 - - -1 -2 -3 - - - - - - -severity -text - - -12 - - -1 -2 -2 - - -6 -7 -1 - - - - - - -severity -entity - - -12 - - -1 -2 -1 - - -16 -17 -1 - - -126 -127 -1 - - - - - - -severity -location - - -12 - - -1 -2 -1 - - -26 -27 -1 - - -214 -215 -1 - - - - - - -severity -stack_trace - - -12 - - -1 -2 -2 - - -29 -30 -1 - - - - - - -origin -id - - -12 - - -264 -265 -1 - - - - - - -origin -severity - - -12 - - -3 -4 -1 - - - - - - -origin -text - - -12 - - -8 -9 -1 - - - - - - -origin -entity - - -12 - - -143 -144 -1 - - - - - - -origin -location - - -12 - - -241 -242 -1 - - - - - - -origin -stack_trace - - -12 - - -30 -31 -1 - - - - - - -text -id - - -12 - - -1 -2 -2 - - -2 -3 -1 - - -4 -5 -1 - - -12 -13 -1 - - -15 -16 -1 - - -35 -36 -1 - - -194 -195 -1 - - - - - - -text -severity - - -12 - - -1 -2 -8 - - - - - - -text -origin - - -12 - - -1 -2 -8 - - - - - - -text -entity - - -12 - - -1 -2 -4 - - -4 -5 -1 - - -6 -7 -1 - - -16 -17 -1 - - -113 -114 -1 - - - - - - -text -location - - -12 - - -1 -2 -3 - - -2 -3 -1 - - -4 -5 -1 - - -12 -13 -1 - - -26 -27 -1 - - -194 -195 -1 - - - - - - -text -stack_trace - - -12 - - -1 -2 -7 - 25 26 @@ -4541,6 +3722,1087 @@ +severity +location + + +12 + + +236 +237 +1 + + +10159 +10160 +1 + + + + + + +error_tag +id + + +12 + + +2 +3 +1 + + +4 +5 +1 + + +6 +7 +1 + + +33 +34 +1 + + +201 +202 +1 + + +11824 +11825 +1 + + + + + + +error_tag +severity + + +12 + + +1 +2 +6 + + + + + + +error_tag +error_message + + +12 + + +1 +2 +6 + + + + + + +error_tag +full_error_message + + +12 + + +1 +2 +2 + + +2 +3 +1 + + +5 +6 +2 + + +13 +14 +1 + + + + + + +error_tag +location + + +12 + + +2 +3 +2 + + +6 +7 +1 + + +27 +28 +1 + + +201 +202 +1 + + +10157 +10158 +1 + + + + + + +error_message +id + + +12 + + +2 +3 +1 + + +4 +5 +1 + + +6 +7 +1 + + +33 +34 +1 + + +201 +202 +1 + + +11824 +11825 +1 + + + + + + +error_message +severity + + +12 + + +1 +2 +6 + + + + + + +error_message +error_tag + + +12 + + +1 +2 +6 + + + + + + +error_message +full_error_message + + +12 + + +1 +2 +2 + + +2 +3 +1 + + +5 +6 +2 + + +13 +14 +1 + + + + + + +error_message +location + + +12 + + +2 +3 +2 + + +6 +7 +1 + + +27 +28 +1 + + +201 +202 +1 + + +10157 +10158 +1 + + + + + + +full_error_message +id + + +12 + + +1 +2 +6 + + +2 +3 +1 + + +3 +4 +2 + + +4 +6 +2 + + +6 +8 +2 + + +9 +11 +2 + + +11 +12 +1 + + +14 +15 +2 + + +16 +17 +3 + + +17 +18 +2 + + +21 +23 +2 + + +27 +11825 +2 + + + + + + +full_error_message +severity + + +12 + + +1 +2 +27 + + + + + + +full_error_message +error_tag + + +12 + + +1 +2 +27 + + + + + + +full_error_message +error_message + + +12 + + +1 +2 +27 + + + + + + +full_error_message +location + + +12 + + +1 +2 +6 + + +2 +3 +2 + + +3 +4 +2 + + +5 +7 +2 + + +7 +10 +2 + + +10 +12 +2 + + +14 +15 +2 + + +16 +17 +3 + + +17 +18 +2 + + +21 +23 +2 + + +27 +10158 +2 + + + + + + +location +id + + +12 + + +1 +2 +9120 + + +2 +3 +1031 + + +3 +12 +244 + + + + + + +location +severity + + +12 + + +1 +2 +10395 + + + + + + +location +error_tag + + +12 + + +1 +2 +10395 + + + + + + +location +error_message + + +12 + + +1 +2 +10395 + + + + + + +location +full_error_message + + +12 + + +1 +2 +10389 + + +2 +3 +6 + + + + + + + + +extractor_messages +57 + + +id +57 + + +severity +3 + + +origin +1 + + +text +4 + + +entity +23 + + +location +34 + + +stack_trace +3 + + + + +id +severity + + +12 + + +1 +2 +57 + + + + + + +id +origin + + +12 + + +1 +2 +57 + + + + + + +id +text + + +12 + + +1 +2 +57 + + + + + + +id +entity + + +12 + + +1 +2 +57 + + + + + + +id +location + + +12 + + +1 +2 +57 + + + + + + +id +stack_trace + + +12 + + +1 +2 +57 + + + + + + +severity +id + + +12 + + +6 +7 +1 + + +15 +16 +1 + + +36 +37 +1 + + + + + + +severity +origin + + +12 + + +1 +2 +3 + + + + + + +severity +text + + +12 + + +1 +2 +2 + + +2 +3 +1 + + + + + + +severity +entity + + +12 + + +1 +2 +1 + + +5 +6 +1 + + +17 +18 +1 + + + + + + +severity +location + + +12 + + +1 +2 +1 + + +6 +7 +1 + + +27 +28 +1 + + + + + + +severity +stack_trace + + +12 + + +1 +2 +2 + + +2 +3 +1 + + + + + + +origin +id + + +12 + + +57 +58 +1 + + + + + + +origin +severity + + +12 + + +3 +4 +1 + + + + + + +origin +text + + +12 + + +4 +5 +1 + + + + + + +origin +entity + + +12 + + +23 +24 +1 + + + + + + +origin +location + + +12 + + +34 +35 +1 + + + + + + +origin +stack_trace + + +12 + + +3 +4 +1 + + + + + + +text +id + + +12 + + +2 +3 +1 + + +4 +5 +1 + + +15 +16 +1 + + +36 +37 +1 + + + + + + +text +severity + + +12 + + +1 +2 +4 + + + + + + +text +origin + + +12 + + +1 +2 +4 + + + + + + +text +entity + + +12 + + +1 +2 +2 + + +4 +5 +1 + + +17 +18 +1 + + + + + + +text +location + + +12 + + +1 +2 +1 + + +2 +3 +1 + + +4 +5 +1 + + +27 +28 +1 + + + + + + +text +stack_trace + + +12 + + +1 +2 +4 + + + + + + entity id @@ -4550,22 +4812,27 @@ 1 2 -96 +11 2 3 -32 +6 3 -6 -12 +4 +2 -6 -40 -3 +4 +5 +2 + + +5 +16 +2 @@ -4581,7 +4848,7 @@ 1 2 -143 +23 @@ -4597,7 +4864,7 @@ 1 2 -143 +23 @@ -4613,7 +4880,7 @@ 1 2 -143 +23 @@ -4629,17 +4896,17 @@ 1 2 -101 +16 2 3 -31 +5 3 -40 -11 +6 +2 @@ -4655,12 +4922,7 @@ 1 2 -141 - - -2 -5 -2 +23 @@ -4676,12 +4938,17 @@ 1 2 -231 +24 2 +3 +9 + + +15 16 -10 +1 @@ -4697,7 +4964,7 @@ 1 2 -241 +34 @@ -4713,7 +4980,7 @@ 1 2 -241 +34 @@ -4729,7 +4996,7 @@ 1 2 -241 +34 @@ -4745,7 +5012,7 @@ 1 2 -241 +34 @@ -4761,7 +5028,7 @@ 1 2 -241 +34 @@ -4775,165 +5042,16 @@ 12 -1 -2 -9 - - 2 3 -3 - - -3 -4 -3 - - -4 -5 -2 - - -5 -6 -1 - - -6 -7 -2 - - -8 -9 -2 - - -9 -11 -2 - - -12 -13 -2 - - -24 -25 -2 - - -50 -59 -2 - - - - - - -stack_trace -severity - - -12 - - -1 -2 -29 - - -2 -3 -1 - - - - - - -stack_trace -origin - - -12 - - -1 -2 -30 - - - - - - -stack_trace -text - - -12 - - -1 -2 -28 - - -2 -3 -2 - - - - - - -stack_trace -entity - - -12 - - -1 -2 -15 - - -2 -3 -5 - - -3 -4 1 4 5 -2 - - -5 -6 1 -6 -7 -3 - - -17 -21 -2 - - 51 52 1 @@ -4944,7 +5062,7 @@ stack_trace -location +severity 12 @@ -4952,57 +5070,101 @@ 1 2 -9 +2 2 3 +1 + + + + + + +stack_trace +origin + + +12 + + +1 +2 3 + + + + + +stack_trace +text + + +12 + -3 -4 -3 +1 +2 +2 + + +2 +3 +1 + + + + + + +stack_trace +entity + + +12 + + +1 +2 +1 4 5 -2 - - -5 -6 1 -6 -7 -2 +18 +19 +1 + + + + + + +stack_trace +location + + +12 + + +2 +3 +1 -8 -9 -2 +4 +5 +1 -9 -11 -2 - - -12 -13 -2 - - -24 -25 -2 - - -27 -59 -2 +28 +29 +1 @@ -5012,19 +5174,19 @@ compilation_finished -641 +1057 id -641 +1057 cpu_seconds -248 +509 elapsed_seconds -641 +1056 @@ -5038,7 +5200,7 @@ 1 2 -641 +1057 @@ -5054,7 +5216,7 @@ 1 2 -641 +1057 @@ -5070,32 +5232,27 @@ 1 2 -154 +299 2 3 -19 +93 3 -5 -22 +4 +41 -5 +4 6 -17 +41 6 -8 -18 - - -8 -15 -18 +14 +35 @@ -5111,32 +5268,27 @@ 1 2 -154 +299 2 3 -19 +93 3 -5 -22 +4 +41 -5 +4 6 -17 +41 6 -8 -18 - - -8 -15 -18 +14 +35 @@ -5152,7 +5304,12 @@ 1 2 -641 +1055 + + +2 +3 +1 @@ -5168,7 +5325,12 @@ 1 2 -641 +1055 + + +2 +3 +1 @@ -5592,11 +5754,11 @@ externalData -16 +18 id -8 +9 path @@ -5608,7 +5770,7 @@ value -16 +18 @@ -5622,7 +5784,7 @@ 1 2 -8 +9 @@ -5638,7 +5800,7 @@ 2 3 -8 +9 @@ -5654,7 +5816,7 @@ 2 3 -8 +9 @@ -5668,8 +5830,8 @@ 12 -8 -9 +9 +10 1 @@ -5700,8 +5862,8 @@ 12 -16 -17 +18 +19 1 @@ -5716,8 +5878,8 @@ 12 -8 -9 +9 +10 2 @@ -5748,8 +5910,8 @@ 12 -8 -9 +9 +10 2 @@ -5766,7 +5928,7 @@ 1 2 -16 +18 @@ -5782,7 +5944,7 @@ 1 2 -16 +18 @@ -5798,7 +5960,7 @@ 1 2 -16 +18 @@ -5830,19 +5992,19 @@ duplicateCode -13480 +20134 id -13480 +20134 relativePath -1215 +2570 equivClass -4735 +7291 @@ -5856,7 +6018,7 @@ 1 2 -13480 +20134 @@ -5872,7 +6034,7 @@ 1 2 -13480 +20134 @@ -5888,42 +6050,37 @@ 1 2 -483 +1164 2 3 -249 +511 3 4 -81 +177 4 -5 -81 +6 +237 -5 -8 -108 +6 +11 +217 -8 -16 -97 +11 +41 +194 -16 -70 -92 - - -71 +41 1047 -24 +70 @@ -5939,37 +6096,32 @@ 1 2 -624 +1401 2 3 -173 +377 3 4 -107 +217 4 -5 -71 +6 +225 -5 -8 -111 +6 +12 +206 -8 -23 -94 - - -23 +12 405 -35 +144 @@ -5985,32 +6137,32 @@ 1 2 -2 +5 2 3 -3064 +4859 3 4 -717 +1105 4 5 -431 +632 5 -8 -361 +9 +574 -8 +9 11 -160 +116 @@ -6026,17 +6178,22 @@ 1 2 -3704 +4521 2 3 -800 +2071 3 +6 +603 + + +6 11 -231 +96 @@ -6046,19 +6203,19 @@ similarCode -124007 +149289 id -124007 +149289 relativePath -3653 +5832 equivClass -34919 +43184 @@ -6072,7 +6229,7 @@ 1 2 -124007 +149289 @@ -6088,7 +6245,7 @@ 1 2 -124007 +149289 @@ -6104,57 +6261,57 @@ 1 2 -819 +1266 2 3 -561 +999 3 4 -253 +428 4 5 -240 +427 5 -7 -328 +6 +317 -7 -10 -303 +6 +8 +460 -10 -16 -290 +8 +12 +464 -16 -27 -280 +12 +19 +445 -27 -63 -277 +19 +40 +450 -63 -540 -274 +40 +158 +438 -563 +158 10255 -28 +138 @@ -6170,47 +6327,47 @@ 1 2 -1136 +1794 2 3 -509 +875 3 4 -343 +565 4 5 -248 +436 5 7 -327 +540 7 10 -285 +473 10 17 -289 +467 17 -39 -283 +45 +443 -39 +45 3151 -233 +239 @@ -6226,37 +6383,37 @@ 1 2 -27 +33 2 3 -15700 +20582 3 4 -6717 +8089 4 5 -4246 +4987 5 6 -2523 +2926 6 8 -3121 +3616 8 11 -2585 +2951 @@ -6272,22 +6429,22 @@ 1 2 -24135 +29024 2 3 -7080 +9400 3 5 -2744 +3481 5 11 -960 +1279 @@ -6297,11 +6454,11 @@ tokens -16303051 +20596077 id -137487 +169423 offset @@ -6313,7 +6470,7 @@ beginColumn -1273 +1275 endLine @@ -6321,7 +6478,7 @@ endColumn -1281 +1282 @@ -6335,72 +6492,72 @@ 100 101 -14059 +17349 101 102 -11347 +14013 102 103 -9867 +11330 103 104 -7193 +8613 104 105 -7011 +8343 105 107 -11281 +13200 107 109 -9402 +11207 109 112 -11634 +13800 112 116 -11231 +13475 116 122 -10975 +13227 122 132 -11245 +13847 132 -151 -10714 +150 +13094 -151 -246 -10322 +150 +200 +12774 -246 +200 24726 -1206 +5151 @@ -6416,77 +6573,72 @@ 3 8 -9658 +15571 8 10 -10203 +13241 10 12 -12464 +14984 12 13 -7171 +8221 13 14 -8457 +9518 14 15 -8662 +10126 15 16 -7359 +8365 16 -17 -6734 +18 +15128 -17 -19 -12294 +18 +20 +14382 -19 -21 -11808 +20 +22 +13269 -21 -23 -10152 +22 +24 +10793 -23 -25 -9076 +24 +27 +14004 -25 -29 -12371 +27 +33 +13393 -29 -50 -10359 - - -50 +33 4516 -719 +8428 @@ -6501,68 +6653,68 @@ 3 -31 -11905 +30 +13731 -31 -36 -11061 +30 +35 +12960 -36 +35 40 -10541 +15615 40 44 -11491 +13732 44 48 -12544 +15209 48 51 -9774 +11686 51 54 -10252 +12470 54 57 -10130 +12211 57 61 -12505 +15141 61 65 -11020 +13198 65 71 -11742 +14162 71 83 -10362 +13148 83 356 -4160 +6160 @@ -6578,82 +6730,77 @@ 3 8 -9693 +15606 8 10 -10246 +13284 10 11 -6305 +7617 11 12 -6863 +8071 12 13 -7917 +8967 13 14 -8978 +10039 14 15 -8596 +10060 15 16 -7157 +8163 16 -17 -6534 - - -17 18 -6305 +15038 18 -19 -6514 +20 +15158 -19 -21 -12394 +20 +22 +13995 -21 -23 -10926 +22 +24 +11189 -23 -25 -9003 +24 +27 +13173 -25 -29 -10845 +27 +35 +13285 -29 +35 4516 -9211 +5778 @@ -6668,68 +6815,68 @@ 3 -33 -11758 +32 +13965 -33 +32 38 -10683 +14984 38 -42 -10267 +43 +15403 -42 -46 -11227 +43 +47 +13368 -46 -50 -11885 +47 +51 +14461 -50 -54 -12367 +51 +55 +15157 -54 -57 -9677 +55 +58 +11849 -57 -60 -9829 +58 +62 +15331 -60 -64 -11875 +62 +66 +13741 -64 -68 -10641 +66 +71 +14501 -68 -73 -10560 +71 +78 +13414 -73 -82 -10400 +78 +120 +12726 -82 +120 363 -6318 +523 @@ -6745,16 +6892,26 @@ 2 3 -21440 +10300 4 -9 +5 +8833 + + +7 +8 +2307 + + +9 +30 1856 -12 -137488 +33 +169424 1429 @@ -6771,16 +6928,26 @@ 2 3 -21440 +10300 -4 -9 +3 +4 +8833 + + +5 +6 +2307 + + +7 +24 1856 -10 -27395 +24 +27429 1429 @@ -6797,17 +6964,27 @@ 1 2 -21460 +10430 2 -7 -1942 +3 +8777 -7 -470 -1323 +3 +4 +2244 + + +4 +15 +1894 + + +15 +489 +1380 @@ -6823,16 +7000,26 @@ 2 3 -21440 +10300 -4 -9 +3 +4 +8833 + + +5 +6 +2307 + + +7 +24 1856 -10 -27361 +24 +27395 1429 @@ -6849,17 +7036,27 @@ 1 2 -21457 +10382 2 -7 -1939 +3 +8807 -7 -479 -1329 +3 +4 +2264 + + +4 +15 +1897 + + +15 +494 +1375 @@ -6895,57 +7092,57 @@ 5 6 -4514 +4513 6 7 -4085 +4086 7 8 -3742 +3748 8 9 -3307 +3319 9 11 -5783 +5799 11 14 -5837 +5802 14 19 -5467 +5476 19 32 -5251 +5188 32 -76 -5025 +80 +5056 -76 -1383 +80 +1828 5022 -1384 -3597 -208 +1830 +5217 +232 @@ -6986,42 +7183,47 @@ 26 35 -5332 +5342 35 45 -5040 +5030 45 57 -5140 +5139 57 72 -5093 +5082 72 91 -5148 +5111 91 114 -5184 +5123 114 -149 -5124 +153 +5067 -149 -441 -4975 +153 +499 +5022 + + +499 +605 +120 @@ -7047,7 +7249,7 @@ 4 6 -4829 +4828 6 @@ -7057,7 +7259,7 @@ 9 12 -5032 +5031 12 @@ -7067,32 +7269,32 @@ 16 20 -5344 +5337 20 26 -5672 +5654 26 35 -5331 +5318 35 -53 -5120 +54 +5192 -53 -93 -5098 +54 +99 +5040 -93 -313 -3993 +99 +340 +4019 @@ -7149,47 +7351,47 @@ 6 9 -6096 +6095 9 12 -5031 +5032 12 16 -5544 +5541 16 20 -5294 +5289 20 26 -5618 +5602 26 35 -5225 +5213 35 53 -5146 +5023 53 -92 -5094 +94 +5029 -92 -319 -4369 +94 +342 +4593 @@ -7205,73 +7407,68 @@ 1 2 -102 +101 2 3 -76 +77 3 5 -104 +103 5 -8 -94 +9 +118 -8 -11 -94 +9 +12 +93 -11 -14 -90 +12 +16 +99 -14 -18 -100 +16 +22 +107 -18 -28 +22 +49 97 -28 -91 +49 +154 96 -92 -263 +155 +460 96 -264 -835 +460 +2842 96 -851 -12397 +2886 +34163 96 -12702 -67475 +34851 +133446 96 - -68233 -114514 -36 - @@ -7286,67 +7483,67 @@ 1 2 -104 +102 2 3 -84 +86 3 5 -112 +111 5 8 -94 +86 8 11 -117 +116 11 -14 -99 +15 +112 -14 -19 -101 +15 +21 +102 -19 -39 -99 - - -40 -82 +21 +46 97 -82 -126 +46 +99 98 -126 -213 -99 - - -215 -449 +99 +152 96 -453 -3387 -73 +153 +273 +96 + + +274 +708 +96 + + +708 +3646 +77 @@ -7362,62 +7559,62 @@ 1 2 -243 +240 2 3 -98 +85 3 4 -112 +115 4 5 -79 +69 5 -6 -84 +7 +118 -6 -8 -107 - - -8 -23 -96 - - -23 -54 +7 +10 97 -54 -144 +10 +33 +97 + + +33 +80 96 -145 -1392 +80 +216 96 -1447 -10372 +216 +1785 96 -10475 -36610 -69 +1861 +10566 +96 + + +10669 +36636 +70 @@ -7433,62 +7630,62 @@ 1 2 -243 +240 2 3 -98 +85 3 4 -112 +115 4 5 -79 +69 5 -6 -84 +7 +118 -6 -8 -107 - - -8 -23 -96 - - -23 -54 +7 +10 97 -54 -144 +10 +33 +97 + + +33 +80 96 -145 -1392 +80 +216 96 -1447 -10375 +216 +1785 96 -10476 -36609 -69 +1861 +10566 +96 + + +10670 +36635 +70 @@ -7504,52 +7701,52 @@ 1 2 -321 +313 2 3 -178 +162 3 4 -164 +154 4 5 -81 +75 5 9 -117 +113 9 15 -97 +102 15 22 -98 +106 22 -44 -96 +35 +98 -44 -88 -96 +35 +75 +98 -89 +75 176 -25 +54 @@ -7585,57 +7782,57 @@ 5 6 -4460 +4459 6 7 -4053 +4054 7 8 -3674 +3680 8 9 -3252 +3264 9 11 -5618 +5635 11 14 -5654 +5618 14 19 -5335 +5343 19 32 -5179 +5112 32 -75 -4971 +78 +4956 -75 -1119 +78 +1307 4932 -1121 -3579 -273 +1308 +5199 +348 @@ -7656,22 +7853,22 @@ 5 9 -5454 +5457 9 15 -5692 +5689 15 22 -5387 +5386 22 30 -5043 +5047 30 @@ -7681,37 +7878,37 @@ 39 50 -5193 +5190 50 63 -5119 +5112 63 79 -4956 +4943 79 99 -5007 +4966 99 125 -5078 +4992 125 -163 -4979 +173 +4964 -163 -441 -3294 +173 +605 +3456 @@ -7768,52 +7965,52 @@ 5 7 -5672 +5671 7 10 -4870 +4871 10 14 -6007 +6004 14 17 -5141 +5140 17 22 -5202 +5191 22 28 -5339 +5324 28 39 -5222 +5191 39 -61 -5007 +62 +5013 -61 -109 -4976 +62 +118 +4937 -109 -313 -2739 +118 +340 +2833 @@ -7844,52 +8041,52 @@ 5 7 -5488 +5487 7 10 -4894 +4895 10 14 -5975 +5972 14 17 -5079 +5077 17 22 -5183 +5177 22 28 -5298 +5282 28 39 -5141 +5107 39 -61 -5028 +62 +5051 -61 -107 -4991 +62 +115 +4947 -107 -318 -3089 +115 +342 +3171 @@ -7905,72 +8102,72 @@ 1 2 -103 +100 2 3 -75 +73 3 5 -109 +112 5 8 -99 +93 8 11 -99 +94 11 15 -109 +102 15 21 -99 +100 21 -38 +36 +100 + + +36 +132 97 -38 -127 +133 +348 97 -128 -343 -98 - - -344 -1906 +350 +1580 97 -1964 -25254 +1614 +21369 97 -25838 -92921 +21416 +97489 97 -95159 -100909 -5 +97674 +119719 +23 @@ -7986,67 +8183,72 @@ 1 2 -106 +102 2 3 -80 +79 3 4 -91 +92 4 8 -118 +115 8 10 -90 +83 10 14 -117 +108 14 19 -102 +105 19 -33 +32 99 -33 -78 -97 - - -80 -122 +32 +81 98 -122 -200 +81 +133 97 -200 -398 +133 +232 97 -398 -2279 -89 +232 +491 +97 + + +491 +1764 +97 + + +1819 +3367 +13 @@ -8062,62 +8264,62 @@ 1 2 -248 +239 2 3 -109 +99 3 4 -89 +94 4 5 -98 +89 5 -6 -74 +7 +108 -6 -8 -101 +7 +11 +105 -8 -22 -97 - - -22 -51 +11 +39 98 -51 -133 +39 +87 97 -133 -1225 +88 +251 97 -1290 -10635 +256 +2289 97 -10679 -26467 -76 +2295 +11901 +97 + + +12187 +26471 +62 @@ -8133,52 +8335,52 @@ 1 2 -319 +309 2 3 -191 +177 3 4 -147 +136 4 -6 -117 +5 +71 -6 -11 -108 +5 +9 +111 -11 -18 +9 +16 +110 + + +16 +25 101 -18 -30 -99 +25 +38 +97 -30 -53 -98 +38 +66 +103 -53 -75 -98 - - -76 +66 110 -3 +67 @@ -8194,62 +8396,62 @@ 1 2 -248 +239 2 3 -109 +99 3 4 -89 +94 4 5 -98 +89 5 -6 -74 +7 +108 -6 -8 -101 +7 +11 +105 -8 -22 -97 - - -22 -51 +11 +39 98 -51 -133 +39 +87 97 -133 -1225 +88 +251 97 -1290 -10635 +256 +2289 97 -10679 -26467 -76 +2295 +11901 +97 + + +12187 +26471 +62 @@ -8259,15 +8461,15 @@ locations_default -7339237 +11787435 id -7339237 +11787435 file -13679 +22092 beginLine @@ -8275,7 +8477,7 @@ beginColumn -1126 +1161 endLine @@ -8283,7 +8485,7 @@ endColumn -1207 +1237 @@ -8297,7 +8499,7 @@ 1 2 -7339237 +11787435 @@ -8313,7 +8515,7 @@ 1 2 -7339237 +11787435 @@ -8329,7 +8531,7 @@ 1 2 -7339237 +11787435 @@ -8345,7 +8547,7 @@ 1 2 -7339237 +11787435 @@ -8361,7 +8563,7 @@ 1 2 -7339237 +11787435 @@ -8376,73 +8578,73 @@ 1 -18 -1049 +16 +1739 -18 -29 -908 +16 +27 +1704 -29 -34 -1032 +27 +35 +1622 -34 -52 -1072 +35 +48 +1689 -52 -74 -1062 +48 +70 +1725 -74 -101 -1043 +70 +98 +1659 -101 -140 -1035 +98 +141 +1671 -140 -194 -1027 +141 +199 +1668 -194 -271 -1035 +199 +286 +1657 -271 -392 -1026 +286 +425 +1666 -392 -601 -1029 +425 +680 +1657 -601 -1067 -1026 +680 +1245 +1658 -1068 -3393 -1026 +1245 +4832 +1657 -3400 -167164 -309 +4835 +167166 +320 @@ -8457,68 +8659,68 @@ 1 -10 -1072 +9 +1729 -10 -15 -1074 +9 +14 +1933 -15 -20 -949 +14 +19 +1627 -20 -23 -1180 +19 +22 +1911 -23 -30 -1114 +22 +29 +1670 -30 +29 39 -1056 +1774 39 -51 -1049 +52 +1707 -51 -69 -1049 +52 +71 +1664 -69 -93 -1048 +71 +99 +1676 -93 -133 -1044 +99 +145 +1659 -133 -204 -1028 +145 +229 +1660 -204 -378 -1027 +229 +454 +1657 -378 +454 44061 -989 +1425 @@ -8534,67 +8736,67 @@ 1 7 -698 +1536 7 -10 -1112 +11 +1891 -10 -16 -1138 +11 +15 +1732 -16 -22 -1222 +15 +21 +1867 -22 -28 -1170 +21 +27 +1695 -28 +27 34 -1044 +1796 34 -41 -1063 +42 +1791 -41 -49 -1065 +42 +51 +1809 -49 -59 -1107 +51 +62 +1803 -59 -70 -1042 +62 +75 +1792 -70 -85 -1080 +75 +91 +1700 -85 -107 -1026 +91 +119 +1673 -107 +119 781 -912 +1007 @@ -8609,68 +8811,68 @@ 1 -10 -1068 +9 +1728 -10 -15 -1066 +9 +14 +1924 -15 -20 -959 +14 +19 +1631 -20 -23 -1174 +19 +22 +1915 -23 +22 30 -1103 +1877 30 -39 -1060 +40 +1726 -39 -51 -1062 +40 +53 +1657 -51 -69 -1061 +53 +73 +1687 -69 -93 -1036 +73 +102 +1684 -93 -133 -1039 +102 +150 +1678 -133 -204 -1033 +150 +242 +1659 -204 -379 -1030 +242 +504 +1659 -380 +504 46103 -988 +1267 @@ -8685,68 +8887,68 @@ 1 -15 -1084 +13 +1769 -15 -23 -1091 +13 +20 +1667 -23 -27 -1154 +20 +25 +1751 -27 -36 -1104 +25 +31 +1697 -36 -44 -1053 +31 +40 +1705 -44 -54 -1096 +40 +50 +1773 -54 -65 -1080 +50 +61 +1688 -65 -77 -1097 +61 +73 +1741 -77 -90 -1064 +73 +86 +1709 -90 -104 -1053 +86 +100 +1727 -104 -121 -1056 +100 +117 +1754 -121 -149 -1043 +117 +142 +1670 -149 +142 883 -704 +1441 @@ -8772,17 +8974,17 @@ 3 4 -4194 +4193 4 5 -3819 +3818 5 7 -6300 +6302 7 @@ -8792,7 +8994,7 @@ 8 10 -4991 +4990 10 @@ -8802,27 +9004,27 @@ 13 18 -5837 +5836 18 28 -5563 +5541 28 -60 -5469 +65 +5497 -60 -223 +65 +290 5443 -223 -25138 -3711 +290 +39954 +3707 @@ -8853,22 +9055,22 @@ 4 6 -5614 +5612 6 12 -5659 +5460 12 -39 -5507 +46 +5480 -39 -13512 -4467 +46 +21923 +4695 @@ -8894,7 +9096,7 @@ 3 4 -5401 +5400 4 @@ -8904,7 +9106,7 @@ 5 6 -5787 +5788 6 @@ -8914,32 +9116,32 @@ 7 9 -6496 +6494 9 12 -6083 +6072 12 18 -5599 +5518 18 -34 -5493 +39 +5563 -34 -90 -5481 +39 +110 +5455 -90 -337 -1877 +110 +373 +1927 @@ -8955,32 +9157,32 @@ 1 2 -33221 +33201 2 3 -21100 +21035 3 4 -6051 +5962 4 -8 -5780 +9 +6100 -8 -34 -5457 +9 +46 +5486 -34 -89 -914 +46 +367 +739 @@ -9006,7 +9208,7 @@ 3 4 -4747 +4746 4 @@ -9016,7 +9218,7 @@ 5 6 -3954 +3955 6 @@ -9026,12 +9228,12 @@ 7 8 -4764 +4762 8 10 -4965 +4966 10 @@ -9041,27 +9243,27 @@ 13 18 -5782 +5776 18 29 -5697 +5626 29 -58 -5476 +64 +5542 -58 -133 -5488 +64 +149 +5479 -133 -377 -1748 +149 +413 +1769 @@ -9077,57 +9279,62 @@ 1 2 -313 +312 2 3 -85 +82 3 4 -67 +61 4 5 -71 +67 5 -7 -78 +8 +107 -7 -13 -92 +8 +17 +90 -13 -38 +17 +55 88 -38 -123 -86 +55 +175 +88 -127 -1194 -85 +176 +1176 +88 -1236 -15406 -85 +1256 +16999 +88 -15727 -1094594 -76 +17523 +646623 +88 + + +1430464 +1573394 +2 @@ -9143,47 +9350,52 @@ 1 2 -386 +369 2 3 -155 +129 3 4 -91 +75 4 6 -82 +88 6 -12 -90 +13 +88 -12 -45 -85 +13 +29 +91 -48 -536 -85 +29 +106 +88 -542 -3990 -85 +110 +1029 +88 -4076 -13387 -67 +1033 +7700 +88 + + +7907 +21381 +57 @@ -9199,57 +9411,57 @@ 1 2 -351 +345 2 3 -96 +89 3 4 -65 +58 4 -5 -61 - - -5 -8 +6 100 -8 -18 -86 +6 +11 +96 -18 -52 -87 +11 +29 +90 -52 -307 -85 +30 +94 +91 -314 -2787 -85 +94 +413 +88 -2849 -9082 -85 +415 +2920 +88 -9434 -50357 -25 +2932 +9215 +88 + + +9290 +50368 +28 @@ -9265,57 +9477,57 @@ 1 2 -351 +345 2 3 -96 +89 3 4 -65 +58 4 -5 -61 - - -5 -8 +6 100 -8 -18 -86 +6 +11 +96 -18 -52 -87 +11 +29 +90 -52 -307 -85 +30 +94 +91 -319 -2788 -85 +94 +413 +88 -2852 -9085 -85 +415 +2918 +88 -9525 -53426 -25 +2936 +9228 +88 + + +9288 +53430 +28 @@ -9331,52 +9543,57 @@ 1 2 -359 +352 2 3 -105 +101 3 4 -85 +76 4 6 -85 +91 6 11 -90 +94 11 -22 +24 89 -22 -40 -87 +24 +41 +89 -40 -76 -86 +41 +68 +89 -76 -197 -85 +68 +162 +88 -199 -453 -55 +162 +383 +88 + + +429 +454 +4 @@ -9402,7 +9619,7 @@ 3 4 -5876 +5875 4 @@ -9432,22 +9649,22 @@ 18 29 -5851 +5819 29 -66 -5624 +73 +5604 -66 -290 -5556 +73 +410 +5557 -290 -24298 -3085 +410 +38993 +3137 @@ -9473,27 +9690,27 @@ 3 4 -7358 +7357 4 6 -5646 +5645 6 12 -5903 +5743 12 -39 -5621 +46 +5573 -39 -13508 -4602 +46 +21919 +4812 @@ -9509,32 +9726,32 @@ 1 2 -37930 +37920 2 3 -17510 +17451 3 4 -5827 +5698 4 -7 +8 +6068 + + +8 +35 5571 -7 -25 -5561 - - -25 -72 -1650 +35 +82 +1341 @@ -9560,12 +9777,12 @@ 3 4 -6607 +6605 4 5 -3869 +3870 5 @@ -9580,32 +9797,32 @@ 7 9 -6712 +6711 9 12 -6169 +6159 12 18 -5741 +5659 18 -35 -5704 +39 +5609 -35 -97 -5588 +39 +113 +5569 -97 -337 -1602 +113 +373 +1810 @@ -9631,7 +9848,7 @@ 3 5 -6505 +6504 5 @@ -9651,32 +9868,32 @@ 10 13 -5916 +5915 13 18 -5691 +5686 18 30 -5804 +5717 30 -62 -5589 +68 +5606 -62 -149 +68 +166 5572 -149 -378 -1103 +166 +413 +1180 @@ -9692,57 +9909,57 @@ 1 2 -303 +305 2 3 -101 +103 3 4 -86 +82 4 6 -107 +100 6 10 -93 +98 10 -30 +32 94 -30 -76 -91 +32 +90 +93 -76 -274 -91 +90 +312 +93 -290 -4787 -91 +318 +3282 +93 -4919 -54258 -91 +3320 +47350 +93 -56076 -183228 -59 +48707 +290233 +83 @@ -9758,47 +9975,52 @@ 1 2 -399 +385 2 3 -159 +150 3 4 -101 +79 4 -9 -97 +7 +99 -9 -20 +7 +23 +95 + + +23 +47 94 -20 -55 -91 +47 +204 +93 -55 -650 -91 +212 +1974 +93 -651 -5179 -91 +2010 +11406 +93 -5249 -10698 -84 +11549 +16182 +56 @@ -9814,57 +10036,57 @@ 1 2 -339 +344 2 3 -112 +103 3 4 -78 +73 4 6 -107 +95 6 -13 -98 +11 +102 -13 -32 -91 +11 +37 +95 -32 -93 -92 +37 +110 +94 -93 -691 -91 +110 +456 +93 -729 -5319 -91 +460 +3065 +93 -5513 -13620 -91 +3078 +11825 +93 -13631 -22565 -17 +11842 +22748 +52 @@ -9880,52 +10102,57 @@ 1 2 -334 +333 2 3 -140 +136 3 4 -91 +87 4 -6 -83 +7 +112 -6 -12 -99 +7 +15 +95 -12 -27 +15 +35 +96 + + +35 +68 94 -27 -53 -91 +68 +93 +95 -53 -81 -91 - - -81 -123 +93 +138 93 -123 -169 -91 +138 +177 +94 + + +177 +179 +2 @@ -9941,57 +10168,57 @@ 1 2 -341 +346 2 3 -112 +103 3 4 -76 +71 4 6 -107 +95 6 -13 -98 +11 +103 -13 -32 -91 +11 +37 +94 -32 -92 -91 +37 +110 +94 -92 -665 -91 +110 +450 +93 -686 -5235 -91 +452 +3056 +93 -5316 -13328 -91 +3072 +11597 +93 -13356 -22538 -18 +11609 +22648 +52 @@ -10001,23 +10228,23 @@ numlines -213180 +344316 element_id -213180 +321238 num_lines -1200 +1544 num_code -1005 +1300 num_comment -387 +506 @@ -10031,7 +10258,12 @@ 1 2 -213180 +298186 + + +2 +4 +23052 @@ -10047,7 +10279,12 @@ 1 2 -213180 +298202 + + +2 +4 +23036 @@ -10063,7 +10300,12 @@ 1 2 -213180 +318086 + + +2 +4 +3152 @@ -10079,47 +10321,42 @@ 1 2 -505 +638 2 3 -154 +199 3 4 -92 +118 4 6 -84 +114 6 10 -94 +123 10 20 -90 +121 20 -81 -90 +76 +116 -81 -26473 -90 - - -33985 -33986 -1 +77 +72660 +115 @@ -10135,42 +10372,42 @@ 1 2 -506 +640 2 3 -158 +201 3 4 -91 +117 4 6 -87 +124 6 10 -104 +126 10 18 -101 +124 18 -32 -92 +34 +116 -32 -47 -61 +34 +53 +96 @@ -10186,42 +10423,42 @@ 1 2 -507 +640 2 3 -158 +199 3 4 -90 +117 4 6 -94 +122 6 10 -96 +131 10 -16 -94 +17 +120 -16 -27 -98 +17 +30 +116 -27 -38 -63 +30 +44 +99 @@ -10237,42 +10474,42 @@ 1 2 -407 +523 2 3 -128 +165 3 4 -78 +102 4 6 -81 +114 6 11 -88 +103 11 23 -77 +98 23 -92 -76 +82 +98 -98 -43772 -70 +84 +101108 +97 @@ -10288,43 +10525,43 @@ 1 2 -407 +524 2 3 -130 +169 3 4 -79 +99 4 6 -82 +116 6 -10 +11 +107 + + +11 +22 +104 + + +22 +45 +101 + + +45 +60 80 - -10 -19 -77 - - -19 -36 -79 - - -36 -53 -71 - @@ -10339,42 +10576,42 @@ 1 2 -409 +526 2 3 -133 +163 3 4 -76 +103 4 6 -85 +118 6 -10 -82 +11 +113 -10 -18 -79 +11 +21 +100 -18 -30 -80 +21 +36 +99 -30 -45 -61 +36 +51 +78 @@ -10390,47 +10627,47 @@ 1 2 -156 +192 2 3 -47 +61 3 4 -31 +45 4 6 -29 +43 6 10 -33 +40 10 -25 -30 +21 +40 -26 -94 -30 +21 +69 +39 -98 -11994 -30 +69 +1913 +38 -166744 -166745 -1 +1919 +255606 +8 @@ -10446,47 +10683,47 @@ 1 2 -156 +193 2 3 -47 +60 3 4 -32 +45 4 6 -30 +43 6 10 -31 +41 10 -24 -30 +21 +39 -24 -74 -30 +21 +57 +38 -74 -231 -30 +58 +227 +38 -365 -366 -1 +227 +375 +9 @@ -10502,42 +10739,47 @@ 1 2 -156 +193 2 3 -47 +60 3 4 -31 +45 4 6 -30 +43 6 10 -32 +40 10 -24 -31 +21 +42 -25 -75 -30 +22 +64 +38 -78 -327 -30 +66 +210 +38 + + +211 +333 +7 @@ -10547,27 +10789,27 @@ assemblies -1870 +2863 id -1870 +2863 file -1870 +2861 fullname -1246 +1321 name -556 +605 version -115 +124 @@ -10581,7 +10823,7 @@ 1 2 -1870 +2863 @@ -10597,7 +10839,7 @@ 1 2 -1870 +2863 @@ -10613,7 +10855,7 @@ 1 2 -1870 +2863 @@ -10629,7 +10871,7 @@ 1 2 -1870 +2863 @@ -10645,7 +10887,12 @@ 1 2 -1870 +2859 + + +2 +3 +2 @@ -10661,7 +10908,12 @@ 1 2 -1870 +2859 + + +2 +3 +2 @@ -10677,7 +10929,7 @@ 1 2 -1870 +2861 @@ -10693,7 +10945,7 @@ 1 2 -1870 +2861 @@ -10709,22 +10961,27 @@ 1 2 -798 +782 2 3 -349 +234 3 -9 -97 +4 +92 -9 -10 -2 +4 +7 +114 + + +7 +13 +99 @@ -10740,22 +10997,27 @@ 1 2 -798 +782 2 3 -349 +234 3 -9 -97 +4 +92 -9 -10 -2 +4 +7 +114 + + +7 +13 +99 @@ -10771,7 +11033,7 @@ 1 2 -1246 +1321 @@ -10787,7 +11049,7 @@ 1 2 -1246 +1321 @@ -10803,124 +11065,134 @@ 1 2 -238 +231 2 3 -85 +70 3 4 -57 - - -4 -5 -49 - - -5 -7 -38 - - -7 -8 -42 - - -8 -14 -44 - - -26 -27 -3 - - - - - - -name -file - - -12 - - -1 -2 -238 - - -2 -3 -85 - - -3 -4 -57 - - -4 -5 -49 - - -5 -7 -38 - - -7 -8 -42 - - -8 -14 -44 - - -26 -27 -3 - - - - - - -name -fullname - - -12 - - -1 -2 -376 - - -2 -3 -66 - - -3 -4 -37 +52 4 6 -42 +55 + + +6 +9 +53 + + +9 +11 +43 + + +11 +13 +39 + + +13 +15 +56 + + +15 +27 +6 + + + + + + +name +file + + +12 + + +1 +2 +231 + + +2 +3 +71 + + +3 +4 +52 + + +4 +6 +54 + + +6 +9 +53 + + +9 +11 +43 + + +11 +13 +39 + + +13 +15 +56 + + +15 +27 +6 + + + + + + +name +fullname + + +12 + + +1 +2 +416 + + +2 +3 +61 + + +3 +4 +48 + + +4 +6 +45 13 @@ -10941,22 +11213,22 @@ 1 2 -411 +452 2 3 -66 +61 3 4 -37 +47 4 6 -42 +45 @@ -10972,37 +11244,47 @@ 1 2 -49 +47 2 3 -20 +16 3 4 -11 +9 4 -7 +6 9 -7 +6 +8 +9 + + +8 10 -7 +9 10 -31 +28 10 -33 +28 +103 +10 + + +147 756 -9 +5 @@ -11018,37 +11300,47 @@ 1 2 -49 +47 2 3 -20 +17 3 4 -11 +9 4 -7 +6 +8 + + +6 +8 9 -7 +8 10 -7 +9 10 -31 +28 10 -33 +28 +103 +10 + + +147 756 -9 +5 @@ -11064,7 +11356,7 @@ 1 2 -64 +68 2 @@ -11073,23 +11365,28 @@ 3 -5 +4 9 -5 -8 -9 - - -8 -23 +4 +7 10 -25 +7 +20 +10 + + +22 +71 +10 + + +123 586 -8 +2 @@ -11105,32 +11402,37 @@ 1 2 -64 +69 2 3 -15 +14 3 -5 +4 9 -5 -8 -9 - - -8 -23 +4 +7 10 -25 +7 +20 +10 + + +22 +71 +10 + + +122 166 -8 +2 @@ -11140,23 +11442,23 @@ files -15550 +24954 id -15550 +24954 name -15550 +24954 simple -12907 +20050 ext -7 +8 fromSource @@ -11174,7 +11476,7 @@ 1 2 -15550 +24954 @@ -11190,7 +11492,7 @@ 1 2 -15550 +24954 @@ -11206,7 +11508,7 @@ 1 2 -15550 +24954 @@ -11222,7 +11524,7 @@ 1 2 -15550 +24954 @@ -11238,7 +11540,7 @@ 1 2 -15550 +24954 @@ -11254,7 +11556,7 @@ 1 2 -15550 +24954 @@ -11270,7 +11572,7 @@ 1 2 -15550 +24954 @@ -11286,7 +11588,7 @@ 1 2 -15550 +24954 @@ -11302,12 +11604,12 @@ 1 2 -12092 +18724 2 -79 -815 +417 +1326 @@ -11323,12 +11625,12 @@ 1 2 -12092 +18724 2 -79 -815 +417 +1326 @@ -11344,12 +11646,12 @@ 1 2 -12862 +19838 2 4 -45 +212 @@ -11365,7 +11667,7 @@ 1 2 -12907 +20050 @@ -11384,6 +11686,11 @@ 1 +2 +3 +1 + + 9 10 1 @@ -11404,13 +11711,13 @@ 1 -1853 -1854 +2842 +2843 1 -13460 -13461 +21873 +21874 1 @@ -11430,6 +11737,11 @@ 1 +2 +3 +1 + + 9 10 1 @@ -11450,13 +11762,13 @@ 1 -1853 -1854 +2842 +2843 1 -13460 -13461 +21873 +21874 1 @@ -11473,7 +11785,7 @@ 1 2 -1 +2 7 @@ -11496,13 +11808,13 @@ 1 -549 -550 +597 +598 1 -12271 -12272 +19532 +19533 1 @@ -11519,7 +11831,7 @@ 1 2 -7 +8 @@ -11533,8 +11845,8 @@ 12 -15550 -15551 +24954 +24955 1 @@ -11549,8 +11861,8 @@ 12 -15550 -15551 +24954 +24955 1 @@ -11565,8 +11877,8 @@ 12 -12907 -12908 +20050 +20051 1 @@ -11581,8 +11893,8 @@ 12 -7 -8 +8 +9 1 @@ -11593,19 +11905,19 @@ folders -4611 +7016 id -4611 +7016 name -4528 +6927 simple -1557 +1989 @@ -11619,7 +11931,7 @@ 1 2 -4611 +7016 @@ -11635,7 +11947,7 @@ 1 2 -4611 +7016 @@ -11651,12 +11963,12 @@ 1 2 -4445 +6838 2 3 -83 +89 @@ -11672,7 +11984,7 @@ 1 2 -4528 +6927 @@ -11688,27 +12000,27 @@ 1 2 -929 +1079 2 3 -312 +347 3 4 -146 +258 4 -9 -122 +6 +170 -9 -243 -48 +6 +352 +135 @@ -11724,27 +12036,27 @@ 1 2 -964 +1114 2 3 -300 +334 3 4 -138 +252 4 -12 -118 +6 +156 -12 -243 -37 +6 +352 +133 @@ -11754,15 +12066,15 @@ containerparent -20158 +31967 parent -4611 +7016 child -20158 +31967 @@ -11776,32 +12088,32 @@ 1 2 -2359 +3597 2 3 -965 +1293 3 4 -276 +556 4 -7 -385 +6 +568 -7 -15 -347 +6 +14 +536 -15 -226 -279 +14 +229 +466 @@ -11817,7 +12129,7 @@ 1 2 -20158 +31967 @@ -11827,11 +12139,11 @@ file_extraction_mode -15330 +24734 file -15330 +24734 mode @@ -11849,7 +12161,7 @@ 1 2 -15330 +24734 @@ -11868,8 +12180,8 @@ 1 -11522 -11523 +20926 +20927 1 @@ -11880,15 +12192,15 @@ namespaces -5457 +6505 id -5457 +6505 name -1491 +1717 @@ -11902,7 +12214,7 @@ 1 2 -5457 +6505 @@ -11918,37 +12230,37 @@ 1 2 -414 +407 2 3 -564 +730 3 4 -102 +103 4 -6 +5 132 -6 -8 -127 +5 +7 +86 -8 -17 -116 +7 +10 +137 -17 -66 -36 +10 +69 +122 @@ -11958,15 +12270,15 @@ namespace_declarations -14700 +22696 id -14700 +22696 namespace_id -1549 +1922 @@ -11980,7 +12292,7 @@ 1 2 -14700 +22696 @@ -11996,47 +12308,47 @@ 1 2 -481 +638 2 3 -281 +295 3 4 -130 +144 4 5 -91 +105 5 7 -136 +148 7 10 -125 +147 10 -16 -118 +17 +157 -16 -38 -118 +17 +35 +147 -38 +35 646 -69 +141 @@ -12046,15 +12358,15 @@ namespace_declaration_location -14700 +22696 id -14700 +22696 loc -12601 +19757 @@ -12068,7 +12380,7 @@ 1 2 -14700 +22696 @@ -12084,17 +12396,17 @@ 1 2 -10914 +17726 2 3 -1412 +1611 3 -11 -275 +128 +420 @@ -12104,15 +12416,15 @@ parent_namespace -454645 +360683 child_id -454645 +360683 namespace_id -3755 +4420 @@ -12126,7 +12438,7 @@ 1 2 -454645 +360683 @@ -12142,52 +12454,52 @@ 1 2 -1052 +1289 2 3 -443 +494 3 4 -265 +306 4 5 -201 +217 5 7 -326 +382 7 11 -343 +402 11 -18 -298 +17 +338 -18 -33 -300 +17 +30 +338 -33 -87 -283 +30 +66 +335 -87 -144013 -244 +66 +108885 +319 @@ -12197,15 +12509,15 @@ parent_namespace_declaration -17614 +34436 child_id -14102 +24003 namespace_id -14694 +22688 @@ -12219,17 +12531,22 @@ 1 2 -12053 +17774 2 3 -1555 +4375 3 -143 -494 +11 +1807 + + +11 +259 +47 @@ -12245,12 +12562,17 @@ 1 2 -13937 +20681 2 +10 +1727 + + +10 299 -757 +280 @@ -12260,15 +12582,15 @@ using_namespace_directives -85929 +106992 id -85929 +106992 namespace_id -1294 +1422 @@ -12282,7 +12604,7 @@ 1 2 -85929 +106992 @@ -12298,52 +12620,52 @@ 1 2 -322 +341 2 3 -193 +202 3 4 -109 +112 4 6 -112 +131 6 9 -98 +112 9 15 -110 +117 15 -29 -103 +28 +111 -29 -71 -99 +28 +55 +107 -71 -265 -98 +55 +180 +107 -266 -8577 -50 +180 +10946 +82 @@ -12353,15 +12675,15 @@ using_static_directives -253 +321 id -253 +321 type_id -74 +75 @@ -12375,7 +12697,7 @@ 1 2 -253 +321 @@ -12396,32 +12718,37 @@ 2 3 -28 +21 3 4 -7 +10 4 5 -8 +6 5 -7 -5 +8 +6 8 -12 -5 +11 +6 -12 -16 -4 +11 +15 +6 + + +15 +19 +3 @@ -12431,15 +12758,15 @@ using_directive_location -86182 +107313 id -86182 +107313 loc -73015 +91983 @@ -12453,7 +12780,7 @@ 1 2 -86182 +107313 @@ -12469,17 +12796,17 @@ 1 2 -61748 +79730 2 3 -9952 +10544 3 -12 -1315 +128 +1709 @@ -12489,19 +12816,19 @@ types -507522 +413820 id -507522 +413820 kind -28 +27 name -146855 +180164 @@ -12515,7 +12842,7 @@ 1 2 -507522 +413820 @@ -12531,7 +12858,7 @@ 1 2 -507522 +413820 @@ -12547,31 +12874,31 @@ 1 2 -18 +17 -272 -2028 +383 +1383 2 -2476 -7952 +1768 +7962 2 -8356 -37595 +8073 +31633 2 -49262 -80546 +40645 +58091 2 -142002 -176860 +126692 +137174 2 @@ -12588,31 +12915,31 @@ 1 2 -18 +17 -194 -562 +317 +580 2 -931 -995 +1014 +1043 2 -2768 -5106 +3386 +6731 2 -12169 -19871 +14006 +23824 2 -46794 -59834 +62903 +69095 2 @@ -12629,27 +12956,17 @@ 1 2 -99207 +158707 2 -3 -22271 - - -3 4 -10613 +15195 4 -8 -11224 - - -8 -10421 -3540 +8751 +6262 @@ -12665,12 +12982,12 @@ 1 2 -144518 +177472 2 5 -2337 +2692 @@ -12680,15 +12997,15 @@ typerefs -427553 +349451 id -427553 +349451 name -64947 +79294 @@ -12702,7 +13019,7 @@ 1 2 -427553 +349451 @@ -12718,22 +13035,17 @@ 1 2 -47720 +69433 2 3 -8138 +5934 3 -5 -5295 - - -5 -36269 -3794 +26887 +3927 @@ -12743,15 +13055,15 @@ typeref_type -415976 +343625 id -415976 +343625 typeId -415976 +343625 @@ -12765,7 +13077,7 @@ 1 2 -415976 +343625 @@ -12781,7 +13093,7 @@ 1 2 -415976 +343625 @@ -12791,11 +13103,11 @@ array_element_type -7951 +7961 array -7951 +7961 dimension @@ -12807,7 +13119,7 @@ element -7930 +7932 @@ -12821,7 +13133,7 @@ 1 2 -7951 +7961 @@ -12837,7 +13149,7 @@ 1 2 -7951 +7961 @@ -12853,7 +13165,7 @@ 1 2 -7951 +7961 @@ -12867,18 +13179,18 @@ 12 -1 -2 +2 +3 1 -28 -29 +49 +50 1 -7922 -7923 +7910 +7911 1 @@ -12919,18 +13231,18 @@ 12 -1 -2 +2 +3 1 -27 -28 +48 +49 1 -7902 -7903 +7882 +7883 1 @@ -12950,18 +13262,18 @@ 1 -6 -7 +10 +11 1 -22 -23 +24 +25 1 -7922 -7923 +7926 +7927 1 @@ -13007,18 +13319,18 @@ 1 -6 -7 +10 +11 1 -22 -23 +24 +25 1 -7922 -7923 +7926 +7927 1 @@ -13035,12 +13347,12 @@ 1 2 -7913 +7908 2 5 -17 +24 @@ -13056,7 +13368,7 @@ 1 2 -7930 +7932 @@ -13072,12 +13384,12 @@ 1 2 -7913 +7908 2 5 -17 +24 @@ -13087,15 +13399,15 @@ nullable_underlying_type -2027 +1382 nullable -2027 +1382 underlying -1490 +1382 @@ -13109,7 +13421,7 @@ 1 2 -2027 +1382 @@ -13125,22 +13437,7 @@ 1 2 -1132 - - -2 -3 -205 - - -3 -4 -138 - - -4 -7 -15 +1382 @@ -13150,15 +13447,15 @@ pointer_referent_type -272 +383 pointer -272 +383 referent -272 +383 @@ -13172,7 +13469,7 @@ 1 2 -272 +383 @@ -13188,7 +13485,7 @@ 1 2 -272 +383 @@ -13198,11 +13495,11 @@ enum_underlying_type -8356 +8079 enum_id -8356 +8079 underlying_type_id @@ -13220,7 +13517,7 @@ 1 2 -8356 +8079 @@ -13234,13 +13531,13 @@ 12 -6 -7 +5 +6 1 -8 -9 +6 +7 1 @@ -13249,28 +13546,28 @@ 1 +41 +42 +1 + + 82 83 1 -111 -112 +289 +290 1 -274 -275 +392 +393 1 -404 -405 -1 - - -7455 -7456 +7248 +7249 1 @@ -13281,15 +13578,15 @@ delegate_return_type -49285 +40602 delegate_id -49285 +40602 return_type_id -21520 +17705 @@ -13303,7 +13600,7 @@ 1 2 -49285 +40602 @@ -13319,17 +13616,17 @@ 1 2 -19160 +16003 2 4 -1772 +1360 4 -7319 -588 +7208 +342 @@ -13339,15 +13636,15 @@ extend -507096 +206708 sub -507096 +206708 super -12966 +10856 @@ -13361,7 +13658,7 @@ 1 2 -507096 +206708 @@ -13377,32 +13674,32 @@ 1 2 -7018 +6157 2 3 -2596 +2069 3 4 -1035 +789 4 6 -1105 +902 6 -24 -974 +34 +815 -24 -176860 -238 +34 +52181 +124 @@ -13412,15 +13709,15 @@ implement -681583 +501419 sub -206287 +165927 super -152713 +111188 @@ -13434,32 +13731,37 @@ 1 2 -51447 +46744 2 3 -62642 +48255 3 4 -47212 +35908 4 -6 -18296 +5 +9804 -6 -11 -16904 +5 +8 +10322 -11 -44 -9786 +8 +14 +14877 + + +14 +31 +17 @@ -13475,32 +13777,32 @@ 1 2 -67731 +52605 2 3 -41030 +27664 3 4 -18277 +11959 4 6 -11342 +9609 6 -8 -11679 +10 +8459 -8 -151421 -2654 +10 +113783 +892 @@ -13510,15 +13812,15 @@ type_location -333640 +445714 id -215765 +185891 loc -26226 +52345 @@ -13532,27 +13834,27 @@ 1 2 -148580 +99018 2 3 -38656 +41333 3 4 -10826 +18115 4 -5 -16223 +7 +16473 -5 -104 -1480 +7 +717 +10952 @@ -13568,17 +13870,12 @@ 1 2 -24077 +49945 2 -252 -1968 - - -257 17019 -181 +2400 @@ -13588,15 +13885,15 @@ tuple_underlying_type -2894 +1768 tuple -2894 +1768 struct -1559 +699 @@ -13610,7 +13907,7 @@ 1 2 -2894 +1768 @@ -13626,22 +13923,27 @@ 1 2 -860 +228 2 3 -447 +259 3 4 -143 +123 4 -101 -109 +6 +64 + + +6 +153 +25 @@ -13651,11 +13953,11 @@ tuple_element -9220 +4528 tuple -2476 +1768 index @@ -13663,7 +13965,7 @@ field -9220 +4528 @@ -13677,32 +13979,27 @@ 1 2 -58 +10 2 3 -1593 +1395 3 4 -265 +221 4 -7 -226 +18 +134 -7 -13 -191 - - -13 +18 22 -143 +8 @@ -13718,32 +14015,27 @@ 1 2 -58 +10 2 3 -1593 +1395 3 4 -265 +221 4 -7 -226 +18 +134 -7 -13 -191 - - -13 +18 22 -143 +8 @@ -13757,8 +14049,48 @@ 12 -13 -14 +2 +3 +1 + + +4 +5 +1 + + +6 +7 +1 + + +8 +9 +1 + + +10 +11 +1 + + +12 +13 +1 + + +14 +15 +1 + + +18 +19 +1 + + +22 +23 1 @@ -13767,13 +14099,28 @@ 1 -39 -40 +32 +33 1 -52 -53 +36 +37 +1 + + +40 +41 +1 + + +47 +48 +1 + + +55 +56 1 @@ -13782,83 +14129,28 @@ 1 -78 -79 +100 +101 1 -91 -92 +142 +143 1 -117 -118 +363 +364 1 -143 -144 +1758 +1759 1 -169 -170 -1 - - -197 -198 -1 - - -223 -224 -1 - - -249 -250 -1 - - -283 -284 -1 - - -334 -335 -1 - - -387 -388 -1 - - -475 -476 -1 - - -560 -561 -1 - - -825 -826 -1 - - -2418 -2419 -1 - - -2476 -2477 +1768 +1769 1 @@ -13873,8 +14165,48 @@ 12 -13 -14 +2 +3 +1 + + +4 +5 +1 + + +6 +7 +1 + + +8 +9 +1 + + +10 +11 +1 + + +12 +13 +1 + + +14 +15 +1 + + +18 +19 +1 + + +22 +23 1 @@ -13883,13 +14215,28 @@ 1 -39 -40 +32 +33 1 -52 -53 +36 +37 +1 + + +40 +41 +1 + + +47 +48 +1 + + +55 +56 1 @@ -13898,83 +14245,28 @@ 1 -78 -79 +100 +101 1 -91 -92 +142 +143 1 -117 -118 +363 +364 1 -143 -144 +1758 +1759 1 -169 -170 -1 - - -197 -198 -1 - - -223 -224 -1 - - -249 -250 -1 - - -283 -284 -1 - - -334 -335 -1 - - -387 -388 -1 - - -475 -476 -1 - - -560 -561 -1 - - -825 -826 -1 - - -2418 -2419 -1 - - -2476 -2477 +1768 +1769 1 @@ -13991,7 +14283,7 @@ 1 2 -9220 +4528 @@ -14007,7 +14299,7 @@ 1 2 -9220 +4528 @@ -14017,19 +14309,19 @@ attributes -120784 +152979 id -120784 +152979 type_id -559 +468 target -67938 +78814 @@ -14043,7 +14335,7 @@ 1 2 -120784 +152979 @@ -14059,7 +14351,7 @@ 1 2 -120784 +152979 @@ -14075,62 +14367,62 @@ 1 2 -90 +71 2 3 -67 +52 3 4 -30 +28 4 6 -48 +42 6 -10 -50 +9 +36 -10 -15 -46 +9 +14 +36 -15 -21 -44 +14 +23 +36 -21 -40 -43 +23 +45 +36 -40 -67 -42 +45 +81 +37 -67 -114 -42 +86 +205 +37 -114 -488 -42 +217 +1059 +39 -509 +1079 49629 -15 +18 @@ -14146,62 +14438,57 @@ 1 2 -111 +93 2 3 -66 +51 3 4 -30 +32 4 6 -40 +35 6 9 -43 +39 9 -14 -42 +16 +38 -14 -20 -44 +16 +28 +36 -20 -31 -42 +28 +56 +36 -31 -59 -42 +56 +121 +36 -59 -101 -42 +124 +417 +38 -103 -343 -42 - - -365 -49629 -15 +421 +49626 +34 @@ -14217,22 +14504,22 @@ 1 2 -33353 +40545 2 3 -25919 +28536 3 4 -6776 +7103 4 -853 -1890 +2518 +2630 @@ -14248,22 +14535,22 @@ 1 2 -33726 +42542 2 3 -26581 +28029 3 4 -6618 +6770 4 -14 -1013 +16 +1473 @@ -14273,15 +14560,15 @@ attribute_location -231497 +295887 id -120784 +152979 loc -119045 +150274 @@ -14300,7 +14587,7 @@ 2 3 -110713 +142908 @@ -14316,12 +14603,12 @@ 1 2 -117698 +147783 2 33350 -1347 +2491 @@ -14331,19 +14618,19 @@ type_mention -1477122 +2269573 id -1477122 +2269573 type_id -40955 +62260 parent -1403992 +2098317 @@ -14357,7 +14644,7 @@ 1 2 -1477122 +2269573 @@ -14373,7 +14660,7 @@ 1 2 -1477122 +2269573 @@ -14389,47 +14676,47 @@ 1 2 -11444 +16389 2 3 -8616 +12921 3 4 -3498 +5673 4 5 -3051 +4952 5 7 -3038 +4946 7 -12 -3491 +11 +4873 -12 -24 -3193 +11 +21 +4739 -24 -80 -3077 +21 +62 +4682 -80 -112680 -1547 +62 +170762 +3085 @@ -14445,47 +14732,47 @@ 1 2 -12381 +19486 2 3 -8459 +12123 3 4 -3612 +5422 4 5 -2990 +4489 5 7 -2899 +4628 7 12 -3354 +5228 12 25 -3238 +4788 25 -125 -3073 +127 +4672 -125 -109603 -949 +127 +157226 +1424 @@ -14501,12 +14788,12 @@ 1 2 -1372976 +1990082 2 953 -31016 +108235 @@ -14522,12 +14809,12 @@ 1 2 -1384839 +2068929 2 29 -19153 +29388 @@ -14537,15 +14824,15 @@ type_mention_location -1477122 +2269573 id -1477122 +2269573 loc -1361596 +2163726 @@ -14559,7 +14846,7 @@ 1 2 -1477122 +2269573 @@ -14575,12 +14862,12 @@ 1 2 -1316306 +2129500 2 -198 -45290 +227 +34226 @@ -14590,15 +14877,15 @@ type_annotation -60856 +45915 id -60732 +45915 annotation -5 +3 @@ -14612,12 +14899,7 @@ 1 2 -60608 - - -2 -3 -124 +45915 @@ -14631,28 +14913,18 @@ 12 -105 -106 +1956 +1957 1 -1664 -1665 +13501 +13502 1 -13118 -13119 -1 - - -14761 -14762 -1 - - -31208 -31209 +30458 +30459 1 @@ -14662,26 +14934,22 @@ -type_argument_annotation -374019 +nullability +116 -constructedgeneric -279883 +nullability +116 -position -21 - - -annotation -2 +kind +3 -constructedgeneric -position +nullability +kind 12 @@ -14689,25 +14957,107 @@ 1 2 -217898 +116 + + + + + + +kind +nullability + + +12 + + +11 +12 +1 + + +47 +48 +1 + + +58 +59 +1 + + + + + + + + +nullability_member +381 + + +nullability +113 + + +index +17 + + +child +25 + + + + +nullability +index + + +12 + + +1 +2 +34 2 3 -50067 +33 3 -22 -11918 +4 +14 + + +4 +5 +10 + + +5 +8 +10 + + +8 +15 +9 + + +15 +18 +3 -constructedgeneric -annotation +nullability +child 12 @@ -14715,112 +15065,112 @@ 1 2 -279477 +50 2 3 -406 +54 + + +3 +4 +9 -position -constructedgeneric +index +nullability 12 +1 +2 +1 + + +2 +3 +1 + + +3 +4 +1 + + +4 +5 +1 + + 5 6 -4 - - -95 -96 1 -234 -235 +6 +7 1 -373 -374 +7 +8 1 -512 -513 +8 +9 1 -651 -652 +9 +10 1 -791 -792 +12 +13 1 -932 -933 +14 +15 1 -1077 -1078 +18 +19 1 -1222 -1223 +22 +23 1 -2100 -2101 +32 +33 1 -2364 -2365 +46 +47 1 -2679 -2680 +79 +80 1 -3197 -3198 -1 - - -3986 -3987 -1 - - -11918 -11919 -1 - - -62003 -62004 -1 - - -279865 -279866 +113 +114 1 @@ -14828,8 +15178,8 @@ -position -annotation +index +child 12 @@ -14837,32 +15187,36 @@ 1 2 -4 +1 2 3 -17 +9 - - - - - -annotation -constructedgeneric - - -12 - -939 -940 +3 +4 +2 + + +4 +5 1 -279350 -279351 +5 +6 +2 + + +9 +10 +1 + + +25 +26 1 @@ -14870,21 +15224,190 @@ -annotation -position +child +nullability 12 -17 +1 +2 +14 + + +3 +4 +1 + + +4 +5 +2 + + +5 +6 +2 + + +6 +7 +2 + + +23 +27 +2 + + +28 +62 +2 + + + + + + +child +index + + +12 + + +1 +2 +16 + + +2 +3 +3 + + +3 +4 +2 + + +5 +8 +2 + + +16 18 -1 +2 + + + + + + + + +type_nullability +243176 + + +id +239388 + + +nullability +107 + + + + +id +nullability + + +12 + + +1 +2 +235606 -21 -22 -1 +2 +4 +3782 + + + + + + +nullability +id + + +12 + + +1 +2 +23 + + +2 +3 +7 + + +3 +4 +4 + + +4 +6 +9 + + +6 +7 +9 + + +7 +10 +5 + + +10 +15 +9 + + +19 +31 +9 + + +40 +106 +9 + + +119 +481 +9 + + +540 +3383 +9 + + +14434 +154277 +5 @@ -14894,33 +15417,33 @@ is_generic -71108 +60403 id -71108 +60403 is_constructed -301218 +237565 id -301218 +237565 type_parameters -80382 +58092 id -80382 +58092 index @@ -14928,7 +15451,7 @@ generic_id -48687 +37990 variance @@ -14946,7 +15469,7 @@ 1 2 -80382 +58092 @@ -14962,7 +15485,7 @@ 1 2 -80382 +58092 @@ -14978,7 +15501,7 @@ 1 2 -80382 +58092 @@ -14992,48 +15515,48 @@ 12 -4 -5 +1 +2 16 -6 -9 +2 +4 3 -31 -76 +7 +15 3 -99 -315 +18 +150 3 -498 -865 +270 +511 3 -1049 -1425 +632 +887 3 -1613 -2054 +1013 +1291 3 -2301 -2958 +1461 +1881 3 -3671 -48681 +2310 +37991 3 @@ -15048,48 +15571,48 @@ 12 -4 -5 +1 +2 16 -6 -9 +2 +4 3 -31 -76 +7 +15 3 -99 -315 +18 +150 3 -498 -865 +270 +511 3 -1049 -1425 +632 +887 3 -1613 -2054 +1013 +1291 3 -2301 -2958 +1461 +1881 3 -3671 -48688 +2310 +37991 3 @@ -15132,22 +15655,17 @@ 1 2 -40503 +32308 2 3 -4513 +3372 3 -22 -3663 - - -23 41 -8 +2310 @@ -15163,22 +15681,17 @@ 1 2 -40503 +32308 2 3 -4513 +3372 3 -22 -3663 - - -23 41 -8 +2310 @@ -15194,12 +15707,12 @@ 1 2 -48578 +37946 2 3 -109 +44 @@ -15213,18 +15726,18 @@ 12 -161 -162 +63 +64 1 -1243 -1244 +312 +313 1 -78971 -78972 +57717 +57718 1 @@ -15265,18 +15778,18 @@ 12 -160 -161 +61 +62 1 -226 -227 +71 +72 1 -48410 -48411 +37902 +37903 1 @@ -15287,11 +15800,11 @@ type_arguments -399681 +312757 id -109145 +87949 index @@ -15299,7 +15812,7 @@ constructed_id -301218 +237565 @@ -15313,17 +15826,17 @@ 1 2 -86914 +68801 2 3 -21432 +18339 3 18 -799 +809 @@ -15339,32 +15852,37 @@ 1 2 -52585 +44933 2 3 -24128 +16977 3 -4 -7419 +5 +7885 -4 +5 7 -9307 +4344 7 -10 -8716 +8 +6689 -10 -8571 -6990 +8 +28 +6603 + + +28 +7377 +518 @@ -15378,93 +15896,93 @@ 12 -5 -6 +2 +3 4 -38 -39 +32 +33 1 -176 -177 +146 +147 1 -314 -315 +259 +260 1 -452 -453 +372 +373 1 -590 -591 +485 +486 1 -729 -730 +600 +601 1 -868 -869 +716 +717 1 -1013 -1014 +836 +837 1 -1156 -1157 +953 +954 1 -1951 -1952 +1185 +1186 1 -2028 -2029 +1279 +1280 1 -2192 -2193 +1436 +1437 1 -2499 -2500 +1645 +1646 1 -2952 -2953 +1998 +1999 1 -9725 -9726 +7659 +7660 1 -25413 -25414 +21869 +21870 1 -80771 -80772 +67117 +67118 1 @@ -15479,93 +15997,93 @@ 12 -5 -6 +2 +3 4 -95 -96 +77 +78 1 -234 -235 +192 +193 1 -373 -374 +307 +308 1 -512 -513 +422 +423 1 -651 -652 +537 +538 1 -791 -792 +654 +655 1 -932 -933 +773 +774 1 -1077 -1078 +894 +895 1 -1222 -1223 +1014 +1015 1 -2100 -2101 +1253 +1254 1 -2364 -2365 +1404 +1405 1 -2683 -2684 +1616 +1617 1 -3208 -3209 +1958 +1959 1 -4032 -4033 +2634 +2635 1 -12237 -12238 +9388 +9389 1 -65932 -65933 +52061 +52062 1 -301218 -301219 +237565 +237566 1 @@ -15582,17 +16100,17 @@ 1 2 -236948 +186726 2 3 -53158 +42264 3 22 -11112 +8575 @@ -15608,17 +16126,17 @@ 1 2 -235286 +185504 2 3 -53695 +42673 3 22 -12237 +9388 @@ -15628,15 +16146,15 @@ constructed_generic -301218 +237565 constructed -301218 +237565 generic -5869 +5449 @@ -15650,7 +16168,7 @@ 1 2 -301218 +237565 @@ -15666,42 +16184,37 @@ 1 2 -2045 +2207 2 3 -1117 +1075 3 4 -526 +506 4 -5 -360 +6 +479 -5 -8 -460 +6 +11 +442 -8 -15 -483 +11 +33 +409 -15 -46 -451 - - -46 -31135 -427 +33 +21877 +331 @@ -15711,15 +16224,15 @@ type_parameter_constraints -330908 +389563 id -330908 +389563 param_id -80545 +58090 @@ -15733,7 +16246,7 @@ 1 2 -330908 +389563 @@ -15749,27 +16262,32 @@ 1 2 -55069 +32353 2 3 -12393 +9062 3 -5 -6822 +4 +5333 -5 -167 -6041 +4 +7 +4581 -171 -7522 -220 +7 +17 +4653 + + +17 +10899 +2108 @@ -15815,15 +16333,15 @@ general_type_parameter_constraints -46646 +49753 id -46610 +49483 kind -4 +5 @@ -15837,12 +16355,12 @@ 1 2 -46574 +49213 2 3 -36 +270 @@ -15856,23 +16374,28 @@ 12 -2 -3 +60 +61 1 -318 -319 +176 +177 1 -3083 -3084 +372 +373 1 -43243 -43244 +4647 +4648 +1 + + +44498 +44499 1 @@ -15883,15 +16406,15 @@ specific_type_parameter_constraints -39729 +41475 id -39242 +40987 base_id -2954 +2496 @@ -15905,12 +16428,12 @@ 1 2 -38792 +40536 2 5 -450 +451 @@ -15926,42 +16449,47 @@ 1 2 -1312 +951 2 3 -349 +329 3 4 -270 +224 4 -5 -223 +6 +231 -5 +6 8 -223 +172 8 -14 -237 +12 +204 -14 -38 -223 +12 +25 +191 -38 -5247 -117 +25 +671 +188 + + +947 +6057 +6 @@ -15970,20 +16498,20 @@ -specific_type_parameter_annotation -6 +specific_type_parameter_nullability +305 id -6 +305 base_id -3 +24 -annotation -1 +nullability +5 @@ -15997,7 +16525,7 @@ 1 2 -6 +305 @@ -16005,7 +16533,7 @@ id -annotation +nullability 12 @@ -16013,7 +16541,7 @@ 1 2 -6 +305 @@ -16029,59 +16557,129 @@ 1 2 +1 + + +2 +3 +7 + + +3 +4 +2 + + +4 +5 +2 + + +5 +6 +5 + + +6 +8 +2 + + +8 +9 +1 + + +34 +35 +2 + + +60 +103 +2 + + + + + + +base_id +nullability + + +12 + + +1 +2 +21 + + +2 +3 +3 + + + + + + +nullability +id + + +12 + + +2 +3 +1 + + +4 +5 +1 + + +5 +6 +1 + + +6 +7 +1 + + +288 +289 +1 + + + + + + +nullability +base_id + + +12 + + +1 +2 2 -4 -5 -1 +2 +3 +2 - - - - - -base_id -annotation - - -12 - -1 -2 -3 - - - - - - -annotation -id - - -12 - - -6 -7 -1 - - - - - - -annotation -base_id - - -12 - - -3 -4 +21 +22 1 @@ -16140,11 +16738,11 @@ has_modifiers -3869176 +3644548 id -2587027 +2423233 mod_id @@ -16162,17 +16760,17 @@ 1 2 -1372230 +1294970 2 3 -1147995 +1036528 3 -5 -66802 +6 +91735 @@ -16186,93 +16784,93 @@ 12 -71 -72 +474 +475 1 -150 -151 +595 +596 1 -453 -454 +858 +859 1 -568 -569 +1986 +1987 1 -1224 -1225 +3632 +3633 1 -3007 -3008 +9430 +9431 1 -21791 -21792 +22226 +22227 1 -40903 -40904 +29654 +29655 1 -52292 -52293 +53969 +53970 1 -85916 -85917 +70891 +70892 1 -122762 -122763 +106769 +106770 1 -166812 -166813 +143771 +143772 1 -168050 -168051 +147924 +147925 1 -201700 -201701 +199833 +199834 1 -226436 -226437 +247611 +247612 1 -342644 -342645 +373610 +373611 1 -435003 -435004 +443150 +443151 1 -1999394 -1999395 +1788165 +1788166 1 @@ -16283,26 +16881,26 @@ compiler_generated -54510 +78129 id -54510 +78129 exprorstmt_name -201 +1656 parent_id -201 +1656 name -44 +221 @@ -16316,7 +16914,7 @@ 1 2 -201 +1656 @@ -16337,31 +16935,41 @@ 2 3 -18 +75 3 4 -4 +36 4 +5 +31 + + +5 6 -4 +14 6 -7 -3 +8 +18 8 13 -4 +19 -14 -38 +13 +85 +17 + + +111 +176 3 @@ -16372,19 +16980,19 @@ nested_types -57997 +57581 id -57997 +57581 declaring_type_id -21939 +18925 unbound_id -37006 +36015 @@ -16398,7 +17006,7 @@ 1 2 -57997 +57581 @@ -16414,7 +17022,7 @@ 1 2 -57997 +57581 @@ -16430,27 +17038,32 @@ 1 2 -11856 +9127 2 3 -3440 +2917 3 4 -3479 +3625 4 -7 -1715 +6 +1378 -7 +6 +14 +1452 + + +14 592 -1449 +426 @@ -16466,27 +17079,32 @@ 1 2 -11883 +9216 2 3 -3455 +2893 3 4 -3471 +3605 4 -7 -1744 +6 +1380 -7 +6 +14 +1427 + + +14 592 -1386 +404 @@ -16502,12 +17120,12 @@ 1 2 -35043 +34018 2 -1139 -1963 +1347 +1997 @@ -16523,12 +17141,12 @@ 1 2 -35366 +34383 2 -1139 -1640 +1347 +1632 @@ -16538,27 +17156,27 @@ properties -277986 +268986 id -277986 +268986 name -43605 +58896 declaring_type_id -67202 +66590 type_id -29120 +27500 unbound_id -184077 +174793 @@ -16572,7 +17190,7 @@ 1 2 -277986 +268986 @@ -16588,7 +17206,7 @@ 1 2 -277986 +268986 @@ -16604,7 +17222,7 @@ 1 2 -277986 +268986 @@ -16620,7 +17238,7 @@ 1 2 -277986 +268986 @@ -16636,32 +17254,27 @@ 1 2 -27030 +37823 2 3 -6251 +11142 3 -4 -2804 +5 +4879 -4 -7 -3533 +5 +31 +4418 -7 -35 -3296 - - -35 -21502 -691 +31 +20332 +634 @@ -16677,32 +17290,27 @@ 1 2 -27030 +37823 2 3 -6279 +11174 3 -4 -2819 +5 +4870 -4 -7 -3498 +5 +32 +4435 -7 -35 -3295 - - -35 -18336 -684 +32 +18333 +594 @@ -16718,22 +17326,17 @@ 1 2 -36738 +53616 2 -3 -2855 +6 +4499 -3 -8 -3321 - - -8 -3061 -691 +6 +3187 +781 @@ -16749,32 +17352,27 @@ 1 2 -27278 +38193 2 3 -6314 +11213 3 -4 -2818 +5 +4821 -4 -7 -3458 +5 +55 +4419 -7 -44 -3282 - - -44 -5880 -455 +55 +5009 +250 @@ -16790,42 +17388,37 @@ 1 2 -21589 +21446 2 3 -20521 +21133 3 4 -6501 +5984 4 5 -4298 +4091 5 7 -4082 +3967 7 12 -5068 +5094 12 -59 -5045 - - -59 -3766 -98 +6356 +4875 @@ -16841,37 +17434,37 @@ 1 2 -24075 +23866 2 3 -18654 +18876 3 4 -5987 +5924 4 5 -4254 +4042 5 7 -5482 +5519 7 11 -5654 +5515 11 -3766 -3096 +6356 +2848 @@ -16887,32 +17480,32 @@ 1 2 -24811 +25457 2 3 -22293 +22110 3 4 -7975 +7831 4 5 -4735 +4467 5 -11 -5410 +12 +6097 -11 -54 -1978 +12 +51 +628 @@ -16928,42 +17521,37 @@ 1 2 -21589 +21446 2 3 -20521 +21133 3 4 -6501 +5984 4 5 -4298 +4091 5 7 -4082 +3967 7 12 -5068 +5094 12 -59 -5045 - - -59 -3766 -98 +6356 +4875 @@ -16979,32 +17567,27 @@ 1 2 -16756 +15184 2 3 -5933 +6965 3 4 -1876 +1444 4 7 -2274 +2106 7 -148 -2184 - - -148 -62273 -97 +55172 +1801 @@ -17020,22 +17603,17 @@ 1 2 -23964 +23189 2 3 -2857 +2495 3 -33 -2184 - - -33 -11367 -115 +19160 +1816 @@ -17051,27 +17629,27 @@ 1 2 -17446 +15664 2 3 -5749 +6934 3 4 -1941 +1415 4 8 -2243 +2095 8 -25633 -1741 +25360 +1392 @@ -17087,27 +17665,27 @@ 1 2 -16893 +15350 2 3 -6155 +7099 3 4 -2003 +1492 4 8 -2323 +2176 8 -32140 -1746 +37193 +1383 @@ -17123,12 +17701,12 @@ 1 2 -180296 +172012 2 -5587 -3781 +5604 +2781 @@ -17144,7 +17722,7 @@ 1 2 -184077 +174793 @@ -17160,12 +17738,12 @@ 1 2 -180296 +172012 2 -5587 -3781 +5604 +2781 @@ -17181,12 +17759,12 @@ 1 2 -180871 +173873 2 -1130 -3206 +1060 +920 @@ -17196,15 +17774,15 @@ property_location -412445 +621543 id -274983 +268771 loc -32996 +73027 @@ -17218,27 +17796,32 @@ 1 2 -199797 +137047 2 3 -39513 +73922 3 4 -10699 +19805 4 -5 -24258 +6 +13360 -5 -28 -716 +6 +15 +20275 + + +15 +257 +4362 @@ -17254,12 +17837,12 @@ 1 2 -31248 +70153 2 -29600 -1748 +29742 +2874 @@ -17269,11 +17852,11 @@ indexers -23786 +25314 id -23786 +25314 name @@ -17281,15 +17864,15 @@ declaring_type_id -17060 +18446 type_id -4609 +5634 unbound_id -2432 +2521 @@ -17303,7 +17886,7 @@ 1 2 -23786 +25314 @@ -17319,7 +17902,7 @@ 1 2 -23786 +25314 @@ -17335,7 +17918,7 @@ 1 2 -23786 +25314 @@ -17351,7 +17934,7 @@ 1 2 -23786 +25314 @@ -17372,21 +17955,16 @@ 2 3 +2 + + +6 +7 1 -7 -8 -1 - - -14 -15 -1 - - -23758 -23759 +25301 +25302 1 @@ -17408,21 +17986,16 @@ 2 3 +2 + + +4 +5 1 -7 -8 -1 - - -8 -9 -1 - - -17043 -17044 +18438 +18439 1 @@ -17442,13 +18015,13 @@ 5 -8 -9 +4 +5 1 -4599 -4600 +5631 +5632 1 @@ -17470,204 +18043,189 @@ 2 3 -1 - - -7 -8 -1 - - -14 -15 -1 - - -2406 -2407 -1 - - - - - - -declaring_type_id -id - - -12 - - -1 -2 -12885 - - -2 -3 -2695 - - -3 -5 -1477 - - -6 -7 -3 - - - - - - -declaring_type_id -name - - -12 - - -1 -2 -17057 - - -2 -3 -3 - - - - - - -declaring_type_id -type_id - - -12 - - -1 -2 -13102 - - -2 -3 -3957 - - -4 -5 -1 - - - - - - -declaring_type_id -unbound_id - - -12 - - -1 -2 -12885 - - -2 -3 -2695 - - -3 -5 -1477 - - -6 -7 -3 - - - - - - -type_id -id - - -12 - - -1 -2 -657 - - -2 -3 -995 - - -3 -4 -1279 - - -4 -5 -262 - - -5 -6 -547 - - -6 -7 -386 - - -7 -13 -366 - - -13 -4907 -117 - - - - - - -type_id -name - - -12 - - -1 -2 -4607 - - -2 -4 2 + +6 +7 +1 + + +2508 +2509 +1 + + + + + + +declaring_type_id +id + + +12 + + +1 +2 +14068 + + +2 +3 +2930 + + +3 +5 +1421 + + +5 +7 +27 + + + + + + +declaring_type_id +name + + +12 + + +1 +2 +18443 + + +2 +3 +3 + + + + + + +declaring_type_id +type_id + + +12 + + +1 +2 +14223 + + +2 +3 +4223 + + + + + + +declaring_type_id +unbound_id + + +12 + + +1 +2 +14068 + + +2 +3 +2930 + + +3 +5 +1421 + + +5 +7 +27 + + + + + + +type_id +id + + +12 + + +1 +2 +739 + + +2 +3 +1537 + + +3 +4 +1740 + + +4 +5 +261 + + +5 +6 +630 + + +6 +7 +435 + + +7 +5790 +292 + + + + + + +type_id +name + + +12 + + +1 +2 +5629 + + +2 +4 +5 + @@ -17682,32 +18240,32 @@ 1 2 -772 +786 2 3 -900 +1495 3 4 -1764 +2375 4 5 -478 +550 5 -7 -351 +32 +423 -7 -4785 -344 +44 +5703 +5 @@ -17723,37 +18281,37 @@ 1 2 -667 +739 2 3 -1151 +1537 3 4 -1329 +1776 4 5 -193 +265 5 6 -582 +643 6 7 -397 +425 7 -993 -290 +1531 +249 @@ -17769,17 +18327,12 @@ 1 2 -2187 +2371 2 -28 -183 - - -28 -3834 -62 +3967 +150 @@ -17795,7 +18348,7 @@ 1 2 -2432 +2521 @@ -17811,17 +18364,12 @@ 1 2 -2187 +2371 2 -28 -183 - - -28 -3834 -62 +3967 +150 @@ -17837,12 +18385,12 @@ 1 2 -2258 +2407 2 -3011 -174 +3967 +114 @@ -17852,15 +18400,15 @@ indexer_location -27388 +40309 id -23784 +25314 loc -427 +1604 @@ -17874,17 +18422,22 @@ 1 2 -21223 +19371 2 3 -1913 +3547 3 -11 -648 +10 +1912 + + +10 +19 +484 @@ -17900,47 +18453,37 @@ 1 2 -168 +1040 2 3 -47 +77 3 4 -32 +72 4 -5 -35 +6 +120 -5 -9 -34 +6 +14 +144 -9 -15 -35 +14 +127 +121 -15 -39 -33 - - -44 -283 -33 - - -283 -6385 -10 +127 +6138 +30 @@ -17950,11 +18493,11 @@ accessors -337094 +336633 id -337094 +336633 kind @@ -17962,15 +18505,15 @@ name -56178 +74791 declaring_member_id -291680 +286717 unbound_id -218777 +211967 @@ -17984,7 +18527,7 @@ 1 2 -337094 +336633 @@ -18000,7 +18543,7 @@ 1 2 -337094 +336633 @@ -18016,7 +18559,7 @@ 1 2 -337094 +336633 @@ -18032,7 +18575,7 @@ 1 2 -337094 +336633 @@ -18046,13 +18589,13 @@ 12 -45608 -45609 +50195 +50196 1 -291486 -291487 +286438 +286439 1 @@ -18067,13 +18610,13 @@ 12 -10798 -10799 +14093 +14094 1 -45380 -45381 +60698 +60699 1 @@ -18088,13 +18631,13 @@ 12 -45249 -45250 +50186 +50187 1 -291486 -291487 +286438 +286439 1 @@ -18109,13 +18652,13 @@ 12 -33261 -33262 +36119 +36120 1 -185516 -185517 +175848 +175849 1 @@ -18132,156 +18675,141 @@ 1 2 -34024 +46914 2 3 -8492 - - -3 -4 -3907 - - -4 -7 -4784 - - -7 -36 -4219 - - -36 -17260 -752 - - - - - - -name -kind - - -12 - - -1 -2 -56178 - - - - - - -name -declaring_member_id - - -12 - - -1 -2 -34058 - - -2 -3 -8490 - - -3 -4 -3887 - - -4 -7 -4784 - - -7 -37 -4237 - - -37 -17260 -722 - - - - - - -name -unbound_id - - -12 - - -1 -2 -34365 - - -2 -3 -8582 - - -3 -4 -3929 - - -4 -7 -4701 - - -7 -58 -4217 - - -58 -3126 -384 - - - - - - -declaring_member_id -id - - -12 - - -1 -2 -246623 - - -2 -3 -44725 +15055 3 5 -332 +6355 + + +5 +29 +5645 + + +29 +17446 +822 + + + + + + +name +kind + + +12 + + +1 +2 +74791 + + + + + + +name +declaring_member_id + + +12 + + +1 +2 +46917 + + +2 +3 +15053 + + +3 +5 +6354 + + +5 +29 +5645 + + +29 +17446 +822 + + + + + + +name +unbound_id + + +12 + + +1 +2 +47440 + + +2 +3 +15185 + + +3 +5 +6280 + + +5 +55 +5613 + + +55 +2297 +273 + + + + + + +declaring_member_id +id + + +12 + + +1 +2 +236810 + + +2 +3 +49898 + + +3 +4 +9 @@ -18297,12 +18825,12 @@ 1 2 -246625 +236810 2 3 -45055 +49907 @@ -18318,12 +18846,12 @@ 1 2 -246625 +236810 2 3 -45055 +49907 @@ -18339,17 +18867,17 @@ 1 2 -246623 +236810 2 3 -44725 +49898 3 -5 -332 +4 +9 @@ -18365,12 +18893,12 @@ 1 2 -214272 +208543 2 -5587 -4505 +5604 +3424 @@ -18386,7 +18914,7 @@ 1 2 -218777 +211967 @@ -18402,7 +18930,7 @@ 1 2 -218777 +211967 @@ -18418,12 +18946,12 @@ 1 2 -214272 +208543 2 -5587 -4505 +5604 +3424 @@ -18433,15 +18961,15 @@ accessor_location -493716 +760991 id -337094 +336633 loc -38581 +87557 @@ -18455,27 +18983,27 @@ 1 2 -250312 +178438 2 3 -46346 +91540 3 4 -12722 +22414 4 -5 -26975 +7 +27767 -5 -28 -739 +7 +257 +16474 @@ -18491,12 +19019,12 @@ 1 2 -36538 +84261 2 -39761 -2043 +38689 +3296 @@ -18506,27 +19034,27 @@ events -6046 +8976 id -6046 +8976 name -3240 +3901 declaring_type_id -1381 +2161 type_id -2048 +2621 unbound_id -5720 +8739 @@ -18540,7 +19068,7 @@ 1 2 -6046 +8976 @@ -18556,7 +19084,7 @@ 1 2 -6046 +8976 @@ -18572,7 +19100,7 @@ 1 2 -6046 +8976 @@ -18588,7 +19116,7 @@ 1 2 -6046 +8976 @@ -18604,22 +19132,27 @@ 1 2 -2526 +2559 2 3 -302 +356 3 -5 -248 +4 +557 -5 -163 -164 +4 +9 +293 + + +9 +148 +136 @@ -18635,22 +19168,22 @@ 1 2 -2526 +2559 2 3 -302 +824 3 -5 -249 +6 +315 -5 -119 -163 +6 +107 +203 @@ -18666,17 +19199,17 @@ 1 2 -2933 +3548 2 5 -261 +304 5 26 -46 +49 @@ -18692,22 +19225,27 @@ 1 2 -2544 +2577 2 3 -298 +351 3 -6 -271 +4 +554 -6 -93 -127 +4 +10 +311 + + +10 +76 +108 @@ -18723,32 +19261,37 @@ 1 2 -701 +877 2 3 -241 +532 3 4 -139 +187 4 5 -79 +172 5 -9 -121 +8 +181 -9 +8 +19 +163 + + +19 465 -100 +49 @@ -18764,32 +19307,32 @@ 1 2 -710 +1091 2 3 -272 +429 3 4 -108 +204 4 -6 -120 +5 +112 -6 -13 -108 +5 +8 +179 -13 +8 465 -63 +146 @@ -18805,135 +19348,140 @@ 1 2 -809 +1345 2 3 -276 +373 3 4 -106 +195 4 -6 -111 - - -6 -181 -79 - - - - - - -declaring_type_id -unbound_id - - -12 - - -1 -2 -701 - - -2 -3 -241 - - -3 -4 -139 - - -4 -5 -79 - - -5 -9 -121 - - -9 -465 -100 - - - - - - -type_id -id - - -12 - - -1 -2 -1222 - - -2 -3 -473 - - -3 -5 -181 - - -5 -29 -154 - - -30 -1024 -18 - - - - - - -type_id -name - - -12 - - -1 -2 -1507 - - -2 -3 -343 - - -3 7 -154 +166 7 -402 -44 +181 +82 + + + + + + +declaring_type_id +unbound_id + + +12 + + +1 +2 +877 + + +2 +3 +532 + + +3 +4 +187 + + +4 +5 +172 + + +5 +8 +181 + + +8 +19 +163 + + +19 +465 +49 + + + + + + +type_id +id + + +12 + + +1 +2 +1063 + + +2 +3 +456 + + +3 +4 +764 + + +4 +7 +204 + + +7 +1070 +134 + + + + + + +type_id +name + + +12 + + +1 +2 +2009 + + +2 +3 +384 + + +3 +9 +197 + + +9 +435 +31 @@ -18949,22 +19497,17 @@ 1 2 -1640 +1456 2 3 -233 +987 3 -9 -156 - - -9 -346 -19 +363 +178 @@ -18980,27 +19523,27 @@ 1 2 -1224 +1065 2 3 -474 +457 3 -5 -181 +4 +763 -5 -31 -155 +4 +7 +206 -31 -1024 -14 +7 +1059 +130 @@ -19016,12 +19559,12 @@ 1 2 -5671 +8689 2 33 -49 +50 @@ -19037,7 +19580,7 @@ 1 2 -5720 +8739 @@ -19053,12 +19596,12 @@ 1 2 -5671 +8689 2 33 -49 +50 @@ -19074,12 +19617,12 @@ 1 2 -5621 +8725 2 26 -99 +14 @@ -19089,15 +19632,15 @@ event_location -7637 +13927 id -5957 +8976 loc -906 +1497 @@ -19111,22 +19654,17 @@ 1 2 -5050 +6948 2 3 -454 +1532 3 -5 -452 - - -8 -9 -1 +19 +496 @@ -19142,27 +19680,22 @@ 1 2 -668 +1123 2 4 -73 +136 4 -12 -68 +13 +126 -12 -32 -69 - - -36 -1532 -28 +13 +2320 +112 @@ -19172,11 +19705,11 @@ event_accessors -12026 +15714 id -12026 +15714 kind @@ -19184,15 +19717,15 @@ name -6534 +7856 declaring_event_id -5924 +7857 unbound_id -11552 +15240 @@ -19206,7 +19739,7 @@ 1 2 -12026 +15714 @@ -19222,7 +19755,7 @@ 1 2 -12026 +15714 @@ -19238,7 +19771,7 @@ 1 2 -12026 +15714 @@ -19254,7 +19787,7 @@ 1 2 -12026 +15714 @@ -19268,8 +19801,8 @@ 12 -6013 -6014 +7857 +7858 2 @@ -19284,8 +19817,8 @@ 12 -3267 -3268 +3928 +3929 2 @@ -19300,8 +19833,8 @@ 12 -5924 -5925 +7857 +7858 2 @@ -19316,8 +19849,8 @@ 12 -5776 -5777 +7620 +7621 2 @@ -19334,100 +19867,100 @@ 1 2 -5098 +5204 2 3 -606 - - -3 -5 -502 - - -5 -110 -328 - - - - - - -name -kind - - -12 - - -1 -2 -6534 - - - - - - -name -declaring_event_id - - -12 - - -1 -2 -5106 - - -2 -3 -614 - - -3 -5 -496 - - -5 -105 -318 - - - - - - -name -unbound_id - - -12 - - -1 -2 -5134 - - -2 -3 -600 +1630 3 6 -542 +616 6 -72 -258 +97 +406 + + + + + + +name +kind + + +12 + + +1 +2 +7856 + + + + + + +name +declaring_event_id + + +12 + + +1 +2 +5204 + + +2 +3 +1630 + + +3 +6 +616 + + +6 +97 +406 + + + + + + +name +unbound_id + + +12 + + +1 +2 +5240 + + +2 +3 +1622 + + +3 +6 +596 + + +6 +58 +398 @@ -19443,12 +19976,7 @@ 2 3 -5836 - - -4 -7 -88 +7857 @@ -19464,7 +19992,7 @@ 2 3 -5924 +7857 @@ -19480,7 +20008,7 @@ 2 3 -5924 +7857 @@ -19496,12 +20024,7 @@ 2 3 -5836 - - -4 -7 -88 +7857 @@ -19517,12 +20040,12 @@ 1 2 -11454 +15140 2 33 -98 +100 @@ -19538,7 +20061,7 @@ 1 2 -11552 +15240 @@ -19554,7 +20077,7 @@ 1 2 -11552 +15240 @@ -19570,12 +20093,12 @@ 1 2 -11454 +15140 2 33 -98 +100 @@ -19585,15 +20108,15 @@ event_accessor_location -15212 +23116 id -12026 +15714 loc -951 +1813 @@ -19607,17 +20130,17 @@ 1 2 -10234 +14122 2 -3 -932 +8 +1180 -3 -5 -860 +8 +19 +412 @@ -19633,32 +20156,27 @@ 1 2 -92 +648 2 3 -624 +798 4 7 -74 +136 8 -27 -73 +29 +137 -28 -107 -72 - - -114 -3063 -16 +30 +4639 +94 @@ -19668,11 +20186,11 @@ operators -14355 +13320 id -14355 +13320 name @@ -19684,15 +20202,15 @@ declaring_type_id -4406 +5147 type_id -1784 +1724 unbound_id -7361 +7036 @@ -19706,7 +20224,7 @@ 1 2 -14355 +13320 @@ -19722,7 +20240,7 @@ 1 2 -14355 +13320 @@ -19738,7 +20256,7 @@ 1 2 -14355 +13320 @@ -19754,7 +20272,7 @@ 1 2 -14355 +13320 @@ -19770,7 +20288,7 @@ 1 2 -14355 +13320 @@ -19784,68 +20302,68 @@ 12 -6 -7 +4 +5 2 -8 -9 -3 +5 +6 +2 -11 +6 +12 +2 + + +12 18 2 -23 -25 +20 +30 2 -30 -68 +31 +53 2 -73 -96 +94 +127 2 -151 -152 -1 - - -152 -153 +128 +134 2 -153 -157 +142 +168 2 -169 -172 +205 +215 2 -189 -221 +332 +346 2 -1456 -2125 +723 +1751 2 -4406 -4478 +4233 +4530 2 @@ -19876,75 +20394,70 @@ 12 -6 -7 +4 +5 2 -8 -9 -3 +5 +6 +2 -11 +6 +12 +2 + + +12 18 2 -23 -25 +20 +30 2 -30 -31 -1 - - -67 -68 +31 +36 2 -73 -82 +47 +119 +2 + + +124 +127 2 129 -130 -1 - - -136 -137 +142 2 -137 -141 +201 +211 2 -143 -188 +330 +344 2 -218 -678 +432 +1105 2 -1335 -2996 +3261 +3558 2 - -3066 -3067 -1 - @@ -19962,60 +20475,60 @@ 2 -4 -5 +2 +3 6 +3 +4 +1 + + 5 6 -1 - - -8 -9 2 11 -18 +13 2 -23 -25 +17 +21 2 -30 -31 +29 +32 +2 + + +35 +48 +2 + + +103 +127 +2 + + +141 +330 +2 + + +342 +435 +2 + + +882 +883 1 - -67 -68 -2 - - -73 -82 -2 - - -119 -144 -2 - - -186 -218 -2 - - -671 -970 -2 - @@ -20028,70 +20541,75 @@ 12 -6 -7 +4 +5 2 -8 -9 -3 +5 +6 +2 -11 +6 +12 +2 + + +12 +13 +1 + + +17 18 2 -23 -25 +28 +30 2 -30 -68 +49 +86 2 -73 -96 +123 +129 2 -151 -152 +133 +140 +2 + + +164 +206 +2 + + +214 +330 +2 + + +342 +380 +2 + + +488 +1913 +2 + + +2208 +2209 1 - -152 -153 -2 - - -153 -157 -2 - - -169 -172 -2 - - -189 -221 -2 - - -977 -1079 -2 - - -1673 -1745 -2 - @@ -20104,63 +20622,63 @@ 12 +4 +5 +2 + + +5 +6 +2 + + 6 -7 +13 2 -8 -9 -3 - - -11 -24 +17 +21 2 -24 -31 +29 +53 2 -73 -96 +94 +127 2 -151 -152 -1 - - -152 -153 +128 +134 2 -153 -157 +173 +179 2 -188 -190 +205 +215 2 -220 -237 +332 +346 2 -1456 -2125 +723 +1751 2 -4406 -4478 +4233 +4530 2 @@ -20196,129 +20714,129 @@ 12 -6 -7 -2 - - -8 -9 -3 - - -11 -24 -2 - - -24 -31 -2 - - -67 -74 -2 - - -81 -132 -2 - - -136 -137 -2 - - -137 -141 -2 - - -143 -188 -2 - - -218 -678 -2 - - -1335 -2996 -2 - - -3066 -3067 -1 - - - - - - -symbol -type_id - - -12 - - -1 -2 -2 - - 4 5 -6 +2 5 6 +2 + + +6 +13 +2 + + +17 +21 +2 + + +29 +36 +2 + + +47 +121 +2 + + +124 +127 +2 + + +129 +142 +2 + + +201 +211 +2 + + +330 +344 +2 + + +432 +1105 +2 + + +3261 +3558 +2 + + + + + + +symbol +type_id + + +12 + + +1 +2 +2 + + +2 +3 +6 + + +3 +4 1 -8 -9 +5 +6 2 -11 -24 +12 +18 2 -24 -31 +20 +30 2 -67 -74 +35 +48 2 -81 -122 +105 +127 2 -143 -187 +141 +330 2 -217 -672 +342 +435 2 -969 -970 +882 +883 1 @@ -20333,63 +20851,63 @@ 12 +4 +5 +2 + + +5 +6 +2 + + 6 -7 +13 2 -8 -9 -3 - - -11 -24 +17 +18 2 -24 -31 +29 +50 2 -73 -96 +85 +124 2 -151 -152 -1 - - -152 -153 +128 +134 2 -153 -157 +167 +176 2 -188 -190 +205 +215 2 -220 -237 +329 +343 2 -977 -1079 +379 +489 2 -1673 -1745 +1912 +2209 2 @@ -20406,32 +20924,27 @@ 1 2 -1105 +1742 2 3 -1458 +1542 3 4 -144 +257 4 5 -1061 +1272 5 -7 -383 - - -7 -114 -255 +77 +334 @@ -20447,27 +20960,27 @@ 1 2 -1241 +1880 2 3 -2380 +2392 3 4 -345 +476 4 -7 -338 +14 +387 -7 +14 24 -102 +12 @@ -20483,27 +20996,27 @@ 1 2 -1241 +1880 2 3 -2381 +2393 3 4 -344 +475 4 -7 -350 +13 +388 -7 +15 22 -90 +11 @@ -20519,22 +21032,17 @@ 1 2 -3187 +3956 2 3 -762 +890 3 -4 -285 - - -4 -60 -172 +41 +301 @@ -20550,32 +21058,27 @@ 1 2 -1105 +1742 2 3 -1458 +1542 3 4 -142 +255 4 5 -1062 +1273 5 -7 -384 - - -7 -114 -255 +77 +335 @@ -20591,58 +21094,53 @@ 1 2 -1112 +1083 2 3 -359 +364 3 4 -131 - - -4 -20 -135 - - -20 -9397 -47 - - - - - - -type_id -name - - -12 - - -1 -2 -1451 - - -2 -3 154 -3 -8 -150 +4 +9483 +123 + + + + + + +type_id +name + + +12 + + +1 +2 +1305 -9 +2 +3 +240 + + +3 +5 +139 + + +5 18 -29 +40 @@ -20658,22 +21156,22 @@ 1 2 -1451 +1305 2 3 -156 +241 3 -7 -148 +5 +143 -8 +5 16 -29 +35 @@ -20689,17 +21187,17 @@ 1 2 -1520 +1553 2 -3 -134 +5 +135 -3 -3499 -130 +5 +4333 +36 @@ -20715,22 +21213,22 @@ 1 2 -1156 +1092 2 3 -344 +367 3 -5 -151 +4 +157 -5 -3838 -133 +4 +4753 +108 @@ -20746,12 +21244,12 @@ 1 2 -7237 +6925 2 -957 -124 +954 +111 @@ -20767,7 +21265,7 @@ 1 2 -7361 +7036 @@ -20783,7 +21281,7 @@ 1 2 -7361 +7036 @@ -20799,12 +21297,12 @@ 1 2 -7237 +6925 2 -957 -124 +954 +111 @@ -20820,12 +21318,12 @@ 1 2 -7329 +6996 2 -380 -32 +316 +40 @@ -20835,15 +21333,15 @@ operator_location -17972 +26888 id -12398 +8870 loc -645 +2942 @@ -20857,22 +21355,32 @@ 1 2 -9338 +5627 2 3 -1751 +1265 3 -4 -634 +5 +670 -4 -11 -675 +5 +15 +602 + + +15 +18 +699 + + +18 +21 +7 @@ -20888,38 +21396,23 @@ 1 2 -322 +2404 2 -3 -99 +5 +270 -3 -6 +5 +121 +221 + + +136 +3457 47 - -6 -11 -57 - - -11 -40 -50 - - -40 -229 -58 - - -278 -4153 -12 - @@ -20928,15 +21421,15 @@ constant_value -123998 +109873 id -123998 +108394 value -24364 +26585 @@ -20950,7 +21443,12 @@ 1 2 -123998 +107086 + + +2 +5 +1308 @@ -20966,27 +21464,22 @@ 1 2 -15909 +20463 2 3 -4035 +3137 3 -5 -1856 +8 +2119 -5 -12 -1925 - - -12 -8469 -639 +8 +8085 +866 @@ -20996,27 +21489,27 @@ methods -1076961 +990339 id -1076961 +990339 name -123752 +145323 declaring_type_id -122626 +115072 type_id -85751 +75864 unbound_id -485699 +416703 @@ -21030,7 +21523,7 @@ 1 2 -1076961 +990339 @@ -21046,7 +21539,7 @@ 1 2 -1076961 +990339 @@ -21062,7 +21555,7 @@ 1 2 -1076961 +990339 @@ -21078,7 +21571,7 @@ 1 2 -1076961 +990339 @@ -21094,27 +21587,27 @@ 1 2 -84817 +103232 2 3 -14120 +18945 3 5 -10260 +11241 5 -13 -9409 +60 +10906 -13 -34427 -5146 +60 +33554 +999 @@ -21130,27 +21623,22 @@ 1 2 -88126 +107949 2 3 -13684 +17436 3 -5 -9813 +6 +12134 -5 -18 -9310 - - -18 -17762 -2819 +6 +17745 +7804 @@ -21166,17 +21654,17 @@ 1 2 -109390 +134024 2 -5 -10284 +124 +10936 -5 -13972 -4078 +124 +13470 +363 @@ -21192,27 +21680,22 @@ 1 2 -85912 +105154 2 3 -14443 +19254 3 5 -10418 +11116 5 -15 -9328 - - -15 -9184 -3651 +8756 +9799 @@ -21228,42 +21711,47 @@ 1 2 -34188 +30339 2 3 -17314 +17979 3 4 -20964 +20209 4 5 -8816 +7063 5 6 -10575 +11230 6 10 -10963 +9248 10 -23 -10702 +21 +8656 -23 -2721 -9104 +21 +82 +9133 + + +82 +4659 +1215 @@ -21279,42 +21767,42 @@ 1 2 -36689 +31840 2 3 -19872 +18946 3 4 -21628 +20938 4 5 -9733 +10198 5 6 -9479 +9143 6 10 -9575 +8968 10 22 -9473 +8901 22 2630 -6177 +6138 @@ -21330,32 +21818,32 @@ 1 2 -50588 +46532 2 3 -38419 +36855 3 4 -8775 +8749 4 5 -8027 +8055 5 9 -9887 +8673 9 -1435 -6930 +2310 +6208 @@ -21371,42 +21859,47 @@ 1 2 -34249 +30464 2 3 -17356 +17990 3 4 -20967 +20224 4 5 -8827 +7078 5 6 -10584 +11238 6 10 -11009 +9259 10 -23 -10686 +22 +8857 -23 -2634 -8948 +22 +82 +8820 + + +82 +2631 +1142 @@ -21422,32 +21915,32 @@ 1 2 -53339 +45668 2 3 -12908 +13238 3 4 -5962 +5192 4 10 -6853 +5878 10 221 -6574 +5798 -222 -291373 -115 +224 +281834 +90 @@ -21463,22 +21956,22 @@ 1 2 -65576 +56967 2 3 -7734 +7755 3 7 -6549 +5788 7 -58312 -5892 +66425 +5354 @@ -21494,22 +21987,22 @@ 1 2 -61912 +53716 2 3 -14166 +13964 3 -6 -6543 +7 +6247 -6 -57678 -3130 +7 +56084 +1937 @@ -21525,32 +22018,32 @@ 1 2 -53406 +45760 2 3 -13007 +13288 3 4 -5965 +5214 4 10 -6831 +5845 10 -221 -6437 +252 +5691 -221 -160307 -105 +254 +149113 +66 @@ -21566,12 +22059,12 @@ 1 2 -465024 +401515 2 -8433 -20675 +8127 +15188 @@ -21587,7 +22080,7 @@ 1 2 -485699 +416703 @@ -21603,12 +22096,12 @@ 1 2 -467820 +404324 2 -8433 -17879 +8127 +12379 @@ -21624,12 +22117,12 @@ 1 2 -474343 +410109 2 -8438 -11356 +8127 +6594 @@ -21639,15 +22132,15 @@ method_location -1613197 +2069011 id -1073711 +989823 loc -136410 +225377 @@ -21661,22 +22154,27 @@ 1 2 -685284 +481413 2 3 -300207 +351054 3 -5 -86944 +4 +59147 -5 -13 -1276 +4 +9 +74877 + + +9 +24 +23332 @@ -21692,12 +22190,12 @@ 1 2 -127523 +213144 2 -122930 -8887 +117240 +12233 @@ -21707,23 +22205,23 @@ constructors -154830 +149144 id -154830 +149144 name -46607 +54143 declaring_type_id -104385 +101619 unbound_id -108271 +98805 @@ -21737,7 +22235,7 @@ 1 2 -154830 +149144 @@ -21753,7 +22251,7 @@ 1 2 -154830 +149144 @@ -21769,7 +22267,7 @@ 1 2 -154830 +149144 @@ -21785,27 +22283,22 @@ 1 2 -29993 +39528 2 3 -8076 +8842 3 -4 -2952 - - -4 7 -3570 +4536 7 -8393 -2016 +7428 +1237 @@ -21821,22 +22314,17 @@ 1 2 -34660 +47190 2 3 -6241 +4506 3 -5 -3617 - - -5 -5524 -2089 +5277 +2447 @@ -21852,27 +22340,22 @@ 1 2 -30316 +40238 2 3 -8174 +8855 3 -4 -2879 +7 +4181 -4 -8 -3698 - - -8 -4201 -1540 +7 +4418 +869 @@ -21888,22 +22371,22 @@ 1 2 -83056 +80662 2 3 -11296 +11743 3 8 -8546 +7758 8 -44 -1487 +42 +1456 @@ -21919,7 +22402,7 @@ 1 2 -104385 +101619 @@ -21935,22 +22418,22 @@ 1 2 -83056 +80662 2 3 -11296 +11743 3 8 -8546 +7758 8 -44 -1487 +42 +1456 @@ -21966,12 +22449,12 @@ 1 2 -106112 +96762 2 -1790 -2159 +3787 +2043 @@ -21987,7 +22470,7 @@ 1 2 -108271 +98805 @@ -22003,12 +22486,12 @@ 1 2 -106112 +96762 2 -1790 -2159 +3787 +2043 @@ -22018,15 +22501,15 @@ constructor_location -222090 +294390 id -154828 +149141 loc -19558 +44163 @@ -22040,22 +22523,27 @@ 1 2 -112277 +95933 2 3 -24589 +26780 3 4 -11838 +12519 4 -28 -6124 +13 +11784 + + +13 +591 +2125 @@ -22071,17 +22559,17 @@ 1 2 -17208 +39468 2 7 -1512 +3388 7 -17811 -838 +17601 +1307 @@ -22091,23 +22579,23 @@ destructors -461 +388 id -461 +388 name -288 +300 declaring_type_id -461 +388 unbound_id -413 +315 @@ -22121,7 +22609,7 @@ 1 2 -461 +388 @@ -22137,7 +22625,7 @@ 1 2 -461 +388 @@ -22153,7 +22641,7 @@ 1 2 -461 +388 @@ -22169,84 +22657,54 @@ 1 2 -220 +278 2 -3 -36 - - -3 -5 -23 - - -5 -25 -9 - - - - - - -name -declaring_type_id - - -12 - - -1 -2 -220 - - -2 -3 -36 - - -3 -5 -23 - - -5 -25 -9 - - - - - - -name -unbound_id - - -12 - - -1 -2 -224 - - -2 -3 -37 - - -3 -6 +23 22 + + + + + +name +declaring_type_id + + +12 + -6 -11 -5 +1 +2 +278 + + +2 +23 +22 + + + + + + +name +unbound_id + + +12 + + +1 +2 +287 + + +2 +4 +13 @@ -22262,7 +22720,7 @@ 1 2 -461 +388 @@ -22278,7 +22736,7 @@ 1 2 -461 +388 @@ -22294,7 +22752,7 @@ 1 2 -461 +388 @@ -22310,12 +22768,12 @@ 1 2 -403 +304 2 -22 -10 +23 +11 @@ -22331,7 +22789,7 @@ 1 2 -413 +315 @@ -22347,12 +22805,12 @@ 1 2 -403 +304 2 -22 -10 +23 +11 @@ -22362,15 +22820,15 @@ destructor_location -842 +1101 id -461 +388 loc -168 +381 @@ -22384,27 +22842,32 @@ 1 2 -268 +197 2 3 -80 +69 3 4 -44 +38 4 -5 -68 +7 +35 -10 -11 -1 +7 +12 +35 + + +12 +18 +14 @@ -22420,37 +22883,32 @@ 1 2 -84 +256 2 3 -20 +35 3 4 -13 +21 4 -5 -14 +6 +33 -5 -9 -14 +6 +22 +29 -9 -20 -13 - - -20 -75 -10 +22 +33 +7 @@ -22460,15 +22918,15 @@ overrides -156312 +117202 id -156312 +116553 base_id -44250 +31431 @@ -22482,7 +22940,12 @@ 1 2 -156312 +115904 + + +2 +3 +649 @@ -22498,27 +22961,27 @@ 1 2 -24930 +18013 2 3 -9202 +6343 3 4 -3081 +2243 4 7 -3911 +2620 7 -3299 -3126 +3939 +2212 @@ -22528,15 +22991,15 @@ explicitly_implements -173173 +181041 id -173173 +181041 interface_id -19919 +21520 @@ -22550,7 +23013,7 @@ 1 2 -173173 +181041 @@ -22566,42 +23029,42 @@ 1 2 -8589 +8591 2 3 -3727 +4158 3 4 -1718 +1973 4 5 -444 +666 5 6 -2452 +2548 6 -12 -1382 +10 +1626 -12 -58 -1496 +10 +19 +1621 -58 -10759 -111 +19 +24037 +337 @@ -22611,23 +23074,23 @@ local_functions -1174 +1201 id -1174 +1201 name -730 +755 return_type -166 +169 unbound_id -1172 +1199 @@ -22641,7 +23104,7 @@ 1 2 -1174 +1201 @@ -22657,7 +23120,7 @@ 1 2 -1174 +1201 @@ -22673,7 +23136,7 @@ 1 2 -1174 +1201 @@ -22689,12 +23152,12 @@ 1 2 -645 +668 2 4 -58 +60 4 @@ -22715,7 +23178,7 @@ 1 2 -722 +747 2 @@ -22736,12 +23199,12 @@ 1 2 -646 +669 2 4 -57 +59 4 @@ -22762,22 +23225,22 @@ 1 2 -121 +123 2 3 -20 +21 3 -6 -14 +5 +13 -6 -693 -11 +5 +697 +12 @@ -22793,7 +23256,7 @@ 1 2 -130 +133 2 @@ -22802,13 +23265,13 @@ 3 -7 -14 +8 +13 -13 -297 -5 +15 +301 +6 @@ -22824,22 +23287,22 @@ 1 2 -121 +123 2 3 -20 +21 3 -6 -14 +5 +13 -6 -693 -11 +5 +697 +12 @@ -22855,7 +23318,7 @@ 1 2 -1171 +1198 3 @@ -22876,7 +23339,7 @@ 1 2 -1172 +1199 @@ -22892,7 +23355,7 @@ 1 2 -1171 +1198 3 @@ -22907,15 +23370,15 @@ local_function_stmts -1305 +1199 fn -1305 +1199 stmt -1172 +1199 @@ -22929,7 +23392,7 @@ 1 2 -1305 +1199 @@ -22945,12 +23408,7 @@ 1 2 -1104 - - -2 -9 -68 +1199 @@ -22960,11 +23418,11 @@ fields -292454 +285648 id -292454 +285648 kind @@ -22972,19 +23430,19 @@ name -103398 +127772 declaring_type_id -55991 +58158 type_id -54021 +47955 unbound_id -272257 +267317 @@ -22998,7 +23456,7 @@ 1 2 -292454 +285648 @@ -23014,7 +23472,7 @@ 1 2 -292454 +285648 @@ -23030,7 +23488,7 @@ 1 2 -292454 +285648 @@ -23046,7 +23504,7 @@ 1 2 -292454 +285648 @@ -23062,7 +23520,7 @@ 1 2 -292454 +285648 @@ -23076,13 +23534,13 @@ 12 -122762 -122763 +106769 +106770 1 -160511 -160512 +178578 +178579 1 @@ -23097,13 +23555,13 @@ 12 -40098 -40099 +54214 +54215 1 -65413 -65414 +76116 +76117 1 @@ -23118,13 +23576,13 @@ 12 -10855 -10856 +10999 +11000 1 -46872 -46873 +49829 +49830 1 @@ -23139,13 +23597,13 @@ 12 -8748 -8749 +7955 +7956 1 -46848 -46849 +41759 +41760 1 @@ -23160,13 +23618,13 @@ 12 -122638 -122639 +106161 +106162 1 -149619 -149620 +161161 +161162 1 @@ -23183,27 +23641,22 @@ 1 2 -71846 +101759 2 3 -12945 +13893 3 -4 -7951 +9 +9606 -4 -10 -8225 - - -10 -6843 -2431 +9 +7502 +2514 @@ -23219,12 +23672,12 @@ 1 2 -101285 +125214 2 3 -2113 +2558 @@ -23240,27 +23693,22 @@ 1 2 -71846 +101759 2 3 -12945 +13893 3 -4 -7951 +9 +9606 -4 -10 -8225 - - -10 -6843 -2431 +9 +7502 +2514 @@ -23276,22 +23724,17 @@ 1 2 -79247 +111990 2 3 -10211 +9417 3 -5 -8781 - - -5 -4553 -5159 +4791 +6365 @@ -23307,27 +23750,22 @@ 1 2 -72207 +102538 2 3 -13022 +13899 3 -4 -7894 +11 +9600 -4 -10 -7975 - - -10 -6843 -2300 +11 +7502 +1735 @@ -23343,42 +23781,42 @@ 1 2 -13938 +13468 2 3 -13645 +13970 3 4 -8248 +9308 4 5 -5544 +5925 5 6 -3469 +3861 6 8 -4613 +4917 8 15 -4445 +4612 15 4792 -2089 +2097 @@ -23394,12 +23832,12 @@ 1 2 -54255 +55488 2 3 -1736 +2670 @@ -23415,42 +23853,42 @@ 1 2 -13938 +13468 2 3 -13645 +13970 3 4 -8248 +9308 4 5 -5544 +5925 5 6 -3469 +3861 6 8 -4613 +4917 8 15 -4445 +4612 15 4792 -2089 +2097 @@ -23466,32 +23904,32 @@ 1 2 -24596 +23657 2 3 -14427 +16254 3 4 -6072 +6661 4 5 -3106 +3854 5 -8 -5024 +7 +4345 -8 -184 -2766 +7 +569 +3387 @@ -23507,42 +23945,42 @@ 1 2 -13938 +13468 2 3 -13645 +13970 3 4 -8248 +9308 4 5 -5544 +5925 5 6 -3469 +3861 6 8 -4613 +4917 8 15 -4445 +4612 15 4792 -2089 +2097 @@ -23558,32 +23996,32 @@ 1 2 -32209 +28567 2 3 -7718 +6526 3 4 -4216 +3634 4 6 -3904 +3781 6 -16 -4181 +15 +3728 -16 -31639 -1793 +15 +38777 +1719 @@ -23599,12 +24037,12 @@ 1 2 -52446 +46196 2 3 -1575 +1759 @@ -23620,27 +24058,27 @@ 1 2 -35276 +31776 2 3 -7110 +5924 3 4 -3716 +3057 4 7 -4170 +3977 7 -16842 -3749 +22007 +3221 @@ -23656,22 +24094,22 @@ 1 2 -41289 +36247 2 3 -6855 +5872 3 -7 -4189 +6 +3680 -7 -11356 -1688 +6 +13299 +2156 @@ -23687,32 +24125,32 @@ 1 2 -32287 +28687 2 3 -7753 +6534 3 4 -4195 +3601 4 6 -3885 +3767 6 -16 -4140 +15 +3691 -16 -31127 -1761 +15 +36782 +1675 @@ -23728,12 +24166,12 @@ 1 2 -270801 +264767 2 -957 -1456 +954 +2550 @@ -23749,7 +24187,12 @@ 1 2 -272257 +267312 + + +2 +3 +5 @@ -23765,7 +24208,7 @@ 1 2 -272257 +267317 @@ -23781,12 +24224,12 @@ 1 2 -270801 +264767 2 -957 -1456 +954 +2550 @@ -23802,12 +24245,12 @@ 1 2 -262887 +265821 2 -957 -9370 +954 +1496 @@ -23817,15 +24260,15 @@ field_location -471966 +665606 id -275969 +283536 loc -38796 +100719 @@ -23839,27 +24282,27 @@ 1 2 -150431 +110804 2 3 -83301 +112944 3 4 -15612 +21535 4 -5 -25909 +7 +25436 -5 -14 -716 +7 +534 +12817 @@ -23875,17 +24318,12 @@ 1 2 -33152 +95087 2 -3 -3438 - - -3 9082 -2206 +5632 @@ -23895,11 +24333,11 @@ localvars -240033 +309450 id -240033 +309450 kind @@ -23907,7 +24345,7 @@ name -34551 +50758 implicitly_typed @@ -23915,11 +24353,11 @@ type_id -14128 +19087 parent_id -240033 +309450 @@ -23933,7 +24371,7 @@ 1 2 -240033 +309450 @@ -23949,7 +24387,7 @@ 1 2 -240033 +309450 @@ -23965,7 +24403,7 @@ 1 2 -240033 +309450 @@ -23981,7 +24419,7 @@ 1 2 -240033 +309450 @@ -23997,7 +24435,7 @@ 1 2 -240033 +309450 @@ -24011,18 +24449,18 @@ 12 -11 -12 +54 +55 1 -1223 -1224 +1627 +1628 1 -238799 -238800 +307769 +307770 1 @@ -24037,18 +24475,18 @@ 12 -5 -6 +31 +32 1 -413 -414 +783 +784 1 -34260 -34261 +50117 +50118 1 @@ -24084,18 +24522,18 @@ 12 -5 -6 +21 +22 1 -32 -33 +43 +44 1 -14120 -14121 +19072 +19073 1 @@ -24110,18 +24548,18 @@ 12 -11 -12 +54 +55 1 -1223 -1224 +1627 +1628 1 -238799 -238800 +307769 +307770 1 @@ -24138,32 +24576,27 @@ 1 2 -20908 +31599 2 3 -5546 +8221 3 4 -2435 +3292 4 -7 -2614 +8 +4188 -7 -62 -2595 - - -62 -14242 -453 +8 +14339 +3458 @@ -24179,12 +24612,12 @@ 1 2 -34424 +50585 2 3 -127 +173 @@ -24200,12 +24633,12 @@ 1 2 -30837 +45779 2 3 -3714 +4979 @@ -24221,17 +24654,17 @@ 1 2 -28724 +43415 2 3 -3287 +4121 3 -1256 -2540 +1514 +3222 @@ -24247,32 +24680,27 @@ 1 2 -20908 +31599 2 3 -5546 +8221 3 4 -2435 +3292 4 -7 -2614 +8 +4188 -7 -62 -2595 - - -62 -14242 -453 +8 +14339 +3458 @@ -24286,13 +24714,13 @@ 12 -49660 -49661 +119948 +119949 1 -190373 -190374 +189502 +189503 1 @@ -24328,13 +24756,13 @@ 12 -11178 -11179 +27809 +27810 1 -27087 -27088 +27928 +27929 1 @@ -24349,13 +24777,13 @@ 12 -4093 -4094 +9524 +9525 1 -12464 -12465 +12356 +12357 1 @@ -24370,13 +24798,13 @@ 12 -49660 -49661 +119948 +119949 1 -190373 -190374 +189502 +189503 1 @@ -24393,37 +24821,37 @@ 1 2 -6390 +8834 2 3 -2419 +3200 3 4 -1200 +1561 4 6 -1291 +1732 6 10 -1115 +1473 10 -30 -1068 +29 +1446 -30 -52306 -645 +29 +57038 +841 @@ -24439,12 +24867,12 @@ 1 2 -14100 +19041 2 4 -28 +46 @@ -24460,27 +24888,27 @@ 1 2 -8681 +11861 2 3 -2316 +3127 3 4 -982 +1302 4 7 -1150 +1505 7 -3654 -999 +5718 +1292 @@ -24496,12 +24924,12 @@ 1 2 -11699 +16294 2 3 -2429 +2793 @@ -24517,37 +24945,37 @@ 1 2 -6390 +8834 2 3 -2419 +3200 3 4 -1200 +1561 4 6 -1291 +1732 6 10 -1115 +1473 10 -30 -1068 +29 +1446 -30 -52306 -645 +29 +57038 +841 @@ -24563,7 +24991,7 @@ 1 2 -240033 +309450 @@ -24579,7 +25007,7 @@ 1 2 -240033 +309450 @@ -24595,7 +25023,7 @@ 1 2 -240033 +309450 @@ -24611,7 +25039,7 @@ 1 2 -240033 +309450 @@ -24627,7 +25055,7 @@ 1 2 -240033 +309450 @@ -24637,15 +25065,15 @@ localvar_location -240033 +309450 id -240033 +309450 loc -233676 +309085 @@ -24659,7 +25087,7 @@ 1 2 -240033 +309450 @@ -24675,12 +25103,12 @@ 1 2 -229323 +308720 2 -9 -4353 +3 +365 @@ -24690,19 +25118,19 @@ params -1873820 +1662795 id -1873820 +1662795 name -41364 +48172 type_id -161044 +127333 index @@ -24714,11 +25142,11 @@ parent_id -1116592 +1009707 unbound_id -877362 +709589 @@ -24732,7 +25160,7 @@ 1 2 -1873820 +1662795 @@ -24748,7 +25176,7 @@ 1 2 -1873820 +1662795 @@ -24764,7 +25192,7 @@ 1 2 -1873820 +1662795 @@ -24780,7 +25208,7 @@ 1 2 -1873820 +1662795 @@ -24796,7 +25224,7 @@ 1 2 -1873820 +1662795 @@ -24812,7 +25240,7 @@ 1 2 -1873820 +1662795 @@ -24828,47 +25256,42 @@ 1 2 -13621 +18527 2 3 -7047 +8846 3 4 -4026 +4277 4 5 -3188 +3465 5 -7 -3256 +8 +4374 -7 -11 -3127 +8 +15 +3854 -11 -21 -3167 +15 +65 +3617 -21 -123 -3106 - - -123 -129722 -826 +65 +115038 +1212 @@ -24884,22 +25307,22 @@ 1 2 -30165 +38960 2 3 -4715 +4760 3 -5 -3381 +12 +3615 -5 -14591 -3103 +12 +13741 +837 @@ -24915,22 +25338,22 @@ 1 2 -28293 +32920 2 3 -7375 +8631 3 4 -2787 +3251 4 28 -2909 +3370 @@ -24946,17 +25369,17 @@ 1 2 -38214 +44430 2 5 -3112 +3689 5 7 -38 +53 @@ -24972,47 +25395,42 @@ 1 2 -13621 +18527 2 3 -7047 +8846 3 4 -4026 +4277 4 5 -3188 +3465 5 -7 -3256 +8 +4374 -7 -11 -3127 +8 +15 +3854 -11 -21 -3167 +15 +65 +3617 -21 -123 -3106 - - -123 -129722 -826 +65 +115038 +1212 @@ -25028,47 +25446,42 @@ 1 2 -13968 +19226 2 3 -7266 +9088 3 4 -4092 +4287 4 5 -3223 +3445 5 -7 -3194 +8 +4279 -7 -11 -3118 +8 +15 +3620 -11 -23 -3207 +15 +107 +3613 -23 -539 -3103 - - -543 -67549 -193 +107 +59449 +614 @@ -25084,37 +25497,37 @@ 1 2 -91168 +66747 2 3 -17876 +14274 3 4 -8604 +7070 4 5 -10406 +10049 5 -9 -12941 +8 +10159 -9 -20 -12267 +8 +16 +10230 -20 -262274 -7782 +16 +250157 +8804 @@ -25130,22 +25543,22 @@ 1 2 -128753 +98326 2 3 -16870 +13720 3 -8 -12219 +6 +10307 -8 -6338 -3202 +6 +7254 +4980 @@ -25161,22 +25574,22 @@ 1 2 -126154 +95270 2 3 -22257 +20230 3 -8 -12236 +5 +10443 -8 +5 50 -397 +1390 @@ -25192,12 +25605,12 @@ 1 2 -152216 +119091 2 6 -8828 +8242 @@ -25213,37 +25626,37 @@ 1 2 -92367 +67557 2 3 -18720 +15267 3 4 -8759 +7257 4 -6 -13993 +5 +8928 -6 -13 -14744 +5 +8 +9845 -13 -283 -12079 +8 +16 +10012 -283 -211973 -382 +16 +203397 +8467 @@ -25259,37 +25672,37 @@ 1 2 -91920 +67273 2 3 -17586 +14078 3 4 -9255 +7143 4 5 -10966 +10798 5 -9 -13759 +8 +10706 -9 -26 -12406 +8 +17 +10208 -26 -94223 -5152 +17 +82653 +7127 @@ -25308,48 +25721,48 @@ 11 -5 -6 +2 +3 8 -9 -28 +6 +19 4 -30 -56 +20 +37 4 -64 -109 +42 +68 4 -124 -231 +74 +119 4 -463 -1329 +285 +932 4 -1755 -4383 +1269 +3439 4 -7196 -32601 +5388 +26515 4 -73082 -1116593 +60694 +1006637 4 @@ -25379,38 +25792,38 @@ 4 -10 -19 +11 +21 4 -19 -29 +21 +32 4 -33 -53 +36 +56 4 -76 -183 +80 +187 4 -255 -752 +270 +852 4 -1209 -4484 +1380 +5216 4 -7204 -19237 +8435 +22372 4 @@ -25430,54 +25843,54 @@ 11 -5 -6 +2 +3 8 -7 -13 +4 +9 4 -14 -23 +10 +15 +2 + + +16 +20 +4 + + +25 +27 3 -23 -46 +32 +176 4 -50 -80 +297 +767 4 -100 -643 +936 +1850 4 -840 -1577 +2277 +8796 4 -1921 -4399 -4 - - -5863 -49674 -4 - - -111424 -111425 -1 +17296 +92711 +3 @@ -25537,48 +25950,48 @@ 11 -5 -6 +2 +3 8 -9 -28 +6 +19 4 -30 -56 +20 +37 4 -64 -109 +42 +68 4 -124 -231 +74 +119 4 -463 -1329 +285 +932 4 -1755 -4383 +1269 +3439 4 -7196 -32601 +5388 +26515 4 -73082 -1116593 +60694 +1006637 4 @@ -25598,48 +26011,48 @@ 11 -5 -6 +2 +3 8 -9 -28 +6 +19 4 -30 -56 +20 +37 4 -64 -109 +42 +68 4 -124 -231 +74 +119 4 -328 -741 +174 +451 4 -1019 -3147 +664 +2379 4 -5508 -25827 +3992 +20329 4 -48569 -474892 +38390 +389589 4 @@ -25654,33 +26067,33 @@ 12 -511 -512 +733 +734 1 -8643 -8644 +6510 +6511 1 -13051 -13052 +13337 +13338 1 -29937 -29938 +20276 +20277 1 -31208 -31209 +30458 +30459 1 -1790319 -1790320 +1591179 +1591180 1 @@ -25695,33 +26108,33 @@ 12 -39 -40 +79 +80 1 -475 -476 +483 +484 1 -960 -961 +1013 +1014 1 -1769 -1770 +2257 +2258 1 -4676 -4677 +5499 +5500 1 -37382 -37383 +43559 +43560 1 @@ -25736,33 +26149,33 @@ 12 -125 -126 +147 +148 1 -1391 -1392 +1038 +1039 1 -1839 -1840 +2115 +2116 1 -5719 -5720 +4196 +4197 1 -10363 -10364 +5987 +5988 1 -151475 -151476 +123175 +123176 1 @@ -25818,33 +26231,33 @@ 12 -447 -448 +652 +653 1 -8643 -8644 +6510 +6511 1 -11110 -11111 +10961 +10962 1 -23417 -23418 +20276 +20277 1 -29937 -29938 +24590 +24591 1 -1093892 -1093893 +991551 +991552 1 @@ -25859,33 +26272,33 @@ 12 -264 -265 +353 +354 1 -5881 -5882 +3872 +3873 1 -11779 -11780 +10322 +10323 1 -18436 -18437 +10847 +10848 1 -23618 -23619 +21440 +21441 1 -817385 -817386 +662845 +662846 1 @@ -25902,22 +26315,22 @@ 1 2 -672190 +614133 2 3 -288892 +263888 3 4 -82428 +71715 4 52 -73082 +59971 @@ -25933,22 +26346,22 @@ 1 2 -672186 +614072 2 3 -288887 +263868 3 4 -82430 +71736 4 52 -73089 +60031 @@ -25964,22 +26377,22 @@ 1 2 -721470 +660352 2 3 -280220 +255417 3 5 -93921 +77910 5 41 -20981 +16028 @@ -25995,22 +26408,22 @@ 1 2 -672190 +614133 2 3 -288892 +263888 3 4 -82428 +71715 4 52 -73082 +59971 @@ -26026,12 +26439,12 @@ 1 2 -1067388 +966434 2 5 -49204 +43273 @@ -26047,22 +26460,22 @@ 1 2 -672185 +614125 2 3 -288897 +263896 3 4 -82428 +71715 4 52 -73082 +59971 @@ -26078,12 +26491,12 @@ 1 2 -839334 +681004 2 -9488 -38028 +15458 +28585 @@ -26099,12 +26512,12 @@ 1 2 -877341 +709322 2 -12 -21 +4 +267 @@ -26120,12 +26533,12 @@ 1 2 -861642 +698010 2 -4604 -15720 +5635 +11579 @@ -26141,7 +26554,7 @@ 1 2 -877362 +709589 @@ -26157,12 +26570,12 @@ 1 2 -877361 +709499 2 3 -1 +90 @@ -26178,12 +26591,12 @@ 1 2 -839334 +681004 2 -9488 -38028 +15458 +28585 @@ -26193,15 +26606,15 @@ param_location -2407035 +3009317 id -1867344 +1650966 loc -199269 +370027 @@ -26215,22 +26628,27 @@ 1 2 -1533663 +1174826 2 3 -175244 +203043 3 -5 -156584 +4 +134596 -5 -13 -1853 +4 +15 +131678 + + +15 +534 +6823 @@ -26246,17 +26664,12 @@ 1 2 -180467 +345724 2 -7 -15302 - - -7 -208250 -3500 +215283 +24303 @@ -26266,11 +26679,11 @@ statements -1072910 +1789979 id -1072910 +1789979 kind @@ -26288,7 +26701,7 @@ 1 2 -1072910 +1789979 @@ -26302,83 +26715,83 @@ 12 -8 -18 +18 +187 2 -22 -55 +234 +253 2 -69 -77 +301 +331 2 -95 -116 +349 +440 2 -148 -150 +783 +795 2 -179 -657 +1199 +1201 2 -1155 -1223 +1334 +1624 2 -1305 -1697 +1831 +3271 2 -1828 -2056 +4304 +4712 2 -2439 -3371 +6120 +6287 2 -5182 -5511 +8021 +8190 2 -7981 -9036 +11629 +17069 2 -10708 -34568 +53160 +62808 2 -71396 -107423 +158006 +172167 2 -213042 -262648 +269815 +483216 2 -328762 -328763 +510339 +510340 1 @@ -26389,11 +26802,11 @@ stmt_parent -915253 +1511647 stmt -915253 +1511647 index @@ -26401,7 +26814,7 @@ parent -362670 +672991 @@ -26415,7 +26828,7 @@ 1 2 -915253 +1511647 @@ -26431,7 +26844,7 @@ 1 2 -915253 +1511647 @@ -26451,17 +26864,17 @@ 2 -15 +16 162 -15 -66 +16 +98 160 -66 -269102 +99 +477408 115 @@ -26482,17 +26895,17 @@ 2 -15 +16 162 -15 -66 +16 +98 160 -66 -269102 +99 +477408 115 @@ -26509,32 +26922,27 @@ 1 2 -210247 +417292 2 3 -61136 +117594 3 4 -30007 +47441 4 -6 -30325 +7 +56561 -6 -18 -27276 - - -18 +7 2123 -3679 +34103 @@ -26550,32 +26958,27 @@ 1 2 -210247 +417292 2 3 -61136 +117594 3 4 -30007 +47441 4 -6 -30325 +7 +56561 -6 -18 -27276 - - -18 +7 2123 -3679 +34103 @@ -26585,11 +26988,11 @@ stmt_parent_top_level -157657 +278332 stmt -157657 +278332 index @@ -26597,7 +27000,7 @@ parent -157653 +250974 @@ -26611,7 +27014,7 @@ 1 2 -157657 +278332 @@ -26627,7 +27030,7 @@ 1 2 -157657 +278332 @@ -26641,8 +27044,8 @@ 12 -157657 -157658 +278332 +278333 1 @@ -26657,8 +27060,8 @@ 12 -157653 -157654 +250974 +250975 1 @@ -26675,12 +27078,17 @@ 1 2 -157649 +223812 2 3 -4 +26967 + + +3 +5 +195 @@ -26696,7 +27104,7 @@ 1 2 -157653 +250974 @@ -26706,15 +27114,15 @@ stmt_location -1072910 +1789979 id -1072910 +1789979 loc -1030702 +1784517 @@ -26728,7 +27136,7 @@ 1 2 -1072910 +1789979 @@ -26744,12 +27152,12 @@ 1 2 -1002522 +1781311 2 -12 -28180 +45 +3206 @@ -26759,15 +27167,15 @@ catch_type -2055 +4711 catch_id -2055 +4711 type_id -166 +163 kind @@ -26785,7 +27193,7 @@ 1 2 -2055 +4711 @@ -26801,7 +27209,7 @@ 1 2 -2055 +4711 @@ -26817,7 +27225,7 @@ 1 2 -60 +48 2 @@ -26827,7 +27235,7 @@ 3 4 -21 +14 4 @@ -26836,23 +27244,28 @@ 5 -7 +8 15 -7 -13 -14 +8 +11 +15 -14 -82 +11 +28 13 -107 -389 -5 +30 +91 +13 + + +114 +1687 +7 @@ -26868,7 +27281,7 @@ 1 2 -166 +163 @@ -26882,13 +27295,13 @@ 12 -317 -318 +758 +759 1 -1738 -1739 +3953 +3954 1 @@ -26903,13 +27316,13 @@ 12 -6 -7 +1 +2 1 -160 -161 +162 +163 1 @@ -26920,19 +27333,19 @@ expressions -4889105 +7417345 id -4889105 +7417345 kind -103 +106 type_id -48005 +63982 @@ -26946,7 +27359,7 @@ 1 2 -4889105 +7417345 @@ -26962,7 +27375,7 @@ 1 2 -4889105 +7417345 @@ -26976,69 +27389,74 @@ 12 -4 -32 -9 - - -34 -55 +8 +50 8 -64 -153 +69 +143 8 -160 -256 +178 +409 8 -257 -382 +435 +657 8 -444 -1842 +715 +1216 8 -1845 -2921 +1258 +2153 8 -3359 -4761 +2309 +4322 8 -4871 -7590 +4350 +7103 8 -8632 -17337 +7270 +12714 8 -20850 -51126 +14417 +22533 8 -58357 -331896 +24042 +32766 8 -342808 -756876 -6 +41161 +212777 +8 + + +268458 +724743 +8 + + +928336 +1050543 +2 @@ -27054,56 +27472,56 @@ 1 2 -28 +29 2 -3 -6 - - -3 -5 +6 8 -5 +6 8 8 8 -16 +12 8 -20 -64 +13 +55 8 -78 -186 +59 +114 8 -215 -715 +115 +319 8 -733 -1554 +327 +1055 8 -1774 -11493 +1063 +2159 8 -12327 -14569 +2975 +17362 +8 + + +18530 +20120 5 @@ -27120,57 +27538,57 @@ 1 2 -12254 +14334 2 3 -5177 +5964 3 4 -3053 +3755 4 5 -2703 +4381 5 7 -4432 +5869 7 10 -3752 +5162 10 15 -3781 +5056 15 -25 -3779 +24 +4964 -25 -51 -3670 +24 +44 +4940 -51 -183 -3607 +44 +108 +4809 -183 -740099 -1797 +108 +977236 +4748 @@ -27186,37 +27604,42 @@ 1 2 -21735 +26518 2 3 -6947 +8251 3 4 -6168 +9231 4 5 -4210 +5758 5 -7 -4274 +6 +3874 -7 -11 -3645 +6 +8 +4706 -11 -54 -1026 +8 +13 +4969 + + +13 +56 +675 @@ -27226,19 +27649,19 @@ expr_parent -4738577 +7178046 expr -4738577 +7178046 index -7172 +8196 parent -3074959 +4743008 @@ -27252,7 +27675,7 @@ 1 2 -4738577 +7178046 @@ -27268,7 +27691,7 @@ 1 2 -4738577 +7178046 @@ -27284,27 +27707,27 @@ 1 2 -1 +1024 2 3 -3434 +3435 3 4 -2717 +2522 4 -7 -601 +9 +699 -7 -2212725 -419 +9 +3426742 +516 @@ -27320,27 +27743,27 @@ 1 2 -1 +1024 2 3 -3434 +3435 3 4 -2717 +2522 4 -7 -601 +9 +699 -7 -2212725 -419 +9 +3426742 +516 @@ -27356,22 +27779,22 @@ 1 2 -1908468 +2972682 2 3 -878461 +1395233 3 -5 -250958 +7 +359960 -5 -7169 -37072 +7 +8193 +15133 @@ -27387,22 +27810,22 @@ 1 2 -1908468 +2972682 2 3 -878461 +1395233 3 -5 -250958 +7 +359960 -5 -7169 -37072 +7 +8193 +15133 @@ -27412,11 +27835,11 @@ expr_parent_top_level -150528 +239299 expr -150528 +239299 index @@ -27424,7 +27847,7 @@ parent -106198 +179958 @@ -27438,7 +27861,7 @@ 1 2 -150528 +239299 @@ -27454,7 +27877,7 @@ 1 2 -150528 +239299 @@ -27478,38 +27901,38 @@ 1 -90 -91 +135 +136 1 -227 -228 +383 +384 1 -776 -777 +1297 +1298 1 -1641 -1642 +3062 +3063 1 -5737 -5738 +9978 +9979 1 -41969 -41970 +46561 +46562 1 -100036 -100037 +177831 +177832 1 @@ -27534,38 +27957,38 @@ 1 -90 -91 +135 +136 1 -227 -228 +383 +384 1 -776 -777 +1297 +1298 1 -1641 -1642 +3062 +3063 1 -5737 -5738 +9593 +9594 1 -41969 -41970 +46561 +46562 1 -100027 -100028 +169840 +169841 1 @@ -27582,17 +28005,17 @@ 1 2 -64654 +126296 2 3 -39903 +50329 3 -9 -1641 +129 +3333 @@ -27608,17 +28031,17 @@ 1 2 -64663 +133922 2 3 -39894 +42974 3 9 -1641 +3062 @@ -27628,22 +28051,22 @@ implicitly_typed_array_creation -11922 +12576 id -11922 +12576 explicitly_sized_array_creation -1067 +4077 id -1067 +4077 @@ -27692,26 +28115,26 @@ expr_compiler_generated -333735 +593552 id -333735 +593552 expr_value -975810 +1399433 id -975810 +1399433 value -148629 +185734 @@ -27725,7 +28148,7 @@ 1 2 -975810 +1399433 @@ -27741,22 +28164,22 @@ 1 2 -110088 +135437 2 3 -18409 +25714 3 7 -12465 +15324 7 -62610 -7667 +144837 +9259 @@ -27766,15 +28189,15 @@ expr_call -926537 +1347739 caller_id -926537 +1347739 target_id -106839 +157393 @@ -27788,7 +28211,7 @@ 1 2 -926537 +1347739 @@ -27804,32 +28227,32 @@ 1 2 -59013 +85183 2 3 -19203 +29466 3 4 -8209 +12338 4 7 -9384 +14239 7 25 -8038 +11905 25 -32692 -2992 +35631 +4262 @@ -27839,15 +28262,15 @@ expr_access -1851048 +2855307 accesser_id -1851048 +2855307 target_id -493998 +725838 @@ -27861,7 +28284,7 @@ 1 2 -1851048 +2855307 @@ -27877,32 +28300,37 @@ 1 2 -148659 +216414 2 3 -161012 +211536 3 4 -78460 +116569 4 5 -39494 +63157 5 -8 -38236 +7 +55255 -8 -20124 -28137 +7 +24 +54454 + + +24 +20125 +8453 @@ -27912,15 +28340,15 @@ expr_location -4889105 +7417345 id -4889105 +7417345 loc -4391516 +6768067 @@ -27934,7 +28362,7 @@ 1 2 -4889105 +7417345 @@ -27950,17 +28378,17 @@ 1 2 -3970377 +6140047 2 3 -376052 +613291 3 143 -45087 +14729 @@ -27970,11 +28398,11 @@ dynamic_member_name -976 +977 id -976 +977 name @@ -27992,7 +28420,7 @@ 1 2 -976 +977 @@ -28013,12 +28441,12 @@ 2 3 -51 +50 3 4 -30 +31 4 @@ -28043,22 +28471,22 @@ conditional_access -2576 +3445 id -2576 +3445 expr_argument -1169007 +1536561 id -1169007 +1536561 mode @@ -28076,7 +28504,7 @@ 1 2 -1169007 +1536561 @@ -28090,23 +28518,23 @@ 12 -97 -98 +123 +124 1 -5611 -5612 +10881 +10882 1 -10517 -10518 +16880 +16881 1 -1152782 -1152783 +1508677 +1508678 1 @@ -28117,15 +28545,15 @@ expr_argument_name -70217 +75690 id -70217 +75690 name -3869 +4374 @@ -28139,7 +28567,7 @@ 1 2 -70217 +75690 @@ -28155,47 +28583,47 @@ 1 2 -1148 +1356 2 3 -740 +859 3 4 -372 +424 4 5 -300 +327 5 7 -300 +331 7 12 -325 +375 12 -23 -302 +25 +340 -23 -88 -291 +25 +259 +329 -88 -10911 -91 +262 +10879 +33 @@ -32449,11 +32877,11 @@ commentline -348293 +618446 id -348293 +618446 kind @@ -32461,11 +32889,11 @@ text -178314 +304702 rawtext -180589 +309171 @@ -32479,7 +32907,7 @@ 1 2 -348293 +618446 @@ -32495,7 +32923,7 @@ 1 2 -348293 +618446 @@ -32511,7 +32939,7 @@ 1 2 -348293 +618446 @@ -32525,18 +32953,18 @@ 12 -2025 -2026 +12000 +12001 1 -155568 -155569 +276055 +276056 1 -190700 -190701 +330391 +330392 1 @@ -32551,18 +32979,18 @@ 12 -925 -926 +5817 +5818 1 -53848 -53849 +98398 +98399 1 -123958 -123959 +201704 +201705 1 @@ -32577,18 +33005,18 @@ 12 -1024 -1025 +6340 +6341 1 -54132 -54133 +99142 +99143 1 -125433 -125434 +203689 +203690 1 @@ -32605,17 +33033,17 @@ 1 2 -148797 +252156 2 3 -19726 +34923 3 -31960 -9791 +49511 +17623 @@ -32631,12 +33059,12 @@ 1 2 -177910 +303526 2 4 -404 +1176 @@ -32652,12 +33080,12 @@ 1 2 -176699 +301509 2 -52 -1615 +86 +3193 @@ -32673,17 +33101,17 @@ 1 2 -151083 +256975 2 3 -19835 +34845 3 -31893 -9671 +49420 +17351 @@ -32699,7 +33127,7 @@ 1 2 -180589 +309171 @@ -32715,7 +33143,7 @@ 1 2 -180589 +309171 @@ -32725,15 +33153,15 @@ commentline_location -348293 +618446 id -348293 +618446 loc -348293 +618446 @@ -32747,7 +33175,7 @@ 1 2 -348293 +618446 @@ -32763,7 +33191,7 @@ 1 2 -348293 +618446 @@ -32773,26 +33201,26 @@ commentblock -142586 +247138 id -142586 +247138 commentblock_location -142586 +247138 id -142586 +247138 loc -142586 +247138 @@ -32806,7 +33234,7 @@ 1 2 -142586 +247138 @@ -32822,7 +33250,7 @@ 1 2 -142586 +247138 @@ -32832,15 +33260,15 @@ commentblock_binding -447717 +794277 id -142583 +247103 entity -190431 +339770 bindtype @@ -32858,22 +33286,22 @@ 1 2 -51033 +64059 2 3 -24776 +47892 3 4 -63952 +134744 4 -25 -2822 +7 +408 @@ -32889,22 +33317,22 @@ 1 2 -10757 +19446 2 3 -40830 +44772 3 4 -25115 +47839 4 5 -65881 +135046 @@ -32920,22 +33348,17 @@ 1 2 -140143 +247642 2 3 -35948 +67118 3 -68 -14284 - - -69 -1882 -56 +8449 +25010 @@ -32951,22 +33374,22 @@ 1 2 -82511 +146681 2 3 -81857 +146587 3 4 -25421 +45202 4 5 -642 +1300 @@ -32980,23 +33403,23 @@ 12 -70390 -70391 +143047 +143048 1 -101775 -101776 +202047 +202048 1 -127314 -127315 +220046 +220047 1 -131807 -131808 +227551 +227552 1 @@ -33011,23 +33434,23 @@ 12 -52557 -52558 +85120 +85121 1 -70536 -70537 +134653 +134654 1 -100163 -100164 +175047 +175048 1 -101800 -101801 +185841 +185842 1 @@ -33038,19 +33461,19 @@ commentblock_child -347934 +618012 id -142586 +247138 commentline -347934 +618012 index -297 +1135 @@ -33064,27 +33487,32 @@ 1 2 -60572 +119292 2 3 -39466 +47018 3 4 -20594 +42534 4 6 -11412 +19386 6 -298 -10542 +32 +18550 + + +32 +1136 +358 @@ -33100,27 +33528,32 @@ 1 2 -60572 +119292 2 3 -39466 +47018 3 4 -20594 +42534 4 6 -11412 +19386 6 -298 -10542 +32 +18550 + + +32 +1136 +358 @@ -33136,7 +33569,7 @@ 1 2 -347934 +618012 @@ -33152,7 +33585,7 @@ 1 2 -347934 +618012 @@ -33168,42 +33601,37 @@ 1 2 -53 +623 2 3 -115 +73 3 4 -9 +142 4 -6 -26 +9 +56 -6 -10 -25 +9 +12 +101 -10 -40 -23 +12 +95 +86 -42 -216 -23 - - -237 -142587 -23 +96 +247139 +54 @@ -33219,42 +33647,37 @@ 1 2 -53 +623 2 3 -115 +73 3 4 -9 +142 4 -6 -26 +9 +56 -6 -10 -25 +9 +12 +101 -10 -40 -23 +12 +95 +86 -42 -216 -23 - - -237 -142587 -23 +96 +247139 +54 @@ -34804,11 +35227,11 @@ cil_instruction -11738854 +17762677 id -11738854 +17762677 opcode @@ -34820,7 +35243,7 @@ impl -764571 +1075745 @@ -34834,7 +35257,7 @@ 1 2 -11738854 +17762677 @@ -34850,7 +35273,7 @@ 1 2 -11738854 +17762677 @@ -34866,7 +35289,7 @@ 1 2 -11738854 +17762677 @@ -34881,67 +35304,67 @@ 1 -14 +31 16 -16 -50 +34 +103 16 -52 -113 +107 +272 16 -127 -392 +291 +761 16 -402 -805 +786 +1799 16 -882 -1781 +1819 +3232 16 -1840 -3594 +3540 +6280 16 -3656 -7680 +6599 +13336 16 -7691 -15395 +13561 +25517 16 -15628 -41250 +26360 +58843 16 -41579 -101314 +60259 +150959 16 -108039 -267456 +153187 +397705 16 -269151 -1219506 +421486 +1761436 13 @@ -34957,68 +35380,68 @@ 1 -9 +17 +17 + + +19 +53 16 -9 -28 +53 +103 16 -30 -61 +115 +193 16 -65 -116 +202 +296 16 -123 -202 +299 +415 16 -203 -304 -16 - - -304 -401 -16 - - -406 +416 524 16 -526 -686 +551 +705 16 -687 -853 +708 +857 16 -886 -1103 +867 +1037 16 -1135 -1907 +1044 +1359 16 -1974 -3722 -13 +1384 +2339 +16 + + +2493 +4004 +12 @@ -35033,68 +35456,68 @@ 1 -7 +16 16 -7 -21 -17 - - -25 -69 +16 +49 16 -72 -190 +54 +133 16 -214 -466 +148 +476 16 -489 -963 +485 +819 16 -964 -1633 +849 +1544 16 -1646 -4521 +1656 +2600 16 -4775 -9554 +2888 +7581 16 -10805 -22012 +7638 +16576 16 -23094 -44749 +16749 +28630 16 -48809 -119795 +29955 +66775 16 -131667 -534809 -12 +72210 +156029 +16 + + +176525 +758788 +13 @@ -35134,48 +35557,48 @@ 6 -8 +9 248 -8 -9 -336 - - 9 -11 -376 +13 +472 -11 -16 -461 +13 +23 +493 -17 -26 -467 +23 +39 +435 -26 -72 -420 +40 +80 +424 -72 -315 +80 +317 +422 + + +317 +1566 419 -315 -4330 +1569 +92206 419 -4367 -764572 -229 +94672 +1075746 +43 @@ -35206,52 +35629,52 @@ 4 5 -282 +281 5 6 -473 +449 6 -8 -473 - - -8 9 -329 +482 9 -11 -389 +12 +435 -11 -14 -423 +12 +17 +474 -14 -22 -452 +17 +26 +453 -22 -49 -420 +26 +45 +428 -49 -93 -421 +45 +79 +424 -93 -169 -358 +79 +136 +422 + + +136 +175 +172 @@ -35291,48 +35714,48 @@ 6 -8 +9 248 -8 -9 -336 - - 9 -11 -376 +13 +472 -11 -16 -461 +13 +23 +493 -17 -26 -467 +23 +39 +435 -26 -72 -420 +40 +80 +424 -72 -315 +80 +317 +422 + + +317 +1566 419 -315 -4330 +1569 +92206 419 -4367 -764572 -229 +94672 +1075746 +43 @@ -35348,52 +35771,52 @@ 1 2 -20708 +27075 2 3 -239575 +283722 3 4 -95590 +178628 4 5 -54260 +76302 5 7 -62698 +91491 7 10 -62426 +93902 10 15 -62313 +83468 15 26 -60287 +84044 26 53 -58090 +82354 53 5580 -48624 +74759 @@ -35409,57 +35832,57 @@ 1 2 -20708 +27075 2 3 -239654 +284008 3 4 -98321 +190914 4 5 -64878 +92479 5 6 -49135 +60711 6 7 -34933 +48353 7 9 -63779 +90930 9 -12 -58221 +13 +98471 -12 -18 -60506 +13 +20 +84244 -18 -32 -58247 +20 +35 +80775 -32 +35 77 -16189 +17785 @@ -35475,52 +35898,52 @@ 1 2 -20708 +27075 2 3 -239575 +283722 3 4 -95590 +178628 4 5 -54260 +76302 5 7 -62698 +91491 7 10 -62426 +93902 10 15 -62313 +83468 15 26 -60287 +84044 26 53 -58090 +82354 53 5580 -48624 +74759 @@ -35530,15 +35953,15 @@ cil_jump -959958 +1461276 instruction -959958 +1461276 target -753795 +1171285 @@ -35552,7 +35975,7 @@ 1 2 -959958 +1461276 @@ -35568,17 +35991,17 @@ 1 2 -646657 +1023904 2 3 -69975 +95406 3 256 -37163 +51975 @@ -35588,15 +36011,15 @@ cil_access -4229231 +6097501 instruction -4229231 +6097501 target -1029648 +1342773 @@ -35610,7 +36033,7 @@ 1 2 -4229231 +6097501 @@ -35626,37 +36049,37 @@ 1 2 -376838 +400905 2 3 -298666 +452358 3 4 -118675 +149466 4 5 -72560 +105242 5 8 -84020 +116951 8 -125 -77235 +30 +100903 -125 -34817 -1654 +30 +47893 +16948 @@ -35666,15 +36089,15 @@ cil_value -368821 +556329 instruction -368821 +556329 value -61708 +86381 @@ -35688,7 +36111,7 @@ 1 2 -368821 +556329 @@ -35704,32 +36127,32 @@ 1 2 -27735 +37537 2 3 -19017 +26864 3 4 -4145 +6509 4 -7 -5590 +6 +6181 -7 -57 -4629 +6 +18 +6520 -57 -93559 -592 +18 +153323 +2770 @@ -35739,11 +36162,11 @@ cil_switch -128085 +154637 instruction -8423 +11344 index @@ -35751,7 +36174,7 @@ target -46102 +65029 @@ -35770,52 +36193,47 @@ 3 4 -2198 +2846 4 5 -1324 +1845 5 6 -1027 +1459 6 7 -534 +727 7 -8 -473 +9 +1045 -8 -11 -749 +9 +12 +879 -11 -15 -656 +12 +18 +952 -15 -27 -684 +18 +32 +885 -27 -154 -722 - - -154 +32 412 -34 +684 @@ -35831,47 +36249,47 @@ 1 2 -89 +58 2 3 -948 +1036 3 4 -2671 +3463 4 5 -1769 +2605 5 6 -773 +1040 6 7 -509 +700 7 10 -691 +996 10 -17 -670 +16 +862 -17 +16 256 -303 +584 @@ -35916,37 +36334,37 @@ 27 -32 +34 35 -33 -353 +35 +355 32 -354 -370 +356 +376 31 -370 -418 +376 +434 31 -418 -547 +434 +626 31 -554 -6204 +640 +8477 31 -8401 -8424 +11322 +11345 3 @@ -35992,37 +36410,37 @@ 27 -32 +34 35 -33 -353 +35 +355 32 -354 -370 +356 +376 31 -370 -418 +376 +434 31 -418 -538 +434 +617 31 -546 -6052 +632 +8262 31 -8212 -8304 +11061 +11172 3 @@ -36039,12 +36457,12 @@ 1 2 -45517 +64116 2 12 -585 +913 @@ -36060,17 +36478,17 @@ 1 2 -39139 +56028 2 4 -3821 +5079 4 247 -3142 +3922 @@ -36122,15 +36540,15 @@ cil_type_location -152210 +212852 id -89583 +118809 loc -1126 +1701 @@ -36144,22 +36562,27 @@ 1 2 -44965 +52292 2 3 -32740 +50361 3 4 -5869 +6744 4 -10 -6009 +6 +9035 + + +6 +16 +377 @@ -36175,48 +36598,58 @@ 1 2 -432 +464 2 -5 -88 +3 +27 -5 -11 +3 +4 +170 + + +4 +9 +150 + + +9 +14 +130 + + +14 +23 +144 + + +23 +37 +133 + + +37 +66 +128 + + +66 +137 +129 + + +138 +416 +128 + + +434 +11741 98 - -11 -19 -86 - - -19 -33 -85 - - -33 -71 -86 - - -72 -144 -85 - - -144 -447 -85 - - -447 -3291 -81 - @@ -36225,15 +36658,15 @@ cil_method_location -1165492 +1622420 id -726017 +939512 loc -691 +1234 @@ -36247,22 +36680,27 @@ 1 2 -418176 +474427 2 3 -221887 +340605 3 4 -41809 +49527 4 -10 -44145 +6 +71871 + + +6 +16 +3082 @@ -36277,74 +36715,74 @@ 1 -14 -53 - - -14 -32 -55 - - -32 -61 -52 - - -61 -100 -53 - - -100 -154 -53 - - -155 -213 -52 - - -217 -292 -54 - - -295 -415 -52 - - -424 -615 -52 - - -619 -1106 -52 - - -1127 -2065 -52 - - -2113 -4064 -52 - - -4078 -25628 -52 - - -28337 -33613 +2 7 + +2 +3 +130 + + +3 +17 +94 + + +17 +44 +95 + + +44 +78 +95 + + +78 +121 +96 + + +122 +179 +93 + + +180 +247 +94 + + +248 +360 +93 + + +362 +520 +94 + + +520 +887 +93 + + +887 +1666 +93 + + +1683 +5309 +93 + + +5436 +59205 +64 + @@ -36353,15 +36791,15 @@ cil_type -343192 +310744 id -343192 +310744 name -53588 +69903 kind @@ -36369,11 +36807,11 @@ parent -91545 +54196 sourceDecl -197636 +189847 @@ -36387,7 +36825,7 @@ 1 2 -343192 +310744 @@ -36403,7 +36841,7 @@ 1 2 -343192 +310744 @@ -36419,7 +36857,7 @@ 1 2 -343192 +310744 @@ -36435,7 +36873,7 @@ 1 2 -343192 +310744 @@ -36451,27 +36889,22 @@ 1 2 -37936 +41024 2 3 -7739 +18965 3 -4 -2848 +5 +5619 -4 -9 -4115 - - -9 -73139 -950 +5 +33435 +4295 @@ -36487,7 +36920,7 @@ 1 2 -53588 +69903 @@ -36503,17 +36936,17 @@ 1 2 -46572 +60864 2 3 -4953 +6391 3 -73139 -2063 +33435 +2648 @@ -36529,22 +36962,22 @@ 1 2 -39647 +42608 2 3 -7512 +19051 3 -5 -4604 +6 +6151 -5 -73139 -1825 +6 +33435 +2093 @@ -36558,23 +36991,23 @@ 12 -440 -441 +638 +639 1 -8222 -8223 +6961 +6962 1 -98272 -98273 +53658 +53659 1 -236158 -236159 +249378 +249379 1 @@ -36594,18 +37027,18 @@ 1 -350 -351 +447 +448 1 -1788 -1789 +2112 +2113 1 -51410 -51411 +67304 +67305 1 @@ -36625,18 +37058,18 @@ 1 -139 -140 +200 +201 1 -19206 -19207 +21759 +21760 1 -73138 -73139 +33434 +33435 1 @@ -36651,23 +37084,23 @@ 12 -440 -441 +638 +639 1 -7605 -7606 +6112 +6113 1 -91319 -91320 +53658 +53659 1 -98272 -98273 +129439 +129440 1 @@ -36684,22 +37117,22 @@ 1 2 -69148 +36999 2 3 -15292 +8838 3 -70 -6868 +6 +4361 -70 -54255 -237 +6 +39242 +3998 @@ -36715,17 +37148,22 @@ 1 2 -69364 +37293 2 3 -15415 +8985 3 -2161 -6766 +6 +4275 + + +6 +2536 +3643 @@ -36741,12 +37179,12 @@ 1 2 -90607 +52999 2 4 -938 +1197 @@ -36762,17 +37200,22 @@ 1 2 -69323 +37238 2 3 -15415 +8978 3 -9130 -6807 +6 +4253 + + +6 +8395 +3727 @@ -36788,12 +37231,12 @@ 1 2 -191008 +181709 2 -11648 -6628 +5085 +8138 @@ -36809,7 +37252,7 @@ 1 2 -197636 +189847 @@ -36825,7 +37268,7 @@ 1 2 -197636 +189847 @@ -36841,12 +37284,12 @@ 1 2 -195187 +186967 2 491 -2449 +2880 @@ -36856,15 +37299,15 @@ cil_pointer_type -440 +638 id -440 +638 pointee -440 +638 @@ -36878,7 +37321,7 @@ 1 2 -440 +638 @@ -36894,7 +37337,7 @@ 1 2 -440 +638 @@ -36904,15 +37347,15 @@ cil_array_type -8222 +6961 id -8222 +6961 element_type -8198 +6928 rank @@ -36930,7 +37373,7 @@ 1 2 -8222 +6961 @@ -36946,7 +37389,7 @@ 1 2 -8222 +6961 @@ -36962,12 +37405,12 @@ 1 2 -8176 +6898 2 4 -22 +30 @@ -36983,12 +37426,12 @@ 1 2 -8176 +6898 2 4 -22 +30 @@ -37002,18 +37445,18 @@ 12 -4 -5 +8 +9 1 -26 -27 +31 +32 1 -8192 -8193 +6922 +6923 1 @@ -37028,18 +37471,18 @@ 12 -4 -5 +8 +9 1 -26 -27 +31 +32 1 -8192 -8193 +6922 +6923 1 @@ -37050,23 +37493,23 @@ cil_method -982868 +1164170 id -982868 +1164170 name -161199 +196164 parent -136179 +166238 return_type -109834 +90658 @@ -37080,7 +37523,7 @@ 1 2 -982868 +1164170 @@ -37096,7 +37539,7 @@ 1 2 -982868 +1164170 @@ -37112,7 +37555,7 @@ 1 2 -982868 +1164170 @@ -37128,32 +37571,32 @@ 1 2 -84543 +91448 2 3 -36569 +46810 3 4 -10379 +18752 4 6 -12506 +15548 6 -16 -12221 +13 +15554 -16 -109404 -4981 +13 +131916 +8052 @@ -37169,32 +37612,32 @@ 1 2 -89508 +96428 2 3 -35748 +46661 3 4 -9567 +17952 4 6 -11701 +14538 6 -23 -12183 +15 +14970 -23 -87224 -2492 +15 +103427 +5615 @@ -37210,22 +37653,17 @@ 1 2 -133751 +162790 2 3 -15357 +19275 3 -6995 -12090 - - -7095 -7096 -1 +7390 +14099 @@ -37241,42 +37679,47 @@ 1 2 -40455 +46618 2 3 -26404 +31338 3 4 -16912 +20193 4 5 -10810 +14379 5 7 -11129 +14505 7 10 -10666 +13582 10 -18 -10760 +17 +12893 -18 -13475 -9043 +17 +197 +12468 + + +197 +6088 +262 @@ -37292,42 +37735,47 @@ 1 2 -42239 +48881 2 3 -27319 +32472 3 4 -17627 +20980 4 5 -11309 +14854 5 -7 -12205 +6 +8121 -7 -11 -11242 +6 +8 +12842 -11 -26 -10224 +8 +13 +13194 -26 +13 +43 +12517 + + +43 3766 -4014 +2377 @@ -37343,37 +37791,37 @@ 1 2 -54109 +63599 2 3 -33724 +40692 3 4 -17338 +22116 4 5 -8609 +11345 5 7 -11498 +14610 7 -27 -10243 +20 +12473 -27 -7169 -658 +20 +3066 +1403 @@ -37389,27 +37837,32 @@ 1 2 -75434 +49584 2 3 -15073 +17237 3 -5 -8716 +4 +7858 -5 -20 -8307 +4 +7 +7467 -20 -322198 -2304 +7 +31 +6851 + + +31 +402822 +1661 @@ -37425,22 +37878,27 @@ 1 2 -83942 +61071 2 3 -13387 +15140 3 -7 -8631 +5 +7349 -7 -43617 -3874 +5 +60 +6802 + + +60 +53362 +296 @@ -37456,22 +37914,27 @@ 1 2 -81013 +55043 2 3 -14595 +16656 3 -6 -9185 +4 +7537 -6 -101084 -5041 +4 +8 +7186 + + +8 +123711 +4236 @@ -37481,15 +37944,15 @@ cil_method_source_declaration -891568 +1075007 method -891568 +1075007 source -785482 +976101 @@ -37503,7 +37966,7 @@ 1 2 -891568 +1075007 @@ -37519,17 +37982,12 @@ 1 2 -709384 +933517 2 -3 -65448 - - -3 -306 -10650 +565 +42584 @@ -37539,19 +37997,19 @@ cil_method_implementation -1040241 +1351436 id -1040241 +1351436 method -647453 +788230 location -659 +1200 @@ -37565,7 +38023,7 @@ 1 2 -1040241 +1351436 @@ -37581,7 +38039,7 @@ 1 2 -1040241 +1351436 @@ -37597,22 +38055,27 @@ 1 2 -369448 +419065 2 3 -203313 +258887 3 4 -36064 +43514 4 -10 -38628 +6 +63854 + + +6 +16 +2910 @@ -37628,22 +38091,27 @@ 1 2 -369448 +419085 2 3 -203313 +258867 3 4 -36064 +43514 4 -10 -38628 +6 +63854 + + +6 +16 +2910 @@ -37658,73 +38126,73 @@ 1 -12 -50 +2 +13 -12 -31 -52 +2 +3 +131 -31 -54 -51 +3 +17 +93 -54 -87 -50 +18 +42 +90 -89 -143 -50 +42 +73 +91 -143 -204 -51 +73 +109 +90 -208 -270 -51 +109 +172 +90 -270 -371 -50 +174 +225 +91 -376 -540 -51 +225 +328 +90 -550 -1119 -51 +329 +450 +90 -1120 -2075 -50 +451 +834 +90 -2100 -4503 -50 +840 +1640 +90 -4651 -32572 -50 +1642 +4858 +90 -32984 +5076 33031 -2 +61 @@ -37739,73 +38207,73 @@ 1 -12 -50 +2 +13 -12 -31 -52 +2 +3 +131 -31 -54 -51 +3 +17 +93 -54 -87 -50 +18 +42 +90 -89 -143 -50 +42 +73 +91 -143 -204 -51 +73 +109 +90 -208 -270 -51 +109 +172 +90 -270 -371 -50 +174 +225 +91 -376 -540 -51 +225 +328 +90 -550 -1119 -51 +329 +450 +90 -1120 -2075 -50 +451 +834 +90 -2100 -4503 -50 +840 +1640 +90 -4651 -32572 -50 +1642 +4858 +90 -32984 +5076 33031 -2 +61 @@ -37815,15 +38283,15 @@ cil_implements -46066 +77303 id -43911 +74672 decl -11125 +32636 @@ -37837,12 +38305,12 @@ 1 2 -42414 +72729 2 5 -1497 +1943 @@ -37858,22 +38326,22 @@ 1 2 -7900 +27601 2 3 -1673 +2530 3 -6 -904 +85 +2450 -6 +86 2300 -648 +55 @@ -37883,23 +38351,23 @@ cil_field -373454 +459117 id -373454 +459117 parent -63864 +78097 name -141811 +163874 field_type -55057 +66956 @@ -37913,7 +38381,7 @@ 1 2 -373454 +459117 @@ -37929,7 +38397,7 @@ 1 2 -373454 +459117 @@ -37945,7 +38413,7 @@ 1 2 -373454 +459117 @@ -37961,47 +38429,47 @@ 1 2 -16008 +18670 2 3 -13743 +16155 3 4 -7634 +9581 4 5 -6078 +7771 5 6 -4068 +5300 6 8 -5334 +6837 8 12 -5499 +6885 12 -34 -4814 +33 +5931 -34 +33 4792 -686 +967 @@ -38017,47 +38485,47 @@ 1 2 -16008 +18670 2 3 -13743 +16155 3 4 -7634 +9581 4 5 -6078 +7771 5 6 -4068 +5300 6 8 -5334 +6837 8 12 -5499 +6885 12 -34 -4814 +33 +5931 -34 +33 4792 -686 +967 @@ -38073,37 +38541,37 @@ 1 2 -19045 +22569 2 3 -22202 +28213 3 4 -7167 +8776 4 5 -4134 +5004 5 7 -4819 +5963 7 13 -4989 +5897 13 -172 -1508 +569 +1675 @@ -38119,22 +38587,22 @@ 1 2 -96617 +105589 2 3 -24916 +32731 3 5 -11640 +13968 5 -7385 -8638 +10637 +11586 @@ -38150,22 +38618,22 @@ 1 2 -96617 +105589 2 3 -24916 +32731 3 5 -11640 +13968 5 -7385 -8638 +10637 +11586 @@ -38181,22 +38649,22 @@ 1 2 -111626 +125364 2 3 -18303 +23735 3 -12 -10801 +10 +12597 -12 -4061 -1081 +10 +4427 +2178 @@ -38212,32 +38680,37 @@ 1 2 -27378 +32076 2 3 -12337 +15156 3 4 -3618 +4604 4 -6 -4812 +5 +4144 -6 -13 -4248 +5 +9 +5779 -13 -49751 -2664 +9 +160 +5023 + + +161 +63270 +174 @@ -38253,22 +38726,22 @@ 1 2 -34264 +41592 2 3 -12721 +15722 3 5 -4135 +5025 5 -21009 -3937 +27862 +4617 @@ -38284,27 +38757,32 @@ 1 2 -36493 +43052 2 3 -6728 +8271 3 4 -3371 +4356 4 7 -4516 +6059 7 -23165 -3949 +89 +5022 + + +90 +25354 +196 @@ -38314,15 +38792,15 @@ cil_parameter -1904597 +2241273 id -1904597 +2241273 method -921545 +1091090 index @@ -38330,7 +38808,7 @@ param_type -233580 +227413 @@ -38344,7 +38822,7 @@ 1 2 -1904597 +2241273 @@ -38360,7 +38838,7 @@ 1 2 -1904597 +2241273 @@ -38376,7 +38854,7 @@ 1 2 -1904597 +2241273 @@ -38392,27 +38870,27 @@ 1 2 -373799 +457241 2 3 -323581 +371753 3 4 -133559 +150895 4 7 -74604 +92314 7 53 -16002 +18887 @@ -38428,27 +38906,27 @@ 1 2 -373799 +457241 2 3 -323581 +371753 3 4 -133559 +150895 4 7 -74604 +92314 7 53 -16002 +18887 @@ -38464,27 +38942,27 @@ 1 2 -397141 +478810 2 3 -328789 +381799 3 4 -125672 +146612 4 -11 -69153 +10 +82574 -11 +10 41 -790 +1295 @@ -38508,58 +38986,58 @@ 11 -12 -13 +10 +11 3 -15 -16 +13 +14 3 -16 -28 +14 +30 4 -36 -58 +38 +62 4 -64 -98 +68 +105 4 -114 -197 +123 +217 4 -241 -572 +265 +641 4 -786 -2257 +877 +2572 4 -3431 -16003 +3932 +18888 4 -27777 -224166 +33136 +262097 4 -547746 -921546 +633849 +1091091 2 @@ -38584,58 +39062,58 @@ 11 -12 -13 +10 +11 3 -15 -16 +13 +14 3 -16 -28 +14 +30 4 -36 -58 +38 +62 4 -64 -98 +68 +105 4 -114 -197 +123 +217 4 -241 -572 +265 +641 4 -786 -2257 +877 +2572 4 -3431 -16003 +3932 +18888 4 -27777 -224166 +33136 +262097 4 -547746 -921546 +633849 +1091091 2 @@ -38660,53 +39138,53 @@ 2 -9 -10 +7 +8 5 -13 -21 +11 +19 4 -21 -31 +19 +30 4 -31 -39 +30 +38 4 -51 -67 +50 +71 4 -83 -176 +90 +194 4 -233 -501 +256 +552 4 -666 -1923 +744 +2266 4 -2805 -10797 +3354 +12987 4 -36393 -175126 +35950 +179765 3 @@ -38723,37 +39201,42 @@ 1 2 -98696 +67477 2 3 -47541 +53744 3 4 -20497 +22720 4 -6 -21504 +5 +15429 -6 -10 -19815 +5 +7 +20114 -10 -27 -17540 +7 +11 +19073 -27 -99475 -7987 +11 +24 +17383 + + +24 +127666 +11473 @@ -38769,37 +39252,42 @@ 1 2 -103646 +68945 2 3 -45853 +53403 3 4 -18465 +22604 4 -6 -21100 +5 +15196 -6 -10 -19543 +5 +7 +20025 -10 -28 -17569 +7 +11 +18906 -28 -80024 -7404 +11 +24 +17145 + + +24 +101271 +11189 @@ -38815,22 +39303,22 @@ 1 2 -170930 +161358 2 3 -42071 +44633 3 -6 -18729 +5 +17710 -6 +5 51 -1850 +3712 @@ -38840,37 +39328,37 @@ cil_parameter_in -23105 +55741 id -23105 +55741 cil_parameter_out -31233 +39090 id -31233 +39090 cil_setter -30179 +44695 prop -30179 +44695 method -30179 +44695 @@ -38884,7 +39372,7 @@ 1 2 -30179 +44695 @@ -38900,7 +39388,7 @@ 1 2 -30179 +44695 @@ -38910,15 +39398,15 @@ cil_getter -165951 +232515 prop -165951 +232515 method -165951 +232515 @@ -38932,7 +39420,7 @@ 1 2 -165951 +232515 @@ -38948,7 +39436,7 @@ 1 2 -165951 +232515 @@ -38958,15 +39446,15 @@ cil_adder -3719 +6369 event -3719 +6369 method -3719 +6369 @@ -38980,7 +39468,7 @@ 1 2 -3719 +6369 @@ -38996,7 +39484,7 @@ 1 2 -3719 +6369 @@ -39006,15 +39494,15 @@ cil_remover -3719 +6369 event -3719 +6369 method -3719 +6369 @@ -39028,7 +39516,7 @@ 1 2 -3719 +6369 @@ -39044,7 +39532,7 @@ 1 2 -3719 +6369 @@ -39102,23 +39590,23 @@ cil_property -166215 +232995 id -166215 +232995 parent -32452 +45688 name -46487 +60870 property_type -17696 +23848 @@ -39132,7 +39620,7 @@ 1 2 -166215 +232995 @@ -39148,7 +39636,7 @@ 1 2 -166215 +232995 @@ -39164,7 +39652,7 @@ 1 2 -166215 +232995 @@ -39180,42 +39668,42 @@ 1 2 -10930 +13054 2 3 -6385 +11267 3 4 -4050 +5670 4 5 -2722 +3802 5 -7 -2979 +6 +2462 -7 -11 -2655 +6 +8 +3199 -11 -39 -2439 +8 +14 +3555 -39 +14 3766 -292 +2679 @@ -39231,42 +39719,42 @@ 1 2 -10954 +15338 2 3 -6401 +9095 3 4 -4029 +5624 4 5 -2725 +3819 5 -7 -2999 +6 +2437 -7 -11 -2625 +6 +8 +3322 -11 -40 -2447 +8 +14 +3455 -40 +14 3766 -272 +2598 @@ -39282,32 +39770,32 @@ 1 2 -13163 +16716 2 3 -7694 +12911 3 4 -4314 +5999 4 5 -2403 +3365 5 8 -2921 +4175 8 50 -1957 +2522 @@ -39323,27 +39811,27 @@ 1 2 -27082 +31483 2 3 -10143 +16819 3 4 -2363 +2816 4 7 -3703 +5360 7 -2519 -3196 +5089 +4392 @@ -39359,27 +39847,27 @@ 1 2 -27082 +31483 2 3 -10143 +16827 3 4 -2363 +2821 4 7 -3704 +5354 7 -2519 -3195 +3124 +4385 @@ -39395,22 +39883,17 @@ 1 2 -39411 +51983 2 3 -3424 +4636 3 -17 -3493 - - -17 -1131 -159 +1437 +4251 @@ -39426,32 +39909,32 @@ 1 2 -10530 +12810 2 3 -2911 +5226 3 4 -1198 +1491 4 7 -1425 +2148 7 -40 -1336 +39 +1797 -40 -32241 -296 +39 +49263 +376 @@ -39467,27 +39950,32 @@ 1 2 -11216 +13648 2 3 -2687 +5033 3 4 -1142 +1436 4 -8 -1460 +7 +1894 -8 -10207 -1191 +7 +149 +1789 + + +152 +13924 +48 @@ -39503,22 +39991,22 @@ 1 2 -13415 +18376 2 3 -2299 +2969 3 -7 -1412 +8 +1886 -7 -13568 -570 +8 +21084 +617 @@ -39528,23 +40016,23 @@ cil_event -3719 +6340 id -3719 +6340 parent -1117 +2205 name -1471 +2130 event_type -1015 +1978 @@ -39558,7 +40046,7 @@ 1 2 -3719 +6340 @@ -39574,7 +40062,7 @@ 1 2 -3719 +6340 @@ -39590,7 +40078,7 @@ 1 2 -3719 +6340 @@ -39606,32 +40094,32 @@ 1 2 -565 +1143 2 3 -227 +438 3 4 -100 +212 4 -6 -97 +5 +115 -6 -14 -85 +5 +8 +168 -14 +8 127 -43 +129 @@ -39647,32 +40135,32 @@ 1 2 -565 +1143 2 3 -227 +438 3 4 -100 +212 4 -6 -97 +5 +115 -6 -14 -85 +5 +8 +168 -14 +8 127 -43 +129 @@ -39688,27 +40176,27 @@ 1 2 -702 +1402 2 3 -194 +372 3 4 -87 +198 4 -7 -90 +8 +176 -7 +8 39 -44 +57 @@ -39724,32 +40212,32 @@ 1 2 -816 +749 2 3 -268 +792 3 4 -130 +112 4 5 -117 +209 5 -15 -114 +9 +173 -15 -77 -26 +9 +88 +95 @@ -39765,32 +40253,32 @@ 1 2 -816 +749 2 3 -268 +792 3 4 -130 +112 4 5 -117 +209 5 -15 -114 +9 +173 -15 -77 -26 +9 +88 +95 @@ -39806,22 +40294,22 @@ 1 2 -1198 +1642 2 3 -103 +224 3 -4 -126 +5 +181 -4 -18 -44 +5 +25 +83 @@ -39837,27 +40325,27 @@ 1 2 -543 +647 2 3 -263 +984 3 4 -52 +58 4 6 -80 +148 6 1055 -77 +141 @@ -39873,27 +40361,22 @@ 1 2 -659 +784 2 3 -203 +999 3 -4 -53 - - -4 7 -78 +165 7 349 -22 +30 @@ -39909,17 +40392,17 @@ 1 2 -800 +1626 2 3 -139 +220 3 433 -76 +132 @@ -39929,15 +40412,15 @@ cil_local_variable -624672 +989635 id -624672 +989635 impl -195943 +292891 index @@ -39945,7 +40428,7 @@ var_type -55931 +69258 @@ -39959,7 +40442,7 @@ 1 2 -624672 +989635 @@ -39975,7 +40458,7 @@ 1 2 -624672 +989635 @@ -39991,7 +40474,7 @@ 1 2 -624672 +989635 @@ -40007,37 +40490,37 @@ 1 2 -90782 +132499 2 3 -33013 +49612 3 4 -20310 +30061 4 5 -12895 +19183 5 7 -16152 +24373 7 12 -15274 +23871 12 286 -7517 +13292 @@ -40053,37 +40536,37 @@ 1 2 -90782 +132499 2 3 -33013 +49612 3 4 -20310 +30061 4 5 -12895 +19183 5 7 -16152 +24373 7 12 -15274 +23871 12 286 -7517 +13292 @@ -40099,32 +40582,32 @@ 1 2 -98633 +147882 2 3 -40155 +63289 3 4 -20365 +30966 4 5 -12225 +17823 5 8 -16632 +23050 8 62 -7933 +9881 @@ -40145,38 +40628,53 @@ 2 3 -144 - - -3 -5 26 -5 -12 +4 +5 +88 + + +6 +7 +4 + + +8 +9 +26 + + +10 +16 +24 + + +17 +33 +23 + + +34 +97 22 -14 -46 +100 +415 22 -48 -173 +435 +2748 22 -181 -1532 +3102 +292892 22 - -1743 -195944 -21 - @@ -40196,38 +40694,53 @@ 2 3 -144 - - -3 -5 26 -5 -12 +4 +5 +88 + + +6 +7 +4 + + +8 +9 +26 + + +10 +16 +24 + + +17 +33 +23 + + +34 +97 22 -14 -46 +100 +415 22 -48 -173 +435 +2748 22 -181 -1532 +3102 +292892 22 - -1743 -195944 -21 - @@ -40242,47 +40755,52 @@ 1 2 -85 +12 2 3 -66 +85 3 4 -15 +49 4 -6 +7 25 -6 -17 +7 +10 23 -17 -38 +10 +28 22 -41 -293 +28 +79 22 -305 -6526 +81 +459 22 -8789 -32764 -5 +503 +13334 +22 + + +16802 +40620 +3 @@ -40298,37 +40816,37 @@ 1 2 -25298 +28957 2 3 -13407 +17276 3 4 -3534 +4168 4 6 -4383 +6351 6 -11 -4499 +10 +5195 -11 -72 -4201 +10 +33 +5228 -72 -121017 -609 +33 +279245 +2083 @@ -40344,32 +40862,37 @@ 1 2 -27445 +31734 2 3 -12868 +16810 3 4 -3534 +4152 4 6 -3993 +5775 6 12 -4215 +5561 12 -55100 -3876 +1221 +5195 + + +1227 +109010 +31 @@ -40385,27 +40908,27 @@ 1 2 -33173 +40009 2 3 -10821 +13804 3 4 -4081 +5323 4 7 -4716 +6061 7 -277 -3140 +279 +4061 @@ -40415,19 +40938,19 @@ cil_handler -38721 +54069 id -38721 +54069 impl -27322 +38434 index -19 +26 kind @@ -40435,15 +40958,15 @@ try_start -37216 +51487 try_end -37715 +52378 handler_start -38721 +54069 @@ -40457,7 +40980,7 @@ 1 2 -38721 +54069 @@ -40473,7 +40996,7 @@ 1 2 -38721 +54069 @@ -40489,7 +41012,7 @@ 1 2 -38721 +54069 @@ -40505,7 +41028,7 @@ 1 2 -38721 +54069 @@ -40521,7 +41044,7 @@ 1 2 -38721 +54069 @@ -40537,7 +41060,7 @@ 1 2 -38721 +54069 @@ -40553,22 +41076,22 @@ 1 2 -20370 +28919 2 3 -4581 +6239 3 6 -2137 +2953 6 -20 -234 +27 +323 @@ -40584,22 +41107,22 @@ 1 2 -20370 +28919 2 3 -4581 +6239 3 6 -2137 +2953 6 -20 -234 +27 +323 @@ -40615,17 +41138,17 @@ 1 2 -24183 +34351 2 3 -2974 +3890 3 4 -165 +193 @@ -40641,17 +41164,17 @@ 1 2 -20998 +30073 2 3 -4347 +5801 3 20 -1977 +2560 @@ -40667,22 +41190,17 @@ 1 2 -20729 +29584 2 3 -4509 +6080 3 -9 -2050 - - -9 20 -34 +2770 @@ -40698,22 +41216,22 @@ 1 2 -20370 +28919 2 3 -4581 +6239 3 6 -2137 +2953 6 -20 -234 +27 +323 @@ -40727,208 +41245,148 @@ 12 -1 -2 -2 - - -2 -3 -2 - - -3 -4 -1 - - -4 -5 -1 - - -10 -11 -1 - - -20 -21 -1 - - -27 -28 -1 - - -30 -31 -1 - - -42 -43 -1 - - -81 -82 -1 - - -135 -136 -1 - - -234 -235 -1 - - -467 -468 -1 - - -1017 -1018 -1 - - -2371 -2372 -1 - - -6952 -6953 -1 - - -27322 -27323 -1 - - - - - - -index -impl - - -12 - - -1 -2 -2 - - -2 -3 -2 - - -3 -4 -1 - - -4 -5 -1 - - -10 -11 -1 - - -20 -21 -1 - - -27 -28 -1 - - -30 -31 -1 - - -42 -43 -1 - - -81 -82 -1 - - -135 -136 -1 - - -234 -235 -1 - - -467 -468 -1 - - -1017 -1018 -1 - - -2371 -2372 -1 - - -6952 -6953 -1 - - -27322 -27323 -1 - - - - - - -index -kind - - -12 - - -1 -2 -2 - - 2 3 7 +4 +5 +2 + + +5 +6 +2 + + +6 +8 +2 + + +13 +25 +2 + + +31 +43 +2 + + +60 +112 +2 + + +184 +324 +2 + + +620 +1392 +2 + + +3276 +9516 +2 + + +38434 +38435 +1 + + + + + + +index +impl + + +12 + + +2 +3 +7 + + +4 +5 +2 + + +5 +6 +2 + + +6 +8 +2 + + +13 +25 +2 + + +31 +43 +2 + + +60 +112 +2 + + +184 +324 +2 + + +620 +1392 +2 + + +3276 +9516 +2 + + +38434 +38435 +1 + + + + + + +index +kind + + +12 + + +1 +2 +7 + + +2 +3 +9 + + 3 4 5 @@ -40950,88 +41408,58 @@ 12 -1 -2 -2 - - 2 3 -2 - - -3 -4 -1 +7 4 5 -1 +2 -10 -11 -1 +5 +6 +2 -20 -21 -1 +6 +8 +2 -27 -28 -1 +13 +25 +2 -30 -31 -1 - - -42 +31 43 -1 +2 -81 -82 -1 +60 +112 +2 -135 -136 -1 +184 +324 +2 -234 -235 -1 +620 +1392 +2 -467 -468 -1 +3276 +9516 +2 -1017 -1018 -1 - - -2371 -2372 -1 - - -6952 -6953 -1 - - -27322 -27323 +38434 +38435 1 @@ -41046,88 +41474,58 @@ 12 -1 -2 -2 - - 2 3 -2 - - -3 -4 -1 +7 4 5 -1 +2 -10 -11 -1 +5 +6 +2 -20 -21 -1 +6 +8 +2 -27 -28 -1 +13 +25 +2 -30 -31 -1 - - -42 +31 43 -1 +2 -81 -82 -1 +60 +112 +2 -135 -136 -1 +184 +324 +2 -234 -235 -1 +620 +1392 +2 -467 -468 -1 +3276 +9516 +2 -1017 -1018 -1 - - -2371 -2372 -1 - - -6952 -6953 -1 - - -27322 -27323 +38434 +38435 1 @@ -41142,88 +41540,58 @@ 12 -1 -2 -2 - - 2 3 -2 - - -3 -4 -1 +7 4 5 -1 +2 -10 -11 -1 +5 +6 +2 -20 -21 -1 +6 +8 +2 -27 -28 -1 +13 +25 +2 -30 -31 -1 - - -42 +31 43 -1 +2 -81 -82 -1 +60 +112 +2 -135 -136 -1 +184 +324 +2 -234 -235 -1 +620 +1392 +2 -467 -468 -1 +3276 +9516 +2 -1017 -1018 -1 - - -2371 -2372 -1 - - -6952 -6953 -1 - - -27322 -27323 +38434 +38435 1 @@ -41238,23 +41606,23 @@ 12 -742 -743 +901 +902 1 -799 -800 +931 +932 1 -10888 -10889 +16252 +16253 1 -26292 -26293 +35985 +35986 1 @@ -41269,23 +41637,23 @@ 12 -698 -699 +849 +850 1 -799 -800 +931 +932 1 -9008 -9009 +13194 +13195 1 -20121 -20122 +27736 +27737 1 @@ -41310,15 +41678,15 @@ 1 -17 -18 -1 - - 19 20 1 + +26 +27 +1 + @@ -41331,23 +41699,23 @@ 12 -730 -731 +888 +889 1 -799 -800 +931 +932 1 -9963 -9964 +14647 +14648 1 -26282 -26283 +35975 +35976 1 @@ -41362,23 +41730,23 @@ 12 -730 -731 +888 +889 1 -799 -800 +931 +932 1 -9978 -9979 +14662 +14663 1 -26292 -26293 +35985 +35986 1 @@ -41393,23 +41761,23 @@ 12 -742 -743 +901 +902 1 -799 -800 +931 +932 1 -10888 -10889 +16252 +16253 1 -26292 -26293 +35985 +35986 1 @@ -41426,12 +41794,12 @@ 1 2 -36056 +49479 2 10 -1160 +2008 @@ -41447,7 +41815,7 @@ 1 2 -37216 +51487 @@ -41463,12 +41831,12 @@ 1 2 -36056 +49479 2 10 -1160 +2008 @@ -41484,12 +41852,12 @@ 1 2 -36674 +50549 2 4 -542 +938 @@ -41505,12 +41873,12 @@ 1 2 -36727 +50606 2 4 -489 +881 @@ -41526,12 +41894,12 @@ 1 2 -36056 +49479 2 10 -1160 +2008 @@ -41547,12 +41915,12 @@ 1 2 -36999 +51177 2 9 -716 +1201 @@ -41568,7 +41936,7 @@ 1 2 -37715 +52378 @@ -41584,12 +41952,12 @@ 1 2 -36999 +51177 2 9 -716 +1201 @@ -41605,12 +41973,12 @@ 1 2 -37631 +52290 2 3 -84 +88 @@ -41626,7 +41994,7 @@ 1 2 -37715 +52378 @@ -41642,12 +42010,12 @@ 1 2 -36999 +51177 2 9 -716 +1201 @@ -41663,7 +42031,7 @@ 1 2 -38721 +54069 @@ -41679,7 +42047,7 @@ 1 2 -38721 +54069 @@ -41695,7 +42063,7 @@ 1 2 -38721 +54069 @@ -41711,7 +42079,7 @@ 1 2 -38721 +54069 @@ -41727,7 +42095,7 @@ 1 2 -38721 +54069 @@ -41743,7 +42111,7 @@ 1 2 -38721 +54069 @@ -41753,15 +42121,15 @@ cil_handler_filter -742 +901 id -742 +901 filter_start -742 +901 @@ -41775,7 +42143,7 @@ 1 2 -742 +901 @@ -41791,7 +42159,7 @@ 1 2 -742 +901 @@ -41801,15 +42169,15 @@ cil_handler_type -10888 +16252 id -10888 +16252 catch_type -300 +441 @@ -41823,7 +42191,7 @@ 1 2 -10888 +16252 @@ -41839,47 +42207,52 @@ 1 2 -80 +102 2 3 -55 +78 3 4 -23 +32 4 5 -28 +43 5 8 -24 +36 8 12 -23 +40 12 -22 -25 +20 +34 -22 -56 -23 +20 +40 +35 -58 -3349 -19 +42 +268 +34 + + +299 +3353 +7 @@ -41889,11 +42262,11 @@ cil_method_stack_size -1040241 +1351436 method -1040241 +1351436 size @@ -41911,7 +42284,7 @@ 1 2 -1040241 +1351436 @@ -41942,37 +42315,42 @@ 10 12 -4 +2 12 -18 +13 +3 + + +15 +38 4 -33 -78 +58 +146 4 -134 -816 +166 +910 4 -831 -3809 +1406 +8644 4 -6693 -22107 +16282 +39542 4 -25517 -830206 -4 +74163 +1041565 +3 @@ -41982,169 +42360,169 @@ cil_public -681979 +883904 id -681979 +883904 cil_private -405970 +508798 id -405970 +508798 cil_protected -663333 +856296 id -663333 +856296 cil_internal -42022 +51633 id -42022 +51633 cil_static -422704 +459535 id -422704 +459535 cil_sealed -131092 +184038 id -131092 +184038 cil_virtual -276040 +375107 id -276040 +375107 cil_abstract -76553 +118976 id -76553 +118976 cil_class -89583 +103798 id -89583 +103798 cil_interface -8115 +15011 id -8115 +15011 cil_security -3903 +3935 id -3903 +3935 cil_requiresecobject -48 +72 id -48 +72 cil_specialname -310527 +415805 id -310527 +415805 cil_newslot -166898 +243445 id -166898 +243445 cil_base_class -85560 +108602 id -85560 +108602 base -7154 +8840 @@ -42158,7 +42536,7 @@ 1 2 -85560 +108602 @@ -42174,32 +42552,32 @@ 1 2 -3312 +4177 2 3 -1950 +2267 3 4 -634 +795 4 6 -564 +714 6 -24 -539 +20 +668 -24 -36427 -155 +20 +45957 +219 @@ -42209,15 +42587,15 @@ cil_base_interface -40265 +52126 id -19132 +25869 base -10540 +16465 @@ -42231,32 +42609,32 @@ 1 2 -11711 +16163 2 3 -2772 +3920 3 4 -1643 +2150 4 5 -466 +687 5 -6 -1645 +7 +2240 -6 -47 -895 +7 +49 +709 @@ -42272,22 +42650,22 @@ 1 2 -7652 +12889 2 3 -1307 +1648 3 -5 -835 +7 +1293 -5 +7 2300 -746 +635 @@ -42297,11 +42675,11 @@ cil_type_parameter -98272 +53658 unbound -73138 +33434 index @@ -42309,7 +42687,7 @@ param -98272 +53658 @@ -42323,17 +42701,17 @@ 1 2 -57933 +24838 2 3 -12999 +6183 3 41 -2206 +2413 @@ -42349,17 +42727,17 @@ 1 2 -57933 +24838 2 3 -12999 +6183 3 41 -2206 +2413 @@ -42373,48 +42751,48 @@ 12 -6 -7 +4 +5 16 -8 -11 +6 +9 3 -30 -71 +34 +87 3 -92 -169 +113 +205 3 -219 -322 +263 +382 3 -373 -489 +441 +579 3 -547 -737 +650 +887 3 -847 -1242 +1023 +1514 3 -2206 -73139 +2413 +33435 3 @@ -42429,48 +42807,48 @@ 12 -6 -7 +4 +5 16 -8 -11 +6 +9 3 -30 -71 +34 +87 3 -92 -169 +113 +205 3 -219 -322 +263 +382 3 -373 -489 +441 +579 3 -547 -737 +650 +887 3 -847 -1242 +1023 +1514 3 -2206 -73139 +2413 +33435 3 @@ -42487,7 +42865,7 @@ 1 2 -98272 +53658 @@ -42503,7 +42881,7 @@ 1 2 -98272 +53658 @@ -42513,11 +42891,11 @@ cil_type_argument -285765 +242722 bound -212638 +171457 index @@ -42525,7 +42903,7 @@ t -94872 +75242 @@ -42539,17 +42917,17 @@ 1 2 -156670 +120678 2 3 -49401 +43115 3 41 -6567 +7664 @@ -42565,17 +42943,17 @@ 1 2 -158825 +122717 2 3 -48373 +42236 3 41 -5440 +6504 @@ -42604,33 +42982,33 @@ 3 -16 -61 +15 +60 3 -91 -154 +90 +153 3 187 -268 +272 3 -308 -1324 +314 +1646 3 -1585 -2884 +1986 +3608 3 -6567 -212639 +7664 +171458 3 @@ -42675,23 +43053,23 @@ 3 -134 -195 +135 +200 3 -226 -914 +233 +1139 3 -921 -1510 +1143 +1878 3 -3492 -80006 +4004 +58848 3 @@ -42708,27 +43086,32 @@ 1 2 -44926 +32891 2 3 -30329 +20500 3 4 -8671 +9967 4 -8 -7431 +6 +5945 -8 -9142 -3515 +6 +43 +5650 + + +43 +7168 +289 @@ -42744,17 +43127,17 @@ 1 2 -78890 +60909 2 3 -14957 +13109 3 18 -1025 +1224 @@ -42855,19 +43238,19 @@ cil_attribute -140634 +248346 attributeid -140634 +248346 element -71402 +94117 constructor -750 +1217 @@ -42881,7 +43264,7 @@ 1 2 -140634 +248346 @@ -42897,7 +43280,7 @@ 1 2 -140634 +248346 @@ -42913,27 +43296,32 @@ 1 2 -33119 +35112 2 3 -26720 +33216 3 4 -3637 +3905 4 -6 -5549 +5 +8237 -6 -41 -2377 +5 +7 +7190 + + +7 +49 +6457 @@ -42949,22 +43337,22 @@ 1 2 -51190 +58737 2 3 -14687 +19785 3 -7 -5397 +4 +9074 -7 -11 -128 +4 +18 +6521 @@ -42980,67 +43368,67 @@ 1 2 -82 +97 2 3 -94 +130 3 4 -28 +38 4 5 -44 +143 5 +6 +47 + + +6 7 -69 +100 7 -11 -65 +10 +95 -11 -19 -59 +10 +15 +99 -19 -35 -60 +15 +29 +97 -35 -61 -59 +29 +57 +96 -61 +57 129 -58 +93 129 -307 -57 +399 +92 -312 -1450 -57 - - -1518 -19521 -18 +404 +23319 +90 @@ -43056,57 +43444,57 @@ 1 2 -120 +152 2 3 -116 +308 3 +4 +56 + + +4 5 -61 +72 5 7 -61 +94 7 -11 -66 +12 +102 -11 -20 -58 +12 +25 +102 -20 -35 -66 +25 +48 +94 -35 -69 -57 +48 +116 +93 -69 -153 -57 +117 +489 +92 -165 -539 -57 - - -586 -15827 -31 +491 +15830 +52 @@ -43116,19 +43504,19 @@ cil_attribute_named_argument -2830 +5911 attribute_id -2462 +5474 param -46 +49 value -459 +543 @@ -43142,17 +43530,12 @@ 1 2 -2142 +5093 2 -3 -276 - - -3 5 -44 +381 @@ -43168,17 +43551,12 @@ 1 2 -2185 +5137 2 -3 -250 - - -3 4 -27 +337 @@ -43194,7 +43572,7 @@ 1 2 -4 +5 2 @@ -43209,52 +43587,52 @@ 4 5 -5 +4 5 -6 -2 - - -6 7 -5 +4 -9 +7 +10 +4 + + +10 12 +3 + + +16 +27 4 -15 -20 -4 - - -25 +27 35 4 36 -58 +91 4 -77 -230 +98 +169 4 -237 -476 +171 +285 4 -482 -483 -1 +286 +2537 +4 @@ -43275,20 +43653,25 @@ 2 3 -7 +8 3 5 -4 +2 5 -7 +8 4 -11 +9 +12 +4 + + +13 26 4 @@ -43298,8 +43681,8 @@ 4 -198 -199 +248 +249 1 @@ -43316,37 +43699,37 @@ 1 2 -126 +152 2 3 -167 +196 3 4 -18 +15 4 5 -62 +60 5 -10 -35 +7 +44 -10 -35 -35 +7 +17 +42 -38 -264 -16 +18 +1137 +34 @@ -43362,12 +43745,12 @@ 1 2 -403 +482 2 3 -33 +38 3 @@ -43382,19 +43765,19 @@ cil_attribute_positional_argument -49501 +206816 attribute_id -46841 +73198 index -6 +11 value -7954 +23645 @@ -43408,12 +43791,17 @@ 1 2 -44365 +55372 2 7 -2476 +4994 + + +11 +12 +12832 @@ -43429,12 +43817,17 @@ 1 2 -44378 +55391 2 -7 -2463 +11 +6295 + + +11 +12 +11512 @@ -43448,33 +43841,38 @@ 12 -4 -5 +12832 +12833 +5 + + +12836 +12837 1 -52 -53 +12914 +12915 1 -55 -56 +12917 +12918 1 -73 -74 +12965 +12966 1 -2476 -2477 +17826 +17827 1 -46841 -46842 +73198 +73199 1 @@ -43489,33 +43887,38 @@ 12 -3 -4 +115 +116 1 -5 -6 +256 +257 +5 + + +257 +258 1 -8 -9 +259 +260 1 -15 -16 +3306 +3307 1 -124 -125 +6197 +6198 1 -7849 -7850 +14427 +14428 1 @@ -43532,32 +43935,32 @@ 1 2 -3974 +4049 2 3 -1480 +14560 3 4 -1101 +1037 4 5 -628 +1972 5 -18 -598 +321 +1774 -18 -7750 -173 +322 +8073 +253 @@ -43573,12 +43976,12 @@ 1 2 -7914 +23039 2 -6 -40 +12 +606 @@ -43588,19 +43991,19 @@ metadata_handle -3939398 +5245589 entity -2510549 +2712144 location -1229 +1806 handle -62737 +117188 @@ -43614,22 +44017,27 @@ 1 2 -1505031 +1333886 2 3 -730243 +920872 3 4 -134024 +171626 4 -104 -141251 +6 +221369 + + +6 +591 +64391 @@ -43645,22 +44053,27 @@ 1 2 -1698902 +1843036 2 3 -598520 +491566 3 -5 -211853 +4 +162465 -5 -20 -1274 +4 +10 +206601 + + +10 +39 +8476 @@ -43681,52 +44094,57 @@ 2 3 -432 +464 3 -75 -93 +13 +146 -75 -192 -93 +14 +88 +136 -192 -424 -93 +88 +208 +136 -424 -706 -93 +208 +409 +137 -718 -1306 -93 +410 +658 +137 -1309 -2401 -93 +663 +1103 +136 -2445 -6196 -93 +1105 +1792 +136 -6271 -34416 -93 +1795 +3903 +136 -35288 -94585 -31 +3999 +13105 +137 + + +13241 +110459 +83 @@ -43742,52 +44160,57 @@ 1 2 -454 +486 2 -40 -93 +7 +142 -40 -108 -94 +7 +46 +136 -110 -226 -94 +46 +113 +137 -229 -417 -93 +113 +222 +136 -417 -729 -94 +223 +355 +136 -735 -1474 -93 +359 +579 +137 -1477 -3811 -93 +583 +1038 +137 -3943 -22304 -93 +1039 +2262 +136 -22464 -55159 -28 +2268 +7743 +136 + + +7800 +110459 +87 @@ -43802,68 +44225,53 @@ 1 -5 -5311 +2 +355 -5 -8 -5381 +2 +3 +53204 -8 -12 -5363 +3 +7 +9098 -12 -17 -5497 +7 +15 +8859 -17 -24 -5744 +15 +26 +9051 -24 -29 -4967 +26 +39 +8919 -29 -41 -4790 +39 +63 +9148 -41 -53 -4973 +63 +104 +8882 -53 -71 -4708 +104 +539 +8794 -71 -83 -4805 - - -83 -127 -4725 - - -127 -295 -4715 - - -295 -1334 -1758 +539 +1544 +878 @@ -43878,73 +44286,48 @@ 1 -3 -3109 - - -3 4 -5069 +4254 4 -7 -4563 +5 +55971 -7 -8 -4073 +5 +12 +9795 -8 -11 -5180 +12 +20 +8862 -11 -14 -4626 +20 +28 +9240 -14 -17 -4785 - - -17 -24 -4978 - - -24 -32 -5382 - - -32 +28 43 -4868 +8804 43 -52 -4881 +63 +8904 -52 -81 -4785 +63 +200 +8803 -81 -195 -4719 - - -195 -1230 -1719 +200 +1807 +2555 From e7f5fd6b4b3d8c8a09e0c452a8aa244e98a9ee10 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Tue, 1 Oct 2019 17:33:29 +0100 Subject: [PATCH 1035/1227] C#: DB upgrade script --- .../old.dbscheme | 1872 ++++++++++++++++ .../semmlecode.csharp.dbscheme | 1883 +++++++++++++++++ .../upgrade.properties | 2 + 3 files changed, 3757 insertions(+) create mode 100644 csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/old.dbscheme create mode 100644 csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme create mode 100644 csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/upgrade.properties diff --git a/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/old.dbscheme b/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/old.dbscheme new file mode 100644 index 00000000000..f93793ee5f6 --- /dev/null +++ b/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/old.dbscheme @@ -0,0 +1,1872 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + varchar(900) queryPath: string ref, + int location: @location ref, + varchar(900) message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + varchar(900) queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + varchar(900) path: string ref, + int column: int ref, + varchar(900) value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + varchar(900) prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + varchar(900) relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + varchar(900) relativePath: string ref, + int equivClass: int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id: @duplication_or_similarity ref, + int offset: int ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + unique int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + varchar(900) fullname: string ref, + varchar(900) name: string ref, + varchar(900) version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + varchar(900) name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + varchar(900) name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + varchar(900) name: string ref); + +typeref_type( + unique int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @struct_type ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @array_type | @expr | @delegate_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +/** The annotation of type arguments of a constructed type or method. */ +type_argument_annotation(int constructedgeneric: @generic ref, int position: int ref, int annotation: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +is_generic(unique int id: @generic ref); + +is_constructed(unique int id: @generic ref); + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_annotation( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int annotation: int ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function; + +modifiers( + unique int id: @modifier, + varchar(900) name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + varchar(900) name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + varchar(900) name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + varchar(900) name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + varchar(900) name: string ref, + varchar(900) symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + unique int id: @variable ref, + varchar(900) value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + unique int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + unique int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + varchar(900) name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + varchar(900) name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + varchar(900) name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + varchar(900) value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + varchar(900) name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + varchar(900) name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + varchar(900) encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + varchar(800) text: string ref, + varchar(800) rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + varchar(1000) name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + varchar(1000) name: string ref); +asp_element_body( + unique int element: @asp_element ref, + varchar(1000) body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + varchar(1000) name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + varchar(1000) name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + varchar(900) value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + varchar(900) name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + varchar(900) name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + varchar(900) name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + varchar(900) name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + varchar(900) name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + varchar(100) param: string ref, + varchar(900) value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + varchar(900) value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme b/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..e4ab77432e6 --- /dev/null +++ b/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme @@ -0,0 +1,1883 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + varchar(900) queryPath: string ref, + int location: @location ref, + varchar(900) message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + varchar(900) queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + varchar(900) path: string ref, + int column: int ref, + varchar(900) value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + varchar(900) prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + varchar(900) relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + varchar(900) relativePath: string ref, + int equivClass: int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id: @duplication_or_similarity ref, + int offset: int ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + varchar(900) fullname: string ref, + varchar(900) name: string ref, + varchar(900) version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + varchar(900) name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + varchar(900) name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + varchar(900) name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[nullability, index] +nullability_member(int nullability: @nullability ref, int index: int ref, int child: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref) + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +is_generic(unique int id: @generic ref); + +is_constructed(unique int id: @generic ref); + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function; + +modifiers( + unique int id: @modifier, + varchar(900) name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + varchar(900) name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + varchar(900) name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + varchar(900) name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + varchar(900) name: string ref, + varchar(900) symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + unique int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + varchar(900) name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + varchar(900) name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + varchar(900) name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + varchar(900) value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + varchar(900) name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr + | @delegate_invocation_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + varchar(900) name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + varchar(900) encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + varchar(800) text: string ref, + varchar(800) rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + varchar(1000) name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + varchar(1000) name: string ref); +asp_element_body( + unique int element: @asp_element ref, + varchar(1000) body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + varchar(1000) name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + varchar(1000) name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + varchar(900) value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + varchar(900) name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + varchar(900) name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + varchar(900) name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + varchar(900) name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + varchar(900) name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + varchar(100) param: string ref, + varchar(900) value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + varchar(900) value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/upgrade.properties b/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/upgrade.properties new file mode 100644 index 00000000000..a8ba5643bcb --- /dev/null +++ b/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/upgrade.properties @@ -0,0 +1,2 @@ +description: Implement structured nullability +compatibility: backwards From c8225adf1b2b82c78570ad367c939cafeb6c764a Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 2 Oct 2019 10:43:56 +0100 Subject: [PATCH 1036/1227] C#: Add missing file & minor fixes. --- .../Entities/Symbol.cs | 1 - .../Entities/Types/Nullability.cs | 272 ++++++++++++++++++ 2 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs index 6d0f5dd80c8..4f239083d24 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs @@ -30,7 +30,6 @@ namespace Semmle.Extraction.CSharp.Entities protected void PopulateNullability(TextWriter trapFile, AnnotatedTypeSymbol type) { - var ta = type.Nullability.GetTypeAnnotation(); var n = NullabilityEntity.Create(Context, Nullability.Create(type)); if (!type.HasObliviousNullability()) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs new file mode 100644 index 00000000000..cef905d343c --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs @@ -0,0 +1,272 @@ +using Microsoft.CodeAnalysis; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Semmle.Extraction.CSharp.Entities +{ + public sealed class Nullability + { + public int Annotation { get; private set; } + + static readonly Nullability[] EmptyArray = new Nullability[0]; + public readonly Nullability[] NullableParameters; + + public static Nullability Create(AnnotatedTypeSymbol ts) + { + if(ts.HasConsistentNullability()) + { + switch (ts.Nullability) + { + case NullableAnnotation.Annotated: + return annotated; + case NullableAnnotation.NotAnnotated: + return notannotated; + default: + return oblivious; + } + } + + return new Nullability(ts); + } + + static readonly Nullability oblivious = new Nullability(NullableAnnotation.Disabled); + static readonly Nullability annotated = new Nullability(NullableAnnotation.Annotated); + static readonly Nullability notannotated = new Nullability(NullableAnnotation.NotAnnotated); + + private Nullability(NullableAnnotation n) + { + SetNullability(n); + NullableParameters = new Nullability[0]; + } + + private void SetNullability(NullableAnnotation n) + { + switch (n) + { + case NullableAnnotation.NotAnnotated: + Annotation = 1; + break; + case NullableAnnotation.Annotated: + Annotation = 2; + break; + default: + Annotation = 0; + break; + } + } + + private Nullability(AnnotatedTypeSymbol ts) : this(ts.Nullability) + { + NullableParameters = ts.HasConsistentNullability() ? EmptyArray : ts.GetAnnotatedTypeArguments().Select(Create).ToArray(); + } + + public Nullability(IMethodSymbol method) + { + Annotation = 0; + NullableParameters = method.GetAnnotatedTypeArguments().Select(a => new Nullability(a)).ToArray(); + } + + public override bool Equals(object other) + { + return other is Nullability n && Annotation == n.Annotation && NullableParameters.SequenceEqual(n.NullableParameters); + } + + public override int GetHashCode() + { + int h = Annotation; + + foreach (var t in NullableParameters) + h = h * 5 + t.GetHashCode(); + + return h; + } + + public void WriteId(TextWriter trapFile) + { + trapFile.Write(Annotation); + trapFile.Write('('); + foreach (var s in NullableParameters) + s.WriteId(trapFile); + trapFile.Write(')'); + } + + public override string ToString() + { + using (var w = new StringWriter()) + { + WriteId(w); + return w.ToString(); + } + } + } + + public class NullabilityEntity : CachedEntity + { + public NullabilityEntity(Context cx, Nullability init) : base(cx, init) + { + } + + public override Location ReportingLocation => throw new System.NotImplementedException(); + + public override bool NeedsPopulation => true; + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public override void Populate(TextWriter trapFile) + { + trapFile.nullability(this, symbol.Annotation); + + int i = 0; + foreach(var s in symbol.NullableParameters) + { + trapFile.nullability_member(this, i, Create(Context, s)); + i++; + } + } + + public override void WriteId(TextWriter trapFile) + { + symbol.WriteId(trapFile); + } + + public static NullabilityEntity Create(Context cx, Nullability init) => NullabilityFactory.Instance.CreateEntity(cx, init); + + class NullabilityFactory : ICachedEntityFactory + { + public static readonly NullabilityFactory Instance = new NullabilityFactory(); + + public NullabilityEntity Create(Context cx, Nullability init) => new NullabilityEntity(cx, init); + } + } + + public static class NullabilityExtensions + { + /// + /// Gets the annotated type of an ILocalSymbol. + /// This has not yet been exposed on the public API. + /// + public static AnnotatedTypeSymbol GetAnnotatedType(this ILocalSymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation); + + /// + /// Gets the annotated type of an IParameterSymbol. + /// This has not yet been exposed on the public API. + /// + public static AnnotatedTypeSymbol GetAnnotatedType(this IParameterSymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation); + + /// + /// Gets the annotated type of an IPropertySymbol. + /// This has not yet been exposed on the public API. + /// + public static AnnotatedTypeSymbol GetAnnotatedType(this IPropertySymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation); + + /// + /// Gets the annotated type of an IEventSymbol. + /// This has not yet been exposed on the public API. + /// + public static AnnotatedTypeSymbol GetAnnotatedType(this IEventSymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation); + + /// + /// Gets the annotated type of an IFieldSymbol. + /// This has not yet been exposed on the public API. + /// + public static AnnotatedTypeSymbol GetAnnotatedType(this IFieldSymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation); + + /// + /// Gets the annotated return type of an IMethodSymbol. + /// This has not yet been exposed on the public API. + /// + public static AnnotatedTypeSymbol GetAnnotatedReturnType(this IMethodSymbol symbol) => new AnnotatedTypeSymbol(symbol.ReturnType, symbol.ReturnNullableAnnotation); + + /// + /// Gets the type annotation for a NullableAnnotation. + /// + public static Kinds.TypeAnnotation GetTypeAnnotation(this NullableAnnotation na) + { + switch (na) + { + case NullableAnnotation.Annotated: + return Kinds.TypeAnnotation.Annotated; + case NullableAnnotation.NotAnnotated: + return Kinds.TypeAnnotation.NotAnnotated; + default: + return Kinds.TypeAnnotation.None; + } + } + + public static IEnumerable GetAnnotatedTypeArguments(this AnnotatedTypeSymbol at) + { + switch (at.Symbol) + { + case IArrayTypeSymbol array: + yield return array.GetAnnotatedElementType(); + break; + case INamedTypeSymbol named: + foreach (var n in named.GetAnnotatedTypeArguments()) + yield return n; + break; + } + } + + /// + /// Checks if this type has consistent nullability, which is the most common case. + /// Either the code is oblivious to nullability, or is non-nullable. + /// This is so that we can avoid populating nullability in most cases. + /// For example, + /// + /// IEnumerable<string?> // false + /// IEnumerable<string?>? // true + /// string? // true + /// string[] // true + /// string?[] // false + /// string?[]? // true + /// + /// + /// The annotated type. + /// If the nullability is consistent in the type. + public static bool HasConsistentNullability(this AnnotatedTypeSymbol at) => + at.GetAnnotatedTypeArguments().All(a => a.Nullability == at.Nullability && a.HasConsistentNullability()); + + /// + /// Holds if the type symbol is completely oblivious to nullability. + /// + /// The annotated type symbol. + /// If at is oblivious. + public static bool HasObliviousNullability(this AnnotatedTypeSymbol at) => + at.Nullability.GetTypeAnnotation() == Kinds.TypeAnnotation.None && at.HasConsistentNullability(); + + /// + /// Gets the annotated element type of an IArrayTypeSymbol. + /// This has not yet been exposed on the public API. + /// + public static AnnotatedTypeSymbol GetAnnotatedElementType(this IArrayTypeSymbol symbol) => + new AnnotatedTypeSymbol(symbol.ElementType, symbol.ElementNullableAnnotation); + + /// + /// Gets the annotated type arguments of an INamedTypeSymbol. + /// This has not yet been exposed on the public API. + /// + public static IEnumerable GetAnnotatedTypeArguments(this INamedTypeSymbol symbol) => + symbol.TypeArguments.Zip(symbol.TypeArgumentsNullableAnnotations, (t, a) => new AnnotatedTypeSymbol(t, a)); + + /// + /// Gets the annotated type arguments of an IMethodSymbol. + /// This has not yet been exposed on the public API. + /// + public static IEnumerable GetAnnotatedTypeArguments(this IMethodSymbol symbol) => + symbol.TypeArguments.Zip(symbol.TypeArgumentsNullableAnnotations, (t, a) => new AnnotatedTypeSymbol(t, a)); + + /// + /// Gets the annotated type constraints of an ITypeParameterSymbol. + /// This has not yet been exposed on the public API. + /// + public static IEnumerable GetAnnotatedTypeConstraints(this ITypeParameterSymbol symbol) => + symbol.ConstraintTypes.Zip(symbol.ConstraintNullableAnnotations, (t, a) => new AnnotatedTypeSymbol(t, a)); + + /// + /// Creates an AnnotatedTypeSymbol from an ITypeSymbol. + /// + public static AnnotatedTypeSymbol WithAnnotation(this ITypeSymbol symbol, NullableAnnotation annotation) => + new AnnotatedTypeSymbol(symbol, annotation); + } +} From a0fa7dad79370ed50ef2f6604412ba7c13fce437 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 2 Oct 2019 11:01:25 +0100 Subject: [PATCH 1037/1227] C#: Autoformat --- csharp/ql/src/semmle/code/csharp/AnnotatedType.qll | 2 +- csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll index afa80c43ae6..a6e2417796a 100644 --- a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll +++ b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll @@ -164,7 +164,7 @@ private module Annotations { /** * Gets the `i`th member of this annotation. - * Returns `this` if the nullability is not explicitly + * Returns `this` if the nullability is not explicitly * stored in the database, since many type annotations will have consistent * nullability. */ diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql index cf5d320ca91..de55dd7b272 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql @@ -45,9 +45,7 @@ query predicate methodTypeArguments(ConstructedGeneric generic, int arg, string argument = generic.getAnnotatedTypeArgument(arg).toString() } -query predicate constructedTypes( - AnnotatedConstructedType at, int i, string arg, string nullability -) { +query predicate constructedTypes(AnnotatedConstructedType at, int i, string arg, string nullability) { arg = at.getTypeArgument(i).toString() and at.getLocation() instanceof SourceLocation and nullability = at.getAnnotations().getNullability().toString() From f00276a82c140dea2cd43e64bdf8999776648489 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 24 Oct 2019 18:53:29 +0100 Subject: [PATCH 1038/1227] C#: Remove non-essential changes --- .../Entities/LocalFunction.cs | 2 +- .../Entities/Method.cs | 10 +-- .../Entities/Types/NamedType.cs | 8 +-- .../Entities/Types/TupleType.cs | 2 +- .../Entities/Types/Type.cs | 3 - .../Entities/UserOperator.cs | 2 +- .../SymbolExtensions.cs | 66 +++++++------------ .../csharp8/NullableRefTypes.expected | 3 - .../library-tests/csharp8/NullableRefTypes.ql | 3 +- 9 files changed, 37 insertions(+), 62 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs index 7199b694507..f58c027eca5 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs @@ -19,7 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities if (symbol.IsGenericMethod && !IsSourceDeclaration) { trapFile.Write('<'); - trapFile.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta, TypeIdentifierContext.MethodName)); + trapFile.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta)); trapFile.Write('>'); } trapFile.Write(";localfunction"); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 18aec3b05ec..f3aba9744be 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -129,7 +129,7 @@ namespace Semmle.Extraction.CSharp.Entities // Type arguments with different nullability can result in // a constructed method with different nullability of its parameters and return type, // so we need to create a distinct database entity for it. - trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol, TypeIdentifierContext.MethodName); trapFile.Write((int)ta.Nullability); }); + trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); trapFile.Write((int)ta.Nullability); }); trapFile.Write('>'); } } @@ -199,10 +199,10 @@ namespace Semmle.Extraction.CSharp.Entities /// to make the reference to #3 in the label definition #4 for /// T valid. /// - protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type, TypeIdentifierContext tic) + protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type) { if (type.ContainsTypeParameters(cx, method)) - type.BuildTypeId(cx, trapFile, (cx0, tb0, type0, _) => AddSignatureTypeToId(cx, tb0, method, type0, tic), tic, method); + type.BuildTypeId(cx, trapFile, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0)); else trapFile.WriteSubId(Type.Create(cx, type).TypeRef); } @@ -215,13 +215,13 @@ namespace Semmle.Extraction.CSharp.Entities if (method.MethodKind == MethodKind.ReducedExtension) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, TypeIdentifierContext.MethodParam); + AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType); } foreach (var param in method.Parameters) { trapFile.WriteSeparator(",", ref index); - AddSignatureTypeToId(cx, trapFile, method, param.Type, TypeIdentifierContext.MethodParam); + AddSignatureTypeToId(cx, trapFile, method, param.Type); switch (param.RefKind) { case RefKind.Out: diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index 28b1e37514a..fa5f6a4bdf9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -111,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeIdentifierContext.TypeName, symbol); + symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); trapFile.Write(";type"); } @@ -177,12 +177,12 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - void ExpandType(Context cx0, TextWriter tb0, ITypeSymbol sub, ISymbol gc) + void ExpandType(Context cx0, TextWriter tb0, ITypeSymbol sub) { - sub.BuildTypeId(cx0, tb0, ExpandType, TypeIdentifierContext.TypeRef, gc); + sub.BuildTypeId(cx0, tb0, ExpandType); } - symbol.BuildTypeId(Context, trapFile, ExpandType, TypeIdentifierContext.TypeRef, symbol); + symbol.BuildTypeId(Context, trapFile, ExpandType); trapFile.Write(";typeref"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index 8da87ba318d..d486506408b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeIdentifierContext.TypeName, symbol); + symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub))); trapFile.Write(";tuple"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index d541febee6d..276cf6758e2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -270,9 +270,6 @@ namespace Semmle.Extraction.CSharp.Entities { type = type.DisambiguateType(); - if (type is INamedTypeSymbol nt && nt.IsEvilTwin()) - type = nt.ConstructedFrom; - const bool errorTypeIsNull = false; return type == null || (errorTypeIsNull && type.TypeKind == TypeKind.Error) ? NullType.Create(cx).Type : (Type)cx.CreateEntity(type); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index 5ac9c3015e0..2a64a29fa0d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -51,7 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType, TypeIdentifierContext.MethodParam); // Needed for op_explicit(), which differs only by return type. + AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType); // Needed for op_explicit(), which differs only by return type. trapFile.Write(' '); BuildMethodId(this, trapFile); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index a5a5dc3aa83..6e2b52f3086 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -27,19 +27,6 @@ namespace Semmle.Extraction.CSharp } } - /// - /// Marks where a type identifier is being generated, which could change - /// the way that the identifier is generated. - /// - public enum TypeIdentifierContext - { - TypeName, - TypeRef, - AnonymousType, - MethodName, - MethodParam - } - static class SymbolExtensions { /// @@ -146,7 +133,7 @@ namespace Semmle.Extraction.CSharp /// The extraction context. /// The trap builder used to store the result. /// The action to apply to syntactic sub terms of this type. - public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, TypeIdentifierContext tic, ISymbol genericContext) + public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction) { switch(type.SpecialType) { @@ -184,7 +171,7 @@ namespace Semmle.Extraction.CSharp { case TypeKind.Array: var array = (IArrayTypeSymbol)type; - subTermAction(cx, trapFile, array.ElementType, genericContext); + subTermAction(cx, trapFile, array.ElementType); array.BuildArraySuffix(trapFile); return; case TypeKind.Class: @@ -194,29 +181,16 @@ namespace Semmle.Extraction.CSharp case TypeKind.Delegate: case TypeKind.Error: var named = (INamedTypeSymbol)type; - named.BuildNamedTypeId(cx, trapFile, subTermAction, tic, genericContext); + named.BuildNamedTypeId(cx, trapFile, subTermAction); return; case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; - subTermAction(cx, trapFile, ptr.PointedAtType, genericContext); + subTermAction(cx, trapFile, ptr.PointedAtType); trapFile.Write("*"); return; case TypeKind.TypeParameter: var tp = (ITypeParameterSymbol)type; - switch(tp.TypeParameterKind) - { - case TypeParameterKind.Method: - if (!Equals(genericContext, tp.DeclaringMethod)) - trapFile.WriteSubId(Method.Create(cx, tp.DeclaringMethod)); - trapFile.Write("!!"); - break; - case TypeParameterKind.Type: - if (!Equals(genericContext,tp.DeclaringType)) - subTermAction(cx, trapFile, tp.DeclaringType, genericContext); - trapFile.Write("!"); - break; - } - trapFile.Write(tp.Ordinal); + trapFile.Write(tp.Name); return; case TypeKind.Dynamic: trapFile.Write("dynamic"); @@ -258,11 +232,10 @@ namespace Semmle.Extraction.CSharp trapFile.Write("::"); } - public static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction, TypeIdentifierContext tic, ISymbol genericContext) + public static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction) { bool prefixAssembly = false; if (named.IsAnonymous()) prefixAssembly = true; - else if(tic == TypeIdentifierContext.TypeName && cx.Extractor.TrapIdentifiers != TrapIdenfierMode.Imprecise) prefixAssembly = true; if (named.ContainingAssembly is null) prefixAssembly = false; if (prefixAssembly) @@ -276,7 +249,7 @@ namespace Semmle.Extraction.CSharp { trapFile.Write(f.Name); trapFile.Write(":"); - subTermAction(cx, tb0, f.Type, genericContext); + subTermAction(cx, tb0, f.Type); } ); trapFile.Write(")"); @@ -285,16 +258,16 @@ namespace Semmle.Extraction.CSharp if (named.ContainingType != null) { - subTermAction(cx, trapFile, named.ContainingType, genericContext); + subTermAction(cx, trapFile, named.ContainingType); trapFile.Write('.'); } - else if (named.ContainingNamespace != null && !named.IsConstructedGeneric()) + else if (named.ContainingNamespace != null) { named.ContainingNamespace.BuildNamespace(cx, trapFile); } if (named.IsAnonymousType) - named.BuildAnonymousName(cx, trapFile, subTermAction, true, genericContext); + named.BuildAnonymousName(cx, trapFile, subTermAction, true); else if (named.TypeParameters.IsEmpty) trapFile.Write(named.Name); else if (IsReallyUnbound(named)) @@ -305,14 +278,14 @@ namespace Semmle.Extraction.CSharp } else { - subTermAction(cx, trapFile, named.ConstructedFrom, genericContext); + subTermAction(cx, trapFile, named.ConstructedFrom); trapFile.Write('<'); // Encode the nullability of the type arguments in the label. // Type arguments with different nullability can result in // a constructed type with different nullability of its members and methods, // so we need to create a distinct database entity for it. trapFile.BuildList(",", named.GetAnnotatedTypeArguments(), - (ta, tb0) => subTermAction(cx, tb0, ta.Symbol, genericContext) + (ta, tb0) => subTermAction(cx, tb0, ta.Symbol) ); trapFile.Write('>'); } @@ -324,16 +297,16 @@ namespace Semmle.Extraction.CSharp trapFile.Write('.'); } - static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, bool includeParamName, ISymbol genericContext) + static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction, bool includeParamName) { var buildParam = includeParamName ? (prop, tb0) => { tb0.Write(prop.Name); tb0.Write(' '); - subTermAction(cx, tb0, prop.Type, genericContext); + subTermAction(cx, tb0, prop.Type); } - : (Action)((prop, tb0) => subTermAction(cx, tb0, prop.Type, genericContext)); + : (Action)((prop, tb0) => subTermAction(cx, tb0, prop.Type)); int memberCount = type.GetMembers().OfType().Count(); int hackTypeNumber = memberCount == 1 ? 1 : 0; trapFile.Write("<>__AnonType"); @@ -405,7 +378,7 @@ namespace Semmle.Extraction.CSharp if (namedType.IsAnonymousType) { - namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub, _) => sub.BuildDisplayName(cx0, tb0), false, namedType); + namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false); } trapFile.Write(namedType.Name); @@ -617,5 +590,12 @@ namespace Semmle.Extraction.CSharp /// public static AnnotatedTypeSymbol WithAnnotation(this ITypeSymbol symbol, NullableAnnotation annotation) => new AnnotatedTypeSymbol(symbol, annotation); + + /// + /// Holds if this type looks like an "anonymous" type. Names of anonymous types + /// sometimes collide so they need to be handled separately. + /// + public static bool IsAnonymous(this INamedTypeSymbol type) => + type.IsAnonymousType || type.Name.StartsWith("<>"); } } diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected index 4ea99349aa8..915992329e3 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected @@ -201,9 +201,6 @@ methodTypeArguments | NullableRefTypes.cs:67:10:67:21 | GenericFn | 0 | MyClass | | NullableRefTypes.cs:67:10:67:21 | GenericFn | 0 | MyClass! | constructedTypes -| AsyncStreams.cs:34:15:34:37 | IAsyncEnumerable | 0 | int | _ | -| AsyncStreams.cs:39:15:39:37 | IAsyncEnumerator | 0 | T | _ | -| AsyncStreams.cs:39:15:39:37 | IAsyncEnumerator | 0 | int | _ | | NullableRefTypes.cs:54:11:54:33 | Generic | 0 | MyClass | _ | | NullableRefTypes.cs:54:11:54:33 | Generic | 1 | MyClass | _ | | NullableRefTypes.cs:54:11:54:33 | Generic | 2 | IDisposable | _ | diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql index de55dd7b272..416929afb92 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql @@ -47,12 +47,13 @@ query predicate methodTypeArguments(ConstructedGeneric generic, int arg, string query predicate constructedTypes(AnnotatedConstructedType at, int i, string arg, string nullability) { arg = at.getTypeArgument(i).toString() and - at.getLocation() instanceof SourceLocation and + at.getLocation().getFile().getBaseName() = "NullableRefTypes.cs" and nullability = at.getAnnotations().getNullability().toString() } query predicate nullableTypeParameters(TypeParameter p) { p.getConstraints().hasNullableRefTypeConstraint() + and p.getLocation().getFile().getBaseName() = "NullableRefTypes.cs" } query predicate annotatedTypeConstraints(TypeParameter p, AnnotatedType t) { From 58e14af9cd3920e6a1ad6db96856648206936090 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Sun, 3 Nov 2019 15:26:29 +0000 Subject: [PATCH 1039/1227] C#: Address review comments. Create a TNullability type annotation and restructure TAnnotation. --- .../Entities/Types/Nullability.cs | 11 +- .../src/semmle/code/csharp/AnnotatedType.qll | 231 +++++++++--------- 2 files changed, 122 insertions(+), 120 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs index cef905d343c..4dc0a9046aa 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs @@ -7,14 +7,14 @@ namespace Semmle.Extraction.CSharp.Entities { public sealed class Nullability { - public int Annotation { get; private set; } + public int Annotation { get; } static readonly Nullability[] EmptyArray = new Nullability[0]; public readonly Nullability[] NullableParameters; public static Nullability Create(AnnotatedTypeSymbol ts) { - if(ts.HasConsistentNullability()) + if (ts.HasConsistentNullability()) { switch (ts.Nullability) { @@ -35,12 +35,6 @@ namespace Semmle.Extraction.CSharp.Entities static readonly Nullability notannotated = new Nullability(NullableAnnotation.NotAnnotated); private Nullability(NullableAnnotation n) - { - SetNullability(n); - NullableParameters = new Nullability[0]; - } - - private void SetNullability(NullableAnnotation n) { switch (n) { @@ -54,6 +48,7 @@ namespace Semmle.Extraction.CSharp.Entities Annotation = 0; break; } + NullableParameters = EmptyArray; } private Nullability(AnnotatedTypeSymbol ts) : this(ts.Nullability) diff --git a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll index a6e2417796a..96300abdcd8 100644 --- a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll +++ b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll @@ -8,173 +8,163 @@ import csharp -private module Annotations { +module Annotations { newtype TAnnotation = - TNotNullableRefType() or - TNullableRefType() or TReadonlyRefType() or TRefType() or - TOutType() + TOutType() or + TNullability(@nullability n) /** An annotation on a type. */ class TypeAnnotation extends TAnnotation { - /** Holds if this string should prefix the type string. */ - predicate isPrefix() { none() } - - /** Holds if this string should suffix the type string. */ - predicate isSuffix() { none() } - - /** Gets the bit position in the bit-field. */ + /** Gets the bit position in the bit-field, also used to order the annotations in the text format. */ abstract int getBit(); + /** Gets the string prefixing the type, if any. */ + string getPrefix() { none() } + + /** Gets the string suffixing the type, if any. */ + string getSuffix() { none() } + /** Gets a string representation of this type annotation. */ - abstract string toString(); - } - - /** An annotation indicating that the type is not nullable. */ - class NonNullableRefType extends TypeAnnotation, TNotNullableRefType { - override predicate isSuffix() { any() } - - override string toString() { result = "!" } - - override int getBit() { result = 2 } - } - - /** An annotation indicating that the type is a nullable reference type. */ - class NullableRefType extends TypeAnnotation, TNullableRefType { - override predicate isSuffix() { any() } - - override string toString() { result = "?" } - - override int getBit() { result = 3 } + string toString() { none() } } /** An annotation indicating that the type is a readonly reference. */ class ReadonlyRefType extends TypeAnnotation, TReadonlyRefType { - override predicate isPrefix() { any() } + override string getPrefix() { result = "readonly " } - override string toString() { result = "readonly " } + override string toString() { result = "readonly ref" } override int getBit() { result = 4 } } /** An annotation indicating that the variable or return is by `ref`. */ class RefTypeAnnotation extends TypeAnnotation, TRefType { - override predicate isPrefix() { any() } + override string getPrefix() { result = "ref " } - override string toString() { result = "ref " } + override string toString() { result = "ref" } override int getBit() { result = 5 } } /** An annotation indicating that the parameter is `out`. */ class OutType extends TypeAnnotation, TOutType { - override predicate isPrefix() { any() } + override string getPrefix() { result = "out " } - override string toString() { result = "out " } + override string toString() { result = "out" } override int getBit() { result = 6 } } - newtype TAnnotations = + private newtype TAnnotations = TAnnotationFlags(int flags, Nullability n) { - exists(Element e | flags = getElementTypeFlags(e) and n = getElementNullability(e)) - or - flags = 0 // n is unbound - } + exists(Element e | + flags = getElementTypeFlags(e) and + n = getElementNullability(e) + ) + } or + TAnnotationsNoFlags(Nullability n) + /** A collection of type annotations. */ class TypeAnnotations extends TAnnotations { - int flags; - - Nullability nullability; - - TypeAnnotations() { this = TAnnotationFlags(flags, nullability) } - - /** Gets the flags (as a bitset) of this type annotation. */ - int getFlags() { result = flags } - /** Gets the nullability of this type annotation. */ - Nullability getNullability() { result = nullability } - - /** - * Gets the `i`th "child" of this type annotation. - * This is used to represent structured datatypes, where the structure - * of the type annotation mirrors the structure of the annotated type. - */ - bindingset[i] - TypeAnnotations getChild(int i) { - result.getFlags() = 0 and result.getNullability() = this.getNullability().getMember(i) + Nullability getNullability() { + this = TAnnotationFlags(_, result) + or + this = TAnnotationsNoFlags(result) } + /** Gets the nullability with no additional flags. */ + Nullability getNoFlagsNullability() { this = TAnnotationsNoFlags(result) } + /** Gets text to be displayed before the type. */ string getTypePrefix() { result = concat(TypeAnnotation a | - a = this.getAnAnnotation() and a.isPrefix() + a = this.getAnAnnotation() | - a.toString(), "" order by a.getBit() + a.getPrefix(), "" order by a.getBit() ) } /** Gets text to be displayed after the type. */ string getTypeSuffix() { result = concat(TypeAnnotation a | - a = this.getAnAnnotation() and a.isSuffix() + a = this.getAnAnnotation() | - a.toString(), "" order by a.getBit() + a.getSuffix(), "" order by a.getBit() ) } /** Gets a textual representation of this type annotation. */ - string toString() { result = getTypePrefix() + getTypeSuffix() } + string toString() { result = getTypePrefix() + getNullability() + getTypeSuffix() } + + private int getFlags() { this = TAnnotationFlags(result, _) } private predicate isSet(int bit) { isBit(bit) and - exists(int mask | mask = getBitMask(bit) | flags.bitAnd(mask) = mask) + exists(int mask | mask = getBitMask(bit) | this.getFlags().bitAnd(mask) = mask) } /** Gets an annotation in this set of annotations. */ TypeAnnotation getAnAnnotation() { isSet(result.getBit()) or - nullability instanceof AnnotatedNullability and result instanceof NullableRefType - or - nullability instanceof NotAnnotatedNullability and result instanceof NonNullableRefType + result = this.getNullability() } } + /** + * Gets the `i`th child of type annotations `annotations`. + * This is used to represent structured datatypes, where the structure + * of the type annotation mirrors the structure of the annotated type. + */ + bindingset[i] + TypeAnnotations getChild(TypeAnnotations annotations, int i) { + result.getNoFlagsNullability() = getChildNullability(annotations.getNullability(), i) + } + /** * A structured type annotation representing type nullability. * For example, `IDictionary?` has nullability `?`. */ - class Nullability extends @nullability { - string toString() { result = getMemberString() + getSelfNullability() } + abstract class Nullability extends TypeAnnotation, TNullability { + @nullability nullability; + + Nullability() { this = TNullability(nullability) } + + @nullability getNullability() { result = nullability } + + override string toString() { result = getMemberString() + getSelfNullability() } language[monotonicAggregates] private string getMemberString() { - if nullability_member(this, _, _) + if nullability_member(nullability, _, _) then result = "<" + concat(int i, Nullability child | - nullability_member(this, i, child) + nullability_member(nullability, i, child.getNullability()) | child.toString(), "," order by i ) + ">" else result = "" } - /** - * Gets the `i`th member of this annotation. - * Returns `this` if the nullability is not explicitly - * stored in the database, since many type annotations will have consistent - * nullability. - */ - bindingset[i] - Nullability getMember(int i) { - if nullability_member(this, i, _) then nullability_member(this, i, result) else result = this - } + /** Gets a string representing the nullability, disregarding child nullability. */ + string getSelfNullability() { none() } + } - /** Gets a string representing the nullability. */ - abstract string getSelfNullability(); + /** + * Gets the `i`th child of nullability `n`. + * Returns `n` if the nullability is not explicitly + * stored in the database, since many type annotations will have consistent + * nullability. + */ + bindingset[i] + Nullability getChildNullability(Nullability n, int i) { + if nullability_member(n.getNullability(), i, _) + then nullability_member(n.getNullability(), i, result.getNullability()) + else result = n } /** @@ -182,8 +172,12 @@ private module Annotations { * applicable, because the code was not compiled in a nullable context, or * because the C# language version is less than 8. */ - class ObliviousNullability extends Nullability, @oblivious { + class ObliviousNullability extends Nullability { + ObliviousNullability() { nullability instanceof @oblivious } + override string getSelfNullability() { result = "_" } + + override int getBit() { none() } } /** @@ -191,26 +185,43 @@ private module Annotations { * and all type arguments are oblivious. */ class NoNullability extends ObliviousNullability { - NoNullability() { not nullability_member(this, _, _) } + NoNullability() { not nullability_member(nullability, _, _) } } /** A type with annotated nullablity, `?`. */ - class AnnotatedNullability extends Nullability, @annotated { + class AnnotatedNullability extends Nullability { + AnnotatedNullability() { nullability instanceof @annotated } + override string getSelfNullability() { result = "?" } + + override int getBit() { result = 3 } + + override string getSuffix() { result = "?" } } /** * A ref type not annotated with `?` in a nullable context. */ - class NotAnnotatedNullability extends Nullability, @not_annotated { + class NotAnnotatedNullability extends Nullability { + NotAnnotatedNullability() { nullability instanceof @not_annotated } + override string getSelfNullability() { result = "!" } + + override int getBit() { result = 2 } + + override string getSuffix() { result = "!" } } /** Holds if the type annotations `annotations` apply to type `type` on element `element`. */ predicate elementTypeAnnotations( @has_type_annotation element, Type type, TypeAnnotations annotations ) { - annotations = TAnnotationFlags(getElementTypeFlags(element), getElementNullability(element)) and + ( + annotations = TAnnotationFlags(getElementTypeFlags(element), getElementNullability(element)) + or + not exists(getElementTypeFlags(element)) and + annotations.getNoFlagsNullability() = getElementNullability(element) + ) and ( type = element.(Assignable).getType() or @@ -232,14 +243,14 @@ private int getBitMask(int bit) { } private int getElementTypeFlags(@has_type_annotation element) { - result = sum(int b | type_annotation(element, b) | b) + result = strictsum(int b | type_annotation(element, b) | b) } private Annotations::Nullability getTypeParameterNullability( TypeParameterConstraints constraints, Type type ) { if specific_type_parameter_nullability(constraints, getTypeRef(type), _) - then specific_type_parameter_nullability(constraints, getTypeRef(type), result) + then specific_type_parameter_nullability(constraints, getTypeRef(type), result.getNullability()) else ( specific_type_parameter_constraints(constraints, type) and result instanceof Annotations::NoNullability @@ -248,7 +259,7 @@ private Annotations::Nullability getTypeParameterNullability( private Annotations::Nullability getElementNullability(@has_type_annotation element) { if type_nullability(element, _) - then type_nullability(element, result) + then type_nullability(element, result.getNullability()) else result instanceof Annotations::NoNullability } @@ -258,26 +269,23 @@ private newtype TAnnotatedType = or exists(AnnotatedConstructedType c, int i | type = c.getType().(ConstructedType).getTypeArgument(i) and - annotations = c.getAnnotations().getChild(i) + annotations = Annotations::getChild(c.getAnnotations(), i) ) or - annotations.getFlags() = 0 and - annotations.getNullability() = getTypeParameterNullability(_, type) + annotations.getNoFlagsNullability() = getTypeParameterNullability(_, type) or - // All types exist as AnnotatedTypes with NoNullability. - annotations.getFlags() = 0 and - annotations.getNullability() instanceof Annotations::NoNullability + // All types have at least one annotated type + annotations.getNoFlagsNullability() instanceof Annotations::NoNullability or exists(AnnotatedArrayType at | type = at.getType().(ArrayType).getElementType() and - annotations = at.getAnnotations().getChild(0) + annotations = Annotations::getChild(at.getAnnotations(), 0) ) } /** A type with additional type information. */ class AnnotatedType extends TAnnotatedType { Type type; - Annotations::TypeAnnotations annotations; AnnotatedType() { this = TAnnotatedTypeNullability(type, annotations) } @@ -317,12 +325,12 @@ class AnnotatedType extends TAnnotatedType { } /** Holds if the type is a non-nullable reference, for example, `string` in a nullable-enabled context. */ - predicate isNonNullableRefType() { - this.getAnAnnotation() instanceof Annotations::NonNullableRefType - } + predicate isNonNullableRefType() { this.getAnAnnotation() instanceof Annotations::NoNullability } /** Holds if the type is a nullable reference, for example `string?`. */ - predicate isNullableRefType() { this.getAnAnnotation() instanceof Annotations::NullableRefType } + predicate isNullableRefType() { + this.getAnAnnotation() instanceof Annotations::AnnotatedNullability + } /** Holds if the type is a `ref`, for example the return type of `ref int F()`. */ predicate isRef() { this.getAnAnnotation() instanceof Annotations::RefTypeAnnotation } @@ -336,17 +344,16 @@ class AnnotatedType extends TAnnotatedType { /** Holds if this annotated type applies to element `e`. */ predicate appliesTo(Element e) { Annotations::elementTypeAnnotations(e, type, annotations) } - /** Holds if this annotated type is the type argument 'i' of constructed generic 'g'. */ + /** Holds if this annotated type is the `ith` type argument of constructed generic 'g'. */ predicate appliesToTypeArgument(ConstructedGeneric g, int i) { - this.getAnnotations().getFlags() = 0 and - this.getAnnotations().getNullability() = getElementNullability(g).getMember(i) and + this.getAnnotations().getNoFlagsNullability() = Annotations::getChildNullability(getElementNullability(g), + i) and this.getType() = g.getTypeArgument(i) } /** Holds if this annotated type applies to type parameter constraints `constraints`. */ predicate appliesToTypeConstraint(TypeParameterConstraints constraints) { - this.getAnnotations().getFlags() = 0 and - this.getAnnotations().getNullability() = getTypeParameterNullability(constraints, type) + this.getAnnotations().getNoFlagsNullability() = getTypeParameterNullability(constraints, type) } } @@ -357,7 +364,7 @@ class AnnotatedArrayType extends AnnotatedType { /** Gets the annotated element type of this array, for example `int?` in `int?[]`. */ final AnnotatedType getElementType() { result.getType() = type.getElementType() and - result.getAnnotations() = this.getAnnotations().getChild(0) + result.getAnnotations() = Annotations::getChild(this.getAnnotations(), 0) } private string getDimensionString(AnnotatedType elementType) { @@ -387,7 +394,7 @@ class AnnotatedConstructedType extends AnnotatedType { /** Gets the `i`th type argument of this constructed type. */ AnnotatedType getTypeArgument(int i) { result.getType() = type.getTypeArgument(i) and - result.getAnnotations() = this.getAnnotations().getChild(i) + result.getAnnotations() = Annotations::getChild(this.getAnnotations(), i) } override string toString() { From 61630118fef5a0aad35215a9dbb86993ccfce810 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Sun, 3 Nov 2019 18:37:38 +0000 Subject: [PATCH 1040/1227] C#: Fix ql tests. --- csharp/ql/test/library-tests/aliases/aliases1.expected | 2 -- csharp/ql/test/library-tests/aliases/aliases2.expected | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/csharp/ql/test/library-tests/aliases/aliases1.expected b/csharp/ql/test/library-tests/aliases/aliases1.expected index f6289f38f51..9417df43012 100644 --- a/csharp/ql/test/library-tests/aliases/aliases1.expected +++ b/csharp/ql/test/library-tests/aliases/aliases1.expected @@ -1,3 +1 @@ -| Assembly1.dll:0:0:0:0 | Class | -| Assembly2.dll:0:0:0:0 | Class | | Program.cs:10:7:10:11 | Class | diff --git a/csharp/ql/test/library-tests/aliases/aliases2.expected b/csharp/ql/test/library-tests/aliases/aliases2.expected index 45870c5dda2..50cfbf37f1e 100644 --- a/csharp/ql/test/library-tests/aliases/aliases2.expected +++ b/csharp/ql/test/library-tests/aliases/aliases2.expected @@ -1,3 +1,3 @@ -| Program.cs:18:21:18:22 | c1 | Assembly1.dll:0:0:0:0 | Class | -| Program.cs:19:21:19:22 | c2 | Assembly2.dll:0:0:0:0 | Class | +| Program.cs:18:21:18:22 | c1 | Program.cs:10:7:10:11 | Class | +| Program.cs:19:21:19:22 | c2 | Program.cs:10:7:10:11 | Class | | Program.cs:20:15:20:16 | c3 | Program.cs:10:7:10:11 | Class | From 657c839e2bfc1a14d2768d9c2f0244da590e9802 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Sun, 3 Nov 2019 18:56:14 +0000 Subject: [PATCH 1041/1227] C#: Change varchar to string in the dbscheme. --- csharp/ql/src/semmlecode.csharp.dbscheme | 130 +++++++++++------------ 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index a26548ca242..e55d8c99030 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -157,28 +157,28 @@ compilation_finished( externalDefects( unique int id: @externalDefect, - varchar(900) queryPath: string ref, + string queryPath: string ref, int location: @location ref, - varchar(900) message: string ref, + string message: string ref, float severity: float ref); externalMetrics( unique int id: @externalMetric, - varchar(900) queryPath: string ref, + string queryPath: string ref, int location: @location ref, float value: float ref); externalData( int id: @externalDataElement, - varchar(900) path: string ref, + string path: string ref, int column: int ref, - varchar(900) value: string ref); + string value: string ref); snapshotDate( unique date snapshotDate: date ref); sourceLocationPrefix( - varchar(900) prefix: string ref); + string prefix: string ref); /* * Duplicate code @@ -186,12 +186,12 @@ sourceLocationPrefix( duplicateCode( unique int id: @duplication, - varchar(900) relativePath: string ref, + string relativePath: string ref, int equivClass: int ref); similarCode( unique int id: @similarity, - varchar(900) relativePath: string ref, + string relativePath: string ref, int equivClass: int ref); @duplication_or_similarity = @duplication | @similarity @@ -252,9 +252,9 @@ numlines( assemblies( unique int id: @assembly, int file: @file ref, - varchar(900) fullname: string ref, - varchar(900) name: string ref, - varchar(900) version: string ref); + string fullname: string ref, + string name: string ref, + string version: string ref); /* fromSource(0) = unknown, @@ -263,15 +263,15 @@ assemblies( */ files( unique int id: @file, - varchar(900) name: string ref, - varchar(900) simple: string ref, - varchar(900) ext: string ref, + string name: string ref, + string simple: string ref, + string ext: string ref, int fromSource: int ref); folders( unique int id: @folder, - varchar(900) name: string ref, - varchar(900) simple: string ref); + string name: string ref, + string simple: string ref); @container = @folder | @file ; @@ -291,7 +291,7 @@ file_extraction_mode( namespaces( unique int id: @namespace, - varchar(900) name: string ref); + string name: string ref); namespace_declarations( unique int id: @namespace_declaration, @@ -330,7 +330,7 @@ using_directive_location( types( unique int id: @type, int kind: int ref, - varchar(900) name: string ref); + string name: string ref); case @type.kind of 1 = @bool_type @@ -378,7 +378,7 @@ case @type.kind of typerefs( unique int id: @typeref, - varchar(900) name: string ref); + string name: string ref); typeref_type( int id: @typeref ref, @@ -540,7 +540,7 @@ specific_type_parameter_nullability( modifiers( unique int id: @modifier, - varchar(900) name: string ref); + string name: string ref); has_modifiers( int id: @modifiable_direct ref, @@ -558,7 +558,7 @@ compiler_generated(unique int id: @modifiable_direct ref); exprorstmt_name( unique int parent_id: @named_exprorstmt ref, - varchar(900) name: string ref); + string name: string ref); nested_types( unique int id: @type ref, @@ -567,7 +567,7 @@ nested_types( properties( unique int id: @property, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @property ref); @@ -578,7 +578,7 @@ property_location( indexers( unique int id: @indexer, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @indexer ref); @@ -590,7 +590,7 @@ indexer_location( accessors( unique int id: @accessor, int kind: int ref, - varchar(900) name: string ref, + string name: string ref, int declaring_member_id: @member ref, int unbound_id: @accessor ref); @@ -605,7 +605,7 @@ accessor_location( events( unique int id: @event, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @event ref); @@ -617,7 +617,7 @@ event_location( event_accessors( unique int id: @event_accessor, int kind: int ref, - varchar(900) name: string ref, + string name: string ref, int declaring_event_id: @event ref, int unbound_id: @event_accessor ref); @@ -632,8 +632,8 @@ event_accessor_location( operators( unique int id: @operator, - varchar(900) name: string ref, - varchar(900) symbol: string ref, + string name: string ref, + string symbol: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @operator ref); @@ -654,7 +654,7 @@ constant_value( methods( unique int id: @method, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @method ref); @@ -665,7 +665,7 @@ method_location( constructors( unique int id: @constructor, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int unbound_id: @constructor ref); @@ -675,7 +675,7 @@ constructor_location( destructors( unique int id: @destructor, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int unbound_id: @destructor ref); @@ -693,7 +693,7 @@ explicitly_implements( local_functions( unique int id: @local_function, - varchar(900) name: string ref, + string name: string ref, int return_type: @type ref, int unbound_id: @local_function ref); @@ -710,7 +710,7 @@ local_function_stmts( fields( unique int id: @field, int kind: int ref, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @field ref); @@ -727,7 +727,7 @@ field_location( localvars( unique int id: @local_variable, int kind: int ref, - varchar(900) name: string ref, + string name: string ref, int implicitly_typed: int ref /* 0 = no, 1 = yes */, int type_id: @type_or_ref ref, int parent_id: @local_var_decl_expr ref); @@ -748,7 +748,7 @@ localvar_location( #keyset[index, parent_id] params( unique int id: @parameter, - varchar(900) name: string ref, + string name: string ref, int type_id: @type_or_ref ref, int index: int ref, int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ @@ -1085,7 +1085,7 @@ expr_compiler_generated( expr_value( unique int id: @expr ref, - varchar(900) value: string ref); + string value: string ref); expr_call( unique int caller_id: @expr ref, @@ -1103,7 +1103,7 @@ expr_location( dynamic_member_name( unique int id: @late_bindable_expr ref, - varchar(900) name: string ref); + string name: string ref); @qualifiable_expr = @member_access_expr | @method_invocation_expr @@ -1119,7 +1119,7 @@ expr_argument( expr_argument_name( unique int id: @expr ref, - varchar(900) name: string ref); + string name: string ref); /** CONTROL/DATA FLOW **/ @@ -1129,18 +1129,18 @@ expr_argument_name( xmlEncoding ( unique int id: @file ref, - varchar(900) encoding: string ref); + string encoding: string ref); xmlDTDs( unique int id: @xmldtd, - varchar(900) root: string ref, - varchar(900) publicId: string ref, - varchar(900) systemId: string ref, + string root: string ref, + string publicId: string ref, + string systemId: string ref, int fileid: @file ref); xmlElements( unique int id: @xmlelement, - varchar(900) name: string ref, + string name: string ref, int parentid: @xmlparent ref, int idx: int ref, int fileid: @file ref); @@ -1148,15 +1148,15 @@ xmlElements( xmlAttrs( unique int id: @xmlattribute, int elementid: @xmlelement ref, - varchar(900) name: string ref, - varchar(3600) value: string ref, + string name: string ref, + string value: string ref, int idx: int ref, int fileid: @file ref); xmlNs( int id: @xmlnamespace, - varchar(900) prefixName: string ref, - varchar(900) URI: string ref, + string prefixName: string ref, + string URI: string ref, int fileid: @file ref); xmlHasNs( @@ -1166,13 +1166,13 @@ xmlHasNs( xmlComments( unique int id: @xmlcomment, - varchar(3600) text: string ref, + string text: string ref, int parentid: @xmlparent ref, int fileid: @file ref); xmlChars( unique int id: @xmlcharacters, - varchar(3600) text: string ref, + string text: string ref, int parentid: @xmlparent ref, int idx: int ref, int isCDATA: int ref, @@ -1192,8 +1192,8 @@ xmllocations( commentline( unique int id: @commentline, int kind: int ref, - varchar(800) text: string ref, - varchar(800) rawtext: string ref); + string text: string ref, + string rawtext: string ref); case @commentline.kind of 0 = @singlelinecomment @@ -1246,22 +1246,22 @@ asp_code_inline(unique int code: @asp_code ref); asp_directive_attribute( int directive: @asp_directive ref, int index: int ref, - varchar(1000) name: string ref, + string name: string ref, int value: @asp_quoted_string ref); asp_directive_name( unique int directive: @asp_directive ref, - varchar(1000) name: string ref); + string name: string ref); asp_element_body( unique int element: @asp_element ref, - varchar(1000) body: string ref); + string body: string ref); asp_tag_attribute( int tag: @asp_open_tag ref, int index: int ref, - varchar(1000) name: string ref, + string name: string ref, int attribute: @asp_attribute ref); asp_tag_name( unique int tag: @asp_open_tag ref, - varchar(1000) name: string ref); + string name: string ref); asp_tag_isempty(int tag: @asp_open_tag ref); /* Common Intermediate Language - CIL */ @@ -1616,7 +1616,7 @@ cil_access( cil_value( unique int instruction: @cil_literal ref, - varchar(900) value: string ref); + string value: string ref); #keyset[instruction, index] cil_switch( @@ -1649,7 +1649,7 @@ case @cil_type.kind of cil_type( unique int id: @cil_type, - varchar(900) name: string ref, + string name: string ref, int kind: int ref, int parent: @cil_type_container ref, int sourceDecl: @cil_type ref); @@ -1665,7 +1665,7 @@ cil_array_type( cil_method( unique int id: @cil_method, - varchar(900) name: string ref, + string name: string ref, int parent: @cil_type ref, int return_type: @cil_type ref); @@ -1686,7 +1686,7 @@ cil_implements( cil_field( unique int id: @cil_field, int parent: @cil_type ref, - varchar(900) name: string ref, + string name: string ref, int field_type: @cil_type ref); @cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; @@ -1723,13 +1723,13 @@ cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); cil_property( unique int id: @cil_property, int parent: @cil_type ref, - varchar(900) name: string ref, + string name: string ref, int property_type: @cil_type ref); #keyset[parent, name] cil_event(unique int id: @cil_event, int parent: @cil_type ref, - varchar(900) name: string ref, + string name: string ref, int event_type: @cil_type ref); #keyset[impl, index] @@ -1827,14 +1827,14 @@ cil_attribute( #keyset[attribute_id, param] cil_attribute_named_argument( int attribute_id: @cil_attribute ref, - varchar(100) param: string ref, - varchar(900) value: string ref); + string param: string ref, + string value: string ref); #keyset[attribute_id, index] cil_attribute_positional_argument( int attribute_id: @cil_attribute ref, int index: int ref, - varchar(900) value: string ref); + string value: string ref); // Common .Net data model covering both C# and CIL From 4d13957eedd8b34125c5aeb1cbd826483be36e48 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Sun, 3 Nov 2019 19:41:50 +0000 Subject: [PATCH 1042/1227] C#: Modify db upgrade script --- .../semmlecode.csharp.dbscheme | 133 +++++++++--------- 1 file changed, 66 insertions(+), 67 deletions(-) diff --git a/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme b/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme index e4ab77432e6..e55d8c99030 100644 --- a/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme +++ b/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme @@ -157,28 +157,28 @@ compilation_finished( externalDefects( unique int id: @externalDefect, - varchar(900) queryPath: string ref, + string queryPath: string ref, int location: @location ref, - varchar(900) message: string ref, + string message: string ref, float severity: float ref); externalMetrics( unique int id: @externalMetric, - varchar(900) queryPath: string ref, + string queryPath: string ref, int location: @location ref, float value: float ref); externalData( int id: @externalDataElement, - varchar(900) path: string ref, + string path: string ref, int column: int ref, - varchar(900) value: string ref); + string value: string ref); snapshotDate( unique date snapshotDate: date ref); sourceLocationPrefix( - varchar(900) prefix: string ref); + string prefix: string ref); /* * Duplicate code @@ -186,12 +186,12 @@ sourceLocationPrefix( duplicateCode( unique int id: @duplication, - varchar(900) relativePath: string ref, + string relativePath: string ref, int equivClass: int ref); similarCode( unique int id: @similarity, - varchar(900) relativePath: string ref, + string relativePath: string ref, int equivClass: int ref); @duplication_or_similarity = @duplication | @similarity @@ -252,9 +252,9 @@ numlines( assemblies( unique int id: @assembly, int file: @file ref, - varchar(900) fullname: string ref, - varchar(900) name: string ref, - varchar(900) version: string ref); + string fullname: string ref, + string name: string ref, + string version: string ref); /* fromSource(0) = unknown, @@ -263,15 +263,15 @@ assemblies( */ files( unique int id: @file, - varchar(900) name: string ref, - varchar(900) simple: string ref, - varchar(900) ext: string ref, + string name: string ref, + string simple: string ref, + string ext: string ref, int fromSource: int ref); folders( unique int id: @folder, - varchar(900) name: string ref, - varchar(900) simple: string ref); + string name: string ref, + string simple: string ref); @container = @folder | @file ; @@ -291,7 +291,7 @@ file_extraction_mode( namespaces( unique int id: @namespace, - varchar(900) name: string ref); + string name: string ref); namespace_declarations( unique int id: @namespace_declaration, @@ -330,7 +330,7 @@ using_directive_location( types( unique int id: @type, int kind: int ref, - varchar(900) name: string ref); + string name: string ref); case @type.kind of 1 = @bool_type @@ -378,7 +378,7 @@ case @type.kind of typerefs( unique int id: @typeref, - varchar(900) name: string ref); + string name: string ref); typeref_type( int id: @typeref ref, @@ -540,7 +540,7 @@ specific_type_parameter_nullability( modifiers( unique int id: @modifier, - varchar(900) name: string ref); + string name: string ref); has_modifiers( int id: @modifiable_direct ref, @@ -558,7 +558,7 @@ compiler_generated(unique int id: @modifiable_direct ref); exprorstmt_name( unique int parent_id: @named_exprorstmt ref, - varchar(900) name: string ref); + string name: string ref); nested_types( unique int id: @type ref, @@ -567,7 +567,7 @@ nested_types( properties( unique int id: @property, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @property ref); @@ -578,7 +578,7 @@ property_location( indexers( unique int id: @indexer, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @indexer ref); @@ -590,7 +590,7 @@ indexer_location( accessors( unique int id: @accessor, int kind: int ref, - varchar(900) name: string ref, + string name: string ref, int declaring_member_id: @member ref, int unbound_id: @accessor ref); @@ -605,7 +605,7 @@ accessor_location( events( unique int id: @event, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @event ref); @@ -617,7 +617,7 @@ event_location( event_accessors( unique int id: @event_accessor, int kind: int ref, - varchar(900) name: string ref, + string name: string ref, int declaring_event_id: @event ref, int unbound_id: @event_accessor ref); @@ -632,8 +632,8 @@ event_accessor_location( operators( unique int id: @operator, - varchar(900) name: string ref, - varchar(900) symbol: string ref, + string name: string ref, + string symbol: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @operator ref); @@ -654,7 +654,7 @@ constant_value( methods( unique int id: @method, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @method ref); @@ -665,7 +665,7 @@ method_location( constructors( unique int id: @constructor, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int unbound_id: @constructor ref); @@ -675,7 +675,7 @@ constructor_location( destructors( unique int id: @destructor, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int unbound_id: @destructor ref); @@ -693,7 +693,7 @@ explicitly_implements( local_functions( unique int id: @local_function, - varchar(900) name: string ref, + string name: string ref, int return_type: @type ref, int unbound_id: @local_function ref); @@ -710,7 +710,7 @@ local_function_stmts( fields( unique int id: @field, int kind: int ref, - varchar(900) name: string ref, + string name: string ref, int declaring_type_id: @type ref, int type_id: @type_or_ref ref, int unbound_id: @field ref); @@ -727,7 +727,7 @@ field_location( localvars( unique int id: @local_variable, int kind: int ref, - varchar(900) name: string ref, + string name: string ref, int implicitly_typed: int ref /* 0 = no, 1 = yes */, int type_id: @type_or_ref ref, int parent_id: @local_var_decl_expr ref); @@ -748,7 +748,7 @@ localvar_location( #keyset[index, parent_id] params( unique int id: @parameter, - varchar(900) name: string ref, + string name: string ref, int type_id: @type_or_ref ref, int index: int ref, int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ @@ -1085,7 +1085,7 @@ expr_compiler_generated( expr_value( unique int id: @expr ref, - varchar(900) value: string ref); + string value: string ref); expr_call( unique int caller_id: @expr ref, @@ -1103,12 +1103,11 @@ expr_location( dynamic_member_name( unique int id: @late_bindable_expr ref, - varchar(900) name: string ref); + string name: string ref); @qualifiable_expr = @member_access_expr | @method_invocation_expr - | @element_access_expr - | @delegate_invocation_expr; + | @element_access_expr; conditional_access( unique int id: @qualifiable_expr ref); @@ -1120,7 +1119,7 @@ expr_argument( expr_argument_name( unique int id: @expr ref, - varchar(900) name: string ref); + string name: string ref); /** CONTROL/DATA FLOW **/ @@ -1130,18 +1129,18 @@ expr_argument_name( xmlEncoding ( unique int id: @file ref, - varchar(900) encoding: string ref); + string encoding: string ref); xmlDTDs( unique int id: @xmldtd, - varchar(900) root: string ref, - varchar(900) publicId: string ref, - varchar(900) systemId: string ref, + string root: string ref, + string publicId: string ref, + string systemId: string ref, int fileid: @file ref); xmlElements( unique int id: @xmlelement, - varchar(900) name: string ref, + string name: string ref, int parentid: @xmlparent ref, int idx: int ref, int fileid: @file ref); @@ -1149,15 +1148,15 @@ xmlElements( xmlAttrs( unique int id: @xmlattribute, int elementid: @xmlelement ref, - varchar(900) name: string ref, - varchar(3600) value: string ref, + string name: string ref, + string value: string ref, int idx: int ref, int fileid: @file ref); xmlNs( int id: @xmlnamespace, - varchar(900) prefixName: string ref, - varchar(900) URI: string ref, + string prefixName: string ref, + string URI: string ref, int fileid: @file ref); xmlHasNs( @@ -1167,13 +1166,13 @@ xmlHasNs( xmlComments( unique int id: @xmlcomment, - varchar(3600) text: string ref, + string text: string ref, int parentid: @xmlparent ref, int fileid: @file ref); xmlChars( unique int id: @xmlcharacters, - varchar(3600) text: string ref, + string text: string ref, int parentid: @xmlparent ref, int idx: int ref, int isCDATA: int ref, @@ -1193,8 +1192,8 @@ xmllocations( commentline( unique int id: @commentline, int kind: int ref, - varchar(800) text: string ref, - varchar(800) rawtext: string ref); + string text: string ref, + string rawtext: string ref); case @commentline.kind of 0 = @singlelinecomment @@ -1247,22 +1246,22 @@ asp_code_inline(unique int code: @asp_code ref); asp_directive_attribute( int directive: @asp_directive ref, int index: int ref, - varchar(1000) name: string ref, + string name: string ref, int value: @asp_quoted_string ref); asp_directive_name( unique int directive: @asp_directive ref, - varchar(1000) name: string ref); + string name: string ref); asp_element_body( unique int element: @asp_element ref, - varchar(1000) body: string ref); + string body: string ref); asp_tag_attribute( int tag: @asp_open_tag ref, int index: int ref, - varchar(1000) name: string ref, + string name: string ref, int attribute: @asp_attribute ref); asp_tag_name( unique int tag: @asp_open_tag ref, - varchar(1000) name: string ref); + string name: string ref); asp_tag_isempty(int tag: @asp_open_tag ref); /* Common Intermediate Language - CIL */ @@ -1617,7 +1616,7 @@ cil_access( cil_value( unique int instruction: @cil_literal ref, - varchar(900) value: string ref); + string value: string ref); #keyset[instruction, index] cil_switch( @@ -1650,7 +1649,7 @@ case @cil_type.kind of cil_type( unique int id: @cil_type, - varchar(900) name: string ref, + string name: string ref, int kind: int ref, int parent: @cil_type_container ref, int sourceDecl: @cil_type ref); @@ -1666,7 +1665,7 @@ cil_array_type( cil_method( unique int id: @cil_method, - varchar(900) name: string ref, + string name: string ref, int parent: @cil_type ref, int return_type: @cil_type ref); @@ -1687,7 +1686,7 @@ cil_implements( cil_field( unique int id: @cil_field, int parent: @cil_type ref, - varchar(900) name: string ref, + string name: string ref, int field_type: @cil_type ref); @cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; @@ -1724,13 +1723,13 @@ cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); cil_property( unique int id: @cil_property, int parent: @cil_type ref, - varchar(900) name: string ref, + string name: string ref, int property_type: @cil_type ref); #keyset[parent, name] cil_event(unique int id: @cil_event, int parent: @cil_type ref, - varchar(900) name: string ref, + string name: string ref, int event_type: @cil_type ref); #keyset[impl, index] @@ -1828,14 +1827,14 @@ cil_attribute( #keyset[attribute_id, param] cil_attribute_named_argument( int attribute_id: @cil_attribute ref, - varchar(100) param: string ref, - varchar(900) value: string ref); + string param: string ref, + string value: string ref); #keyset[attribute_id, index] cil_attribute_positional_argument( int attribute_id: @cil_attribute ref, int index: int ref, - varchar(900) value: string ref); + string value: string ref); // Common .Net data model covering both C# and CIL From ce188c0c22f703ef93b29cff48791e15145b0169 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 4 Nov 2019 09:39:43 +0000 Subject: [PATCH 1043/1227] C#: Autoformat --- csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql index 416929afb92..c37e180d1ec 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.ql @@ -52,8 +52,8 @@ query predicate constructedTypes(AnnotatedConstructedType at, int i, string arg, } query predicate nullableTypeParameters(TypeParameter p) { - p.getConstraints().hasNullableRefTypeConstraint() - and p.getLocation().getFile().getBaseName() = "NullableRefTypes.cs" + p.getConstraints().hasNullableRefTypeConstraint() and + p.getLocation().getFile().getBaseName() = "NullableRefTypes.cs" } query predicate annotatedTypeConstraints(TypeParameter p, AnnotatedType t) { From a261cbaeef409075107477709deca27566ae28f1 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 6 Nov 2019 12:43:12 +0000 Subject: [PATCH 1044/1227] C#: Fix type ID generation from merge --- .../Semmle.Extraction.CSharp/SymbolExtensions.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index 6e2b52f3086..9f7f36ce662 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -234,12 +234,7 @@ namespace Semmle.Extraction.CSharp public static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction) { - bool prefixAssembly = false; - if (named.IsAnonymous()) prefixAssembly = true; - if (named.ContainingAssembly is null) prefixAssembly = false; - - if (prefixAssembly) - BuildAssembly(named.ContainingAssembly, trapFile); + bool prefixAssembly = !(named.ContainingAssembly is null); if (named.IsTupleType) { @@ -263,6 +258,8 @@ namespace Semmle.Extraction.CSharp } else if (named.ContainingNamespace != null) { + if (prefixAssembly) + BuildAssembly(named.ContainingAssembly, trapFile); named.ContainingNamespace.BuildNamespace(cx, trapFile); } From fe83bac0fb368f061edf827e11bc9fe6a4947564 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 6 Nov 2019 18:22:26 +0000 Subject: [PATCH 1045/1227] C#: Fix up test output C#: Fix a qltest whereby a tuple type having multiple underlying types was causing an issue with the IR sanity checks. C#: Revert more changes. C#: Fix tests and remove dead code. --- .../Entities/Method.cs | 2 +- .../Entities/Parameter.cs | 3 +- .../Entities/Types/NamedType.cs | 27 +- .../Entities/Types/TupleType.cs | 2 +- .../Entities/Types/Type.cs | 2 - .../Semmle.Extraction.CSharp/Extractor.cs | 3 +- .../SymbolExtensions.cs | 182 +-- .../Semmle.Extraction.CSharp/Tuples.cs | 8 +- .../extractor/Semmle.Extraction/Extractor.cs | 19 - .../src/semmle/code/csharp/AnnotatedType.qll | 2 +- .../library-tests/aliases/aliases1.expected | 2 + .../library-tests/aliases/aliases2.expected | 4 +- .../Disposal/DisposedParameter.expected | 2 +- .../csharp7/LocalVariables.expected | 10 +- .../library-tests/csharp7/TupleTypes.expected | 98 +- .../library/LibraryTypeDataFlow.expected | 1054 ++++++++--------- .../dispatch/GetADynamicTarget.expected | 232 ++-- .../format/StringFormatItemParameter.expected | 24 +- .../methods/Parameters9.expected | 4 +- .../overrides/Overrides22.expected | 6 +- .../toStringWithTypes.expected | 9 +- 21 files changed, 774 insertions(+), 921 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index f3aba9744be..f3a9a9f0d08 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -204,7 +204,7 @@ namespace Semmle.Extraction.CSharp.Entities if (type.ContainsTypeParameters(cx, method)) type.BuildTypeId(cx, trapFile, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0)); else - trapFile.WriteSubId(Type.Create(cx, type).TypeRef); + trapFile.WriteSubId(Type.Create(cx, type)); } protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index c353ea34c16..f05bab3f366 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -86,8 +86,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.Write(";parameter"); } - // If we don't have the type of the parameter, do not populate it. - public override bool NeedsPopulation => symbol.Type.TypeKind != TypeKind.Error; + public override bool NeedsPopulation => true; string Name { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index fa5f6a4bdf9..e22d32c0d01 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities return; } - trapFile.typeref_type((TypeRef)TypeRef, this); + trapFile.typeref_type((NamedTypeRef)TypeRef, this); if (symbol.IsGenericType) { @@ -151,39 +151,34 @@ namespace Semmle.Extraction.CSharp.Entities public NamedType Create(Context cx, INamedTypeSymbol init) => new NamedType(cx, init); } - public override Type TypeRef => Entities.TypeRef.Create(Context, this, symbol); + public override Type TypeRef => NamedTypeRef.Create(Context, symbol); } - class TypeRef : Type + class NamedTypeRef : Type { readonly Type referencedType; - public TypeRef(Context cx, Type type, ITypeSymbol symbol) : base(cx, symbol) + public NamedTypeRef(Context cx, INamedTypeSymbol symbol) : base(cx, symbol) { - referencedType = type; + referencedType = Type.Create(cx, symbol); } - public static TypeRef Create(Context cx, Type referencedType, ITypeSymbol type) => - NamedTypeRefFactory.Instance.CreateEntity2(cx, (referencedType, type)); + public static NamedTypeRef Create(Context cx, INamedTypeSymbol type) => + NamedTypeRefFactory.Instance.CreateEntity2(cx, type); - class NamedTypeRefFactory : ICachedEntityFactory<(Type, ITypeSymbol), TypeRef> + class NamedTypeRefFactory : ICachedEntityFactory { public static readonly NamedTypeRefFactory Instance = new NamedTypeRefFactory(); - public TypeRef Create(Context cx, (Type, ITypeSymbol) init) => new TypeRef(cx, init.Item1, init.Item2); + public NamedTypeRef Create(Context cx, INamedTypeSymbol init) => new NamedTypeRef(cx, init); } public override bool NeedsPopulation => true; public override void WriteId(TextWriter trapFile) { - void ExpandType(Context cx0, TextWriter tb0, ITypeSymbol sub) - { - sub.BuildTypeId(cx0, tb0, ExpandType); - } - - symbol.BuildTypeId(Context, trapFile, ExpandType); - trapFile.Write(";typeref"); + trapFile.WriteSubId(referencedType); + trapFile.Write(";typeRef"); } public override void Populate(TextWriter trapFile) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index d486506408b..de6ea217084 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -42,7 +42,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulateGenerics(); var underlyingType = NamedType.Create(Context, symbol.TupleUnderlyingType); - trapFile.tuple_underlying_type(this, underlyingType.TypeRef); + trapFile.tuple_underlying_type(this, underlyingType); int index = 0; foreach (var element in TupleElements) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 276cf6758e2..4b4a8f919ec 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -95,7 +95,6 @@ namespace Semmle.Extraction.CSharp.Entities var baseTypes = new List(); if (symbol.BaseType != null) { - // !! Do not extend "object" if the base type is missing :-( Type baseKey = Create(Context, symbol.BaseType); trapFile.extend(this, baseKey.TypeRef); if (symbol.TypeKind != TypeKind.Struct) @@ -269,7 +268,6 @@ namespace Semmle.Extraction.CSharp.Entities public static Type Create(Context cx, ITypeSymbol type) { type = type.DisambiguateType(); - const bool errorTypeIsNull = false; return type == null || (errorTypeIsNull && type.TypeKind == TypeKind.Error) ? NullType.Create(cx).Type : (Type)cx.CreateEntity(type); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs index fadcbd8127b..7ca12e00f26 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs @@ -120,8 +120,7 @@ namespace Semmle.Extraction.CSharp var syntaxTrees = new List(); var syntaxTreeTasks = ReadSyntaxTrees( compilerArguments.SourceFiles. - Select(src => canonicalPathCache.GetCanonicalPath(src.Path)). - Where(f => !f.EndsWith(".dll")), + Select(src => canonicalPathCache.GetCanonicalPath(src.Path)), analyser, compilerArguments.ParseOptions, compilerArguments.Encoding, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index 9f7f36ce662..e42eb56ddbc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Security.Cryptography; -using System.Text; namespace Semmle.Extraction.CSharp { @@ -135,34 +133,15 @@ namespace Semmle.Extraction.CSharp /// The action to apply to syntactic sub terms of this type. public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action subTermAction) { - switch(type.SpecialType) + if (type.SpecialType != SpecialType.None) { - case SpecialType.System_Object: - case SpecialType.System_Void: - case SpecialType.System_Boolean: - case SpecialType.System_Char: - case SpecialType.System_SByte: - case SpecialType.System_Byte: - case SpecialType.System_Int16: - case SpecialType.System_UInt16: - case SpecialType.System_Int32: - case SpecialType.System_UInt32: - case SpecialType.System_Int64: - case SpecialType.System_UInt64: - case SpecialType.System_Decimal: - case SpecialType.System_Single: - case SpecialType.System_Double: - case SpecialType.System_String: - case SpecialType.System_IntPtr: - case SpecialType.System_UIntPtr: - - /* - * Use the keyword ("int" etc) for the built-in types. - * This makes the IDs shorter and means that all built-in types map to - * the same entities (even when using multiple versions of mscorlib). - */ - trapFile.Write(type.ToDisplayString()); - return; + /* + * Use the keyword ("int" etc) for the built-in types. + * This makes the IDs shorter and means that all built-in types map to + * the same entities (even when using multiple versions of mscorlib). + */ + trapFile.Write(type.ToDisplayString()); + return; } using (cx.StackGuard) @@ -186,7 +165,7 @@ namespace Semmle.Extraction.CSharp case TypeKind.Pointer: var ptr = (IPointerTypeSymbol)type; subTermAction(cx, trapFile, ptr.PointedAtType); - trapFile.Write("*"); + trapFile.Write('*'); return; case TypeKind.TypeParameter: var tp = (ITypeParameterSymbol)type; @@ -214,28 +193,8 @@ namespace Semmle.Extraction.CSharp trapFile.Write(']'); } - private static void BuildAssembly(IAssemblySymbol asm, TextWriter trapFile, bool extraPrecise = false) + static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction) { - var assembly = asm.Identity; - trapFile.Write(assembly.Name); - trapFile.Write('_'); - trapFile.Write(assembly.Version.Major); - trapFile.Write('.'); - trapFile.Write(assembly.Version.Minor); - trapFile.Write('.'); - trapFile.Write(assembly.Version.Build); - if (extraPrecise) - { - trapFile.Write('.'); - trapFile.Write(assembly.Version.Revision); - } - trapFile.Write("::"); - } - - public static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction) - { - bool prefixAssembly = !(named.ContainingAssembly is null); - if (named.IsTupleType) { trapFile.Write('('); @@ -258,8 +217,6 @@ namespace Semmle.Extraction.CSharp } else if (named.ContainingNamespace != null) { - if (prefixAssembly) - BuildAssembly(named.ContainingAssembly, trapFile); named.ContainingNamespace.BuildNamespace(cx, trapFile); } @@ -290,6 +247,26 @@ namespace Semmle.Extraction.CSharp static void BuildNamespace(this INamespaceSymbol ns, Context cx, TextWriter trapFile) { + // Only include the assembly information in each type ID + // for normal extractions. This is because standalone extractions + // lack assembly information or may be ambiguous. + bool prependAssemblyToTypeId = !cx.Extractor.Standalone && ns.ContainingAssembly != null; + + if (prependAssemblyToTypeId) + { + // Note that we exclude the revision number as this has + // been observed to be unstable. + var assembly = ns.ContainingAssembly.Identity; + trapFile.Write(assembly.Name); + trapFile.Write('_'); + trapFile.Write(assembly.Version.Major); + trapFile.Write('.'); + trapFile.Write(assembly.Version.Minor); + trapFile.Write('.'); + trapFile.Write(assembly.Version.Build); + trapFile.Write("::"); + } + trapFile.WriteSubId(Namespace.Create(cx, ns)); trapFile.Write('.'); } @@ -379,7 +356,7 @@ namespace Semmle.Extraction.CSharp } trapFile.Write(namedType.Name); - if (namedType.IsGenericType && namedType.TypeArguments.Any()) + if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any()) { trapFile.Write('<'); trapFile.BuildList(",", namedType.TypeArguments, (p, tb0) => @@ -478,30 +455,6 @@ namespace Semmle.Extraction.CSharp public static SymbolInfo GetSymbolInfo(this Context cx, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode node) => cx.GetModel(node).GetSymbolInfo(node); - /// - /// Gets the symbol for a particular syntax node. - /// Throws an exception if the symbol is not found. - /// - /// - /// - /// This gives a nicer message than a "null pointer exception", - /// and should be used where we require a symbol to be resolved. - /// - /// - /// The extraction context. - /// The syntax node. - /// The resolved symbol. - public static ISymbol GetSymbol(this Context cx, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode node) - { - var info = GetSymbolInfo(cx, node); - if (info.Symbol == null) - { - throw new InternalError(node, "Could not resolve symbol"); - } - - return info.Symbol; - } - /// /// Determines the type of a node, or default /// if the type could not be determined. @@ -515,84 +468,11 @@ namespace Semmle.Extraction.CSharp return new AnnotatedTypeSymbol(info.Type.DisambiguateType(), info.Nullability.Annotation); } - /// - /// Gets the annotated type of an IPropertySymbol. - /// This has not yet been exposed on the public API. - /// - public static AnnotatedTypeSymbol GetAnnotatedType(this IPropertySymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation); - - /// - /// Gets the annotated type of an IFieldSymbol. - /// This has not yet been exposed on the public API. - /// - public static AnnotatedTypeSymbol GetAnnotatedType(this IFieldSymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation); - private static bool IsSpecialized(this IMethodSymbol method) => - method.IsGenericMethod && - !ReferenceEquals(method, method.OriginalDefinition) && - method.TypeParameters.Zip(method.TypeArguments, (a, b) => !ReferenceEquals(a, b)).Any(b => b); - - /// - /// Gets the annotated return type of an IMethodSymbol. - /// This has not yet been exposed on the public API. - /// - public static AnnotatedTypeSymbol GetAnnotatedReturnType(this IMethodSymbol symbol) => new AnnotatedTypeSymbol(symbol.ReturnType, symbol.ReturnNullableAnnotation); - - /// - /// Gets the type annotation for a NullableAnnotation. - /// - public static Kinds.TypeAnnotation GetTypeAnnotation(this NullableAnnotation na) - { - switch(na) - { - case NullableAnnotation.Annotated: - return Kinds.TypeAnnotation.Annotated; - case NullableAnnotation.NotAnnotated: - return Kinds.TypeAnnotation.NotAnnotated; - default: - return Kinds.TypeAnnotation.None; - } - } - - /// - /// Gets the annotated element type of an IArrayTypeSymbol. - /// This has not yet been exposed on the public API. - /// - public static AnnotatedTypeSymbol GetAnnotatedElementType(this IArrayTypeSymbol symbol) => - new AnnotatedTypeSymbol(symbol.ElementType, symbol.ElementNullableAnnotation); - /// /// Gets the annotated type arguments of an INamedTypeSymbol. /// This has not yet been exposed on the public API. /// public static IEnumerable GetAnnotatedTypeArguments(this INamedTypeSymbol symbol) => symbol.TypeArguments.Zip(symbol.TypeArgumentsNullableAnnotations, (t, a) => new AnnotatedTypeSymbol(t, a)); - - /// - /// Gets the annotated type arguments of an IMethodSymbol. - /// This has not yet been exposed on the public API. - /// - public static IEnumerable GetAnnotatedTypeArguments(this IMethodSymbol symbol) => - symbol.TypeArguments.Zip(symbol.TypeArgumentsNullableAnnotations, (t, a) => new AnnotatedTypeSymbol(t, a)); - - /// - /// Gets the annotated type constraints of an ITypeParameterSymbol. - /// This has not yet been exposed on the public API. - /// - public static IEnumerable GetAnnotatedTypeConstraints(this ITypeParameterSymbol symbol) => - symbol.ConstraintTypes.Zip(symbol.ConstraintNullableAnnotations, (t, a) => new AnnotatedTypeSymbol(t, a)); - - /// - /// Creates an AnnotatedTypeSymbol from an ITypeSymbol. - /// Note: not currently used but might be useful. - /// - public static AnnotatedTypeSymbol WithAnnotation(this ITypeSymbol symbol, NullableAnnotation annotation) => - new AnnotatedTypeSymbol(symbol, annotation); - - /// - /// Holds if this type looks like an "anonymous" type. Names of anonymous types - /// sometimes collide so they need to be handled separately. - /// - public static bool IsAnonymous(this INamedTypeSymbol type) => - type.IsAnonymousType || type.Name.StartsWith("<>"); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index c239d4f0bb2..f6de00452d0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -388,7 +388,7 @@ namespace Semmle.Extraction.CSharp internal static void nullability_member(this TextWriter trapFile, NullabilityEntity nullability, int index, NullabilityEntity child) { - trapFile.WriteTuple(nameof(nullability_member), nullability, index, child); + trapFile.WriteTuple("nullability_member", nullability, index, child); } internal static void numlines(this TextWriter trapFile, IEntity label, LineCounts lineCounts) @@ -481,7 +481,7 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("tuple_element", type, index, field); } - internal static void tuple_underlying_type(this TextWriter trapFile, TupleType type, Type underlying) + internal static void tuple_underlying_type(this TextWriter trapFile, TupleType type, NamedType underlying) { trapFile.WriteTuple("tuple_underlying_type", type, underlying); } @@ -526,12 +526,12 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("type_parameters", param, child, typeOrMethod, (int)param.Variance); } - internal static void typeref_type(this TextWriter trapFile, TypeRef typeref, Type type) + internal static void typeref_type(this TextWriter trapFile, NamedTypeRef typeref, Type type) { trapFile.WriteTuple("typeref_type", typeref, type); } - internal static void typerefs(this TextWriter trapFile, TypeRef type, string name) + internal static void typerefs(this TextWriter trapFile, NamedTypeRef type, string name) { trapFile.WriteTuple("typerefs", type, name); } diff --git a/csharp/extractor/Semmle.Extraction/Extractor.cs b/csharp/extractor/Semmle.Extraction/Extractor.cs index fd8aee723e3..e470d3258ec 100644 --- a/csharp/extractor/Semmle.Extraction/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction/Extractor.cs @@ -87,22 +87,6 @@ namespace Semmle.Extraction /// The extraction scope (what to include in this trap file). /// Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope); - - /// - /// Adjusts the algorithm used to generate identifiers in trap files. - /// - TrapIdenfierMode TrapIdentifiers { get; } - } - - /// - /// Configures how to generate identifiers in trap files. - /// - public enum TrapIdenfierMode - { - Imprecise, // Names are not qualified by assembly version - Flexible, // Some names are qualified by assembly versions - typerefs are not however. - Precise, // All names are qualified by their partial assembly version (excludes build number) - ExtraPrecise // All names are qualified by their full assembly version. } /// @@ -128,7 +112,6 @@ namespace Semmle.Extraction public Extractor(bool standalone, string outputPath, ILogger logger) { Standalone = standalone; - if (Standalone) TrapIdentifiers = TrapIdenfierMode.Imprecise; OutputPath = outputPath; Logger = logger; } @@ -214,7 +197,5 @@ namespace Semmle.Extraction public ILogger Logger { get; private set; } public static string Version => $"{ThisAssembly.Git.BaseTag} ({ThisAssembly.Git.Sha})"; - - public TrapIdenfierMode TrapIdentifiers { get; } = TrapIdenfierMode.Imprecise; } } diff --git a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll index 96300abdcd8..98e25aa7524 100644 --- a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll +++ b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll @@ -8,7 +8,7 @@ import csharp -module Annotations { +private module Annotations { newtype TAnnotation = TReadonlyRefType() or TRefType() or diff --git a/csharp/ql/test/library-tests/aliases/aliases1.expected b/csharp/ql/test/library-tests/aliases/aliases1.expected index 9417df43012..f6289f38f51 100644 --- a/csharp/ql/test/library-tests/aliases/aliases1.expected +++ b/csharp/ql/test/library-tests/aliases/aliases1.expected @@ -1 +1,3 @@ +| Assembly1.dll:0:0:0:0 | Class | +| Assembly2.dll:0:0:0:0 | Class | | Program.cs:10:7:10:11 | Class | diff --git a/csharp/ql/test/library-tests/aliases/aliases2.expected b/csharp/ql/test/library-tests/aliases/aliases2.expected index 50cfbf37f1e..45870c5dda2 100644 --- a/csharp/ql/test/library-tests/aliases/aliases2.expected +++ b/csharp/ql/test/library-tests/aliases/aliases2.expected @@ -1,3 +1,3 @@ -| Program.cs:18:21:18:22 | c1 | Program.cs:10:7:10:11 | Class | -| Program.cs:19:21:19:22 | c2 | Program.cs:10:7:10:11 | Class | +| Program.cs:18:21:18:22 | c1 | Assembly1.dll:0:0:0:0 | Class | +| Program.cs:19:21:19:22 | c2 | Assembly2.dll:0:0:0:0 | Class | | Program.cs:20:15:20:16 | c3 | Program.cs:10:7:10:11 | Class | diff --git a/csharp/ql/test/library-tests/commons/Disposal/DisposedParameter.expected b/csharp/ql/test/library-tests/commons/Disposal/DisposedParameter.expected index 917ea971094..88f27e32bbc 100644 --- a/csharp/ql/test/library-tests/commons/Disposal/DisposedParameter.expected +++ b/csharp/ql/test/library-tests/commons/Disposal/DisposedParameter.expected @@ -332,7 +332,7 @@ | XmlEncodedRawTextWriterIndent(Stream, XmlWriterSettings) | 0 | | XmlEncodedRawTextWriterIndent(TextWriter, XmlWriterSettings) | 0 | | XmlRawWriterWrapper(XmlWriter) | 0 | -| XmlSqlBinaryReader(Stream, byte[], int, string, bool, XmlReaderSettings) | 0 | +| XmlSqlBinaryReader(Stream, Byte[], int, string, bool, XmlReaderSettings) | 0 | | XmlTextReader(Stream) | 0 | | XmlTextReader(Stream, XmlNameTable) | 0 | | XmlTextReader(Stream, XmlNodeType, XmlParserContext) | 0 | diff --git a/csharp/ql/test/library-tests/csharp7/LocalVariables.expected b/csharp/ql/test/library-tests/csharp7/LocalVariables.expected index 33514e8f6a3..06f61a52f91 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalVariables.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalVariables.expected @@ -33,8 +33,8 @@ | CSharp7.cs:119:13:119:15 | m11 | int | | CSharp7.cs:122:16:122:18 | m12 | string | | CSharp7.cs:123:16:123:18 | m13 | string | -| CSharp7.cs:135:19:135:20 | f4 | Func | -| CSharp7.cs:139:24:139:25 | f5 | Func | +| CSharp7.cs:135:19:135:20 | f4 | Func | +| CSharp7.cs:139:24:139:25 | f5 | Func | | CSharp7.cs:151:16:151:16 | a | Action | | CSharp7.cs:176:16:176:18 | src | string | | CSharp7.cs:181:13:181:17 | sink1 | string | @@ -42,7 +42,7 @@ | CSharp7.cs:183:13:183:17 | sink3 | string | | CSharp7.cs:191:13:191:14 | v1 | int | | CSharp7.cs:192:17:192:18 | r1 | int | -| CSharp7.cs:193:13:193:17 | array | int[] | +| CSharp7.cs:193:13:193:17 | array | Int32[] | | CSharp7.cs:196:17:196:18 | r2 | int | | CSharp7.cs:197:17:197:18 | r3 | int | | CSharp7.cs:199:17:199:18 | r4 | int | @@ -58,8 +58,8 @@ | CSharp7.cs:261:22:261:23 | i3 | int | | CSharp7.cs:264:25:264:26 | s2 | string | | CSharp7.cs:270:22:270:23 | v2 | object | -| CSharp7.cs:283:13:283:16 | dict | Dictionary | -| CSharp7.cs:284:13:284:16 | list | IEnumerable<(int, string)> | +| CSharp7.cs:283:13:283:16 | dict | Dictionary | +| CSharp7.cs:284:13:284:16 | list | IEnumerable<(Int32,String)> | | CSharp7.cs:286:23:286:23 | a | int | | CSharp7.cs:286:33:286:33 | b | string | | CSharp7.cs:288:23:288:23 | a | int | diff --git a/csharp/ql/test/library-tests/csharp7/TupleTypes.expected b/csharp/ql/test/library-tests/csharp7/TupleTypes.expected index 8c50282dd03..7168e2b833f 100644 --- a/csharp/ql/test/library-tests/csharp7/TupleTypes.expected +++ b/csharp/ql/test/library-tests/csharp7/TupleTypes.expected @@ -1,49 +1,49 @@ -| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:77:10:77:14 | a | -| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:77:36:77:36 | Item1 | -| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:78:24:78:24 | b | -| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:77:17:77:30 | Item2 | -| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:77:39:77:39 | z | -| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:78:27:78:32 | Item2 | -| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 0 | CSharp7.cs:98:19:98:19 | Item1 | -| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 1 | CSharp7.cs:98:22:98:42 | Item2 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:214:6:214:8 | Item1 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:224:10:224:14 | x | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:225:10:225:10 | Item1 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:214:11:214:16 | Item2 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:224:17:224:17 | Item2 | -| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:225:13:225:17 | y | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:64:6:64:8 | Item1 | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:71:10:71:14 | x | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:77:18:77:22 | b | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:78:28:78:28 | c | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:112:15:112:16 | m4 | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:114:19:114:24 | m8 | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:64:11:64:13 | Item2 | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:71:17:71:21 | y | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:77:25:77:29 | c | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:78:31:78:31 | a | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:112:19:112:20 | m5 | -| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:114:27:114:32 | m9 | -| (Int32,Int32,Int32) | (int, int, int) | ValueTuple | 3 | 0 | CSharp7.cs:75:10:75:10 | x | -| (Int32,Int32,Int32) | (int, int, int) | ValueTuple | 3 | 1 | CSharp7.cs:75:13:75:13 | y | -| (Int32,Int32,Int32) | (int, int, int) | ValueTuple | 3 | 2 | CSharp7.cs:75:16:75:22 | Item3 | -| (Int32,String) | (int, string) | ValueTuple | 2 | 0 | CSharp7.cs:284:41:284:48 | Key | -| (Int32,String) | (int, string) | ValueTuple | 2 | 0 | CSharp7.cs:286:19:286:23 | a | -| (Int32,String) | (int, string) | ValueTuple | 2 | 1 | CSharp7.cs:284:51:284:60 | Value | -| (Int32,String) | (int, string) | ValueTuple | 2 | 1 | CSharp7.cs:286:26:286:33 | b | -| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:109:10:109:15 | m1 | -| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:112:10:112:11 | m3 | -| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:114:10:114:15 | m7 | -| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:109:18:109:23 | m2 | -| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:112:14:112:21 | Item2 | -| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:114:18:114:33 | Item2 | -| (String,Int32) | (string, int) | ValueTuple | 2 | 0 | CSharp7.cs:79:14:79:14 | i | -| (String,Int32) | (string, int) | ValueTuple | 2 | 0 | CSharp7.cs:79:23:79:24 | Item1 | -| (String,Int32) | (string, int) | ValueTuple | 2 | 0 | CSharp7.cs:84:17:84:17 | a | -| (String,Int32) | (string, int) | ValueTuple | 2 | 1 | CSharp7.cs:79:17:79:17 | j | -| (String,Int32) | (string, int) | ValueTuple | 2 | 1 | CSharp7.cs:79:27:79:27 | x | -| (String,Int32) | (string, int) | ValueTuple | 2 | 1 | CSharp7.cs:84:23:84:23 | Item2 | -| (String,String) | (string, string) | ValueTuple | 2 | 0 | CSharp7.cs:89:19:89:27 | Item1 | -| (String,String) | (string, string) | ValueTuple | 2 | 0 | CSharp7.cs:90:10:90:15 | t2 | -| (String,String) | (string, string) | ValueTuple | 2 | 1 | CSharp7.cs:89:30:89:33 | Item2 | -| (String,String) | (string, string) | ValueTuple | 2 | 1 | CSharp7.cs:90:18:90:23 | t3 | +| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:77:10:77:14 | a | +| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:77:36:77:36 | Item1 | +| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:78:24:78:24 | b | +| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:77:17:77:30 | Item2 | +| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:77:39:77:39 | z | +| (Int32,(Int32,Int32)) | (int, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:78:27:78:32 | Item2 | +| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 0 | CSharp7.cs:98:19:98:19 | Item1 | +| (Int32,(String,Int32)) | (int, (string, int)) | ValueTuple | 2 | 1 | CSharp7.cs:98:22:98:42 | Item2 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:214:6:214:8 | Item1 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:224:10:224:14 | x | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 0 | CSharp7.cs:225:10:225:10 | Item1 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:214:11:214:16 | Item2 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:224:17:224:17 | Item2 | +| (Int32,Double) | (int, double) | ValueTuple | 2 | 1 | CSharp7.cs:225:13:225:17 | y | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:64:6:64:8 | Item1 | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:71:10:71:14 | x | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:77:18:77:22 | b | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:78:28:78:28 | c | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:112:15:112:16 | m4 | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 0 | CSharp7.cs:114:19:114:24 | m8 | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:64:11:64:13 | Item2 | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:71:17:71:21 | y | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:77:25:77:29 | c | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:78:31:78:31 | a | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:112:19:112:20 | m5 | +| (Int32,Int32) | (int, int) | ValueTuple | 2 | 1 | CSharp7.cs:114:27:114:32 | m9 | +| (Int32,Int32,Int32) | (int, int, int) | ValueTuple | 3 | 0 | CSharp7.cs:75:10:75:10 | x | +| (Int32,Int32,Int32) | (int, int, int) | ValueTuple | 3 | 1 | CSharp7.cs:75:13:75:13 | y | +| (Int32,Int32,Int32) | (int, int, int) | ValueTuple | 3 | 2 | CSharp7.cs:75:16:75:22 | Item3 | +| (Int32,String) | (int, string) | ValueTuple | 2 | 0 | CSharp7.cs:284:41:284:48 | Key | +| (Int32,String) | (int, string) | ValueTuple | 2 | 0 | CSharp7.cs:286:19:286:23 | a | +| (Int32,String) | (int, string) | ValueTuple | 2 | 1 | CSharp7.cs:284:51:284:60 | Value | +| (Int32,String) | (int, string) | ValueTuple | 2 | 1 | CSharp7.cs:286:26:286:33 | b | +| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:109:10:109:15 | m1 | +| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:112:10:112:11 | m3 | +| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 0 | CSharp7.cs:114:10:114:15 | m7 | +| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:109:18:109:23 | m2 | +| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:112:14:112:21 | Item2 | +| (String,(Int32,Int32)) | (string, (int, int)) | ValueTuple | 2 | 1 | CSharp7.cs:114:18:114:33 | Item2 | +| (String,Int32) | (string, int) | ValueTuple | 2 | 0 | CSharp7.cs:79:14:79:14 | i | +| (String,Int32) | (string, int) | ValueTuple | 2 | 0 | CSharp7.cs:79:23:79:24 | Item1 | +| (String,Int32) | (string, int) | ValueTuple | 2 | 0 | CSharp7.cs:84:17:84:17 | a | +| (String,Int32) | (string, int) | ValueTuple | 2 | 1 | CSharp7.cs:79:17:79:17 | j | +| (String,Int32) | (string, int) | ValueTuple | 2 | 1 | CSharp7.cs:79:27:79:27 | x | +| (String,Int32) | (string, int) | ValueTuple | 2 | 1 | CSharp7.cs:84:23:84:23 | Item2 | +| (String,String) | (string, string) | ValueTuple | 2 | 0 | CSharp7.cs:89:19:89:27 | Item1 | +| (String,String) | (string, string) | ValueTuple | 2 | 0 | CSharp7.cs:90:10:90:15 | t2 | +| (String,String) | (string, string) | ValueTuple | 2 | 1 | CSharp7.cs:89:30:89:33 | Item2 | +| (String,String) | (string, string) | ValueTuple | 2 | 1 | CSharp7.cs:90:18:90:23 | t3 | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected index 12ae9dff58a..be9d872af1f 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected @@ -178,7 +178,7 @@ | System.Collections.Specialized.OrderedDictionary.get_Values() | qualifier -> return | false | | System.Collections.Specialized.StringCollection.Add(object) | argument 0 -> qualifier | false | | System.Collections.Specialized.StringCollection.Add(string) | argument 0 -> qualifier | false | -| System.Collections.Specialized.StringCollection.AddRange(string[]) | argument 0 -> qualifier | false | +| System.Collections.Specialized.StringCollection.AddRange(String[]) | argument 0 -> qualifier | false | | System.Collections.Specialized.StringCollection.GetEnumerator() | qualifier -> return | false | | System.Collections.Specialized.StringCollection.Insert(int, object) | argument 1 -> qualifier | false | | System.Collections.Specialized.StringCollection.Insert(int, string) | argument 1 -> qualifier | false | @@ -221,17 +221,17 @@ | System.Convert.ChangeType(object, Type, IFormatProvider) | argument 0 -> return | false | | System.Convert.ChangeType(object, TypeCode) | argument 0 -> return | false | | System.Convert.ChangeType(object, TypeCode, IFormatProvider) | argument 0 -> return | false | -| System.Convert.FromBase64CharArray(char[], int, int) | argument 0 -> return | false | +| System.Convert.FromBase64CharArray(Char[], int, int) | argument 0 -> return | false | | System.Convert.FromBase64String(string) | argument 0 -> return | false | | System.Convert.GetTypeCode(object) | argument 0 -> return | false | | System.Convert.IsDBNull(object) | argument 0 -> return | false | -| System.Convert.ToBase64CharArray(byte[], int, int, char[], int) | argument 0 -> return | false | -| System.Convert.ToBase64CharArray(byte[], int, int, char[], int, Base64FormattingOptions) | argument 0 -> return | false | -| System.Convert.ToBase64String(ReadOnlySpan, Base64FormattingOptions) | argument 0 -> return | false | -| System.Convert.ToBase64String(byte[]) | argument 0 -> return | false | -| System.Convert.ToBase64String(byte[], Base64FormattingOptions) | argument 0 -> return | false | -| System.Convert.ToBase64String(byte[], int, int) | argument 0 -> return | false | -| System.Convert.ToBase64String(byte[], int, int, Base64FormattingOptions) | argument 0 -> return | false | +| System.Convert.ToBase64CharArray(Byte[], int, int, Char[], int) | argument 0 -> return | false | +| System.Convert.ToBase64CharArray(Byte[], int, int, Char[], int, Base64FormattingOptions) | argument 0 -> return | false | +| System.Convert.ToBase64String(Byte[]) | argument 0 -> return | false | +| System.Convert.ToBase64String(Byte[], Base64FormattingOptions) | argument 0 -> return | false | +| System.Convert.ToBase64String(Byte[], int, int) | argument 0 -> return | false | +| System.Convert.ToBase64String(Byte[], int, int, Base64FormattingOptions) | argument 0 -> return | false | +| System.Convert.ToBase64String(ReadOnlySpan, Base64FormattingOptions) | argument 0 -> return | false | | System.Convert.ToBoolean(DateTime) | argument 0 -> return | false | | System.Convert.ToBoolean(bool) | argument 0 -> return | false | | System.Convert.ToBoolean(byte) | argument 0 -> return | false | @@ -528,58 +528,58 @@ | System.Convert.ToUInt64(uint) | argument 0 -> return | false | | System.Convert.ToUInt64(ulong) | argument 0 -> return | false | | System.Convert.ToUInt64(ushort) | argument 0 -> return | false | -| System.Convert.TryFromBase64Chars(ReadOnlySpan, Span, out int) | argument 0 -> return | false | -| System.Convert.TryFromBase64String(string, Span, out int) | argument 0 -> return | false | -| System.Convert.TryToBase64Chars(ReadOnlySpan, Span, out int, Base64FormattingOptions) | argument 0 -> return | false | -| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 -> qualifier | false | +| System.Convert.TryFromBase64Chars(ReadOnlySpan, Span, out int) | argument 0 -> return | false | +| System.Convert.TryFromBase64String(string, Span, out int) | argument 0 -> return | false | +| System.Convert.TryToBase64Chars(ReadOnlySpan, Span, out int, Base64FormattingOptions) | argument 0 -> return | false | +| System.Dynamic.ExpandoObject.Add(KeyValuePair) | argument 0 -> qualifier | false | | System.Dynamic.ExpandoObject.Add(string, object) | argument 1 -> qualifier | false | | System.Dynamic.ExpandoObject.GetEnumerator() | qualifier -> return | false | | System.ICloneable.Clone() | qualifier -> return | false | -| System.IO.BufferedStream.BeginRead(byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | -| System.IO.BufferedStream.BeginWrite(byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | +| System.IO.BufferedStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | +| System.IO.BufferedStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.IO.BufferedStream.CopyTo(Stream, int) | qualifier -> argument 0 | false | | System.IO.BufferedStream.CopyToAsync(Stream, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.BufferedStream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.IO.BufferedStream.ReadAsync(byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.BufferedStream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.IO.BufferedStream.WriteAsync(byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | -| System.IO.Compression.DeflateStream.BeginRead(byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | -| System.IO.Compression.DeflateStream.BeginWrite(byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | +| System.IO.BufferedStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.IO.BufferedStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | +| System.IO.BufferedStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.IO.BufferedStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | +| System.IO.Compression.DeflateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | +| System.IO.Compression.DeflateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.IO.Compression.DeflateStream.CopyToAsync(Stream, int, CancellationToken) | qualifier -> argument 0 | false | | System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionLevel) | argument 0 -> return | false | | System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionLevel, bool) | argument 0 -> return | false | | System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionMode) | argument 0 -> return | false | | System.IO.Compression.DeflateStream.DeflateStream(Stream, CompressionMode, bool) | argument 0 -> return | false | -| System.IO.Compression.DeflateStream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.IO.Compression.DeflateStream.ReadAsync(byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.Compression.DeflateStream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.IO.Compression.DeflateStream.WriteAsync(byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | -| System.IO.Compression.GZipStream.BeginRead(byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | -| System.IO.Compression.GZipStream.BeginWrite(byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | +| System.IO.Compression.DeflateStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.IO.Compression.DeflateStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | +| System.IO.Compression.DeflateStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.IO.Compression.DeflateStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | +| System.IO.Compression.GZipStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | +| System.IO.Compression.GZipStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.IO.Compression.GZipStream.CopyTo(Stream, int) | qualifier -> argument 0 | false | | System.IO.Compression.GZipStream.CopyToAsync(Stream, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.Compression.GZipStream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.IO.Compression.GZipStream.ReadAsync(byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.Compression.GZipStream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.IO.Compression.GZipStream.WriteAsync(byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | -| System.IO.FileStream.BeginRead(byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | -| System.IO.FileStream.BeginWrite(byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | -| System.IO.FileStream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.IO.FileStream.ReadAsync(byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.FileStream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.IO.FileStream.WriteAsync(byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | +| System.IO.Compression.GZipStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.IO.Compression.GZipStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | +| System.IO.Compression.GZipStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.IO.Compression.GZipStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | +| System.IO.FileStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | +| System.IO.FileStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | +| System.IO.FileStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.IO.FileStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | +| System.IO.FileStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.IO.FileStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | | System.IO.MemoryStream.CopyTo(Stream, int) | qualifier -> argument 0 | false | | System.IO.MemoryStream.CopyToAsync(Stream, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.MemoryStream.MemoryStream(byte[]) | argument 0 -> return | false | -| System.IO.MemoryStream.MemoryStream(byte[], bool) | argument 0 -> return | false | -| System.IO.MemoryStream.MemoryStream(byte[], int, int) | argument 0 -> return | false | -| System.IO.MemoryStream.MemoryStream(byte[], int, int, bool) | argument 0 -> return | false | -| System.IO.MemoryStream.MemoryStream(byte[], int, int, bool, bool) | argument 0 -> return | false | -| System.IO.MemoryStream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.IO.MemoryStream.ReadAsync(byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | +| System.IO.MemoryStream.MemoryStream(Byte[]) | argument 0 -> return | false | +| System.IO.MemoryStream.MemoryStream(Byte[], bool) | argument 0 -> return | false | +| System.IO.MemoryStream.MemoryStream(Byte[], int, int) | argument 0 -> return | false | +| System.IO.MemoryStream.MemoryStream(Byte[], int, int, bool) | argument 0 -> return | false | +| System.IO.MemoryStream.MemoryStream(Byte[], int, int, bool, bool) | argument 0 -> return | false | +| System.IO.MemoryStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.IO.MemoryStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | | System.IO.MemoryStream.ToArray() | qualifier -> return | false | -| System.IO.MemoryStream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.IO.MemoryStream.WriteAsync(byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | +| System.IO.MemoryStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.IO.MemoryStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | | System.IO.Path.Combine(string, string) | argument 0 -> return | false | | System.IO.Path.Combine(string, string) | argument 1 -> return | false | | System.IO.Path.Combine(string, string, string) | argument 0 -> return | false | @@ -589,69 +589,69 @@ | System.IO.Path.Combine(string, string, string, string) | argument 1 -> return | false | | System.IO.Path.Combine(string, string, string, string) | argument 2 -> return | false | | System.IO.Path.Combine(string, string, string, string) | argument 3 -> return | false | -| System.IO.Path.GetDirectoryName(ReadOnlySpan) | argument 0 -> return | false | +| System.IO.Path.GetDirectoryName(ReadOnlySpan) | argument 0 -> return | false | | System.IO.Path.GetDirectoryName(string) | argument 0 -> return | false | -| System.IO.Path.GetExtension(ReadOnlySpan) | argument 0 -> return | false | +| System.IO.Path.GetExtension(ReadOnlySpan) | argument 0 -> return | false | | System.IO.Path.GetExtension(string) | argument 0 -> return | false | -| System.IO.Path.GetFileName(ReadOnlySpan) | argument 0 -> return | false | +| System.IO.Path.GetFileName(ReadOnlySpan) | argument 0 -> return | false | | System.IO.Path.GetFileName(string) | argument 0 -> return | false | -| System.IO.Path.GetFileNameWithoutExtension(ReadOnlySpan) | argument 0 -> return | false | +| System.IO.Path.GetFileNameWithoutExtension(ReadOnlySpan) | argument 0 -> return | false | | System.IO.Path.GetFileNameWithoutExtension(string) | argument 0 -> return | false | | System.IO.Path.GetFullPath(string) | argument 0 -> return | false | | System.IO.Path.GetFullPath(string, string) | argument 0 -> return | false | -| System.IO.Path.GetPathRoot(ReadOnlySpan) | argument 0 -> return | false | +| System.IO.Path.GetPathRoot(ReadOnlySpan) | argument 0 -> return | false | | System.IO.Path.GetPathRoot(string) | argument 0 -> return | false | | System.IO.Path.GetRelativePath(string, string) | argument 1 -> return | false | -| System.IO.Pipes.PipeStream.BeginRead(byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | -| System.IO.Pipes.PipeStream.BeginWrite(byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | -| System.IO.Pipes.PipeStream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.IO.Pipes.PipeStream.ReadAsync(byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.Pipes.PipeStream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.IO.Pipes.PipeStream.WriteAsync(byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | -| System.IO.Stream.BeginRead(byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | -| System.IO.Stream.BeginWrite(byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | +| System.IO.Pipes.PipeStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | +| System.IO.Pipes.PipeStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | +| System.IO.Pipes.PipeStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.IO.Pipes.PipeStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | +| System.IO.Pipes.PipeStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.IO.Pipes.PipeStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | +| System.IO.Stream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | +| System.IO.Stream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.IO.Stream.CopyTo(Stream) | qualifier -> argument 0 | false | | System.IO.Stream.CopyTo(Stream, int) | qualifier -> argument 0 | false | | System.IO.Stream.CopyToAsync(Stream) | qualifier -> argument 0 | false | | System.IO.Stream.CopyToAsync(Stream, CancellationToken) | qualifier -> argument 0 | false | | System.IO.Stream.CopyToAsync(Stream, int) | qualifier -> argument 0 | false | | System.IO.Stream.CopyToAsync(Stream, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.Stream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.IO.Stream.ReadAsync(byte[], int, int) | qualifier -> argument 0 | false | -| System.IO.Stream.ReadAsync(byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.Stream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.IO.Stream.WriteAsync(byte[], int, int) | argument 0 -> qualifier | false | -| System.IO.Stream.WriteAsync(byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | +| System.IO.Stream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.IO.Stream.ReadAsync(Byte[], int, int) | qualifier -> argument 0 | false | +| System.IO.Stream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | +| System.IO.Stream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.IO.Stream.WriteAsync(Byte[], int, int) | argument 0 -> qualifier | false | +| System.IO.Stream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | | System.IO.StringReader.Read() | qualifier -> return | false | -| System.IO.StringReader.Read(Span) | qualifier -> return | false | -| System.IO.StringReader.Read(char[], int, int) | qualifier -> return | false | -| System.IO.StringReader.ReadAsync(Memory, CancellationToken) | qualifier -> return | false | -| System.IO.StringReader.ReadAsync(char[], int, int) | qualifier -> return | false | -| System.IO.StringReader.ReadBlock(Span) | qualifier -> return | false | -| System.IO.StringReader.ReadBlockAsync(Memory, CancellationToken) | qualifier -> return | false | -| System.IO.StringReader.ReadBlockAsync(char[], int, int) | qualifier -> return | false | +| System.IO.StringReader.Read(Char[], int, int) | qualifier -> return | false | +| System.IO.StringReader.Read(Span) | qualifier -> return | false | +| System.IO.StringReader.ReadAsync(Char[], int, int) | qualifier -> return | false | +| System.IO.StringReader.ReadAsync(Memory, CancellationToken) | qualifier -> return | false | +| System.IO.StringReader.ReadBlock(Span) | qualifier -> return | false | +| System.IO.StringReader.ReadBlockAsync(Char[], int, int) | qualifier -> return | false | +| System.IO.StringReader.ReadBlockAsync(Memory, CancellationToken) | qualifier -> return | false | | System.IO.StringReader.ReadLine() | qualifier -> return | false | | System.IO.StringReader.ReadLineAsync() | qualifier -> return | false | | System.IO.StringReader.ReadToEnd() | qualifier -> return | false | | System.IO.StringReader.ReadToEndAsync() | qualifier -> return | false | | System.IO.StringReader.StringReader(string) | argument 0 -> return | false | | System.IO.TextReader.Read() | qualifier -> return | false | -| System.IO.TextReader.Read(Span) | qualifier -> return | false | -| System.IO.TextReader.Read(char[], int, int) | qualifier -> return | false | -| System.IO.TextReader.ReadAsync(Memory, CancellationToken) | qualifier -> return | false | -| System.IO.TextReader.ReadAsync(char[], int, int) | qualifier -> return | false | -| System.IO.TextReader.ReadBlock(Span) | qualifier -> return | false | -| System.IO.TextReader.ReadBlock(char[], int, int) | qualifier -> return | false | -| System.IO.TextReader.ReadBlockAsync(Memory, CancellationToken) | qualifier -> return | false | -| System.IO.TextReader.ReadBlockAsync(char[], int, int) | qualifier -> return | false | +| System.IO.TextReader.Read(Char[], int, int) | qualifier -> return | false | +| System.IO.TextReader.Read(Span) | qualifier -> return | false | +| System.IO.TextReader.ReadAsync(Char[], int, int) | qualifier -> return | false | +| System.IO.TextReader.ReadAsync(Memory, CancellationToken) | qualifier -> return | false | +| System.IO.TextReader.ReadBlock(Char[], int, int) | qualifier -> return | false | +| System.IO.TextReader.ReadBlock(Span) | qualifier -> return | false | +| System.IO.TextReader.ReadBlockAsync(Char[], int, int) | qualifier -> return | false | +| System.IO.TextReader.ReadBlockAsync(Memory, CancellationToken) | qualifier -> return | false | | System.IO.TextReader.ReadLine() | qualifier -> return | false | | System.IO.TextReader.ReadLineAsync() | qualifier -> return | false | | System.IO.TextReader.ReadToEnd() | qualifier -> return | false | | System.IO.TextReader.ReadToEndAsync() | qualifier -> return | false | -| System.IO.UnmanagedMemoryStream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.IO.UnmanagedMemoryStream.ReadAsync(byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | -| System.IO.UnmanagedMemoryStream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.IO.UnmanagedMemoryStream.WriteAsync(byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | +| System.IO.UnmanagedMemoryStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.IO.UnmanagedMemoryStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | +| System.IO.UnmanagedMemoryStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.IO.UnmanagedMemoryStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | | System.Int32.Parse(string) | argument 0 -> return | false | | System.Int32.Parse(string, IFormatProvider) | argument 0 -> return | false | | System.Int32.Parse(string, NumberStyles) | argument 0 -> return | false | @@ -673,23 +673,23 @@ | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func) | output from argument 2 -> return | false | | System.Linq.Enumerable.Aggregate(IEnumerable, Func) | argument 0 -> parameter 1 of argument 1 | false | | System.Linq.Enumerable.Aggregate(IEnumerable, Func) | output from argument 1 -> return | false | -| System.Linq.Enumerable.All(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Any(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.All(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Any(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.AsEnumerable(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Average(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Average(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.Cast(IEnumerable) | argument 0 -> return | false | | System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | argument 0 -> return | false | | System.Linq.Enumerable.Concat(IEnumerable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Enumerable.Count(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Count(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.DefaultIfEmpty(IEnumerable) | argument 0 -> return | false | | System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 0 -> return | false | | System.Linq.Enumerable.DefaultIfEmpty(IEnumerable, TSource) | argument 1 -> return | false | @@ -700,11 +700,11 @@ | System.Linq.Enumerable.Except(IEnumerable, IEnumerable) | argument 0 -> return | false | | System.Linq.Enumerable.Except(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | | System.Linq.Enumerable.First(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.First(IEnumerable, Func) | argument 0 -> return | false | | System.Linq.Enumerable.FirstOrDefault(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.FirstOrDefault(IEnumerable, Func) | argument 0 -> return | false | | System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | | System.Linq.Enumerable.GroupBy(IEnumerable, Func, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 3 | false | @@ -753,34 +753,34 @@ | System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | | System.Linq.Enumerable.Join(IEnumerable, IEnumerable, Func, Func, Func, IEqualityComparer) | output from argument 4 -> return | false | | System.Linq.Enumerable.Last(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Last(IEnumerable, Func) | argument 0 -> return | false | | System.Linq.Enumerable.LastOrDefault(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.LongCount(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.LastOrDefault(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.LongCount(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Max(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Max(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Min(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Min(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.OfType(IEnumerable) | argument 0 -> return | false | | System.Linq.Enumerable.OrderBy(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.OrderBy(IEnumerable, Func) | argument 0 -> return | false | @@ -791,48 +791,48 @@ | System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.OrderByDescending(IEnumerable, Func, IComparer) | argument 0 -> return | false | | System.Linq.Enumerable.Reverse(IEnumerable) | argument 0 -> return | false | +| System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 -> return | false | | System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 -> return | false | -| System.Linq.Enumerable.Select(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Select(IEnumerable, Func) | output from argument 1 -> return | false | | System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | | System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | | System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 -> return | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 -> return | false | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>, Func) | output from argument 2 -> return | false | | System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 -> return | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 -> return | false | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.SelectMany(IEnumerable, Func>) | output from argument 1 -> return | false | | System.Linq.Enumerable.Single(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Single(IEnumerable, Func) | argument 0 -> return | false | | System.Linq.Enumerable.SingleOrDefault(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.SingleOrDefault(IEnumerable, Func) | argument 0 -> return | false | | System.Linq.Enumerable.Skip(IEnumerable, int) | argument 0 -> return | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.SkipWhile(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Sum(IEnumerable, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Sum(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.Take(IEnumerable, int) | argument 0 -> return | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.TakeWhile(IEnumerable, Func) | argument 0 -> return | false | | System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func) | argument 0 -> return | false | | System.Linq.Enumerable.ThenBy(IOrderedEnumerable, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | @@ -867,10 +867,10 @@ | System.Linq.Enumerable.Union(IEnumerable, IEnumerable) | argument 1 -> return | false | | System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | | System.Linq.Enumerable.Union(IEnumerable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> return | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> return | false | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Enumerable.Where(IEnumerable, Func) | argument 0 -> return | false | | System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | argument 0 -> parameter 0 of argument 2 | false | | System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | argument 1 -> parameter 1 of argument 2 | false | | System.Linq.Enumerable.Zip(IEnumerable, IEnumerable, Func) | output from argument 2 -> return | false | @@ -889,25 +889,25 @@ | System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, TAccumulate, Func) | output from argument 2 -> return | false | | System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | argument 0 -> parameter 1 of argument 1 | false | | System.Linq.ParallelEnumerable.Aggregate(ParallelQuery, Func) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.All(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Any(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.All(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Any(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.AsEnumerable(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Average(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.Cast(ParallelQuery) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.Concat(ParallelQuery, IEnumerable) | argument 1 -> return | false | | System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.Concat(ParallelQuery, ParallelQuery) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Count(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Count(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.DefaultIfEmpty(ParallelQuery, TSource) | argument 1 -> return | false | @@ -920,11 +920,11 @@ | System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.Except(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.First(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.First(ParallelQuery, Func) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.FirstOrDefault(ParallelQuery, Func) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | argument 0 -> parameter 0 of argument 2 | false | | System.Linq.ParallelEnumerable.GroupBy(ParallelQuery, Func, Func, Func, TResult>) | output from argument 1 -> parameter 0 of argument 3 | false | @@ -997,34 +997,34 @@ | System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | | System.Linq.ParallelEnumerable.Join(ParallelQuery, ParallelQuery, Func, Func, Func, IEqualityComparer) | output from argument 4 -> return | false | | System.Linq.ParallelEnumerable.Last(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Last(ParallelQuery, Func) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LongCount(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.LastOrDefault(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.LongCount(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Max(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Min(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.OfType(ParallelQuery) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.OrderBy(ParallelQuery, Func) | argument 0 -> return | false | @@ -1035,48 +1035,48 @@ | System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.OrderByDescending(ParallelQuery, Func, IComparer) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.Reverse(ParallelQuery) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 -> return | false | | System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Select(ParallelQuery, Func) | output from argument 1 -> return | false | | System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | | System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | | System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 -> return | false | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 1 -> parameter 1 of argument 2 | false | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>, Func) | output from argument 2 -> return | false | | System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 -> return | false | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.SelectMany(ParallelQuery, Func>) | output from argument 1 -> return | false | | System.Linq.ParallelEnumerable.Single(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Single(ParallelQuery, Func) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.SingleOrDefault(ParallelQuery, Func) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.Skip(ParallelQuery, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.SkipWhile(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Sum(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.Take(ParallelQuery, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.TakeWhile(ParallelQuery, Func) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.ThenBy(OrderedParallelQuery, Func, IComparer) | argument 0 -> parameter 0 of argument 1 | false | @@ -1115,10 +1115,10 @@ | System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery) | argument 1 -> return | false | | System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.Union(ParallelQuery, ParallelQuery, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> return | false | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.ParallelEnumerable.Where(ParallelQuery, Func) | argument 0 -> return | false | | System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | argument 0 -> parameter 0 of argument 2 | false | | System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | argument 1 -> parameter 1 of argument 2 | false | | System.Linq.ParallelEnumerable.Zip(ParallelQuery, IEnumerable, Func) | output from argument 2 -> return | false | @@ -1127,31 +1127,31 @@ | System.Linq.ParallelEnumerable.Zip(ParallelQuery, ParallelQuery, Func) | output from argument 2 -> return | false | | System.Linq.ParallelQuery.GetEnumerator() | qualifier -> return | false | | System.Linq.ParallelQuery<>.GetEnumerator() | qualifier -> return | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 2 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 3 -> return | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | argument 0 -> parameter 1 of argument 1 | false | -| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | output from argument 1 -> return | false | -| System.Linq.Queryable.All(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Any(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 0 -> parameter 1 of argument 2 | false | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | argument 1 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 2 -> parameter 0 of argument 3 | false | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>, Expression>) | output from argument 3 -> return | false | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 0 -> parameter 1 of argument 2 | false | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | argument 1 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.Aggregate(IQueryable, TAccumulate, Expression>) | output from argument 2 -> return | false | +| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | argument 0 -> parameter 1 of argument 1 | false | +| System.Linq.Queryable.Aggregate(IQueryable, Expression>) | output from argument 1 -> return | false | +| System.Linq.Queryable.All(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Any(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Average(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Average(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Queryable.Cast(IQueryable) | argument 0 -> return | false | | System.Linq.Queryable.Concat(IQueryable, IEnumerable) | argument 0 -> return | false | | System.Linq.Queryable.Concat(IQueryable, IEnumerable) | argument 1 -> return | false | -| System.Linq.Queryable.Count(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Count(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Queryable.DefaultIfEmpty(IQueryable) | argument 0 -> return | false | | System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 0 -> return | false | | System.Linq.Queryable.DefaultIfEmpty(IQueryable, TSource) | argument 1 -> return | false | @@ -1162,135 +1162,135 @@ | System.Linq.Queryable.Except(IQueryable, IEnumerable) | argument 0 -> return | false | | System.Linq.Queryable.Except(IQueryable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | | System.Linq.Queryable.First(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.First(IQueryable, Expression>) | argument 0 -> return | false | | System.Linq.Queryable.FirstOrDefault(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression, TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression, TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression, TResult>>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression, TResult>>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression, TResult>>) | output from argument 3 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression, TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression, TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression, TResult>>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression, TResult>>, IEqualityComparer) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression, TResult>>, IEqualityComparer) | output from argument 3 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression, TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression, TResult>>) | output from argument 2 -> return | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression, TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression, TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | argument 0 -> return | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression, TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression, TResult>>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression, TResult>>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression, TResult>>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression, TResult>>) | output from argument 4 -> return | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression, TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression, TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression, TResult>>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression, TResult>>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression, TResult>>, IEqualityComparer) | output from argument 4 -> return | false | +| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.FirstOrDefault(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 1 -> parameter 0 of argument 3 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 2 -> parameter 1 of argument 3 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>) | output from argument 3 -> return | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 1 -> parameter 0 of argument 3 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 2 -> parameter 1 of argument 3 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 3 -> return | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>) | output from argument 2 -> return | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>) | output from argument 2 -> return | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.GroupBy(IQueryable, Expression>, IEqualityComparer) | argument 0 -> return | false | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 0 -> parameter 0 of argument 4 | false | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 1 -> parameter 0 of argument 3 | false | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | argument 1 -> parameter 1 of argument 4 | false | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>) | output from argument 4 -> return | false | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | +| System.Linq.Queryable.GroupJoin(IQueryable, IEnumerable, Expression>, Expression>, Expression,TResult>>, IEqualityComparer) | output from argument 4 -> return | false | | System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | argument 0 -> return | false | | System.Linq.Queryable.Intersect(IQueryable, IEnumerable) | argument 1 -> return | false | | System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | | System.Linq.Queryable.Intersect(IQueryable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | output from argument 4 -> return | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | output from argument 4 -> return | false | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 0 -> parameter 0 of argument 4 | false | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 -> parameter 0 of argument 3 | false | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | argument 1 -> parameter 1 of argument 4 | false | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>) | output from argument 4 -> return | false | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 0 -> parameter 0 of argument 4 | false | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 -> parameter 0 of argument 3 | false | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | argument 1 -> parameter 1 of argument 4 | false | +| System.Linq.Queryable.Join(IQueryable, IEnumerable, Expression>, Expression>, Expression>, IEqualityComparer) | output from argument 4 -> return | false | | System.Linq.Queryable.Last(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Last(IQueryable, Expression>) | argument 0 -> return | false | | System.Linq.Queryable.LastOrDefault(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.LongCount(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Max(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Min(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.LastOrDefault(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.LongCount(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Max(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Min(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Queryable.OfType(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 -> return | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 -> return | false | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.OrderBy(IQueryable, Expression>, IComparer) | argument 0 -> return | false | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.OrderByDescending(IQueryable, Expression>, IComparer) | argument 0 -> return | false | | System.Linq.Queryable.Reverse(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 -> return | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 -> return | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 -> return | false | +| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 -> return | false | +| System.Linq.Queryable.Select(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Select(IQueryable, Expression>) | output from argument 1 -> return | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 -> parameter 1 of argument 2 | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 -> return | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 1 -> parameter 1 of argument 2 | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>, Expression>) | output from argument 2 -> return | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 -> return | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.SelectMany(IQueryable, Expression>>) | output from argument 1 -> return | false | | System.Linq.Queryable.Single(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Single(IQueryable, Expression>) | argument 0 -> return | false | | System.Linq.Queryable.SingleOrDefault(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.SingleOrDefault(IQueryable, Expression>) | argument 0 -> return | false | | System.Linq.Queryable.Skip(IQueryable, int) | argument 0 -> return | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.SkipWhile(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Sum(IQueryable, Expression>>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Sum(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | | System.Linq.Queryable.Take(IQueryable, int) | argument 0 -> return | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 -> return | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 -> return | false | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.TakeWhile(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.ThenBy(IOrderedQueryable, Expression>, IComparer) | argument 0 -> return | false | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.ThenByDescending(IOrderedQueryable, Expression>, IComparer) | argument 0 -> return | false | | System.Linq.Queryable.Union(IQueryable, IEnumerable) | argument 0 -> return | false | | System.Linq.Queryable.Union(IQueryable, IEnumerable) | argument 1 -> return | false | | System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | argument 0 -> return | false | | System.Linq.Queryable.Union(IQueryable, IEnumerable, IEqualityComparer) | argument 1 -> return | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> return | false | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | output from argument 2 -> return | false | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> parameter 0 of argument 1 | false | +| System.Linq.Queryable.Where(IQueryable, Expression>) | argument 0 -> return | false | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 0 -> parameter 0 of argument 2 | false | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | argument 1 -> parameter 1 of argument 2 | false | +| System.Linq.Queryable.Zip(IQueryable, IEnumerable, Expression>) | output from argument 2 -> return | false | | System.Net.Cookie.get_Value() | qualifier -> return | false | | System.Net.CookieCollection.Add(Cookie) | argument 0 -> qualifier | false | | System.Net.CookieCollection.Add(CookieCollection) | argument 0 -> qualifier | false | @@ -1300,16 +1300,16 @@ | System.Net.HttpListenerPrefixCollection.GetEnumerator() | qualifier -> return | false | | System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | argument 0 -> qualifier | false | | System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | qualifier -> return | false | -| System.Net.Security.NegotiateStream.BeginRead(byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | -| System.Net.Security.NegotiateStream.BeginWrite(byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | -| System.Net.Security.NegotiateStream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.Net.Security.NegotiateStream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.Net.Security.SslStream.BeginRead(byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | -| System.Net.Security.SslStream.BeginWrite(byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | -| System.Net.Security.SslStream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.Net.Security.SslStream.ReadAsync(byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | -| System.Net.Security.SslStream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.Net.Security.SslStream.WriteAsync(byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | +| System.Net.Security.NegotiateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | +| System.Net.Security.NegotiateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | +| System.Net.Security.NegotiateStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.Net.Security.NegotiateStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.Net.Security.SslStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | +| System.Net.Security.SslStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | +| System.Net.Security.SslStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.Net.Security.SslStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | +| System.Net.Security.SslStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.Net.Security.SslStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | | System.Net.WebUtility.HtmlEncode(string) | argument 0 -> return | false | | System.Net.WebUtility.HtmlEncode(string, TextWriter) | argument 0 -> return | false | | System.Net.WebUtility.UrlEncode(string) | argument 0 -> return | false | @@ -1326,15 +1326,15 @@ | System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | argument 1 -> qualifier | false | | System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | qualifier -> return | false | | System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | qualifier -> return | false | -| System.Security.Cryptography.CryptoStream.BeginRead(byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | -| System.Security.Cryptography.CryptoStream.BeginWrite(byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | -| System.Security.Cryptography.CryptoStream.Read(byte[], int, int) | qualifier -> argument 0 | false | -| System.Security.Cryptography.CryptoStream.ReadAsync(byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | -| System.Security.Cryptography.CryptoStream.Write(byte[], int, int) | argument 0 -> qualifier | false | -| System.Security.Cryptography.CryptoStream.WriteAsync(byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | +| System.Security.Cryptography.CryptoStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | +| System.Security.Cryptography.CryptoStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | +| System.Security.Cryptography.CryptoStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | +| System.Security.Cryptography.CryptoStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | +| System.Security.Cryptography.CryptoStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | +| System.Security.Cryptography.CryptoStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | | System.String.Clone() | qualifier -> return | false | | System.String.Clone() | qualifier -> return | true | -| System.String.Concat(IEnumerable) | argument 0 -> return | false | +| System.String.Concat(IEnumerable) | argument 0 -> return | false | | System.String.Concat(object) | argument 0 -> return | false | | System.String.Concat(object, object) | argument 0 -> return | false | | System.String.Concat(object, object) | argument 1 -> return | false | @@ -1373,16 +1373,16 @@ | System.String.GetEnumerator() | qualifier -> return | false | | System.String.Insert(int, string) | argument 1 -> return | false | | System.String.Insert(int, string) | qualifier -> return | false | -| System.String.Join(string, IEnumerable) | argument 0 -> return | false | -| System.String.Join(string, IEnumerable) | argument 1 -> return | false | -| System.String.Join(string, params string[]) | argument 0 -> return | false | -| System.String.Join(string, params string[]) | argument 1 -> return | false | -| System.String.Join(string, params string[]) | argument 2 -> return | false | -| System.String.Join(string, params string[]) | argument 3 -> return | false | -| System.String.Join(string, string[], int, int) | argument 0 -> return | false | -| System.String.Join(string, string[], int, int) | argument 1 -> return | false | -| System.String.Join(string, string[], int, int) | argument 2 -> return | false | -| System.String.Join(string, string[], int, int) | argument 3 -> return | false | +| System.String.Join(string, IEnumerable) | argument 0 -> return | false | +| System.String.Join(string, IEnumerable) | argument 1 -> return | false | +| System.String.Join(string, String[], int, int) | argument 0 -> return | false | +| System.String.Join(string, String[], int, int) | argument 1 -> return | false | +| System.String.Join(string, String[], int, int) | argument 2 -> return | false | +| System.String.Join(string, String[], int, int) | argument 3 -> return | false | +| System.String.Join(string, params String[]) | argument 0 -> return | false | +| System.String.Join(string, params String[]) | argument 1 -> return | false | +| System.String.Join(string, params String[]) | argument 2 -> return | false | +| System.String.Join(string, params String[]) | argument 3 -> return | false | | System.String.Join(string, IEnumerable) | argument 0 -> return | false | | System.String.Join(string, IEnumerable) | argument 1 -> return | false | | System.String.Normalize() | qualifier -> return | false | @@ -1397,18 +1397,18 @@ | System.String.Replace(char, char) | qualifier -> return | false | | System.String.Replace(string, string) | argument 1 -> return | false | | System.String.Replace(string, string) | qualifier -> return | false | +| System.String.Split(Char[], StringSplitOptions) | qualifier -> return | false | +| System.String.Split(Char[], int) | qualifier -> return | false | +| System.String.Split(Char[], int, StringSplitOptions) | qualifier -> return | false | +| System.String.Split(String[], StringSplitOptions) | qualifier -> return | false | +| System.String.Split(String[], int, StringSplitOptions) | qualifier -> return | false | | System.String.Split(char, StringSplitOptions) | qualifier -> return | false | | System.String.Split(char, int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(char[], StringSplitOptions) | qualifier -> return | false | -| System.String.Split(char[], int) | qualifier -> return | false | -| System.String.Split(char[], int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(params char[]) | qualifier -> return | false | +| System.String.Split(params Char[]) | qualifier -> return | false | | System.String.Split(string, StringSplitOptions) | qualifier -> return | false | | System.String.Split(string, int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(string[], StringSplitOptions) | qualifier -> return | false | -| System.String.Split(string[], int, StringSplitOptions) | qualifier -> return | false | -| System.String.String(char[]) | argument 0 -> return | false | -| System.String.String(char[], int, int) | argument 0 -> return | false | +| System.String.String(Char[]) | argument 0 -> return | false | +| System.String.String(Char[], int, int) | argument 0 -> return | false | | System.String.Substring(int) | qualifier -> return | false | | System.String.Substring(int, int) | qualifier -> return | false | | System.String.ToLower() | qualifier -> return | false | @@ -1420,30 +1420,30 @@ | System.String.ToUpperInvariant() | qualifier -> return | false | | System.String.Trim() | qualifier -> return | false | | System.String.Trim(char) | qualifier -> return | false | -| System.String.Trim(params char[]) | qualifier -> return | false | +| System.String.Trim(params Char[]) | qualifier -> return | false | | System.String.TrimEnd() | qualifier -> return | false | | System.String.TrimEnd(char) | qualifier -> return | false | -| System.String.TrimEnd(params char[]) | qualifier -> return | false | +| System.String.TrimEnd(params Char[]) | qualifier -> return | false | | System.String.TrimStart() | qualifier -> return | false | | System.String.TrimStart(char) | qualifier -> return | false | -| System.String.TrimStart(params char[]) | qualifier -> return | false | -| System.Text.Encoding.GetBytes(ReadOnlySpan, Span) | argument 0 -> return | false | +| System.String.TrimStart(params Char[]) | qualifier -> return | false | +| System.Text.Encoding.GetBytes(Char[]) | argument 0 -> return | false | +| System.Text.Encoding.GetBytes(Char[], int, int) | argument 0 -> return | false | +| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | argument 0 -> return | false | +| System.Text.Encoding.GetBytes(ReadOnlySpan, Span) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(char*, int, byte*, int) | argument 0 -> return | false | -| System.Text.Encoding.GetBytes(char[]) | argument 0 -> return | false | -| System.Text.Encoding.GetBytes(char[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetBytes(char[], int, int, byte[], int) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string, int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetBytes(string, int, int, byte[], int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(ReadOnlySpan, Span) | argument 0 -> return | false | +| System.Text.Encoding.GetBytes(string, int, int, Byte[], int) | argument 0 -> return | false | +| System.Text.Encoding.GetChars(Byte[]) | argument 0 -> return | false | +| System.Text.Encoding.GetChars(Byte[], int, int) | argument 0 -> return | false | +| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | argument 0 -> return | false | +| System.Text.Encoding.GetChars(ReadOnlySpan, Span) | argument 0 -> return | false | | System.Text.Encoding.GetChars(byte*, int, char*, int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(byte[]) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(byte[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(byte[], int, int, char[], int) | argument 0 -> return | false | -| System.Text.Encoding.GetString(ReadOnlySpan) | argument 0 -> return | false | +| System.Text.Encoding.GetString(Byte[]) | argument 0 -> return | false | +| System.Text.Encoding.GetString(Byte[], int, int) | argument 0 -> return | false | +| System.Text.Encoding.GetString(ReadOnlySpan) | argument 0 -> return | false | | System.Text.Encoding.GetString(byte*, int) | argument 0 -> return | false | -| System.Text.Encoding.GetString(byte[]) | argument 0 -> return | false | -| System.Text.Encoding.GetString(byte[], int, int) | argument 0 -> return | false | | System.Text.RegularExpressions.CaptureCollection.Add(Capture) | argument 0 -> qualifier | false | | System.Text.RegularExpressions.CaptureCollection.Add(object) | argument 0 -> qualifier | false | | System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | qualifier -> return | false | @@ -1485,106 +1485,106 @@ | System.Text.StringBuilder.StringBuilder(string, int) | argument 0 -> return | false | | System.Text.StringBuilder.StringBuilder(string, int, int, int) | argument 0 -> return | false | | System.Text.StringBuilder.ToString() | qualifier -> return | false | -| System.Threading.Tasks.Task.ContinueWith(Action, object) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Action, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Action, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Action, object) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Action, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Action, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.ContinueWith(Func) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.ContinueWith(Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.ContinueWith(Func, TaskContinuationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.ContinueWith(Func, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskContinuationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task.ContinueWith(Func, object, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.FromResult(TResult) | argument 0 -> return | true | | System.Threading.Tasks.Task.Run(Func) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.Run(Func, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.Run(Func>) | output from argument 0 -> return | true | | System.Threading.Tasks.Task.Run(Func>, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task.Task(Action, object) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task.Task(Action, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task.Task(Action, object, CancellationToken, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task.Task(Action, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task.Task(Action, object) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task.Task(Action, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task.Task(Action, object, CancellationToken, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task.Task(Action, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task.WhenAll(IEnumerable>) | argument 0 -> return | true | | System.Threading.Tasks.Task.WhenAll(params Task[]) | argument 0 -> return | true | | System.Threading.Tasks.Task.WhenAll(params Task[]) | argument 1 -> return | true | | System.Threading.Tasks.Task.WhenAny(IEnumerable>) | argument 0 -> return | true | | System.Threading.Tasks.Task.WhenAny(params Task[]) | argument 0 -> return | true | | System.Threading.Tasks.Task.WhenAny(params Task[]) | argument 1 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, object>, object) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, object>, object) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, object>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, object>, object, CancellationToken) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, object>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, object>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, object>, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, object>, object, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, object>, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action, object>, object, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action>) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action>, CancellationToken) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action>, CancellationToken, TaskContinuationOptions, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, CancellationToken) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, TaskContinuationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.ContinueWith(Func, object, TNewResult>, object, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action>) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action>, CancellationToken) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action>, CancellationToken, TaskContinuationOptions, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Action>, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, Object, TNewResult>, object, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskContinuationOptions) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.ContinueWith(Func, TNewResult>, TaskScheduler) | qualifier -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.Task(Func, object) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.Task(Func, object) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | output from argument 0 -> return | true | +| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.Task(Func) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.Task(Func, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.Task(Func, CancellationToken, TaskCreationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.Task(Func, TaskCreationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.Task(Func, object) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, CancellationToken, TaskCreationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task<>.Task(Func, object, TaskCreationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.Task<>.get_Result() | qualifier -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func[], TResult>) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func[], TResult>) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func[], TResult>, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func[], TResult>, CancellationToken) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func[], TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func[], TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func[], TResult>, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func[], TResult>, TaskContinuationOptions) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action[]>) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action[]>, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action[]>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action[]>, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | output from argument 1 -> return | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 -> return | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 -> return | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Action, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | @@ -1605,34 +1605,34 @@ | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory.ContinueWhenAny(Task[], Func, TaskContinuationOptions) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory.StartNew(Action, object) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Action, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Action, object) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Action, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Action, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | output from argument 0 -> return | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | output from argument 0 -> return | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 -> return | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory.StartNew(Func) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory.StartNew(Func, TaskCreationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory.StartNew(Func, object, TaskCreationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func[], TResult>) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func[], TResult>) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func[], TResult>, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func[], TResult>, CancellationToken) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func[], TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func[], TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func[], TResult>, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | -| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func[], TResult>, TaskContinuationOptions) | output from argument 1 -> return | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func) | output from argument 1 -> return | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken) | output from argument 1 -> return | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | +| System.Threading.Tasks.TaskFactory<>.ContinueWhenAll(Task[], Func, TaskContinuationOptions) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | @@ -1645,18 +1645,18 @@ | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 1 -> return | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | argument 0 -> parameter 0 of argument 1 | true | | System.Threading.Tasks.TaskFactory<>.ContinueWhenAny(Task[], Func, TResult>, TaskContinuationOptions) | output from argument 1 -> return | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | output from argument 0 -> return | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | output from argument 0 -> return | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 -> return | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | +| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 -> return | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, TaskCreationOptions) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, CancellationToken, TaskCreationOptions, TaskScheduler) | output from argument 0 -> return | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.TaskFactory<>.StartNew(Func, object, TaskCreationOptions) | output from argument 0 -> return | true | | System.Uri.ToString() | qualifier -> return | false | | System.Uri.Uri(string) | argument 0 -> return | false | | System.Uri.Uri(string, UriKind) | argument 0 -> return | false | diff --git a/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected b/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected index fb766901ed5..93f291abd5b 100644 --- a/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected +++ b/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected @@ -70,10 +70,10 @@ | ViableCallable.cs:12:9:12:28 | call to method M | C2.M(string, T3) | | ViableCallable.cs:12:9:12:28 | call to method M | C2.M(string, T3) | | ViableCallable.cs:12:9:12:28 | call to method M | C3.M(string, T3) | -| ViableCallable.cs:12:9:12:28 | call to method M | C4.M(int[], T3) | +| ViableCallable.cs:12:9:12:28 | call to method M | C4.M(Int32[], T3) | | ViableCallable.cs:12:9:12:28 | call to method M | C5.M(string, T3) | | ViableCallable.cs:12:9:12:28 | call to method M | C6.M(bool, T3) | -| ViableCallable.cs:12:9:12:28 | call to method M | C6.M(int[], T3) | +| ViableCallable.cs:12:9:12:28 | call to method M | C6.M(Int32[], T3) | | ViableCallable.cs:12:9:12:28 | call to method M | C6.M(string, T3) | | ViableCallable.cs:12:9:12:28 | call to method M | C6.M(string, T3) | | ViableCallable.cs:12:9:12:28 | call to method M | C6.M(string, T3) | @@ -82,10 +82,10 @@ | ViableCallable.cs:14:9:14:15 | access to property Prop | C2.set_Prop(string) | | ViableCallable.cs:14:9:14:15 | access to property Prop | C2.set_Prop(string) | | ViableCallable.cs:14:9:14:15 | access to property Prop | C3.set_Prop(string) | -| ViableCallable.cs:14:9:14:15 | access to property Prop | C4.set_Prop(int[]) | +| ViableCallable.cs:14:9:14:15 | access to property Prop | C4.set_Prop(Int32[]) | | ViableCallable.cs:14:9:14:15 | access to property Prop | C5.set_Prop(string) | | ViableCallable.cs:14:9:14:15 | access to property Prop | C6.set_Prop(bool) | -| ViableCallable.cs:14:9:14:15 | access to property Prop | C6.set_Prop(int[]) | +| ViableCallable.cs:14:9:14:15 | access to property Prop | C6.set_Prop(Int32[]) | | ViableCallable.cs:14:9:14:15 | access to property Prop | C6.set_Prop(string) | | ViableCallable.cs:14:9:14:15 | access to property Prop | C6.set_Prop(string) | | ViableCallable.cs:14:9:14:15 | access to property Prop | C6.set_Prop(string) | @@ -106,10 +106,10 @@ | ViableCallable.cs:16:9:16:23 | access to indexer | C2.set_Item(decimal, string) | | ViableCallable.cs:16:9:16:23 | access to indexer | C2.set_Item(int, string) | | ViableCallable.cs:16:9:16:23 | access to indexer | C3.set_Item(decimal, string) | -| ViableCallable.cs:16:9:16:23 | access to indexer | C4.set_Item(bool, int[]) | +| ViableCallable.cs:16:9:16:23 | access to indexer | C4.set_Item(bool, Int32[]) | | ViableCallable.cs:16:9:16:23 | access to indexer | C5.set_Item(bool, string) | | ViableCallable.cs:16:9:16:23 | access to indexer | C6.set_Item(byte, bool) | -| ViableCallable.cs:16:9:16:23 | access to indexer | C6.set_Item(bool, int[]) | +| ViableCallable.cs:16:9:16:23 | access to indexer | C6.set_Item(bool, Int32[]) | | ViableCallable.cs:16:9:16:23 | access to indexer | C6.set_Item(bool, string) | | ViableCallable.cs:16:9:16:23 | access to indexer | C6.set_Item(decimal, string) | | ViableCallable.cs:16:9:16:23 | access to indexer | C6.set_Item(int, string) | @@ -126,45 +126,45 @@ | ViableCallable.cs:16:27:16:41 | access to indexer | C6.get_Item(decimal) | | ViableCallable.cs:16:27:16:41 | access to indexer | C6.get_Item(int) | | ViableCallable.cs:16:27:16:41 | access to indexer | C7.get_Item(byte) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C2.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C2.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C2.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C3.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C4.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C5.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C6.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C6.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C6.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C6.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C6.add_Event(EventHandler) | -| ViableCallable.cs:18:9:18:16 | access to event Event | C7.add_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C2.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C2.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C2.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C3.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C4.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C5.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C6.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C6.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C6.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C6.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C6.remove_Event(EventHandler) | -| ViableCallable.cs:19:9:19:16 | access to event Event | C7.remove_Event(EventHandler) | -| ViableCallable.cs:22:9:22:30 | call to method M | C4.M(int[], T3) | -| ViableCallable.cs:22:9:22:30 | call to method M | C6.M(int[], T3) | -| ViableCallable.cs:24:9:24:15 | access to property Prop | C4.set_Prop(int[]) | -| ViableCallable.cs:24:9:24:15 | access to property Prop | C6.set_Prop(int[]) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C2.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C2.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C2.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C3.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C4.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C5.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C6.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C6.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C6.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C6.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C6.add_Event(EventHandler) | +| ViableCallable.cs:18:9:18:16 | access to event Event | C7.add_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C2.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C2.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C2.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C3.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C4.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C5.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C6.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C6.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C6.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C6.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C6.remove_Event(EventHandler) | +| ViableCallable.cs:19:9:19:16 | access to event Event | C7.remove_Event(EventHandler) | +| ViableCallable.cs:22:9:22:30 | call to method M | C4.M(Int32[], T3) | +| ViableCallable.cs:22:9:22:30 | call to method M | C6.M(Int32[], T3) | +| ViableCallable.cs:24:9:24:15 | access to property Prop | C4.set_Prop(Int32[]) | +| ViableCallable.cs:24:9:24:15 | access to property Prop | C6.set_Prop(Int32[]) | | ViableCallable.cs:24:19:24:25 | access to property Prop | C4.get_Prop() | | ViableCallable.cs:24:19:24:25 | access to property Prop | C6.get_Prop() | -| ViableCallable.cs:26:9:26:23 | access to indexer | C4.set_Item(bool, int[]) | -| ViableCallable.cs:26:9:26:23 | access to indexer | C6.set_Item(bool, int[]) | +| ViableCallable.cs:26:9:26:23 | access to indexer | C4.set_Item(bool, Int32[]) | +| ViableCallable.cs:26:9:26:23 | access to indexer | C6.set_Item(bool, Int32[]) | | ViableCallable.cs:26:27:26:41 | access to indexer | C4.get_Item(bool) | | ViableCallable.cs:26:27:26:41 | access to indexer | C6.get_Item(bool) | -| ViableCallable.cs:28:9:28:16 | access to event Event | C4.add_Event(EventHandler) | -| ViableCallable.cs:28:9:28:16 | access to event Event | C6.add_Event(EventHandler) | -| ViableCallable.cs:29:9:29:16 | access to event Event | C4.remove_Event(EventHandler) | -| ViableCallable.cs:29:9:29:16 | access to event Event | C6.remove_Event(EventHandler) | -| ViableCallable.cs:32:30:32:52 | call to method Mock | ViableCallable.Mock>() | +| ViableCallable.cs:28:9:28:16 | access to event Event | C4.add_Event(EventHandler) | +| ViableCallable.cs:28:9:28:16 | access to event Event | C6.add_Event(EventHandler) | +| ViableCallable.cs:29:9:29:16 | access to event Event | C4.remove_Event(EventHandler) | +| ViableCallable.cs:29:9:29:16 | access to event Event | C6.remove_Event(EventHandler) | +| ViableCallable.cs:32:30:32:52 | call to method Mock | ViableCallable.Mock>() | | ViableCallable.cs:33:9:33:23 | call to method M | C2.M(string, T3) | | ViableCallable.cs:33:9:33:23 | call to method M | C6.M(string, T3) | | ViableCallable.cs:35:9:35:15 | access to property Prop | C2.set_Prop(string) | @@ -175,11 +175,11 @@ | ViableCallable.cs:37:9:37:13 | access to indexer | C6.set_Item(int, string) | | ViableCallable.cs:37:17:37:21 | access to indexer | C2.get_Item(int) | | ViableCallable.cs:37:17:37:21 | access to indexer | C6.get_Item(int) | -| ViableCallable.cs:39:9:39:16 | access to event Event | C2.add_Event(EventHandler) | -| ViableCallable.cs:39:9:39:16 | access to event Event | C6.add_Event(EventHandler) | -| ViableCallable.cs:40:9:40:16 | access to event Event | C2.remove_Event(EventHandler) | -| ViableCallable.cs:40:9:40:16 | access to event Event | C6.remove_Event(EventHandler) | -| ViableCallable.cs:43:34:43:60 | call to method Mock | ViableCallable.Mock>() | +| ViableCallable.cs:39:9:39:16 | access to event Event | C2.add_Event(EventHandler) | +| ViableCallable.cs:39:9:39:16 | access to event Event | C6.add_Event(EventHandler) | +| ViableCallable.cs:40:9:40:16 | access to event Event | C2.remove_Event(EventHandler) | +| ViableCallable.cs:40:9:40:16 | access to event Event | C6.remove_Event(EventHandler) | +| ViableCallable.cs:43:34:43:60 | call to method Mock | ViableCallable.Mock>() | | ViableCallable.cs:44:9:44:24 | call to method M | C2.M(string, T3) | | ViableCallable.cs:44:9:44:24 | call to method M | C3.M(string, T3) | | ViableCallable.cs:44:9:44:24 | call to method M | C6.M(string, T3) | @@ -195,28 +195,28 @@ | ViableCallable.cs:48:18:48:23 | access to indexer | C2.get_Item(decimal) | | ViableCallable.cs:48:18:48:23 | access to indexer | C3.get_Item(decimal) | | ViableCallable.cs:48:18:48:23 | access to indexer | C6.get_Item(decimal) | -| ViableCallable.cs:50:9:50:16 | access to event Event | C2.add_Event(EventHandler) | -| ViableCallable.cs:50:9:50:16 | access to event Event | C3.add_Event(EventHandler) | -| ViableCallable.cs:50:9:50:16 | access to event Event | C6.add_Event(EventHandler) | -| ViableCallable.cs:51:9:51:16 | access to event Event | C2.remove_Event(EventHandler) | -| ViableCallable.cs:51:9:51:16 | access to event Event | C3.remove_Event(EventHandler) | -| ViableCallable.cs:51:9:51:16 | access to event Event | C6.remove_Event(EventHandler) | -| ViableCallable.cs:54:30:54:52 | call to method Mock | ViableCallable.Mock>() | -| ViableCallable.cs:55:9:55:44 | call to method M | C4.M(int[], T3) | -| ViableCallable.cs:55:9:55:44 | call to method M | C6.M(int[], T3) | -| ViableCallable.cs:57:9:57:15 | access to property Prop | C4.set_Prop(int[]) | -| ViableCallable.cs:57:9:57:15 | access to property Prop | C6.set_Prop(int[]) | +| ViableCallable.cs:50:9:50:16 | access to event Event | C2.add_Event(EventHandler) | +| ViableCallable.cs:50:9:50:16 | access to event Event | C3.add_Event(EventHandler) | +| ViableCallable.cs:50:9:50:16 | access to event Event | C6.add_Event(EventHandler) | +| ViableCallable.cs:51:9:51:16 | access to event Event | C2.remove_Event(EventHandler) | +| ViableCallable.cs:51:9:51:16 | access to event Event | C3.remove_Event(EventHandler) | +| ViableCallable.cs:51:9:51:16 | access to event Event | C6.remove_Event(EventHandler) | +| ViableCallable.cs:54:30:54:52 | call to method Mock | ViableCallable.Mock>() | +| ViableCallable.cs:55:9:55:44 | call to method M | C4.M(Int32[], T3) | +| ViableCallable.cs:55:9:55:44 | call to method M | C6.M(Int32[], T3) | +| ViableCallable.cs:57:9:57:15 | access to property Prop | C4.set_Prop(Int32[]) | +| ViableCallable.cs:57:9:57:15 | access to property Prop | C6.set_Prop(Int32[]) | | ViableCallable.cs:57:19:57:25 | access to property Prop | C4.get_Prop() | | ViableCallable.cs:57:19:57:25 | access to property Prop | C6.get_Prop() | -| ViableCallable.cs:59:9:59:17 | access to indexer | C4.set_Item(bool, int[]) | -| ViableCallable.cs:59:9:59:17 | access to indexer | C6.set_Item(bool, int[]) | +| ViableCallable.cs:59:9:59:17 | access to indexer | C4.set_Item(bool, Int32[]) | +| ViableCallable.cs:59:9:59:17 | access to indexer | C6.set_Item(bool, Int32[]) | | ViableCallable.cs:59:21:59:29 | access to indexer | C4.get_Item(bool) | | ViableCallable.cs:59:21:59:29 | access to indexer | C6.get_Item(bool) | -| ViableCallable.cs:61:9:61:16 | access to event Event | C4.add_Event(EventHandler) | -| ViableCallable.cs:61:9:61:16 | access to event Event | C6.add_Event(EventHandler) | -| ViableCallable.cs:62:9:62:16 | access to event Event | C4.remove_Event(EventHandler) | -| ViableCallable.cs:62:9:62:16 | access to event Event | C6.remove_Event(EventHandler) | -| ViableCallable.cs:65:31:65:54 | call to method Mock | ViableCallable.Mock>() | +| ViableCallable.cs:61:9:61:16 | access to event Event | C4.add_Event(EventHandler) | +| ViableCallable.cs:61:9:61:16 | access to event Event | C6.add_Event(EventHandler) | +| ViableCallable.cs:62:9:62:16 | access to event Event | C4.remove_Event(EventHandler) | +| ViableCallable.cs:62:9:62:16 | access to event Event | C6.remove_Event(EventHandler) | +| ViableCallable.cs:65:31:65:54 | call to method Mock | ViableCallable.Mock>() | | ViableCallable.cs:66:9:66:30 | call to method M | C2.M(string, T3) | | ViableCallable.cs:66:9:66:30 | call to method M | C5.M(string, T3) | | ViableCallable.cs:66:9:66:30 | call to method M | C6.M(string, T3) | @@ -232,12 +232,12 @@ | ViableCallable.cs:70:21:70:29 | access to indexer | C2.get_Item(bool) | | ViableCallable.cs:70:21:70:29 | access to indexer | C5.get_Item(bool) | | ViableCallable.cs:70:21:70:29 | access to indexer | C6.get_Item(bool) | -| ViableCallable.cs:72:9:72:16 | access to event Event | C2.add_Event(EventHandler) | -| ViableCallable.cs:72:9:72:16 | access to event Event | C5.add_Event(EventHandler) | -| ViableCallable.cs:72:9:72:16 | access to event Event | C6.add_Event(EventHandler) | -| ViableCallable.cs:73:9:73:16 | access to event Event | C2.remove_Event(EventHandler) | -| ViableCallable.cs:73:9:73:16 | access to event Event | C5.remove_Event(EventHandler) | -| ViableCallable.cs:73:9:73:16 | access to event Event | C6.remove_Event(EventHandler) | +| ViableCallable.cs:72:9:72:16 | access to event Event | C2.add_Event(EventHandler) | +| ViableCallable.cs:72:9:72:16 | access to event Event | C5.add_Event(EventHandler) | +| ViableCallable.cs:72:9:72:16 | access to event Event | C6.add_Event(EventHandler) | +| ViableCallable.cs:73:9:73:16 | access to event Event | C2.remove_Event(EventHandler) | +| ViableCallable.cs:73:9:73:16 | access to event Event | C5.remove_Event(EventHandler) | +| ViableCallable.cs:73:9:73:16 | access to event Event | C6.remove_Event(EventHandler) | | ViableCallable.cs:77:9:77:29 | call to method M | C6.M(T1, T3) | | ViableCallable.cs:79:9:79:15 | access to property Prop | C6.set_Prop(T1) | | ViableCallable.cs:79:19:79:25 | access to property Prop | C6.get_Prop() | @@ -246,9 +246,9 @@ | ViableCallable.cs:83:9:83:16 | access to event Event | C6.add_Event(EventHandler) | | ViableCallable.cs:84:9:84:16 | access to event Event | C6.remove_Event(EventHandler) | | ViableCallable.cs:87:21:87:30 | call to method Mock | ViableCallable.Mock() | -| ViableCallable.cs:88:9:88:44 | dynamic call to method M | C8.M(IEnumerable>) | -| ViableCallable.cs:88:9:88:44 | dynamic call to method M | C9<>.M(IEnumerable>) | -| ViableCallable.cs:88:13:88:43 | call to method Mock | ViableCallable.Mock>>() | +| ViableCallable.cs:88:9:88:44 | dynamic call to method M | C8.M(IEnumerable>) | +| ViableCallable.cs:88:9:88:44 | dynamic call to method M | C9<>.M(IEnumerable>) | +| ViableCallable.cs:88:13:88:43 | call to method Mock | ViableCallable.Mock>>() | | ViableCallable.cs:90:9:90:15 | dynamic access to member Prop1 | C8.set_Prop1(string) | | ViableCallable.cs:90:9:90:15 | dynamic access to member Prop1 | C9<>.set_Prop1(string) | | ViableCallable.cs:90:19:90:25 | dynamic access to member Prop1 | C8.get_Prop1() | @@ -257,13 +257,13 @@ | ViableCallable.cs:92:9:92:12 | dynamic access to element | C9<>.set_Item(int, string) | | ViableCallable.cs:92:16:92:19 | dynamic access to element | C8.get_Item(int) | | ViableCallable.cs:92:16:92:19 | dynamic access to element | C9<>.get_Item(int) | -| ViableCallable.cs:95:13:95:40 | call to method Mock | ViableCallable.Mock>>() | +| ViableCallable.cs:95:13:95:40 | call to method Mock | ViableCallable.Mock>>() | | ViableCallable.cs:99:9:99:15 | dynamic call to method M | C5.M(int) | | ViableCallable.cs:102:9:102:16 | access to property Prop2 | C5.set_Prop2(string) | -| ViableCallable.cs:105:9:105:17 | access to event Event2 | C5.add_Event2(EventHandler) | -| ViableCallable.cs:106:9:106:17 | access to event Event2 | C5.remove_Event2(EventHandler) | -| ViableCallable.cs:120:9:120:25 | dynamic call to method M2 | C8.M2(decimal[]) | -| ViableCallable.cs:124:9:124:24 | dynamic call to method M2 | C8.M2(string[]) | +| ViableCallable.cs:105:9:105:17 | access to event Event2 | C5.add_Event2(EventHandler) | +| ViableCallable.cs:106:9:106:17 | access to event Event2 | C5.remove_Event2(EventHandler) | +| ViableCallable.cs:120:9:120:25 | dynamic call to method M2 | C8.M2(Decimal[]) | +| ViableCallable.cs:124:9:124:24 | dynamic call to method M2 | C8.M2(String[]) | | ViableCallable.cs:132:9:132:28 | dynamic call to method M | C6.M(T1, T3) | | ViableCallable.cs:134:9:134:14 | dynamic access to member Prop | C6.set_Prop(T1) | | ViableCallable.cs:134:18:134:23 | dynamic access to member Prop | C6.get_Prop() | @@ -272,23 +272,23 @@ | ViableCallable.cs:138:9:138:52 | ... += ... | C6.add_Event(EventHandler) | | ViableCallable.cs:139:9:139:52 | ... -= ... | C6.remove_Event(EventHandler) | | ViableCallable.cs:143:13:143:22 | call to method Mock | ViableCallable.Mock() | -| ViableCallable.cs:144:9:144:14 | dynamic call to method M3 | C8.M3(params double[]) | +| ViableCallable.cs:144:9:144:14 | dynamic call to method M3 | C8.M3(params Double[]) | | ViableCallable.cs:144:9:144:14 | dynamic call to method M3 | C9<>.M3(params T[]) | -| ViableCallable.cs:145:9:145:15 | dynamic call to method M3 | C8.M3(params double[]) | +| ViableCallable.cs:145:9:145:15 | dynamic call to method M3 | C8.M3(params Double[]) | | ViableCallable.cs:145:9:145:15 | dynamic call to method M3 | C9<>.M3(params T[]) | -| ViableCallable.cs:146:9:146:20 | dynamic call to method M3 | C8.M3(params double[]) | +| ViableCallable.cs:146:9:146:20 | dynamic call to method M3 | C8.M3(params Double[]) | | ViableCallable.cs:146:9:146:20 | dynamic call to method M3 | C9<>.M3(params T[]) | -| ViableCallable.cs:149:9:149:16 | dynamic call to method M3 | C8.M3(params double[]) | +| ViableCallable.cs:149:9:149:16 | dynamic call to method M3 | C8.M3(params Double[]) | | ViableCallable.cs:149:9:149:16 | dynamic call to method M3 | C9<>.M3(params T[]) | -| ViableCallable.cs:149:9:149:16 | dynamic call to method M3 | C10.M3(params double[]) | +| ViableCallable.cs:149:9:149:16 | dynamic call to method M3 | C10.M3(params Double[]) | | ViableCallable.cs:149:9:149:16 | dynamic call to method M3 | Test.MainClass.ImplAlpha.M3() | | ViableCallable.cs:149:9:149:16 | dynamic call to method M3 | Test.MainClass.SecondLevelImpl.M3() | -| ViableCallable.cs:150:9:150:17 | dynamic call to method M3 | C8.M3(params double[]) | +| ViableCallable.cs:150:9:150:17 | dynamic call to method M3 | C8.M3(params Double[]) | | ViableCallable.cs:150:9:150:17 | dynamic call to method M3 | C9<>.M3(params T[]) | -| ViableCallable.cs:150:9:150:17 | dynamic call to method M3 | C10.M3(params double[]) | -| ViableCallable.cs:151:9:151:22 | dynamic call to method M3 | C8.M3(params double[]) | +| ViableCallable.cs:150:9:150:17 | dynamic call to method M3 | C10.M3(params Double[]) | +| ViableCallable.cs:151:9:151:22 | dynamic call to method M3 | C8.M3(params Double[]) | | ViableCallable.cs:151:9:151:22 | dynamic call to method M3 | C9<>.M3(params T[]) | -| ViableCallable.cs:151:9:151:22 | dynamic call to method M3 | C10.M3(params double[]) | +| ViableCallable.cs:151:9:151:22 | dynamic call to method M3 | C10.M3(params Double[]) | | ViableCallable.cs:153:9:153:17 | dynamic access to member Prop1 | C8.set_Prop1(string) | | ViableCallable.cs:153:9:153:17 | dynamic access to member Prop1 | C9<>.set_Prop1(string) | | ViableCallable.cs:153:9:153:17 | dynamic access to member Prop1 | C10.set_Prop1(bool) | @@ -323,39 +323,39 @@ | ViableCallable.cs:155:18:155:23 | dynamic access to element | C8.get_Item(int) | | ViableCallable.cs:155:18:155:23 | dynamic access to element | C9<>.get_Item(int) | | ViableCallable.cs:155:18:155:23 | dynamic access to element | C10.get_Item(int) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C2<>.add_Event(EventHandler) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C2.add_Event(EventHandler) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C2.add_Event(EventHandler) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C2.add_Event(EventHandler) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C3.add_Event(EventHandler) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C5.add_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C2<>.add_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C2.add_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C2.add_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C2.add_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C3.add_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C5.add_Event(EventHandler) | | ViableCallable.cs:157:9:157:54 | ... += ... | C6<,>.add_Event(EventHandler) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C6.add_Event(EventHandler) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C6.add_Event(EventHandler) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C6.add_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C6.add_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C6.add_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C6.add_Event(EventHandler) | | ViableCallable.cs:157:9:157:54 | ... += ... | C6.add_Event(EventHandler) | | ViableCallable.cs:157:9:157:54 | ... += ... | C6.add_Event(EventHandler) | | ViableCallable.cs:157:9:157:54 | ... += ... | C7<>.add_Event(EventHandler) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C8.add_Event(EventHandler) | -| ViableCallable.cs:157:9:157:54 | ... += ... | C9<>.add_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C2<>.remove_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C2.remove_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C2.remove_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C2.remove_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C3.remove_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C5.remove_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C8.add_Event(EventHandler) | +| ViableCallable.cs:157:9:157:54 | ... += ... | C9<>.add_Event(EventHandler) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C2<>.remove_Event(EventHandler) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C2.remove_Event(EventHandler) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C2.remove_Event(EventHandler) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C2.remove_Event(EventHandler) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C3.remove_Event(EventHandler) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C5.remove_Event(EventHandler) | | ViableCallable.cs:158:9:158:54 | ... -= ... | C6<,>.remove_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C6.remove_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C6.remove_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C6.remove_Event(EventHandler) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C6.remove_Event(EventHandler) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C6.remove_Event(EventHandler) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C6.remove_Event(EventHandler) | | ViableCallable.cs:158:9:158:54 | ... -= ... | C6.remove_Event(EventHandler) | | ViableCallable.cs:158:9:158:54 | ... -= ... | C6.remove_Event(EventHandler) | | ViableCallable.cs:158:9:158:54 | ... -= ... | C7<>.remove_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C8.remove_Event(EventHandler) | -| ViableCallable.cs:158:9:158:54 | ... -= ... | C9<>.remove_Event(EventHandler) | -| ViableCallable.cs:161:9:161:40 | dynamic call to method M4 | C8.M4(byte, IEnumerable) | -| ViableCallable.cs:161:19:161:39 | call to method Mock | ViableCallable.Mock>() | -| ViableCallable.cs:162:9:162:38 | dynamic call to method M4 | C8.M4(byte, IEnumerable) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C8.remove_Event(EventHandler) | +| ViableCallable.cs:158:9:158:54 | ... -= ... | C9<>.remove_Event(EventHandler) | +| ViableCallable.cs:161:9:161:40 | dynamic call to method M4 | C8.M4(byte, IEnumerable) | +| ViableCallable.cs:161:19:161:39 | call to method Mock | ViableCallable.Mock>() | +| ViableCallable.cs:162:9:162:38 | dynamic call to method M4 | C8.M4(byte, IEnumerable) | | ViableCallable.cs:165:9:165:17 | dynamic access to member Prop1 | C10.set_Prop1(bool) | | ViableCallable.cs:175:9:175:15 | dynamic access to element | C2<>.set_Item(T, string) | | ViableCallable.cs:175:9:175:15 | dynamic access to element | C6<,>.set_Item(T2, T1) | @@ -366,16 +366,16 @@ | ViableCallable.cs:191:9:191:149 | call to method InvokeMember | C10.set_Prop3(string) | | ViableCallable.cs:194:9:194:146 | call to method InvokeMember | C10.get_Item(int) | | ViableCallable.cs:195:9:195:152 | call to method InvokeMember | C10.set_Item(int, bool) | -| ViableCallable.cs:199:9:199:147 | call to method InvokeMember | C10.add_Event(EventHandler) | -| ViableCallable.cs:200:9:200:150 | call to method InvokeMember | C10.remove_Event(EventHandler) | +| ViableCallable.cs:199:9:199:147 | call to method InvokeMember | C10.add_Event(EventHandler) | +| ViableCallable.cs:200:9:200:150 | call to method InvokeMember | C10.remove_Event(EventHandler) | | ViableCallable.cs:235:9:235:15 | call to method M | C2.M(string, T3) | | ViableCallable.cs:235:9:235:15 | call to method M | C2.M(string, T3) | | ViableCallable.cs:235:9:235:15 | call to method M | C2.M(string, T3) | | ViableCallable.cs:235:9:235:15 | call to method M | C3.M(string, T3) | -| ViableCallable.cs:235:9:235:15 | call to method M | C4.M(int[], T3) | +| ViableCallable.cs:235:9:235:15 | call to method M | C4.M(Int32[], T3) | | ViableCallable.cs:235:9:235:15 | call to method M | C5.M(string, T3) | | ViableCallable.cs:235:9:235:15 | call to method M | C6.M(bool, T3) | -| ViableCallable.cs:235:9:235:15 | call to method M | C6.M(int[], T3) | +| ViableCallable.cs:235:9:235:15 | call to method M | C6.M(Int32[], T3) | | ViableCallable.cs:235:9:235:15 | call to method M | C6.M(string, T3) | | ViableCallable.cs:235:9:235:15 | call to method M | C6.M(string, T3) | | ViableCallable.cs:235:9:235:15 | call to method M | C6.M(string, T3) | diff --git a/csharp/ql/test/library-tests/frameworks/format/StringFormatItemParameter.expected b/csharp/ql/test/library-tests/frameworks/format/StringFormatItemParameter.expected index 456d7bbea6d..85e2d82f3ab 100644 --- a/csharp/ql/test/library-tests/frameworks/format/StringFormatItemParameter.expected +++ b/csharp/ql/test/library-tests/frameworks/format/StringFormatItemParameter.expected @@ -4,57 +4,57 @@ | Console | Write(string, object, object, object) | arg0 | | Console | Write(string, object, object, object) | arg1 | | Console | Write(string, object, object, object) | arg2 | -| Console | Write(string, params object[]) | arg | +| Console | Write(string, params Object[]) | arg | | Console | WriteLine(string, object) | arg0 | | Console | WriteLine(string, object, object) | arg0 | | Console | WriteLine(string, object, object) | arg1 | | Console | WriteLine(string, object, object, object) | arg0 | | Console | WriteLine(string, object, object, object) | arg1 | | Console | WriteLine(string, object, object, object) | arg2 | -| Console | WriteLine(string, params object[]) | arg | -| Debug | Assert(bool, string, string, params object[]) | args | -| Debug | Print(string, params object[]) | args | -| Debug | WriteLine(string, params object[]) | args | +| Console | WriteLine(string, params Object[]) | arg | +| Debug | Assert(bool, string, string, params Object[]) | args | +| Debug | Print(string, params Object[]) | args | +| Debug | WriteLine(string, params Object[]) | args | | StringBuilder | AppendFormat(IFormatProvider, string, object) | arg0 | | StringBuilder | AppendFormat(IFormatProvider, string, object, object) | arg0 | | StringBuilder | AppendFormat(IFormatProvider, string, object, object) | arg1 | | StringBuilder | AppendFormat(IFormatProvider, string, object, object, object) | arg0 | | StringBuilder | AppendFormat(IFormatProvider, string, object, object, object) | arg1 | | StringBuilder | AppendFormat(IFormatProvider, string, object, object, object) | arg2 | -| StringBuilder | AppendFormat(IFormatProvider, string, params object[]) | args | +| StringBuilder | AppendFormat(IFormatProvider, string, params Object[]) | args | | StringBuilder | AppendFormat(string, object) | arg0 | | StringBuilder | AppendFormat(string, object, object) | arg0 | | StringBuilder | AppendFormat(string, object, object) | arg1 | | StringBuilder | AppendFormat(string, object, object, object) | arg0 | | StringBuilder | AppendFormat(string, object, object, object) | arg1 | | StringBuilder | AppendFormat(string, object, object, object) | arg2 | -| StringBuilder | AppendFormat(string, params object[]) | args | -| Strings | MyStringFormat(string, params object[]) | args | +| StringBuilder | AppendFormat(string, params Object[]) | args | +| Strings | MyStringFormat(string, params Object[]) | args | | TextWriter | Write(string, object) | arg0 | | TextWriter | Write(string, object, object) | arg0 | | TextWriter | Write(string, object, object) | arg1 | | TextWriter | Write(string, object, object, object) | arg0 | | TextWriter | Write(string, object, object, object) | arg1 | | TextWriter | Write(string, object, object, object) | arg2 | -| TextWriter | Write(string, params object[]) | arg | +| TextWriter | Write(string, params Object[]) | arg | | TextWriter | WriteLine(string, object) | arg0 | | TextWriter | WriteLine(string, object, object) | arg0 | | TextWriter | WriteLine(string, object, object) | arg1 | | TextWriter | WriteLine(string, object, object, object) | arg0 | | TextWriter | WriteLine(string, object, object, object) | arg1 | | TextWriter | WriteLine(string, object, object, object) | arg2 | -| TextWriter | WriteLine(string, params object[]) | arg | +| TextWriter | WriteLine(string, params Object[]) | arg | | string | Format(IFormatProvider, string, object) | arg0 | | string | Format(IFormatProvider, string, object, object) | arg0 | | string | Format(IFormatProvider, string, object, object) | arg1 | | string | Format(IFormatProvider, string, object, object, object) | arg0 | | string | Format(IFormatProvider, string, object, object, object) | arg1 | | string | Format(IFormatProvider, string, object, object, object) | arg2 | -| string | Format(IFormatProvider, string, params object[]) | args | +| string | Format(IFormatProvider, string, params Object[]) | args | | string | Format(string, object) | arg0 | | string | Format(string, object, object) | arg0 | | string | Format(string, object, object) | arg1 | | string | Format(string, object, object, object) | arg0 | | string | Format(string, object, object, object) | arg1 | | string | Format(string, object, object, object) | arg2 | -| string | Format(string, params object[]) | args | +| string | Format(string, params Object[]) | args | diff --git a/csharp/ql/test/library-tests/methods/Parameters9.expected b/csharp/ql/test/library-tests/methods/Parameters9.expected index 66c1f42c7fd..2af714b9abc 100644 --- a/csharp/ql/test/library-tests/methods/Parameters9.expected +++ b/csharp/ql/test/library-tests/methods/Parameters9.expected @@ -3,5 +3,5 @@ | methods.cs:145:65:145:65 | e | methods.cs:145:69:145:77 | ... + ... | Method2(int, int, int, int, string) | | methods.cs:168:51:168:55 | right | methods.cs:168:59:168:59 | 0 | Plus(int, int) | | methods.cs:173:133:173:133 | i | methods.cs:173:137:173:137 | 1 | SkipTwo(IEnumerable, int) | -| methods.cs:173:133:173:133 | i | methods.cs:173:137:173:137 | 1 | SkipTwo(IEnumerable, int) | -| methods.cs:178:137:178:137 | i | methods.cs:178:141:178:141 | 1 | SkipTwoInt(IEnumerable, int) | +| methods.cs:173:133:173:133 | i | methods.cs:173:137:173:137 | 1 | SkipTwo(IEnumerable, int) | +| methods.cs:178:137:178:137 | i | methods.cs:178:141:178:141 | 1 | SkipTwoInt(IEnumerable, int) | diff --git a/csharp/ql/test/library-tests/overrides/Overrides22.expected b/csharp/ql/test/library-tests/overrides/Overrides22.expected index cef719c8add..11bb9d46cbd 100644 --- a/csharp/ql/test/library-tests/overrides/Overrides22.expected +++ b/csharp/ql/test/library-tests/overrides/Overrides22.expected @@ -2,15 +2,15 @@ | CallTargets.C3.m() | CallTargets.C2.m() | overrides | | overrides.A1.Event | overrides.I5.Event | implements | | overrides.A1.Item[int] | overrides.I5.Item[int] | implements | -| overrides.A1.M(dynamic[], T) | overrides.I2.M(object[], S) | implements | +| overrides.A1.M(dynamic[], T) | overrides.I2.M(Object[], S) | implements | | overrides.A1.Property | overrides.I5.Property | implements | | overrides.A4.Event | overrides.I5.Event | implements | | overrides.A4.Item[int] | overrides.I5.Item[int] | implements | -| overrides.A4.M(dynamic[], T) | overrides.I2.M(object[], S) | implements | +| overrides.A4.M(dynamic[], T) | overrides.I2.M(Object[], S) | implements | | overrides.A4.Property | overrides.I5.Property | implements | | overrides.A6.Event | overrides.I5.Event | implements | | overrides.A6.Item[int] | overrides.I5.Item[int] | implements | -| overrides.A6.M(object[], T) | overrides.I2.M(object[], S) | implements | +| overrides.A6.M(Object[], T) | overrides.I2.M(Object[], S) | implements | | overrides.A6.Property | overrides.I5.Property | implements | | overrides.A8.Event | overrides.A1.Event | overrides | | overrides.A8.Item[int] | overrides.A1.Item[int] | overrides | diff --git a/csharp/ql/test/library-tests/tostringwithtypes/toStringWithTypes.expected b/csharp/ql/test/library-tests/tostringwithtypes/toStringWithTypes.expected index 228694785c6..2dd28b7214d 100644 --- a/csharp/ql/test/library-tests/tostringwithtypes/toStringWithTypes.expected +++ b/csharp/ql/test/library-tests/tostringwithtypes/toStringWithTypes.expected @@ -1,7 +1,7 @@ | Delegate<> | Delegate(int, T) | -| Delegate | Delegate | | Item | Item[T, bool] | -| M | M(IEnumerable) | +| M | M(IEnumerable) | +| M | M(Int32[,,,][][,][,,]) | | M | M(__arglist) | | M | M(bool) | | M | M(byte) | @@ -13,7 +13,6 @@ | M | M(float) | | M | M(int) | | M | M(int*) | -| M | M(int[,,,][][,][,,]) | | M | M(long) | | M | M(object) | | M | M(out T) | @@ -27,6 +26,6 @@ | M | M(ref S) | | M | M(ref char?) | | ToStringWithTypes<> | ToStringWithTypes | -| add_Event | add_Event(Delegate) | +| add_Event | add_Event(Delegate) | | get_Item | get_Item(T, bool) | -| remove_Event | remove_Event(Delegate) | +| remove_Event | remove_Event(Delegate) | From 41b441614b31c7cacf864689d6db1f60991d1385 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 11 Nov 2019 18:47:46 +0000 Subject: [PATCH 1046/1227] C#: Address review comments part 1. --- .../Entities/Method.cs | 6 +- .../Entities/Types/Nullability.cs | 4 +- .../src/semmle/code/csharp/AnnotatedType.qll | 104 ++++++++++-------- 3 files changed, 63 insertions(+), 51 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index f3a9a9f0d08..abd104be156 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -264,7 +264,7 @@ namespace Semmle.Extraction.CSharp.Entities var methodKind = methodDecl.MethodKind; - if(methodKind == MethodKind.ExplicitInterfaceImplementation) + if (methodKind == MethodKind.ExplicitInterfaceImplementation) { // Retrieve the original method kind methodKind = methodDecl.ExplicitInterfaceImplementations.Select(m => m.MethodKind).FirstOrDefault(); @@ -348,7 +348,9 @@ namespace Semmle.Extraction.CSharp.Entities child++; } - trapFile.type_nullability(this, NullabilityEntity.Create(Context, new Nullability(symbol))); + var nullability = new Nullability(symbol); + if (!nullability.IsOblivious) + trapFile.type_nullability(this, NullabilityEntity.Create(Context, nullability)); } else { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs index 4dc0a9046aa..084ac570fa0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs @@ -30,6 +30,8 @@ namespace Semmle.Extraction.CSharp.Entities return new Nullability(ts); } + public bool IsOblivious => Annotation == 0 && NullableParameters.Length == 0; + static readonly Nullability oblivious = new Nullability(NullableAnnotation.Disabled); static readonly Nullability annotated = new Nullability(NullableAnnotation.Annotated); static readonly Nullability notannotated = new Nullability(NullableAnnotation.NotAnnotated); @@ -113,7 +115,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.nullability(this, symbol.Annotation); int i = 0; - foreach(var s in symbol.NullableParameters) + foreach (var s in symbol.NullableParameters) { trapFile.nullability_member(this, i, Create(Context, s)); i++; diff --git a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll index 98e25aa7524..d1146f5ea1e 100644 --- a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll +++ b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll @@ -18,7 +18,7 @@ private module Annotations { /** An annotation on a type. */ class TypeAnnotation extends TAnnotation { /** Gets the bit position in the bit-field, also used to order the annotations in the text format. */ - abstract int getBit(); + int getBit() { none() } /** Gets the string prefixing the type, if any. */ string getPrefix() { none() } @@ -57,6 +57,41 @@ private module Annotations { override int getBit() { result = 6 } } + /** + * A structured type annotation representing type nullability. + * For example, `IDictionary?` has nullability `?`. + */ + class Nullability extends TypeAnnotation, TNullability { + @nullability nullability; + + Nullability() { this = TNullability(nullability) } + + override string toString() { result = getMemberString() + getSelfNullability() } + + language[monotonicAggregates] + private string getMemberString() { + if nullability_member(nullability, _, _) + then + result = "<" + + concat(int i, Nullability child | + nullability_member(nullability, i, getNullability(child)) + | + child.toString(), "," order by i + ) + ">" + else result = "" + } + + /** + * Gets a string representing the nullability, disregarding child nullability. + * For example, `IDictionary?` has nullability `?`. + */ + string getSelfNullability() { none() } + + override int getBit() { none() } + } + + @nullability getNullability(Nullability n) { n = TNullability(result) } + private newtype TAnnotations = TAnnotationFlags(int flags, Nullability n) { exists(Element e | @@ -75,9 +110,6 @@ private module Annotations { this = TAnnotationsNoFlags(result) } - /** Gets the nullability with no additional flags. */ - Nullability getNoFlagsNullability() { this = TAnnotationsNoFlags(result) } - /** Gets text to be displayed before the type. */ string getTypePrefix() { result = concat(TypeAnnotation a | @@ -114,6 +146,11 @@ private module Annotations { } } + /** Gets the nullability with no additional flags. */ + Nullability getNoFlagsNullability(TypeAnnotations annotations) { + annotations = TAnnotationsNoFlags(result) + } + /** * Gets the `i`th child of type annotations `annotations`. * This is used to represent structured datatypes, where the structure @@ -121,37 +158,7 @@ private module Annotations { */ bindingset[i] TypeAnnotations getChild(TypeAnnotations annotations, int i) { - result.getNoFlagsNullability() = getChildNullability(annotations.getNullability(), i) - } - - /** - * A structured type annotation representing type nullability. - * For example, `IDictionary?` has nullability `?`. - */ - abstract class Nullability extends TypeAnnotation, TNullability { - @nullability nullability; - - Nullability() { this = TNullability(nullability) } - - @nullability getNullability() { result = nullability } - - override string toString() { result = getMemberString() + getSelfNullability() } - - language[monotonicAggregates] - private string getMemberString() { - if nullability_member(nullability, _, _) - then - result = "<" + - concat(int i, Nullability child | - nullability_member(nullability, i, child.getNullability()) - | - child.toString(), "," order by i - ) + ">" - else result = "" - } - - /** Gets a string representing the nullability, disregarding child nullability. */ - string getSelfNullability() { none() } + getNoFlagsNullability(result) = getChildNullability(annotations.getNullability(), i) } /** @@ -162,8 +169,8 @@ private module Annotations { */ bindingset[i] Nullability getChildNullability(Nullability n, int i) { - if nullability_member(n.getNullability(), i, _) - then nullability_member(n.getNullability(), i, result.getNullability()) + if nullability_member(getNullability(n), i, _) + then nullability_member(getNullability(n), i, getNullability(result)) else result = n } @@ -176,8 +183,6 @@ private module Annotations { ObliviousNullability() { nullability instanceof @oblivious } override string getSelfNullability() { result = "_" } - - override int getBit() { none() } } /** @@ -220,7 +225,7 @@ private module Annotations { annotations = TAnnotationFlags(getElementTypeFlags(element), getElementNullability(element)) or not exists(getElementTypeFlags(element)) and - annotations.getNoFlagsNullability() = getElementNullability(element) + getNoFlagsNullability(annotations) = getElementNullability(element) ) and ( type = element.(Assignable).getType() @@ -250,16 +255,18 @@ private Annotations::Nullability getTypeParameterNullability( TypeParameterConstraints constraints, Type type ) { if specific_type_parameter_nullability(constraints, getTypeRef(type), _) - then specific_type_parameter_nullability(constraints, getTypeRef(type), result.getNullability()) + then + specific_type_parameter_nullability(constraints, getTypeRef(type), + Annotations::getNullability(result)) else ( - specific_type_parameter_constraints(constraints, type) and + specific_type_parameter_constraints(constraints, getTypeRef(type)) and result instanceof Annotations::NoNullability ) } private Annotations::Nullability getElementNullability(@has_type_annotation element) { if type_nullability(element, _) - then type_nullability(element, result.getNullability()) + then type_nullability(element, Annotations::getNullability(result)) else result instanceof Annotations::NoNullability } @@ -272,10 +279,10 @@ private newtype TAnnotatedType = annotations = Annotations::getChild(c.getAnnotations(), i) ) or - annotations.getNoFlagsNullability() = getTypeParameterNullability(_, type) + Annotations::getNoFlagsNullability(annotations) = getTypeParameterNullability(_, type) or // All types have at least one annotated type - annotations.getNoFlagsNullability() instanceof Annotations::NoNullability + Annotations::getNoFlagsNullability(annotations) instanceof Annotations::NoNullability or exists(AnnotatedArrayType at | type = at.getType().(ArrayType).getElementType() and @@ -344,16 +351,17 @@ class AnnotatedType extends TAnnotatedType { /** Holds if this annotated type applies to element `e`. */ predicate appliesTo(Element e) { Annotations::elementTypeAnnotations(e, type, annotations) } - /** Holds if this annotated type is the `ith` type argument of constructed generic 'g'. */ + /** Holds if this annotated type is the `i`th type argument of constructed generic 'g'. */ predicate appliesToTypeArgument(ConstructedGeneric g, int i) { - this.getAnnotations().getNoFlagsNullability() = Annotations::getChildNullability(getElementNullability(g), + Annotations::getNoFlagsNullability(this.getAnnotations()) = Annotations::getChildNullability(getElementNullability(g), i) and this.getType() = g.getTypeArgument(i) } /** Holds if this annotated type applies to type parameter constraints `constraints`. */ predicate appliesToTypeConstraint(TypeParameterConstraints constraints) { - this.getAnnotations().getNoFlagsNullability() = getTypeParameterNullability(constraints, type) + Annotations::getNoFlagsNullability(this.getAnnotations()) = getTypeParameterNullability(constraints, + type) } } From 7c21ebb526288f1377c4321ea93ae3b0535b51a1 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 11 Nov 2019 19:24:48 +0000 Subject: [PATCH 1047/1227] C#: Change dbscheme from nullability_member to nullability_parent --- .../Entities/Types/Nullability.cs | 2 +- .../Semmle.Extraction.CSharp/Tuples.cs | 4 +- .../src/semmle/code/csharp/AnnotatedType.qll | 10 +- csharp/ql/src/semmlecode.csharp.dbscheme | 4 +- .../ql/src/semmlecode.csharp.dbscheme.stats | 18266 ++++++++-------- 5 files changed, 8928 insertions(+), 9358 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs index 084ac570fa0..64f4ed58783 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs @@ -117,7 +117,7 @@ namespace Semmle.Extraction.CSharp.Entities int i = 0; foreach (var s in symbol.NullableParameters) { - trapFile.nullability_member(this, i, Create(Context, s)); + trapFile.nullability_parent(Create(Context, s), i, this); i++; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index f6de00452d0..c6637640556 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -386,9 +386,9 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("nullability", nullability, annotation); } - internal static void nullability_member(this TextWriter trapFile, NullabilityEntity nullability, int index, NullabilityEntity child) + internal static void nullability_parent(this TextWriter trapFile, NullabilityEntity nullability, int index, NullabilityEntity parent) { - trapFile.WriteTuple("nullability_member", nullability, index, child); + trapFile.WriteTuple("nullability_parent", nullability, index, parent); } internal static void numlines(this TextWriter trapFile, IEntity label, LineCounts lineCounts) diff --git a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll index d1146f5ea1e..feec749f097 100644 --- a/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll +++ b/csharp/ql/src/semmle/code/csharp/AnnotatedType.qll @@ -70,11 +70,11 @@ private module Annotations { language[monotonicAggregates] private string getMemberString() { - if nullability_member(nullability, _, _) + if nullability_parent(_, _, nullability) then result = "<" + concat(int i, Nullability child | - nullability_member(nullability, i, getNullability(child)) + nullability_parent(getNullability(child), i, nullability) | child.toString(), "," order by i ) + ">" @@ -169,8 +169,8 @@ private module Annotations { */ bindingset[i] Nullability getChildNullability(Nullability n, int i) { - if nullability_member(getNullability(n), i, _) - then nullability_member(getNullability(n), i, getNullability(result)) + if nullability_parent(_, i, getNullability(n)) + then nullability_parent(getNullability(result), i, getNullability(n)) else result = n } @@ -190,7 +190,7 @@ private module Annotations { * and all type arguments are oblivious. */ class NoNullability extends ObliviousNullability { - NoNullability() { not nullability_member(nullability, _, _) } + NoNullability() { not nullability_parent(_, _, nullability) } } /** A type with annotated nullablity, `?`. */ diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index e55d8c99030..df0118d2d28 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -480,8 +480,8 @@ case @nullability.kind of | 2 = @annotated ; -#keyset[nullability, index] -nullability_member(int nullability: @nullability ref, int index: int ref, int child: @nullability ref) +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref) diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme.stats b/csharp/ql/src/semmlecode.csharp.dbscheme.stats index 426949c2061..08b4255824e 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme.stats +++ b/csharp/ql/src/semmlecode.csharp.dbscheme.stats @@ -5,11 +5,11 @@ @diagnostic -12070 +108998 @extractor_message -57 +55 @externalDefect @@ -21,43 +21,43 @@ @externalDataElement -9 +10 @duplication -20134 +18936 @similarity -149289 +141055 @location_default -11787435 +10628591 @assembly -2863 +2760 @file -24954 +20987 @folder -7016 +6292 @namespace -6505 +5700 @namespace_declaration -22696 +19007 @using_namespace_directive -106992 +86694 @using_static_directive @@ -117,23 +117,23 @@ @enum_type -8073 +11359 @struct_type -31632 +43620 @class_type -126692 +142562 @interface_type -137173 +206665 @delegate_type -40645 +55958 @null_type @@ -141,19 +141,19 @@ @type_parameter -58090 +80353 @pointer_type -383 +456 @nullable_type -1382 +2279 @array_type -7961 +9835 @void_type @@ -168,40 +168,40 @@ 1 +@arglist_type +1 + + @tuple_type -1768 +2682 @uint_ptr_type 0 -@arglist_type -0 - - @unknown_type 0 @typeref -349451 +462875 @attribute -152979 +144787 @type_mention -2269573 +2181438 @oblivious -58 +57 @not_annotated -47 +49 @annotated @@ -209,7 +209,7 @@ @type_parameter_constraints -389563 +363573 @modifier @@ -217,87 +217,87 @@ @property -268986 +326745 @indexer -25314 +29544 @getter -286438 +338867 @setter -50195 +54213 @event -8976 +7794 @add_event_accessor -7857 +6531 @remove_event_accessor -7857 +6531 @operator -13320 +18266 @method -990339 +1183684 @constructor -149144 +171824 @destructor -388 +569 @local_function -1201 +1225 @addressable_field -178578 +187149 @constant -106769 +147707 @addressable_local_variable -307769 +289247 @local_constant -1627 +1741 @local_variable_ref -54 +70 @parameter -1662795 +2097984 @block_stmt -483215 +470589 @expr_stmt -510339 +484425 @if_stmt -158006 +154912 @switch_stmt @@ -305,107 +305,107 @@ @while_stmt -4304 +4300 @do_stmt -794 +825 @for_stmt -8189 +8294 @foreach_stmt -11629 +10100 @break_stmt -17068 +16413 @continue_stmt -3270 +3174 @goto_stmt -1200 +1297 @goto_case_stmt -330 +328 @goto_default_stmt -252 +266 @throw_stmt -62807 +63215 @return_stmt -172166 +166461 @yield_stmt -1334 +1269 @try_stmt -6286 +6192 @checked_stmt -234 +241 @unchecked_stmt -186 +169 @lock_stmt -1831 +1789 @using_block_stmt -6120 +4219 @var_decl_stmt -269815 +253667 @const_decl_stmt -1623 +1735 @empty_stmt -349 +244 @unsafe_stmt -301 +342 @fixed_stmt -783 +1207 @label_stmt -439 +448 @catch -4711 +4524 @case_stmt -53160 +53221 @local_function_stmt -1199 +1335 @using_decl_stmt @@ -413,271 +413,271 @@ @bool_literal_expr -83252 +76358 @char_literal_expr -16894 +15164 @decimal_literal_expr -134 +100 @int_literal_expr -268458 +275065 @long_literal_expr -178 +193 @uint_literal_expr -2083 +3178 @ulong_literal_expr -227 +249 @float_literal_expr -631 +627 @double_literal_expr -656 +629 @string_literal_expr -402840 +372602 @null_literal_expr -141562 +139157 @this_access_expr -489938 +461644 @base_access_expr -5239 +4040 @local_variable_access_expr -1050542 +991740 @parameter_access_expr -579372 +572331 @field_access_expr -712366 +711987 @property_access_expr -473246 +424606 @method_access_expr -7270 +7195 @event_access_expr -2309 +1273 @indexer_access_expr -31604 +30564 @array_access_expr -25694 +24812 @type_access_expr -724742 +706800 @typeof_expr -26440 +24651 @method_invocation_expr -928336 +873671 @delegate_invocation_expr -4558 +4434 @operator_invocation_expr -41161 +40914 @cast_expr -212776 +210715 @object_creation_expr -104367 +90994 @explicit_delegate_creation_expr -1190 +1143 @implicit_delegate_creation_expr -3755 +3030 @array_creation_expr -22244 +21192 @default_expr -8135 +8491 @plus_expr -73 +64 @minus_expr -6795 +5824 @bit_not_expr -715 +801 @log_not_expr -27569 +28058 @post_incr_expr -12713 +12241 @post_decr_expr -1368 +1467 @pre_incr_expr -1215 +1297 @pre_decr_expr -294 +287 @mul_expr -4053 +4200 @div_expr -1258 +1261 @rem_expr -573 +583 @add_expr -32765 +29468 @sub_expr -10607 +11073 @lshift_expr -1678 +1825 @rshift_expr -1075 +1182 @lt_expr -15042 +15563 @gt_expr -10187 +10285 @le_expr -3530 +3891 @ge_expr -5467 +5876 @eq_expr -78231 +73546 @ne_expr -53191 +52803 @bit_and_expr -5903 +6565 @bit_xor_expr -507 +497 @bit_or_expr -11954 +12259 @log_and_expr -31285 +30520 @log_or_expr -21875 +22295 @is_expr -8517 +8506 @as_expr -7102 +6480 @null_coalescing_expr -4350 +4436 @conditional_expr -14417 +13572 @simple_assign_expr -207337 +196499 @assign_add_expr -3522 +3401 @assign_sub_expr -619 +634 @assign_mul_expr -123 +131 @assign_div_expr -49 +54 @assign_rem_expr @@ -685,67 +685,67 @@ @assign_and_expr -374 +382 @assign_xor_expr -88 +105 @assign_or_expr -1706 +1858 @assign_lshift_expr -69 +90 @assign_rshift_expr -97 +119 @object_init_expr -5120 +3022 @collection_init_expr -1313 +911 @array_init_expr -19188 +17916 @checked_expr -369 +403 @unchecked_expr -1872 +2931 @constructor_init_expr -9978 +9066 @add_event_expr -877 +672 @remove_event_expr -408 +334 @local_var_decl_expr -309563 +291172 @lambda_expr -24042 +16045 @anonymous_method_expr -192 +174 @dynamic_element_access_expr @@ -753,59 +753,55 @@ @dynamic_member_access_expr -444 +89 @pointer_indirection_expr -2768 +3240 @address_of_expr -717 +967 @sizeof_expr -746 +1106 @await_expr -27405 +27481 @nameof_expr -18016 +18864 @interpolated_string_expr -4321 - - -@unknown_expr -22532 +5023 @throw_expr -917 +931 @tuple_expr -2152 +2261 @local_function_invocation_expr -2317 +2434 @ref_expr -108 +145 @discard_expr -471 +544 @switch_expr -34 +35 @recursive_pattern_expr @@ -821,7 +817,7 @@ @switch_case_expr -142 +148 @assign_coalesce_expr @@ -829,11 +825,11 @@ @suppress_nullable_warning_expr -252 +428 @namespace_access_expr -435 +12 @par_expr @@ -844,6 +840,10 @@ 0 +@unknown_expr +0 + + @range_expr 0 @@ -857,11 +857,11 @@ @xmlelement -3426 +1226 @xmlattribute -5138 +1785 @xmlnamespace @@ -869,63 +869,63 @@ @xmlcomment -300 +152 @xmlcharacters -826 +238 @singlelinecomment -330391 +305420 @xmldoccomment -276055 +210408 @multilinecomment -12000 +10871 @commentblock -247138 +216571 @asp_close_tag -1542 - - -@asp_code -244 +22 @asp_comment -14 - - -@asp_data_binding -44 +5 @asp_directive -243 +3 @asp_open_tag -1920 +28 @asp_quoted_string -4545 +31 @asp_text -3522 +58 @asp_xml_directive -16 +1 + + +@asp_code +0 + + +@asp_data_binding +0 @cil_arglist @@ -1013,7 +1013,7 @@ @cil_stsfld -50533 +50535 @cil_stobj @@ -1269,15 +1269,15 @@ @cil_ldarg_0 -1761435 +1761439 @cil_ldarg_1 -666051 +666052 @cil_ldarg_2 -260505 +260506 @cil_ldarg_3 @@ -1285,7 +1285,7 @@ @cil_ldloc_0 -552028 +552030 @cil_ldloc_1 @@ -1301,11 +1301,11 @@ @cil_stloc_0 -366179 +366180 @cil_stloc_1 -199127 +199128 @cil_stloc_2 @@ -1333,7 +1333,7 @@ @cil_ldloca_s -306809 +306810 @cil_stloc_s @@ -1413,11 +1413,11 @@ @cil_call -1478944 +1478950 @cil_ret -867422 +867426 @cil_br_s @@ -1425,11 +1425,11 @@ @cil_brfalse_s -397704 +397705 @cil_brtrue_s -202600 +202602 @cil_beq_s @@ -1693,7 +1693,7 @@ @cil_callvirt -1047788 +1047791 @cil_ldobj @@ -1701,11 +1701,11 @@ @cil_ldstr -267378 +267379 @cil_newobj -283677 +283678 @cil_castclass @@ -1741,7 +1741,7 @@ @cil_ldsfld -153187 +153188 @cil_ldsflda @@ -1801,7 +1801,7 @@ @cil_valueorreftype -249378 +249380 @cil_typeparameter @@ -1817,23 +1817,23 @@ @cil_method -1164170 +1164177 @cil_method_implementation -1351436 +1351440 @cil_field -459117 +459120 @cil_parameter -2241273 +2241281 @cil_property -232995 +232996 @cil_event @@ -1841,7 +1841,7 @@ @cil_local_variable -989635 +989637 @cil_catch_handler @@ -1941,7 +1941,7 @@ arg -1058 +1056 @@ -2046,13 +2046,13 @@ 1 -413 -414 +416 +417 1 -637 -638 +635 +636 1 @@ -2069,12 +2069,12 @@ 1 2 -1045 +1041 2 1058 -13 +15 @@ -2090,12 +2090,12 @@ 1 2 -1054 +1049 2 3 -4 +7 @@ -2105,7 +2105,7 @@ compilation_compiling_files -21036 +21452 id @@ -2117,7 +2117,7 @@ file -18151 +18152 @@ -2135,33 +2135,33 @@ 2 -3 -11 - - -3 4 -224 +18 4 -6 -82 +5 +225 -6 -18 +5 +8 +84 + + +8 +23 80 -18 -64 -80 +23 +78 +81 -64 +78 1094 -79 +68 @@ -2181,33 +2181,33 @@ 2 -3 -11 - - -3 4 -224 +18 4 -6 -82 +5 +225 -6 -18 +5 +8 +84 + + +8 +23 80 -18 -64 -80 +23 +78 +81 -64 +78 1094 -79 +68 @@ -2233,12 +2233,12 @@ 4 5 -213 +212 5 6 -100 +101 6 @@ -2253,7 +2253,7 @@ 9 10 -151 +150 10 @@ -2266,14 +2266,14 @@ 83 -56 -160 +55 +159 82 -165 +160 1058 -17 +18 @@ -2299,12 +2299,12 @@ 4 5 -213 +212 5 6 -100 +101 6 @@ -2319,7 +2319,7 @@ 9 10 -151 +150 10 @@ -2328,17 +2328,17 @@ 20 -54 -82 +55 +83 -54 -152 +55 +155 82 156 -1042 +1047 18 @@ -2364,8 +2364,8 @@ 4 -129 -197 +417 +198 @@ -2381,17 +2381,17 @@ 1 2 -16536 +16531 2 4 -1447 +1449 4 77 -168 +172 @@ -2669,58 +2669,58 @@ 6 -28 +27 21 -28 -49 +27 +46 21 -49 -79 +48 +78 21 -79 -101 +78 +105 21 -101 -141 +110 +146 21 -146 -168 +152 +171 +21 + + +171 +180 23 -168 -180 -21 - - -180 -191 +182 +197 24 -191 -196 -22 +197 +202 +19 -196 -203 +202 +208 23 -203 -226 -15 +208 +231 +18 @@ -2807,57 +2807,57 @@ 1 2 -332 +334 2 3 -173 +156 3 4 -164 +189 4 -5 -130 +6 +135 -5 -12 -129 +6 +13 +128 -12 -17 -144 +13 +18 +139 -17 +18 21 -145 +118 21 26 -134 +143 26 35 -141 +145 35 96 -132 +129 96 -116 -77 +123 +85 @@ -2883,7 +2883,7 @@ seconds -3864 +3821 @@ -2929,12 +2929,12 @@ 6 7 -6 +36 7 8 -1051 +1021 @@ -2980,8 +2980,8 @@ 12 -3864 -3865 +3821 +3822 1 @@ -3028,34 +3028,34 @@ 12 -312 -313 +322 +323 +2 + + +325 +326 1 -328 -329 +336 +337 1 -369 -370 -1 - - -416 -417 -1 - - -1005 -1006 +1017 +1018 1 1056 1057 -2 +1 + + +1057 +1058 +1 @@ -3071,17 +3071,17 @@ 1 2 -3350 +3373 2 -6 -321 +8 +290 -6 -71 -193 +8 +94 +158 @@ -3097,7 +3097,7 @@ 1 2 -3864 +3821 @@ -3113,12 +3113,12 @@ 1 2 -3460 +3445 2 4 -336 +308 4 @@ -3133,15 +3133,15 @@ diagnostic_for -12070 +108998 diagnostic -12070 +108998 compilation -328 +554 file_number @@ -3149,7 +3149,7 @@ file_number_diagnostic_number -1099 +1332 @@ -3163,7 +3163,7 @@ 1 2 -12070 +108998 @@ -3179,7 +3179,7 @@ 1 2 -12070 +108998 @@ -3195,7 +3195,7 @@ 1 2 -12070 +108998 @@ -3209,64 +3209,59 @@ 12 -1 -2 -2 - - 2 -3 -53 - - -3 -4 -27 - - -4 -5 -41 - - -5 7 -29 +45 7 -9 -25 +21 +43 -9 -13 -28 +21 +183 +42 -13 -19 -26 +192 +233 +3 -19 -28 -26 +233 +234 +226 -28 -57 -25 +234 +235 +2 -57 -154 -25 +235 +236 +51 -160 -1100 -21 +236 +238 +42 + + +238 +246 +42 + + +246 +299 +42 + + +305 +1333 +16 @@ -3282,7 +3277,7 @@ 1 2 -328 +554 @@ -3296,64 +3291,59 @@ 12 -1 -2 -2 - - 2 -3 -53 - - -3 -4 -27 - - -4 -5 -41 - - -5 7 -29 +45 7 -9 -25 +21 +43 -9 -13 -28 +21 +183 +42 -13 -19 -26 +192 +233 +3 -19 -28 -26 +233 +234 +226 -28 -57 -25 +234 +235 +2 -57 -154 -25 +235 +236 +51 -160 -1100 -21 +236 +238 +42 + + +238 +246 +42 + + +246 +299 +42 + + +305 +1333 +16 @@ -3367,8 +3357,8 @@ 12 -12070 -12071 +108998 +108999 1 @@ -3383,8 +3373,8 @@ 12 -328 -329 +554 +555 1 @@ -3399,8 +3389,8 @@ 12 -1099 -1100 +1332 +1333 1 @@ -3417,42 +3407,42 @@ 1 2 -71 +304 2 3 -488 +484 3 -4 -147 +9 +118 -4 -5 -82 +9 +15 +104 -5 -12 -88 +15 +422 +90 -12 -24 -89 +422 +434 +109 -25 -52 -84 +434 +464 +100 -52 -329 -50 +465 +555 +23 @@ -3468,42 +3458,42 @@ 1 2 -71 +304 2 3 -488 +484 3 -4 -147 +9 +118 -4 -5 -82 +9 +15 +104 -5 -12 -88 +15 +422 +90 -12 -24 -89 +422 +434 +109 -25 -52 -84 +434 +464 +100 -52 -329 -50 +465 +555 +23 @@ -3519,7 +3509,7 @@ 1 2 -1099 +1332 @@ -3529,11 +3519,11 @@ diagnostics -12070 +108998 id -12070 +108998 severity @@ -3541,19 +3531,19 @@ error_tag -6 +18 error_message -6 +7 full_error_message -27 +59 location -10395 +10620 @@ -3567,7 +3557,7 @@ 1 2 -12070 +108998 @@ -3583,7 +3573,7 @@ 1 2 -12070 +108998 @@ -3599,7 +3589,7 @@ 1 2 -12070 +108998 @@ -3615,7 +3605,7 @@ 1 2 -12070 +108998 @@ -3631,7 +3621,7 @@ 1 2 -12070 +108998 @@ -3645,13 +3635,13 @@ 12 -242 -243 +11828 +11829 1 -11828 -11829 +97170 +97171 1 @@ -3671,8 +3661,8 @@ 1 -4 -5 +16 +17 1 @@ -3692,8 +3682,8 @@ 1 -4 -5 +5 +6 1 @@ -3713,8 +3703,8 @@ 1 -25 -26 +57 +58 1 @@ -3729,8 +3719,8 @@ 12 -236 -237 +461 +462 1 @@ -3775,10 +3765,45 @@ 1 +416 +417 +4 + + +832 +833 +2 + + +1248 +1249 +2 + + +1664 +1665 +1 + + +2080 +2081 +1 + + +3328 +3329 +1 + + 11824 11825 1 + +84032 +84033 +1 + @@ -3793,7 +3818,7 @@ 1 2 -6 +18 @@ -3809,7 +3834,7 @@ 1 2 -6 +18 @@ -3825,12 +3850,12 @@ 1 2 -2 +11 2 3 -1 +2 5 @@ -3838,9 +3863,14 @@ 2 +8 +9 +1 + + 13 14 -1 +2 @@ -3854,16 +3884,41 @@ 12 +1 +2 +4 + + 2 3 +4 + + +3 +4 2 +4 +5 +1 + + +5 +6 +1 + + 6 7 1 +8 +9 +1 + + 27 28 1 @@ -3874,6 +3929,11 @@ 1 +202 +203 +1 + + 10157 10158 1 @@ -3919,6 +3979,11 @@ 11825 1 + +96928 +96929 +1 + @@ -3933,7 +3998,7 @@ 1 2 -6 +7 @@ -3951,6 +4016,11 @@ 2 6 + +12 +13 +1 + @@ -3982,6 +4052,11 @@ 14 1 + +32 +33 +1 + @@ -4014,6 +4089,11 @@ 1 +225 +226 +1 + + 10157 10158 1 @@ -4036,58 +4116,48 @@ 2 -3 -1 - - -3 -4 -2 - - -4 6 -2 +5 6 -8 -2 - - -9 -11 -2 - - -11 12 -1 +5 14 -15 -2 - - -16 17 -3 +5 17 -18 -2 +28 +5 -21 -23 -2 +416 +417 +18 -27 +832 +833 +4 + + +1248 +1249 +5 + + +1664 11825 -2 +5 + + +65312 +65313 +1 @@ -4103,7 +4173,7 @@ 1 2 -27 +59 @@ -4119,7 +4189,7 @@ 1 2 -27 +59 @@ -4135,7 +4205,7 @@ 1 2 -27 +59 @@ -4151,57 +4221,42 @@ 1 2 -6 +24 2 3 -2 +6 3 4 -2 +7 -5 +4 7 -2 +5 7 -10 -2 - - -10 12 -2 +4 14 -15 -2 - - -16 17 -3 +5 17 -18 -2 - - -21 23 -2 +5 27 10158 -2 +3 @@ -4226,8 +4281,8 @@ 3 -12 -244 +833 +469 @@ -4243,7 +4298,7 @@ 1 2 -10395 +10620 @@ -4259,7 +4314,12 @@ 1 2 -10395 +10612 + + +2 +3 +8 @@ -4275,7 +4335,7 @@ 1 2 -10395 +10620 @@ -4291,12 +4351,12 @@ 1 2 -10389 +10606 2 3 -6 +14 @@ -4306,11 +4366,11 @@ extractor_messages -57 +55 id -57 +55 severity @@ -4322,19 +4382,19 @@ text -4 +3 entity -23 +22 location -34 +32 stack_trace -3 +4 @@ -4348,7 +4408,7 @@ 1 2 -57 +55 @@ -4364,7 +4424,7 @@ 1 2 -57 +55 @@ -4380,7 +4440,7 @@ 1 2 -57 +55 @@ -4396,7 +4456,7 @@ 1 2 -57 +55 @@ -4412,7 +4472,7 @@ 1 2 -57 +55 @@ -4428,7 +4488,7 @@ 1 2 -57 +55 @@ -4442,8 +4502,8 @@ 12 -6 -7 +4 +5 1 @@ -4486,12 +4546,7 @@ 1 2 -2 - - -2 -3 -1 +3 @@ -4510,8 +4565,8 @@ 1 -5 -6 +4 +5 1 @@ -4536,8 +4591,8 @@ 1 -6 -7 +4 +5 1 @@ -4562,8 +4617,8 @@ 2 -2 -3 +3 +4 1 @@ -4578,8 +4633,8 @@ 12 -57 -58 +55 +56 1 @@ -4610,8 +4665,8 @@ 12 -4 -5 +3 +4 1 @@ -4626,8 +4681,8 @@ 12 -23 -24 +22 +23 1 @@ -4642,8 +4697,8 @@ 12 -34 -35 +32 +33 1 @@ -4658,8 +4713,8 @@ 12 -3 -4 +4 +5 1 @@ -4674,11 +4729,6 @@ 12 -2 -3 -1 - - 4 5 1 @@ -4707,7 +4757,7 @@ 1 2 -4 +3 @@ -4723,7 +4773,7 @@ 1 2 -4 +3 @@ -4739,7 +4789,7 @@ 1 2 -2 +1 4 @@ -4768,11 +4818,6 @@ 1 -2 -3 -1 - - 4 5 1 @@ -4796,7 +4841,12 @@ 1 2 -4 +2 + + +3 +4 +1 @@ -4817,7 +4867,7 @@ 2 3 -6 +5 3 @@ -4848,7 +4898,7 @@ 1 2 -23 +22 @@ -4864,7 +4914,7 @@ 1 2 -23 +22 @@ -4880,7 +4930,7 @@ 1 2 -23 +22 @@ -4901,7 +4951,7 @@ 2 3 -5 +4 3 @@ -4922,7 +4972,7 @@ 1 2 -23 +22 @@ -4938,7 +4988,7 @@ 1 2 -24 +22 2 @@ -4964,7 +5014,7 @@ 1 2 -34 +32 @@ -4980,7 +5030,7 @@ 1 2 -34 +32 @@ -4996,7 +5046,7 @@ 1 2 -34 +32 @@ -5012,7 +5062,7 @@ 1 2 -34 +32 @@ -5028,7 +5078,7 @@ 1 2 -34 +32 @@ -5042,13 +5092,13 @@ 12 -2 -3 -1 +1 +2 +2 -4 -5 +2 +3 1 @@ -5070,7 +5120,7 @@ 1 2 -2 +3 2 @@ -5091,7 +5141,7 @@ 1 2 -3 +4 @@ -5107,7 +5157,7 @@ 1 2 -2 +3 2 @@ -5128,11 +5178,11 @@ 1 2 -1 +2 -4 -5 +2 +3 1 @@ -5152,13 +5202,13 @@ 12 -2 -3 -1 +1 +2 +2 -4 -5 +2 +3 1 @@ -5182,11 +5232,11 @@ cpu_seconds -509 +467 elapsed_seconds -1056 +1054 @@ -5232,27 +5282,27 @@ 1 2 -299 +281 2 3 -93 +70 3 4 -41 +43 4 -6 +8 41 -6 -14 -35 +8 +13 +32 @@ -5268,27 +5318,27 @@ 1 2 -299 +281 2 3 -93 +70 3 4 -41 +43 4 -6 +8 41 -6 -14 -35 +8 +13 +32 @@ -5304,12 +5354,12 @@ 1 2 -1055 +1051 2 3 -1 +3 @@ -5325,12 +5375,12 @@ 1 2 -1055 +1051 2 3 -1 +3 @@ -5754,11 +5804,11 @@ externalData -18 +20 id -9 +10 path @@ -5770,7 +5820,7 @@ value -18 +20 @@ -5784,7 +5834,7 @@ 1 2 -9 +10 @@ -5800,7 +5850,7 @@ 2 3 -9 +10 @@ -5816,7 +5866,7 @@ 2 3 -9 +10 @@ -5830,8 +5880,8 @@ 12 -9 -10 +10 +11 1 @@ -5862,8 +5912,8 @@ 12 -18 -19 +20 +21 1 @@ -5878,8 +5928,8 @@ 12 -9 -10 +10 +11 2 @@ -5910,8 +5960,8 @@ 12 -9 -10 +10 +11 2 @@ -5928,7 +5978,7 @@ 1 2 -18 +20 @@ -5944,7 +5994,7 @@ 1 2 -18 +20 @@ -5960,7 +6010,7 @@ 1 2 -18 +20 @@ -5992,19 +6042,19 @@ duplicateCode -20134 +18936 id -20134 +18936 relativePath -2570 +2265 equivClass -7291 +6810 @@ -6018,7 +6068,7 @@ 1 2 -20134 +18936 @@ -6034,7 +6084,7 @@ 1 2 -20134 +18936 @@ -6050,37 +6100,37 @@ 1 2 -1164 +1060 2 3 -511 +418 3 4 -177 +161 4 6 -237 +198 6 11 -217 +179 11 -41 -194 +36 +170 -41 +36 1047 -70 +79 @@ -6096,32 +6146,32 @@ 1 2 -1401 +1248 2 3 -377 +310 3 4 -217 +188 4 6 -225 +195 6 12 -206 +186 12 405 -144 +138 @@ -6142,27 +6192,27 @@ 2 3 -4859 +4495 3 4 -1105 +1051 4 5 -632 +595 5 9 -574 +551 9 11 -116 +113 @@ -6178,22 +6228,22 @@ 1 2 -4521 +4222 2 3 -2071 +1918 3 -6 -603 +5 +520 -6 +5 11 -96 +150 @@ -6203,19 +6253,19 @@ similarCode -149289 +141055 id -149289 +141055 relativePath -5832 +4793 equivClass -43184 +40443 @@ -6229,7 +6279,7 @@ 1 2 -149289 +141055 @@ -6245,7 +6295,7 @@ 1 2 -149289 +141055 @@ -6261,57 +6311,52 @@ 1 2 -1266 +989 2 3 -999 +824 3 4 -428 +334 4 5 -427 +338 5 -6 -317 +7 +425 -6 -8 -460 +7 +10 +422 -8 -12 -464 +10 +16 +391 -12 -19 -445 +16 +28 +367 -19 -40 -450 +28 +63 +360 -40 -158 -438 - - -158 +63 10255 -138 +343 @@ -6327,47 +6372,47 @@ 1 2 -1794 +1419 2 3 -875 +717 3 4 -565 +447 4 5 -436 +353 5 7 -540 +426 7 10 -473 +394 10 17 -467 +400 17 -45 -443 +39 +363 -45 +39 3151 -239 +274 @@ -6383,37 +6428,37 @@ 1 2 -33 +22 2 3 -20582 +18979 3 4 -8089 +7590 4 5 -4987 +4736 5 6 -2926 +2796 6 8 -3616 +3485 8 11 -2951 +2835 @@ -6429,22 +6474,22 @@ 1 2 -29024 +27489 2 3 -9400 +8570 3 5 -3481 +3204 5 11 -1279 +1180 @@ -6454,11 +6499,11 @@ tokens -20596077 +19390833 id -169423 +159991 offset @@ -6466,19 +6511,19 @@ beginLine -66951 +66941 beginColumn -1275 +1274 endLine -65748 +65737 endColumn -1282 +1280 @@ -6492,72 +6537,67 @@ 100 101 -17349 +16507 101 102 -14013 +13400 102 103 -11330 +10706 103 104 -8613 +8227 104 -105 -8343 +106 +14785 -105 -107 -13200 +106 +108 +10905 -107 -109 -11207 +108 +111 +14230 -109 -112 -13800 +111 +115 +13953 -112 -116 -13475 +115 +121 +13841 -116 -122 -13227 +121 +130 +12523 -122 -132 -13847 +130 +145 +12013 -132 -150 -13094 +145 +186 +12027 -150 -200 -12774 - - -200 +186 24726 -5151 +6874 @@ -6573,72 +6613,72 @@ 3 8 -15571 +14714 8 10 -13241 +12264 10 12 -14984 +14261 12 13 -8221 +7803 13 14 -9518 +8972 14 15 -10126 +9603 15 16 -8365 +7805 16 18 -15128 +14115 18 20 -14382 +13499 20 22 -13269 +12619 22 24 -10793 +10282 24 27 -14004 +13441 27 33 -13393 +12806 33 4516 -8428 +7807 @@ -6654,67 +6694,67 @@ 3 30 -13731 +12551 30 35 -12960 +12550 35 -40 -15615 +39 +11810 -40 -44 -13732 +39 +43 +12757 -44 -48 -15209 +43 +47 +14181 -48 +47 51 -11686 +14812 51 54 -12470 +11812 54 57 -12211 +11572 57 61 -15141 +14300 61 65 -13198 +12505 65 71 -14162 +13314 71 83 -13148 +12181 83 356 -6160 +5646 @@ -6730,77 +6770,72 @@ 3 8 -15606 +14749 8 10 -13284 +12307 10 11 -7617 +7233 11 12 -8071 +7732 12 13 -8967 +8549 13 14 -10039 +9485 14 15 -10060 +9545 15 -16 -8163 +17 +14705 -16 -18 -15038 +17 +19 +13999 -18 -20 -15158 +19 +21 +13941 -20 -22 -13995 +21 +23 +12055 -22 -24 -11189 +23 +26 +14297 -24 -27 -13173 +26 +31 +12102 -27 -35 -13285 - - -35 +31 4516 -5778 +9292 @@ -6816,67 +6851,67 @@ 3 32 -13965 +12833 32 38 -14984 +14379 38 43 -15403 +14719 43 47 -13368 +12728 47 51 -14461 +13764 51 55 -15157 +14329 55 58 -11849 +11193 58 62 -15331 +14558 62 66 -13741 +13018 66 71 -14501 +13691 71 78 -13414 +12570 78 -120 -12726 +135 +12009 -120 +135 363 -523 +200 @@ -6906,13 +6941,13 @@ 9 -30 -1856 +28 +1913 -33 -169424 -1429 +29 +159992 +1372 @@ -6942,13 +6977,13 @@ 7 -24 -1856 +22 +1926 -24 -27429 -1429 +22 +27426 +1359 @@ -6978,13 +7013,13 @@ 4 -15 -1894 +13 +1987 -15 -489 -1380 +13 +488 +1287 @@ -7014,13 +7049,13 @@ 7 -24 -1856 +22 +1926 -24 -27395 -1429 +22 +27392 +1359 @@ -7050,13 +7085,13 @@ 4 -15 -1897 +12 +1856 -15 +12 494 -1375 +1416 @@ -7072,52 +7107,52 @@ 1 2 -3940 +3932 2 3 -4614 +4619 3 4 -5107 +5103 4 5 -5049 +5047 5 6 -4513 +4515 6 7 -4086 +4084 7 8 -3748 +3752 8 9 -3319 +3318 9 11 -5799 +5798 11 14 -5802 +5800 14 @@ -7127,7 +7162,7 @@ 19 32 -5188 +5189 32 @@ -7136,13 +7171,13 @@ 80 -1828 +1631 5022 -1830 -5217 -232 +1632 +4188 +230 @@ -7158,22 +7193,22 @@ 1 4 -4906 +4909 4 7 -5029 +5022 7 12 -5528 +5527 12 18 -5048 +5044 18 @@ -7183,22 +7218,22 @@ 26 35 -5342 +5343 35 45 -5030 +5029 45 57 -5139 +5140 57 72 -5082 +5080 72 @@ -7213,17 +7248,17 @@ 114 153 -5067 +5079 153 -499 -5022 +472 +5021 -499 -605 -120 +472 +570 +109 @@ -7239,62 +7274,62 @@ 1 2 -9046 +9053 2 4 -5786 +5791 4 6 -4828 +4819 6 9 -6118 +6109 9 12 -5031 +5030 12 16 -5582 +5585 16 20 -5337 +5338 20 26 -5654 +5652 26 35 -5318 +5315 35 54 -5192 +5190 54 99 -5040 +5046 99 -340 -4019 +339 +4013 @@ -7310,12 +7345,12 @@ 1 2 -56336 +56327 2 3 -5720 +5719 3 @@ -7336,62 +7371,62 @@ 1 2 -9015 +9022 2 4 -5814 +5819 4 6 -4705 +4696 6 9 -6095 +6085 9 12 -5032 +5031 12 16 -5541 +5544 16 20 -5289 +5291 20 26 -5602 +5600 26 35 -5213 +5211 35 -53 -5023 +54 +5217 -53 -94 -5029 +54 +97 +5056 -94 -342 -4593 +97 +341 +4369 @@ -7412,7 +7447,7 @@ 2 3 -77 +76 3 @@ -7421,54 +7456,59 @@ 5 -9 -118 +8 +90 -9 -12 -93 +8 +11 +91 -12 -16 -99 - - -16 -22 +11 +15 107 -22 -49 -97 +15 +20 +100 -49 -154 +20 +34 96 -155 -460 +34 +116 96 -460 -2842 +116 +318 96 -2886 -34163 +319 +1276 96 -34851 -133446 +1313 +15993 96 + +16054 +81805 +96 + + +81831 +126123 +30 + @@ -7483,7 +7523,7 @@ 1 2 -102 +101 2 @@ -7522,28 +7562,28 @@ 46 -99 +97 +96 + + +97 +150 +97 + + +150 +265 +96 + + +265 +676 98 -99 -152 -96 - - -153 -273 -96 - - -274 -708 -96 - - -708 -3646 -77 +676 +3602 +76 @@ -7564,7 +7604,7 @@ 2 3 -85 +84 3 @@ -7578,43 +7618,48 @@ 5 -7 -118 +6 +67 -7 -10 +6 +8 +91 + + +8 +15 +98 + + +15 +48 97 -10 -33 -97 - - -33 -80 +48 +106 96 -80 -216 +106 +447 96 -216 -1785 +458 +4412 96 -1861 -10566 +4439 +15076 96 -10669 -36636 -70 +15140 +36635 +29 @@ -7635,7 +7680,7 @@ 2 3 -85 +84 3 @@ -7649,43 +7694,48 @@ 5 -7 -118 +6 +67 -7 -10 +6 +8 +91 + + +8 +15 +98 + + +15 +48 97 -10 -33 -97 - - -33 -80 +48 +106 96 -80 -216 +106 +447 96 -216 -1785 +458 +4412 96 -1861 -10566 +4439 +15076 96 -10670 -36635 -70 +15138 +36634 +29 @@ -7701,7 +7751,7 @@ 1 2 -313 +312 2 @@ -7721,32 +7771,32 @@ 5 9 -113 +114 9 15 -102 +103 15 22 -106 +110 22 -35 -98 +36 +96 -35 +37 75 -98 +99 -75 -176 -54 +76 +175 +49 @@ -7762,37 +7812,37 @@ 1 2 -3847 +3838 2 3 -4499 +4504 3 4 -5022 +5018 4 5 -4979 +4977 5 6 -4459 +4461 6 7 -4054 +4052 7 8 -3680 +3684 8 @@ -7802,12 +7852,12 @@ 9 11 -5635 +5632 11 14 -5618 +5617 14 @@ -7817,7 +7867,7 @@ 19 32 -5112 +5113 32 @@ -7826,13 +7876,13 @@ 78 -1307 +1173 4932 -1308 -5199 -348 +1173 +4170 +346 @@ -7848,22 +7898,22 @@ 1 5 -5546 +5550 5 9 -5457 +5452 9 15 -5689 +5683 15 22 -5386 +5385 22 @@ -7873,22 +7923,22 @@ 30 39 -5000 +5001 39 50 -5190 +5186 50 63 -5112 +5115 63 79 -4943 +4940 79 @@ -7903,12 +7953,12 @@ 125 173 -4964 +4975 173 -605 -3456 +570 +3445 @@ -7924,7 +7974,7 @@ 1 2 -53887 +53876 2 @@ -7950,27 +8000,27 @@ 1 2 -6483 +6489 2 3 -3747 +3749 3 5 -5343 +5347 5 7 -5671 +5657 7 10 -4871 +4866 10 @@ -7980,37 +8030,37 @@ 14 17 -5140 +5144 17 22 -5191 +5187 22 28 -5324 +5323 28 39 -5191 +5189 39 62 -5013 +5012 62 118 -4937 +4958 118 -340 -2833 +339 +2812 @@ -8026,67 +8076,67 @@ 1 2 -6454 +6460 2 3 -3708 +3710 3 5 -5420 +5424 5 7 -5487 +5473 7 10 -4895 +4889 10 14 -5972 +5973 14 17 -5077 +5081 17 22 -5177 +5173 22 28 -5282 +5281 28 39 -5107 +5106 39 62 -5051 +5049 62 115 -4947 +4960 115 -342 -3171 +340 +3158 @@ -8107,7 +8157,7 @@ 2 3 -73 +71 3 @@ -8137,37 +8187,37 @@ 21 36 -100 +98 36 -132 +124 97 -133 -348 -97 +125 +331 +96 -350 -1580 -97 +333 +1416 +96 -1614 -21369 -97 +1469 +18166 +96 -21416 -97489 -97 +18253 +87352 +96 -97674 -119719 -23 +87890 +113121 +29 @@ -8183,7 +8233,7 @@ 1 2 -102 +100 2 @@ -8222,33 +8272,33 @@ 32 -81 +80 +96 + + +80 +132 98 -81 -133 -97 +132 +224 +98 -133 -232 -97 +226 +480 +96 -232 -491 -97 +480 +1699 +96 -491 -1764 -97 - - -1819 -3367 -13 +1720 +3280 +15 @@ -8269,7 +8319,7 @@ 2 3 -99 +97 3 @@ -8293,33 +8343,33 @@ 11 -39 -98 +38 +96 -39 -87 +38 +79 +96 + + +79 +225 97 -88 -251 -97 +229 +2123 +96 -256 -2289 -97 +2143 +11420 +96 -2295 -11901 -97 - - -12187 -26471 -62 +11472 +26469 +67 @@ -8335,7 +8385,7 @@ 1 2 -309 +307 2 @@ -8359,28 +8409,28 @@ 9 -16 -110 +15 +99 -16 -25 -101 +15 +24 +107 -25 -38 +24 +37 97 -38 -66 -103 +37 +63 +96 -66 +63 110 -67 +79 @@ -8401,7 +8451,7 @@ 2 3 -99 +97 3 @@ -8425,33 +8475,33 @@ 11 -39 -98 +38 +96 -39 -87 +38 +79 +96 + + +79 +225 97 -88 -251 -97 +229 +2123 +96 -256 -2289 -97 +2143 +11428 +96 -2295 -11901 -97 - - -12187 -26471 -62 +11469 +26469 +67 @@ -8461,15 +8511,15 @@ locations_default -11787435 +10628591 id -11787435 +10628591 file -22092 +18229 beginLine @@ -8485,7 +8535,7 @@ endColumn -1237 +1234 @@ -8499,7 +8549,7 @@ 1 2 -11787435 +10628591 @@ -8515,7 +8565,7 @@ 1 2 -11787435 +10628591 @@ -8531,7 +8581,7 @@ 1 2 -11787435 +10628591 @@ -8547,7 +8597,7 @@ 1 2 -11787435 +10628591 @@ -8563,7 +8613,7 @@ 1 2 -11787435 +10628591 @@ -8579,72 +8629,72 @@ 1 16 -1739 +1382 16 27 -1704 +1438 27 -35 -1622 +34 +1384 -35 -48 -1689 +34 +47 +1422 -48 +47 70 -1725 +1406 70 -98 -1659 +103 +1387 -98 -141 -1671 +103 +151 +1371 -141 -199 -1668 +151 +215 +1374 -199 -286 -1657 +215 +310 +1375 -286 -425 -1666 +310 +465 +1372 -425 -680 -1657 +465 +754 +1370 -680 -1245 -1658 +754 +1405 +1368 -1245 -4832 -1657 +1405 +6323 +1368 -4835 +6331 167166 -320 +212 @@ -8660,67 +8710,67 @@ 1 9 -1729 +1356 9 14 -1933 +1624 14 19 -1627 +1345 19 -22 -1911 +21 +1382 -22 -29 -1670 +21 +28 +1454 -29 -39 -1774 +28 +38 +1411 -39 +38 52 -1707 +1450 52 -71 -1664 +72 +1390 -71 -99 -1676 +72 +101 +1371 -99 -145 -1659 +101 +148 +1369 -145 -229 -1660 +148 +233 +1376 -229 -454 -1657 +233 +449 +1368 -454 +449 44061 -1425 +1333 @@ -8736,67 +8786,67 @@ 1 7 -1536 +1283 7 -11 -1891 +10 +1423 -11 -15 -1732 +10 +14 +1422 -15 -21 -1867 +14 +20 +1544 -21 +20 27 -1695 +1519 27 34 -1796 +1370 34 42 -1791 +1415 42 51 -1809 +1467 51 62 -1803 +1485 62 -75 -1792 +74 +1378 -75 -91 -1700 +74 +89 +1410 -91 -119 -1673 +89 +113 +1383 -119 +113 781 -1007 +1130 @@ -8812,67 +8862,67 @@ 1 9 -1728 +1355 9 14 -1924 +1629 14 19 -1631 +1340 19 -22 -1915 +21 +1388 -22 -30 -1877 +21 +28 +1450 -30 -40 -1726 +28 +38 +1396 -40 -53 -1657 +38 +52 +1466 -53 -73 -1687 +52 +72 +1390 -73 -102 -1684 +72 +101 +1370 -102 -150 -1678 +101 +148 +1374 -150 -242 -1659 +148 +234 +1377 -242 -504 -1659 +234 +453 +1369 -504 +453 46103 -1267 +1325 @@ -8888,67 +8938,67 @@ 1 13 -1769 +1388 13 20 -1667 +1394 20 25 -1751 +1524 25 31 -1697 +1459 31 -40 -1705 +41 +1454 -40 -50 -1773 +41 +52 +1475 -50 -61 -1688 +52 +64 +1432 -61 -73 -1741 +64 +76 +1407 -73 -86 -1709 +76 +90 +1459 -86 -100 -1727 +90 +104 +1429 -100 -117 -1754 +104 +121 +1373 -117 -142 -1670 +121 +149 +1396 -142 +149 883 -1441 +1039 @@ -9014,17 +9064,17 @@ 28 65 -5497 +5498 65 -290 +289 5443 -290 -39954 -3707 +289 +33315 +3706 @@ -9069,7 +9119,7 @@ 46 -21923 +18137 4695 @@ -9121,7 +9171,7 @@ 9 12 -6072 +6073 12 @@ -9131,17 +9181,17 @@ 18 39 -5563 +5564 39 -110 -5455 +109 +5477 -110 -373 -1927 +109 +370 +1903 @@ -9176,13 +9226,13 @@ 9 -46 -5486 +45 +5468 -46 +45 367 -739 +757 @@ -9253,17 +9303,17 @@ 29 64 -5542 +5543 64 -149 -5479 +147 +5447 -149 -413 -1769 +147 +411 +1800 @@ -9299,42 +9349,37 @@ 5 8 -107 +106 8 17 -90 +95 17 -55 +56 88 -55 -175 +56 +168 88 -176 -1176 +172 +1186 88 -1256 -16999 +1190 +16937 88 -17523 -646623 -88 - - -1430464 -1573394 -2 +18267 +1428349 +86 @@ -9350,52 +9395,52 @@ 1 2 -369 +368 2 3 -129 +131 3 4 -75 +74 4 6 -88 +90 6 13 -88 +89 13 -29 +28 91 -29 -106 +28 +97 88 -110 -1029 +97 +958 88 -1033 -7700 +962 +6873 88 -7907 -21381 -57 +6919 +17795 +54 @@ -9411,12 +9456,12 @@ 1 2 -345 +344 2 3 -89 +91 3 @@ -9431,37 +9476,37 @@ 6 11 -96 +94 11 -29 +28 90 -30 -94 -91 +28 +86 +90 -94 -413 +86 +357 88 -415 -2920 +370 +2712 88 -2932 -9215 +2841 +9048 88 -9290 -50368 -28 +9055 +50367 +30 @@ -9477,17 +9522,17 @@ 1 2 -345 +344 2 3 -89 +90 3 4 -58 +59 4 @@ -9497,37 +9542,37 @@ 6 11 -96 +94 11 -29 +28 90 -30 -94 -91 +28 +86 +90 -94 -413 +86 +357 88 -415 -2918 +371 +2711 88 -2936 -9228 +2842 +9053 88 -9288 -53430 -28 +9106 +53429 +30 @@ -9543,7 +9588,7 @@ 1 2 -352 +351 2 @@ -9553,7 +9598,7 @@ 3 4 -76 +77 4 @@ -9563,37 +9608,32 @@ 6 11 -94 +95 11 -24 -89 +23 +91 -24 -41 -89 +23 +39 +92 -41 +39 68 -89 +88 68 -162 +157 88 -162 -383 -88 - - -429 -454 -4 +157 +450 +87 @@ -9654,17 +9694,17 @@ 29 73 -5604 +5605 73 -410 +407 5557 -410 -38993 -3137 +407 +32723 +3136 @@ -9709,7 +9749,7 @@ 46 -21919 +18133 4812 @@ -9741,17 +9781,17 @@ 4 8 -6068 +6069 8 35 -5571 +5605 35 -82 -1341 +80 +1306 @@ -9802,7 +9842,7 @@ 9 12 -6159 +6160 12 @@ -9812,17 +9852,17 @@ 18 39 -5609 +5610 39 -113 -5569 +112 +5598 -113 -373 -1810 +112 +370 +1779 @@ -9883,17 +9923,17 @@ 30 68 -5606 +5607 68 -166 -5572 +165 +5575 -166 +165 413 -1180 +1176 @@ -9909,57 +9949,57 @@ 1 2 -305 +307 2 3 -103 +102 3 4 -82 +78 4 6 -100 +102 6 10 -98 +100 10 -32 -94 - - -32 -90 +33 93 -90 -312 +33 +85 93 -318 -3282 +85 +287 93 -3320 -47350 +290 +3095 93 -48707 -290233 -83 +3150 +47095 +93 + + +47807 +264670 +80 @@ -9975,52 +10015,52 @@ 1 2 -385 +383 2 3 -150 +148 3 4 -79 +78 4 7 -99 +105 7 23 -95 +101 23 -47 -94 - - -47 -204 +46 93 -212 -1974 +46 +232 93 -2010 -11406 +233 +2143 93 -11549 -16182 -56 +2153 +10467 +93 + + +10478 +13226 +47 @@ -10036,7 +10076,7 @@ 1 2 -344 +345 2 @@ -10046,7 +10086,7 @@ 3 4 -73 +72 4 @@ -10056,7 +10096,7 @@ 6 11 -102 +101 11 @@ -10065,28 +10105,28 @@ 37 -110 -94 - - -110 -456 +102 93 -460 -3065 +103 +442 93 -3078 -11825 +443 +3057 93 -11842 +3249 +11842 +93 + + +11855 22748 -52 +51 @@ -10102,57 +10142,57 @@ 1 2 -333 +332 2 3 -136 +133 3 4 -87 +85 4 -7 -112 - - -7 -15 -95 - - -15 -35 -96 - - -35 -68 -94 - - -68 -93 -95 - - -93 -138 +6 93 -138 -177 +6 +12 94 -177 -179 -2 +12 +26 +93 + + +26 +54 +93 + + +54 +80 +94 + + +80 +117 +93 + + +117 +164 +95 + + +164 +178 +29 @@ -10188,7 +10228,7 @@ 6 11 -103 +102 11 @@ -10197,28 +10237,28 @@ 37 -110 -94 - - -110 -450 +101 93 -452 -3056 +102 +439 93 -3072 -11597 +442 +3053 93 -11609 +3217 +11609 +93 + + +11646 22648 -52 +51 @@ -10228,23 +10268,23 @@ numlines -344316 +333286 element_id -321238 +314329 num_lines -1544 +1502 num_code -1300 +1276 num_comment -506 +491 @@ -10258,12 +10298,12 @@ 1 2 -298186 +295373 2 -4 -23052 +3 +18956 @@ -10279,12 +10319,12 @@ 1 2 -298202 +295380 2 -4 -23036 +3 +18949 @@ -10300,12 +10340,12 @@ 1 2 -318086 +311689 2 -4 -3152 +3 +2640 @@ -10321,42 +10361,42 @@ 1 2 -638 +633 2 3 -199 +203 3 4 -118 +113 4 6 -114 +108 6 10 -123 - - -10 -20 -121 - - -20 -76 116 -77 -72660 -115 +10 +21 +116 + + +21 +93 +114 + + +93 +79337 +99 @@ -10372,22 +10412,22 @@ 1 2 -640 +636 2 3 -201 +204 3 4 -117 +113 4 6 -124 +116 6 @@ -10397,17 +10437,17 @@ 10 18 -124 +115 18 -34 -116 +35 +115 -34 -53 -96 +35 +48 +77 @@ -10423,42 +10463,42 @@ 1 2 -640 +635 2 3 -199 +205 3 4 -117 +111 4 6 -122 +113 6 10 -131 +126 10 17 -120 +122 17 30 -116 +117 30 -44 -99 +41 +73 @@ -10474,93 +10514,93 @@ 1 2 +522 + + +2 +3 +174 + + +3 +4 +98 + + +4 +6 +106 + + +6 +12 +112 + + +12 +26 +98 + + +26 +137 +96 + + +143 +104495 +70 + + + + + + +num_code +num_lines + + +12 + + +1 +2 523 2 3 -165 +176 3 4 -102 +98 4 6 -114 +108 6 11 -103 +100 11 -23 -98 - - -23 -82 -98 - - -84 -101108 -97 - - - - - - -num_code -num_lines - - -12 - - -1 -2 -524 - - -2 -3 -169 - - -3 -4 +21 99 -4 -6 -116 +21 +43 +99 -6 -11 -107 - - -11 -22 -104 - - -22 -45 -101 - - -45 -60 -80 +43 +58 +73 @@ -10576,42 +10616,42 @@ 1 2 -526 +525 2 3 -163 +172 3 4 -103 +100 4 6 -118 +111 6 11 -113 +106 11 -21 +20 100 -21 -36 -99 +20 +35 +107 -36 -51 -78 +35 +48 +55 @@ -10627,47 +10667,47 @@ 1 2 -192 +198 2 3 -61 +66 3 4 -45 +40 4 6 -43 +36 6 10 -40 - - -10 -21 -40 - - -21 -69 39 -69 -1913 -38 +10 +24 +37 -1919 -255606 -8 +24 +82 +37 + + +82 +15817 +37 + + +254391 +254392 +1 @@ -10683,47 +10723,47 @@ 1 2 -193 +199 2 3 -60 +65 3 4 -45 +41 4 6 -43 +36 6 10 -41 +38 10 -21 -39 +23 +37 -21 -57 -38 +23 +70 +37 -58 -227 -38 +70 +309 +37 -227 -375 -9 +372 +373 +1 @@ -10739,47 +10779,42 @@ 1 2 -193 +199 2 3 -60 +65 3 4 -45 +40 4 6 -43 +37 6 10 -40 +39 10 -21 -42 +23 +37 -22 -64 -38 +23 +71 +37 -66 -210 -38 - - -211 -333 -7 +79 +331 +37 @@ -10789,27 +10824,27 @@ assemblies -2863 +2760 id -2863 +2760 file -2861 +2758 fullname -1321 +1253 name -605 +553 version -124 +95 @@ -10823,7 +10858,7 @@ 1 2 -2863 +2760 @@ -10839,7 +10874,7 @@ 1 2 -2863 +2760 @@ -10855,7 +10890,7 @@ 1 2 -2863 +2760 @@ -10871,7 +10906,7 @@ 1 2 -2863 +2760 @@ -10887,7 +10922,7 @@ 1 2 -2859 +2756 2 @@ -10908,7 +10943,7 @@ 1 2 -2859 +2756 2 @@ -10929,7 +10964,7 @@ 1 2 -2861 +2758 @@ -10945,7 +10980,7 @@ 1 2 -2861 +2758 @@ -10961,7 +10996,7 @@ 1 2 -782 +722 2 @@ -10971,17 +11006,22 @@ 3 4 -92 +84 4 -7 -114 +6 +65 -7 +6 +8 +116 + + +8 13 -99 +32 @@ -10997,7 +11037,7 @@ 1 2 -782 +722 2 @@ -11007,17 +11047,22 @@ 3 4 -92 +84 4 -7 -114 +6 +65 -7 +6 +8 +116 + + +8 13 -99 +32 @@ -11033,7 +11078,7 @@ 1 2 -1321 +1253 @@ -11049,7 +11094,7 @@ 1 2 -1321 +1253 @@ -11065,134 +11110,144 @@ 1 2 -231 +181 2 3 -70 +73 3 4 -52 +47 4 -6 -55 +5 +36 -6 +5 +7 +42 + + +7 9 -53 +33 9 11 -43 - - -11 -13 -39 - - -13 -15 -56 - - -15 -27 -6 - - - - - - -name -file - - -12 - - -1 -2 -231 - - -2 -3 -71 - - -3 -4 -52 - - -4 -6 -54 - - -6 -9 -53 - - -9 -11 -43 - - -11 -13 -39 - - -13 -15 -56 - - -15 -27 -6 - - - - - - -name -fullname - - -12 - - -1 -2 -416 - - -2 -3 -61 - - -3 -4 48 +11 +13 +37 + + +13 +15 +50 + + +15 +27 +6 + + + + + + +name +file + + +12 + + +1 +2 +181 + + +2 +3 +74 + + +3 +4 +47 + + +4 +5 +35 + + +5 +7 +42 + + +7 +9 +33 + + +9 +11 +48 + + +11 +13 +37 + + +13 +15 +50 + + +15 +27 +6 + + + + + + +name +fullname + + +12 + + +1 +2 +368 + + +2 +3 +66 + + +3 +4 +42 + + 4 6 -45 +42 13 @@ -11213,22 +11268,22 @@ 1 2 -452 +404 2 3 -61 +66 3 4 -47 +41 4 6 -45 +42 @@ -11244,47 +11299,52 @@ 1 2 -47 +25 2 3 -16 +15 3 4 -9 +6 4 6 -9 +8 6 -8 -9 +7 +7 -8 -10 -9 +7 +9 +6 -10 -28 -10 +9 +11 +8 -28 -103 -10 +12 +31 +8 -147 +33 +142 +8 + + +157 756 -5 +4 @@ -11300,47 +11360,52 @@ 1 2 -47 +25 2 3 -17 +16 3 4 -9 +6 4 6 -8 +7 6 -8 -9 +7 +7 -8 -10 -9 +7 +9 +6 -10 -28 -10 +9 +11 +8 -28 -103 -10 +12 +31 +8 -147 +33 +142 +8 + + +157 756 -5 +4 @@ -11356,37 +11421,37 @@ 1 2 -68 +45 2 3 -15 +14 3 4 -9 +8 4 -7 -10 +6 +6 -7 -20 -10 +6 +13 +8 -22 -71 -10 +15 +27 +8 -123 +30 586 -2 +6 @@ -11402,37 +11467,37 @@ 1 2 -69 +46 2 3 -14 +13 3 4 -9 +8 4 -7 -10 +6 +6 -7 -20 -10 +6 +13 +8 -22 -71 -10 +15 +27 +8 -122 +30 166 -2 +6 @@ -11442,23 +11507,23 @@ files -24954 +20987 id -24954 +20987 name -24954 +20987 simple -20050 +16459 ext -8 +7 fromSource @@ -11476,7 +11541,7 @@ 1 2 -24954 +20987 @@ -11492,7 +11557,7 @@ 1 2 -24954 +20987 @@ -11508,7 +11573,7 @@ 1 2 -24954 +20987 @@ -11524,7 +11589,7 @@ 1 2 -24954 +20987 @@ -11540,7 +11605,7 @@ 1 2 -24954 +20987 @@ -11556,7 +11621,7 @@ 1 2 -24954 +20987 @@ -11572,7 +11637,7 @@ 1 2 -24954 +20987 @@ -11588,7 +11653,7 @@ 1 2 -24954 +20987 @@ -11604,12 +11669,12 @@ 1 2 -18724 +15342 2 417 -1326 +1117 @@ -11625,12 +11690,12 @@ 1 2 -18724 +15342 2 417 -1326 +1117 @@ -11646,12 +11711,12 @@ 1 2 -19838 +16251 2 4 -212 +208 @@ -11667,7 +11732,7 @@ 1 2 -20050 +16459 @@ -11683,123 +11748,16 @@ 1 2 -1 - - -2 -3 -1 - - -9 -10 -1 - - -17 -18 -1 - - -98 -99 -1 - - -112 -113 -1 - - -2842 -2843 -1 - - -21873 -21874 -1 - - - - - - -ext -name - - -12 - - -1 -2 -1 - - -2 -3 -1 - - -9 -10 -1 - - -17 -18 -1 - - -98 -99 -1 - - -112 -113 -1 - - -2842 -2843 -1 - - -21873 -21874 -1 - - - - - - -ext -simple - - -12 - - -1 -2 2 -7 -8 +2 +3 1 -11 -12 -1 - - -56 -57 +17 +18 1 @@ -11808,13 +11766,90 @@ 1 -597 -598 +2740 +2741 1 -19532 -19533 +18168 +18169 +1 + + + + + + +ext +name + + +12 + + +1 +2 +2 + + +2 +3 +1 + + +17 +18 +1 + + +58 +59 +1 + + +2740 +2741 +1 + + +18168 +18169 +1 + + + + + + +ext +simple + + +12 + + +1 +2 +3 + + +11 +12 +1 + + +31 +32 +1 + + +545 +546 +1 + + +16078 +16079 1 @@ -11831,7 +11866,7 @@ 1 2 -8 +7 @@ -11845,8 +11880,8 @@ 12 -24954 -24955 +20987 +20988 1 @@ -11861,8 +11896,8 @@ 12 -24954 -24955 +20987 +20988 1 @@ -11877,8 +11912,8 @@ 12 -20050 -20051 +16459 +16460 1 @@ -11893,8 +11928,8 @@ 12 -8 -9 +7 +8 1 @@ -11905,19 +11940,19 @@ folders -7016 +6292 id -7016 +6292 name -6927 +6258 simple -1989 +1648 @@ -11931,7 +11966,7 @@ 1 2 -7016 +6292 @@ -11947,7 +11982,7 @@ 1 2 -7016 +6292 @@ -11963,12 +11998,12 @@ 1 2 -6838 +6224 2 3 -89 +34 @@ -11984,7 +12019,7 @@ 1 2 -6927 +6258 @@ -12000,27 +12035,32 @@ 1 2 -1079 +841 2 3 -347 +293 3 4 -258 +236 4 6 -170 +152 6 -352 -135 +211 +124 + + +301 +342 +2 @@ -12036,27 +12076,32 @@ 1 2 -1114 +853 2 3 -334 +286 3 4 -252 +237 4 6 -156 +147 6 -352 -133 +302 +124 + + +341 +342 +1 @@ -12066,15 +12111,15 @@ containerparent -31967 +27276 parent -7016 +6292 child -31967 +27276 @@ -12088,32 +12133,32 @@ 1 2 -3597 +3258 2 3 -1293 +1213 3 4 -556 +509 4 6 -568 +500 6 -14 -536 +16 +474 -14 -229 -466 +16 +230 +338 @@ -12129,7 +12174,7 @@ 1 2 -31967 +27276 @@ -12139,15 +12184,15 @@ file_extraction_mode -24734 +20927 file -24734 +20927 mode -2 +1 @@ -12161,7 +12206,7 @@ 1 2 -24734 +20927 @@ -12175,13 +12220,8 @@ 12 -3808 -3809 -1 - - -20926 -20927 +20927 +20928 1 @@ -12192,15 +12232,15 @@ namespaces -6505 +5700 id -6505 +5700 name -1717 +1313 @@ -12214,7 +12254,7 @@ 1 2 -6505 +5700 @@ -12230,37 +12270,42 @@ 1 2 -407 +67 2 3 -730 +744 3 4 -103 +55 4 5 -132 +127 5 7 -86 +81 7 -10 -137 +9 +113 -10 -69 -122 +9 +21 +103 + + +21 +66 +23 @@ -12270,15 +12315,15 @@ namespace_declarations -22696 +19007 id -22696 +19007 namespace_id -1922 +1509 @@ -12292,7 +12337,7 @@ 1 2 -22696 +19007 @@ -12308,47 +12353,47 @@ 1 2 -638 +558 2 3 -295 +223 3 4 -144 +107 4 -5 -105 +6 +125 -5 -7 -148 +6 +9 +126 -7 -10 -147 +9 +15 +114 -10 -17 -157 +15 +32 +117 -17 -35 -147 +32 +112 +114 -35 +115 646 -141 +25 @@ -12358,15 +12403,15 @@ namespace_declaration_location -22696 +19007 id -22696 +19007 loc -19757 +16071 @@ -12380,7 +12425,7 @@ 1 2 -22696 +19007 @@ -12396,16 +12441,16 @@ 1 2 -17726 +14045 2 3 -1611 +1606 3 -128 +129 420 @@ -12416,15 +12461,15 @@ parent_namespace -360683 +501755 child_id -360683 +501755 namespace_id -4420 +3630 @@ -12438,7 +12483,7 @@ 1 2 -360683 +501755 @@ -12454,52 +12499,52 @@ 1 2 -1289 +1108 2 3 -494 +423 3 4 -306 +245 4 -5 -217 +6 +334 -5 -7 -382 +6 +9 +286 -7 -11 -402 +9 +15 +308 -11 -17 -338 +15 +28 +282 -17 -30 -338 +28 +58 +276 -30 -66 -335 +58 +254 +273 -66 -108885 -319 +255 +170410 +95 @@ -12509,15 +12554,15 @@ parent_namespace_declaration -34436 +30406 child_id -24003 +21983 namespace_id -22688 +19004 @@ -12531,22 +12576,17 @@ 1 2 -17774 +16376 2 3 -4375 +4192 3 -11 -1807 - - -11 -259 -47 +143 +1415 @@ -12562,17 +12602,17 @@ 1 2 -20681 +17129 2 -10 -1727 +7 +1458 -10 +7 299 -280 +417 @@ -12582,15 +12622,15 @@ using_namespace_directives -106992 +86694 id -106992 +86694 namespace_id -1422 +1088 @@ -12604,7 +12644,7 @@ 1 2 -106992 +86694 @@ -12620,53 +12660,53 @@ 1 2 -341 +291 2 3 -202 +138 3 4 -112 +85 4 6 -131 +100 6 9 -112 +82 9 15 -117 +86 15 -28 -111 +27 +91 -28 -55 -107 - - -55 -180 -107 - - -180 -10946 +27 +53 82 + +54 +237 +82 + + +241 +8479 +51 + @@ -12683,7 +12723,7 @@ type_id -75 +98 @@ -12713,42 +12753,37 @@ 1 2 -17 +29 2 3 -21 +32 3 4 -10 +9 4 5 -6 +10 5 -8 -6 +9 +9 -8 -11 -6 - - -11 +9 15 -6 +8 15 -19 -3 +16 +1 @@ -12758,15 +12793,15 @@ using_directive_location -107313 +87015 id -107313 +87015 loc -91983 +71734 @@ -12780,7 +12815,7 @@ 1 2 -107313 +87015 @@ -12796,16 +12831,16 @@ 1 2 -79730 +59536 2 3 -10544 +10489 3 -128 +129 1709 @@ -12816,19 +12851,19 @@ types -413820 +555841 id -413820 +555841 kind -27 +28 name -180164 +158850 @@ -12842,7 +12877,7 @@ 1 2 -413820 +555841 @@ -12858,7 +12893,7 @@ 1 2 -413820 +555841 @@ -12874,31 +12909,31 @@ 1 2 -17 +18 -383 -1383 +456 +2280 2 -1768 -7962 +2682 +9836 2 -8073 -31633 +11359 +43621 2 -40645 -58091 +55958 +80354 2 -126692 -137174 +142562 +206666 2 @@ -12915,31 +12950,31 @@ 1 2 -17 +18 -317 -580 +312 +578 2 -1014 -1043 +852 +994 2 -3386 -6731 +2988 +6687 2 -14006 -23824 +13823 +21622 2 -62903 -69095 +55697 +56500 2 @@ -12956,17 +12991,27 @@ 1 2 -158707 +105413 2 +3 +27307 + + +3 4 -15195 +9579 4 -8751 -6262 +8 +12599 + + +8 +11441 +3952 @@ -12982,12 +13027,12 @@ 1 2 -177472 +157673 2 5 -2692 +1177 @@ -12997,15 +13042,15 @@ typerefs -349451 +462875 id -349451 +462875 name -79294 +69295 @@ -13019,7 +13064,7 @@ 1 2 -349451 +462875 @@ -13035,17 +13080,22 @@ 1 2 -69433 +50533 2 3 -5934 +10126 3 -26887 -3927 +6 +6047 + + +6 +37752 +2589 @@ -13055,15 +13105,15 @@ typeref_type -343625 +462440 id -343625 +462440 typeId -343625 +462440 @@ -13077,7 +13127,7 @@ 1 2 -343625 +462440 @@ -13093,7 +13143,7 @@ 1 2 -343625 +462440 @@ -13103,11 +13153,11 @@ array_element_type -7961 +9835 array -7961 +9835 dimension @@ -13119,7 +13169,7 @@ element -7932 +9808 @@ -13133,7 +13183,7 @@ 1 2 -7961 +9835 @@ -13149,7 +13199,7 @@ 1 2 -7961 +9835 @@ -13165,7 +13215,7 @@ 1 2 -7961 +9835 @@ -13184,13 +13234,13 @@ 1 -49 -50 +54 +55 1 -7910 -7911 +9779 +9780 1 @@ -13236,13 +13286,13 @@ 1 -48 -49 +53 +54 1 -7882 -7883 +9753 +9754 1 @@ -13262,8 +13312,8 @@ 1 -10 -11 +11 +12 1 @@ -13272,8 +13322,8 @@ 1 -7926 -7927 +9799 +9800 1 @@ -13319,8 +13369,8 @@ 1 -10 -11 +11 +12 1 @@ -13329,8 +13379,8 @@ 1 -7926 -7927 +9799 +9800 1 @@ -13347,12 +13397,12 @@ 1 2 -7908 +9786 2 5 -24 +22 @@ -13368,7 +13418,7 @@ 1 2 -7932 +9808 @@ -13384,12 +13434,12 @@ 1 2 -7908 +9786 2 5 -24 +22 @@ -13399,15 +13449,15 @@ nullable_underlying_type -1382 +2279 nullable -1382 +2279 underlying -1382 +1665 @@ -13421,7 +13471,7 @@ 1 2 -1382 +2279 @@ -13437,7 +13487,22 @@ 1 2 -1382 +1243 + + +2 +3 +266 + + +3 +4 +139 + + +4 +8 +17 @@ -13447,15 +13512,15 @@ pointer_referent_type -383 +456 pointer -383 +456 referent -383 +456 @@ -13469,7 +13534,7 @@ 1 2 -383 +456 @@ -13485,7 +13550,7 @@ 1 2 -383 +456 @@ -13495,11 +13560,11 @@ enum_underlying_type -8079 +11359 enum_id -8079 +11359 underlying_type_id @@ -13517,7 +13582,7 @@ 1 2 -8079 +11359 @@ -13531,43 +13596,43 @@ 12 -5 -6 +7 +8 1 -6 -7 +10 +11 1 -16 -17 +27 +28 1 -41 -42 +103 +104 1 -82 -83 +106 +107 1 -289 -290 +435 +436 1 -392 -393 +461 +462 1 -7248 -7249 +10210 +10211 1 @@ -13578,15 +13643,15 @@ delegate_return_type -40602 +55985 delegate_id -40602 +55985 return_type_id -17705 +23894 @@ -13600,7 +13665,7 @@ 1 2 -40602 +55985 @@ -13616,17 +13681,17 @@ 1 2 -16003 +21161 2 -4 -1360 +3 +1803 -4 -7208 -342 +3 +9114 +930 @@ -13636,15 +13701,15 @@ extend -206708 +557003 sub -206708 +557003 super -10856 +12849 @@ -13658,7 +13723,7 @@ 1 2 -206708 +557003 @@ -13674,32 +13739,32 @@ 1 2 -6157 +6927 2 3 -2069 +2601 3 4 -789 +1039 4 6 -902 +1131 6 -34 -815 +31 +966 -34 -52181 -124 +31 +206666 +185 @@ -13709,15 +13774,15 @@ implement -501419 +752149 sub -165927 +235420 super -111188 +170825 @@ -13731,37 +13796,32 @@ 1 2 -46744 +59364 2 3 -48255 +74329 3 4 -35908 +54343 4 -5 -9804 +6 +19213 -5 -8 -10322 +6 +11 +18398 -8 -14 -14877 - - -14 -31 -17 +11 +44 +9773 @@ -13777,32 +13837,32 @@ 1 2 -52605 +78466 2 3 -27664 +44401 3 4 -11959 +19338 4 6 -9609 +13428 6 -10 -8459 +9 +13436 -10 -113783 -892 +9 +175652 +1756 @@ -13812,15 +13872,15 @@ type_location -445714 +430401 id -185891 +224933 loc -52345 +46244 @@ -13834,27 +13894,27 @@ 1 2 -99018 +121778 2 3 -41333 +57052 3 4 -18115 +17460 4 -7 -16473 +5 +19506 -7 -717 -10952 +5 +77 +9137 @@ -13870,12 +13930,17 @@ 1 2 -49945 +41878 2 +29 +3484 + + +29 17019 -2400 +882 @@ -13885,15 +13950,15 @@ tuple_underlying_type -1768 +3134 tuple -1768 +3134 struct -699 +1704 @@ -13907,7 +13972,7 @@ 1 2 -1768 +3134 @@ -13923,27 +13988,22 @@ 1 2 -228 +961 2 3 -259 +472 3 4 -123 +158 4 -6 -64 - - -6 -153 -25 +101 +113 @@ -13953,11 +14013,11 @@ tuple_element -4528 +10263 tuple -1768 +2682 index @@ -13965,7 +14025,7 @@ field -4528 +10263 @@ -13979,27 +14039,37 @@ 1 2 -10 +67 2 3 -1395 +1670 3 4 -221 +306 4 -18 -134 +6 +193 -18 +6 +11 +219 + + +11 +21 +212 + + +21 22 -8 +15 @@ -14015,27 +14085,37 @@ 1 2 -10 +67 2 3 -1395 +1670 3 4 -221 +306 4 -18 -134 +6 +193 -18 +6 +11 +219 + + +11 +21 +212 + + +21 22 -8 +15 @@ -14049,108 +14129,108 @@ 12 -2 -3 +15 +16 1 -4 -5 +30 +31 1 -6 -7 +45 +46 1 -8 -9 +60 +61 1 -10 -11 +75 +76 1 -12 -13 +90 +91 1 -14 -15 +105 +106 1 -18 -19 +135 +136 1 -22 -23 +165 +166 1 -26 -27 +195 +196 1 -32 -33 +227 +228 1 -36 -37 +257 +258 1 -40 -41 +287 +288 1 -47 -48 +326 +327 1 -55 -56 +385 +386 1 -65 -66 +446 +447 1 -100 -101 +539 +540 1 -142 -143 +639 +640 1 -363 -364 +945 +946 1 -1758 -1759 +2615 +2616 1 -1768 -1769 +2682 +2683 1 @@ -14165,108 +14245,108 @@ 12 -2 -3 +15 +16 1 -4 -5 +30 +31 1 -6 -7 +45 +46 1 -8 -9 +60 +61 1 -10 -11 +75 +76 1 -12 -13 +90 +91 1 -14 -15 +105 +106 1 -18 -19 +135 +136 1 -22 -23 +165 +166 1 -26 -27 +195 +196 1 -32 -33 +227 +228 1 -36 -37 +257 +258 1 -40 -41 +287 +288 1 -47 -48 +326 +327 1 -55 -56 +385 +386 1 -65 -66 +446 +447 1 -100 -101 +539 +540 1 -142 -143 +639 +640 1 -363 -364 +945 +946 1 -1758 -1759 +2615 +2616 1 -1768 -1769 +2682 +2683 1 @@ -14283,7 +14363,7 @@ 1 2 -4528 +10263 @@ -14299,7 +14379,7 @@ 1 2 -4528 +10263 @@ -14309,19 +14389,19 @@ attributes -152979 +144787 id -152979 +144787 type_id -468 +517 target -78814 +74146 @@ -14335,7 +14415,7 @@ 1 2 -152979 +144787 @@ -14351,7 +14431,7 @@ 1 2 -152979 +144787 @@ -14367,62 +14447,67 @@ 1 2 -71 +46 2 3 -52 +50 3 -4 -28 +5 +45 -4 -6 +5 +8 +41 + + +8 +11 42 -6 -9 -36 +11 +16 +43 -9 -14 -36 - - -14 -23 -36 - - -23 -45 -36 - - -45 -81 -37 - - -86 -205 -37 - - -217 -1059 +16 +25 39 -1079 +25 +49 +46 + + +49 +84 +40 + + +84 +161 +39 + + +164 +296 +44 + + +315 +7070 +39 + + +14098 49629 -18 +3 @@ -14438,57 +14523,62 @@ 1 2 -93 +72 2 3 -51 +49 3 -4 -32 +5 +40 -4 -6 -35 +5 +8 +44 -6 -9 +8 +12 +45 + + +12 +19 +43 + + +19 +31 +40 + + +31 +56 39 -9 -16 -38 - - -16 -28 -36 - - -28 -56 -36 - - 56 -121 -36 +95 +41 -124 -417 -38 +95 +196 +39 -421 -49626 -34 +201 +326 +40 + + +339 +49629 +25 @@ -14504,22 +14594,22 @@ 1 2 -40545 +37641 2 3 -28536 +27423 3 4 -7103 +6746 4 2518 -2630 +2336 @@ -14535,22 +14625,22 @@ 1 2 -42542 +38510 2 3 -28029 +27709 3 4 -6770 +6480 4 16 -1473 +1447 @@ -14560,15 +14650,15 @@ attribute_location -295887 +289574 id -152979 +144787 loc -150274 +140232 @@ -14580,14 +14670,9 @@ 12 -1 -2 -10071 - - 2 3 -142908 +144787 @@ -14603,12 +14688,12 @@ 1 2 -147783 +137280 2 33350 -2491 +2952 @@ -14618,19 +14703,19 @@ type_mention -2269573 +2181438 id -2269573 +2181438 type_id -62260 +64029 parent -2098317 +2040856 @@ -14644,7 +14729,7 @@ 1 2 -2269573 +2181438 @@ -14660,7 +14745,7 @@ 1 2 -2269573 +2181438 @@ -14676,47 +14761,47 @@ 1 2 -16389 +17289 2 3 -12921 +13682 3 4 -5673 +5842 4 5 -4952 +5042 5 7 -4946 +4865 7 -11 -4873 +12 +5498 -11 -21 -4739 +12 +25 +4984 -21 -62 -4682 +25 +99 +4820 -62 -170762 -3085 +99 +161715 +2007 @@ -14732,47 +14817,47 @@ 1 2 -19486 +20094 2 3 -12123 +12833 3 4 -5422 +5717 4 5 -4489 +4591 5 7 -4628 +4623 7 12 -5228 +5197 12 -25 -4788 +26 +4929 -25 -127 -4672 +26 +155 +4805 -127 -157226 -1424 +155 +154065 +1240 @@ -14788,12 +14873,12 @@ 1 2 -1990082 +1950128 2 953 -108235 +90728 @@ -14809,12 +14894,12 @@ 1 2 -2068929 +2012696 2 29 -29388 +28160 @@ -14824,15 +14909,15 @@ type_mention_location -2269573 +2181438 id -2269573 +2181438 loc -2163726 +1978560 @@ -14846,7 +14931,7 @@ 1 2 -2269573 +2181438 @@ -14862,12 +14947,12 @@ 1 2 -2129500 +1892284 2 227 -34226 +86276 @@ -14877,11 +14962,11 @@ type_annotation -45915 +59922 id -45915 +59922 annotation @@ -14899,7 +14984,7 @@ 1 2 -45915 +59922 @@ -14913,18 +14998,18 @@ 12 -1956 -1957 +2330 +2331 1 -13501 -13502 +17268 +17269 1 -30458 -30459 +40324 +40325 1 @@ -14935,11 +15020,11 @@ nullability -116 +117 nullability -116 +117 kind @@ -14957,7 +15042,7 @@ 1 2 -116 +117 @@ -14976,13 +15061,13 @@ 1 -47 -48 +49 +50 1 -58 -59 +57 +58 1 @@ -14992,20 +15077,20 @@ -nullability_member -381 +nullability_parent +386 nullability -113 +25 index 17 -child -25 +parent +114 @@ -15019,37 +15104,27 @@ 1 2 -34 +16 2 3 -33 +3 3 4 -14 - - -4 -5 -10 +2 5 8 -10 +2 -8 -15 -9 - - -15 +16 18 -3 +2 @@ -15057,7 +15132,7 @@ nullability -child +parent 12 @@ -15065,17 +15140,37 @@ 1 2 -50 - - -2 -3 -54 +14 3 4 -9 +1 + + +4 +5 +2 + + +5 +6 +2 + + +6 +7 +2 + + +23 +26 +2 + + +30 +64 +2 @@ -15096,102 +15191,6 @@ 2 3 -1 - - -3 -4 -1 - - -4 -5 -1 - - -5 -6 -1 - - -6 -7 -1 - - -7 -8 -1 - - -8 -9 -1 - - -9 -10 -1 - - -12 -13 -1 - - -14 -15 -1 - - -18 -19 -1 - - -22 -23 -1 - - -32 -33 -1 - - -46 -47 -1 - - -79 -80 -1 - - -113 -114 -1 - - - - - - -index -child - - -12 - - -1 -2 -1 - - -2 -3 9 @@ -15224,8 +15223,8 @@ -child -nullability +index +parent 12 @@ -15233,7 +15232,12 @@ 1 2 -14 +1 + + +2 +3 +1 3 @@ -15243,34 +15247,105 @@ 4 5 -2 +1 5 6 -2 +1 6 7 -2 +1 -23 -27 -2 +7 +8 +1 -28 -62 -2 +8 +9 +1 + + +9 +10 +1 + + +12 +13 +1 + + +14 +15 +1 + + +18 +19 +1 + + +22 +23 +1 + + +33 +34 +1 + + +48 +49 +1 + + +80 +81 +1 + + +114 +115 +1 -child +parent +nullability + + +12 + + +1 +2 +49 + + +2 +3 +56 + + +3 +4 +9 + + + + + + +parent index @@ -15279,27 +15354,37 @@ 1 2 -16 +34 2 3 -3 +32 3 4 -2 +15 + + +4 +5 +11 5 8 -2 +10 -16 +8 +15 +9 + + +15 18 -2 +3 @@ -15309,15 +15394,15 @@ type_nullability -243176 +297491 id -239388 +293770 nullability -107 +108 @@ -15331,12 +15416,12 @@ 1 2 -235606 +290049 2 -4 -3782 +3 +3721 @@ -15356,13 +15441,8 @@ 2 -3 -7 - - -3 4 -4 +10 4 @@ -15371,43 +15451,43 @@ 6 -7 +9 +10 + + +9 +13 +10 + + +14 +30 9 -7 -10 -5 - - -10 -15 +30 +76 9 -19 -31 +76 +285 9 -40 -106 +292 +788 9 -119 -481 +1023 +28413 9 -540 -3383 -9 - - -14434 -154277 -5 +188323 +188324 +1 @@ -15417,33 +15497,33 @@ is_generic -60403 +73607 id -60403 +73607 is_constructed -237565 +339924 id -237565 +339924 type_parameters -58092 +80200 id -58092 +80200 index @@ -15451,7 +15531,7 @@ generic_id -37990 +49295 variance @@ -15469,7 +15549,7 @@ 1 2 -58092 +80200 @@ -15485,7 +15565,7 @@ 1 2 -58092 +80200 @@ -15501,7 +15581,7 @@ 1 2 -58092 +80200 @@ -15515,48 +15595,48 @@ 12 -1 -2 +4 +5 16 -2 -4 +6 +9 3 -7 -15 +33 +84 3 -18 -150 +110 +317 3 -270 -511 +489 +836 3 -632 -887 +1009 +1369 3 -1013 -1291 +1550 +1995 3 -1461 -1881 +2233 +2928 3 -2310 -37991 +3776 +49278 3 @@ -15571,48 +15651,48 @@ 12 -1 -2 +4 +5 16 -2 -4 +6 +9 3 -7 -15 +33 +84 3 -18 -150 +110 +317 3 -270 -511 +489 +836 3 -632 -887 +1009 +1369 3 -1013 -1291 +1550 +1995 3 -1461 -1881 +2233 +2928 3 -2310 -37991 +3776 +49296 3 @@ -15655,17 +15735,22 @@ 1 2 -32308 +41484 2 3 -3372 +4035 3 +20 +3720 + + +20 41 -2310 +56 @@ -15681,17 +15766,22 @@ 1 2 -32308 +41484 2 3 -3372 +4035 3 +20 +3720 + + +20 41 -2310 +56 @@ -15707,12 +15797,12 @@ 1 2 -37946 +49186 2 3 -44 +109 @@ -15726,18 +15816,18 @@ 12 -63 -64 +180 +181 1 -312 -313 +1500 +1501 1 -57717 -57718 +78502 +78503 1 @@ -15778,18 +15868,18 @@ 12 -61 -62 +186 +187 1 -71 -72 +244 +245 1 -37902 -37903 +48974 +48975 1 @@ -15800,11 +15890,11 @@ type_arguments -312757 +446484 id -87949 +118281 index @@ -15812,7 +15902,7 @@ constructed_id -237565 +339924 @@ -15826,17 +15916,17 @@ 1 2 -68801 +93801 2 3 -18339 +23468 3 18 -809 +1012 @@ -15852,37 +15942,32 @@ 1 2 -44933 +54689 2 3 -16977 +26868 3 -5 -7885 +4 +8139 -5 +4 7 -4344 +10745 7 -8 -6689 +9 +9001 -8 -28 -6603 - - -28 -7377 -518 +9 +9658 +8839 @@ -15896,93 +15981,93 @@ 12 -2 -3 +4 +5 4 -32 -33 +37 +38 1 -146 -147 +175 +176 1 -259 -260 +313 +314 1 -372 -373 +451 +452 1 -485 -486 +589 +590 1 -600 -601 +729 +730 1 -716 -717 +870 +871 1 -836 -837 +1017 +1018 1 -953 -954 +1161 +1162 1 -1185 -1186 +2044 +2045 1 -1279 -1280 +2144 +2145 1 -1436 -1437 +2297 +2298 1 -1645 -1646 +2628 +2629 1 -1998 -1999 +3171 +3172 1 -7659 -7660 +10871 +10872 1 -21869 -21870 +27900 +27901 1 -67117 -67118 +88130 +88131 1 @@ -15997,93 +16082,93 @@ 12 -2 -3 +4 +5 4 -77 -78 +94 +95 1 -192 -193 +233 +234 1 -307 -308 +372 +373 1 -422 -423 +511 +512 1 -537 -538 +650 +651 1 -654 -655 +791 +792 1 -773 -774 +934 +935 1 -894 -895 +1081 +1082 1 -1014 -1015 +1227 +1228 1 -1253 -1254 +2216 +2217 1 -1404 -1405 +2506 +2507 1 -1616 -1617 +2884 +2885 1 -1958 -1959 +3505 +3506 1 -2634 -2635 +4555 +4556 1 -9388 -9389 +13989 +13990 1 -52061 -52062 +70996 +70997 1 -237565 -237566 +339924 +339925 1 @@ -16100,17 +16185,17 @@ 1 2 -186726 +270905 2 3 -42264 +56336 3 22 -8575 +12683 @@ -16126,17 +16211,17 @@ 1 2 -185504 +268928 2 3 -42673 +57007 3 22 -9388 +13989 @@ -16146,15 +16231,15 @@ constructed_generic -237565 +339924 constructed -237565 +339924 generic -5449 +6639 @@ -16168,7 +16253,7 @@ 1 2 -237565 +339924 @@ -16184,37 +16269,42 @@ 1 2 -2207 +2575 2 3 -1075 +1249 3 4 -506 +557 4 6 -479 +565 6 11 -442 +554 11 -33 -409 +25 +502 -33 -21877 -331 +25 +213 +499 + + +214 +37705 +138 @@ -16224,15 +16314,15 @@ type_parameter_constraints -389563 +363573 id -389563 +363573 param_id -58090 +80353 @@ -16246,7 +16336,7 @@ 1 2 -389563 +363573 @@ -16262,32 +16352,27 @@ 1 2 -32353 +50203 2 3 -9062 +14018 3 -4 -5333 +5 +7399 -4 -7 -4581 +5 +14 +6191 -7 -17 -4653 - - -17 -10899 -2108 +14 +9487 +2542 @@ -16333,11 +16418,11 @@ general_type_parameter_constraints -49753 +48124 id -49483 +47846 kind @@ -16355,12 +16440,12 @@ 1 2 -49213 +47568 2 3 -270 +278 @@ -16379,23 +16464,23 @@ 1 -176 -177 +186 +187 1 -372 -373 +324 +325 1 -4647 -4648 +4170 +4171 1 -44498 -44499 +43384 +43385 1 @@ -16406,15 +16491,15 @@ specific_type_parameter_constraints -41475 +38432 id -40987 +37993 base_id -2496 +2291 @@ -16428,12 +16513,12 @@ 1 2 -40536 +37585 2 5 -451 +408 @@ -16449,47 +16534,47 @@ 1 2 -951 +717 2 3 -329 +296 3 4 -224 +255 4 -6 -231 +5 +256 -6 +5 8 -172 +210 8 12 -204 +180 12 -25 -191 +22 +176 -25 -671 -188 +22 +185 +172 -947 -6057 -6 +186 +5259 +29 @@ -16499,15 +16584,15 @@ specific_type_parameter_nullability -305 +306 id -305 +306 base_id -24 +36 nullability @@ -16525,7 +16610,7 @@ 1 2 -305 +306 @@ -16541,7 +16626,7 @@ 1 2 -305 +306 @@ -16557,47 +16642,37 @@ 1 2 -1 +3 2 3 -7 +10 3 4 -2 +11 4 5 -2 - - -5 -6 -5 - - -6 -8 -2 +3 8 -9 -1 +13 +3 -34 -35 -2 +22 +25 +3 -60 -103 -2 +36 +67 +3 @@ -16613,12 +16688,12 @@ 1 2 -21 +35 2 3 -3 +1 @@ -16652,8 +16727,8 @@ 1 -288 -289 +289 +290 1 @@ -16675,11 +16750,16 @@ 2 3 -2 +1 -21 -22 +3 +4 +1 + + +30 +31 1 @@ -16738,11 +16818,11 @@ has_modifiers -3644548 +4409612 id -2423233 +2914166 mod_id @@ -16760,17 +16840,17 @@ 1 2 -1294970 +1527243 2 3 -1036528 +1280137 3 6 -91735 +106786 @@ -16784,93 +16864,93 @@ 12 -474 -475 +608 +609 1 -595 -596 +876 +877 1 -858 -859 +979 +980 1 -1986 -1987 +2568 +2569 1 -3632 -3633 +4159 +4160 1 -9430 -9431 +10471 +10472 1 -22226 -22227 +22235 +22236 1 -29654 -29655 +41832 +41833 1 -53969 -53970 +62104 +62105 1 -70891 -70892 +77024 +77025 1 -106769 -106770 +147707 +147708 1 -143771 -143772 +183303 +183304 1 -147924 -147925 +191235 +191236 1 -199833 -199834 +235884 +235885 1 -247611 -247612 +310096 +310097 1 -373610 -373611 +418191 +418192 1 -443150 -443151 +513043 +513044 1 -1788165 -1788166 +2187297 +2187298 1 @@ -16881,22 +16961,22 @@ compiler_generated -78129 +76391 id -78129 +76391 exprorstmt_name -1656 +1762 parent_id -1656 +1762 name @@ -16914,7 +16994,7 @@ 1 2 -1656 +1762 @@ -16935,7 +17015,7 @@ 2 3 -75 +74 3 @@ -16945,7 +17025,7 @@ 4 5 -31 +30 5 @@ -16960,17 +17040,17 @@ 8 13 -19 +20 13 -85 +55 17 111 176 -3 +4 @@ -16980,19 +17060,19 @@ nested_types -57581 +59639 id -57581 +59639 declaring_type_id -18925 +22408 unbound_id -36015 +36073 @@ -17006,7 +17086,7 @@ 1 2 -57581 +59639 @@ -17022,7 +17102,7 @@ 1 2 -57581 +59639 @@ -17038,32 +17118,27 @@ 1 2 -9127 +12009 2 3 -2917 +3462 3 4 -3625 +3848 4 -6 -1378 +8 +1847 -6 -14 -1452 - - -14 +8 592 -426 +1242 @@ -17079,32 +17154,27 @@ 1 2 -9216 +12105 2 3 -2893 +3437 3 4 -3605 +3833 4 -6 -1380 +8 +1847 -6 -14 -1427 - - -14 +8 592 -404 +1186 @@ -17120,12 +17190,12 @@ 1 2 -34018 +33986 2 -1347 -1997 +1139 +2087 @@ -17141,12 +17211,12 @@ 1 2 -34383 +34409 2 -1347 -1632 +1139 +1664 @@ -17156,27 +17226,27 @@ properties -268986 +326745 id -268986 +326745 name -58896 +53824 declaring_type_id -66590 +77800 type_id -27500 +34329 unbound_id -174793 +209618 @@ -17190,7 +17260,7 @@ 1 2 -268986 +326745 @@ -17206,7 +17276,7 @@ 1 2 -268986 +326745 @@ -17222,7 +17292,7 @@ 1 2 -268986 +326745 @@ -17238,7 +17308,7 @@ 1 2 -268986 +326745 @@ -17254,27 +17324,32 @@ 1 2 -37823 +29682 2 3 -11142 +12552 3 -5 -4879 +4 +2436 -5 -31 -4418 +4 +7 +4763 -31 -20332 -634 +7 +66 +4039 + + +66 +26166 +352 @@ -17290,27 +17365,32 @@ 1 2 -37823 +29682 2 3 -11174 +12553 3 -5 -4870 +4 +2443 -5 -32 -4435 +4 +7 +4758 -32 -18333 -594 +7 +66 +4041 + + +66 +22680 +347 @@ -17326,99 +17406,104 @@ 1 2 -53616 +45461 2 +3 +4275 + + +3 +55 +4037 + + +58 +3744 +51 + + + + + + +name +unbound_id + + +12 + + +1 +2 +29905 + + +2 +3 +12628 + + +3 +5 +4979 + + +5 +13 +4389 + + +13 +5665 +1923 + + + + + + +declaring_type_id +id + + +12 + + +1 +2 +26097 + + +2 +3 +23827 + + +3 +4 +7432 + + +4 6 -4499 +6926 6 -3187 -781 - - - - - - -name -unbound_id - - -12 - - -1 -2 -38193 +10 +6616 -2 -3 -11213 +10 +25 +5868 -3 -5 -4821 - - -5 -55 -4419 - - -55 -5009 -250 - - - - - - -declaring_type_id -id - - -12 - - -1 -2 -21446 - - -2 -3 -21133 - - -3 -4 -5984 - - -4 -5 -4091 - - -5 -7 -3967 - - -7 -12 -5094 - - -12 -6356 -4875 +25 +3766 +1034 @@ -17434,37 +17519,37 @@ 1 2 -23866 +28521 2 3 -18876 +22076 3 4 -5924 +6893 4 -5 -4042 +6 +6926 -5 -7 -5519 +6 +9 +7156 -7 -11 -5515 +9 +36 +5835 -11 -6356 -2848 +36 +3766 +393 @@ -17480,32 +17565,32 @@ 1 2 -25457 +29504 2 3 -22110 +25881 3 4 -7831 +8656 4 -5 -4467 +6 +7061 -5 -12 -6097 +6 +13 +5868 -12 -51 -628 +13 +54 +830 @@ -17521,37 +17606,37 @@ 1 2 -21446 +26097 2 3 -21133 +23827 3 4 -5984 +7432 4 -5 -4091 +6 +6926 -5 -7 -3967 +6 +10 +6616 -7 -12 -5094 +10 +25 +5868 -12 -6356 -4875 +25 +3766 +1034 @@ -17567,27 +17652,27 @@ 1 2 -15184 +18227 2 3 -6965 +8740 3 4 -1444 +1980 4 7 -2106 +2891 7 -55172 -1801 +70171 +2491 @@ -17603,17 +17688,17 @@ 1 2 -23189 +28616 2 3 -2495 +3226 3 -19160 -1816 +17827 +2487 @@ -17629,27 +17714,27 @@ 1 2 -15664 +18941 2 3 -6934 +8659 3 4 -1415 +2056 4 8 -2095 +2771 8 -25360 -1392 +30299 +1902 @@ -17665,27 +17750,27 @@ 1 2 -15350 +18408 2 3 -7099 +9025 3 4 -1492 +2096 4 8 -2176 +2843 8 -37193 -1383 +41346 +1957 @@ -17701,12 +17786,12 @@ 1 2 -172012 +205640 2 -5604 -2781 +7099 +3978 @@ -17722,7 +17807,7 @@ 1 2 -174793 +209618 @@ -17738,12 +17823,12 @@ 1 2 -172012 +205640 2 -5604 -2781 +7099 +3978 @@ -17759,12 +17844,12 @@ 1 2 -173873 +200534 2 -1060 -920 +1517 +9084 @@ -17774,15 +17859,15 @@ property_location -621543 +596956 id -268771 +317336 loc -73027 +64445 @@ -17796,32 +17881,27 @@ 1 2 -137047 +170365 2 3 -73922 +91549 3 4 -19805 +15062 4 -6 -13360 +5 +28727 -6 -15 -20275 - - -15 -257 -4362 +5 +18 +11633 @@ -17837,12 +17917,12 @@ 1 2 -70153 +60908 2 29742 -2874 +3537 @@ -17852,27 +17932,27 @@ indexers -25314 +29544 id -25314 +29544 name -7 +49 declaring_type_id -18446 +21477 type_id -5634 +6092 unbound_id -2521 +3019 @@ -17886,7 +17966,7 @@ 1 2 -25314 +29544 @@ -17902,7 +17982,7 @@ 1 2 -25314 +29544 @@ -17918,7 +17998,7 @@ 1 2 -25314 +29544 @@ -17934,7 +18014,7 @@ 1 2 -25314 +29544 @@ -17950,23 +18030,33 @@ 1 2 -3 +11 2 3 +20 + + +3 +4 +8 + + +5 +10 +4 + + +10 +43 +4 + + +53 +29271 2 - -6 -7 -1 - - -25301 -25302 -1 - @@ -17981,23 +18071,33 @@ 1 2 -3 +11 2 3 +21 + + +3 +4 +7 + + +5 +10 +4 + + +10 +33 +4 + + +53 +21309 2 - -4 -5 -1 - - -18438 -18439 -1 - @@ -18012,17 +18112,17 @@ 1 2 -5 +37 -4 -5 -1 +2 +3 +10 -5631 -5632 -1 +14 +6068 +2 @@ -18038,21 +18138,31 @@ 1 2 -3 +11 2 3 -2 +21 -6 -7 -1 +3 +4 +8 -2508 -2509 +5 +11 +4 + + +21 +54 +4 + + +2780 +2781 1 @@ -18069,22 +18179,22 @@ 1 2 -14068 +16476 2 3 -2930 +3218 3 5 -1421 +1749 5 -7 -27 +11 +34 @@ -18100,12 +18210,12 @@ 1 2 -18443 +21440 2 -3 -3 +11 +37 @@ -18121,12 +18231,17 @@ 1 2 -14223 +16763 2 3 -4223 +4706 + + +3 +11 +8 @@ -18142,22 +18257,22 @@ 1 2 -14068 +16476 2 3 -2930 +3218 3 5 -1421 +1749 5 -7 -27 +11 +34 @@ -18173,37 +18288,42 @@ 1 2 -739 +869 2 3 -1537 +1573 3 4 -1740 +1581 4 5 -261 +382 5 6 -630 +681 6 7 -435 +458 7 -5790 -292 +15 +460 + + +15 +5910 +88 @@ -18219,12 +18339,12 @@ 1 2 -5629 +6080 2 -4 -5 +19 +12 @@ -18240,32 +18360,32 @@ 1 2 -786 +984 2 3 -1495 +1477 3 4 -2375 +2243 4 5 -550 +584 5 -32 -423 +8 +497 -44 -5703 -5 +8 +5744 +307 @@ -18281,37 +18401,37 @@ 1 2 -739 +938 2 3 -1537 +1689 3 4 -1776 +1624 4 5 -265 +317 5 6 -643 +726 6 -7 -425 +8 +552 -7 -1531 -249 +8 +1274 +246 @@ -18327,12 +18447,17 @@ 1 2 -2371 +2690 2 -3967 -150 +20 +227 + + +20 +4903 +102 @@ -18348,7 +18473,7 @@ 1 2 -2521 +3019 @@ -18364,12 +18489,17 @@ 1 2 -2371 +2690 2 -3967 -150 +20 +227 + + +20 +4903 +102 @@ -18385,12 +18515,17 @@ 1 2 -2407 +2786 2 -3967 -114 +555 +227 + + +562 +4006 +6 @@ -18400,15 +18535,15 @@ indexer_location -40309 +38478 id -25314 +29534 loc -1604 +1544 @@ -18422,22 +18557,17 @@ 1 2 -19371 +24841 2 3 -3547 +3236 3 -10 -1912 - - -10 -19 -484 +18 +1457 @@ -18453,37 +18583,37 @@ 1 2 -1040 +984 2 3 -77 +85 3 4 -72 +66 4 6 -120 +115 6 -14 -144 +13 +119 -14 -127 -121 +13 +57 +117 -127 -6138 -30 +59 +6373 +58 @@ -18493,11 +18623,11 @@ accessors -336633 +393080 id -336633 +393080 kind @@ -18505,15 +18635,15 @@ name -74791 +67062 declaring_member_id -286717 +339184 unbound_id -211967 +251384 @@ -18527,7 +18657,7 @@ 1 2 -336633 +393080 @@ -18543,7 +18673,7 @@ 1 2 -336633 +393080 @@ -18559,7 +18689,7 @@ 1 2 -336633 +393080 @@ -18575,7 +18705,7 @@ 1 2 -336633 +393080 @@ -18589,13 +18719,13 @@ 12 -50195 -50196 +54213 +54214 1 -286438 -286439 +338867 +338868 1 @@ -18610,13 +18740,13 @@ 12 -14093 -14094 +11762 +11763 1 -60698 -60699 +55300 +55301 1 @@ -18631,13 +18761,13 @@ 12 -50186 -50187 +52525 +52526 1 -286438 -286439 +338844 +338845 1 @@ -18652,13 +18782,13 @@ 12 -36119 -36120 +39797 +39798 1 -175848 -175849 +211587 +211588 1 @@ -18675,141 +18805,156 @@ 1 2 -46914 +35118 2 3 -15055 - - -3 -5 -6355 - - -5 -29 -5645 - - -29 -17446 -822 - - - - - - -name -kind - - -12 - - -1 -2 -74791 - - - - - - -name -declaring_member_id - - -12 - - -1 -2 -46917 - - -2 -3 -15053 - - -3 -5 -6354 - - -5 -29 -5645 - - -29 -17446 -822 - - - - - - -name -unbound_id - - -12 - - -1 -2 -47440 - - -2 -3 -15185 - - -3 -5 -6280 - - -5 -55 -5613 - - -55 -2297 -273 - - - - - - -declaring_member_id -id - - -12 - - -1 -2 -236810 - - -2 -3 -49898 +16521 3 4 -9 +3142 + + +4 +6 +5072 + + +6 +15 +5054 + + +15 +21474 +2155 + + + + + + +name +kind + + +12 + + +1 +2 +67062 + + + + + + +name +declaring_member_id + + +12 + + +1 +2 +35213 + + +2 +3 +16742 + + +3 +4 +3102 + + +4 +6 +4876 + + +6 +16 +5111 + + +16 +21474 +2018 + + + + + + +name +unbound_id + + +12 + + +1 +2 +35393 + + +2 +3 +16651 + + +3 +4 +3073 + + +4 +6 +5095 + + +6 +17 +5105 + + +17 +3014 +1745 + + + + + + +declaring_member_id +id + + +12 + + +1 +2 +286982 + + +2 +3 +50646 + + +3 +6 +1556 @@ -18825,12 +18970,12 @@ 1 2 -236810 +286999 2 3 -49907 +52185 @@ -18846,12 +18991,12 @@ 1 2 -236810 +286999 2 3 -49907 +52185 @@ -18867,17 +19012,17 @@ 1 2 -236810 +286982 2 3 -49898 +50646 3 -4 -9 +6 +1556 @@ -18893,12 +19038,12 @@ 1 2 -208543 +246685 2 -5604 -3424 +7099 +4699 @@ -18914,7 +19059,7 @@ 1 2 -211967 +251384 @@ -18930,7 +19075,7 @@ 1 2 -211967 +251384 @@ -18946,12 +19091,12 @@ 1 2 -208543 +246685 2 -5604 -3424 +7099 +4699 @@ -18961,15 +19106,15 @@ accessor_location -760991 +728766 id -336633 +393080 loc -87557 +75018 @@ -18983,27 +19128,27 @@ 1 2 -178438 +218037 2 3 -91540 +109741 3 4 -22414 +17821 4 -7 -27767 +5 +32479 -7 -257 -16474 +5 +18 +15002 @@ -19019,12 +19164,12 @@ 1 2 -84261 +70907 2 -38689 -3296 +39694 +4111 @@ -19034,27 +19179,27 @@ events -8976 +7794 id -8976 +7794 name -3901 +2035 declaring_type_id -2161 +2249 type_id -2621 +1984 unbound_id -8739 +7233 @@ -19068,7 +19213,7 @@ 1 2 -8976 +7794 @@ -19084,7 +19229,7 @@ 1 2 -8976 +7794 @@ -19100,7 +19245,7 @@ 1 2 -8976 +7794 @@ -19116,7 +19261,7 @@ 1 2 -8976 +7794 @@ -19132,27 +19277,37 @@ 1 2 -2559 +676 2 3 -356 +303 3 4 -557 +561 4 -9 -293 +5 +135 -9 -148 -136 +5 +7 +158 + + +7 +16 +157 + + +16 +173 +45 @@ -19168,22 +19323,32 @@ 1 2 -2559 +676 2 3 -824 +772 3 -6 -315 +4 +116 -6 -107 -203 +4 +5 +199 + + +5 +8 +154 + + +8 +125 +118 @@ -19199,17 +19364,22 @@ 1 2 -3548 +1496 2 +3 +268 + + +3 5 -304 +173 5 -26 -49 +27 +98 @@ -19225,325 +19395,335 @@ 1 2 -2577 +677 2 3 -351 +308 3 4 +556 + + +4 +5 +136 + + +5 +7 +159 + + +7 +16 +156 + + +16 +101 +43 + + + + + + +declaring_type_id +id + + +12 + + +1 +2 +970 + + +2 +3 554 -4 -10 -311 - - -10 -76 -108 - - - - - - -declaring_type_id -id - - -12 - - -1 -2 -877 - - -2 -3 -532 - - 3 4 -187 +192 4 5 -172 +177 5 -8 -181 - - -8 -19 -163 - - -19 -465 -49 - - - - - - -declaring_type_id -name - - -12 - - -1 -2 -1091 - - -2 -3 -429 - - -3 -4 -204 - - -4 -5 -112 - - -5 -8 -179 - - -8 -465 -146 - - - - - - -declaring_type_id -type_id - - -12 - - -1 -2 -1345 - - -2 -3 -373 - - -3 -4 -195 - - -4 -7 -166 - - -7 -181 -82 - - - - - - -declaring_type_id -unbound_id - - -12 - - -1 -2 -877 - - -2 -3 -532 - - -3 -4 -187 - - -4 -5 -172 - - -5 -8 -181 - - -8 -19 -163 - - -19 -465 -49 - - - - - - -type_id -id - - -12 - - -1 -2 -1063 - - -2 -3 -456 - - -3 -4 -764 - - -4 -7 -204 - - -7 -1070 -134 - - - - - - -type_id -name - - -12 - - -1 -2 -2009 - - -2 -3 -384 - - -3 9 -197 - - -9 -435 -31 - - - - - - -type_id -declaring_type_id - - -12 - - -1 -2 -1456 - - -2 -3 -987 - - -3 -363 -178 - - - - - - -type_id -unbound_id - - -12 - - -1 -2 -1065 - - -2 -3 -457 - - -3 -4 -763 - - -4 -7 206 +9 +127 +150 + + + + + + +declaring_type_id +name + + +12 + + +1 +2 +1184 + + +2 +3 +459 + + +3 +4 +205 + + +4 +6 +204 + + +6 +18 +169 + + +18 +127 +28 + + + + + + +declaring_type_id +type_id + + +12 + + +1 +2 +1282 + + +2 +3 +518 + + +3 +4 +182 + + +4 +7 +194 + + 7 -1059 -130 +39 +73 + + + + + + +declaring_type_id +unbound_id + + +12 + + +1 +2 +970 + + +2 +3 +554 + + +3 +4 +192 + + +4 +5 +177 + + +5 +9 +206 + + +9 +127 +150 + + + + + + +type_id +id + + +12 + + +1 +2 +643 + + +2 +3 +313 + + +3 +4 +717 + + +4 +6 +109 + + +6 +13 +152 + + +13 +1024 +50 + + + + + + +type_id +name + + +12 + + +1 +2 +1649 + + +2 +3 +204 + + +3 +402 +131 + + + + + + +type_id +declaring_type_id + + +12 + + +1 +2 +766 + + +2 +3 +1012 + + +3 +7 +169 + + +7 +346 +37 + + + + + + +type_id +unbound_id + + +12 + + +1 +2 +645 + + +2 +3 +313 + + +3 +4 +717 + + +4 +6 +110 + + +6 +13 +150 + + +13 +1024 +49 @@ -19559,12 +19739,12 @@ 1 2 -8689 +7200 2 33 -50 +33 @@ -19580,7 +19760,7 @@ 1 2 -8739 +7233 @@ -19596,12 +19776,12 @@ 1 2 -8689 +7200 2 33 -50 +33 @@ -19617,12 +19797,12 @@ 1 2 -8725 +6901 2 -26 -14 +6 +332 @@ -19632,15 +19812,15 @@ event_location -13927 +11829 id -8976 +7413 loc -1497 +1034 @@ -19654,17 +19834,22 @@ 1 2 -6948 +5015 2 3 -1532 +1707 3 -19 -496 +8 +567 + + +8 +11 +124 @@ -19680,22 +19865,32 @@ 1 2 -1123 +693 2 -4 -136 +3 +64 -4 -13 -126 +3 +6 +89 -13 +6 +14 +80 + + +14 +34 +78 + + +36 2320 -112 +30 @@ -19705,11 +19900,11 @@ event_accessors -15714 +13062 id -15714 +13062 kind @@ -19717,15 +19912,15 @@ name -7856 +4162 declaring_event_id -7857 +6326 unbound_id -15240 +12702 @@ -19739,7 +19934,7 @@ 1 2 -15714 +13062 @@ -19755,7 +19950,7 @@ 1 2 -15714 +13062 @@ -19771,7 +19966,7 @@ 1 2 -15714 +13062 @@ -19787,7 +19982,7 @@ 1 2 -15714 +13062 @@ -19801,8 +19996,8 @@ 12 -7857 -7858 +6531 +6532 2 @@ -19817,8 +20012,8 @@ 12 -3928 -3929 +2081 +2082 2 @@ -19833,8 +20028,8 @@ 12 -7857 -7858 +6326 +6327 2 @@ -19849,8 +20044,8 @@ 12 -7620 -7621 +6351 +6352 2 @@ -19867,22 +20062,32 @@ 1 2 -5204 +1424 2 3 -1630 +1530 3 -6 -616 +4 +210 -6 -97 -406 +4 +5 +448 + + +5 +9 +358 + + +9 +117 +192 @@ -19898,7 +20103,7 @@ 1 2 -7856 +4162 @@ -19914,22 +20119,32 @@ 1 2 -5204 +1436 2 3 -1630 +1560 3 -6 -616 +4 +220 -6 -97 -406 +4 +5 +434 + + +5 +9 +326 + + +9 +111 +186 @@ -19945,22 +20160,32 @@ 1 2 -5240 +1426 2 3 -1622 +1540 3 -6 -596 +4 +200 -6 -58 -398 +4 +5 +450 + + +5 +9 +356 + + +9 +78 +190 @@ -19976,7 +20201,12 @@ 2 3 -7857 +6176 + + +4 +11 +150 @@ -19992,7 +20222,7 @@ 2 3 -7857 +6326 @@ -20008,7 +20238,7 @@ 2 3 -7857 +6326 @@ -20024,7 +20254,12 @@ 2 3 -7857 +6176 + + +4 +11 +150 @@ -20040,12 +20275,12 @@ 1 2 -15140 +12636 2 33 -100 +66 @@ -20061,7 +20296,7 @@ 1 2 -15240 +12702 @@ -20077,7 +20312,7 @@ 1 2 -15240 +12702 @@ -20093,12 +20328,12 @@ 1 2 -15140 +12636 2 33 -100 +66 @@ -20108,15 +20343,15 @@ event_accessor_location -23116 +19010 id -15714 +13062 loc -1813 +1353 @@ -20130,17 +20365,22 @@ 1 2 -14122 +10644 2 -8 -1180 +3 +1092 -8 -19 -412 +3 +6 +994 + + +6 +11 +332 @@ -20156,27 +20396,32 @@ 1 2 -648 +634 2 3 -798 +382 4 7 -136 +119 8 -29 -137 +25 +108 -30 +26 +221 +102 + + +262 4639 -94 +8 @@ -20186,11 +20431,11 @@ operators -13320 +18266 id -13320 +18266 name @@ -20202,15 +20447,15 @@ declaring_type_id -5147 +5817 type_id -1724 +2366 unbound_id -7036 +10445 @@ -20224,7 +20469,7 @@ 1 2 -13320 +18266 @@ -20240,7 +20485,7 @@ 1 2 -13320 +18266 @@ -20256,7 +20501,7 @@ 1 2 -13320 +18266 @@ -20272,7 +20517,7 @@ 1 2 -13320 +18266 @@ -20288,7 +20533,7 @@ 1 2 -13320 +18266 @@ -20302,70 +20547,70 @@ 12 -4 -5 -2 - - -5 -6 -2 - - 6 -12 +7 +3 + + +9 +10 2 -12 -18 +19 +22 2 -20 -30 +28 +32 2 -31 -53 +43 +86 2 -94 -127 +107 +165 2 -128 -134 +178 +209 2 -142 -168 +212 +231 2 -205 -215 +253 +290 2 -332 -346 +298 +427 2 -723 -1751 +457 +1688 2 -4233 -4530 +2364 +5359 2 + +5757 +5758 +1 + @@ -20394,70 +20639,70 @@ 12 -4 -5 -2 - - -5 -6 -2 - - 6 -12 +7 +3 + + +9 +10 2 -12 -18 +19 +22 2 -20 -30 +28 +32 2 -31 -36 +42 +84 2 -47 -119 +84 +102 2 -124 -127 +163 +189 2 -129 -142 +192 +196 2 -201 -211 +229 +270 2 -330 -344 +278 +426 2 -432 -1105 +456 +720 2 -3261 -3558 +1349 +3839 2 + +4237 +4238 +1 + @@ -20475,58 +20720,53 @@ 2 -2 -3 -6 - - -3 -4 -1 - - 5 6 +7 + + +9 +10 2 -11 -13 +19 +22 2 -17 -21 -2 - - -29 +28 32 2 -35 -48 +43 +85 2 -103 -127 +85 +103 2 -141 -330 +164 +182 2 -342 -435 +230 +427 2 -882 -883 +457 +722 +2 + + +1182 +1183 1 @@ -20541,73 +20781,68 @@ 12 -4 -5 -2 - - -5 -6 -2 - - 6 -12 +7 +3 + + +9 +10 2 -12 -13 -1 - - -17 -18 +19 +22 2 28 -30 +32 2 -49 -86 +40 +83 2 -123 -129 +104 +162 2 -133 -140 +169 +209 2 -164 -206 +212 +228 2 -214 -330 +250 +290 2 -342 -380 +298 +424 2 -488 -1913 +454 +948 2 -2208 -2209 +1223 +2413 +2 + + +2811 +2812 1 @@ -20622,65 +20857,65 @@ 12 -4 -5 -2 - - -5 -6 -2 - - 6 -13 +7 +3 + + +9 +10 2 -17 -21 +19 +29 2 -29 -53 +31 +44 2 -94 -127 +107 +165 2 -128 -134 +178 +209 2 -173 -179 +212 +275 2 -205 -215 +289 +299 2 -332 -346 +315 +427 2 -723 -1751 +457 +1688 2 -4233 -4530 +2364 +5359 2 + +5757 +5758 +1 + @@ -20714,65 +20949,65 @@ 12 -4 -5 -2 - - -5 -6 -2 - - 6 -13 +7 +3 + + +9 +10 2 -17 -21 +19 +29 2 -29 -36 +31 +43 2 -47 -121 +83 +102 2 -124 -127 +163 +189 2 -129 -142 +192 +197 2 -201 -211 +229 +270 2 -330 -344 +278 +426 2 -432 -1105 +456 +720 2 -3261 -3558 +1349 +3839 2 + +4237 +4238 +1 + @@ -20790,53 +21025,48 @@ 2 -2 -3 -6 - - -3 -4 -1 - - 5 6 +7 + + +9 +10 2 -12 -18 +19 +29 2 -20 -30 +31 +44 2 -35 -48 +84 +103 2 -105 -127 +164 +183 2 -141 -330 +230 +427 2 -342 -435 +457 +722 2 -882 -883 +1182 +1183 1 @@ -20851,198 +21081,208 @@ 12 -4 -5 -2 - - -5 -6 -2 - - 6 -13 +7 +3 + + +9 +10 2 -17 -18 +19 +29 2 -29 -50 -2 - - -85 -124 -2 - - -128 -134 -2 - - -167 -176 -2 - - -205 -215 -2 - - -329 -343 -2 - - -379 -489 -2 - - -1912 -2209 -2 - - - - - - -declaring_type_id -id - - -12 - - -1 -2 -1742 - - -2 -3 -1542 - - -3 -4 -257 - - -4 -5 -1272 - - -5 -77 -334 - - - - - - -declaring_type_id -name - - -12 - - -1 -2 -1880 - - -2 -3 -2392 - - -3 -4 -476 - - -4 -14 -387 - - -14 -24 -12 - - - - - - -declaring_type_id -symbol - - -12 - - -1 -2 -1880 - - -2 -3 -2393 - - -3 -4 -475 - - -4 -13 -388 - - -15 -22 -11 - - - - - - -declaring_type_id -type_id - - -12 - - -1 -2 -3956 - - -2 -3 -890 - - -3 +31 41 -301 +2 + + +104 +162 +2 + + +169 +209 +2 + + +212 +272 +2 + + +289 +299 +2 + + +309 +424 +2 + + +454 +948 +2 + + +1223 +2413 +2 + + +2811 +2812 +1 + + + + + + +declaring_type_id +id + + +12 + + +1 +2 +1558 + + +2 +3 +1877 + + +3 +4 +306 + + +4 +5 +1290 + + +5 +7 +493 + + +7 +114 +293 + + + + + + +declaring_type_id +name + + +12 + + +1 +2 +1727 + + +2 +3 +2878 + + +3 +4 +588 + + +4 +7 +490 + + +7 +24 +134 + + + + + + +declaring_type_id +symbol + + +12 + + +1 +2 +1727 + + +2 +3 +2878 + + +3 +4 +588 + + +4 +7 +506 + + +7 +22 +118 + + + + + + +declaring_type_id +type_id + + +12 + + +1 +2 +4141 + + +2 +3 +1168 + + +3 +5 +474 + + +5 +60 +34 @@ -21058,27 +21298,32 @@ 1 2 -1742 +1558 2 3 -1542 +1877 3 4 -255 +303 4 5 -1273 +1290 5 -77 -335 +7 +494 + + +7 +114 +295 @@ -21094,22 +21339,27 @@ 1 2 -1083 +1331 2 3 -364 +576 3 4 -154 +228 4 -9483 -123 +18 +178 + + +18 +11857 +53 @@ -21125,22 +21375,22 @@ 1 2 -1305 +1779 2 3 -240 +307 3 5 -139 +185 5 18 -40 +95 @@ -21156,22 +21406,22 @@ 1 2 -1305 +1779 2 3 -241 +308 3 5 -143 +203 5 16 -35 +76 @@ -21187,17 +21437,17 @@ 1 2 -1553 +2031 2 -5 -135 +3 +181 -5 -4333 -36 +3 +4808 +154 @@ -21213,22 +21463,27 @@ 1 2 -1092 +1375 2 3 -367 +566 3 4 -157 +214 4 -4753 -108 +21 +182 + + +23 +5960 +29 @@ -21244,12 +21499,12 @@ 1 2 -6925 +10278 2 -954 -111 +957 +167 @@ -21265,7 +21520,7 @@ 1 2 -7036 +10445 @@ -21281,7 +21536,7 @@ 1 2 -7036 +10445 @@ -21297,12 +21552,12 @@ 1 2 -6925 +10278 2 -954 -111 +957 +167 @@ -21318,12 +21573,12 @@ 1 2 -6996 +10375 2 -316 -40 +436 +70 @@ -21333,15 +21588,15 @@ operator_location -26888 +27407 id -8870 +13504 loc -2942 +2763 @@ -21355,32 +21610,27 @@ 1 2 -5627 +8747 2 3 -1265 +2266 3 -5 -670 +4 +753 -5 -15 -602 +4 +8 +911 -15 +8 18 -699 - - -18 -21 -7 +827 @@ -21396,22 +21646,22 @@ 1 2 -2404 +2250 2 -5 -270 +4 +220 -5 -121 -221 +4 +58 +209 -136 -3457 -47 +58 +4153 +84 @@ -21421,15 +21671,15 @@ constant_value -109873 +149474 id -108394 +149448 value -26585 +25399 @@ -21443,12 +21693,12 @@ 1 2 -107086 +149422 2 -5 -1308 +3 +26 @@ -21464,22 +21714,27 @@ 1 2 -20463 +15881 2 3 -3137 +4778 3 -8 -2119 +5 +2077 -8 -8085 -866 +5 +12 +1909 + + +12 +10788 +754 @@ -21489,27 +21744,27 @@ methods -990339 +1183684 id -990339 +1183684 name -145323 +134084 declaring_type_id -115072 +133860 type_id -75864 +95938 unbound_id -416703 +526541 @@ -21523,7 +21778,7 @@ 1 2 -990339 +1183684 @@ -21539,7 +21794,7 @@ 1 2 -990339 +1183684 @@ -21555,7 +21810,7 @@ 1 2 -990339 +1183684 @@ -21571,7 +21826,7 @@ 1 2 -990339 +1183684 @@ -21587,27 +21842,27 @@ 1 2 -103232 +88559 2 3 -18945 +18867 3 5 -11241 +11037 5 -60 -10906 +13 +10205 -60 -33554 -999 +13 +41109 +5416 @@ -21623,22 +21878,27 @@ 1 2 -107949 +92496 2 3 -17436 +18555 3 -6 -12134 +5 +10104 -6 -17745 -7804 +5 +19 +10202 + + +19 +21909 +2727 @@ -21654,17 +21914,17 @@ 1 2 -134024 +118086 2 -124 -10936 +4 +10444 -124 -13470 -363 +4 +16981 +5554 @@ -21680,22 +21940,27 @@ 1 2 -105154 +89804 2 3 -19254 +19187 3 5 -11116 +11028 5 -8756 -9799 +15 +10315 + + +15 +9650 +3750 @@ -21711,47 +21976,47 @@ 1 2 -30339 +37015 2 3 -17979 +17719 3 4 -20209 +23020 4 5 -7063 +9486 5 6 -11230 +13094 6 10 -9248 +10992 10 21 -8656 +10067 21 82 -9133 +10827 82 -4659 -1215 +2721 +1640 @@ -21767,42 +22032,42 @@ 1 2 -31840 +39708 2 3 -18946 +20610 3 4 -20938 +24897 4 5 -10198 +10091 5 6 -9143 +10989 6 10 -8968 +10083 10 -22 -8901 +21 +10169 -22 +21 2630 -6138 +7313 @@ -21818,32 +22083,32 @@ 1 2 -46532 +53734 2 3 -36855 +44021 3 4 -8749 +9050 4 -5 -8055 +6 +12331 -5 -9 -8673 +6 +13 +10314 -9 -2310 -6208 +13 +1435 +4410 @@ -21859,47 +22124,47 @@ 1 2 -30464 +37120 2 3 -17990 +17732 3 4 -20224 +23026 4 5 -7078 +9496 5 6 -11238 +13109 6 10 -9259 +11009 10 -22 -8857 +21 +10050 -22 +21 82 -8820 +10745 82 -2631 -1142 +2634 +1573 @@ -21915,32 +22180,27 @@ 1 2 -45668 +58934 2 3 -13238 +16031 3 -4 -5192 +5 +8772 -4 -10 -5878 +5 +17 +7197 -10 -221 -5798 - - -224 -281834 -90 +17 +325334 +5004 @@ -21956,22 +22216,22 @@ 1 2 -56967 +74195 2 3 -7755 +8668 3 -7 -5788 +8 +7691 -7 -66425 -5354 +8 +61151 +5384 @@ -21987,22 +22247,22 @@ 1 2 -53716 +67793 2 3 -13964 +17642 3 -7 -6247 +6 +7213 -7 -56084 -1937 +6 +63071 +3290 @@ -22018,32 +22278,27 @@ 1 2 -45760 +58983 2 3 -13288 +16197 3 -4 -5214 +5 +8734 -4 -10 -5845 +5 +18 +7281 -10 -252 -5691 - - -254 -149113 -66 +18 +175281 +4743 @@ -22059,12 +22314,12 @@ 1 2 -401515 +504345 2 -8127 -15188 +10883 +22196 @@ -22080,7 +22335,7 @@ 1 2 -416703 +526541 @@ -22096,12 +22351,12 @@ 1 2 -404324 +507671 2 -8127 -12379 +10883 +18870 @@ -22117,12 +22372,12 @@ 1 2 -410109 +511409 2 -8127 -6594 +10889 +15132 @@ -22132,15 +22387,15 @@ method_location -2069011 +2029259 id -989823 +1176044 loc -225377 +207281 @@ -22154,27 +22409,27 @@ 1 2 -481413 +641931 2 3 -351054 +392731 3 4 -59147 +45310 4 9 -74877 +90857 9 -24 -23332 +18 +5215 @@ -22190,12 +22445,17 @@ 1 2 -213144 +190293 2 -117240 -12233 +97 +15549 + + +97 +122930 +1439 @@ -22205,23 +22465,23 @@ constructors -149144 +171824 id -149144 +171824 name -54143 +47516 declaring_type_id -101619 +112258 unbound_id -98805 +118081 @@ -22235,7 +22495,7 @@ 1 2 -149144 +171824 @@ -22251,7 +22511,7 @@ 1 2 -149144 +171824 @@ -22267,7 +22527,7 @@ 1 2 -149144 +171824 @@ -22283,22 +22543,27 @@ 1 2 -39528 +29299 2 3 -8842 +9048 3 +4 +2448 + + +4 7 -4536 +4174 7 -7428 -1237 +9204 +2547 @@ -22314,17 +22579,22 @@ 1 2 -47190 +34025 2 3 -4506 +7559 3 -5277 -2447 +6 +4238 + + +6 +6154 +1694 @@ -22340,22 +22610,27 @@ 1 2 -40238 +29766 2 3 -8855 +9080 3 +4 +2367 + + +4 7 -4181 +4051 7 -4418 -869 +3757 +2252 @@ -22371,22 +22646,22 @@ 1 2 -80662 +87385 2 3 -11743 +13079 3 -8 -7758 +7 +8631 -8 -42 -1456 +7 +84 +3163 @@ -22402,7 +22677,7 @@ 1 2 -101619 +112258 @@ -22418,22 +22693,22 @@ 1 2 -80662 +87383 2 3 -11743 +13081 3 -8 -7758 +7 +8629 -8 -42 -1456 +7 +84 +3165 @@ -22449,12 +22724,12 @@ 1 2 -96762 +115422 2 -3787 -2043 +1848 +2659 @@ -22470,7 +22745,7 @@ 1 2 -98805 +118081 @@ -22486,12 +22761,12 @@ 1 2 -96762 +115422 2 -3787 -2043 +1848 +2659 @@ -22501,15 +22776,15 @@ constructor_location -294390 +283625 id -149141 +171819 loc -44163 +37542 @@ -22523,27 +22798,22 @@ 1 2 -95933 +109508 2 3 -26780 +35225 3 4 -12519 +14677 4 -13 -11784 - - -13 -591 -2125 +17 +12409 @@ -22559,17 +22829,17 @@ 1 2 -39468 +33267 2 -7 -3388 +6 +2946 -7 -17601 -1307 +6 +17817 +1329 @@ -22579,23 +22849,23 @@ destructors -388 +569 id -388 +569 name -300 +313 declaring_type_id -388 +569 unbound_id -315 +503 @@ -22609,7 +22879,7 @@ 1 2 -388 +569 @@ -22625,7 +22895,7 @@ 1 2 -388 +569 @@ -22641,7 +22911,7 @@ 1 2 -388 +569 @@ -22657,12 +22927,22 @@ 1 2 -278 +214 2 -23 -22 +3 +61 + + +3 +6 +27 + + +6 +26 +11 @@ -22678,12 +22958,22 @@ 1 2 -278 +214 2 -23 -22 +3 +61 + + +3 +6 +27 + + +6 +26 +11 @@ -22699,12 +22989,22 @@ 1 2 -287 +217 2 -4 -13 +3 +62 + + +3 +6 +26 + + +6 +12 +8 @@ -22720,7 +23020,7 @@ 1 2 -388 +569 @@ -22736,7 +23036,7 @@ 1 2 -388 +569 @@ -22752,7 +23052,7 @@ 1 2 -388 +569 @@ -22768,12 +23068,12 @@ 1 2 -304 +491 2 -23 -11 +22 +12 @@ -22789,7 +23089,7 @@ 1 2 -315 +503 @@ -22805,12 +23105,12 @@ 1 2 -304 +491 2 -23 -11 +22 +12 @@ -22820,15 +23120,15 @@ destructor_location -1101 +1270 id -388 +569 loc -381 +371 @@ -22842,32 +23142,27 @@ 1 2 -197 +247 2 3 -69 +143 3 4 -38 +53 4 -7 -35 +5 +93 -7 -12 -35 - - -12 -18 -14 +5 +17 +33 @@ -22883,7 +23178,7 @@ 1 2 -256 +243 2 @@ -22898,17 +23193,17 @@ 4 6 -33 +32 6 -22 -29 +20 +28 -22 -33 -7 +20 +75 +12 @@ -22918,15 +23213,15 @@ overrides -117202 +157613 id -116553 +153631 base_id -31431 +45218 @@ -22940,12 +23235,12 @@ 1 2 -115904 +149718 2 -3 -649 +6 +3913 @@ -22961,27 +23256,32 @@ 1 2 -18013 +24514 2 3 -6343 +9725 3 4 -2243 +3456 4 7 -2620 +4118 7 -3939 -2212 +466 +3392 + + +466 +3858 +13 @@ -22991,15 +23291,15 @@ explicitly_implements -181041 +219576 id -181041 +219576 interface_id -21520 +26939 @@ -23013,7 +23313,7 @@ 1 2 -181041 +219576 @@ -23029,42 +23329,42 @@ 1 2 -8591 +10815 2 3 -4158 +5175 3 4 -1973 +2496 4 5 -666 +901 5 6 -2548 +3149 6 -10 -1626 +11 +2183 -10 -19 -1621 +11 +43 +2025 -19 -24037 -337 +43 +11723 +195 @@ -23074,11 +23374,11 @@ local_functions -1201 +1225 id -1201 +1225 name @@ -23086,11 +23386,11 @@ return_type -169 +173 unbound_id -1199 +1223 @@ -23104,7 +23404,7 @@ 1 2 -1201 +1225 @@ -23120,7 +23420,7 @@ 1 2 -1201 +1225 @@ -23136,7 +23436,7 @@ 1 2 -1201 +1225 @@ -23152,17 +23452,17 @@ 1 2 -668 +655 2 4 -60 +68 4 102 -27 +32 @@ -23178,12 +23478,12 @@ 1 2 -747 +746 2 4 -8 +9 @@ -23199,17 +23499,17 @@ 1 2 -669 +656 2 4 -59 +67 4 102 -27 +32 @@ -23235,12 +23535,17 @@ 3 5 -13 +15 5 -697 -12 +171 +13 + + +708 +709 +1 @@ -23256,7 +23561,7 @@ 1 2 -133 +135 2 @@ -23265,11 +23570,11 @@ 3 -8 -13 +7 +15 -15 +9 301 6 @@ -23297,12 +23602,17 @@ 3 5 -13 +15 5 -697 -12 +171 +13 + + +708 +709 +1 @@ -23318,7 +23628,7 @@ 1 2 -1198 +1222 3 @@ -23339,7 +23649,7 @@ 1 2 -1199 +1223 @@ -23355,7 +23665,7 @@ 1 2 -1198 +1222 3 @@ -23370,15 +23680,15 @@ local_function_stmts -1199 +1335 fn -1199 +1335 stmt -1199 +1223 @@ -23392,7 +23702,7 @@ 1 2 -1199 +1335 @@ -23408,7 +23718,12 @@ 1 2 -1199 +1163 + + +2 +4 +60 @@ -23418,11 +23733,11 @@ fields -285648 +345655 id -285648 +345655 kind @@ -23430,19 +23745,19 @@ name -127772 +119955 declaring_type_id -58158 +63411 type_id -47955 +61091 unbound_id -267317 +316899 @@ -23456,7 +23771,7 @@ 1 2 -285648 +345655 @@ -23472,7 +23787,7 @@ 1 2 -285648 +345655 @@ -23488,7 +23803,7 @@ 1 2 -285648 +345655 @@ -23504,7 +23819,7 @@ 1 2 -285648 +345655 @@ -23520,7 +23835,7 @@ 1 2 -285648 +345655 @@ -23534,13 +23849,13 @@ 12 -106769 -106770 +147707 +147708 1 -178578 -178579 +187149 +187150 1 @@ -23555,13 +23870,13 @@ 12 -54214 -54215 +49719 +49720 1 -76116 -76117 +72553 +72554 1 @@ -23576,13 +23891,13 @@ 12 -10999 -11000 +14304 +14305 1 -49829 -49830 +50951 +50952 1 @@ -23597,13 +23912,13 @@ 12 -7955 -7956 +10750 +10751 1 -41759 -41760 +52512 +52513 1 @@ -23618,13 +23933,13 @@ 12 -106161 -106162 +147035 +147036 1 -161161 -161162 +169869 +169870 1 @@ -23641,22 +23956,27 @@ 1 2 -101759 +79665 2 3 -13893 +21311 3 -9 -9606 +5 +9796 -9 -7502 -2514 +5 +92 +8997 + + +92 +6652 +186 @@ -23672,12 +23992,12 @@ 1 2 -125214 +117638 2 3 -2558 +2317 @@ -23693,22 +24013,27 @@ 1 2 -101759 +79665 2 3 -13893 +21311 3 -9 -9606 +5 +9796 -9 -7502 -2514 +5 +92 +8997 + + +92 +6652 +186 @@ -23724,17 +24049,22 @@ 1 2 -111990 +90184 2 3 -9417 +17169 3 -4791 -6365 +8 +9686 + + +8 +4099 +2916 @@ -23750,22 +24080,22 @@ 1 2 -102538 +80248 2 3 -13899 +21408 3 -11 -9600 +5 +9617 -11 -7502 -1735 +5 +6652 +8682 @@ -23781,42 +24111,42 @@ 1 2 -13468 +14274 2 3 -13970 +14991 3 4 -9308 +10294 4 5 -5925 +6512 5 6 -3861 +3957 6 8 -4917 +5374 8 -15 -4612 +14 +4901 -15 +14 4792 -2097 +3108 @@ -23832,12 +24162,12 @@ 1 2 -55488 +61567 2 3 -2670 +1844 @@ -23853,42 +24183,42 @@ 1 2 -13468 +14274 2 3 -13970 +14991 3 4 -9308 +10294 4 5 -5925 +6512 5 6 -3861 +3957 6 8 -4917 +5374 8 -15 -4612 +14 +4901 -15 +14 4792 -2097 +3108 @@ -23904,32 +24234,32 @@ 1 2 -23657 +28364 2 3 -16254 +15388 3 4 -6661 +7113 4 5 -3854 +3655 5 -7 -4345 +8 +5720 -7 +8 569 -3387 +3171 @@ -23945,42 +24275,42 @@ 1 2 -13468 +14274 2 3 -13970 +14991 3 4 -9308 +10294 4 5 -5925 +6512 5 6 -3861 +3957 6 8 -4917 +5374 8 -15 -4612 +14 +4901 -15 +14 4792 -2097 +3108 @@ -23996,32 +24326,32 @@ 1 2 -28567 +36047 2 3 -6526 +8714 3 4 -3634 +4830 4 6 -3781 +4598 6 15 -3728 +4677 15 -38777 -1719 +44112 +2225 @@ -24037,12 +24367,12 @@ 1 2 -46196 +58920 2 3 -1759 +2171 @@ -24058,27 +24388,27 @@ 1 2 -31776 +39393 2 3 -5924 +7943 3 4 -3057 +4291 4 7 -3977 +5065 7 -22007 -3221 +21402 +4399 @@ -24094,22 +24424,22 @@ 1 2 -36247 +46553 2 3 -5872 +8053 3 -6 -3680 +7 +4656 -6 -13299 -2156 +7 +13834 +1829 @@ -24125,32 +24455,32 @@ 1 2 -28687 +36177 2 3 -6534 +8726 3 4 -3601 +4784 4 6 -3767 +4580 6 15 -3691 +4634 15 -36782 -1675 +42017 +2190 @@ -24166,12 +24496,12 @@ 1 2 -264767 +314171 2 -954 -2550 +957 +2728 @@ -24187,7 +24517,7 @@ 1 2 -267312 +316894 2 @@ -24208,7 +24538,7 @@ 1 2 -267317 +316899 @@ -24224,12 +24554,12 @@ 1 2 -264767 +314171 2 -954 -2550 +957 +2728 @@ -24245,12 +24575,12 @@ 1 2 -265821 +305378 2 -954 -1496 +957 +11521 @@ -24260,15 +24590,15 @@ field_location -665606 +680142 id -283536 +327265 loc -100719 +93985 @@ -24282,27 +24612,27 @@ 1 2 -110804 +114298 2 3 -112944 +143264 3 4 -21535 +28161 4 -7 -25436 +5 +32658 -7 -534 -12817 +5 +18 +8884 @@ -24318,12 +24648,17 @@ 1 2 -95087 +83759 2 +5 +7464 + + +5 9082 -5632 +2762 @@ -24333,11 +24668,11 @@ localvars -309450 +291058 id -309450 +291058 kind @@ -24345,7 +24680,7 @@ name -50758 +45721 implicitly_typed @@ -24353,11 +24688,11 @@ type_id -19087 +18890 parent_id -309450 +291058 @@ -24371,7 +24706,7 @@ 1 2 -309450 +291058 @@ -24387,7 +24722,7 @@ 1 2 -309450 +291058 @@ -24403,7 +24738,7 @@ 1 2 -309450 +291058 @@ -24419,7 +24754,7 @@ 1 2 -309450 +291058 @@ -24435,7 +24770,7 @@ 1 2 -309450 +291058 @@ -24449,18 +24784,18 @@ 12 -54 -55 +70 +71 1 -1627 -1628 +1741 +1742 1 -307769 -307770 +289247 +289248 1 @@ -24480,13 +24815,13 @@ 1 -783 -784 +719 +720 1 -50117 -50118 +45123 +45124 1 @@ -24522,18 +24857,18 @@ 12 -21 -22 +29 +30 1 -43 -44 +49 +50 1 -19072 -19073 +18869 +18870 1 @@ -24548,18 +24883,18 @@ 12 -54 -55 +70 +71 1 -1627 -1628 +1741 +1742 1 -307769 -307770 +289247 +289248 1 @@ -24576,339 +24911,349 @@ 1 2 -31599 +27463 2 3 -8221 +7549 3 4 -3292 - - -4 -8 -4188 - - -8 -14339 -3458 - - - - - - -name -kind - - -12 - - -1 -2 -50585 - - -2 -3 -173 - - - - - - -name -implicitly_typed - - -12 - - -1 -2 -45779 - - -2 -3 -4979 - - - - - - -name -type_id - - -12 - - -1 -2 -43415 - - -2 -3 -4121 - - -3 -1514 -3222 - - - - - - -name -parent_id - - -12 - - -1 -2 -31599 - - -2 -3 -8221 - - -3 -4 -3292 - - -4 -8 -4188 - - -8 -14339 -3458 - - - - - - -implicitly_typed -id - - -12 - - -119948 -119949 -1 - - -189502 -189503 -1 - - - - - - -implicitly_typed -kind - - -12 - - -1 -2 -1 - - -3 -4 -1 - - - - - - -implicitly_typed -name - - -12 - - -27809 -27810 -1 - - -27928 -27929 -1 - - - - - - -implicitly_typed -type_id - - -12 - - -9524 -9525 -1 - - -12356 -12357 -1 - - - - - - -implicitly_typed -parent_id - - -12 - - -119948 -119949 -1 - - -189502 -189503 -1 - - - - - - -type_id -id - - -12 - - -1 -2 -8834 - - -2 -3 -3200 - - -3 -4 -1561 - - -4 -6 -1732 - - -6 -10 -1473 - - -10 -29 -1446 - - -29 -57038 -841 - - - - - - -type_id -kind - - -12 - - -1 -2 -19041 - - -2 -4 -46 - - - - - - -type_id -name - - -12 - - -1 -2 -11861 - - -2 -3 -3127 - - -3 -4 -1302 +3193 4 7 -1505 +3665 7 -5718 -1292 +76 +3434 + + +76 +14308 +417 + + + + + + +name +kind + + +12 + + +1 +2 +45569 + + +2 +3 +152 + + + + + + +name +implicitly_typed + + +12 + + +1 +2 +41398 + + +2 +3 +4323 + + + + + + +name +type_id + + +12 + + +1 +2 +38504 + + +2 +3 +4024 + + +3 +1437 +3193 + + + + + + +name +parent_id + + +12 + + +1 +2 +27463 + + +2 +3 +7549 + + +3 +4 +3193 + + +4 +7 +3665 + + +7 +76 +3434 + + +76 +14308 +417 + + + + + + +implicitly_typed +id + + +12 + + +120891 +120892 +1 + + +170167 +170168 +1 + + + + + + +implicitly_typed +kind + + +12 + + +1 +2 +1 + + +3 +4 +1 + + + + + + +implicitly_typed +name + + +12 + + +23673 +23674 +1 + + +26371 +26372 +1 + + + + + + +implicitly_typed +type_id + + +12 + + +10122 +10123 +1 + + +11399 +11400 +1 + + + + + + +implicitly_typed +parent_id + + +12 + + +120891 +120892 +1 + + +170167 +170168 +1 + + + + + + +type_id +id + + +12 + + +1 +2 +8936 + + +2 +3 +3256 + + +3 +4 +1573 + + +4 +6 +1639 + + +6 +10 +1418 + + +10 +34 +1423 + + +34 +54940 +645 + + + + + + +type_id +kind + + +12 + + +1 +2 +18836 + + +2 +4 +54 + + + + + + +type_id +name + + +12 + + +1 +2 +11811 + + +2 +3 +3125 + + +3 +4 +1288 + + +4 +7 +1453 + + +7 +5354 +1213 @@ -24924,12 +25269,12 @@ 1 2 -16294 +16259 2 3 -2793 +2631 @@ -24945,37 +25290,37 @@ 1 2 -8834 +8936 2 3 -3200 +3256 3 4 -1561 +1573 4 6 -1732 +1639 6 10 -1473 +1418 10 -29 -1446 +34 +1423 -29 -57038 -841 +34 +54940 +645 @@ -24991,7 +25336,7 @@ 1 2 -309450 +291058 @@ -25007,7 +25352,7 @@ 1 2 -309450 +291058 @@ -25023,7 +25368,7 @@ 1 2 -309450 +291058 @@ -25039,7 +25384,7 @@ 1 2 -309450 +291058 @@ -25055,7 +25400,7 @@ 1 2 -309450 +291058 @@ -25065,15 +25410,15 @@ localvar_location -309450 +291058 id -309450 +291058 loc -309085 +278972 @@ -25087,7 +25432,7 @@ 1 2 -309450 +291058 @@ -25103,12 +25448,12 @@ 1 2 -308720 +272069 2 -3 -365 +129 +6903 @@ -25118,19 +25463,19 @@ params -1662795 +2097984 id -1662795 +2097984 name -48172 +44551 type_id -127333 +175674 index @@ -25142,11 +25487,11 @@ parent_id -1009707 +1234259 unbound_id -709589 +987535 @@ -25160,7 +25505,7 @@ 1 2 -1662795 +2097984 @@ -25176,7 +25521,7 @@ 1 2 -1662795 +2097984 @@ -25192,7 +25537,7 @@ 1 2 -1662795 +2097984 @@ -25208,7 +25553,7 @@ 1 2 -1662795 +2097984 @@ -25224,7 +25569,7 @@ 1 2 -1662795 +2097984 @@ -25240,7 +25585,7 @@ 1 2 -1662795 +2097984 @@ -25256,130 +25601,140 @@ 1 2 -18527 +14198 2 3 -8846 +7897 3 4 -4277 +4014 4 5 -3465 - - -5 -8 -4374 - - -8 -15 -3854 - - -15 -65 -3617 - - -65 -115038 -1212 - - - - - - -name -type_id - - -12 - - -1 -2 -38960 - - -2 -3 -4760 - - -3 -12 -3615 - - -12 -13741 -837 - - - - - - -name -index - - -12 - - -1 -2 -32920 - - -2 -3 -8631 - - -3 -4 -3251 - - -4 -28 -3370 - - - - - - -name -mode - - -12 - - -1 -2 -44430 - - -2 -5 -3689 +3556 5 7 -53 +3451 + + +7 +11 +3507 + + +11 +21 +3528 + + +21 +104 +3342 + + +104 +140662 +1058 + + + + + + +name +type_id + + +12 + + +1 +2 +32125 + + +2 +3 +5671 + + +3 +5 +3322 + + +5 +372 +3342 + + +376 +16189 +91 + + + + + + +name +index + + +12 + + +1 +2 +30618 + + +2 +3 +7837 + + +3 +4 +3003 + + +4 +28 +3093 + + + + + + +name +mode + + +12 + + +1 +2 +41046 + + +2 +5 +3456 + + +5 +7 +49 @@ -25395,42 +25750,47 @@ 1 2 -18527 +14198 2 3 -8846 +7897 3 4 -4277 +4014 4 5 -3465 +3556 5 -8 -4374 +7 +3451 -8 -15 -3854 +7 +11 +3507 -15 -65 -3617 +11 +21 +3528 -65 -115038 -1212 +21 +104 +3342 + + +104 +140662 +1058 @@ -25446,42 +25806,47 @@ 1 2 -19226 +14654 2 3 -9088 +8134 3 4 -4287 +4041 4 5 -3445 +3605 5 -8 -4279 +7 +3383 -8 -15 -3620 +7 +11 +3502 -15 -107 -3613 +11 +22 +3393 -107 -59449 -614 +22 +202 +3342 + + +202 +78950 +497 @@ -25497,37 +25862,37 @@ 1 2 -66747 +95806 2 3 -14274 +20579 3 4 -7070 +9813 4 5 -10049 +12543 5 -8 -10159 +9 +14829 -8 -16 -10230 +9 +20 +13388 -16 -250157 -8804 +20 +307642 +8716 @@ -25543,22 +25908,22 @@ 1 2 -98326 +138567 2 3 -13720 +18845 3 -6 -10307 +7 +13967 -6 -7254 -4980 +7 +6231 +4295 @@ -25574,22 +25939,22 @@ 1 2 -95270 +135400 2 3 -20230 +26087 3 -5 -10443 +7 +13560 -5 +7 50 -1390 +627 @@ -25605,12 +25970,12 @@ 1 2 -119091 +165275 2 6 -8242 +10399 @@ -25626,37 +25991,37 @@ 1 2 -67557 +97258 2 3 -15267 +21625 3 4 -7257 +10035 4 5 -8928 +10868 5 -8 -9845 +9 +14535 -8 -16 -10012 +9 +21 +13364 -16 -203397 -8467 +21 +247760 +7989 @@ -25672,37 +26037,37 @@ 1 2 -67273 +96636 2 3 -14078 +20263 3 4 -7143 +10275 4 5 -10798 +13284 5 8 -10706 +13488 8 -17 -10208 +19 +13600 -17 -82653 -7127 +19 +105466 +8128 @@ -25721,48 +26086,48 @@ 11 -2 -3 +5 +6 8 -6 -19 +9 +28 4 -20 -37 +31 +56 4 -42 -68 +63 +109 4 -74 -119 +124 +234 4 -285 -932 +476 +1355 4 -1269 -3439 +1804 +4752 4 -5388 -26515 +7904 +37970 4 -60694 -1006637 +83795 +1234260 4 @@ -25787,110 +26152,110 @@ 8 -4 -10 -4 - - -11 -21 -4 - - -21 -32 -4 - - -36 -56 -4 - - -80 -187 -4 - - -270 -852 -4 - - -1380 -5216 -4 - - -8435 -22372 -4 - - - - - - -index -type_id - - -12 - - -1 -2 -11 - - -2 -3 -8 - - -4 +3 9 4 10 -15 -2 - - -16 -20 -4 - - -25 -27 +17 3 -32 -176 +18 +26 4 -297 -767 +28 +42 4 -936 -1850 +48 +126 4 -2277 -8796 +166 +532 4 -17296 -92711 -3 +781 +3084 +4 + + +4858 +17361 +4 + + +20606 +20607 +1 + + + + + + +index +type_id + + +12 + + +1 +2 +11 + + +5 +6 +8 + + +7 +13 +4 + + +15 +23 +4 + + +23 +51 +4 + + +56 +101 +4 + + +278 +841 +4 + + +1072 +1974 +4 + + +2807 +6378 +4 + + +12473 +122056 +4 @@ -25950,48 +26315,48 @@ 11 -2 -3 +5 +6 8 -6 -19 +9 +28 4 -20 -37 +31 +56 4 -42 -68 +63 +109 4 -74 -119 +124 +234 4 -285 -932 +476 +1355 4 -1269 -3439 +1804 +4752 4 -5388 -26515 +7904 +37970 4 -60694 -1006637 +83795 +1234260 4 @@ -26011,48 +26376,48 @@ 11 -2 -3 +5 +6 8 -6 -19 +9 +28 4 -20 -37 +31 +56 4 -42 -68 +63 +109 4 -74 -119 +124 +234 4 -174 -451 +341 +766 4 -664 -2379 +1065 +3474 4 -3992 -20329 +6189 +30065 4 -38390 -389589 +56290 +522599 4 @@ -26067,33 +26432,33 @@ 12 -733 -734 +922 +923 1 -6510 -6511 +6880 +6881 1 -13337 -13338 +17011 +17012 1 -20276 -20277 +28998 +28999 1 -30458 -30459 +40324 +40325 1 -1591179 -1591180 +2002611 +2002612 1 @@ -26113,28 +26478,28 @@ 1 -483 -484 +395 +396 1 -1013 -1014 +877 +878 1 -2257 -2258 +2127 +2128 1 -5499 -5500 +5406 +5407 1 -43559 -43560 +40079 +40080 1 @@ -26149,33 +26514,33 @@ 12 -147 -148 +180 +181 1 -1038 -1039 +1278 +1279 1 -2115 -2116 +2819 +2820 1 -4196 -4197 +7076 +7077 1 -5987 -5988 +11152 +11153 1 -123175 -123176 +164786 +164787 1 @@ -26231,33 +26596,33 @@ 12 -652 -653 +839 +840 1 -6510 -6511 +6880 +6881 1 -10961 -10962 +14029 +14030 1 -20276 -20277 +28998 +28999 1 -24590 -24591 +31219 +31220 1 -991551 -991552 +1210324 +1210325 1 @@ -26272,33 +26637,33 @@ 12 -353 -354 +463 +464 1 -3872 -3873 +4979 +4980 1 -10322 -10323 +14099 +14100 1 -10847 -10848 +17330 +17331 1 -21440 -21441 +29956 +29957 1 -662845 -662846 +920725 +920726 1 @@ -26315,22 +26680,22 @@ 1 2 -614133 +728545 2 3 -263888 +327567 3 4 -71715 +94352 4 52 -59971 +83795 @@ -26346,22 +26711,22 @@ 1 2 -614072 +728528 2 3 -263868 +327562 3 4 -71736 +94369 4 52 -60031 +83800 @@ -26377,22 +26742,22 @@ 1 2 -660352 +787670 2 3 -255417 +315961 3 5 -77910 +106814 5 41 -16028 +23814 @@ -26408,22 +26773,22 @@ 1 2 -614133 +728545 2 3 -263888 +327567 3 4 -71715 +94352 4 52 -59971 +83795 @@ -26439,12 +26804,12 @@ 1 2 -966434 +1178256 2 5 -43273 +56003 @@ -26460,22 +26825,22 @@ 1 2 -614125 +728513 2 3 -263896 +327545 3 4 -71715 +94316 4 52 -59971 +83885 @@ -26491,12 +26856,12 @@ 1 2 -681004 +945854 2 -15458 -28585 +9523 +41681 @@ -26512,12 +26877,12 @@ 1 2 -709322 +987486 2 -4 -267 +3 +49 @@ -26533,12 +26898,12 @@ 1 2 -698010 +968168 2 -5635 -11579 +6040 +19367 @@ -26554,7 +26919,7 @@ 1 2 -709589 +987535 @@ -26570,12 +26935,12 @@ 1 2 -709499 +987518 2 3 -90 +17 @@ -26591,12 +26956,12 @@ 1 2 -681004 +945854 2 -15458 -28585 +9523 +41681 @@ -26606,15 +26971,15 @@ param_location -3009317 +2973125 id -1650966 +2084755 loc -370027 +335646 @@ -26628,27 +26993,22 @@ 1 2 -1174826 +1599701 2 3 -203043 +253142 3 -4 -134596 +5 +191770 -4 -15 -131678 - - -15 -534 -6823 +5 +17 +40142 @@ -26664,12 +27024,17 @@ 1 2 -345724 +299339 2 -215283 -24303 +4 +25464 + + +4 +207747 +10843 @@ -26679,11 +27044,11 @@ statements -1789979 +1723240 id -1789979 +1723240 kind @@ -26701,7 +27066,7 @@ 1 2 -1789979 +1723240 @@ -26716,82 +27081,82 @@ 18 -187 +170 2 -234 -253 +241 +245 2 -301 -331 +266 +329 2 -349 -440 +342 +449 2 -783 -795 +825 +1208 2 -1199 -1201 +1269 +1298 2 -1334 -1624 +1335 +1736 2 -1831 -3271 +1789 +3175 2 -4304 -4712 +4219 +4301 2 -6120 -6287 +4524 +6193 2 8021 -8190 +8295 2 -11629 -17069 +10100 +16414 2 -53160 -62808 +53221 +63216 2 -158006 -172167 +154912 +166462 2 -269815 -483216 +253667 +470590 2 -510339 -510340 +484425 +484426 1 @@ -26802,19 +27167,19 @@ stmt_parent -1511647 +1456112 stmt -1511647 +1456112 index -2123 +437 parent -672991 +653326 @@ -26828,7 +27193,7 @@ 1 2 -1511647 +1456112 @@ -26844,7 +27209,7 @@ 1 2 -1511647 +1456112 @@ -26860,22 +27225,72 @@ 1 2 -1686 +34 -2 -16 -162 +4 +5 +36 -16 -98 -160 +6 +10 +23 -99 -477408 -115 +10 +11 +18 + + +11 +13 +37 + + +13 +19 +33 + + +19 +27 +39 + + +28 +36 +34 + + +36 +58 +35 + + +59 +102 +33 + + +103 +187 +33 + + +191 +566 +33 + + +611 +5634 +33 + + +6311 +464364 +16 @@ -26891,22 +27306,72 @@ 1 2 -1686 +34 -2 -16 -162 +4 +5 +36 -16 -98 -160 +6 +10 +23 -99 -477408 -115 +10 +11 +18 + + +11 +13 +37 + + +13 +19 +33 + + +19 +27 +39 + + +28 +36 +34 + + +36 +58 +35 + + +59 +102 +33 + + +103 +187 +33 + + +191 +566 +33 + + +611 +5634 +33 + + +6311 +464364 +16 @@ -26922,27 +27387,27 @@ 1 2 -417292 +406302 2 3 -117594 +114821 3 4 -47441 +45603 4 7 -56561 +54347 7 -2123 -34103 +437 +32253 @@ -26958,27 +27423,27 @@ 1 2 -417292 +406302 2 3 -117594 +114821 3 4 -47441 +45603 4 7 -56561 +54347 7 -2123 -34103 +437 +32253 @@ -26988,11 +27453,11 @@ stmt_parent_top_level -278332 +267128 stmt -278332 +267128 index @@ -27000,7 +27465,7 @@ parent -250974 +245404 @@ -27014,7 +27479,7 @@ 1 2 -278332 +267128 @@ -27030,7 +27495,7 @@ 1 2 -278332 +267128 @@ -27044,8 +27509,8 @@ 12 -278332 -278333 +267128 +267129 1 @@ -27060,8 +27525,8 @@ 12 -250974 -250975 +245404 +245405 1 @@ -27078,17 +27543,12 @@ 1 2 -223812 +223680 2 3 -26967 - - -3 -5 -195 +21724 @@ -27104,7 +27564,7 @@ 1 2 -250974 +245404 @@ -27114,15 +27574,15 @@ stmt_location -1789979 +1723240 id -1789979 +1723240 loc -1784517 +1626301 @@ -27136,7 +27596,7 @@ 1 2 -1789979 +1723240 @@ -27152,12 +27612,12 @@ 1 2 -1781311 +1574917 2 -45 -3206 +129 +51384 @@ -27167,15 +27627,15 @@ catch_type -4711 +4524 catch_id -4711 +4524 type_id -163 +249 kind @@ -27193,7 +27653,7 @@ 1 2 -4711 +4524 @@ -27209,7 +27669,7 @@ 1 2 -4711 +4524 @@ -27225,47 +27685,47 @@ 1 2 -48 +73 2 3 -27 +41 3 4 -14 +21 4 5 -11 +28 5 8 -15 +18 8 -11 -15 +12 +22 -11 -28 -13 +12 +22 +19 -30 -91 -13 +22 +111 +19 -114 -1687 -7 +134 +766 +8 @@ -27281,7 +27741,7 @@ 1 2 -163 +249 @@ -27295,13 +27755,13 @@ 12 -758 -759 +685 +686 1 -3953 -3954 +3839 +3840 1 @@ -27316,13 +27776,13 @@ 12 -1 -2 +6 +7 1 -162 -163 +243 +244 1 @@ -27333,19 +27793,19 @@ expressions -7417345 +7076055 id -7417345 +7076055 kind -106 +105 type_id -63982 +64483 @@ -27359,7 +27819,7 @@ 1 2 -7417345 +7076055 @@ -27375,7 +27835,7 @@ 1 2 -7417345 +7076055 @@ -27390,73 +27850,73 @@ 8 -50 +49 8 -69 -143 +54 +132 8 -178 -409 +145 +383 8 -435 -657 +403 +635 8 -715 -1216 +672 +1183 8 -1258 -2153 +1261 +2435 8 -2309 -4322 +2931 +4041 8 -4350 -7103 +4200 +6566 8 -7270 -12714 +7195 +12260 8 -14417 -22533 +13572 +22296 8 -24042 -32766 +24651 +40915 8 -41161 -212777 +52803 +275066 8 -268458 -724743 +291172 +873672 8 -928336 -1050543 -2 +991740 +991741 +1 @@ -27472,57 +27932,57 @@ 1 2 -29 +33 2 -6 -8 +7 +5 -6 +7 8 8 8 -12 +14 8 -13 -55 +23 +62 8 -59 -114 +64 +152 8 -115 -319 +164 +419 8 -327 -1055 +532 +1073 8 -1063 -2159 +1104 +4709 8 -2975 -17362 +6810 +18882 8 -18530 -20120 -5 +18895 +20864 +3 @@ -27538,57 +27998,57 @@ 1 2 -14334 +14844 2 3 -5964 +6684 3 4 -3755 +4053 4 5 -4381 +4062 5 7 -5869 +5754 7 10 -5162 +4976 10 15 -5056 +5000 15 24 -4964 +4858 24 -44 -4940 +45 +4995 -44 -108 -4809 +45 +115 +4837 -108 -977236 -4748 +115 +911533 +4420 @@ -27604,42 +28064,42 @@ 1 2 -26518 +27769 2 3 -8251 +7925 3 4 -9231 +9070 4 5 -5758 +5626 5 6 -3874 +3807 6 8 -4706 +4690 8 13 -4969 +4982 13 56 -675 +614 @@ -27649,11 +28109,11 @@ expr_parent -7178046 +6837747 expr -7178046 +6837747 index @@ -27661,7 +28121,7 @@ parent -4743008 +4501731 @@ -27675,7 +28135,7 @@ 1 2 -7178046 +6837747 @@ -27691,7 +28151,7 @@ 1 2 -7178046 +6837747 @@ -27712,21 +28172,26 @@ 2 3 -3435 +1 3 4 -2522 +3434 4 -9 +5 +2522 + + +5 +10 699 -9 -3426742 +10 +3276180 516 @@ -27748,21 +28213,26 @@ 2 3 -3435 +1 3 4 -2522 +3434 4 -9 +5 +2522 + + +5 +10 699 -9 -3426742 +10 +3276180 516 @@ -27779,22 +28249,22 @@ 1 2 -2972682 +2815953 2 3 -1395233 +1327530 3 7 -359960 +343499 7 8193 -15133 +14749 @@ -27810,22 +28280,22 @@ 1 2 -2972682 +2815953 2 3 -1395233 +1327530 3 7 -359960 +343499 7 8193 -15133 +14749 @@ -27835,11 +28305,11 @@ expr_parent_top_level -239299 +238308 expr -239299 +238308 index @@ -27847,7 +28317,7 @@ parent -179958 +185165 @@ -27861,7 +28331,7 @@ 1 2 -239299 +238308 @@ -27877,7 +28347,7 @@ 1 2 -239299 +238308 @@ -27891,48 +28361,48 @@ 12 -13 -14 +12 +13 1 -39 -40 +26 +27 1 -135 -136 +98 +99 1 -383 -384 +243 +244 1 -1297 -1298 +942 +943 1 -3062 -3063 +2399 +2400 1 -9978 -9979 +9066 +9067 1 -46561 -46562 +44849 +44850 1 -177831 -177832 +180673 +180674 1 @@ -27947,48 +28417,48 @@ 12 -13 -14 +12 +13 1 -39 -40 +26 +27 1 -135 -136 +98 +99 1 -383 -384 +243 +244 1 -1297 -1298 +942 +943 1 -3062 -3063 +2399 +2400 1 -9593 -9594 +8788 +8789 1 -46561 -46562 +44849 +44850 1 -169840 -169841 +175784 +175785 1 @@ -28005,17 +28475,17 @@ 1 2 -126296 +135742 2 3 -50329 +47024 3 -129 -3333 +9 +2399 @@ -28031,17 +28501,17 @@ 1 2 -133922 +140909 2 3 -42974 +41857 3 9 -3062 +2399 @@ -28051,22 +28521,22 @@ implicitly_typed_array_creation -12576 +11665 id -12576 +11665 explicitly_sized_array_creation -4077 +4292 id -4077 +4292 @@ -28115,26 +28585,26 @@ expr_compiler_generated -593552 +565505 id -593552 +565505 expr_value -1399433 +1376292 id -1399433 +1376292 value -185734 +170997 @@ -28148,7 +28618,7 @@ 1 2 -1399433 +1376292 @@ -28164,22 +28634,22 @@ 1 2 -135437 +124844 2 3 -25714 +23274 3 7 -15324 +13927 7 -144837 -9259 +142428 +8952 @@ -28189,15 +28659,15 @@ expr_call -1347739 +1301429 caller_id -1347739 +1301429 target_id -157393 +157417 @@ -28211,7 +28681,7 @@ 1 2 -1347739 +1301429 @@ -28227,32 +28697,32 @@ 1 2 -85183 +85870 2 3 -29466 +29491 3 4 -12338 +12178 4 7 -14239 +14128 7 -25 -11905 +27 +11933 -25 -35631 -4262 +27 +35604 +3817 @@ -28262,15 +28732,15 @@ expr_access -2855307 +2739712 accesser_id -2855307 +2739712 target_id -725838 +704804 @@ -28284,7 +28754,7 @@ 1 2 -2855307 +2739712 @@ -28300,37 +28770,37 @@ 1 2 -216414 +211418 2 3 -211536 +204592 3 4 -116569 +113092 4 5 -63157 +61793 5 7 -55255 +53915 7 -24 -54454 +26 +52934 -24 +26 20125 -8453 +7060 @@ -28340,15 +28810,15 @@ expr_location -7417345 +7076055 id -7417345 +7076055 loc -6768067 +6141754 @@ -28362,7 +28832,7 @@ 1 2 -7417345 +7076055 @@ -28378,17 +28848,17 @@ 1 2 -6140047 +5428525 2 3 -613291 +624132 3 143 -14729 +89097 @@ -28398,15 +28868,15 @@ dynamic_member_name -977 +161 id -977 +161 name -294 +33 @@ -28420,7 +28890,7 @@ 1 2 -977 +161 @@ -28436,32 +28906,42 @@ 1 2 -155 +16 2 3 -50 +2 3 4 -31 +3 4 5 -23 +3 -5 -14 -24 +7 +8 +2 -14 -106 -11 +8 +9 +3 + + +12 +19 +3 + + +39 +40 +1 @@ -28471,22 +28951,22 @@ conditional_access -3445 +3675 id -3445 +3675 expr_argument -1536561 +1471073 id -1536561 +1471073 mode @@ -28504,7 +28984,7 @@ 1 2 -1536561 +1471073 @@ -28518,23 +28998,23 @@ 12 -123 -124 +143 +144 1 -10881 -10882 +11416 +11417 1 -16880 -16881 +17078 +17079 1 -1508677 -1508678 +1442436 +1442437 1 @@ -28545,15 +29025,15 @@ expr_argument_name -75690 +75494 id -75690 +75494 name -4374 +4229 @@ -28567,7 +29047,7 @@ 1 2 -75690 +75494 @@ -28583,47 +29063,47 @@ 1 2 -1356 +1270 2 3 -859 +838 3 4 -424 +409 4 5 -327 +331 5 7 -331 +329 7 12 -375 +348 12 25 -340 - - -25 -259 329 -262 -10879 -33 +25 +159 +318 + + +159 +10921 +57 @@ -28633,11 +29113,11 @@ xmlEncoding -112 +58 id -112 +58 encoding @@ -28655,7 +29135,7 @@ 1 2 -112 +58 @@ -28669,8 +29149,8 @@ 12 -112 -113 +58 +59 1 @@ -29029,27 +29509,27 @@ xmlElements -3426 +1226 id -3426 +1226 name -333 +207 parentid -1038 +418 idx -106 +34 fileid -112 +58 @@ -29063,7 +29543,7 @@ 1 2 -3426 +1226 @@ -29079,7 +29559,7 @@ 1 2 -3426 +1226 @@ -29095,7 +29575,7 @@ 1 2 -3426 +1226 @@ -29111,7 +29591,7 @@ 1 2 -3426 +1226 @@ -29127,42 +29607,37 @@ 1 2 -97 +78 2 3 -80 +45 3 4 -38 +23 4 5 -28 +17 5 -8 -27 +11 +16 -8 -17 -25 +11 +26 +19 -20 -53 -25 - - -62 -413 -13 +26 +138 +9 @@ -29178,7 +29653,171 @@ 1 2 -107 +86 + + +2 +3 +46 + + +3 +4 +23 + + +4 +5 +17 + + +5 +13 +18 + + +13 +41 +16 + + +51 +52 +1 + + + + + + +name +idx + + +12 + + +1 +2 +132 + + +2 +3 +38 + + +3 +5 +13 + + +5 +8 +16 + + +9 +35 +8 + + + + + + +name +fileid + + +12 + + +1 +2 +102 + + +2 +3 +47 + + +3 +4 +24 + + +4 +5 +16 + + +5 +13 +16 + + +21 +41 +2 + + + + + + +parentid +id + + +12 + + +1 +2 +222 + + +2 +3 +93 + + +3 +5 +36 + + +5 +9 +22 + + +9 +14 +33 + + +14 +35 +12 + + + + + + +parentid +name + + +12 + + +1 +2 +265 2 @@ -29187,35 +29826,20 @@ 3 -4 -44 +6 +34 -4 -5 -24 - - -5 -9 -25 - - -9 -23 -23 - - -25 -162 -23 +6 +18 +32 -name +parentid idx @@ -29224,196 +29848,32 @@ 1 2 -197 +222 2 3 -64 - - -3 -4 -26 - - -4 -6 -22 - - -6 -107 -24 - - - - - - -name -fileid - - -12 - - -1 -2 -118 - - -2 -3 -106 - - -3 -4 -50 - - -4 -6 -30 - - -6 -21 -25 - - -22 -51 -4 - - - - - - -parentid -id - - -12 - - -1 -2 -434 - - -2 -3 -298 - - -3 -4 -96 - - -4 -5 -22 - - -5 -6 -84 - - -6 -17 -78 - - -17 -107 -26 - - - - - - -parentid -name - - -12 - - -1 -2 -561 - - -2 -3 -284 +93 3 5 -76 - - -5 -8 -81 - - -8 -26 36 - - - - - -parentid -idx - - -12 - -1 -2 -434 - - -2 -3 -298 - - -3 -4 -96 - - -4 -5 +5 +9 22 -5 -6 -84 +9 +14 +33 -6 -17 -78 - - -17 -107 -26 +14 +35 +12 @@ -29429,7 +29889,7 @@ 1 2 -1038 +418 @@ -29444,13 +29904,8 @@ 1 -2 -42 - - -2 3 -6 +3 3 @@ -29458,280 +29913,46 @@ 5 -5 -6 -14 - - -6 -10 -9 - - -11 -18 -8 - - -18 -31 -8 - - -33 -97 -8 - - -104 -1039 -6 - - - - - - -idx -name - - -12 - - -1 -2 -48 - - -2 -3 -5 - - -3 -4 -21 - - -4 -8 -7 - - -8 -12 -8 - - -13 -27 -8 - - -28 -114 -8 - - -180 -181 -1 - - - - - - -idx -parentid - - -12 - - -1 -2 -42 - - -2 -3 -6 - - -3 -4 -5 - - -5 -6 -14 - - -6 -10 -9 - - -11 -18 -8 - - -18 -31 -8 - - -33 -97 -8 - - -104 -1039 -6 - - - - - - -idx -fileid - - -12 - - -1 -2 -42 - - -2 -3 -6 - - -3 -4 -19 - - -4 -8 -9 - - -9 -13 -5 - - -13 -17 -8 - - -17 -29 -8 - - -32 -92 -8 - - -112 -113 -1 - - - - - - -fileid -id - - -12 - - -1 -3 -8 - - -3 -4 -8 - - 4 5 -7 +8 5 -6 -9 - - -6 -7 -10 - - -7 9 -9 +3 9 -11 -9 +15 +3 -11 -18 -10 +18 +29 +3 -19 -27 -7 +45 +50 +3 -29 -31 -9 +53 +73 +3 -31 -49 -9 - - -51 -78 -9 - - -107 -327 -8 +103 +419 +3 -fileid +idx name @@ -29745,7 +29966,7 @@ 2 3 -27 +5 3 @@ -29754,18 +29975,186 @@ 4 +6 +2 + + +7 +11 +3 + + +11 +15 +3 + + +16 +18 +3 + + +19 +30 +3 + + +33 +73 +3 + + +121 +122 +1 + + + + + + +idx +parentid + + +12 + + +1 +3 +3 + + +3 +4 +5 + + +4 5 +8 + + +5 +9 +3 + + +9 +15 +3 + + +18 +29 +3 + + +45 +50 +3 + + +53 +73 +3 + + +103 +419 +3 + + + + + + +idx +fileid + + +12 + + +1 +3 +3 + + +3 +4 +5 + + +4 +5 +8 + + +5 +7 +2 + + +7 +8 +4 + + +8 +12 +3 + + +13 +15 +3 + + +17 +21 +3 + + +28 +59 +3 + + + + + + +fileid +id + + +12 + + +2 +3 +2 + + +3 +4 9 +4 +5 +5 + + 5 6 -8 +4 6 7 -15 +6 7 @@ -29775,27 +30164,98 @@ 8 9 -13 +6 + + +9 +10 +5 + + +10 +17 +4 + + +19 +32 +5 + + +32 +54 +5 + + +63 +238 +5 + + + + + + +fileid +name + + +12 + + +2 +3 +4 + + +3 +4 +11 + + +4 +5 +6 + + +5 +6 +4 + + +6 +7 +11 + + +7 +8 +2 + + +8 +9 +4 9 13 -8 +5 14 18 -9 +4 -18 -77 -9 +19 +32 +5 -81 -82 -1 +52 +56 +2 @@ -29809,59 +30269,49 @@ 12 -1 -2 -3 - - 2 3 -27 +4 3 4 -11 +14 4 5 -14 +8 5 6 -12 +14 6 -8 -9 +7 +3 8 -13 +10 4 13 -14 -8 +15 +4 -14 -19 -9 +15 +25 +5 -20 -33 -9 - - -37 -65 -6 +26 +48 +2 @@ -29877,58 +30327,43 @@ 1 2 -21 +16 2 3 -19 +14 3 4 -10 - - -4 -5 -6 - - -5 -7 8 -7 -8 -5 +4 +6 +3 -8 -9 -11 +6 +8 +4 9 12 -9 +5 12 -19 -9 - - -19 -33 -9 - - -37 -107 +27 5 + +31 +35 +3 + @@ -29937,23 +30372,23 @@ xmlAttrs -5138 +1785 id -5138 +1785 elementid -1923 +590 name -197 +152 value -1313 +728 idx @@ -29961,7 +30396,7 @@ fileid -107 +56 @@ -29975,7 +30410,7 @@ 1 2 -5138 +1785 @@ -29991,7 +30426,7 @@ 1 2 -5138 +1785 @@ -30007,7 +30442,7 @@ 1 2 -5138 +1785 @@ -30023,7 +30458,7 @@ 1 2 -5138 +1785 @@ -30039,7 +30474,7 @@ 1 2 -5138 +1785 @@ -30055,95 +30490,100 @@ 1 2 -546 - - -2 -3 -450 - - -3 -4 -736 - - -4 -10 -151 - - -10 -17 -40 - - - - - - -elementid -name - - -12 - - -1 -2 -546 - - -2 -3 -450 - - -3 -4 -736 - - -4 -10 -151 - - -10 -17 -40 - - - - - - -elementid -value - - -12 - - -1 -2 -549 - - -2 -3 -489 - - -3 -4 -710 - - -4 -15 175 + +2 +3 +203 + + +3 +4 +135 + + +4 +12 +41 + + +16 +17 +36 + + + + + + +elementid +name + + +12 + + +1 +2 +175 + + +2 +3 +203 + + +3 +4 +135 + + +4 +12 +41 + + +16 +17 +36 + + + + + + +elementid +value + + +12 + + +1 +2 +178 + + +2 +3 +208 + + +3 +4 +130 + + +4 +14 +43 + + +14 +15 +31 + @@ -30158,27 +30598,27 @@ 1 2 -546 +175 2 3 -450 +203 3 4 -736 +135 4 -10 -151 +12 +41 -10 +16 17 -40 +36 @@ -30194,7 +30634,7 @@ 1 2 -1923 +590 @@ -30210,46 +30650,41 @@ 1 2 -65 +62 2 3 -31 +25 3 4 -20 +15 4 -6 -13 +9 +12 -6 -13 -15 +11 +27 +12 -14 -33 -15 +27 +31 +4 36 -52 -15 +37 +14 -52 -179 -15 - - -216 -461 +54 +230 8 @@ -30266,46 +30701,41 @@ 1 2 -65 +62 2 3 -31 +25 3 4 -20 +15 4 -6 -13 +9 +12 -6 -13 -15 +11 +27 +12 -14 -33 -15 +27 +31 +4 36 -52 -15 +37 +14 -52 -179 -15 - - -216 -461 +54 +230 8 @@ -30322,32 +30752,27 @@ 1 2 -109 +98 2 3 -34 +19 3 -5 -16 +7 +14 -5 -12 -15 +7 +27 +12 -12 -42 -15 - - -43 -208 -8 +29 +139 +9 @@ -30363,22 +30788,17 @@ 1 2 -157 +128 2 3 -22 +17 3 -6 -15 - - -6 -10 -3 +7 +7 @@ -30394,27 +30814,27 @@ 1 2 -82 +72 2 3 -59 +48 3 4 -26 +11 4 -12 -16 +7 +12 -12 -48 -14 +7 +24 +9 @@ -30430,27 +30850,22 @@ 1 2 -592 +429 2 3 -421 +215 3 -4 -110 +10 +57 -4 -8 -107 - - -8 -192 -83 +10 +76 +27 @@ -30466,27 +30881,22 @@ 1 2 -603 +430 2 3 -415 +214 3 -4 -107 +10 +57 -4 -8 -106 - - -8 -174 -82 +10 +54 +27 @@ -30502,17 +30912,12 @@ 1 2 -1192 +690 2 -3 -100 - - -3 -37 -21 +28 +38 @@ -30528,12 +30933,12 @@ 1 2 -1217 +682 2 11 -96 +46 @@ -30549,22 +30954,17 @@ 1 2 -675 +486 2 3 -438 +195 3 -5 -116 - - -5 -35 -84 +21 +47 @@ -30593,48 +30993,43 @@ 1 -49 -50 +41 +42 +2 + + +42 +43 1 -80 -81 +46 +47 1 -102 -103 +63 +64 1 -104 -105 +77 +78 1 -127 -128 +212 +213 1 -191 -192 +415 +416 1 -927 -928 -1 - - -1377 -1378 -1 - - -1923 -1924 +590 +591 1 @@ -30664,48 +31059,43 @@ 1 -49 -50 +41 +42 +2 + + +42 +43 1 -80 -81 +46 +47 1 -102 -103 +63 +64 1 -104 -105 +77 +78 1 -127 -128 +212 +213 1 -191 -192 +415 +416 1 -927 -928 -1 - - -1377 -1378 -1 - - -1923 -1924 +590 +591 1 @@ -30732,7 +31122,12 @@ 4 5 -1 +2 + + +5 +6 +2 7 @@ -30740,145 +31135,8 @@ 1 -8 -9 -1 - - -11 -12 -2 - - -19 -20 -1 - - -34 -35 -1 - - -54 -55 -1 - - -57 -58 -1 - - -67 -68 -1 - - - - - - -idx -value - - -12 - - -1 -2 -3 - - -8 -9 -1 - - -26 -27 -1 - - -29 -30 -4 - - -31 -32 -2 - - -39 -40 -1 - - -66 -67 -1 - - -146 -147 -1 - - -345 -346 -1 - - -670 -671 -1 - - - - - - -idx -fileid - - -12 - - -2 -3 -5 - - -4 -5 -1 - - -5 -6 -1 - - -8 -9 -1 - - -9 -10 -1 - - -10 -11 -1 - - -11 -12 +13 +14 1 @@ -30887,23 +31145,160 @@ 1 -35 -36 +34 +35 1 -73 -74 +40 +41 1 -101 -102 +49 +50 +1 + + + + + + +idx +value + + +12 + + +1 +2 +3 + + +8 +9 1 -107 -108 +14 +15 +1 + + +16 +17 +1 + + +17 +18 +1 + + +18 +19 +1 + + +23 +24 +1 + + +25 +26 +1 + + +29 +30 +2 + + +31 +32 +1 + + +47 +48 +1 + + +211 +212 +1 + + +330 +331 +1 + + + + + + +idx +fileid + + +12 + + +2 +3 +5 + + +4 +5 +1 + + +5 +6 +1 + + +6 +7 +2 + + +7 +8 +1 + + +10 +11 +1 + + +15 +16 +1 + + +18 +19 +1 + + +28 +29 +1 + + +52 +53 +1 + + +56 +57 1 @@ -30919,63 +31314,58 @@ 1 +2 +2 + + +2 3 -9 +10 3 4 -11 +8 4 5 -11 +6 -5 +6 8 -7 +4 8 -11 -9 +10 +5 -11 +10 15 -8 +5 18 32 -9 +3 -32 -40 -8 +33 +39 +5 -40 -45 -9 +73 +115 +5 -47 -61 -9 - - -67 -118 -9 - - -174 -794 -8 +241 +338 +3 @@ -30991,62 +31381,42 @@ 1 2 -18 +17 2 3 -11 +8 3 4 -11 - - -4 -5 -9 - - -5 -8 -7 - - -8 -13 -7 - - -13 -17 8 -17 -18 -7 +4 +6 +5 -19 -26 -9 +6 +13 +5 -27 -38 -9 +16 +23 +5 -39 -72 -9 +23 +36 +4 -274 -306 -2 +41 +127 +4 @@ -31062,51 +31432,51 @@ 1 2 -5 +3 2 3 -15 +18 3 4 -25 +8 4 5 -13 +4 5 6 -8 +3 6 7 -5 +3 7 8 -14 +3 8 -11 -9 +12 +5 -11 -19 -9 +12 +18 +5 -23 -69 +18 +62 4 @@ -31122,67 +31492,52 @@ 1 +2 +2 + + +2 3 -9 +10 3 4 -12 +8 4 5 -11 +8 5 -6 -7 +7 +5 -6 -8 -8 +7 +10 +5 -9 -13 -8 - - -13 -17 -9 - - -19 +11 24 -6 +5 -24 -28 -7 - - -28 -33 -9 +27 +32 +5 33 -49 -9 +78 +5 -54 -111 -9 - - -141 -327 +95 +168 3 @@ -31199,37 +31554,37 @@ 1 2 -6 +4 2 3 -28 +24 3 4 -38 +10 4 5 -13 +3 5 6 -11 +5 6 -12 -9 +10 +5 -16 +10 17 -2 +5 @@ -31239,7 +31594,7 @@ xmlNs -20 +8 id @@ -31255,7 +31610,7 @@ fileid -19 +7 @@ -31301,12 +31656,7 @@ 4 5 -1 - - -16 -17 -1 +2 @@ -31354,12 +31704,7 @@ 4 5 -1 - - -16 -17 -1 +2 @@ -31407,12 +31752,7 @@ 4 5 -1 - - -16 -17 -1 +2 @@ -31428,7 +31768,7 @@ 1 2 -18 +6 2 @@ -31449,7 +31789,7 @@ 1 2 -18 +6 2 @@ -31470,7 +31810,7 @@ 1 2 -18 +6 2 @@ -31485,11 +31825,11 @@ xmlHasNs -982 +140 elementId -982 +140 nsId @@ -31497,7 +31837,7 @@ fileid -18 +6 @@ -31511,7 +31851,7 @@ 1 2 -982 +140 @@ -31527,7 +31867,7 @@ 1 2 -982 +140 @@ -31541,13 +31881,13 @@ 12 -470 -471 +37 +38 1 -512 -513 +103 +104 1 @@ -31567,8 +31907,8 @@ 1 -16 -17 +4 +5 1 @@ -31598,38 +31938,13 @@ 1 -25 -26 -8 - - -34 -35 +31 +32 2 -40 -41 -1 - - -43 -44 -1 - - -49 -50 -1 - - -55 -56 -1 - - -520 -521 +71 +72 1 @@ -31646,7 +31961,7 @@ 1 2 -17 +5 2 @@ -31661,23 +31976,23 @@ xmlComments -300 +152 id -300 +152 text -187 +109 parentid -120 +74 fileid -52 +37 @@ -31691,7 +32006,7 @@ 1 2 -300 +152 @@ -31707,7 +32022,7 @@ 1 2 -300 +152 @@ -31723,7 +32038,7 @@ 1 2 -300 +152 @@ -31739,285 +32054,275 @@ 1 2 -92 +79 2 3 -83 +23 3 9 -12 - - - - - - -text -parentid - - -12 - - -1 -2 -92 - - -2 -3 -83 - - -3 -9 -12 - - - - - - -text -fileid - - -12 - - -1 -2 -92 - - -2 -3 -83 - - -3 -9 -12 - - - - - - -parentid -id - - -12 - - -1 -2 -71 - - -2 -3 -15 - - -3 -4 -21 - - -4 -15 -9 - - -15 -25 -4 - - - - - - -parentid -text - - -12 - - -1 -2 -71 - - -2 -3 -15 - - -3 -4 -21 - - -4 -15 -9 - - -15 -25 -4 - - - - - - -parentid -fileid - - -12 - - -1 -2 -120 - - - - - - -fileid -id - - -12 - - -1 -2 -24 - - -2 -3 -6 - - -3 -4 -6 - - -4 -5 -5 - - -5 -10 -4 - - -14 -20 -4 - - -25 -62 -3 - - - - - - -fileid -text - - -12 - - -1 -2 -24 - - -2 -3 -6 - - -3 -4 -6 - - -4 -5 -5 - - -5 -10 -4 - - -14 -20 -4 - - -25 -62 -3 - - - - - - -fileid -parentid - - -12 - - -1 -2 -32 - - -2 -3 7 + + + + + +text +parentid + + +12 + + +1 +2 +79 + + +2 +3 +25 + + +3 +9 +5 + + + + + + +text +fileid + + +12 + + +1 +2 +79 + + +2 +3 +25 + + +3 +9 +5 + + + + + + +parentid +id + + +12 + + +1 +2 +49 + + +2 +3 +10 + 3 4 -8 +9 4 -14 +24 +6 + + + + + + +parentid +text + + +12 + + +1 +2 +49 + + +2 +3 +10 + + +3 +4 +9 + + +4 +22 +6 + + + + + + +parentid +fileid + + +12 + + +1 +2 +74 + + + + + + +fileid +id + + +12 + + +1 +2 +18 + + +2 +3 +5 + + +3 +4 +5 + + +4 +6 +2 + + +10 +11 +2 + + +14 +15 +3 + + +15 +24 +2 + + + + + + +fileid +text + + +12 + + +1 +2 +18 + + +2 +3 +5 + + +3 +4 +5 + + +4 +6 +2 + + +10 +11 +2 + + +14 +15 +3 + + +15 +22 +2 + + + + + + +fileid +parentid + + +12 + + +1 +2 +23 + + +2 +3 4 -17 -18 -1 +3 +4 +5 + + +4 +6 +2 + + +6 +8 +3 @@ -32027,19 +32332,19 @@ xmlChars -826 +238 id -826 +238 text -357 +123 parentid -826 +238 idx @@ -32051,7 +32356,7 @@ fileid -17 +10 @@ -32065,7 +32370,7 @@ 1 2 -826 +238 @@ -32081,7 +32386,7 @@ 1 2 -826 +238 @@ -32097,7 +32402,7 @@ 1 2 -826 +238 @@ -32113,7 +32418,7 @@ 1 2 -826 +238 @@ -32129,7 +32434,7 @@ 1 2 -826 +238 @@ -32145,121 +32450,111 @@ 1 2 -112 +82 2 3 -179 +26 3 -4 -17 +6 +10 -4 +6 +28 +5 + + + + + + +text +parentid + + +12 + + +1 +2 +82 + + +2 +3 +26 + + +3 +6 +10 + + +6 +28 +5 + + + + + + +text +idx + + +12 + + +1 +2 +123 + + + + + + +text +isCDATA + + +12 + + +1 +2 +123 + + + + + + +text +fileid + + +12 + + +1 +2 +89 + + +2 +3 +30 + + +3 5 -31 - - -5 -32 -18 - - - - - - -text -parentid - - -12 - - -1 -2 -112 - - -2 -3 -179 - - -3 -4 -17 - - -4 -5 -31 - - -5 -32 -18 - - - - - - -text -idx - - -12 - - -1 -2 -357 - - - - - - -text -isCDATA - - -12 - - -1 -2 -357 - - - - - - -text -fileid - - -12 - - -1 -2 -116 - - -2 -3 -220 - - -3 -9 -21 +4 @@ -32275,7 +32570,7 @@ 1 2 -826 +238 @@ -32291,7 +32586,7 @@ 1 2 -826 +238 @@ -32307,7 +32602,7 @@ 1 2 -826 +238 @@ -32323,7 +32618,7 @@ 1 2 -826 +238 @@ -32339,7 +32634,7 @@ 1 2 -826 +238 @@ -32353,8 +32648,8 @@ 12 -826 -827 +238 +239 1 @@ -32369,8 +32664,8 @@ 12 -357 -358 +123 +124 1 @@ -32385,8 +32680,8 @@ 12 -826 -827 +238 +239 1 @@ -32417,8 +32712,8 @@ 12 -17 -18 +10 +11 1 @@ -32433,13 +32728,13 @@ 12 -117 -118 +47 +48 1 -709 -710 +191 +192 1 @@ -32454,13 +32749,13 @@ 12 -74 -75 +37 +38 1 -283 -284 +86 +87 1 @@ -32475,13 +32770,13 @@ 12 -117 -118 +47 +48 1 -709 -710 +191 +192 1 @@ -32512,13 +32807,13 @@ 12 -8 -9 +6 +7 1 -17 -18 +10 +11 1 @@ -32540,41 +32835,26 @@ 2 3 +2 + + +9 +10 +2 + + +14 +15 1 -3 -4 +15 +16 1 -4 -5 -1 - - -5 -6 -1 - - -16 -17 -1 - - -21 -22 -1 - - -25 -26 -1 - - -30 -31 +36 +37 1 @@ -32583,30 +32863,10 @@ 1 -41 -42 -2 - - -63 -64 -1 - - -80 -81 -1 - - 110 111 1 - -172 -173 -2 - @@ -32626,22 +32886,12 @@ 2 3 -1 +2 -3 -4 -1 - - -4 -5 -1 - - -5 -6 -1 +8 +9 +2 11 @@ -32649,38 +32899,18 @@ 1 -12 -13 +14 +15 1 -18 -19 +15 +16 1 -20 -21 -1 - - -29 -30 -1 - - -38 -39 -2 - - -41 -42 -1 - - -57 -58 +28 +29 1 @@ -32688,11 +32918,6 @@ 74 1 - -138 -139 -2 - @@ -32712,41 +32937,26 @@ 2 3 +2 + + +9 +10 +2 + + +14 +15 1 -3 -4 +15 +16 1 -4 -5 -1 - - -5 -6 -1 - - -16 -17 -1 - - -21 -22 -1 - - -25 -26 -1 - - -30 -31 +36 +37 1 @@ -32755,30 +32965,10 @@ 1 -41 -42 -2 - - -63 -64 -1 - - -80 -81 -1 - - 110 111 1 - -172 -173 -2 - @@ -32793,7 +32983,7 @@ 1 2 -17 +10 @@ -32809,12 +32999,12 @@ 1 2 -9 +4 2 3 -8 +6 @@ -32824,15 +33014,15 @@ xmllocations -9824 +3469 xmlElement -9806 +3463 location -9824 +3469 @@ -32846,11 +33036,11 @@ 1 2 -9804 +3461 4 -17 +5 2 @@ -32867,7 +33057,7 @@ 1 2 -9824 +3469 @@ -32877,11 +33067,11 @@ commentline -618446 +526699 id -618446 +526699 kind @@ -32889,11 +33079,11 @@ text -304702 +269293 rawtext -309171 +273305 @@ -32907,7 +33097,7 @@ 1 2 -618446 +526699 @@ -32923,7 +33113,7 @@ 1 2 -618446 +526699 @@ -32939,7 +33129,7 @@ 1 2 -618446 +526699 @@ -32953,18 +33143,18 @@ 12 -12000 -12001 +10871 +10872 1 -276055 -276056 +210408 +210409 1 -330391 -330392 +305420 +305421 1 @@ -32979,18 +33169,18 @@ 12 -5817 -5818 +5341 +5342 1 -98398 -98399 +80159 +80160 1 -201704 -201705 +184908 +184909 1 @@ -33005,18 +33195,18 @@ 12 -6340 -6341 +5828 +5829 1 -99142 -99143 +80802 +80803 1 -203689 -203690 +186675 +186676 1 @@ -33033,17 +33223,17 @@ 1 2 -252156 +224371 2 3 -34923 +30221 3 -49511 -17623 +37016 +14701 @@ -33059,12 +33249,12 @@ 1 2 -303526 +268207 2 4 -1176 +1086 @@ -33080,12 +33270,12 @@ 1 2 -301509 +266406 2 -86 -3193 +76 +2887 @@ -33101,17 +33291,17 @@ 1 2 -256975 +228701 2 3 -34845 +30180 3 -49420 -17351 +36967 +14424 @@ -33127,7 +33317,7 @@ 1 2 -309171 +273305 @@ -33143,7 +33333,7 @@ 1 2 -309171 +273305 @@ -33153,15 +33343,15 @@ commentline_location -618446 +526699 id -618446 +526699 loc -618446 +526699 @@ -33175,7 +33365,7 @@ 1 2 -618446 +526699 @@ -33191,7 +33381,7 @@ 1 2 -618446 +526699 @@ -33201,26 +33391,26 @@ commentblock -247138 +216571 id -247138 +216571 commentblock_location -247138 +216571 id -247138 +216571 loc -247138 +216571 @@ -33234,7 +33424,7 @@ 1 2 -247138 +216571 @@ -33250,7 +33440,7 @@ 1 2 -247138 +216571 @@ -33260,15 +33450,15 @@ commentblock_binding -794277 +724338 id -247103 +216569 entity -339770 +311724 bindtype @@ -33286,22 +33476,22 @@ 1 2 -64059 +60480 2 3 -47892 +40519 3 4 -134744 +109785 4 -7 -408 +257 +5785 @@ -33317,22 +33507,22 @@ 1 2 -19446 +19145 2 3 -44772 +42539 3 4 -47839 +41305 4 5 -135046 +113580 @@ -33348,17 +33538,17 @@ 1 2 -247642 +226442 2 3 -67118 +64133 3 -8449 -25010 +1882 +21149 @@ -33374,22 +33564,22 @@ 1 2 -146681 +134634 2 3 -146587 +135222 3 4 -45202 +40684 4 5 -1300 +1184 @@ -33403,23 +33593,23 @@ 12 -143047 -143048 +120670 +120671 1 -202047 -202048 +172840 +172841 1 -220046 -220047 +191618 +191619 1 -227551 -227552 +197330 +197331 1 @@ -33434,23 +33624,23 @@ 12 -85120 -85121 +79358 +79359 1 -134653 -134654 +122819 +122820 1 -175047 -175048 +158785 +158786 1 -185841 -185842 +170904 +170905 1 @@ -33461,15 +33651,15 @@ commentblock_child -618012 +526620 id -247138 +216571 commentline -618012 +526620 index @@ -33487,32 +33677,27 @@ 1 2 -119292 +104360 2 3 -47018 +45412 3 4 -42534 +37592 4 -6 -19386 +7 +18798 -6 -32 -18550 - - -32 +7 1136 -358 +10409 @@ -33528,32 +33713,27 @@ 1 2 -119292 +104360 2 3 -47018 +45412 3 4 -42534 +37592 4 -6 -19386 +7 +18798 -6 -32 -18550 - - -32 +7 1136 -358 +10409 @@ -33569,7 +33749,7 @@ 1 2 -618012 +526620 @@ -33585,7 +33765,7 @@ 1 2 -618012 +526620 @@ -33625,12 +33805,12 @@ 12 -95 +90 86 -96 -247139 +91 +216572 54 @@ -33671,12 +33851,12 @@ 12 -95 +90 86 -96 -247139 +91 +216572 54 @@ -33687,19 +33867,19 @@ asp_elements -12090 +148 id -12090 +148 kind -9 +7 loc -12090 +148 @@ -33713,7 +33893,7 @@ 1 2 -12090 +148 @@ -33729,7 +33909,7 @@ 1 2 -12090 +148 @@ -33743,48 +33923,38 @@ 12 -14 -15 +1 +2 1 -16 -17 +3 +4 1 -44 -45 +5 +6 1 -243 -244 +22 +23 1 -244 -245 +28 +29 1 -1542 -1543 +31 +32 1 -1920 -1921 -1 - - -3522 -3523 -1 - - -4545 -4546 +58 +59 1 @@ -33799,48 +33969,38 @@ 12 -14 -15 +1 +2 1 -16 -17 +3 +4 1 -44 -45 +5 +6 1 -243 -244 +22 +23 1 -244 -245 +28 +29 1 -1542 -1543 +31 +32 1 -1920 -1921 -1 - - -3522 -3523 -1 - - -4545 -4546 +58 +59 1 @@ -33857,7 +34017,7 @@ 1 2 -12090 +148 @@ -33873,7 +34033,7 @@ 1 2 -12090 +148 @@ -33883,45 +34043,45 @@ asp_comment_server -2 +0 comment -2 +0 asp_code_inline -238 +0 code -238 +0 asp_directive_attribute -879 +6 directive -243 +3 index -7 +4 name -21 +5 value -879 +6 @@ -33935,32 +34095,12 @@ 1 2 -22 - - -2 -3 -3 - - -3 -4 -117 +2 4 5 -30 - - -5 -6 -50 - - -6 -8 -21 +1 @@ -33976,32 +34116,12 @@ 1 2 -22 - - -2 -3 -3 - - -3 -4 -117 +2 4 5 -30 - - -5 -6 -50 - - -6 -8 -21 +1 @@ -34017,32 +34137,12 @@ 1 2 -22 - - -2 -3 -3 - - -3 -4 -117 +2 4 5 -30 - - -5 -6 -50 - - -6 -8 -21 +1 @@ -34056,38 +34156,13 @@ 12 -4 -5 -1 +1 +2 +3 -21 -22 -1 - - -71 -72 -1 - - -101 -102 -1 - - -218 -219 -1 - - -221 -222 -1 - - -243 -244 +3 +4 1 @@ -34102,30 +34177,15 @@ 12 +1 +2 +3 + + 2 3 1 - -6 -7 -1 - - -7 -8 -1 - - -8 -9 -2 - - -10 -11 -2 - @@ -34138,38 +34198,13 @@ 12 -4 -5 -1 +1 +2 +3 -21 -22 -1 - - -71 -72 -1 - - -101 -102 -1 - - -218 -219 -1 - - -221 -222 -1 - - -243 -244 +3 +4 1 @@ -34186,81 +34221,11 @@ 1 2 -3 +4 2 3 -3 - - -3 -4 -1 - - -5 -6 -2 - - -9 -10 -1 - - -10 -11 -1 - - -13 -14 -1 - - -31 -32 -1 - - -63 -64 -1 - - -72 -73 -1 - - -98 -99 -1 - - -105 -106 -1 - - -106 -107 -1 - - -108 -109 -1 - - -113 -114 -1 - - -129 -130 1 @@ -34277,27 +34242,7 @@ 1 2 -9 - - -2 -3 -3 - - -3 -4 -4 - - -4 -5 -1 - - -5 -6 -4 +5 @@ -34313,81 +34258,11 @@ 1 2 -3 +4 2 3 -3 - - -3 -4 -1 - - -5 -6 -2 - - -9 -10 -1 - - -10 -11 -1 - - -13 -14 -1 - - -31 -32 -1 - - -63 -64 -1 - - -72 -73 -1 - - -98 -99 -1 - - -105 -106 -1 - - -106 -107 -1 - - -108 -109 -1 - - -113 -114 -1 - - -129 -130 1 @@ -34404,7 +34279,7 @@ 1 2 -879 +6 @@ -34420,7 +34295,7 @@ 1 2 -879 +6 @@ -34436,7 +34311,7 @@ 1 2 -879 +6 @@ -34446,15 +34321,15 @@ asp_directive_name -243 +3 directive -243 +3 name -5 +2 @@ -34468,7 +34343,7 @@ 1 2 -243 +3 @@ -34482,30 +34357,15 @@ 12 +1 +2 +1 + + 2 3 1 - -9 -10 -1 - - -21 -22 -1 - - -98 -99 -1 - - -113 -114 -1 - @@ -34514,15 +34374,15 @@ asp_element_body -9927 +117 element -9927 +117 body -1800 +73 @@ -34536,7 +34396,7 @@ 1 2 -9927 +117 @@ -34552,32 +34412,22 @@ 1 2 -815 +55 2 3 -601 +10 3 -4 -62 +6 +5 -4 -7 -159 - - -7 -55 -135 - - -57 -982 -28 +6 +11 +3 @@ -34587,23 +34437,23 @@ asp_tag_attribute -3666 +25 tag -1455 +16 index -10 +2 name -119 +10 attribute -3666 +25 @@ -34617,27 +34467,12 @@ 1 2 -321 +7 2 3 -506 - - -3 -4 -368 - - -4 -5 -153 - - -5 -11 -107 +9 @@ -34653,27 +34488,12 @@ 1 2 -321 +7 2 3 -506 - - -3 -4 -368 - - -4 -5 -153 - - -5 -11 -107 +9 @@ -34689,27 +34509,12 @@ 1 2 -321 +7 2 3 -506 - - -3 -4 -368 - - -4 -5 -153 - - -5 -11 -107 +9 @@ -34723,53 +34528,13 @@ 12 -1 -2 +9 +10 1 -4 -5 -1 - - -10 -11 -1 - - -19 -20 -1 - - -48 -49 -1 - - -107 -108 -1 - - -260 -261 -1 - - -628 -629 -1 - - -1134 -1135 -1 - - -1455 -1456 +16 +17 1 @@ -34784,217 +34549,92 @@ 12 -1 -2 -1 - - -2 -3 -1 - - -4 -5 -1 - - -8 -9 -1 - - -17 -18 -1 - - -30 -31 -1 - - -42 -43 -1 - - -43 -44 -1 - - -50 -51 -1 - - -60 -61 -1 - - - - - - -index -attribute - - -12 - - -1 -2 -1 - - -4 -5 -1 - - -10 -11 -1 - - -19 -20 -1 - - -48 -49 -1 - - -107 -108 -1 - - -260 -261 -1 - - -628 -629 -1 - - -1134 -1135 -1 - - -1455 -1456 -1 - - - - - - -name -tag - - -12 - - -1 -2 -16 - - -2 -3 -25 - - -3 -4 -8 - - -4 -5 -12 - - 5 6 -6 - - -6 -7 -9 +1 7 -11 -10 - - -11 -19 -9 - - -19 -39 -9 - - -42 -130 -9 - - -132 -980 -6 - - - - - - -name -index - - -12 - - -1 -2 -52 - - -2 -3 -31 - - -3 -4 -15 - - -4 -5 -12 - - -5 8 -9 +1 + + + + + + +index +attribute + + +12 + + +9 +10 +1 + + +16 +17 +1 + + + + + + +name +tag + + +12 + + +1 +2 +5 + + +2 +3 +1 + + +3 +4 +1 + + +4 +5 +2 + + +7 +8 +1 + + + + + + +name +index + + +12 + + +1 +2 +8 + + +2 +3 +2 @@ -35010,57 +34650,27 @@ 1 2 -16 +5 2 3 -25 +1 3 4 -8 +1 4 5 -12 - - -5 -6 -6 - - -6 -7 -9 +2 7 -11 -10 - - -11 -19 -9 - - -19 -39 -9 - - -42 -130 -9 - - -132 -980 -6 +8 +1 @@ -35076,7 +34686,7 @@ 1 2 -3666 +25 @@ -35092,7 +34702,7 @@ 1 2 -3666 +25 @@ -35108,7 +34718,7 @@ 1 2 -3666 +25 @@ -35118,15 +34728,15 @@ asp_tag_name -1920 +28 tag -1920 +28 name -110 +15 @@ -35140,7 +34750,7 @@ 1 2 -1920 +28 @@ -35156,57 +34766,27 @@ 1 2 -15 +10 2 3 -20 +2 3 4 -3 - - -4 -5 -10 +1 5 -8 -9 +6 +1 -8 -11 -9 - - -11 -14 -9 - - -14 -21 -10 - - -24 -38 -10 - - -50 -71 -9 - - -76 -130 -6 +6 +7 +1 @@ -35216,22 +34796,22 @@ asp_tag_isempty -363 +1 tag -363 +1 cil_instruction -17762677 +17762709 id -17762677 +17762709 opcode @@ -35243,7 +34823,7 @@ impl -1075745 +1075749 @@ -35257,7 +34837,7 @@ 1 2 -17762677 +17762709 @@ -35273,7 +34853,7 @@ 1 2 -17762677 +17762709 @@ -35289,7 +34869,7 @@ 1 2 -17762677 +17762709 @@ -35358,13 +34938,13 @@ 16 -153187 -397705 +153188 +397706 16 421486 -1761436 +1761440 13 @@ -35511,12 +35091,12 @@ 72210 -156029 +156030 16 176525 -758788 +758792 13 @@ -35597,7 +35177,7 @@ 94672 -1075746 +1075750 43 @@ -35754,7 +35334,7 @@ 94672 -1075746 +1075750 43 @@ -35781,7 +35361,7 @@ 3 4 -178628 +178631 4 @@ -35796,17 +35376,17 @@ 7 10 -93902 +93903 10 15 -83468 +83467 15 26 -84044 +84045 26 @@ -35842,7 +35422,7 @@ 3 4 -190914 +190917 4 @@ -35862,17 +35442,17 @@ 7 9 -90930 +90931 9 13 -98471 +98470 13 20 -84244 +84245 20 @@ -35908,7 +35488,7 @@ 3 4 -178628 +178631 4 @@ -35923,17 +35503,17 @@ 7 10 -93902 +93903 10 15 -83468 +83467 15 26 -84044 +84045 26 @@ -35953,15 +35533,15 @@ cil_jump -1461276 +1461279 instruction -1461276 +1461279 target -1171285 +1171286 @@ -35975,7 +35555,7 @@ 1 2 -1461276 +1461279 @@ -36001,7 +35581,7 @@ 3 256 -51975 +51976 @@ -36011,15 +35591,15 @@ cil_access -6097501 +6097515 instruction -6097501 +6097515 target -1342773 +1342781 @@ -36033,7 +35613,7 @@ 1 2 -6097501 +6097515 @@ -36049,7 +35629,7 @@ 1 2 -400905 +400912 2 @@ -36059,7 +35639,7 @@ 3 4 -149466 +149467 4 @@ -36078,7 +35658,7 @@ 30 -47893 +47894 16948 @@ -36089,15 +35669,15 @@ cil_value -556329 +556330 instruction -556329 +556330 value -86381 +86382 @@ -36111,7 +35691,7 @@ 1 2 -556329 +556330 @@ -36127,7 +35707,7 @@ 1 2 -37537 +37538 2 @@ -36540,11 +36120,11 @@ cil_type_location -212852 +212853 id -118809 +118810 loc @@ -36562,7 +36142,7 @@ 1 2 -52292 +52293 2 @@ -36658,11 +36238,11 @@ cil_method_location -1622420 +1622426 id -939512 +939518 loc @@ -36680,7 +36260,7 @@ 1 2 -474427 +474433 2 @@ -36791,15 +36371,15 @@ cil_type -310744 +310746 id -310744 +310746 name -69903 +69904 kind @@ -36811,7 +36391,7 @@ sourceDecl -189847 +189848 @@ -36825,7 +36405,7 @@ 1 2 -310744 +310746 @@ -36841,7 +36421,7 @@ 1 2 -310744 +310746 @@ -36857,7 +36437,7 @@ 1 2 -310744 +310746 @@ -36873,7 +36453,7 @@ 1 2 -310744 +310746 @@ -36889,7 +36469,7 @@ 1 2 -41024 +41025 2 @@ -36920,7 +36500,7 @@ 1 2 -69903 +69904 @@ -36936,7 +36516,7 @@ 1 2 -60864 +60865 2 @@ -36962,7 +36542,7 @@ 1 2 -42608 +42609 2 @@ -37006,8 +36586,8 @@ 1 -249378 -249379 +249380 +249381 1 @@ -37037,8 +36617,8 @@ 1 -67304 -67305 +67305 +67306 1 @@ -37099,8 +36679,8 @@ 1 -129439 -129440 +129440 +129441 1 @@ -37231,7 +36811,7 @@ 1 2 -181709 +181710 2 @@ -37252,7 +36832,7 @@ 1 2 -189847 +189848 @@ -37268,7 +36848,7 @@ 1 2 -189847 +189848 @@ -37284,7 +36864,7 @@ 1 2 -186967 +186968 2 @@ -37493,19 +37073,19 @@ cil_method -1164170 +1164177 id -1164170 +1164177 name -196164 +196167 parent -166238 +166239 return_type @@ -37523,7 +37103,7 @@ 1 2 -1164170 +1164177 @@ -37539,7 +37119,7 @@ 1 2 -1164170 +1164177 @@ -37555,7 +37135,7 @@ 1 2 -1164170 +1164177 @@ -37571,7 +37151,7 @@ 1 2 -91448 +91451 2 @@ -37595,7 +37175,7 @@ 13 -131916 +131917 8052 @@ -37612,7 +37192,7 @@ 1 2 -96428 +96431 2 @@ -37636,7 +37216,7 @@ 15 -103427 +103428 5615 @@ -37653,7 +37233,7 @@ 1 2 -162790 +162793 2 @@ -37689,7 +37269,7 @@ 3 4 -20193 +20194 4 @@ -37745,7 +37325,7 @@ 3 4 -20980 +20981 4 @@ -37796,7 +37376,7 @@ 2 3 -40692 +40693 3 @@ -37861,7 +37441,7 @@ 31 -402822 +402825 1661 @@ -37933,7 +37513,7 @@ 8 -123711 +123712 4236 @@ -37944,15 +37524,15 @@ cil_method_source_declaration -1075007 +1075014 method -1075007 +1075014 source -976101 +976107 @@ -37966,7 +37546,7 @@ 1 2 -1075007 +1075014 @@ -37982,7 +37562,7 @@ 1 2 -933517 +933523 2 @@ -37997,15 +37577,15 @@ cil_method_implementation -1351436 +1351440 id -1351436 +1351440 method -788230 +788234 location @@ -38023,7 +37603,7 @@ 1 2 -1351436 +1351440 @@ -38039,7 +37619,7 @@ 1 2 -1351436 +1351440 @@ -38055,7 +37635,7 @@ 1 2 -419065 +419069 2 @@ -38091,7 +37671,7 @@ 1 2 -419085 +419089 2 @@ -38351,23 +37931,23 @@ cil_field -459117 +459120 id -459117 +459120 parent -78097 +78098 name -163874 +163877 field_type -66956 +66957 @@ -38381,7 +37961,7 @@ 1 2 -459117 +459120 @@ -38397,7 +37977,7 @@ 1 2 -459117 +459120 @@ -38413,7 +37993,7 @@ 1 2 -459117 +459120 @@ -38429,7 +38009,7 @@ 1 2 -18670 +18671 2 @@ -38485,7 +38065,7 @@ 1 2 -18670 +18671 2 @@ -38541,7 +38121,7 @@ 1 2 -22569 +22570 2 @@ -38587,7 +38167,7 @@ 1 2 -105589 +105592 2 @@ -38618,7 +38198,7 @@ 1 2 -105589 +105592 2 @@ -38649,7 +38229,7 @@ 1 2 -125364 +125367 2 @@ -38680,7 +38260,7 @@ 1 2 -32076 +32077 2 @@ -38709,7 +38289,7 @@ 161 -63270 +63271 174 @@ -38726,7 +38306,7 @@ 1 2 -41592 +41593 2 @@ -38757,7 +38337,7 @@ 1 2 -43052 +43053 2 @@ -38781,7 +38361,7 @@ 90 -25354 +25355 196 @@ -38792,15 +38372,15 @@ cil_parameter -2241273 +2241281 id -2241273 +2241281 method -1091090 +1091095 index @@ -38808,7 +38388,7 @@ param_type -227413 +227415 @@ -38822,7 +38402,7 @@ 1 2 -2241273 +2241281 @@ -38838,7 +38418,7 @@ 1 2 -2241273 +2241281 @@ -38854,7 +38434,7 @@ 1 2 -2241273 +2241281 @@ -38870,17 +38450,17 @@ 1 2 -457241 +457244 2 3 -371753 +371754 3 4 -150895 +150896 4 @@ -38906,17 +38486,17 @@ 1 2 -457241 +457244 2 3 -371753 +371754 3 4 -150895 +150896 4 @@ -38942,12 +38522,12 @@ 1 2 -478810 +478813 2 3 -381799 +381801 3 @@ -39032,12 +38612,12 @@ 33136 -262097 +262098 4 -633849 -1091091 +633851 +1091096 2 @@ -39108,12 +38688,12 @@ 33136 -262097 +262098 4 -633849 -1091091 +633851 +1091096 2 @@ -39184,7 +38764,7 @@ 35950 -179765 +179767 3 @@ -39201,22 +38781,22 @@ 1 2 -67477 +67478 2 3 -53744 +53745 3 4 -22720 +22719 4 5 -15429 +15430 5 @@ -39252,22 +38832,22 @@ 1 2 -68945 +68946 2 3 -53403 +53404 3 4 -22604 +22603 4 5 -15196 +15197 5 @@ -39303,17 +38883,17 @@ 1 2 -161358 +161360 2 3 -44633 +44632 3 5 -17710 +17711 5 @@ -39398,15 +38978,15 @@ cil_getter -232515 +232516 prop -232515 +232516 method -232515 +232516 @@ -39420,7 +39000,7 @@ 1 2 -232515 +232516 @@ -39436,7 +39016,7 @@ 1 2 -232515 +232516 @@ -39590,11 +39170,11 @@ cil_property -232995 +232996 id -232995 +232996 parent @@ -39602,7 +39182,7 @@ name -60870 +60871 property_type @@ -39620,7 +39200,7 @@ 1 2 -232995 +232996 @@ -39636,7 +39216,7 @@ 1 2 -232995 +232996 @@ -39652,7 +39232,7 @@ 1 2 -232995 +232996 @@ -39811,7 +39391,7 @@ 1 2 -31483 +31484 2 @@ -39847,7 +39427,7 @@ 1 2 -31483 +31484 2 @@ -39883,7 +39463,7 @@ 1 2 -51983 +51984 2 @@ -40412,15 +39992,15 @@ cil_local_variable -989635 +989637 id -989635 +989637 impl -292891 +292892 index @@ -40442,7 +40022,7 @@ 1 2 -989635 +989637 @@ -40458,7 +40038,7 @@ 1 2 -989635 +989637 @@ -40474,7 +40054,7 @@ 1 2 -989635 +989637 @@ -40495,7 +40075,7 @@ 2 3 -49612 +49613 3 @@ -40541,7 +40121,7 @@ 2 3 -49612 +49613 3 @@ -40587,7 +40167,7 @@ 2 3 -63289 +63290 3 @@ -40672,7 +40252,7 @@ 3102 -292892 +292893 22 @@ -40738,7 +40318,7 @@ 3102 -292892 +292893 22 @@ -42262,11 +41842,11 @@ cil_method_stack_size -1351436 +1351440 method -1351436 +1351440 size @@ -42284,7 +41864,7 @@ 1 2 -1351436 +1351440 @@ -42349,7 +41929,7 @@ 74163 -1041565 +1041568 3 @@ -42360,77 +41940,77 @@ cil_public -883904 +883908 id -883904 +883908 cil_private -508798 +508804 id -508798 +508804 cil_protected -856296 +856299 id -856296 +856299 cil_internal -51633 +51635 id -51633 +51635 cil_static -459535 +459542 id -459535 +459542 cil_sealed -184038 +184039 id -184038 +184039 cil_virtual -375107 +375108 id -375107 +375108 @@ -42448,11 +42028,11 @@ cil_class -103798 +103799 id -103798 +103799 @@ -42492,33 +42072,33 @@ cil_specialname -415805 +415808 id -415805 +415808 cil_newslot -243445 +243446 id -243445 +243446 cil_base_class -108602 +108603 id -108602 +108603 base @@ -42536,7 +42116,7 @@ 1 2 -108602 +108603 @@ -42576,7 +42156,7 @@ 20 -45957 +45958 219 @@ -42587,15 +42167,15 @@ cil_base_interface -52126 +52127 id -25869 +25870 base -16465 +16466 @@ -42609,7 +42189,7 @@ 1 2 -16163 +16164 2 @@ -42650,7 +42230,7 @@ 1 2 -12889 +12890 2 @@ -42891,11 +42471,11 @@ cil_type_argument -242722 +242724 bound -171457 +171459 index @@ -42917,7 +42497,7 @@ 1 2 -120678 +120680 2 @@ -42943,7 +42523,7 @@ 1 2 -122717 +122719 2 @@ -43008,7 +42588,7 @@ 7664 -171458 +171460 3 @@ -43991,15 +43571,15 @@ metadata_handle -5245589 +5188835 entity -2712144 +3004043 location -1806 +1703 handle @@ -44017,27 +43597,27 @@ 1 2 -1333886 +1502534 2 3 -920872 +1109759 3 4 -171626 +156365 4 6 -221369 +226414 6 -591 -64391 +16 +8971 @@ -44053,27 +43633,22 @@ 1 2 -1843036 +2108097 2 3 -491566 +607938 3 4 -162465 +139145 4 -10 -206601 - - -10 -39 -8476 +13 +148863 @@ -44087,64 +43662,59 @@ 12 -1 -2 -22 - - 2 3 464 -3 +4 13 -146 +141 14 -88 -136 +93 +128 -88 -208 -136 +93 +213 +128 -208 -409 -137 +213 +418 +130 -410 -658 -137 +418 +666 +128 -663 -1103 -136 +666 +1113 +128 -1105 -1792 -136 +1115 +1811 +128 -1795 -3903 -136 +1825 +4029 +128 -3999 -13105 -137 +4055 +15302 +128 -13241 +15445 110459 -83 +72 @@ -44160,57 +43730,57 @@ 1 2 -486 +464 2 7 -142 +140 7 -46 -136 +48 +129 -46 -113 -137 +48 +114 +129 -113 -222 -136 +114 +225 +130 -223 -355 -136 +225 +360 +129 -359 +360 579 -137 +128 583 -1038 -137 +1033 +128 -1039 -2262 -136 +1037 +2272 +128 -2268 -7743 -136 +2297 +8607 +129 -7800 +8727 110459 -87 +69 @@ -44231,47 +43801,47 @@ 2 3 -53204 +52480 3 7 -9098 +9134 7 15 -8859 +9762 15 -26 -9051 +28 +9288 -26 -39 -8919 +28 +42 +8952 -39 -63 -9148 +42 +65 +8905 -63 -104 -8882 +65 +105 +8954 -104 -539 -8794 +105 +652 +8790 -539 -1544 -878 +652 +1533 +568 @@ -44292,42 +43862,42 @@ 4 5 -55971 +55970 5 -12 -9795 +11 +8999 -12 -20 -8862 +11 +18 +9170 -20 -28 -9240 +18 +26 +9007 -28 -43 -8804 +26 +40 +9508 -43 -63 -8904 +40 +61 +8955 -63 -200 -8803 +61 +185 +8830 -200 -1807 -2555 +185 +1704 +2495 From e990bea248d280239b99c240acf3284d6b9e14a4 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Tue, 12 Nov 2019 11:50:06 +0000 Subject: [PATCH 1048/1227] C#: Update upgrade script --- .../semmlecode.csharp.dbscheme | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme b/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme index e55d8c99030..df0118d2d28 100644 --- a/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme +++ b/csharp/upgrades/f93793ee5f6b7bec615eaa1af0a1a4dea19472bb/semmlecode.csharp.dbscheme @@ -480,8 +480,8 @@ case @nullability.kind of | 2 = @annotated ; -#keyset[nullability, index] -nullability_member(int nullability: @nullability ref, int index: int ref, int child: @nullability ref) +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref) From f50dd84c490f257118f389c3f6869de534f77576 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 12 Nov 2019 14:09:54 +0000 Subject: [PATCH 1049/1227] CPP: Rename good and bad example files. --- .../{NtohlArrayBad.cpp => NtohlArrayNoBound-bad.cpp} | 0 .../{NtohlArrayGood.cpp => NtohlArrayNoBound-good.cpp} | 0 .../src/Likely Bugs/Memory Management/NtohlArrayNoBound.qhelp | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename cpp/ql/src/Likely Bugs/Memory Management/{NtohlArrayBad.cpp => NtohlArrayNoBound-bad.cpp} (100%) rename cpp/ql/src/Likely Bugs/Memory Management/{NtohlArrayGood.cpp => NtohlArrayNoBound-good.cpp} (100%) diff --git a/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayBad.cpp b/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound-bad.cpp similarity index 100% rename from cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayBad.cpp rename to cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound-bad.cpp diff --git a/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayGood.cpp b/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound-good.cpp similarity index 100% rename from cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayGood.cpp rename to cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound-good.cpp diff --git a/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qhelp b/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qhelp index fc8f309f73a..3556df38c58 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qhelp +++ b/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qhelp @@ -31,10 +31,10 @@ it to host byte order. The data is then used as an index in an array access expr there is no validation that the data returned by ntohl is within the bounds of the array, which could lead to reading outside the bounds of the buffer.

    - +

    In the corrected example, the returned data is validated against the known size of the buffer, before being used as an array index.

    - + From 0343bd6b9ca51035919ae7a01c74cb6867093707 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 12 Nov 2019 14:37:56 +0000 Subject: [PATCH 1050/1227] CPP: Inline BufferAccess into NtohlArrayNoBound.qll (we'd prefer other queries to be written with the models library or Security.BufferAccess). --- .../Memory Management/BufferAccess.qll | 174 ------------------ .../Memory Management/NtohlArrayNoBound.qll | 174 +++++++++++++++++- 2 files changed, 173 insertions(+), 175 deletions(-) delete mode 100644 cpp/ql/src/Likely Bugs/Memory Management/BufferAccess.qll diff --git a/cpp/ql/src/Likely Bugs/Memory Management/BufferAccess.qll b/cpp/ql/src/Likely Bugs/Memory Management/BufferAccess.qll deleted file mode 100644 index 286db31020f..00000000000 --- a/cpp/ql/src/Likely Bugs/Memory Management/BufferAccess.qll +++ /dev/null @@ -1,174 +0,0 @@ -import cpp -import semmle.code.cpp.dataflow.TaintTracking -private import semmle.code.cpp.dataflow.RecursionPrevention - -/** - * A buffer which includes an allocation size. - */ -abstract class BufferWithSize extends DataFlow::Node { - abstract Expr getSizeExpr(); - - BufferAccess getAnAccess() { - any(BufferWithSizeConfig bsc).hasFlow(this, DataFlow::exprNode(result.getPointer())) - } -} - -/** An allocation function. */ -abstract class Alloc extends Function { } - -/** - * Allocation functions identified by the QL for C/C++ standard library. - */ -class DefaultAlloc extends Alloc { - DefaultAlloc() { allocationFunction(this) } -} - -/** A buffer created through a call to an allocation function. */ -class AllocBuffer extends BufferWithSize { - FunctionCall call; - - AllocBuffer() { - asExpr() = call and - call.getTarget() instanceof Alloc - } - - override Expr getSizeExpr() { result = call.getArgument(0) } -} - -/** - * Find accesses of buffers for which we have a size expression. - */ -private class BufferWithSizeConfig extends TaintTracking::Configuration { - BufferWithSizeConfig() { this = "BufferWithSize" } - - override predicate isSource(DataFlow::Node n) { n = any(BufferWithSize b) } - - override predicate isSink(DataFlow::Node n) { n.asExpr() = any(BufferAccess ae).getPointer() } - - override predicate isSanitizer(DataFlow::Node s) { - s = any(BufferWithSize b) and - s.asExpr().getControlFlowScope() instanceof Alloc - } -} - -/** - * An access (read or write) to a buffer, provided as a pair of - * a pointer to the buffer and the length of data to be read or written. - * Extend this class to support different kinds of buffer access. - */ -abstract class BufferAccess extends Locatable { - /** Gets the pointer to the buffer being accessed. */ - abstract Expr getPointer(); - - /** Gets the length of the data being read or written by this buffer access. */ - abstract Expr getAccessedLength(); -} - -/** - * A buffer access through an array expression. - */ -class ArrayBufferAccess extends BufferAccess, ArrayExpr { - override Expr getPointer() { result = this.getArrayBase() } - - override Expr getAccessedLength() { result = this.getArrayOffset() } -} - -/** - * A buffer access through an overloaded array expression. - */ -class OverloadedArrayBufferAccess extends BufferAccess, OverloadedArrayExpr { - override Expr getPointer() { result = this.getQualifier() } - - override Expr getAccessedLength() { result = this.getAnArgument() } -} - -/** - * A buffer access through pointer arithmetic. - */ -class PointerArithmeticAccess extends BufferAccess, Expr { - PointerArithmeticOperation p; - - PointerArithmeticAccess() { - this = p and - p.getAnOperand().getType().getUnspecifiedType() instanceof IntegralType and - not p.getParent() instanceof ComparisonOperation - } - - override Expr getPointer() { - result = p.getAnOperand() and - result.getType().getUnspecifiedType() instanceof PointerType - } - - override Expr getAccessedLength() { - result = p.getAnOperand() and - result.getType().getUnspecifiedType() instanceof IntegralType - } -} - -/** - * A pair of buffer accesses through a call to memcpy. - */ -class MemCpy extends BufferAccess, FunctionCall { - MemCpy() { getTarget().hasName("memcpy") } - - override Expr getPointer() { - result = getArgument(0) or - result = getArgument(1) - } - - override Expr getAccessedLength() { result = getArgument(2) } -} - -class StrncpySizeExpr extends BufferAccess, FunctionCall { - StrncpySizeExpr() { getTarget().hasName("strncpy") } - - override Expr getPointer() { - result = getArgument(0) or - result = getArgument(1) - } - - override Expr getAccessedLength() { result = getArgument(2) } -} - -class RecvSizeExpr extends BufferAccess, FunctionCall { - RecvSizeExpr() { getTarget().hasName("recv") } - - override Expr getPointer() { result = getArgument(1) } - - override Expr getAccessedLength() { result = getArgument(2) } -} - -class SendSizeExpr extends BufferAccess, FunctionCall { - SendSizeExpr() { getTarget().hasName("send") } - - override Expr getPointer() { result = getArgument(1) } - - override Expr getAccessedLength() { result = getArgument(2) } -} - -class SnprintfSizeExpr extends BufferAccess, FunctionCall { - SnprintfSizeExpr() { getTarget().hasName("snprintf") } - - override Expr getPointer() { result = getArgument(0) } - - override Expr getAccessedLength() { result = getArgument(1) } -} - -class MemcmpSizeExpr extends BufferAccess, FunctionCall { - MemcmpSizeExpr() { getTarget().hasName("Memcmp") } - - override Expr getPointer() { - result = getArgument(0) or - result = getArgument(1) - } - - override Expr getAccessedLength() { result = getArgument(2) } -} - -class MallocSizeExpr extends BufferAccess, FunctionCall { - MallocSizeExpr() { getTarget().hasName("malloc") } - - override Expr getPointer() { none() } - - override Expr getAccessedLength() { result = getArgument(1) } -} diff --git a/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll b/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll index 3e1f74bfbed..306c7251667 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll +++ b/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll @@ -1,8 +1,180 @@ import cpp import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Guards -import BufferAccess import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.dataflow.TaintTracking +private import semmle.code.cpp.dataflow.RecursionPrevention + +/** + * A buffer which includes an allocation size. + */ +abstract class BufferWithSize extends DataFlow::Node { + abstract Expr getSizeExpr(); + + BufferAccess getAnAccess() { + any(BufferWithSizeConfig bsc).hasFlow(this, DataFlow::exprNode(result.getPointer())) + } +} + +/** An allocation function. */ +abstract class Alloc extends Function { } + +/** + * Allocation functions identified by the QL for C/C++ standard library. + */ +class DefaultAlloc extends Alloc { + DefaultAlloc() { allocationFunction(this) } +} + +/** A buffer created through a call to an allocation function. */ +class AllocBuffer extends BufferWithSize { + FunctionCall call; + + AllocBuffer() { + asExpr() = call and + call.getTarget() instanceof Alloc + } + + override Expr getSizeExpr() { result = call.getArgument(0) } +} + +/** + * Find accesses of buffers for which we have a size expression. + */ +private class BufferWithSizeConfig extends TaintTracking::Configuration { + BufferWithSizeConfig() { this = "BufferWithSize" } + + override predicate isSource(DataFlow::Node n) { n = any(BufferWithSize b) } + + override predicate isSink(DataFlow::Node n) { n.asExpr() = any(BufferAccess ae).getPointer() } + + override predicate isSanitizer(DataFlow::Node s) { + s = any(BufferWithSize b) and + s.asExpr().getControlFlowScope() instanceof Alloc + } +} + +/** + * An access (read or write) to a buffer, provided as a pair of + * a pointer to the buffer and the length of data to be read or written. + * Extend this class to support different kinds of buffer access. + */ +abstract class BufferAccess extends Locatable { + /** Gets the pointer to the buffer being accessed. */ + abstract Expr getPointer(); + + /** Gets the length of the data being read or written by this buffer access. */ + abstract Expr getAccessedLength(); +} + +/** + * A buffer access through an array expression. + */ +class ArrayBufferAccess extends BufferAccess, ArrayExpr { + override Expr getPointer() { result = this.getArrayBase() } + + override Expr getAccessedLength() { result = this.getArrayOffset() } +} + +/** + * A buffer access through an overloaded array expression. + */ +class OverloadedArrayBufferAccess extends BufferAccess, OverloadedArrayExpr { + override Expr getPointer() { result = this.getQualifier() } + + override Expr getAccessedLength() { result = this.getAnArgument() } +} + +/** + * A buffer access through pointer arithmetic. + */ +class PointerArithmeticAccess extends BufferAccess, Expr { + PointerArithmeticOperation p; + + PointerArithmeticAccess() { + this = p and + p.getAnOperand().getType().getUnspecifiedType() instanceof IntegralType and + not p.getParent() instanceof ComparisonOperation + } + + override Expr getPointer() { + result = p.getAnOperand() and + result.getType().getUnspecifiedType() instanceof PointerType + } + + override Expr getAccessedLength() { + result = p.getAnOperand() and + result.getType().getUnspecifiedType() instanceof IntegralType + } +} + +/** + * A pair of buffer accesses through a call to memcpy. + */ +class MemCpy extends BufferAccess, FunctionCall { + MemCpy() { getTarget().hasName("memcpy") } + + override Expr getPointer() { + result = getArgument(0) or + result = getArgument(1) + } + + override Expr getAccessedLength() { result = getArgument(2) } +} + +class StrncpySizeExpr extends BufferAccess, FunctionCall { + StrncpySizeExpr() { getTarget().hasName("strncpy") } + + override Expr getPointer() { + result = getArgument(0) or + result = getArgument(1) + } + + override Expr getAccessedLength() { result = getArgument(2) } +} + +class RecvSizeExpr extends BufferAccess, FunctionCall { + RecvSizeExpr() { getTarget().hasName("recv") } + + override Expr getPointer() { result = getArgument(1) } + + override Expr getAccessedLength() { result = getArgument(2) } +} + +class SendSizeExpr extends BufferAccess, FunctionCall { + SendSizeExpr() { getTarget().hasName("send") } + + override Expr getPointer() { result = getArgument(1) } + + override Expr getAccessedLength() { result = getArgument(2) } +} + +class SnprintfSizeExpr extends BufferAccess, FunctionCall { + SnprintfSizeExpr() { getTarget().hasName("snprintf") } + + override Expr getPointer() { result = getArgument(0) } + + override Expr getAccessedLength() { result = getArgument(1) } +} + +class MemcmpSizeExpr extends BufferAccess, FunctionCall { + MemcmpSizeExpr() { getTarget().hasName("Memcmp") } + + override Expr getPointer() { + result = getArgument(0) or + result = getArgument(1) + } + + override Expr getAccessedLength() { result = getArgument(2) } +} + +class MallocSizeExpr extends BufferAccess, FunctionCall { + MallocSizeExpr() { getTarget().hasName("malloc") } + + override Expr getPointer() { none() } + + override Expr getAccessedLength() { result = getArgument(1) } +} class NetworkFunctionCall extends FunctionCall { NetworkFunctionCall() { From 5c87ed5ab27afbf8004be654615cb709cceb37ec Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 12 Nov 2019 14:43:08 +0000 Subject: [PATCH 1051/1227] CPP: Remove unused code. --- .../Memory Management/NtohlArrayNoBound.qll | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll b/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll index 306c7251667..0871da2f92e 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll +++ b/cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll @@ -2,57 +2,6 @@ import cpp import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Guards import semmle.code.cpp.valuenumbering.GlobalValueNumbering -import semmle.code.cpp.dataflow.TaintTracking -private import semmle.code.cpp.dataflow.RecursionPrevention - -/** - * A buffer which includes an allocation size. - */ -abstract class BufferWithSize extends DataFlow::Node { - abstract Expr getSizeExpr(); - - BufferAccess getAnAccess() { - any(BufferWithSizeConfig bsc).hasFlow(this, DataFlow::exprNode(result.getPointer())) - } -} - -/** An allocation function. */ -abstract class Alloc extends Function { } - -/** - * Allocation functions identified by the QL for C/C++ standard library. - */ -class DefaultAlloc extends Alloc { - DefaultAlloc() { allocationFunction(this) } -} - -/** A buffer created through a call to an allocation function. */ -class AllocBuffer extends BufferWithSize { - FunctionCall call; - - AllocBuffer() { - asExpr() = call and - call.getTarget() instanceof Alloc - } - - override Expr getSizeExpr() { result = call.getArgument(0) } -} - -/** - * Find accesses of buffers for which we have a size expression. - */ -private class BufferWithSizeConfig extends TaintTracking::Configuration { - BufferWithSizeConfig() { this = "BufferWithSize" } - - override predicate isSource(DataFlow::Node n) { n = any(BufferWithSize b) } - - override predicate isSink(DataFlow::Node n) { n.asExpr() = any(BufferAccess ae).getPointer() } - - override predicate isSanitizer(DataFlow::Node s) { - s = any(BufferWithSize b) and - s.asExpr().getControlFlowScope() instanceof Alloc - } -} /** * An access (read or write) to a buffer, provided as a pair of From 5b2e32b0513463d4c5f29fcea133e6f761555ba6 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 12 Nov 2019 15:03:02 +0000 Subject: [PATCH 1052/1227] Add `qlpack.yml` files for test folders. --- cpp/ql/test/qlpack.yml | 3 +++ csharp/ql/test/qlpack.yml | 3 +++ java/ql/test/qlpack.yml | 3 +++ javascript/ql/test/qlpack.yml | 3 +++ python/ql/test/qlpack.yml | 3 +++ 5 files changed, 15 insertions(+) create mode 100644 cpp/ql/test/qlpack.yml create mode 100644 csharp/ql/test/qlpack.yml create mode 100644 java/ql/test/qlpack.yml create mode 100644 javascript/ql/test/qlpack.yml create mode 100644 python/ql/test/qlpack.yml diff --git a/cpp/ql/test/qlpack.yml b/cpp/ql/test/qlpack.yml new file mode 100644 index 00000000000..36dcb70d4ef --- /dev/null +++ b/cpp/ql/test/qlpack.yml @@ -0,0 +1,3 @@ +name: codeql-cpp-tests +version: 0.0.0 +libraryPathDependencies: codeql-cpp diff --git a/csharp/ql/test/qlpack.yml b/csharp/ql/test/qlpack.yml new file mode 100644 index 00000000000..20f6e83ee30 --- /dev/null +++ b/csharp/ql/test/qlpack.yml @@ -0,0 +1,3 @@ +name: codeql-csharp-tests +version: 0.0.0 +libraryPathDependencies: codeql-csharp diff --git a/java/ql/test/qlpack.yml b/java/ql/test/qlpack.yml new file mode 100644 index 00000000000..d4b46d7d2b0 --- /dev/null +++ b/java/ql/test/qlpack.yml @@ -0,0 +1,3 @@ +name: codeql-java-tests +version: 0.0.0 +libraryPathDependencies: codeql-java diff --git a/javascript/ql/test/qlpack.yml b/javascript/ql/test/qlpack.yml new file mode 100644 index 00000000000..d40472ed653 --- /dev/null +++ b/javascript/ql/test/qlpack.yml @@ -0,0 +1,3 @@ +name: codeql-javascript-tests +version: 0.0.0 +libraryPathDependencies: codeql-javascript diff --git a/python/ql/test/qlpack.yml b/python/ql/test/qlpack.yml new file mode 100644 index 00000000000..eed82a82aec --- /dev/null +++ b/python/ql/test/qlpack.yml @@ -0,0 +1,3 @@ +name: codeql-python-tests +version: 0.0.0 +libraryPathDependencies: codeql-python From ea9e3bb1a89d22ebad7f8ca81c6d2bd353226cf0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 12 Nov 2019 16:17:03 +0000 Subject: [PATCH 1053/1227] CPP: Rename VirtualDispatch again. --- cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll | 2 +- .../VirtualDispatchPrototype.qll} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename cpp/ql/src/semmle/code/cpp/{controlflow/VirtualDispatch.qll => dispatch/VirtualDispatchPrototype.qll} (100%) diff --git a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll index 0d7b9083846..8f2950c9123 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll +++ b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll @@ -4,7 +4,7 @@ import cpp import external.ExternalArtifact -private import semmle.code.cpp.controlflow.VirtualDispatch +private import semmle.code.cpp.dispatch.VirtualDispatchPrototype import semmle.code.cpp.NestedFields import Microsoft.SAL import semmle.code.cpp.controlflow.Guards diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/VirtualDispatch.qll b/cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatchPrototype.qll similarity index 100% rename from cpp/ql/src/semmle/code/cpp/controlflow/VirtualDispatch.qll rename to cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatchPrototype.qll From 8cd6b5176316d00e06a59f27f01fbf7d6c909de9 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 12 Nov 2019 17:27:18 +0100 Subject: [PATCH 1054/1227] Java: Add ConditionalExpr to overflow candidate pattern. --- java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql | 5 +++++ java/ql/test/query-tests/UselessComparisonTest/A.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql b/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql index e28b190b465..af37df936e0 100644 --- a/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql +++ b/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql @@ -132,6 +132,11 @@ Expr overFlowCand() { result.(AssignExpr).getRhs() = overFlowCand() or result.(LocalVariableDeclExpr).getInit() = overFlowCand() + or + exists(ConditionalExpr c | c = result | + c.getTrueExpr() = overFlowCand() and + c.getFalseExpr() = overFlowCand() + ) } predicate positiveOrNegative(Expr e) { positive(e) or negative(e) } diff --git a/java/ql/test/query-tests/UselessComparisonTest/A.java b/java/ql/test/query-tests/UselessComparisonTest/A.java index f2b473c2ee3..abc525ff20d 100644 --- a/java/ql/test/query-tests/UselessComparisonTest/A.java +++ b/java/ql/test/query-tests/UselessComparisonTest/A.java @@ -121,6 +121,11 @@ public class A { } } + void overflowTests2(int[] a, boolean b) { + int newlen = b ? (a.length + 1) << 1 : (a.length >> 1) + a.length; + if (newlen < 0) overflow(); + } + static final long VAL = 100L; long overflowAwareIncrease(long x) { From 7619275c8bcf21db7e46faf5c4799be564ea3bbf Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 12 Nov 2019 15:59:59 +0100 Subject: [PATCH 1055/1227] Java: Fix range analysis bug in integral inequality bounds. --- .../semmle/code/java/dataflow/RangeAnalysis.qll | 15 +++++++++------ .../test/query-tests/UselessComparisonTest/C.java | 6 ++++++ 2 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 java/ql/test/query-tests/UselessComparisonTest/C.java diff --git a/java/ql/src/semmle/code/java/dataflow/RangeAnalysis.qll b/java/ql/src/semmle/code/java/dataflow/RangeAnalysis.qll index 41ed735b752..f8384245073 100644 --- a/java/ql/src/semmle/code/java/dataflow/RangeAnalysis.qll +++ b/java/ql/src/semmle/code/java/dataflow/RangeAnalysis.qll @@ -298,10 +298,11 @@ private predicate boundFlowStepSsa( ) } -/** Holds if `v != e + delta` at `pos`. */ -private predicate unequalFlowStepSsa( +/** Holds if `v != e + delta` at `pos` and `v` is of integral type. */ +private predicate unequalFlowStepIntegralSsa( SsaVariable v, SsaReadPosition pos, Expr e, int delta, Reason reason ) { + v.getSourceVariable().getType() instanceof IntegralType and exists(Guard guard, boolean testIsTrue | pos.hasReadOfVar(v) and guard = eqFlowCond(v, e, delta, false, testIsTrue) and @@ -555,7 +556,7 @@ private predicate boundedSsa( boundedSsa(v, pos, b, d, upper, fromBackEdge, origdelta, r2) or boundedPhi(v, b, d, upper, fromBackEdge, origdelta, r2) | - unequalSsa(v, pos, b, d, r1) and + unequalIntegralSsa(v, pos, b, d, r1) and ( upper = true and delta = d - 1 or @@ -570,11 +571,13 @@ private predicate boundedSsa( } /** - * Holds if `v != b + delta` at `pos`. + * Holds if `v != b + delta` at `pos` and `v` is of integral type. */ -private predicate unequalSsa(SsaVariable v, SsaReadPosition pos, Bound b, int delta, Reason reason) { +private predicate unequalIntegralSsa( + SsaVariable v, SsaReadPosition pos, Bound b, int delta, Reason reason +) { exists(Expr e, int d1, int d2 | - unequalFlowStepSsa(v, pos, e, d1, reason) and + unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and bounded(e, b, d2, true, _, _, _) and bounded(e, b, d2, false, _, _, _) and delta = d2 + d1 diff --git a/java/ql/test/query-tests/UselessComparisonTest/C.java b/java/ql/test/query-tests/UselessComparisonTest/C.java new file mode 100644 index 00000000000..c1ca8261eb2 --- /dev/null +++ b/java/ql/test/query-tests/UselessComparisonTest/C.java @@ -0,0 +1,6 @@ +public class C { + double m1(double x) { + return (x < 0 || x > 1 || Double.isNaN(x)) ? Double.NaN : + x == 0 ? 0 : x == 1 ? 1 : 0.5; + } +} From f54e0d0d07425b269f7e5269059c8b7bd7c774fe Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 26 Aug 2019 11:04:42 -0700 Subject: [PATCH 1056/1227] [CPP-418] Initial modifications to Type.qll. To be continued. --- cpp/ql/src/semmle/code/cpp/Type.qll | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index ea1e7fd5026..a838a09eebf 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -5,6 +5,8 @@ private import semmle.code.cpp.internal.ResolveClass /** * A C/C++ type. + * + * This QL class represents the root of the C/C++ type hierarchy. */ class Type extends Locatable, @type { Type() { isType(underlyingElement(this)) } @@ -289,6 +291,13 @@ class Type extends Locatable, @type { /** * A C/C++ built-in primitive type (int, float, void, and so on). See 4.1.1. + * In the following example, `unsigned int` and `double` denote primitive + * built-in types: + * ``` + * double a; + * unsigned int ua[40]; + * typedef double LargeFloat; + * ``` */ class BuiltInType extends Type, @builtintype { override string toString() { result = this.getName() } From 1f35f4bb522ad1ca258dea3c242df5889b682440 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 2 Sep 2019 15:45:38 -0700 Subject: [PATCH 1057/1227] [CPP-418] Add descriptions for QL classes in Type.qll. (Still need to figure out how to describe unknown and erroneous types.) --- cpp/ql/src/semmle/code/cpp/Type.qll | 302 +++++++++++++++++++++++----- 1 file changed, 252 insertions(+), 50 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index a838a09eebf..a90b87bc7ac 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -310,7 +310,7 @@ class BuiltInType extends Type, @builtintype { } /** - * An erroneous type. + * An erroneous type. This type has no corresponding C/C++ syntax. */ class ErroneousType extends BuiltInType { ErroneousType() { builtintypes(underlyingElement(this), _, 1, _, _, _) } @@ -319,7 +319,7 @@ class ErroneousType extends BuiltInType { } /** - * The unknown type. + * The unknown type. This type has no corresponding C/C++ syntax. */ class UnknownType extends BuiltInType { UnknownType() { builtintypes(underlyingElement(this), _, 2, _, _, _) } @@ -335,6 +335,10 @@ private predicate isArithmeticType(@builtintype type, int kind) { /** * The C/C++ arithmetic types. See 4.1.1. + * + * This includes primitive types on which arithmetic, bitwise or logical + * operations may be performed. Examples of arithmetic types include + * `char`, `int`, `float` and `bool`. */ class ArithmeticType extends BuiltInType { ArithmeticType() { isArithmeticType(underlyingElement(this), _) } @@ -359,10 +363,19 @@ private predicate isIntegralType(@builtintype type, int kind) { /** * A C/C++ integral or enum type. - * The definition of "integral type" in the C++ Standard excludes enum types, - * but because an enum type holds a value of its underlying integral type, + * + * The definition of "integral type" in the C++ Standard excludes `enum` types, + * but because an `enum` type holds a value of its underlying integral type, * it is often useful to have a common category that includes both integral - * and enum types. + * and `enum` types. + * + * In the following example, `a`, `b` and `c` are all declared with an + * integral or `enum` type: + * ``` + * unsigned long a; + * enum e1 { val1, val2 } b; + * enum class e2: short { val3, val4 } c; + * ``` */ class IntegralOrEnumType extends Type { IntegralOrEnumType() { @@ -435,7 +448,17 @@ private predicate integralTypeMapping(int original, int canonical, int unsigned, } /** - * The C/C++ integral types. See 4.1.1. + * The C/C++ integral types. See 4.1.1. These are types that are represented + * as integers of varying sizes. Both `enum` types and floating-point types + * are excluded. + * + * In the following examples, `a`, `b` and `c` are declared using integral + * types: + * ``` + * unsigned int a; + * long long b; + * char c; + * ``` */ class IntegralType extends ArithmeticType, IntegralOrEnumType { int kind; @@ -506,7 +529,12 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType { } /** - * The C/C++ boolean type. See 4.2. + * The C/C++ boolean type. See 4.2. This is the C `_Bool` type + * or the C++ `bool` type. For example, + * ``` + * extern bool a, b; // C++ + * _Bool c, d; // C + * ``` */ class BoolType extends IntegralType { BoolType() { builtintypes(underlyingElement(this), _, 4, _, _, _) } @@ -515,12 +543,23 @@ class BoolType extends IntegralType { } /** - * The C/C++ character types. See 4.3. + * The C/C++ character types. See 4.3. This includes the `char`, + * `signed char` and `unsigned char` types, all of which are + * distinct from one another. For example, + * ``` + * char a, b; + * signed char c, d; + * unsigned char e, f; + * ``` */ abstract class CharType extends IntegralType { } /** - * The C/C++ char type (which is different to signed char and unsigned char). + * The C/C++ `char` type (which is distinct from `signed char` and + * `unsigned char`). For example, + * ``` + * char a, b; + * ``` */ class PlainCharType extends CharType { PlainCharType() { builtintypes(underlyingElement(this), _, 5, _, _, _) } @@ -529,7 +568,11 @@ class PlainCharType extends CharType { } /** - * The C/C++ unsigned char type (which is different to plain char, even when chars are unsigned by default). + * The C/C++ `unsigned char` type (which is distinct from plain `char` + * even when `char` is unsigned by default). + * ``` + * unsigned char e, f; + * ``` */ class UnsignedCharType extends CharType { UnsignedCharType() { builtintypes(underlyingElement(this), _, 6, _, _, _) } @@ -538,7 +581,11 @@ class UnsignedCharType extends CharType { } /** - * The C/C++ signed char type (which is different to plain char, even when chars are signed by default). + * The C/C++ `signed char` type (which is distinct from plain `char` + * even when `char` is signed by default). + * ``` + * signed char c, d; + * ``` */ class SignedCharType extends CharType { SignedCharType() { builtintypes(underlyingElement(this), _, 7, _, _, _) } @@ -547,7 +594,11 @@ class SignedCharType extends CharType { } /** - * The C/C++ short types. See 4.3. + * The C/C++ short types. See 4.3. This includes `short`, `signed short` + * and `unsigned short`; `short` and `signed short` are equivalent. + * ``` + * signed short ss; + * ``` */ class ShortType extends IntegralType { ShortType() { @@ -560,7 +611,11 @@ class ShortType extends IntegralType { } /** - * The C/C++ integer types. See 4.4. + * The C/C++ integer types. See 4.4. This includes `int`, `signed int` + * and `unsigned int`; `int` and `signed int` are equivalent. + * ``` + * unsigned int ui; + * ``` */ class IntType extends IntegralType { IntType() { @@ -573,7 +628,11 @@ class IntType extends IntegralType { } /** - * The C/C++ long types. See 4.4. + * The C/C++ long types. See 4.4. This includes `long`, `signed long` + * and `unsigned long`; `long` and `signed long` are equivalent. + * ``` + * long l; + * ``` */ class LongType extends IntegralType { LongType() { @@ -586,7 +645,11 @@ class LongType extends IntegralType { } /** - * The C/C++ long long types. See 4.4. + * The C/C++ long long types. See 4.4. This includes `long long`, `signed long long` + * and `unsigned long long`; `long long` and `signed long long` are equivalent. + * ``` + * signed long long sll; + * ``` */ class LongLongType extends IntegralType { LongLongType() { @@ -599,7 +662,13 @@ class LongLongType extends IntegralType { } /** - * The GNU C __int128 types. + * The GNU C __int128 primitive types. They are not part of standard C/C++. + * + * This includes `__int128`, `signed __int128` + * and `unsigned __int128`; `__int128` and `signed __int128` are equivalent. + * ``` + * unsigned __int128 ui128; + * ``` */ class Int128Type extends IntegralType { Int128Type() { @@ -607,10 +676,18 @@ class Int128Type extends IntegralType { builtintypes(underlyingElement(this), _, 36, _, _, _) or builtintypes(underlyingElement(this), _, 37, _, _, _) } + + override string getCanonicalQLClass() { result = "Int128Type" } } /** - * The C/C++ floating point types. See 4.5. + * The C/C++ floating point types. See 4.5. This includes `float`, + * `double` and `long double` types. + * ``` + * float f; + * double d; + * long double ld; + * ``` */ class FloatingPointType extends ArithmeticType { FloatingPointType() { @@ -628,7 +705,10 @@ class FloatingPointType extends ArithmeticType { } /** - * The C/C++ float type. + * The C/C++ `float` type. + * ``` + * float f; + * ``` */ class FloatType extends FloatingPointType { FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) } @@ -637,7 +717,10 @@ class FloatType extends FloatingPointType { } /** - * The C/C++ double type. + * The C/C++ `double` type. + * ``` + * double d; + * ``` */ class DoubleType extends FloatingPointType { DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) } @@ -646,7 +729,10 @@ class DoubleType extends FloatingPointType { } /** - * The C/C++ long double type. + * The C/C++ `long double` type. + * ``` + * long double ld; + * ``` */ class LongDoubleType extends FloatingPointType { LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) } @@ -655,35 +741,58 @@ class LongDoubleType extends FloatingPointType { } /** - * The GNU C __float128 type. + * The GNU C `__float128` primitive type. This is not standard C/C++. + * ``` + * __float128 f128; + * ``` */ class Float128Type extends FloatingPointType { Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) } + + override string getCanonicalQLClass() { result = "Float128Type" } } /** - * The GNU C _Decimal32 type. + * The GNU C `_Decimal32` primitive type. This is not standard C/C++. + * ``` + * _Decimal32 d32; + * ``` */ class Decimal32Type extends FloatingPointType { Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) } + + override string getCanonicalQLClass() { result = "Decimal32Type" } } /** - * The GNU C _Decimal64 type. + * The GNU C `_Decimal64` primitive type. This is not standard C/C++. + * ``` + * _Decimal64 d64; + * ``` */ class Decimal64Type extends FloatingPointType { Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) } + + override string getCanonicalQLClass() { result = "Decimal64Type" } } /** - * The GNU C _Decimal128 type. + * The GNU C `_Decimal128` primitive type. This is not standard C/C++. + * ``` + * _Decimal128 d128; + * ``` */ class Decimal128Type extends FloatingPointType { Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) } + + override string getCanonicalQLClass() { result = "Decimal128Type" } } /** - * The C/C++ void type. See 4.7. + * The C/C++ `void` type. See 4.7. + * ``` + * const void *cvp; + * ``` */ class VoidType extends BuiltInType { VoidType() { builtintypes(underlyingElement(this), _, 3, _, _, _) } @@ -697,6 +806,9 @@ class VoidType extends BuiltInType { * Note that on some platforms `wchar_t` doesn't exist as a built-in * type but a typedef is provided. Consider using the `Wchar_t` QL * class to include these types. + * ``` + * wchar_t wc; + * ``` */ class WideCharType extends IntegralType { WideCharType() { builtintypes(underlyingElement(this), _, 33, _, _, _) } @@ -705,7 +817,10 @@ class WideCharType extends IntegralType { } /** - * The C/C++ `char16_t` type. + * The C/C++ `char16_t` type. This is available starting with C11 and C++11. + * ``` + * char16_t c16; + * ``` */ class Char16Type extends IntegralType { Char16Type() { builtintypes(underlyingElement(this), _, 43, _, _, _) } @@ -714,7 +829,10 @@ class Char16Type extends IntegralType { } /** - * The C/C++ `char32_t` type. + * The C/C++ `char32_t` type. This is available starting with C11 and C++11. + * ``` + * char32_t c32; + * ``` */ class Char32Type extends IntegralType { Char32Type() { builtintypes(underlyingElement(this), _, 44, _, _, _) } @@ -723,13 +841,11 @@ class Char32Type extends IntegralType { } /** - * The type of the C++11 nullptr constant. - * - * Note that this is not `nullptr_t`, as `nullptr_t` is defined as: + * The (primitive) type of the C++11 `nullptr` constant. It is the + * unspeakable type given by `decltype(nullptr)`. * ``` - * typedef decltype(nullptr) nullptr_t; + * typedef decltype(nullptr) nullptr_t; * ``` - * Instead, this is the unspeakable type given by `decltype(nullptr)`. */ class NullPointerType extends BuiltInType { NullPointerType() { builtintypes(underlyingElement(this), _, 34, _, _, _) } @@ -740,8 +856,14 @@ class NullPointerType extends BuiltInType { /** * A C/C++ derived type. * - * These are pointer and reference types, array and vector types, and const and volatile types. - * In all cases, the type is formed from a single base type. + * These are pointer and reference types, array and GNU vector types, and `const` and `volatile` types. + * In all cases, the type is formed from a single base type. For example, + * ``` + * int *pi; + * int &ri = *pi; + * const float fa[40]; + * decltype(pi) dpi; + * ``` */ class DerivedType extends Type, @derivedtype { override string toString() { result = this.getName() } @@ -786,9 +908,16 @@ class DerivedType extends Type, @derivedtype { } /** - * An instance of the C++11 decltype operator. + * An instance of the C++11 `decltype` operator. For example, + * ``` + * int a; + * decltype(a) b; + * ``` */ class Decltype extends Type, @decltype { + + override string getCanonicalQLClass() { result = "Decltype" } + /** * The expression whose type is being obtained by this decltype. */ @@ -852,6 +981,10 @@ class Decltype extends Type, @decltype { /** * A C/C++ pointer type. See 4.9.1. + * ``` + * void *ptr; + * void **ptr2 = &ptr; + * ``` */ class PointerType extends DerivedType { PointerType() { derivedtypes(underlyingElement(this), _, 1, _) } @@ -874,7 +1007,7 @@ class PointerType extends DerivedType { /** * A C++ reference type. See 4.9.1. * - * For C++11 code bases, this includes both lvalue references (&) and rvalue references (&&). + * For C++11 code bases, this includes both _lvalue_ references (&) and _rvalue_ references (&&). * To distinguish between them, use the LValueReferenceType and RValueReferenceType classes. */ class ReferenceType extends DerivedType { @@ -900,7 +1033,11 @@ class ReferenceType extends DerivedType { } /** - * A C++11 lvalue reference type (e.g. int&). + * A C++11 lvalue reference type (e.g. `int&`). + * ``` + * int a; + * int& b = a; + * ``` */ class LValueReferenceType extends ReferenceType { LValueReferenceType() { derivedtypes(underlyingElement(this), _, 2, _) } @@ -909,7 +1046,14 @@ class LValueReferenceType extends ReferenceType { } /** - * A C++11 rvalue reference type (e.g. int&&). + * A C++11 rvalue reference type (e.g. `int&&`). It is used to + * implement "move" semantics for object construction and assignments. + * ``` + * class C { + * E e; + * C(C&& from): e(from.e) { } + * }; + * ``` */ class RValueReferenceType extends ReferenceType { RValueReferenceType() { derivedtypes(underlyingElement(this), _, 8, _) } @@ -921,6 +1065,10 @@ class RValueReferenceType extends ReferenceType { /** * A type with specifiers. + * ``` + * const int a; + * volatile char v; + * ``` */ class SpecifiedType extends DerivedType { SpecifiedType() { derivedtypes(underlyingElement(this), _, 3, _) } @@ -966,6 +1114,9 @@ class SpecifiedType extends DerivedType { /** * A C/C++ array type. See 4.9.1. + * ``` + * char table[32]; + * ``` */ class ArrayType extends DerivedType { ArrayType() { derivedtypes(underlyingElement(this), _, 4, _) } @@ -1012,10 +1163,16 @@ class ArrayType extends DerivedType { * A GNU/Clang vector type. * * In both Clang and GNU compilers, vector types can be introduced using the - * __attribute__((vector_size(byte_size))) syntax. The Clang compiler also - * allows vector types to be introduced using the ext_vector_type, - * neon_vector_type, and neon_polyvector_type attributes (all of which take + * `__attribute__((vector_size(byte_size)))` syntax. The Clang compiler also + * allows vector types to be introduced using the `ext_vector_type`, + * `neon_vector_type`, and `neon_polyvector_typ`e attributes (all of which take * an element type rather than a byte size). + * ``` + * typedef int v4si __attribute__ (( vector_size(4*sizeof(int)) )); + * v4si v = { 1, 2, 3, 4 }; + * typedef float float4 __attribute__((ext_vector_type(4))); + * float4 vf = (float4)(1.0f, 2.0f, 3.0f, 4.0f); + * ``` */ class GNUVectorType extends DerivedType { GNUVectorType() { derivedtypes(underlyingElement(this), _, 5, _) } @@ -1054,7 +1211,10 @@ class GNUVectorType extends DerivedType { } /** - * A C/C++ pointer to function. See 7.7. + * A C/C++ pointer to a function. See 7.7. + * ``` + * int(* pointer)(const void *element1, const void *element2); + * ``` */ class FunctionPointerType extends FunctionPointerIshType { FunctionPointerType() { derivedtypes(underlyingElement(this), _, 6, _) } @@ -1069,13 +1229,20 @@ class FunctionPointerType extends FunctionPointerIshType { } /** - * A C/C++ reference to function. + * A C++ reference to a function. + * ``` + * int(& reference)(const void *element1, const void *element2); + * ``` */ class FunctionReferenceType extends FunctionPointerIshType { FunctionReferenceType() { derivedtypes(underlyingElement(this), _, 7, _) } override string getCanonicalQLClass() { result = "FunctionReferenceType" } + override int getPointerIndirectionLevel() { + result = getBaseType().getPointerIndirectionLevel() + } + override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() } override string explain() { @@ -1088,6 +1255,10 @@ class FunctionReferenceType extends FunctionPointerIshType { * * Block types (along with blocks themselves) are a language extension * supported by Clang, and by Apple's branch of GCC. + * ``` + * int(^ block)(const char *element1, const char *element2) + * = ^int (const char *element1, const char *element2) { return element1 - element 2; } + * ``` */ class BlockType extends FunctionPointerIshType { BlockType() { derivedtypes(underlyingElement(this), _, 10, _) } @@ -1100,7 +1271,9 @@ class BlockType extends FunctionPointerIshType { } /** - * A C/C++ pointer to function, or a block. + * A C/C++ pointer to a function, a C++ function reference, or a clang/Apple block. + * + * See FunctionPointerType, FunctionReferenceType and BlockType for more information. */ class FunctionPointerIshType extends DerivedType { FunctionPointerIshType() { @@ -1145,7 +1318,14 @@ class FunctionPointerIshType extends DerivedType { } /** - * A C++ pointer to member. See 15.5. + * A C++ pointer to data member. See 15.5. + * ``` + * class C { int m; }; + * int C::* p = &C::m; // pointer to data member m of class C + * class C *; + * int val = c.*p; // access data member + * + * ``` */ class PointerToMemberType extends Type, @ptrtomember { /** a printable representation of this named element */ @@ -1182,7 +1362,9 @@ class PointerToMemberType extends Type, @ptrtomember { } /** - * A C/C++ routine type. This is what results from stripping away the pointer from a function pointer type. + * A C/C++ routine type. Conceptually, this is what results from stripping away the pointer from a function pointer type. + * It has no corresponding syntax in C/C++. + * */ class RoutineType extends Type, @routinetype { /** a printable representation of this named element */ @@ -1243,6 +1425,12 @@ class RoutineType extends Type, @routinetype { /** * A C++ typename template parameter. + * + * In the example below, `T` is a template parameter: + * ``` + * template + * class C { }; + * ``` */ class TemplateParameter extends UserType { TemplateParameter() { @@ -1254,15 +1442,29 @@ class TemplateParameter extends UserType { override predicate involvesTemplateParameter() { any() } } -/** A C++ template template parameter, e.g. template <template <typename,typename> class T>. */ -class TemplateTemplateParameter extends TemplateParameter { - TemplateTemplateParameter() { usertypes(underlyingElement(this), _, 8) } +/** A C++ template template parameter. + * + * In the example below, `T` is a template template parameter (although its name + * may be omitted): + * ``` + * template