diff --git a/config/add-overlay-annotations.py b/config/add-overlay-annotations.py index 0a30eee5799..4fbd9a2b7fc 100644 --- a/config/add-overlay-annotations.py +++ b/config/add-overlay-annotations.py @@ -199,6 +199,7 @@ def annotate_as_appropriate(filename, lines): # as overlay[local?]. It is not clear that these heuristics are exactly what we want, # but they seem to work well enough for now (as determined by speed and accuracy numbers). if (filename.endswith("Test.qll") or + re.search(r"go/ql/lib/semmle/go/security/[^/]+[.]qll$", filename.replace(os.sep, "/")) or ((filename.endswith("Query.qll") or filename.endswith("Config.qll")) and any("implements DataFlow::ConfigSig" in line for line in lines))): return None diff --git a/config/identical-files.json b/config/identical-files.json index bdaf567ae17..8a5c00a49f8 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -172,10 +172,6 @@ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintDominance.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll" ], - "C# ControlFlowReachability": [ - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll" - ], "C++ ExternalAPIs": [ "cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll", "cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll" diff --git a/cpp/ql/lib/semmle/code/cpp/Function.qll b/cpp/ql/lib/semmle/code/cpp/Function.qll index 10b156e3fb6..8d93ac0f2a3 100644 --- a/cpp/ql/lib/semmle/code/cpp/Function.qll +++ b/cpp/ql/lib/semmle/code/cpp/Function.qll @@ -524,6 +524,12 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { not exists(NewOrNewArrayExpr new | e = new.getAllocatorCall().getArgument(0)) ) } + + /** + * Holds if this function has an ambiguous return type, meaning that zero or multiple return + * types for this function are present in the database (this can occur in `build-mode: none`). + */ + predicate hasAmbiguousReturnType() { count(this.getType()) != 1 } } pragma[noinline] diff --git a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll index 3dea144bbf6..e93bf578921 100644 --- a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll +++ b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll @@ -6,117 +6,67 @@ private import OverlayXml /** * Holds always for the overlay variant and never for the base variant. - * This local predicate is used to define local predicates that behave - * differently for the base and overlay variant. */ overlay[local] predicate isOverlay() { databaseMetadata("isOverlay", "true") } -overlay[local] -private string getLocationFilePath(@location_default loc) { - exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result)) -} - /** - * Gets the file path for an element with a single location. + * Holds if the TRAP file or tag `t` is reachable from source file `sourceFile` + * in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant. */ overlay[local] -private string getSingleLocationFilePath(@element e) { - exists(@location_default loc | - var_decls(e, _, _, _, loc) - or - fun_decls(e, _, _, _, loc) - or - type_decls(e, _, loc) - or - namespace_decls(e, _, loc, _) - or - macroinvocations(e, _, loc, _) - or - preprocdirects(e, _, loc) - or - diagnostics(e, _, _, _, _, loc) - or - usings(e, _, loc, _) - or - static_asserts(e, _, _, loc, _) - or - derivations(e, _, _, _, loc) - or - frienddecls(e, _, _, loc) - or - comments(e, _, loc) - or - exprs(e, _, loc) - or - stmts(e, _, loc) - or - initialisers(e, _, _, loc) - or - attributes(e, _, _, _, loc) - or - attribute_args(e, _, _, _, loc) - or - namequalifiers(e, _, _, loc) - or - enumconstants(e, _, _, _, _, loc) - or - type_mentions(e, _, loc, _) - or - lambda_capture(e, _, _, _, _, _, loc) - or - concept_templates(e, _, loc) - | - result = getLocationFilePath(loc) +private predicate locallyReachableTrapOrTag( + boolean isOverlayVariant, string sourceFile, @trap_or_tag t +) { + exists(@source_file sf, @trap trap | + (if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and + source_file_uses_trap(sf, trap) and + source_file_name(sf, sourceFile) and + (t = trap or trap_uses_tag(trap, t)) ) } /** - * Gets the file path for an element with potentially multiple locations. + * Holds if element `e` is in TRAP file or tag `t` + * in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant. */ overlay[local] -private string getMultiLocationFilePath(@element e) { - exists(@location_default loc | - var_decls(_, e, _, _, loc) - or - fun_decls(_, e, _, _, loc) - or - type_decls(_, e, loc) - or - namespace_decls(_, e, loc, _) - | - result = getLocationFilePath(loc) - ) -} - -/** - * A local helper predicate that holds in the base variant and never in the - * overlay variant. - */ -overlay[local] -private predicate isBase() { not isOverlay() } - -/** - * Holds if `path` was extracted in the overlay database. - */ -overlay[local] -private predicate overlayHasFile(string path) { - isOverlay() and - files(_, path) and - path != "" +private predicate locallyInTrapOrTag(boolean isOverlayVariant, @element e, @trap_or_tag t) { + (if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and + in_trap_or_tag(e, t) } /** * Discards an element from the base variant if: - * - It has a single location in a file extracted in the overlay, or - * - All of its locations are in files extracted in the overlay. + * - We have knowledge about what TRAP file or tag it is in (in the base). + * - It is not in any overlay TRAP file or tag that is reachable from an overlay source file. + * - For every base TRAP file or tag that contains it and is reachable from a base source file, + * either the source file has changed, or the overlay has redefined the TRAP file or tag, + * or the overlay runner has re-extracted the same source file. */ overlay[discard_entity] private predicate discardElement(@element e) { - isBase() and - ( - overlayHasFile(getSingleLocationFilePath(e)) - or - forex(string path | path = getMultiLocationFilePath(e) | overlayHasFile(path)) + // If we don't have any knowledge about what TRAP file something + // is in, then we don't want to discard it, so we only consider + // entities that are known to be in a base TRAP file or tag. + locallyInTrapOrTag(false, e, _) and + // Anything that is reachable from an overlay source file should + // not be discarded. + not exists(@trap_or_tag t | locallyInTrapOrTag(true, e, t) | + locallyReachableTrapOrTag(true, _, t) + ) and + // Finally, we have to make sure the base variant does not retain it. + // If it is reachable from a base source file, then that is + // sufficient unless either the base source file has changed (in + // particular, been deleted), or the overlay has redefined the TRAP + // file or tag it is in, or the overlay runner has re-extracted the same + // source file (e.g. because a header it includes has changed). + forall(@trap_or_tag t, string sourceFile | + locallyInTrapOrTag(false, e, t) and + locallyReachableTrapOrTag(false, sourceFile, t) + | + overlayChangedFiles(sourceFile) or + locallyReachableTrapOrTag(true, _, t) or + locallyReachableTrapOrTag(true, sourceFile, _) ) } diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql index a54ac9020c8..6747d177c80 100644 --- a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql +++ b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql @@ -218,7 +218,9 @@ where // only report if we cannot prove that the result of the // multiplication will be less (resp. greater) than the // maximum (resp. minimum) number we can compute. - overflows(me, t1) + overflows(me, t1) and + // exclude cases where the expression type may not have been extracted accurately + not me.getParent().(Call).getTarget().hasAmbiguousReturnType() select me, "Multiplication result may overflow '" + me.getType().toString() + "' before it is converted to '" + me.getFullyConverted().getType().toString() + "'." diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql index 994aba733d2..0e4a8f9741c 100644 --- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql +++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id cpp/cgi-xss * @tags security diff --git a/cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md b/cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md new file mode 100644 index 00000000000..4d4a66c0a22 --- /dev/null +++ b/cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Fixed an issue with the "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query causing false positive results in `build-mode: none` databases. diff --git a/cpp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/cpp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..0810e9c49ba --- /dev/null +++ b/cpp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,4 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `cpp/cgi-xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c new file mode 100644 index 00000000000..3d01a28fae0 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c @@ -0,0 +1,28 @@ +// semmle-extractor-options: --expect_errors + +void test_float_double1(float f, double d) { + float r1 = f * f; // GOOD + float r2 = f * d; // GOOD + double r3 = f * f; // BAD + double r4 = f * d; // GOOD + + float f1 = fabsf(f * f); // GOOD + float f2 = fabsf(f * d); // GOOD + double f3 = fabs(f * f); // BAD [NOT DETECTED] + double f4 = fabs(f * d); // GOOD +} + +double fabs(double f); +float fabsf(float f); + +void test_float_double2(float f, double d) { + float r1 = f * f; // GOOD + float r2 = f * d; // GOOD + double r3 = f * f; // BAD + double r4 = f * d; // GOOD + + float f1 = fabsf(f * f); // GOOD + float f2 = fabsf(f * d); // GOOD + double f3 = fabs(f * f); // BAD [NOT DETECTED] + double f4 = fabs(f * d); // GOOD +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected index 2806aaa809f..05b2b7e1ea3 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected @@ -1,3 +1,5 @@ +| Buildless.c:6:17:6:21 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | +| Buildless.c:21:17:21:21 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | | IntMultToLong.c:4:10:4:14 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'long long'. | | IntMultToLong.c:7:16:7:20 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'long long'. | | IntMultToLong.c:18:19:18:23 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | diff --git a/csharp/ql/consistency-queries/CfgConsistency.ql b/csharp/ql/consistency-queries/CfgConsistency.ql index d7f0c091538..4b0d15f8a81 100644 --- a/csharp/ql/consistency-queries/CfgConsistency.ql +++ b/csharp/ql/consistency-queries/CfgConsistency.ql @@ -1,63 +1,5 @@ import csharp import semmle.code.csharp.controlflow.internal.Completion -import semmle.code.csharp.controlflow.internal.PreBasicBlocks import ControlFlow import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl::Consistency import semmle.code.csharp.controlflow.internal.Splitting - -private predicate splitBB(ControlFlow::BasicBlock bb) { - exists(ControlFlow::Node first | - first = bb.getFirstNode() and - first.isJoin() and - strictcount(first.getAPredecessor().getAstNode()) = 1 - ) -} - -private class RelevantBasicBlock extends ControlFlow::BasicBlock { - RelevantBasicBlock() { not splitBB(this) } -} - -predicate bbStartInconsistency(ControlFlowElement cfe) { - exists(RelevantBasicBlock bb | bb.getFirstNode() = cfe.getAControlFlowNode()) and - not cfe = any(PreBasicBlock bb).getFirstElement() -} - -predicate bbSuccInconsistency(ControlFlowElement pred, ControlFlowElement succ) { - exists(RelevantBasicBlock predBB, RelevantBasicBlock succBB | - predBB.getLastNode() = pred.getAControlFlowNode() and - succBB = predBB.getASuccessor() and - succBB.getFirstNode() = succ.getAControlFlowNode() - ) and - not exists(PreBasicBlock predBB, PreBasicBlock succBB | - predBB.getLastNode() = pred and - succBB = predBB.getASuccessor() and - succBB.getFirstElement() = succ - ) -} - -predicate bbIntraSuccInconsistency(ControlFlowElement pred, ControlFlowElement succ) { - exists(ControlFlow::BasicBlock bb, int i | - pred.getAControlFlowNode() = bb.getNode(i) and - succ.getAControlFlowNode() = bb.getNode(i + 1) - ) and - not exists(PreBasicBlock bb | - bb.getLastNode() = pred and - bb.getASuccessor().getFirstElement() = succ - ) and - not exists(PreBasicBlock bb, int i | - bb.getNode(i) = pred and - bb.getNode(i + 1) = succ - ) -} - -query predicate preBasicBlockConsistency(ControlFlowElement cfe1, ControlFlowElement cfe2, string s) { - bbStartInconsistency(cfe1) and - cfe2 = cfe1 and - s = "start inconsistency" - or - bbSuccInconsistency(cfe1, cfe2) and - s = "succ inconsistency" - or - bbIntraSuccInconsistency(cfe1, cfe2) and - s = "intra succ inconsistency" -} diff --git a/csharp/ql/consistency-queries/DataFlowConsistency.ql b/csharp/ql/consistency-queries/DataFlowConsistency.ql index 638bace3892..03e0f3f1b74 100644 --- a/csharp/ql/consistency-queries/DataFlowConsistency.ql +++ b/csharp/ql/consistency-queries/DataFlowConsistency.ql @@ -35,9 +35,7 @@ private module Input implements InputSig { or n.asExpr().(ObjectCreation).hasInitializer() or - exists( - n.(PostUpdateNode).getPreUpdateNode().asExprAtNode(LocalFlow::getPostUpdateReverseStep(_)) - ) + n.(PostUpdateNode).getPreUpdateNode().asExpr() = LocalFlow::getPostUpdateReverseStep(_) } predicate argHasPostUpdateExclude(ArgumentNode n) { diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll index f8346cfe01e..611b578b859 100644 --- a/csharp/ql/lib/semmle/code/csharp/Callable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll @@ -336,6 +336,22 @@ class ExtensionTypeExtensionMethod extends ExtensionMethodImpl { ExtensionTypeExtensionMethod() { this.isInExtension() } } +/** + * A non-static member with an initializer, for example a field `int Field = 0`. + */ +private class InitializedInstanceMember extends Member { + private AssignExpr ae; + + InitializedInstanceMember() { + not this.isStatic() and + expr_parent_top_level(ae, _, this) and + not ae = getExpressionBody(_) + } + + /** Gets the initializer expression. */ + AssignExpr getInitializer() { result = ae } +} + /** * An object initializer method. * @@ -347,6 +363,17 @@ class ExtensionTypeExtensionMethod extends ExtensionMethodImpl { */ class ObjectInitMethod extends Method { ObjectInitMethod() { this.getName() = "" } + + /** + * Holds if this object initializer method performs the initialization + * of a member via assignment `init`. + */ + predicate initializes(AssignExpr init) { + exists(InitializedInstanceMember m | + this.getDeclaringType().getAMember() = m and + init = m.getInitializer() + ) + } } /** diff --git a/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll index aa834ef9103..5afacf608a8 100644 --- a/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll +++ b/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll @@ -214,6 +214,8 @@ private module Cached { parent*(enclosingStart(cfe), c.(Constructor).getInitializer()) or parent*(cfe, c.(Constructor).getObjectInitializerCall()) + or + parent*(cfe, any(AssignExpr init | c.(ObjectInitMethod).initializes(init))) } /** Holds if the enclosing statement of expression `e` is `s`. */ diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll index 1696869e591..0bdf1f795db 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll @@ -10,42 +10,15 @@ private import semmle.code.csharp.ExprOrStmtParent private import semmle.code.csharp.commons.Compilation private module Initializers { - /** - * A non-static member with an initializer, for example a field `int Field = 0`. - */ - class InitializedInstanceMember extends Member { - private AssignExpr ae; - - InitializedInstanceMember() { - not this.isStatic() and - expr_parent_top_level(ae, _, this) and - not ae = any(Callable c).getExpressionBody() - } - - /** Gets the initializer expression. */ - AssignExpr getInitializer() { result = ae } - } - - /** - * Holds if `obinit` is an object initializer method that performs the initialization - * of a member via assignment `init`. - */ - predicate obinitInitializes(ObjectInitMethod obinit, AssignExpr init) { - exists(InitializedInstanceMember m | - obinit.getDeclaringType().getAMember() = m and - init = m.getInitializer() - ) - } - /** * Gets the `i`th member initializer expression for object initializer method `obinit` * in compilation `comp`. */ AssignExpr initializedInstanceMemberOrder(ObjectInitMethod obinit, CompilationExt comp, int i) { - obinitInitializes(obinit, result) and + obinit.initializes(result) and result = rank[i + 1](AssignExpr ae0, Location l | - obinitInitializes(obinit, ae0) and + obinit.initializes(ae0) and l = ae0.getLocation() and getCompilation(l.getFile()) = comp | @@ -74,7 +47,7 @@ class CfgScope extends Element, @top_level_exprorstmt_parent { any(Callable c | c.(Constructor).hasInitializer() or - Initializers::obinitInitializes(c, _) + c.(ObjectInitMethod).initializes(_) or c.hasBody() ) diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll deleted file mode 100644 index 38eca378edf..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll +++ /dev/null @@ -1,175 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides a basic block implementation on control flow elements. That is, - * a "pre-CFG" where the nodes are (unsplit) control flow elements and the - * successor relation is `succ = succ(pred, _)`. - * - * The logic is duplicated from the implementation in `BasicBlocks.qll`, and - * being an internal class, all predicate documentation has been removed. - */ - -import csharp -private import Completion -private import ControlFlowGraphImpl -private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg -private import codeql.controlflow.BasicBlock as BB - -private predicate startsBB(ControlFlowElement cfe) { - not succ(_, cfe, _) and - ( - succ(cfe, _, _) - or - scopeLast(_, cfe, _) - ) - or - strictcount(ControlFlowElement pred, Completion c | succ(pred, cfe, c)) > 1 - or - succ(_, cfe, any(ConditionalCompletion c)) - or - exists(ControlFlowElement pred, int i | - succ(pred, cfe, _) and - i = count(ControlFlowElement succ, Completion c | succ(pred, succ, c)) - | - i > 1 - or - i = 1 and - scopeLast(_, pred, _) - ) -} - -private predicate intraBBSucc(ControlFlowElement pred, ControlFlowElement succ) { - succ(pred, succ, _) and - not startsBB(succ) -} - -private predicate bbIndex(ControlFlowElement bbStart, ControlFlowElement cfe, int i) = - shortestDistances(startsBB/1, intraBBSucc/2)(bbStart, cfe, i) - -private predicate succBB(PreBasicBlock pred, PreBasicBlock succ) { succ = pred.getASuccessor() } - -private predicate entryBB(PreBasicBlock bb) { scopeFirst(_, bb) } - -private predicate bbIDominates(PreBasicBlock dom, PreBasicBlock bb) = - idominance(entryBB/1, succBB/2)(_, dom, bb) - -class PreBasicBlock extends ControlFlowElement { - PreBasicBlock() { startsBB(this) } - - PreBasicBlock getASuccessor(Cfg::SuccessorType t) { - succ(this.getLastNode(), result, any(Completion c | t = c.getAMatchingSuccessorType())) - } - - deprecated PreBasicBlock getASuccessorByType(Cfg::SuccessorType t) { - result = this.getASuccessor(t) - } - - PreBasicBlock getASuccessor() { result = this.getASuccessor(_) } - - PreBasicBlock getAPredecessor() { result.getASuccessor() = this } - - ControlFlowElement getNode(int pos) { bbIndex(this, result, pos) } - - deprecated ControlFlowElement getElement(int pos) { result = this.getNode(pos) } - - ControlFlowElement getAnElement() { result = this.getNode(_) } - - ControlFlowElement getFirstElement() { result = this } - - ControlFlowElement getLastNode() { result = this.getNode(this.length() - 1) } - - deprecated ControlFlowElement getLastElement() { result = this.getLastNode() } - - int length() { result = strictcount(this.getAnElement()) } - - PreBasicBlock getImmediateDominator() { bbIDominates(result, this) } - - predicate immediatelyDominates(PreBasicBlock bb) { bbIDominates(this, bb) } - - pragma[inline] - predicate strictlyDominates(PreBasicBlock bb) { this.immediatelyDominates+(bb) } - - pragma[inline] - predicate dominates(PreBasicBlock bb) { - bb = this - or - this.strictlyDominates(bb) - } - - predicate inDominanceFrontier(PreBasicBlock df) { - this = df.getAPredecessor() and not bbIDominates(this, df) - or - exists(PreBasicBlock prev | prev.inDominanceFrontier(df) | - bbIDominates(this, prev) and - not bbIDominates(this, df) - ) - } - - /** Unsupported. Do not use. */ - predicate strictlyPostDominates(PreBasicBlock bb) { none() } - - /** Unsupported. Do not use. */ - predicate postDominates(PreBasicBlock bb) { - this.strictlyPostDominates(bb) or - this = bb - } -} - -private Completion getConditionalCompletion(ConditionalCompletion cc) { - result.getInnerCompletion() = cc -} - -pragma[nomagic] -private predicate conditionBlockImmediatelyControls( - ConditionBlock cond, PreBasicBlock succ, ConditionalCompletion cc -) { - exists(ControlFlowElement last, Completion c | - last = cond.getLastNode() and - c = getConditionalCompletion(cc) and - succ(last, succ, c) and - // In the pre-CFG, we need to account for case where one predecessor node has - // two edges to the same successor node. Assertion expressions are examples of - // such nodes. - not exists(Completion other | - succ(last, succ, other) and - other != c - ) and - forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != cond | - succ.dominates(pred) - ) - ) -} - -class ConditionBlock extends PreBasicBlock { - ConditionBlock() { - exists(Completion c | c = getConditionalCompletion(_) | - succ(this.getLastNode(), _, c) - or - scopeLast(_, this.getLastNode(), c) - ) - } - - pragma[nomagic] - predicate controls(PreBasicBlock controlled, Cfg::ConditionalSuccessor s) { - exists(PreBasicBlock succ, ConditionalCompletion c | - conditionBlockImmediatelyControls(this, succ, c) - | - succ.dominates(controlled) and - s = c.getAMatchingSuccessorType() - ) - } -} - -module PreCfg implements BB::CfgSig { - class ControlFlowNode = ControlFlowElement; - - class BasicBlock = PreBasicBlock; - - class EntryBasicBlock extends BasicBlock { - EntryBasicBlock() { entryBB(this) } - } - - predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { - conditionBlockImmediatelyControls(bb1, bb2, _) - } -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll deleted file mode 100644 index 706893c64ea..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll +++ /dev/null @@ -1,246 +0,0 @@ -import csharp - -private class ControlFlowScope extends ControlFlowElement { - private boolean exactScope; - - ControlFlowScope() { - exists(ControlFlowReachabilityConfiguration c | - c.candidate(_, _, this, exactScope, _) or - c.candidateDef(_, _, this, exactScope, _) - ) - } - - predicate isExact() { exactScope = true } - - predicate isNonExact() { exactScope = false } -} - -private newtype TControlFlowElementOrBasicBlock = - TControlFlowElement(ControlFlowElement cfe) or - TBasicBlock(ControlFlow::BasicBlock bb) - -class ControlFlowElementOrBasicBlock extends TControlFlowElementOrBasicBlock { - ControlFlowElement asControlFlowElement() { this = TControlFlowElement(result) } - - ControlFlow::BasicBlock asBasicBlock() { this = TBasicBlock(result) } - - string toString() { - result = this.asControlFlowElement().toString() - or - result = this.asBasicBlock().toString() - } - - Location getLocation() { - result = this.asControlFlowElement().getLocation() - or - result = this.asBasicBlock().getLocation() - } -} - -private predicate isBasicBlock(ControlFlowElementOrBasicBlock c) { c instanceof TBasicBlock } - -private predicate isNonExactScope(ControlFlowElementOrBasicBlock c) { - c.asControlFlowElement().(ControlFlowScope).isNonExact() -} - -private predicate step(ControlFlowElementOrBasicBlock pred, ControlFlowElementOrBasicBlock succ) { - pred.asBasicBlock().getANode().getAstNode() = succ.asControlFlowElement() - or - pred.asControlFlowElement() = succ.asControlFlowElement().getAChild() -} - -private predicate basicBlockInNonExactScope( - ControlFlowElementOrBasicBlock bb, ControlFlowElementOrBasicBlock scope -) = doublyBoundedFastTC(step/2, isBasicBlock/1, isNonExactScope/1)(bb, scope) - -pragma[noinline] -private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) { - basicBlockInNonExactScope(TBasicBlock(result), TControlFlowElement(scope)) and - exactScope = false - or - scope.isExact() and - result.getANode().getAstNode() = scope and - exactScope = true -} - -/** - * A helper class for determining control-flow reachability for pairs of - * elements. - * - * This is useful when defining for example expression-based data-flow steps in - * the presence of control-flow splitting, where a data-flow step should make - * sure to stay in the same split. - * - * For example, in - * - * ```csharp - * if (b) - * .... - * var x = "foo"; - * if (b) - * .... - * ``` - * - * there should only be steps from `[b = true] "foo"` to `[b = true] SSA def(x)` - * and `[b = false] "foo"` to `[b = false] SSA def(x)`, and for example not from - * `[b = true] "foo"` to `[b = false] SSA def(x)` - */ -abstract class ControlFlowReachabilityConfiguration extends string { - bindingset[this] - ControlFlowReachabilityConfiguration() { any() } - - /** - * Holds if `e1` and `e2` are expressions for which we want to find a - * control-flow path that follows control flow successors (resp. - * predecessors, as specified by `isSuccessor`) inside the syntactic scope - * `scope`. The Boolean `exactScope` indicates whether a transitive child - * of `scope` is allowed (`exactScope = false`). - */ - predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - none() - } - - /** - * Holds if `e` and `def` are elements for which we want to find a - * control-flow path that follows control flow successors (resp. - * predecessors, as specified by `isSuccessor`) inside the syntactic scope - * `scope`. The Boolean `exactScope` indicates whether a transitive child - * of `scope` is allowed (`exactScope = false`). - */ - predicate candidateDef( - Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - none() - } - - pragma[nomagic] - private predicate reachesBasicBlockExprBase( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, int i, - ControlFlow::BasicBlock bb - ) { - this.candidate(e1, e2, _, _, isSuccessor) and - cfn1 = e1.getAControlFlowNode() and - bb.getNode(i) = cfn1 - } - - pragma[nomagic] - private predicate reachesBasicBlockExprRec( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, - ControlFlow::BasicBlock bb - ) { - exists(ControlFlow::BasicBlock mid | - this.reachesBasicBlockExpr(e1, e2, isSuccessor, cfn1, mid) - | - isSuccessor = true and - bb = mid.getASuccessor() - or - isSuccessor = false and - bb = mid.getAPredecessor() - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockExpr( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, - ControlFlow::BasicBlock bb - ) { - this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, _, bb) - or - exists(ControlFlowElement scope, boolean exactScope | - this.candidate(e1, e2, scope, exactScope, isSuccessor) and - this.reachesBasicBlockExprRec(e1, e2, isSuccessor, cfn1, bb) and - bb = getABasicBlockInScope(scope, exactScope) - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinitionBase( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - int i, ControlFlow::BasicBlock bb - ) { - this.candidateDef(e, def, _, _, isSuccessor) and - cfn = e.getAControlFlowNode() and - bb.getNode(i) = cfn - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinitionRec( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - ControlFlow::BasicBlock bb - ) { - exists(ControlFlow::BasicBlock mid | - this.reachesBasicBlockDefinition(e, def, isSuccessor, cfn, mid) - | - isSuccessor = true and - bb = mid.getASuccessor() - or - isSuccessor = false and - bb = mid.getAPredecessor() - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinition( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - ControlFlow::BasicBlock bb - ) { - this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, _, bb) - or - exists(ControlFlowElement scope, boolean exactScope | - this.candidateDef(e, def, scope, exactScope, isSuccessor) and - this.reachesBasicBlockDefinitionRec(e, def, isSuccessor, cfn, bb) and - bb = getABasicBlockInScope(scope, exactScope) - ) - } - - /** - * Holds if there is a control-flow path from `cfn1` to `cfn2`, where `cfn1` is a - * control-flow node for `e1` and `cfn2` is a control-flow node for `e2`. - */ - pragma[nomagic] - predicate hasExprPath(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2) { - exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j | - this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, i, bb) and - cfn2 = bb.getNode(j) and - cfn2 = e2.getAControlFlowNode() - | - isSuccessor = true and j >= i - or - isSuccessor = false and i >= j - ) - or - exists(ControlFlow::BasicBlock bb | - this.reachesBasicBlockExprRec(e1, e2, _, cfn1, bb) and - cfn2 = bb.getANode() and - cfn2 = e2.getAControlFlowNode() - ) - } - - /** - * Holds if there is a control-flow path from `cfn` to `cfnDef`, where `cfn` is a - * control-flow node for `e` and `cfnDef` is a control-flow node for `def`. - */ - pragma[nomagic] - predicate hasDefPath( - Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef - ) { - exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j | - this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, i, bb) and - cfnDef = bb.getNode(j) and - def.getExpr().getAControlFlowNode() = cfnDef - | - isSuccessor = true and j >= i - or - isSuccessor = false and i >= j - ) - or - exists(ControlFlow::BasicBlock bb | - this.reachesBasicBlockDefinitionRec(e, def, _, cfn, bb) and - def.getExpr().getAControlFlowNode() = cfnDef and - cfnDef = bb.getANode() - ) - } -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 70161a6fc47..03164960d41 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -2,7 +2,6 @@ private import csharp private import DataFlowPublic private import DataFlowDispatch private import DataFlowImplCommon -private import ControlFlowReachability private import FlowSummaryImpl as FlowSummaryImpl private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary private import semmle.code.csharp.dataflow.internal.ExternalFlow @@ -259,34 +258,16 @@ private module ThisFlow { } } -/** - * Holds if there is a control-flow path from `n1` to `n2`. `n2` is either an - * expression node or an SSA definition node. - */ -pragma[nomagic] -predicate hasNodePath(ControlFlowReachabilityConfiguration conf, ExprNode n1, Node n2) { - exists(ControlFlow::Node cfn1, ControlFlow::Node cfn2 | conf.hasExprPath(_, cfn1, _, cfn2) | - cfn1 = n1.getControlFlowNode() and - cfn2 = n2.(ExprNode).getControlFlowNode() - ) - or - exists(ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef | - conf.hasDefPath(_, cfn, def, cfnDef) and - cfn = n1.getControlFlowNode() and - n2 = TAssignableDefinitionNode(def, cfnDef) - ) -} - /** Provides logic related to captured variables. */ module VariableCapture { private import codeql.dataflow.VariableCapture as Shared private import semmle.code.csharp.controlflow.BasicBlocks as BasicBlocks private predicate closureFlowStep(ControlFlow::Nodes::ExprNode e1, ControlFlow::Nodes::ExprNode e2) { - e1 = LocalFlow::getALastEvalNode(e2) + e1.getExpr() = LocalFlow::getALastEvalNode(e2.getExpr()) or exists(Ssa::Definition def, AssignableDefinition adef | - LocalFlow::defAssigns(adef, _, e1) and + LocalFlow::defAssigns(adef, _, _, e1) and def.getAnUltimateDefinition().(Ssa::ExplicitDefinition).getADefinition() = adef and exists(def.getAReadAtNode(e2)) ) @@ -379,7 +360,7 @@ module VariableCapture { this = def.getExpr().getAControlFlowNode() } - ControlFlow::Node getRhs() { LocalFlow::defAssigns(def, this, result) } + ControlFlow::Node getRhs() { LocalFlow::defAssigns(def, this, _, result) } CapturedVariable getVariable() { result = v } } @@ -528,127 +509,74 @@ module SsaFlow { /** Provides predicates related to local data flow. */ module LocalFlow { - class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration { - LocalExprStepConfiguration() { this = "LocalExprStepConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exactScope = false and - ( - e1 = e2.(ParenthesizedExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - e1 = e2.(NullCoalescingExpr).getAnOperand() and - scope = e2 and - isSuccessor = true - or - e1 = e2.(SuppressNullableWarningExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - e2 = - any(ConditionalExpr ce | - e1 = ce.getThen() or - e1 = ce.getElse() - ) and - scope = e2 and - isSuccessor = true - or - e1 = e2.(Cast).getExpr() and - scope = e2 and - isSuccessor = true - or - // An `=` expression, where the result of the expression is used - e2 = - any(AssignExpr ae | - ae.getParent() = any(ControlFlowElement cfe | not cfe instanceof ExprStmt) and - e1 = ae.getRValue() - ) and - scope = e2 and - isSuccessor = true - or - e1 = e2.(ObjectCreation).getInitializer() and - scope = e2 and - isSuccessor = false - or - e1 = e2.(ArrayCreation).getInitializer() and - scope = e2 and - isSuccessor = false - or - e1 = e2.(SwitchExpr).getACase().getBody() and - scope = e2 and - isSuccessor = true - or - e1 = e2.(CheckedExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - e1 = e2.(UncheckedExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - e1 = e2.(CollectionExpression).getAnElement() and - e1 instanceof SpreadElementExpr and - scope = e2 and - isSuccessor = true - or - e1 = e2.(SpreadElementExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - exists(WithExpr we | - scope = we and - isSuccessor = true - | - e1 = we.getExpr() and - e2 = we.getInitializer() - or - e1 = we.getInitializer() and - e2 = we - ) - or - scope = any(AssignExpr ae | ae.getLValue().(TupleExpr) = e2 and ae.getRValue() = e1) and - isSuccessor = false - or - isSuccessor = true and - exists(ControlFlowElement cfe | cfe = e2.(TupleExpr).(PatternExpr).getPatternMatch() | - cfe.(IsExpr).getExpr() = e1 and scope = cfe - or - exists(Switch sw | sw.getACase() = cfe and sw.getExpr() = e1 and scope = sw) - ) + predicate localExprStep(Expr e1, Expr e2) { + e1 = e2.(ParenthesizedExpr).getExpr() + or + e1 = e2.(NullCoalescingExpr).getAnOperand() + or + e1 = e2.(SuppressNullableWarningExpr).getExpr() + or + e2 = + any(ConditionalExpr ce | + e1 = ce.getThen() or + e1 = ce.getElse() ) - } - - override predicate candidateDef( - Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - // Flow from source to definition - exactScope = false and - def.getSource() = e and - ( - scope = def.getExpr() and - isSuccessor = true - or - scope = def.(AssignableDefinitions::PatternDefinition).getMatch().(IsExpr) and - isSuccessor = false - or - exists(Switch s | - s.getACase() = def.(AssignableDefinitions::PatternDefinition).getMatch() and - isSuccessor = true - | - scope = s.getExpr() - or - scope = s.getACase() - ) + or + e1 = e2.(Cast).getExpr() + or + // An `=` expression, where the result of the expression is used + e2 = + any(AssignExpr ae | + ae.getParent() = any(ControlFlowElement cfe | not cfe instanceof ExprStmt) and + e1 = ae.getRValue() ) - } + or + e1 = e2.(ObjectCreation).getInitializer() + or + e1 = e2.(ArrayCreation).getInitializer() + or + e1 = e2.(SwitchExpr).getACase().getBody() + or + e1 = e2.(CheckedExpr).getExpr() + or + e1 = e2.(UncheckedExpr).getExpr() + or + e1 = e2.(CollectionExpression).getAnElement() and + e1 instanceof SpreadElementExpr + or + e1 = e2.(SpreadElementExpr).getExpr() + or + exists(WithExpr we | + e1 = we.getExpr() and + e2 = we.getInitializer() + or + e1 = we.getInitializer() and + e2 = we + ) + or + exists(AssignExpr ae | ae.getLValue().(TupleExpr) = e2 and ae.getRValue() = e1) + or + exists(ControlFlowElement cfe | cfe = e2.(TupleExpr).(PatternExpr).getPatternMatch() | + cfe.(IsExpr).getExpr() = e1 + or + exists(Switch sw | sw.getACase() = cfe and sw.getExpr() = e1) + ) } - predicate defAssigns(AssignableDefinition def, ControlFlow::Node cfnDef, ControlFlow::Node value) { - any(LocalExprStepConfiguration x).hasDefPath(_, value, def, cfnDef) + predicate defAssigns( + AssignableDefinition def, ControlFlow::Node cfnDef, Expr value, ControlFlow::Node valueCfn + ) { + def.getSource() = value and + valueCfn = value.getControlFlowNode() and + cfnDef = def.getExpr().getAControlFlowNode() + } + + private predicate defAssigns(ExprNode value, AssignableDefinitionNode defNode) { + exists(ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef | + defAssigns(def, cfnDef, value.getExpr(), _) and + cfn = value.getControlFlowNode() and + defNode = TAssignableDefinitionNode(def, cfnDef) + ) } /** @@ -659,7 +587,9 @@ module LocalFlow { } predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) { - hasNodePath(any(LocalExprStepConfiguration x), nodeFrom, nodeTo) + localExprStep(nodeFrom.asExpr(), nodeTo.asExpr()) + or + defAssigns(nodeFrom, nodeTo) or ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) and nodeFrom != nodeTo @@ -685,11 +615,12 @@ module LocalFlow { } /** - * Gets a node that may execute last in `n`, and which, when it executes last, - * will be the value of `n`. + * Gets a node that may execute last in `e`, and which, when it executes last, + * will be the value of `e`. */ - ControlFlow::Nodes::ExprNode getALastEvalNode(ControlFlow::Nodes::ExprNode cfn) { - exists(Expr e | any(LocalExprStepConfiguration x).hasExprPath(_, result, e, cfn) | + Expr getALastEvalNode(Expr e) { + localExprStep(result, e) and + ( e instanceof ConditionalExpr or e instanceof Cast or e instanceof NullCoalescingExpr or @@ -713,9 +644,7 @@ module LocalFlow { * we add a reverse flow step from `[post] b ? x : y` to `[post] x` and to * `[post] y`, in order for the side-effect of `m` to reach both `x` and `y`. */ - ControlFlow::Nodes::ExprNode getPostUpdateReverseStep(ControlFlow::Nodes::ExprNode e) { - result = getALastEvalNode(e) - } + Expr getPostUpdateReverseStep(Expr e) { result = getALastEvalNode(e) } /** * Holds if the value of `node2` is given by `node1`. @@ -729,9 +658,10 @@ module LocalFlow { e instanceof ThisAccess or e instanceof BaseAccess ) or - hasNodePath(any(LocalExprStepConfiguration x), node1, node2) and + defAssigns(node1, node2) + or + localExprStep(node1.asExpr(), node2.asExpr()) and ( - node2 instanceof AssignableDefinitionNode or node2.asExpr() instanceof Cast or node2.asExpr() instanceof AssignExpr ) @@ -775,12 +705,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) { or nodeTo = nodeFrom.(LocalFunctionCreationNode).getAnAccess(true) or - nodeTo.(PostUpdateNode).getPreUpdateNode().(ExprNode).getControlFlowNode() = - LocalFlow::getPostUpdateReverseStep(nodeFrom - .(PostUpdateNode) - .getPreUpdateNode() - .(ExprNode) - .getControlFlowNode()) + nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = + LocalFlow::getPostUpdateReverseStep(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()) ) and model = "" or @@ -834,11 +760,11 @@ private class Argument extends Expr { } /** - * Holds if `e` is an assignment of `src` to field or property `c` of `q`. + * Holds if there is an assignment of `src` to field or property `c` of `q`. * * `postUpdate` indicates whether the store targets a post-update node. */ -private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, boolean postUpdate) { +private predicate fieldOrPropertyStore(ContentSet c, Expr src, Expr q, boolean postUpdate) { exists(FieldOrProperty f | c = f.getContentSet() and ( @@ -861,25 +787,20 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b f = fa.getTarget() and src = def.getSource() and q = fa.getQualifier() and - e = def.getExpr() and postUpdate = true ) or // `with` expression initializer, `x with { f = src }` - e = - any(WithExpr we | - exists(MemberInitializer mi | - q = we and - mi = we.getInitializer().getAMemberInitializer() and - f = mi.getInitializedMember() and - src = mi.getRValue() and - postUpdate = false - ) - ) + exists(WithExpr we, MemberInitializer mi | + q = we and + mi = we.getInitializer().getAMemberInitializer() and + f = mi.getInitializedMember() and + src = mi.getRValue() and + postUpdate = false + ) or // Object initializer, `new C() { f = src }` exists(MemberInitializer mi | - e = q and mi = q.(ObjectInitializer).getAMemberInitializer() and q.getParent() instanceof ObjectCreation and f = mi.getInitializedMember() and @@ -888,16 +809,13 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b ) or // Tuple element, `(..., src, ...)` `f` is `ItemX` of tuple `q` - e = - any(TupleExpr te | - exists(int i | - e = q and - src = te.getArgument(i) and - te.isConstruction() and - f = q.getType().(TupleType).getElement(i) and - postUpdate = false - ) - ) + exists(TupleExpr te, int i | + te = q and + src = te.getArgument(i) and + te.isConstruction() and + f = q.getType().(TupleType).getElement(i) and + postUpdate = false + ) ) or // A write to a dynamic property @@ -907,7 +825,6 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b c.isDynamicProperty(dp) and src = def.getSource() and q = dma.getQualifier() and - e = def.getExpr() and postUpdate = true ) } @@ -943,22 +860,20 @@ private predicate collectionStore(Expr src, CollectionExpression ce) { } /** - * Holds if `e` is an expression that adds `src` to array `a`. + * Holds if there is an expression that adds `src` to array `a`. * * `postUpdate` indicates whether the store targets a post-update node. */ -private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) { +private predicate arrayStore(Expr src, Expr a, boolean postUpdate) { // Direct assignment, `a[i] = src` exists(AssignableDefinition def | a = def.getTargetAccess().(ArrayWrite).getQualifier() and src = def.getSource() and - e = def.getExpr() and postUpdate = true ) or // Array initializer, `new [] { src }` src = a.(ArrayInitializer).getAnElement() and - e = a and postUpdate = false or // Member initializer, `new C { Array = { [i] = src } }` @@ -966,7 +881,6 @@ private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) { mi = a.(ObjectInitializer).getAMemberInitializer() and mi.getLValue() instanceof ArrayAccess and mi.getRValue() = src and - e = a and postUpdate = false ) } @@ -1141,17 +1055,17 @@ private module Cached { ( cfn.getExpr() instanceof Argument or - cfn = - LocalFlow::getPostUpdateReverseStep(any(ControlFlow::Nodes::ExprNode e | - exists(any(SourcePostUpdateNode p).getPreUpdateNode().asExprAtNode(e)) - )) + cfn.getExpr() = + LocalFlow::getPostUpdateReverseStep(any(SourcePostUpdateNode p) + .getPreUpdateNode() + .asExpr()) ) and exprMayHavePostUpdateNode(cfn.getExpr()) or exists(Expr e | e = cfn.getExpr() | - fieldOrPropertyStore(_, _, _, e, true) + fieldOrPropertyStore(_, _, e, true) or - arrayStore(_, _, e, true) + arrayStore(_, e, true) or // needed for reverse stores; e.g. `x.f1.f2 = y` induces // a store step of `f1` into `x` @@ -1166,7 +1080,7 @@ private module Cached { ) ) or - lambdaCallExpr(_, cfn) + lambdaCallExpr(_, _, cfn) } or TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) { sn.getSummarizedCallable() instanceof CallableUsedInSource @@ -1563,35 +1477,15 @@ abstract private class ArgumentNodeImpl extends Node { } private module ArgumentNodes { - private class ArgumentConfiguration extends ControlFlowReachabilityConfiguration { - ArgumentConfiguration() { this = "ArgumentConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - e1.(Argument).isArgumentOf(e2, _) and - exactScope = false and - isSuccessor = true and - if e2 instanceof PropertyWrite - then - exists(AssignableDefinition def | - def.getTargetAccess() = e2 and - scope = def.getExpr() - ) - else scope = e2 - } - } - /** A data-flow node that represents an explicit call argument. */ class ExplicitArgumentNode extends ArgumentNodeImpl { ExplicitArgumentNode() { this.asExpr() instanceof Argument } override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { - exists(ArgumentConfiguration x, Expr c, Argument arg | + exists(Expr c, Argument arg | arg = this.asExpr() and c = call.getExpr() and - arg.isArgumentOf(c, pos) and - x.hasExprPath(_, this.getControlFlowNode(), _, call.getControlFlowNode()) + arg.isArgumentOf(c, pos) ) } } @@ -1600,7 +1494,7 @@ private module ArgumentNodes { class DelegateSelfArgumentNode extends ArgumentNodeImpl, ExprNode { private DataFlowCall call_; - DelegateSelfArgumentNode() { lambdaCallExpr(call_, this.getControlFlowNode()) } + DelegateSelfArgumentNode() { lambdaCallExpr(call_, this.getExpr(), _) } override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { call = call_ and @@ -1857,27 +1751,6 @@ private module OutNodes { } } - class ObjectOrCollectionInitializerConfiguration extends ControlFlowReachabilityConfiguration { - ObjectOrCollectionInitializerConfiguration() { - this = "ObjectOrCollectionInitializerConfiguration" - } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exactScope = false and - scope = e1 and - isSuccessor = true and - exists(ObjectOrCollectionInitializer init | init = e1.(ObjectCreation).getInitializer() | - // E.g. `new Dictionary{ {0, "a"}, {1, "b"} }` - e2 = init.(CollectionInitializer).getAnElementInitializer() - or - // E.g. `new Dictionary() { [0] = "a", [1] = "b" }` - e2 = init.(ObjectInitializer).getAMemberInitializer().getLValue() - ) - } - } - /** * A data-flow node that reads a value returned by a callable using an * `out` or `ref` parameter. @@ -2236,30 +2109,6 @@ predicate jumpStep(Node pred, Node succ) { succ = pred.(LocalFunctionCreationNode).getAnAccess(false) } -private class StoreStepConfiguration extends ControlFlowReachabilityConfiguration { - StoreStepConfiguration() { this = "StoreStepConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exactScope = false and - fieldOrPropertyStore(scope, _, e1, e2, isSuccessor.booleanNot()) - or - exactScope = false and - arrayStore(scope, e1, e2, isSuccessor.booleanNot()) - or - exactScope = false and - isSuccessor = true and - collectionStore(e1, e2) and - scope = e2 - or - exactScope = false and - isSuccessor = true and - isParamsArg(e2, e1, _) and - scope = e2 - } -} - pragma[nomagic] private ContentSet getResultContent() { result.isProperty(any(SystemThreadingTasksTaskTClass c_).getResultProperty()) @@ -2282,21 +2131,17 @@ private predicate recordParameter(RecordType t, Parameter p, string name) { } private predicate storeContentStep(Node node1, Content c, Node node2) { - exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate | - hasNodePath(x, node1, node) and + exists(ExprNode node, boolean postUpdate | if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2 | - arrayStore(_, node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent + arrayStore(node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent ) or - exists(StoreStepConfiguration x | hasNodePath(x, node1, node2) | - collectionStore(node1.asExpr(), node2.asExpr()) and c instanceof ElementContent - ) + collectionStore(node1.asExpr(), node2.asExpr()) and c instanceof ElementContent or - exists(StoreStepConfiguration x, Expr arg, ControlFlow::Node callCfn | - x.hasExprPath(arg, node1.(ExprNode).getControlFlowNode(), _, callCfn) and - node2 = TParamsArgumentNode(callCfn) and - isParamsArg(_, arg, _) and + exists(Call call | + node2 = TParamsArgumentNode(call.getControlFlowNode()) and + isParamsArg(call, node1.asExpr(), _) and c instanceof ElementContent ) or @@ -2352,11 +2197,10 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { c.isSingleton(cont) ) or - exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate | - hasNodePath(x, node1, node) and + exists(ExprNode node, boolean postUpdate | if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2 | - fieldOrPropertyStore(_, c, node1.asExpr(), node.getExpr(), postUpdate) + fieldOrPropertyStore(c, node1.asExpr(), node.getExpr(), postUpdate) ) or exists(Expr e | @@ -2378,133 +2222,51 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepDelegateCall(node1, c, node2) } -pragma[nomagic] -private predicate isAssignExprLValueDescendant(Expr e) { - e = any(AssignExpr ae).getLValue() - or - exists(Expr parent | - isAssignExprLValueDescendant(parent) and - e = parent.getAChildExpr() - ) -} - -private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration { - ReadStepConfiguration() { this = "ReadStepConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exactScope = false and - isSuccessor = true and - fieldOrPropertyRead(e1, _, e2) and - scope = e2 - or - exactScope = false and - isSuccessor = true and - dynamicPropertyRead(e1, _, e2) and - scope = e2 - or - exactScope = false and - isSuccessor = true and - arrayRead(e1, e2) and - scope = e2 - or - exactScope = false and - e1 = e2.(AwaitExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - exactScope = false and - e2 = e1.(TupleExpr).getAnArgument() and - scope = e1 and - isSuccessor = false - } - - override predicate candidateDef( - Expr e, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - exists(ForeachStmt fs | - e = fs.getIterableExpr() and - defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = - fs.getVariableDeclExpr() and - isSuccessor = true - | - scope = fs and - exactScope = true - or - scope = fs.getIterableExpr() and - exactScope = false - or - scope = fs.getVariableDeclExpr() and - exactScope = false - ) - or - scope = - any(AssignExpr ae | - ae = defTo.(AssignableDefinitions::TupleAssignmentDefinition).getAssignment() and - isAssignExprLValueDescendant(e.(TupleExpr)) and - exactScope = false and - isSuccessor = true - ) - or - scope = - any(TupleExpr te | - te.getAnArgument() = defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() and - e = te and - exactScope = false and - isSuccessor = false - ) - } -} - private predicate readContentStep(Node node1, Content c, Node node2) { - exists(ReadStepConfiguration x | - hasNodePath(x, node1, node2) and - arrayRead(node1.asExpr(), node2.asExpr()) and + arrayRead(node1.asExpr(), node2.asExpr()) and + c instanceof ElementContent + or + exists( + ForeachStmt fs, Ssa::ExplicitDefinition def, + AssignableDefinitions::LocalVariableDefinition defTo + | + node1.asExpr() = fs.getIterableExpr() and + defTo.getDeclaration() = fs.getVariableDeclExpr() and + def.getADefinition() = defTo and + node2.(SsaDefinitionNode).getDefinition() = def and c instanceof ElementContent + ) + or + node1 = + any(InstanceParameterAccessPreNode n | + n.getUnderlyingControlFlowNode() = node2.(ExprNode).getControlFlowNode() and + n.getParameter() = c.(PrimaryConstructorParameterContent).getParameter() + ) and + node2.asExpr() instanceof ParameterRead + or + // node1 = (..., node2, ...) + // node1.ItemX flows to node2 + exists(TupleExpr te, int i, Expr item | + te = node1.asExpr() and + not te.isConstruction() and + c.(FieldContent).getField() = te.getType().(TupleType).getElement(i).getUnboundDeclaration() and + // node1 = (..., item, ...) + te.getArgument(i) = item + | + // item = (..., ..., ...) in node1 = (..., (..., ..., ...), ...) + node2.asExpr().(TupleExpr) = item or - exists(ForeachStmt fs, Ssa::ExplicitDefinition def | - x.hasDefPath(fs.getIterableExpr(), node1.getControlFlowNode(), def.getADefinition(), - def.getControlFlowNode()) and - node2.(SsaDefinitionNode).getDefinition() = def and - c instanceof ElementContent + // item = variable in node1 = (..., variable, ...) + exists(AssignableDefinitions::TupleAssignmentDefinition tad | + node2.(AssignableDefinitionNode).getDefinition() = tad and + tad.getLeaf() = item ) or - node1 = - any(InstanceParameterAccessPreNode n | - n.getUnderlyingControlFlowNode() = node2.(ExprNode).getControlFlowNode() and - n.getParameter() = c.(PrimaryConstructorParameterContent).getParameter() - ) and - node2.asExpr() instanceof ParameterRead - or - // node1 = (..., node2, ...) - // node1.ItemX flows to node2 - exists(TupleExpr te, int i, Expr item | - te = node1.asExpr() and - not te.isConstruction() and - c.(FieldContent).getField() = te.getType().(TupleType).getElement(i).getUnboundDeclaration() and - // node1 = (..., item, ...) - te.getArgument(i) = item - | - // item = (..., ..., ...) in node1 = (..., (..., ..., ...), ...) - node2.asExpr().(TupleExpr) = item and - hasNodePath(x, node1, node2) - or - // item = variable in node1 = (..., variable, ...) - exists(AssignableDefinitions::TupleAssignmentDefinition tad | - node2.(AssignableDefinitionNode).getDefinition() = tad and - tad.getLeaf() = item and - hasNodePath(x, node1, node2) - ) - or - // item = variable in node1 = (..., variable, ...) in a case/is var (..., ...) - isPatternExprDescendant(te) and - exists(AssignableDefinitions::LocalVariableDefinition lvd | - node2.(AssignableDefinitionNode).getDefinition() = lvd and - lvd.getDeclaration() = item and - hasNodePath(x, node1, node2) - ) + // item = variable in node1 = (..., variable, ...) in a case/is var (..., ...) + isPatternExprDescendant(te) and + exists(AssignableDefinitions::LocalVariableDefinition lvd | + node2.(AssignableDefinitionNode).getDefinition() = lvd and + lvd.getDeclaration() = item ) ) or @@ -2535,14 +2297,12 @@ predicate readStep(Node node1, ContentSet c, Node node2) { c.isSingleton(cont) ) or - exists(ReadStepConfiguration x | hasNodePath(x, node1, node2) | - fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr()) - or - dynamicPropertyRead(node1.asExpr(), c, node2.asExpr()) - or - node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and - c = getResultContent() - ) + fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr()) + or + dynamicPropertyRead(node1.asExpr(), c, node2.asExpr()) + or + node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and + c = getResultContent() or FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c, node2.(FlowSummaryNode).getSummaryNode()) @@ -2576,9 +2336,9 @@ predicate clearsContent(Node n, ContentSet c) { c.isSingleton(cont) ) or - fieldOrPropertyStore(_, c, _, n.asExpr(), true) + fieldOrPropertyStore(c, _, n.asExpr(), true) or - fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false) + fieldOrPropertyStore(c, _, n.(ObjectInitializerNode).getInitializer(), false) or FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c) or @@ -2817,8 +2577,13 @@ module PostUpdateNodes { override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { pos.isQualifier() and - any(ObjectOrCollectionInitializerConfiguration x) - .hasExprPath(_, cfn, _, call.getControlFlowNode()) + exists(ObjectOrCollectionInitializer init | init = oc.getInitializer() | + // E.g. `new Dictionary{ {0, "a"}, {1, "b"} }` + call.getExpr() = init.(CollectionInitializer).getAnElementInitializer() + or + // E.g. `new Dictionary() { [0] = "a", [1] = "b" }` + call.getExpr() = init.(ObjectInitializer).getAMemberInitializer().getLValue() + ) } override DataFlowCallable getEnclosingCallableImpl() { @@ -2980,45 +2745,26 @@ private predicate isLocalFunctionCallReceiver( f = receiver.getTarget().getUnboundDeclaration() } -private class LambdaConfiguration extends ControlFlowReachabilityConfiguration { - LambdaConfiguration() { this = "LambdaConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - e1 = e2.(DelegateLikeCall).getExpr() and - exactScope = false and - scope = e2 and - isSuccessor = true - or - e1 = e2.(DelegateCreation).getArgument() and - exactScope = false and - scope = e2 and - isSuccessor = true - or - isLocalFunctionCallReceiver(e2, e1, _) and - exactScope = false and - scope = e2 and - isSuccessor = true - } -} - -private predicate lambdaCallExpr(DataFlowCall call, ControlFlow::Node receiver) { - exists(LambdaConfiguration x, DelegateLikeCall dc | - x.hasExprPath(dc.getExpr(), receiver, dc, call.getControlFlowNode()) +private predicate lambdaCallExpr(DataFlowCall call, Expr receiver, ControlFlow::Node receiverCfn) { + exists(DelegateLikeCall dc | + call.(ExplicitDelegateLikeDataFlowCall).getCall() = dc and + receiver = dc.getExpr() and + receiverCfn = receiver.getControlFlowNode() ) or // In local function calls, `F()`, we use the local function access `F` // to represent the receiver. Only needed for flow through captured variables. - exists(LambdaConfiguration x, LocalFunctionCall fc | - x.hasExprPath(fc.getAChild(), receiver, fc, call.getControlFlowNode()) + exists(LocalFunctionCall fc | + receiver = fc.getAChild() and + receiverCfn = receiver.getControlFlowNode() and + fc.getControlFlowNode() = call.getControlFlowNode() ) } /** Holds if `call` is a lambda call where `receiver` is the lambda expression. */ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { ( - lambdaCallExpr(call, receiver.(ExprNode).getControlFlowNode()) and + lambdaCallExpr(call, receiver.asExpr(), _) and // local function calls can be resolved directly without a flow analysis not call.getControlFlowNode().getAstNode() instanceof LocalFunctionCall or @@ -3028,9 +2774,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { } private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) { - exists(LambdaConfiguration x, DelegateCreation dc | - x.hasExprPath(dc.getArgument(), nodeFrom.(ExprNode).getControlFlowNode(), dc, - nodeTo.(ExprNode).getControlFlowNode()) + exists(DelegateCreation dc | + dc.getArgument() = nodeFrom.asExpr() and + dc = nodeTo.asExpr() ) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index bb08c8f7e2c..99a50b36873 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -4,7 +4,6 @@ private import FlowSummaryImpl as FlowSummaryImpl private import semmle.code.csharp.Caching private import semmle.code.csharp.dataflow.internal.DataFlowDispatch private import semmle.code.csharp.dataflow.internal.DataFlowPrivate -private import semmle.code.csharp.dataflow.internal.ControlFlowReachability private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.commons.ComparisonTest // import `TaintedMember` definitions from other files to avoid potential reevaluation @@ -45,82 +44,58 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) ) } -private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityConfiguration { - LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exactScope = false and - isSuccessor = true and - ( - e1 = e2.(ElementAccess).getQualifier() and - scope = e2 - or - e1 = e2.(AddExpr).getAnOperand() and - scope = e2 - or - // A comparison expression where taint can flow from one of the - // operands if the other operand is a constant value. - exists(ComparisonTest ct, Expr other | - ct.getExpr() = e2 and - e1 = ct.getAnArgument() and - other = ct.getAnArgument() and - other.stripCasts().hasValue() and - e1 != other and - scope = e2 - ) - or - e1 = e2.(UnaryLogicalOperation).getAnOperand() and - scope = e2 - or - e1 = e2.(BinaryLogicalOperation).getAnOperand() and - scope = e2 - or - e1 = e2.(InterpolatedStringExpr).getAChild() and - scope = e2 - or - e1 = e2.(InterpolatedStringInsertExpr).getInsert() and - scope = e2 - or - e2 = - any(OperatorCall oc | - oc.getTarget().(ConversionOperator).fromLibrary() and - e1 = oc.getAnArgument() and - scope = e2 - ) - or - e1 = e2.(AwaitExpr).getExpr() and - scope = e2 - or - // Taint flows from the operand of a cast to the cast expression if the cast is to an interpolated string handler. - e2 = - any(CastExpr ce | - e1 = ce.getExpr() and - scope = ce and - ce.getTargetType() - .(Attributable) - .getAnAttribute() - .getType() - .hasFullyQualifiedName("System.Runtime.CompilerServices", - "InterpolatedStringHandlerAttribute") - ) - ) - } -} - -private ControlFlow::Nodes::ExprNode getALastEvalNode(ControlFlow::Nodes::ExprNode cfn) { - exists(OperatorCall oc | any(LocalTaintExprStepConfiguration x).hasExprPath(_, result, oc, cfn) | - oc.getTarget() instanceof ImplicitConversionOperator +private predicate localTaintExprStep(Expr e1, Expr e2) { + e1 = e2.(ElementAccess).getQualifier() + or + e1 = e2.(AddExpr).getAnOperand() + or + // A comparison expression where taint can flow from one of the + // operands if the other operand is a constant value. + exists(ComparisonTest ct, Expr other | + ct.getExpr() = e2 and + e1 = ct.getAnArgument() and + other = ct.getAnArgument() and + other.stripCasts().hasValue() and + e1 != other ) + or + e1 = e2.(UnaryLogicalOperation).getAnOperand() + or + e1 = e2.(BinaryLogicalOperation).getAnOperand() + or + e1 = e2.(InterpolatedStringExpr).getAChild() + or + e1 = e2.(InterpolatedStringInsertExpr).getInsert() + or + e2 = + any(OperatorCall oc | + oc.getTarget().(ConversionOperator).fromLibrary() and + e1 = oc.getAnArgument() + ) + or + e1 = e2.(AwaitExpr).getExpr() + or + // Taint flows from the operand of a cast to the cast expression if the cast is to an interpolated string handler. + e2 = + any(CastExpr ce | + e1 = ce.getExpr() and + ce.getTargetType() + .(Attributable) + .getAnAttribute() + .getType() + .hasFullyQualifiedName("System.Runtime.CompilerServices", + "InterpolatedStringHandlerAttribute") + ) } -private ControlFlow::Nodes::ExprNode getPostUpdateReverseStep(ControlFlow::Nodes::ExprNode e) { - result = getALastEvalNode(e) +private Expr getALastEvalNode(OperatorCall oc) { + localTaintExprStep(result, oc) and oc.getTarget() instanceof ImplicitConversionOperator } +private Expr getPostUpdateReverseStep(Expr e) { result = getALastEvalNode(e) } + private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - hasNodePath(any(LocalTaintExprStepConfiguration x), nodeFrom, nodeTo) + localTaintExprStep(nodeFrom.asExpr(), nodeTo.asExpr()) } cached @@ -191,12 +166,8 @@ private module Cached { // Allow reverse update flow for implicit conversion operator calls. // This is needed to support flow out of method call arguments, where an implicit conversion is applied // to a call argument. - nodeTo.(PostUpdateNode).getPreUpdateNode().(DataFlow::ExprNode).getControlFlowNode() = - getPostUpdateReverseStep(nodeFrom - .(PostUpdateNode) - .getPreUpdateNode() - .(DataFlow::ExprNode) - .getControlFlowNode()) + nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = + getPostUpdateReverseStep(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()) ) and model = "" or diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll deleted file mode 100644 index 706893c64ea..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll +++ /dev/null @@ -1,246 +0,0 @@ -import csharp - -private class ControlFlowScope extends ControlFlowElement { - private boolean exactScope; - - ControlFlowScope() { - exists(ControlFlowReachabilityConfiguration c | - c.candidate(_, _, this, exactScope, _) or - c.candidateDef(_, _, this, exactScope, _) - ) - } - - predicate isExact() { exactScope = true } - - predicate isNonExact() { exactScope = false } -} - -private newtype TControlFlowElementOrBasicBlock = - TControlFlowElement(ControlFlowElement cfe) or - TBasicBlock(ControlFlow::BasicBlock bb) - -class ControlFlowElementOrBasicBlock extends TControlFlowElementOrBasicBlock { - ControlFlowElement asControlFlowElement() { this = TControlFlowElement(result) } - - ControlFlow::BasicBlock asBasicBlock() { this = TBasicBlock(result) } - - string toString() { - result = this.asControlFlowElement().toString() - or - result = this.asBasicBlock().toString() - } - - Location getLocation() { - result = this.asControlFlowElement().getLocation() - or - result = this.asBasicBlock().getLocation() - } -} - -private predicate isBasicBlock(ControlFlowElementOrBasicBlock c) { c instanceof TBasicBlock } - -private predicate isNonExactScope(ControlFlowElementOrBasicBlock c) { - c.asControlFlowElement().(ControlFlowScope).isNonExact() -} - -private predicate step(ControlFlowElementOrBasicBlock pred, ControlFlowElementOrBasicBlock succ) { - pred.asBasicBlock().getANode().getAstNode() = succ.asControlFlowElement() - or - pred.asControlFlowElement() = succ.asControlFlowElement().getAChild() -} - -private predicate basicBlockInNonExactScope( - ControlFlowElementOrBasicBlock bb, ControlFlowElementOrBasicBlock scope -) = doublyBoundedFastTC(step/2, isBasicBlock/1, isNonExactScope/1)(bb, scope) - -pragma[noinline] -private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) { - basicBlockInNonExactScope(TBasicBlock(result), TControlFlowElement(scope)) and - exactScope = false - or - scope.isExact() and - result.getANode().getAstNode() = scope and - exactScope = true -} - -/** - * A helper class for determining control-flow reachability for pairs of - * elements. - * - * This is useful when defining for example expression-based data-flow steps in - * the presence of control-flow splitting, where a data-flow step should make - * sure to stay in the same split. - * - * For example, in - * - * ```csharp - * if (b) - * .... - * var x = "foo"; - * if (b) - * .... - * ``` - * - * there should only be steps from `[b = true] "foo"` to `[b = true] SSA def(x)` - * and `[b = false] "foo"` to `[b = false] SSA def(x)`, and for example not from - * `[b = true] "foo"` to `[b = false] SSA def(x)` - */ -abstract class ControlFlowReachabilityConfiguration extends string { - bindingset[this] - ControlFlowReachabilityConfiguration() { any() } - - /** - * Holds if `e1` and `e2` are expressions for which we want to find a - * control-flow path that follows control flow successors (resp. - * predecessors, as specified by `isSuccessor`) inside the syntactic scope - * `scope`. The Boolean `exactScope` indicates whether a transitive child - * of `scope` is allowed (`exactScope = false`). - */ - predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - none() - } - - /** - * Holds if `e` and `def` are elements for which we want to find a - * control-flow path that follows control flow successors (resp. - * predecessors, as specified by `isSuccessor`) inside the syntactic scope - * `scope`. The Boolean `exactScope` indicates whether a transitive child - * of `scope` is allowed (`exactScope = false`). - */ - predicate candidateDef( - Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - none() - } - - pragma[nomagic] - private predicate reachesBasicBlockExprBase( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, int i, - ControlFlow::BasicBlock bb - ) { - this.candidate(e1, e2, _, _, isSuccessor) and - cfn1 = e1.getAControlFlowNode() and - bb.getNode(i) = cfn1 - } - - pragma[nomagic] - private predicate reachesBasicBlockExprRec( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, - ControlFlow::BasicBlock bb - ) { - exists(ControlFlow::BasicBlock mid | - this.reachesBasicBlockExpr(e1, e2, isSuccessor, cfn1, mid) - | - isSuccessor = true and - bb = mid.getASuccessor() - or - isSuccessor = false and - bb = mid.getAPredecessor() - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockExpr( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, - ControlFlow::BasicBlock bb - ) { - this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, _, bb) - or - exists(ControlFlowElement scope, boolean exactScope | - this.candidate(e1, e2, scope, exactScope, isSuccessor) and - this.reachesBasicBlockExprRec(e1, e2, isSuccessor, cfn1, bb) and - bb = getABasicBlockInScope(scope, exactScope) - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinitionBase( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - int i, ControlFlow::BasicBlock bb - ) { - this.candidateDef(e, def, _, _, isSuccessor) and - cfn = e.getAControlFlowNode() and - bb.getNode(i) = cfn - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinitionRec( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - ControlFlow::BasicBlock bb - ) { - exists(ControlFlow::BasicBlock mid | - this.reachesBasicBlockDefinition(e, def, isSuccessor, cfn, mid) - | - isSuccessor = true and - bb = mid.getASuccessor() - or - isSuccessor = false and - bb = mid.getAPredecessor() - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinition( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - ControlFlow::BasicBlock bb - ) { - this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, _, bb) - or - exists(ControlFlowElement scope, boolean exactScope | - this.candidateDef(e, def, scope, exactScope, isSuccessor) and - this.reachesBasicBlockDefinitionRec(e, def, isSuccessor, cfn, bb) and - bb = getABasicBlockInScope(scope, exactScope) - ) - } - - /** - * Holds if there is a control-flow path from `cfn1` to `cfn2`, where `cfn1` is a - * control-flow node for `e1` and `cfn2` is a control-flow node for `e2`. - */ - pragma[nomagic] - predicate hasExprPath(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2) { - exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j | - this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, i, bb) and - cfn2 = bb.getNode(j) and - cfn2 = e2.getAControlFlowNode() - | - isSuccessor = true and j >= i - or - isSuccessor = false and i >= j - ) - or - exists(ControlFlow::BasicBlock bb | - this.reachesBasicBlockExprRec(e1, e2, _, cfn1, bb) and - cfn2 = bb.getANode() and - cfn2 = e2.getAControlFlowNode() - ) - } - - /** - * Holds if there is a control-flow path from `cfn` to `cfnDef`, where `cfn` is a - * control-flow node for `e` and `cfnDef` is a control-flow node for `def`. - */ - pragma[nomagic] - predicate hasDefPath( - Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef - ) { - exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j | - this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, i, bb) and - cfnDef = bb.getNode(j) and - def.getExpr().getAControlFlowNode() = cfnDef - | - isSuccessor = true and j >= i - or - isSuccessor = false and i >= j - ) - or - exists(ControlFlow::BasicBlock bb | - this.reachesBasicBlockDefinitionRec(e, def, _, cfn, bb) and - def.getExpr().getAControlFlowNode() = cfnDef and - cfnDef = bb.getANode() - ) - } -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll index 71d177a48bb..656bf9aae21 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll @@ -8,26 +8,14 @@ private module Impl { private import ConstantUtils private import SsaReadPositionCommon private import semmle.code.csharp.controlflow.Guards as G - private import ControlFlowReachability private class ExprNode = ControlFlow::Nodes::ExprNode; - private class ExprChildReachability extends ControlFlowReachabilityConfiguration { - ExprChildReachability() { this = "ExprChildReachability" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - e2 = e1.getAChild() and - scope = e1 and - exactScope = false and - isSuccessor in [false, true] - } - } - /** Holds if `parent` having child `child` implies `parentNode` having child `childNode`. */ predicate hasChild(Expr parent, Expr child, ExprNode parentNode, ExprNode childNode) { - any(ExprChildReachability x).hasExprPath(parent, parentNode, child, childNode) + parent.getAChild() = child and + parentNode = parent.getControlFlowNode() and + childNode = child.getControlFlowNode() } /** Holds if SSA definition `def` equals `e + delta`. */ diff --git a/csharp/ql/src/Security Features/CWE-079/XSS.ql b/csharp/ql/src/Security Features/CWE-079/XSS.ql index 8735d89ef50..b819ed06bf8 100644 --- a/csharp/ql/src/Security Features/CWE-079/XSS.ql +++ b/csharp/ql/src/Security Features/CWE-079/XSS.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id cs/web/xss * @tags security diff --git a/csharp/ql/src/Security Features/CWE-117/LogForging.ql b/csharp/ql/src/Security Features/CWE-117/LogForging.ql index 9494af33570..a922f1c02f8 100644 --- a/csharp/ql/src/Security Features/CWE-117/LogForging.ql +++ b/csharp/ql/src/Security Features/CWE-117/LogForging.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @security-severity 7.8 + * @security-severity 6.1 * @precision high * @id cs/log-forging * @tags security diff --git a/csharp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/csharp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..c317194bc25 --- /dev/null +++ b/csharp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `cs/log-forging` has been reduced from 7.8 (high) to 6.1 (medium). +* The `@security-severity` metadata of `cs/web/xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index b2094817cfb..90ef19f62fe 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -26,6 +26,7 @@ | CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:16:31:20 | ... > ... | | CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:24:31:24 | access to parameter i | | CSharp7.cs:31:24:31:24 | access to parameter i | CSharp7.cs:31:16:31:59 | ... ? ... : ... | +| CSharp7.cs:31:28:31:59 | throw ... | CSharp7.cs:31:16:31:59 | ... ? ... : ... | | CSharp7.cs:35:7:35:18 | this | CSharp7.cs:35:7:35:18 | this access | | CSharp7.cs:39:9:39:9 | access to parameter x | CSharp7.cs:39:9:39:21 | SSA def(x) | | CSharp7.cs:39:13:39:21 | "tainted" | CSharp7.cs:39:9:39:9 | access to parameter x | @@ -253,6 +254,7 @@ | CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:235:13:235:42 | [input] SSA phi read(o) | | CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:237:18:237:18 | access to local variable o | | CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... | +| CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [true] ... && ... | | CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... | | CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [true] ... && ... | | CSharp7.cs:233:18:233:23 | Int32 i1 | CSharp7.cs:233:18:233:23 | SSA def(i1) | @@ -338,6 +340,8 @@ | CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:40:297:44 | Int32 y | | CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:49:297:49 | access to local variable x | | CSharp7.cs:297:35:297:44 | [false] ... is ... | CSharp7.cs:297:25:297:44 | [false] ... && ... | +| CSharp7.cs:297:35:297:44 | [false] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... | +| CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [false] ... && ... | | CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... | | CSharp7.cs:297:40:297:44 | Int32 y | CSharp7.cs:297:40:297:44 | SSA def(y) | | CSharp7.cs:297:40:297:44 | SSA def(y) | CSharp7.cs:299:31:299:31 | access to local variable y | diff --git a/csharp/ql/test/library-tests/dispatch/CallGraph.expected b/csharp/ql/test/library-tests/dispatch/CallGraph.expected index 31e2a99ae24..e7ebca868ba 100644 --- a/csharp/ql/test/library-tests/dispatch/CallGraph.expected +++ b/csharp/ql/test/library-tests/dispatch/CallGraph.expected @@ -24,6 +24,7 @@ | ExactCallable.cs:15:25:15:35 | Run`2 | ExactCallable.cs:172:21:172:33 | MethodWithOut | | ExactCallable.cs:15:25:15:35 | Run`2 | ExactCallable.cs:177:21:177:34 | MethodWithOut2 | | ExactCallable.cs:182:21:182:22 | M1 | ExactCallable.cs:187:21:187:22 | M2 | +| TypeFlow.cs:3:7:3:14 | | TypeFlow.cs:22:20:22:22 | set_Prop | | TypeFlow.cs:5:5:5:12 | TypeFlow | TypeFlow.cs:24:10:24:12 | Run | | TypeFlow.cs:24:10:24:12 | Run | TypeFlow.cs:12:29:12:34 | Method | | TypeFlow.cs:24:10:24:12 | Run | TypeFlow.cs:17:30:17:35 | Method | diff --git a/csharp/ql/test/library-tests/structuralcomparison/structuralComparison.expected b/csharp/ql/test/library-tests/structuralcomparison/structuralComparison.expected index 0f131d8c25c..d9b6636469a 100644 --- a/csharp/ql/test/library-tests/structuralcomparison/structuralComparison.expected +++ b/csharp/ql/test/library-tests/structuralcomparison/structuralComparison.expected @@ -56,11 +56,11 @@ gvn | StructuralComparison.cs:3:14:3:18 | this access | (kind:Expr(12),false,Class) | | StructuralComparison.cs:3:14:3:18 | {...} | (kind:Stmt(1)) | | StructuralComparison.cs:5:26:5:26 | access to field x | (kind:Expr(16),true,x) | -| StructuralComparison.cs:5:26:5:26 | this access | (kind:Expr(12)) | +| StructuralComparison.cs:5:26:5:26 | this access | (kind:Expr(12),false,Class) | | StructuralComparison.cs:5:26:5:30 | ... = ... | ((kind:Expr(16),true,x) :: (0 :: (kind:Expr(63)))) | | StructuralComparison.cs:5:30:5:30 | 0 | 0 | | StructuralComparison.cs:6:26:6:26 | access to field y | (kind:Expr(16),true,y) | -| StructuralComparison.cs:6:26:6:26 | this access | (kind:Expr(12)) | +| StructuralComparison.cs:6:26:6:26 | this access | (kind:Expr(12),false,Class) | | StructuralComparison.cs:6:26:6:30 | ... = ... | ((kind:Expr(16),true,y) :: (1 :: (kind:Expr(63)))) | | StructuralComparison.cs:6:30:6:30 | 1 | 1 | | StructuralComparison.cs:8:24:8:24 | 0 | 0 | diff --git a/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst b/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst index 413471be885..b8f064c7574 100644 --- a/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst +++ b/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst @@ -406,7 +406,7 @@ Adds a new taint source. Most taint-tracking queries will use the new source. - **type**: Name of a type from which to evaluate **path**. - **path**: Access path leading to the source. -- **kind**: Kind of source to add. Currently only **remote** is used. +- **kind**: Kind of source to add. See the section on source kinds for a list of supported kinds. Example: @@ -553,7 +553,16 @@ Kinds Source kinds ~~~~~~~~~~~~ -See documentation below for :ref:`Threat models `. +- **remote**: A general source of remote flow. +- **browser**: A source in the browser environment that does not fit a more specific browser kind. +- **browser-url-query**: A source derived from the query parameters of the browser URL, such as ``location.search``. +- **browser-url-fragment**: A source derived from the fragment part of the browser URL, such as ``location.hash``. +- **browser-url-path**: A source derived from the pathname of the browser URL, such as ``location.pathname``. +- **browser-url**: A source derived from the browser URL, where the untrusted part is prefixed by trusted data such as the scheme and hostname. +- **browser-window-name**: A source derived from the window name, such as ``window.name``. +- **browser-message-event**: A source derived from cross-window message passing, such as ``event`` in ``window.onmessage = event => {...}``. + +See also :ref:`Threat models `. Sink kinds ~~~~~~~~~~ diff --git a/go/extractor/go.mod b/go/extractor/go.mod index 46d189d005e..ae43e8a51bd 100644 --- a/go/extractor/go.mod +++ b/go/extractor/go.mod @@ -9,8 +9,8 @@ toolchain go1.26.0 // when adding or removing dependencies, run // bazel mod tidy require ( - golang.org/x/mod v0.33.0 - golang.org/x/tools v0.42.0 + golang.org/x/mod v0.34.0 + golang.org/x/tools v0.43.0 ) require github.com/stretchr/testify v1.11.1 @@ -18,6 +18,6 @@ require github.com/stretchr/testify v1.11.1 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sync v0.19.0 // indirect + golang.org/x/sync v0.20.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go/extractor/go.sum b/go/extractor/go.sum index ade080a41ad..8bb3f3dc9fc 100644 --- a/go/extractor/go.sum +++ b/go/extractor/go.sum @@ -6,12 +6,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/go/ql/lib/Customizations.qll b/go/ql/lib/Customizations.qll index 127840de9dd..56824bc03eb 100644 --- a/go/ql/lib/Customizations.qll +++ b/go/ql/lib/Customizations.qll @@ -8,5 +8,7 @@ * `FileSystemAccess`, or the `Source` and `Sink` classes associated with the security queries * to model frameworks that are not covered by the standard library. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/go.qll b/go/ql/lib/go.qll index 1b8bf94a0d2..af9f676e013 100644 --- a/go/ql/lib/go.qll +++ b/go/ql/lib/go.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with Go programs. */ +overlay[local?] +module; import Customizations import semmle.go.Architectures diff --git a/go/ql/lib/ideContextual.qll b/go/ql/lib/ideContextual.qll index b28a23a6e00..2f96afdeffe 100644 --- a/go/ql/lib/ideContextual.qll +++ b/go/ql/lib/ideContextual.qll @@ -2,6 +2,8 @@ * Provides classes and predicates related to contextual queries * in the code viewer. */ +overlay[local?] +module; import go private import codeql.util.FileSystem diff --git a/go/ql/lib/semmle/go/AST.qll b/go/ql/lib/semmle/go/AST.qll index 6a840f81cbb..a0715f6ca0e 100644 --- a/go/ql/lib/semmle/go/AST.qll +++ b/go/ql/lib/semmle/go/AST.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with AST nodes. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/Architectures.qll b/go/ql/lib/semmle/go/Architectures.qll index bb4face2407..0daef5147b4 100644 --- a/go/ql/lib/semmle/go/Architectures.qll +++ b/go/ql/lib/semmle/go/Architectures.qll @@ -1,4 +1,6 @@ /** Provides classes for working with architectures. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/Comments.qll b/go/ql/lib/semmle/go/Comments.qll index b55810311f8..08a0fabc1ca 100644 --- a/go/ql/lib/semmle/go/Comments.qll +++ b/go/ql/lib/semmle/go/Comments.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with code comments. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/Concepts.qll b/go/ql/lib/semmle/go/Concepts.qll index 4e328ed76c4..ffa48ea9654 100644 --- a/go/ql/lib/semmle/go/Concepts.qll +++ b/go/ql/lib/semmle/go/Concepts.qll @@ -3,6 +3,8 @@ * access or system command execution, for which individual framework libraries * provide concrete subclasses. */ +overlay[local?] +module; import go import semmle.go.dataflow.FunctionInputsAndOutputs diff --git a/go/ql/lib/semmle/go/Decls.qll b/go/ql/lib/semmle/go/Decls.qll index 9d1e4d2611a..7588ab913be 100644 --- a/go/ql/lib/semmle/go/Decls.qll +++ b/go/ql/lib/semmle/go/Decls.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with declarations. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/DiagnosticsReporting.qll b/go/ql/lib/semmle/go/DiagnosticsReporting.qll index 691c430aa73..c7d0b547a86 100644 --- a/go/ql/lib/semmle/go/DiagnosticsReporting.qll +++ b/go/ql/lib/semmle/go/DiagnosticsReporting.qll @@ -1,4 +1,6 @@ /** Provides classes for working with errors and warnings recorded during extraction. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/Errors.qll b/go/ql/lib/semmle/go/Errors.qll index 2e138e8de61..4ea0ed2c015 100644 --- a/go/ql/lib/semmle/go/Errors.qll +++ b/go/ql/lib/semmle/go/Errors.qll @@ -1,4 +1,6 @@ /** Provides classes for working with Go frontend errors recorded during extraction. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/Expr.qll b/go/ql/lib/semmle/go/Expr.qll index 4a4ab00f053..0dcc707b19d 100644 --- a/go/ql/lib/semmle/go/Expr.qll +++ b/go/ql/lib/semmle/go/Expr.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with expressions. */ +overlay[local] +module; import go @@ -829,7 +831,7 @@ class ConversionExpr extends CallOrConversionExpr { /** * A function call expression. * - * On snapshots with incomplete type information, type conversions may be misclassified + * On databases with incomplete type information, type conversions may be misclassified * as function call expressions. * * Examples: @@ -2035,6 +2037,9 @@ class ConstantName extends ValueName { override string getAPrimaryQlClass() { result = "ConstantName" } } +/** Holds if `e` is an expression that refers to the `nil` constant. */ +predicate exprRefersToNil(Expr e) { e.(ConstantName).getTarget() = Builtin::nil() } + /** * A name referring to a variable. * @@ -2093,7 +2098,7 @@ class LabelName extends Name { * Holds if `e` is a type expression, as determined by a bottom-up syntactic * analysis starting with `TypeName`s. * - * On a snapshot with full type information, this predicate covers all type + * On a database with full type information, this predicate covers all type * expressions. However, if type information is missing then not all type names * may be identified as such, so not all type expressions can be determined by * a bottom-up analysis. In such cases, `isTypeExprTopDown` below is useful. @@ -2131,11 +2136,12 @@ private predicate isTypeExprBottomUp(Expr e) { * Holds if `e` must be a type expression because it either occurs in a syntactic * position where a type is expected, or it is part of a larger type expression. * - * This predicate is only needed on snapshots for which type information is - * incomplete. It is an underapproximation; in cases where it is syntactically ambiguous - * whether an expression refers to a type or a value, we conservatively assume that - * it may be the latter and so this predicate does not consider the expression to be - * a type expression. + * This predicate is only needed on databases for which type information is + * incomplete - for example, when some dependencies could not be reached during + * extraction. It is an underapproximation; in cases where it is syntactically + * ambiguous whether an expression refers to a type or a value, we conservatively + * assume that it may be the latter and so this predicate does not consider the + * expression to be a type expression. */ pragma[nomagic] private predicate isTypeExprTopDown(Expr e) { @@ -2145,20 +2151,12 @@ private predicate isTypeExprTopDown(Expr e) { or e = any(ArrayTypeExpr ae).getElement() or - e = any(FieldDecl f).getTypeExpr() - or - e = any(ParameterDecl pd).getTypeExpr() + e = any(FieldBase fb).getTypeExpr() or e = any(TypeParamDecl tpd).getTypeConstraintExpr() or e = any(TypeParamDecl tpd).getNameExpr(_) or - e = any(ReceiverDecl rd).getTypeExpr() - or - e = any(ResultVariableDecl rvd).getTypeExpr() - or - e = any(MethodSpec md).getTypeExpr() - or e = any(MapTypeExpr mt).getKeyTypeExpr() or e = any(MapTypeExpr mt).getValueTypeExpr() @@ -2175,7 +2173,7 @@ private predicate isTypeExprTopDown(Expr e) { or e = any(TypeSwitchStmt s).getACase().getExpr(_) and // special case: `nil` is allowed in a type case but isn't a type - not e = Builtin::nil().getAReference() + not exprRefersToNil(e) or e = any(SelectorExpr sel | isTypeExprTopDown(sel)).getBase() or diff --git a/go/ql/lib/semmle/go/Files.qll b/go/ql/lib/semmle/go/Files.qll index cda168482ca..ab4e2e084ed 100644 --- a/go/ql/lib/semmle/go/Files.qll +++ b/go/ql/lib/semmle/go/Files.qll @@ -1,4 +1,6 @@ /** Provides classes for working with files and folders. */ +overlay[local] +module; import go private import codeql.util.FileSystem diff --git a/go/ql/lib/semmle/go/GoMod.qll b/go/ql/lib/semmle/go/GoMod.qll index 119339c18eb..6a899cd1d60 100644 --- a/go/ql/lib/semmle/go/GoMod.qll +++ b/go/ql/lib/semmle/go/GoMod.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with go.mod files. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/HTML.qll b/go/ql/lib/semmle/go/HTML.qll index 2f0e411a88d..01f8a069fe9 100644 --- a/go/ql/lib/semmle/go/HTML.qll +++ b/go/ql/lib/semmle/go/HTML.qll @@ -1,4 +1,6 @@ /** Provides classes for working with HTML documents. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/Locations.qll b/go/ql/lib/semmle/go/Locations.qll index 7503421c0ff..da55799e6df 100644 --- a/go/ql/lib/semmle/go/Locations.qll +++ b/go/ql/lib/semmle/go/Locations.qll @@ -1,4 +1,6 @@ /** Provides classes for working with locations and program elements that have locations. */ +overlay[local] +module; import go private import semmle.go.Overlay diff --git a/go/ql/lib/semmle/go/Packages.qll b/go/ql/lib/semmle/go/Packages.qll index d1163350446..f37ddb0507e 100644 --- a/go/ql/lib/semmle/go/Packages.qll +++ b/go/ql/lib/semmle/go/Packages.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with packages. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/PrintAst.qll b/go/ql/lib/semmle/go/PrintAst.qll index bee97008dbd..6ea5fcc3971 100644 --- a/go/ql/lib/semmle/go/PrintAst.qll +++ b/go/ql/lib/semmle/go/PrintAst.qll @@ -1,6 +1,8 @@ /** * Provides queries to pretty-print a Go AST as a graph. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/Scopes.qll b/go/ql/lib/semmle/go/Scopes.qll index 2ab08b5b5b4..4e9a13c8ea1 100644 --- a/go/ql/lib/semmle/go/Scopes.qll +++ b/go/ql/lib/semmle/go/Scopes.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with scopes and declared objects. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/Stmt.qll b/go/ql/lib/semmle/go/Stmt.qll index 8719ad543cf..aa6fe7c24de 100644 --- a/go/ql/lib/semmle/go/Stmt.qll +++ b/go/ql/lib/semmle/go/Stmt.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with statements. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/StringOps.qll b/go/ql/lib/semmle/go/StringOps.qll index 3463e4fdf87..6af2946f95c 100644 --- a/go/ql/lib/semmle/go/StringOps.qll +++ b/go/ql/lib/semmle/go/StringOps.qll @@ -1,6 +1,8 @@ /** * Provides predicates and classes for working with string operations. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index d377cb2c9d8..574d7568543 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with Go types. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/Util.qll b/go/ql/lib/semmle/go/Util.qll index 02175f2d66a..a6fe2a6b2b5 100644 --- a/go/ql/lib/semmle/go/Util.qll +++ b/go/ql/lib/semmle/go/Util.qll @@ -1,4 +1,6 @@ /** This module provides general utility classes and predicates. */ +overlay[local] +module; /** * A Boolean value. diff --git a/go/ql/lib/semmle/go/VariableWithFields.qll b/go/ql/lib/semmle/go/VariableWithFields.qll index 0fce5247dcd..277a7dcc326 100644 --- a/go/ql/lib/semmle/go/VariableWithFields.qll +++ b/go/ql/lib/semmle/go/VariableWithFields.qll @@ -1,4 +1,6 @@ /** Provides the `VariableWithFields` class, for working with variables with a chain of field or element accesses chained to it. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/concepts/GeneratedFile.qll b/go/ql/lib/semmle/go/concepts/GeneratedFile.qll index d1067b60ad0..683a8be7e05 100644 --- a/go/ql/lib/semmle/go/concepts/GeneratedFile.qll +++ b/go/ql/lib/semmle/go/concepts/GeneratedFile.qll @@ -1,4 +1,6 @@ /** Provides a class for generated files. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/concepts/HTTP.qll b/go/ql/lib/semmle/go/concepts/HTTP.qll index b3990edd084..73f3bfb8784 100644 --- a/go/ql/lib/semmle/go/concepts/HTTP.qll +++ b/go/ql/lib/semmle/go/concepts/HTTP.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with HTTP-related concepts such as requests and responses. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll b/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll index 43b8c7e8dd3..dc52abb25ab 100644 --- a/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll +++ b/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with basic blocks. */ +overlay[local] +module; import go private import ControlFlowGraphImpl diff --git a/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll b/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll index 88adb88c026..77bb94d89f8 100644 --- a/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll +++ b/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with a CFG-based program representation. */ +overlay[local] +module; import go private import ControlFlowGraphImpl @@ -62,6 +64,7 @@ module ControlFlow { BasicBlock getBasicBlock() { result.getANode() = this } /** Holds if this node dominates `dominee` in the control-flow graph. */ + overlay[caller?] pragma[inline] predicate dominatesNode(ControlFlow::Node dominee) { exists(ReachableBasicBlock thisbb, ReachableBasicBlock dbb, int i, int j | diff --git a/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll b/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll index 71bd0ea561f..a26ab3adaf5 100644 --- a/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll +++ b/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll @@ -3,6 +3,8 @@ * * Provides predicates for building intra-procedural CFGs. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/controlflow/IR.qll b/go/ql/lib/semmle/go/controlflow/IR.qll index 144f0df6e7d..a4c73004108 100644 --- a/go/ql/lib/semmle/go/controlflow/IR.qll +++ b/go/ql/lib/semmle/go/controlflow/IR.qll @@ -9,6 +9,8 @@ * Each instruction is also a control-flow node, but there are control-flow nodes that are not * instructions (synthetic entry and exit nodes, as well as no-op skip nodes). */ +overlay[local] +module; import go private import semmle.go.controlflow.ControlFlowGraphImpl @@ -294,7 +296,7 @@ module IR { /** * An IR instruction that reads the value of a field. * - * On snapshots with incomplete type information, method expressions may sometimes be + * On databases with incomplete type information, method expressions may sometimes be * misclassified as field reads. */ class FieldReadInstruction extends ComponentReadInstruction { diff --git a/go/ql/lib/semmle/go/dataflow/DataFlow.qll b/go/ql/lib/semmle/go/dataflow/DataFlow.qll index c26adbfd2c2..bc0d310566e 100644 --- a/go/ql/lib/semmle/go/dataflow/DataFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/DataFlow.qll @@ -14,6 +14,8 @@ * (intraprocedural) data flow, invoke `DataFlow::localFlow` or * `DataFlow::LocalFlowStep` with arguments of type `DataFlow::Node`. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 388921224ad..e1170aeda24 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -84,6 +84,8 @@ * "taint" indicates a default additional taint step and "value" indicates a * globally applicable value-preserving step. */ +overlay[local?] +module; private import go private import internal.ExternalFlowExtensions::Extensions as Extensions diff --git a/go/ql/lib/semmle/go/dataflow/FlowSummary.qll b/go/ql/lib/semmle/go/dataflow/FlowSummary.qll index 749e1c92e06..632697b341f 100644 --- a/go/ql/lib/semmle/go/dataflow/FlowSummary.qll +++ b/go/ql/lib/semmle/go/dataflow/FlowSummary.qll @@ -1,6 +1,8 @@ /** * Provides classes and predicates for defining flow summaries. */ +overlay[local?] +module; import go private import internal.FlowSummaryImpl as Impl diff --git a/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll b/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll index 89d3c297fed..5f437f81576 100644 --- a/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll +++ b/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll @@ -2,6 +2,8 @@ * Provides QL classes for indicating data flow through a function parameter, return value, * or receiver. */ +overlay[local] +module; import go private import semmle.go.dataflow.internal.DataFlowPrivate diff --git a/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll b/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll index e566ca41c2f..88a659f6f82 100644 --- a/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll +++ b/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll @@ -29,6 +29,8 @@ * common reason for this is that the analysis cannot prove that there * are no side-effects that might cause the computed value to change. */ +overlay[local] +module; /* * Note to developers: the correctness of this module depends on the diff --git a/go/ql/lib/semmle/go/dataflow/Properties.qll b/go/ql/lib/semmle/go/dataflow/Properties.qll index f7df3391f40..573b001a3c3 100644 --- a/go/ql/lib/semmle/go/dataflow/Properties.qll +++ b/go/ql/lib/semmle/go/dataflow/Properties.qll @@ -1,6 +1,8 @@ /** * Provides a class for representing and reasoning about properties of data-flow nodes. */ +overlay[local] +module; import go @@ -22,7 +24,7 @@ class Property extends TProperty { isTrue = eq.getPolarity().booleanXor(e.getBoolValue().booleanXor(outcome)) or this = IsNil(isTrue) and - e = Builtin::nil().getAReference() and + exprRefersToNil(e) and isTrue = eq.getPolarity().booleanXor(outcome).booleanNot() ) or diff --git a/go/ql/lib/semmle/go/dataflow/SSA.qll b/go/ql/lib/semmle/go/dataflow/SSA.qll index 69fffa393c1..46ce4da3935 100644 --- a/go/ql/lib/semmle/go/dataflow/SSA.qll +++ b/go/ql/lib/semmle/go/dataflow/SSA.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with static single assignment form (SSA). */ +overlay[local] +module; import go private import SsaImpl diff --git a/go/ql/lib/semmle/go/dataflow/SsaImpl.qll b/go/ql/lib/semmle/go/dataflow/SsaImpl.qll index 026c8114f9f..9648335a6dd 100644 --- a/go/ql/lib/semmle/go/dataflow/SsaImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/SsaImpl.qll @@ -3,6 +3,8 @@ * * Provides predicates for constructing an SSA representation for functions. */ +overlay[local] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/TaintTracking.qll b/go/ql/lib/semmle/go/dataflow/TaintTracking.qll index c469574b3b9..89b43de0738 100644 --- a/go/ql/lib/semmle/go/dataflow/TaintTracking.qll +++ b/go/ql/lib/semmle/go/dataflow/TaintTracking.qll @@ -2,6 +2,8 @@ * Provides classes for performing local (intra-procedural) and * global (inter-procedural) taint-tracking analyses. */ +overlay[local?] +module; import semmle.go.dataflow.DataFlow diff --git a/go/ql/lib/semmle/go/dataflow/barrierguardutil/RedirectCheckBarrierGuard.qll b/go/ql/lib/semmle/go/dataflow/barrierguardutil/RedirectCheckBarrierGuard.qll index d185f9f78f3..cd5490e63c0 100644 --- a/go/ql/lib/semmle/go/dataflow/barrierguardutil/RedirectCheckBarrierGuard.qll +++ b/go/ql/lib/semmle/go/dataflow/barrierguardutil/RedirectCheckBarrierGuard.qll @@ -1,6 +1,8 @@ /** * Provides an implementation of a commonly used barrier guard for sanitizing untrusted URLs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/barrierguardutil/RegexpCheck.qll b/go/ql/lib/semmle/go/dataflow/barrierguardutil/RegexpCheck.qll index 8cdc3b2e1ac..4b669a305f5 100644 --- a/go/ql/lib/semmle/go/dataflow/barrierguardutil/RegexpCheck.qll +++ b/go/ql/lib/semmle/go/dataflow/barrierguardutil/RegexpCheck.qll @@ -1,6 +1,8 @@ /** * Provides an implementation of a commonly used barrier guard for sanitizing untrusted URLs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/barrierguardutil/UrlCheck.qll b/go/ql/lib/semmle/go/dataflow/barrierguardutil/UrlCheck.qll index 8abcfb327cc..8a105cc8fa9 100644 --- a/go/ql/lib/semmle/go/dataflow/barrierguardutil/UrlCheck.qll +++ b/go/ql/lib/semmle/go/dataflow/barrierguardutil/UrlCheck.qll @@ -1,6 +1,8 @@ /** * Provides an implementation of a commonly used barrier guard for sanitizing untrusted URLs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll b/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll index e978cb3e587..05897354061 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll @@ -1,4 +1,6 @@ /** Contains predicates for dealing with container flow. */ +overlay[local?] +module; import go private import DataFlowNodes diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll index a06edad0be2..10455f84edb 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import go private import DataFlowPrivate @@ -119,6 +122,7 @@ class ArgumentPosition extends int { } /** Holds if arguments at position `apos` match parameters at position `ppos`. */ +overlay[caller?] pragma[inline] predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos } @@ -130,6 +134,7 @@ private predicate isInterfaceMethod(Method c) { * Holds if `call` is passing `arg` to param `p` in any circumstance except passing * a receiver parameter to a concrete method. */ +overlay[caller?] pragma[inline] predicate golangSpecificParamArgFilter( DataFlowCall call, DataFlow::ParameterNode p, DataFlow::ArgumentNode arg diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll index c9761d21702..ae10681799f 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import DataFlowImplSpecific private import codeql.dataflow.internal.DataFlowImpl private import semmle.go.Locations diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll index 6df86bde023..27db6081e49 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import DataFlowImplSpecific private import codeql.dataflow.internal.DataFlowImplCommon private import semmle.go.Locations diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll index b4d92771150..cf4794a9715 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll @@ -2,6 +2,8 @@ * Provides consistency queries for checking invariants in the language-specific * data-flow classes and predicates. */ +overlay[local?] +module; private import go private import DataFlowImplSpecific as Impl diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplSpecific.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplSpecific.qll index c680778ce4d..c2c6b0b7c43 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplSpecific.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplSpecific.qll @@ -1,6 +1,8 @@ /** * Provides Go-specific definitions for use in the data flow library. */ +overlay[local?] +module; private import codeql.dataflow.DataFlow private import semmle.go.Locations diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll index 4fb767e548c..8fca4bec8c6 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + private import go private import semmle.go.dataflow.FunctionInputsAndOutputs private import semmle.go.dataflow.FlowSummary diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll index 76b0ef363e3..33149bf0057 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import go private import DataFlowUtil private import DataFlowImplCommon @@ -478,5 +481,6 @@ predicate allowParameterReturnInSelf(ParameterNode p) { class ContentApprox = Unit; /** Gets an approximated value for content `c`. */ +overlay[caller?] pragma[inline] ContentApprox getContentApprox(Content c) { any() } diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll index 404eca4b4a2..b29ff7d5ea8 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll @@ -1,6 +1,8 @@ /** * Provides Go-specific definitions for use in the data flow library. */ +overlay[local?] +module; private import go private import semmle.go.dataflow.FunctionInputsAndOutputs @@ -147,6 +149,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) { * Holds if data flows from `source` to `sink` in zero or more local * (intra-procedural) steps. */ +overlay[caller?] pragma[inline] predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } @@ -560,7 +563,7 @@ private predicate onlyPossibleReturnOfBool(FuncDecl fd, FunctionOutput res, Node */ predicate possiblyReturnsNonNil(FuncDecl fd, FunctionOutput res, Node ret) { ret = res.getEntryNode(fd) and - not ret.asExpr() = Builtin::nil().getAReference() + not exprRefersToNil(ret.asExpr()) } /** @@ -570,7 +573,7 @@ predicate possiblyReturnsNonNil(FuncDecl fd, FunctionOutput res, Node ret) { private predicate onlyPossibleReturnOfNonNil(FuncDecl fd, FunctionOutput res, Node ret) { possiblyReturnsNonNil(fd, res, ret) and forall(Node otherRet | otherRet = res.getEntryNode(fd) and otherRet != ret | - otherRet.asExpr() = Builtin::nil().getAReference() + exprRefersToNil(otherRet.asExpr()) ) } @@ -609,7 +612,7 @@ private predicate isCertainlyNotNil(DataFlow::Node node) { */ private predicate onlyPossibleReturnOfNil(FuncDecl fd, FunctionOutput res, DataFlow::Node ret) { ret = res.getEntryNode(fd) and - ret.asExpr() = Builtin::nil().getAReference() and + exprRefersToNil(ret.asExpr()) and forall(DataFlow::Node otherRet | otherRet = res.getEntryNode(fd) and otherRet != ret | isCertainlyNotNil(otherRet) ) diff --git a/go/ql/lib/semmle/go/dataflow/internal/ExternalFlowExtensions.qll b/go/ql/lib/semmle/go/dataflow/internal/ExternalFlowExtensions.qll index 2e962299f3e..5d43cf674c1 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/ExternalFlowExtensions.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/ExternalFlowExtensions.qll @@ -1,6 +1,8 @@ /** * This module provides extensible predicates for defining MaD models. */ +overlay[local?] +module; private import codeql.mad.static.ModelsAsData as SharedMaD diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll index f09f42872ea..240665bd492 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll @@ -1,6 +1,8 @@ /** * Provides classes and predicates for defining flow summaries. */ +overlay[local?] +module; private import go private import codeql.dataflow.internal.FlowSummaryImpl diff --git a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingImplSpecific.qll b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingImplSpecific.qll index b9795bb14d3..e0c416087fd 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingImplSpecific.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingImplSpecific.qll @@ -1,6 +1,8 @@ /** * Provides Go-specific definitions for use in the taint tracking library. */ +overlay[local?] +module; private import codeql.dataflow.TaintTracking private import DataFlowImplSpecific diff --git a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll index af28f7f4020..f9f14874493 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll @@ -1,6 +1,8 @@ /** * Provides Go-specific definitions for use in the taint-tracking library. */ +overlay[local?] +module; private import go private import FlowSummaryImpl as FlowSummaryImpl @@ -11,6 +13,7 @@ private import DataFlowPrivate as DataFlowPrivate * Holds if taint can flow from `src` to `sink` in zero or more * local (intra-procedural) steps. */ +overlay[caller?] pragma[inline] predicate localTaint(DataFlow::Node src, DataFlow::Node sink) { localTaintStep*(src, sink) } @@ -18,6 +21,7 @@ predicate localTaint(DataFlow::Node src, DataFlow::Node sink) { localTaintStep*( * Holds if taint can flow from `src` to `sink` in zero or more * local (intra-procedural) steps. */ +overlay[caller?] pragma[inline] predicate localExprTaint(Expr src, Expr sink) { localTaint(DataFlow::exprNode(src), DataFlow::exprNode(sink)) @@ -418,7 +422,7 @@ predicate functionEnsuresInputIsConstant( forex(DataFlow::Node ret, IR::ReturnInstruction ri | ret = outp.getEntryNode(fd) and ri.getReturnStmt().getAnExpr() = ret.asExpr() and - ret.asExpr() = Builtin::nil().getAReference() + exprRefersToNil(ret.asExpr()) | DataFlow::localFlow(inp.getExitNode(fd), _) and mustPassConstantCaseTestToReach(ri, inp.getExitNode(fd)) diff --git a/go/ql/lib/semmle/go/dependencies/Dependencies.qll b/go/ql/lib/semmle/go/dependencies/Dependencies.qll index d8c8ee52d29..6c9537c72c4 100644 --- a/go/ql/lib/semmle/go/dependencies/Dependencies.qll +++ b/go/ql/lib/semmle/go/dependencies/Dependencies.qll @@ -1,6 +1,8 @@ /** * Provides classes for modeling go.mod dependencies. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dependencies/SemVer.qll b/go/ql/lib/semmle/go/dependencies/SemVer.qll index 88d37563931..290617781ec 100644 --- a/go/ql/lib/semmle/go/dependencies/SemVer.qll +++ b/go/ql/lib/semmle/go/dependencies/SemVer.qll @@ -1,6 +1,8 @@ /** * Provides classes for dealing with semantic versions, for dependency versions. */ +overlay[local?] +module; import semmle.go.dependencies.Dependencies diff --git a/go/ql/lib/semmle/go/frameworks/Afero.qll b/go/ql/lib/semmle/go/frameworks/Afero.qll index c03bf611433..22704a6af8e 100644 --- a/go/ql/lib/semmle/go/frameworks/Afero.qll +++ b/go/ql/lib/semmle/go/frameworks/Afero.qll @@ -2,6 +2,8 @@ * Provides classes for working with sinks and taint propagators * from the `github.com/spf13/afero` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/AwsLambda.qll b/go/ql/lib/semmle/go/frameworks/AwsLambda.qll index 28f21c9101b..f366a877097 100644 --- a/go/ql/lib/semmle/go/frameworks/AwsLambda.qll +++ b/go/ql/lib/semmle/go/frameworks/AwsLambda.qll @@ -2,6 +2,8 @@ * Provides classes for working with remote flow sources, sinks and taint propagators * from the `github.com/aws/aws-lambda-go/lambda` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Beego.qll b/go/ql/lib/semmle/go/frameworks/Beego.qll index 383be8ec42a..5f3f2e986c2 100644 --- a/go/ql/lib/semmle/go/frameworks/Beego.qll +++ b/go/ql/lib/semmle/go/frameworks/Beego.qll @@ -2,6 +2,8 @@ * Provides classes for working with remote flow sources, sinks and taint propagators * from the `github.com/beego/beego` package. */ +overlay[local?] +module; import go import semmle.go.security.Xss diff --git a/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll b/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll index 925b0f19fa3..e1bc5c481bd 100644 --- a/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll +++ b/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll @@ -2,6 +2,8 @@ * Provides classes for working with remote flow sources, sinks and taint propagators * from the `github.com/astaxie/beego/orm` subpackage. */ +overlay[local?] +module; import go private import semmle.go.security.StoredXssCustomizations diff --git a/go/ql/lib/semmle/go/frameworks/Bun.qll b/go/ql/lib/semmle/go/frameworks/Bun.qll index 5be82d2cacc..8637c8f5704 100644 --- a/go/ql/lib/semmle/go/frameworks/Bun.qll +++ b/go/ql/lib/semmle/go/frameworks/Bun.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `Bun` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Couchbase.qll b/go/ql/lib/semmle/go/frameworks/Couchbase.qll index b5bfbcb22a2..d1be1a73205 100644 --- a/go/ql/lib/semmle/go/frameworks/Couchbase.qll +++ b/go/ql/lib/semmle/go/frameworks/Couchbase.qll @@ -1,6 +1,8 @@ /** * Provides models of commonly used functions in the official Couchbase Go SDK library. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll index 154ac82e7a2..7f0e52b449a 100644 --- a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll +++ b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll @@ -1,6 +1,8 @@ /** * Provides classes for modeling cryptographic libraries. */ +overlay[local?] +module; import go import semmle.go.Concepts::Cryptography diff --git a/go/ql/lib/semmle/go/frameworks/Echo.qll b/go/ql/lib/semmle/go/frameworks/Echo.qll index a2a6e7d846a..865d8c3972b 100644 --- a/go/ql/lib/semmle/go/frameworks/Echo.qll +++ b/go/ql/lib/semmle/go/frameworks/Echo.qll @@ -2,6 +2,8 @@ * Provides classes for working with remote flow sources, taint propagators, and HTTP sinks * from the `github.com/labstack/echo` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll b/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll index b1bf4571216..23f3a8c2d4d 100644 --- a/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll +++ b/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with concepts relating to the [github.com/elazarl/goproxy](https://pkg.go.dev/github.com/elazarl/goproxy) package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Email.qll b/go/ql/lib/semmle/go/frameworks/Email.qll index ba4cf8be415..97894806f6f 100644 --- a/go/ql/lib/semmle/go/frameworks/Email.qll +++ b/go/ql/lib/semmle/go/frameworks/Email.qll @@ -1,4 +1,6 @@ /** Provides classes for working with email-related APIs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Encoding.qll b/go/ql/lib/semmle/go/frameworks/Encoding.qll index 201e2c9001d..45f83021a0c 100644 --- a/go/ql/lib/semmle/go/frameworks/Encoding.qll +++ b/go/ql/lib/semmle/go/frameworks/Encoding.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling taint propagation through marshalling and encoding functions. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Fasthttp.qll b/go/ql/lib/semmle/go/frameworks/Fasthttp.qll index 941e6b44945..2dea987ade6 100644 --- a/go/ql/lib/semmle/go/frameworks/Fasthttp.qll +++ b/go/ql/lib/semmle/go/frameworks/Fasthttp.qll @@ -2,6 +2,8 @@ * Provides classes for working with remote flow sources, sinks and taint propagators * from the `github.com/valyala/fasthttp` package. */ +overlay[local?] +module; import go private import semmle.go.security.RequestForgeryCustomizations diff --git a/go/ql/lib/semmle/go/frameworks/Gin.qll b/go/ql/lib/semmle/go/frameworks/Gin.qll index 71ed5d931fa..f6d2bf8ff55 100644 --- a/go/ql/lib/semmle/go/frameworks/Gin.qll +++ b/go/ql/lib/semmle/go/frameworks/Gin.qll @@ -1,6 +1,8 @@ /** * Provides classes for modeling the `github.com/gin-gonic/gin` package. */ +overlay[local?] +module; import go import semmle.go.concepts.HTTP diff --git a/go/ql/lib/semmle/go/frameworks/GinCors.qll b/go/ql/lib/semmle/go/frameworks/GinCors.qll index cc993ea4dee..cd742ac9ba2 100644 --- a/go/ql/lib/semmle/go/frameworks/GinCors.qll +++ b/go/ql/lib/semmle/go/frameworks/GinCors.qll @@ -1,6 +1,8 @@ /** * Provides classes for modeling the `github.com/gin-contrib/cors` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Glog.qll b/go/ql/lib/semmle/go/frameworks/Glog.qll index 146b8a4f814..a9ffc432181 100644 --- a/go/ql/lib/semmle/go/frameworks/Glog.qll +++ b/go/ql/lib/semmle/go/frameworks/Glog.qll @@ -2,6 +2,8 @@ * Provides models of commonly used functions in the `github.com/golang/glog` and `k8s.io/klog` * packages. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/GoJose.qll b/go/ql/lib/semmle/go/frameworks/GoJose.qll index 509e289f586..6ee1feb5ab9 100644 --- a/go/ql/lib/semmle/go/frameworks/GoJose.qll +++ b/go/ql/lib/semmle/go/frameworks/GoJose.qll @@ -2,6 +2,8 @@ * Provides classes for working with the `gopkg.in/square/go-jose` and `github.com/go-jose/go-jose` * packages. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/GoKit.qll b/go/ql/lib/semmle/go/frameworks/GoKit.qll index e4a9e48d207..f56451b1b81 100644 --- a/go/ql/lib/semmle/go/frameworks/GoKit.qll +++ b/go/ql/lib/semmle/go/frameworks/GoKit.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with concepts relating to the [github.com/go-kit/kit](https://pkg.go.dev/github.com/go-kit/kit) package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/GoMicro.qll b/go/ql/lib/semmle/go/frameworks/GoMicro.qll index f01dcde9f1e..723f58899ff 100644 --- a/go/ql/lib/semmle/go/frameworks/GoMicro.qll +++ b/go/ql/lib/semmle/go/frameworks/GoMicro.qll @@ -1,6 +1,8 @@ /** * Provides models of the [Go Micro library](https://github.com/go-micro/go-micro). */ +overlay[local?] +module; import go private import semmle.go.security.RequestForgeryCustomizations diff --git a/go/ql/lib/semmle/go/frameworks/Gorqlite.qll b/go/ql/lib/semmle/go/frameworks/Gorqlite.qll index 65ac5d88bab..434c8148bd7 100644 --- a/go/ql/lib/semmle/go/frameworks/Gorqlite.qll +++ b/go/ql/lib/semmle/go/frameworks/Gorqlite.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `gorqlite` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Gqlgen.qll b/go/ql/lib/semmle/go/frameworks/Gqlgen.qll index 4edaab46b22..bcde5ce9a36 100644 --- a/go/ql/lib/semmle/go/frameworks/Gqlgen.qll +++ b/go/ql/lib/semmle/go/frameworks/Gqlgen.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions and types in the gqlgen packages. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Jwt.qll b/go/ql/lib/semmle/go/frameworks/Jwt.qll index 681ead26834..d139f48ae2b 100644 --- a/go/ql/lib/semmle/go/frameworks/Jwt.qll +++ b/go/ql/lib/semmle/go/frameworks/Jwt.qll @@ -2,6 +2,8 @@ * Provides classes and predicates for working with the `github.com/golang-jwt/jwt` and * `github.com/dgrijalva/jwt-go` packages. */ +overlay[local?] +module; import go private import semmle.go.security.MissingJwtSignatureCheckCustomizations::MissingJwtSignatureCheck diff --git a/go/ql/lib/semmle/go/frameworks/K8sIoApiCoreV1.qll b/go/ql/lib/semmle/go/frameworks/K8sIoApiCoreV1.qll index 6fe789dccc3..ea80d0eba37 100644 --- a/go/ql/lib/semmle/go/frameworks/K8sIoApiCoreV1.qll +++ b/go/ql/lib/semmle/go/frameworks/K8sIoApiCoreV1.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions in the `k8s.io/api/core/v1` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll b/go/ql/lib/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll index 5c7481e5808..945904ba0ae 100644 --- a/go/ql/lib/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll +++ b/go/ql/lib/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions in the `k8s.io/apimachinery/pkg/runtime` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/K8sIoClientGo.qll b/go/ql/lib/semmle/go/frameworks/K8sIoClientGo.qll index c087cc26ff8..f23d069f4c0 100644 --- a/go/ql/lib/semmle/go/frameworks/K8sIoClientGo.qll +++ b/go/ql/lib/semmle/go/frameworks/K8sIoClientGo.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions in the `k8s.io/client-go/kubernetes/typed/core/v1` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Logrus.qll b/go/ql/lib/semmle/go/frameworks/Logrus.qll index 83278a4cd9e..33287462c05 100644 --- a/go/ql/lib/semmle/go/frameworks/Logrus.qll +++ b/go/ql/lib/semmle/go/frameworks/Logrus.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Macaron.qll b/go/ql/lib/semmle/go/frameworks/Macaron.qll index 41e95095aa2..1c088804263 100644 --- a/go/ql/lib/semmle/go/frameworks/Macaron.qll +++ b/go/ql/lib/semmle/go/frameworks/Macaron.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with concepts relating to the Macaron web framework */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Mux.qll b/go/ql/lib/semmle/go/frameworks/Mux.qll index e9bb5968f70..a4790e3c5cd 100644 --- a/go/ql/lib/semmle/go/frameworks/Mux.qll +++ b/go/ql/lib/semmle/go/frameworks/Mux.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with concepts in the Mux HTTP middleware library. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/NoSQL.qll b/go/ql/lib/semmle/go/frameworks/NoSQL.qll index 2772182f4fc..463a3923496 100644 --- a/go/ql/lib/semmle/go/frameworks/NoSQL.qll +++ b/go/ql/lib/semmle/go/frameworks/NoSQL.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with NoSQL-related concepts such as queries. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Protobuf.qll b/go/ql/lib/semmle/go/frameworks/Protobuf.qll index 62443eb46af..246608159e5 100644 --- a/go/ql/lib/semmle/go/frameworks/Protobuf.qll +++ b/go/ql/lib/semmle/go/frameworks/Protobuf.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions and types in the protobuf packages. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Revel.qll b/go/ql/lib/semmle/go/frameworks/Revel.qll index a1eff5e736e..c6250c2f8a5 100644 --- a/go/ql/lib/semmle/go/frameworks/Revel.qll +++ b/go/ql/lib/semmle/go/frameworks/Revel.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with remote flow sources from the `github.com/revel/revel` package. */ +overlay[local?] +module; import go private import semmle.go.security.OpenUrlRedirectCustomizations diff --git a/go/ql/lib/semmle/go/frameworks/RsCors.qll b/go/ql/lib/semmle/go/frameworks/RsCors.qll index 52b4a7fe6d0..7609b27b58a 100644 --- a/go/ql/lib/semmle/go/frameworks/RsCors.qll +++ b/go/ql/lib/semmle/go/frameworks/RsCors.qll @@ -1,4 +1,6 @@ /** Provides classes for modeling the `github.com/rs/cors` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/SQL.qll b/go/ql/lib/semmle/go/frameworks/SQL.qll index c5cf4989d1a..fad4722ad5c 100644 --- a/go/ql/lib/semmle/go/frameworks/SQL.qll +++ b/go/ql/lib/semmle/go/frameworks/SQL.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with SQL-related concepts such as queries. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Spew.qll b/go/ql/lib/semmle/go/frameworks/Spew.qll index f49a4aa4d89..4c8720868b7 100644 --- a/go/ql/lib/semmle/go/frameworks/Spew.qll +++ b/go/ql/lib/semmle/go/frameworks/Spew.qll @@ -1,6 +1,8 @@ /** * Provides models of commonly used functions in the `github.com/davecgh/go-spew/spew` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Squirrel.qll b/go/ql/lib/semmle/go/frameworks/Squirrel.qll index c7d75003cfe..28168c54107 100644 --- a/go/ql/lib/semmle/go/frameworks/Squirrel.qll +++ b/go/ql/lib/semmle/go/frameworks/Squirrel.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `squirrel` ORM package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Stdlib.qll b/go/ql/lib/semmle/go/frameworks/Stdlib.qll index 3b05627168d..4a8a2e8d0ea 100644 --- a/go/ql/lib/semmle/go/frameworks/Stdlib.qll +++ b/go/ql/lib/semmle/go/frameworks/Stdlib.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the standard libraries. */ +overlay[local?] +module; import go import semmle.go.frameworks.stdlib.ArchiveTar diff --git a/go/ql/lib/semmle/go/frameworks/SystemCommandExecutors.qll b/go/ql/lib/semmle/go/frameworks/SystemCommandExecutors.qll index 8abf2bbd368..d1bbbf41d89 100644 --- a/go/ql/lib/semmle/go/frameworks/SystemCommandExecutors.qll +++ b/go/ql/lib/semmle/go/frameworks/SystemCommandExecutors.qll @@ -2,6 +2,8 @@ * Provides concrete classes for data-flow nodes that execute an * operating system command, for instance by spawning a new process. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Testing.qll b/go/ql/lib/semmle/go/frameworks/Testing.qll index c0246c7df50..c6173ac099a 100644 --- a/go/ql/lib/semmle/go/frameworks/Testing.qll +++ b/go/ql/lib/semmle/go/frameworks/Testing.qll @@ -1,4 +1,6 @@ /** Provides classes for working with tests. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Twirp.qll b/go/ql/lib/semmle/go/frameworks/Twirp.qll index 254949ad772..2fcd44da2ff 100644 --- a/go/ql/lib/semmle/go/frameworks/Twirp.qll +++ b/go/ql/lib/semmle/go/frameworks/Twirp.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions and types in the twirp packages. */ +overlay[local?] +module; import go private import semmle.go.security.RequestForgeryCustomizations diff --git a/go/ql/lib/semmle/go/frameworks/WebSocket.qll b/go/ql/lib/semmle/go/frameworks/WebSocket.qll index eb6160214cc..36c6db5c453 100644 --- a/go/ql/lib/semmle/go/frameworks/WebSocket.qll +++ b/go/ql/lib/semmle/go/frameworks/WebSocket.qll @@ -1,4 +1,6 @@ /** Provides classes for working with WebSocket-related APIs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/XNetHtml.qll b/go/ql/lib/semmle/go/frameworks/XNetHtml.qll index 003c0e8570e..4eec0c9b331 100644 --- a/go/ql/lib/semmle/go/frameworks/XNetHtml.qll +++ b/go/ql/lib/semmle/go/frameworks/XNetHtml.qll @@ -6,6 +6,8 @@ * that were already untrusted. We do not yet model adding a child `Node` to a tree then calling `Render` * yielding an untrustworthy string. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/XPath.qll b/go/ql/lib/semmle/go/frameworks/XPath.qll index 0d8dc5d8176..d052a619c35 100644 --- a/go/ql/lib/semmle/go/frameworks/XPath.qll +++ b/go/ql/lib/semmle/go/frameworks/XPath.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with XPath-related concepts such as XPath expressions. */ +overlay[local?] +module; import go import semmle.go.dataflow.ExternalFlow diff --git a/go/ql/lib/semmle/go/frameworks/Yaml.qll b/go/ql/lib/semmle/go/frameworks/Yaml.qll index 22fc4f8c58c..160e5f18c6b 100644 --- a/go/ql/lib/semmle/go/frameworks/Yaml.qll +++ b/go/ql/lib/semmle/go/frameworks/Yaml.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with the [gopkg.in/yaml](https://pkg.go.dev/gopkg.in/yaml.v3) package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Zap.qll b/go/ql/lib/semmle/go/frameworks/Zap.qll index 0928d2b0595..b634d8e9795 100644 --- a/go/ql/lib/semmle/go/frameworks/Zap.qll +++ b/go/ql/lib/semmle/go/frameworks/Zap.qll @@ -1,6 +1,8 @@ /** * Provides models of commonly used functions in the `go.uber.org/zap` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll b/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll index 24d16f86b66..0798f187647 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `archive/tar` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveZip.qll b/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveZip.qll index ed4061700dc..273b8ddff2c 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveZip.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveZip.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `archive/zip` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Bufio.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Bufio.qll index 1ddb7e0889c..e79a5f16a90 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Bufio.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Bufio.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `bufio` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/CompressFlate.qll b/go/ql/lib/semmle/go/frameworks/stdlib/CompressFlate.qll index 5df4ac972c9..1d63d0dda29 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/CompressFlate.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/CompressFlate.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `compress/flate` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/CompressGzip.qll b/go/ql/lib/semmle/go/frameworks/stdlib/CompressGzip.qll index 29b731ec927..695c9ea5df5 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/CompressGzip.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/CompressGzip.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `compress/gzip` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/CompressLzw.qll b/go/ql/lib/semmle/go/frameworks/stdlib/CompressLzw.qll index 4d8e2d1de93..319c1d4dd93 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/CompressLzw.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/CompressLzw.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `compress/lzw` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/CompressZlib.qll b/go/ql/lib/semmle/go/frameworks/stdlib/CompressZlib.qll index be8d7fa69a0..26a2872ae1c 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/CompressZlib.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/CompressZlib.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `compress/zlib` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/CryptoTls.qll b/go/ql/lib/semmle/go/frameworks/stdlib/CryptoTls.qll index 2bd85457cf8..a370f12c24d 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/CryptoTls.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/CryptoTls.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `crypto/tls` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll b/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll index f4132688796..1969724b486 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `database/sql` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingAsn1.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingAsn1.qll index 68d9655b11c..7a860608a90 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingAsn1.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingAsn1.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/asn1` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingCsv.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingCsv.qll index 7606cdc16bd..283eeebacb6 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingCsv.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingCsv.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/csv` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingGob.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingGob.qll index ada9f167f8d..01db1ec539a 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingGob.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingGob.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/gob` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingJson.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingJson.qll index f38db392bd0..bf6e25ff9f1 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingJson.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingJson.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/json` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingPem.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingPem.qll index cb2383d428a..4ef997c7815 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingPem.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingPem.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/pem` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingXml.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingXml.qll index b36f9007084..b5206754529 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingXml.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingXml.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/xml` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll index 133a69795b8..d20d0c1837e 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `errors` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll index 6adbd542e9b..bc58441ada9 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `fmt` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Html.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Html.qll index 82e5f13e130..c26d329f625 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Html.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Html.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `html` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/HtmlTemplate.qll b/go/ql/lib/semmle/go/frameworks/stdlib/HtmlTemplate.qll index f61482c35d7..8d343bfa4fe 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/HtmlTemplate.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/HtmlTemplate.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `html/template` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Io.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Io.qll index f44ca36ff85..41597e40f02 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Io.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Io.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `io` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/IoFs.qll b/go/ql/lib/semmle/go/frameworks/stdlib/IoFs.qll index de7fafc514f..b071e56cbb5 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/IoFs.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/IoFs.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the 'io/fs' package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll index ca74160bf0d..a5ebca68be5 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `log` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/MimeMultipart.qll b/go/ql/lib/semmle/go/frameworks/stdlib/MimeMultipart.qll index ad60672e35e..d8c193d7f3e 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/MimeMultipart.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/MimeMultipart.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `mime/multipart` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/MimeQuotedprintable.qll b/go/ql/lib/semmle/go/frameworks/stdlib/MimeQuotedprintable.qll index 0cf54c107a7..64b3d4c1755 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/MimeQuotedprintable.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/MimeQuotedprintable.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `mime/quotedprintable` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Net.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Net.qll index 5b66e523bad..9d3f4abf6bd 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Net.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Net.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `net` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll index a2aab2517d7..9bafe9721b7 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `net/http` package. */ +overlay[local?] +module; import go private import semmle.go.dataflow.internal.DataFlowPrivate diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttpHttputil.qll b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttpHttputil.qll index f914626c770..465181bb39f 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttpHttputil.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttpHttputil.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `net/http/httputil` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/NetTextproto.qll b/go/ql/lib/semmle/go/frameworks/stdlib/NetTextproto.qll index 9e19e719ce5..b1d314fdfd1 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/NetTextproto.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/NetTextproto.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `net/textproto` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll index 72ea4cc6c57..0a633de08c8 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `os` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Path.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Path.qll index 98215ecd00a..0bdf0b67ff0 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Path.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Path.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `path` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/PathFilepath.qll b/go/ql/lib/semmle/go/frameworks/stdlib/PathFilepath.qll index 379c141fb2a..43deb8e1e7e 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/PathFilepath.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/PathFilepath.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `path/filepath` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Reflect.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Reflect.qll index 62c09ef0c5e..9a4a74d70d5 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Reflect.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Reflect.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `reflect` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Regexp.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Regexp.qll index 17cc0249908..6a28cd1709f 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Regexp.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Regexp.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `regexp` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Strconv.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Strconv.qll index 0f3d2f95cc7..7048ddcbe0d 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Strconv.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Strconv.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `strconv` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Strings.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Strings.qll index 96b07f5de34..2f514bf28f4 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Strings.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Strings.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `strings` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Syscall.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Syscall.qll index b93a991e8e3..cb74560809f 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Syscall.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Syscall.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `syscall` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/TextTabwriter.qll b/go/ql/lib/semmle/go/frameworks/stdlib/TextTabwriter.qll index 964afecb4e6..f0e78817c2d 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/TextTabwriter.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/TextTabwriter.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `text/tabwriter` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/TextTemplate.qll b/go/ql/lib/semmle/go/frameworks/stdlib/TextTemplate.qll index c5a67f388f4..31d7f94ec57 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/TextTemplate.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/TextTemplate.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `text/template` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll index d14598e6f79..307686feac6 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `unsafe` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll b/go/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll index 1d185440772..3bdc948842c 100644 --- a/go/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll +++ b/go/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import go as G private import codeql.util.test.InlineExpectationsTest diff --git a/go/ql/src/RedundantCode/UnreachableStatement.ql b/go/ql/src/RedundantCode/UnreachableStatement.ql index c177705a86f..12b035049e9 100644 --- a/go/ql/src/RedundantCode/UnreachableStatement.ql +++ b/go/ql/src/RedundantCode/UnreachableStatement.ql @@ -26,7 +26,7 @@ ControlFlow::Node nonGuardPredecessor(ControlFlow::Node nd) { * Matches if `retval` is a constant or a struct composed wholly of constants. */ predicate isAllowedReturnValue(Expr retval) { - retval = Builtin::nil().getAReference() + exprRefersToNil(retval) or retval = Builtin::true_().getAReference() or diff --git a/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql b/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql index 15373ee85ed..f556630965c 100644 --- a/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql +++ b/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql @@ -5,7 +5,7 @@ * scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id go/html-template-escaping-bypass-xss * @tags security diff --git a/go/ql/src/Security/CWE-079/ReflectedXss.ql b/go/ql/src/Security/CWE-079/ReflectedXss.ql index 0fca12ac285..ebabb69f0a4 100644 --- a/go/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/go/ql/src/Security/CWE-079/ReflectedXss.ql @@ -4,7 +4,7 @@ * a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id go/reflected-xss * @tags security diff --git a/go/ql/src/Security/CWE-079/StoredXss.ql b/go/ql/src/Security/CWE-079/StoredXss.ql index 83628b31042..dcae0a5f9c1 100644 --- a/go/ql/src/Security/CWE-079/StoredXss.ql +++ b/go/ql/src/Security/CWE-079/StoredXss.ql @@ -4,7 +4,7 @@ * a stored cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision low * @id go/stored-xss * @tags security diff --git a/go/ql/src/Security/CWE-117/LogInjection.ql b/go/ql/src/Security/CWE-117/LogInjection.ql index 5b6586c8e4e..08febfd842e 100644 --- a/go/ql/src/Security/CWE-117/LogInjection.ql +++ b/go/ql/src/Security/CWE-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @security-severity 7.8 + * @security-severity 6.1 * @precision medium * @id go/log-injection * @tags security diff --git a/go/ql/src/Security/CWE-327/examples/Crypto.go b/go/ql/src/Security/CWE-327/examples/Crypto.go index b3f71f0772b..ec34c0c6cf5 100644 --- a/go/ql/src/Security/CWE-327/examples/Crypto.go +++ b/go/ql/src/Security/CWE-327/examples/Crypto.go @@ -13,7 +13,7 @@ func EncryptMessageWeak(key []byte, message []byte) (dst []byte) { } func EncryptMessageStrong(key []byte, message []byte) (dst []byte) { - // GOOD, AES is a weak crypto algorithm + // GOOD, AES is a strong crypto algorithm block, _ := aes.NewCipher(key) block.Encrypt(dst, message) return diff --git a/go/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/go/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..45320bcd719 --- /dev/null +++ b/go/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `go/log-injection` has been reduced from 7.8 (high) to 6.1 (medium). +* The `@security-severity` metadata of `go/html-template-escaping-bypass-xss`, `go/reflected-xss` and `go/stored-xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/go/ql/src/experimental/CWE-203/Timing.ql b/go/ql/src/experimental/CWE-203/Timing.ql index e488adf2f97..30ce6952e06 100644 --- a/go/ql/src/experimental/CWE-203/Timing.ql +++ b/go/ql/src/experimental/CWE-203/Timing.ql @@ -36,7 +36,7 @@ private class SensitiveStringCompareSink extends Sink { not op1 = nonSensitiveOperand and not ( // Comparisons with `nil` should be excluded. - nonSensitiveOperand = Builtin::nil().getAReference() + exprRefersToNil(nonSensitiveOperand) or // Comparisons with empty string should also be excluded. nonSensitiveOperand.getStringValue().length() = 0 @@ -60,7 +60,7 @@ private class SensitiveCompareSink extends Sink { not op1 = op2 and not ( // Comparisons with `nil` should be excluded. - op2 = Builtin::nil().getAReference() + exprRefersToNil(op2) or // Comparisons with empty string should also be excluded. op2.getStringValue().length() = 0 @@ -85,7 +85,7 @@ private class SensitiveStringSink extends Sink { not op1 = op2 and not ( // Comparisons with `nil` should be excluded. - op2 = Builtin::nil().getAReference() + exprRefersToNil(op2) or // Comparisons with empty string should also be excluded. op2.getStringValue().length() = 0 diff --git a/go/ql/src/filters/ClassifyFiles.ql b/go/ql/src/filters/ClassifyFiles.ql index f5ac1258375..8e353740c1a 100644 --- a/go/ql/src/filters/ClassifyFiles.ql +++ b/go/ql/src/filters/ClassifyFiles.ql @@ -1,6 +1,6 @@ /** * @name Classify files - * @description This query produces a list of all files in a snapshot that are classified as + * @description This query produces a list of all files in a database that are classified as * generated code, test code or vendored-in library code. * @kind file-classifier * @id go/file-classifier diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.ql b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.ql index 4ca15c10ac5..bbcaa16f28b 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.ql +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.ql @@ -5,6 +5,7 @@ import go import semmle.go.PrintAst +overlay[local] class Cfg extends PrintAstConfiguration { override predicate shouldPrintFunction(FuncDecl func) { any() } diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstNestedFunction.ql b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstNestedFunction.ql index eaddceacaa3..b04be6edfac 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstNestedFunction.ql +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstNestedFunction.ql @@ -5,6 +5,7 @@ import go import semmle.go.PrintAst +overlay[local] class Cfg extends PrintAstConfiguration { override predicate shouldPrintFunction(FuncDecl func) { func.getName() = "hasNested" } diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFile.ql b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFile.ql index 83d27b9cf26..60cda4f5045 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFile.ql +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFile.ql @@ -5,6 +5,7 @@ import go import semmle.go.PrintAst +overlay[local] class Cfg extends PrintAstConfiguration { override predicate shouldPrintFunction(FuncDecl func) { any() } diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.ql b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.ql index 382fc397755..5b3501edc6c 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.ql +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.ql @@ -5,6 +5,7 @@ import go import semmle.go.PrintAst +overlay[local] class Cfg extends PrintAstConfiguration { override predicate shouldPrintFunction(FuncDecl func) { func.getName() = "g" } diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.ql index 181c55b29df..2468a57cac0 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.ql +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.ql @@ -34,6 +34,7 @@ module FlowTest implements TestSig { } } +overlay[local] class MyStep extends DataFlow::FunctionModel, Method { MyStep() { this.hasQualifiedName("github.com/nonexistent/test", "I1", "Step") } diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.ql index e82a6cb4da1..788c8c028d2 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.ql +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.ql @@ -44,6 +44,7 @@ module FlowTest implements TestSig { } } +overlay[local] class MyStep extends DataFlow::FunctionModel, Method { MyStep() { this.hasQualifiedName("github.com/nonexistent/test", "P1", "Step") } diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.ql index c4124dcd10e..127fb0012a3 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.ql +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.ql @@ -44,6 +44,7 @@ module FlowTest implements TestSig { } } +overlay[local] class MyStep extends DataFlow::FunctionModel, Method { MyStep() { this.hasQualifiedName("github.com/nonexistent/test", "S1", "Step") } diff --git a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql index 78e21d534e0..bbe5618b568 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql +++ b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql @@ -4,6 +4,7 @@ import ModelValidation import utils.test.InlineFlowTest import DefaultFlowTest +overlay[local] class SummaryModelTest extends DataFlow::FunctionModel { FunctionInput inp; FunctionOutput outp; diff --git a/java/ql/src/Security/CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql b/java/ql/src/Security/CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql index 4368b537ab7..3b4abcaa7f6 100644 --- a/java/ql/src/Security/CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql +++ b/java/ql/src/Security/CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql @@ -4,7 +4,7 @@ * @description Exposing a Java object in a WebView with a JavaScript interface can lead to malicious JavaScript controlling the application. * @kind problem * @problem.severity warning - * @security-severity 6.1 + * @security-severity 7.8 * @precision medium * @tags security * external/cwe/cwe-079 diff --git a/java/ql/src/Security/CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql b/java/ql/src/Security/CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql index 561b2af8de0..3ea2b207c04 100644 --- a/java/ql/src/Security/CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql +++ b/java/ql/src/Security/CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql @@ -4,7 +4,7 @@ * @kind problem * @id java/android/websettings-javascript-enabled * @problem.severity warning - * @security-severity 6.1 + * @security-severity 7.8 * @precision medium * @tags security * external/cwe/cwe-079 diff --git a/java/ql/src/Security/CWE/CWE-079/XSS.ql b/java/ql/src/Security/CWE/CWE-079/XSS.ql index 9ae92a7e362..f1261ebff74 100644 --- a/java/ql/src/Security/CWE/CWE-079/XSS.ql +++ b/java/ql/src/Security/CWE/CWE-079/XSS.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id java/xss * @tags security diff --git a/java/ql/src/Security/CWE/CWE-117/LogInjection.ql b/java/ql/src/Security/CWE/CWE-117/LogInjection.ql index dd4ffb6a10a..f3efb578f76 100644 --- a/java/ql/src/Security/CWE/CWE-117/LogInjection.ql +++ b/java/ql/src/Security/CWE/CWE-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by malicious users. * @kind path-problem * @problem.severity error - * @security-severity 7.8 + * @security-severity 6.1 * @precision medium * @id java/log-injection * @tags security diff --git a/java/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/java/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..fa1288af16e --- /dev/null +++ b/java/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `java/log-injection` has been reduced from 7.8 (high) to 6.1 (medium). +* The `@security-severity` metadata of `java/android/webview-addjavascriptinterface`, `java/android/websettings-javascript-enabled` and `java/xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java index 9cf5c3b295c..70d6677855d 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java @@ -28,13 +28,13 @@ import com.semmle.util.trap.TrapWriter.Label; */ public class FileExtractor { /** - * Pattern to use on the shebang line of a script to identify whether it is a Node.js script. + * Pattern to use on the shebang line of a script to identify whether it is a JavaScript script. * - *

There are many different ways of invoking the Node.js interpreter (directly, through {@code + *

There are many different ways of invoking a JavaScript interpreter (directly, through {@code * env}, with or without flags, with or without modified environment, etc.), so we simply look for - * the word {@code "node"} or {@code "nodejs"}. + * the word {@code "node"}, {@code "nodejs"}, {@code "bun"}, or {@code "tsx"}. */ - private static final Pattern NODE_INVOCATION = Pattern.compile("\\bnode(js)?\\b"); + private static final Pattern JS_INVOCATION = Pattern.compile("\\b(node(js)?|bun|tsx)\\b"); /** A pattern that matches strings starting with `{ "...":`, suggesting JSON data. */ public static final Pattern JSON_OBJECT_START = @@ -157,7 +157,7 @@ public class FileExtractor { // do a cheap check first if (firstLine != null && firstLine.startsWith("#!")) { // now do the slightly more expensive one - return NODE_INVOCATION.matcher(firstLine).find(); + return JS_INVOCATION.matcher(firstLine).find(); } } catch (IOException e) { Exceptions.ignore(e, "We simply skip this file."); @@ -302,7 +302,7 @@ public class FileExtractor { int lengthOfText = endOfLine - startOfText; String text = new String(bytes, startOfText, lengthOfText, StandardCharsets.UTF_8); // Check if the shebang is a recognized JavaScript intepreter. - return !NODE_INVOCATION.matcher(text).find(); + return !JS_INVOCATION.matcher(text).find(); } @Override diff --git a/javascript/ql/lib/change-notes/2026-03-11-browser-source-kinds.md b/javascript/ql/lib/change-notes/2026-03-11-browser-source-kinds.md new file mode 100644 index 00000000000..71d06f3d1b6 --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-03-11-browser-source-kinds.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added support for browser-specific source kinds (`browser`, `browser-url-query`, `browser-url-fragment`, `browser-url-path`, `browser-url`, `browser-window-name`, `browser-message-event`) that can be used in data extensions to model sources in browser environments. diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll index e4adff2a9ac..391f2ea1b33 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll @@ -35,6 +35,18 @@ private class RemoteFlowSourceFromMaD extends RemoteFlowSource { override string getSourceType() { result = "Remote flow" } } +private class ClientSideRemoteFlowSourceFromMaD extends ClientSideRemoteFlowSource { + private ClientSideRemoteFlowKind kind; + + ClientSideRemoteFlowSourceFromMaD() { ModelOutput::sourceNode(this, kind) } + + override ClientSideRemoteFlowKind getKind() { result = kind } + + override string getSourceType() { + result = "Source node (" + this.getThreatModel() + ") [from data-extension]" + } +} + /** * A threat-model flow source originating from a data extension. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll index 9f4975e605a..8791382180a 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll @@ -43,53 +43,65 @@ import Cached /** * A type of remote flow source that is specific to the browser environment. + * + * The underlying string also corresponds to a source kind. */ class ClientSideRemoteFlowKind extends string { ClientSideRemoteFlowKind() { - this = ["query", "fragment", "path", "url", "name", "message-event"] + this = + [ + "browser", "browser-url-query", "browser-url-fragment", "browser-url-path", "browser-url", + "browser-window-name", "browser-message-event" + ] } /** - * Holds if this is the `query` kind, describing sources derived from the query parameters of the browser URL, + * Holds if this is the `browser` kind, indicating a remote source in a browser context, that does not fit into one + * of the more specific kinds. + */ + predicate isGenericBrowserSourceKind() { this = "browser" } + + /** + * Holds if this is the `browser-url-query` kind, describing sources derived from the query parameters of the browser URL, * such as `location.search`. */ - predicate isQuery() { this = "query" } + predicate isQuery() { this = "browser-url-query" } /** - * Holds if this is the `frgament` kind, describing sources derived from the fragment part of the browser URL, + * Holds if this is the `browser-url-fragment` kind, describing sources derived from the fragment part of the browser URL, * such as `location.hash`. */ - predicate isFragment() { this = "fragment" } + predicate isFragment() { this = "browser-url-fragment" } /** - * Holds if this is the `path` kind, describing sources derived from the pathname of the browser URL, + * Holds if this is the `browser-url-path` kind, describing sources derived from the pathname of the browser URL, * such as `location.pathname`. */ - predicate isPath() { this = "path" } + predicate isPath() { this = "browser-url-path" } /** - * Holds if this is the `url` kind, describing sources derived from the browser URL, + * Holds if this is the `browser-url` kind, describing sources derived from the browser URL, * where the untrusted part of the URL is prefixed by trusted data, such as the scheme and hostname. */ - predicate isUrl() { this = "url" } + predicate isUrl() { this = "browser-url" } - /** Holds if this is the `query` or `fragment` kind. */ + /** Holds if this is the `browser-url-query` or `browser-url-fragment` kind. */ predicate isQueryOrFragment() { this.isQuery() or this.isFragment() } - /** Holds if this is the `path`, `query`, or `fragment` kind. */ + /** Holds if this is the `browser-url-path`, `browser-url-query`, or `browser-url-fragment` kind. */ predicate isPathOrQueryOrFragment() { this.isPath() or this.isQuery() or this.isFragment() } - /** Holds if this is the `path` or `url` kind. */ + /** Holds if this is the `browser-url-path` or `browser-url` kind. */ predicate isPathOrUrl() { this.isPath() or this.isUrl() } - /** Holds if this is the `name` kind, describing sources derived from the window name, such as `window.name`. */ - predicate isWindowName() { this = "name" } + /** Holds if this is the `browser-window-name` kind, describing sources derived from the window name, such as `window.name`. */ + predicate isWindowName() { this = "browser-window-name" } /** - * Holds if this is the `message-event` kind, describing sources derived from cross-window message passing, + * Holds if this is the `browser-message-event` kind, describing sources derived from cross-window message passing, * such as `event` in `window.onmessage = event => {...}`. */ - predicate isMessageEvent() { this = "message-event" } + predicate isMessageEvent() { this = "browser-message-event" } } /** diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.expected b/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.expected new file mode 100644 index 00000000000..3f4d018029a --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.expected @@ -0,0 +1,4 @@ +| shebang_bun.ts | +| shebang_node.ts | +| shebang_tsx.ts | +| tsconfig.json | diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.ql b/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.ql new file mode 100644 index 00000000000..1b3590b82d0 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.ql @@ -0,0 +1,4 @@ +import javascript + +from File f +select f.getRelativePath() diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_bun.ts b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_bun.ts new file mode 100644 index 00000000000..417e04ff16a --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_bun.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env bun +const x: number = 1; diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_node.ts b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_node.ts new file mode 100644 index 00000000000..10b11969aa5 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_node.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env node +const x: number = 1; diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_tsx.ts b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_tsx.ts new file mode 100644 index 00000000000..31331240ced --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_tsx.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env tsx +const x: number = 1; diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/tsconfig.json b/javascript/ql/test/library-tests/TypeScript/Shebangs/tsconfig.json new file mode 100644 index 00000000000..82194fc7ab0 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["."] +} diff --git a/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.expected b/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.expected index 1d6b8781db7..aed2cabe358 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.expected +++ b/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.expected @@ -3,6 +3,7 @@ | clientSide.js:14:5:14:64 | request ... search) | clientSide.js:14:42:14:63 | window. ... .search | clientSide.js:14:13:14:63 | 'https: ... .search | The $@ of this request depends on a $@. | clientSide.js:14:13:14:63 | 'https: ... .search | URL | clientSide.js:14:42:14:63 | window. ... .search | user-provided value | | clientSide.js:17:5:17:58 | request ... '/id') | clientSide.js:16:22:16:41 | window.location.hash | clientSide.js:17:13:17:57 | 'https: ... + '/id' | The $@ of this request depends on a $@. | clientSide.js:17:13:17:57 | 'https: ... + '/id' | URL | clientSide.js:16:22:16:41 | window.location.hash | user-provided value | | clientSide.js:21:5:21:54 | request ... '/id') | clientSide.js:20:18:20:28 | window.name | clientSide.js:21:13:21:53 | 'https: ... + '/id' | The $@ of this request depends on a $@. | clientSide.js:21:13:21:53 | 'https: ... + '/id' | URL | clientSide.js:20:18:20:28 | window.name | user-provided value | +| clientSide.js:27:5:27:19 | request(custom) | clientSide.js:26:20:26:56 | require ... ource() | clientSide.js:27:13:27:18 | custom | The $@ of this request depends on a $@. | clientSide.js:27:13:27:18 | custom | URL | clientSide.js:26:20:26:56 | require ... ource() | user-provided value | edges | clientSide.js:11:11:11:15 | query | clientSide.js:12:42:12:46 | query | provenance | | | clientSide.js:11:19:11:40 | window. ... .search | clientSide.js:11:19:11:53 | window. ... ring(1) | provenance | | @@ -16,6 +17,8 @@ edges | clientSide.js:20:11:20:14 | name | clientSide.js:21:42:21:45 | name | provenance | | | clientSide.js:20:18:20:28 | window.name | clientSide.js:20:11:20:14 | name | provenance | | | clientSide.js:21:42:21:45 | name | clientSide.js:21:13:21:53 | 'https: ... + '/id' | provenance | | +| clientSide.js:26:11:26:16 | custom | clientSide.js:27:13:27:18 | custom | provenance | | +| clientSide.js:26:20:26:56 | require ... ource() | clientSide.js:26:11:26:16 | custom | provenance | | nodes | clientSide.js:11:11:11:15 | query | semmle.label | query | | clientSide.js:11:19:11:40 | window. ... .search | semmle.label | window. ... .search | @@ -33,4 +36,7 @@ nodes | clientSide.js:20:18:20:28 | window.name | semmle.label | window.name | | clientSide.js:21:13:21:53 | 'https: ... + '/id' | semmle.label | 'https: ... + '/id' | | clientSide.js:21:42:21:45 | name | semmle.label | name | +| clientSide.js:26:11:26:16 | custom | semmle.label | custom | +| clientSide.js:26:20:26:56 | require ... ource() | semmle.label | require ... ource() | +| clientSide.js:27:13:27:18 | custom | semmle.label | custom | subpaths diff --git a/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.ext.yml b/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.ext.yml new file mode 100644 index 00000000000..950186d58df --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.ext.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/javascript-all + extensible: sourceModel + data: + - ['testlib', 'Member[getBrowserSource].ReturnValue', 'browser-url-query'] + - ['testlib', 'Member[getServerSource].ReturnValue', 'remote'] diff --git a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected index 1818e116d82..79383f58521 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected +++ b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected @@ -39,6 +39,7 @@ | serverSide.js:143:5:143:26 | axios.g ... t.href) | serverSide.js:139:19:139:31 | req.query.url | serverSide.js:143:15:143:25 | target.href | The $@ of this request depends on a $@. | serverSide.js:143:15:143:25 | target.href | URL | serverSide.js:139:19:139:31 | req.query.url | user-provided value | | serverSide.js:145:5:145:25 | axios.g ... dedUrl) | serverSide.js:139:19:139:31 | req.query.url | serverSide.js:145:15:145:24 | encodedUrl | The $@ of this request depends on a $@. | serverSide.js:145:15:145:24 | encodedUrl | URL | serverSide.js:139:19:139:31 | req.query.url | user-provided value | | serverSide.js:147:5:147:25 | axios.g ... pedUrl) | serverSide.js:139:19:139:31 | req.query.url | serverSide.js:147:15:147:24 | escapedUrl | The $@ of this request depends on a $@. | serverSide.js:147:15:147:24 | escapedUrl | URL | serverSide.js:139:19:139:31 | req.query.url | user-provided value | +| serverSide.js:151:1:151:15 | request(custom) | serverSide.js:150:16:150:51 | require ... ource() | serverSide.js:151:9:151:14 | custom | The $@ of this request depends on a $@. | serverSide.js:151:9:151:14 | custom | URL | serverSide.js:150:16:150:51 | require ... ource() | user-provided value | edges | Request/app/api/proxy/route2.serverSide.ts:4:9:4:15 | { url } | Request/app/api/proxy/route2.serverSide.ts:4:11:4:13 | url | provenance | | | Request/app/api/proxy/route2.serverSide.ts:4:11:4:13 | url | Request/app/api/proxy/route2.serverSide.ts:5:27:5:29 | url | provenance | | @@ -144,6 +145,8 @@ edges | serverSide.js:146:11:146:20 | escapedUrl | serverSide.js:147:15:147:24 | escapedUrl | provenance | | | serverSide.js:146:24:146:36 | escape(input) | serverSide.js:146:11:146:20 | escapedUrl | provenance | | | serverSide.js:146:31:146:35 | input | serverSide.js:146:24:146:36 | escape(input) | provenance | | +| serverSide.js:150:7:150:12 | custom | serverSide.js:151:9:151:14 | custom | provenance | | +| serverSide.js:150:16:150:51 | require ... ource() | serverSide.js:150:7:150:12 | custom | provenance | | nodes | Request/app/api/proxy/route2.serverSide.ts:4:9:4:15 | { url } | semmle.label | { url } | | Request/app/api/proxy/route2.serverSide.ts:4:11:4:13 | url | semmle.label | url | @@ -271,4 +274,7 @@ nodes | serverSide.js:146:24:146:36 | escape(input) | semmle.label | escape(input) | | serverSide.js:146:31:146:35 | input | semmle.label | input | | serverSide.js:147:15:147:24 | escapedUrl | semmle.label | escapedUrl | +| serverSide.js:150:7:150:12 | custom | semmle.label | custom | +| serverSide.js:150:16:150:51 | require ... ource() | semmle.label | require ... ource() | +| serverSide.js:151:9:151:14 | custom | semmle.label | custom | subpaths diff --git a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.ext.yml b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.ext.yml new file mode 100644 index 00000000000..950186d58df --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.ext.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/javascript-all + extensible: sourceModel + data: + - ['testlib', 'Member[getBrowserSource].ReturnValue', 'browser-url-query'] + - ['testlib', 'Member[getServerSource].ReturnValue', 'remote'] diff --git a/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js b/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js index aa4174cd9ab..a8e29602f1f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js +++ b/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js @@ -22,4 +22,7 @@ export function MyComponent() { request('https://example.com/api?q=' + name); request(window.location.href + '?q=123'); + + const custom = require('testlib').getBrowserSource(); // $ Source[js/client-side-request-forgery] + request(custom); // $ Alert[js/client-side-request-forgery] } diff --git a/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js b/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js index 38f2bb72ac3..c359312738b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js +++ b/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js @@ -146,3 +146,6 @@ var server2 = http.createServer(function (req, res) { const escapedUrl = escape(input); axios.get(escapedUrl); // $ Alert[js/request-forgery] }); + +const custom = require('testlib').getServerSource(); // $ Source[js/request-forgery] +request(custom); // $ Alert[js/request-forgery] diff --git a/misc/bazel/registry/modules/rules_kotlin/2.2.2-codeql.1/MODULE.bazel b/misc/bazel/registry/modules/rules_kotlin/2.2.2-codeql.1/MODULE.bazel index 162e914f894..ec37914a8f7 100644 --- a/misc/bazel/registry/modules/rules_kotlin/2.2.2-codeql.1/MODULE.bazel +++ b/misc/bazel/registry/modules/rules_kotlin/2.2.2-codeql.1/MODULE.bazel @@ -8,7 +8,7 @@ module( bazel_dep(name = "platforms", version = "0.0.11") bazel_dep(name = "bazel_skylib", version = "1.7.1") bazel_dep(name = "rules_java", version = "8.9.0") -bazel_dep(name = "rules_android", version = "0.7.1") +bazel_dep(name = "rules_android", version = "0.6.4") bazel_dep(name = "bazel_features", version = "1.25.0") bazel_dep(name = "protobuf", version = "29.0", repo_name = "com_google_protobuf") bazel_dep(name = "rules_proto", version = "6.0.2", repo_name = "rules_proto") diff --git a/python/ql/lib/change-notes/2026-03-11-fix-unresolved-relative-imports.md b/python/ql/lib/change-notes/2026-03-11-fix-unresolved-relative-imports.md new file mode 100644 index 00000000000..15290fb3d66 --- /dev/null +++ b/python/ql/lib/change-notes/2026-03-11-fix-unresolved-relative-imports.md @@ -0,0 +1,5 @@ +--- +category: fix +--- + +- Fixed the resolution of relative imports such as `from . import helper` inside namespace packages (directories without an `__init__.py` file), which previously did not work correctly, leading to missing flow. diff --git a/python/ql/lib/semmle/python/Import.qll b/python/ql/lib/semmle/python/Import.qll index e8a7facccad..2f7fae95539 100644 --- a/python/ql/lib/semmle/python/Import.qll +++ b/python/ql/lib/semmle/python/Import.qll @@ -17,6 +17,10 @@ private predicate valid_module_name(string name) { exists(Module m | m.getName() = name) or exists(Builtin cmod | cmod.getClass() = Builtin::special("ModuleType") and cmod.getName() = name) + or + // Namespace packages may not have a corresponding Module entity, + // but their names are still valid for the purpose of import resolution. + name = moduleNameFromFile(any(Folder f)) } /** An artificial expression representing an import */ diff --git a/python/ql/src/Classes/CallsToInitDel/MethodCallOrder.qll b/python/ql/src/Classes/CallsToInitDel/MethodCallOrder.qll index 635953168d7..232c29e7dee 100644 --- a/python/ql/src/Classes/CallsToInitDel/MethodCallOrder.qll +++ b/python/ql/src/Classes/CallsToInitDel/MethodCallOrder.qll @@ -152,11 +152,7 @@ predicate missingCallToSuperclassMethod(Class base, Function shouldCall, string */ predicate missingCallToSuperclassMethodRestricted(Class base, Function shouldCall, string name) { missingCallToSuperclassMethod(base, shouldCall, name) and - not exists(Class superBase | - // Alert only on the highest base class that has the issue - superBase = getADirectSuperclass+(base) and - missingCallToSuperclassMethod(superBase, shouldCall, name) - ) and + not superclassAlsoMissesCall(base, shouldCall, name) and not exists(Function subShouldCall | // Mention in the alert only the lowest method we're missing the call to subShouldCall.getScope() = getADirectSubclass+(shouldCall.getScope()) and @@ -164,6 +160,15 @@ predicate missingCallToSuperclassMethodRestricted(Class base, Function shouldCal ) } +/** + * Holds if a strict superclass of `base` is also missing a call to `shouldCall` named `name`, + * indicating that `base` is not the highest class in the hierarchy with this issue. + */ +pragma[nomagic] +private predicate superclassAlsoMissesCall(Class base, Function shouldCall, string name) { + missingCallToSuperclassMethod(getADirectSuperclass+(base), shouldCall, name) +} + /** * If `base` contains a `super()` call, gets a method in the inheritance hierarchy of `name` in the MRO of `base` * that does not contain a `super()` call, but would call `shouldCall` if it did, which does not otherwise get called diff --git a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql index 97bbb72edec..fd03ba433a1 100644 --- a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql +++ b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql @@ -4,7 +4,7 @@ * cause a cross-site scripting vulnerability. * @kind problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision medium * @id py/jinja2/autoescape-false * @tags security diff --git a/python/ql/src/Security/CWE-079/ReflectedXss.ql b/python/ql/src/Security/CWE-079/ReflectedXss.ql index 11ebad00e37..286dbece126 100644 --- a/python/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/python/ql/src/Security/CWE-079/ReflectedXss.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @sub-severity high * @precision high * @id py/reflective-xss diff --git a/python/ql/src/Security/CWE-117/LogInjection.ql b/python/ql/src/Security/CWE-117/LogInjection.ql index f1b72faaccb..64b29e142e0 100644 --- a/python/ql/src/Security/CWE-117/LogInjection.ql +++ b/python/ql/src/Security/CWE-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @security-severity 7.8 + * @security-severity 6.1 * @precision medium * @id py/log-injection * @tags security diff --git a/python/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/python/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..4278d0171e3 --- /dev/null +++ b/python/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `py/log-injection` has been reduced from 7.8 (high) to 6.1 (medium). +* The `@security-severity` metadata of `py/jinja2/autoescape-false` and `py/reflective-xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/caller.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/caller.py new file mode 100644 index 00000000000..f30065eec99 --- /dev/null +++ b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/caller.py @@ -0,0 +1,5 @@ +from . import helper + +def use_relative(): + tainted = source() + helper.process(tainted) diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py new file mode 100644 index 00000000000..f75e9957738 --- /dev/null +++ b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py @@ -0,0 +1,5 @@ +def process(value): + sink(value) #$ flow=source + +def process2(value): + sink(value) #$ flow=source diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/__init__.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/caller2.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/caller2.py new file mode 100644 index 00000000000..3afab28cd42 --- /dev/null +++ b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/caller2.py @@ -0,0 +1,5 @@ +from .. import helper + +def use_multi_level_relative(): + tainted = source() + helper.process2(tainted) diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/test.expected b/python/ql/test/experimental/import-resolution-namespace-relative/test.expected new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/python/ql/test/experimental/import-resolution-namespace-relative/test.expected @@ -0,0 +1 @@ + diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/test.ql b/python/ql/test/experimental/import-resolution-namespace-relative/test.ql new file mode 100644 index 00000000000..4f5f09a527d --- /dev/null +++ b/python/ql/test/experimental/import-resolution-namespace-relative/test.ql @@ -0,0 +1,35 @@ +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking +import utils.test.InlineExpectationsTest + +private module TestConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + node.(DataFlow::CallCfgNode).getFunction().asCfgNode().(NameNode).getId() = "source" + } + + predicate isSink(DataFlow::Node node) { + exists(DataFlow::CallCfgNode call | + call.getFunction().asCfgNode().(NameNode).getId() = "sink" and + node = call.getArg(0) + ) + } +} + +private module TestFlow = TaintTracking::Global; + +module FlowTest implements TestSig { + string getARelevantTag() { result = "flow" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(DataFlow::Node sink | + TestFlow::flow(_, sink) and + tag = "flow" and + location = sink.getLocation() and + value = "source" and + element = sink.toString() + ) + } +} + +import MakeTest diff --git a/ruby/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/ruby/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..459c2ce7f91 --- /dev/null +++ b/ruby/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `rb/log-injection` has been reduced from 7.8 (high) to 6.1 (medium). +* The `@security-severity` metadata of `rb/reflected-xss`, `rb/stored-xss` and `rb/html-constructed-from-input` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/ruby/ql/src/queries/security/cwe-079/ReflectedXSS.ql b/ruby/ql/src/queries/security/cwe-079/ReflectedXSS.ql index 8cc60618cc5..04eed164046 100644 --- a/ruby/ql/src/queries/security/cwe-079/ReflectedXSS.ql +++ b/ruby/ql/src/queries/security/cwe-079/ReflectedXSS.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @sub-severity high * @precision high * @id rb/reflected-xss diff --git a/ruby/ql/src/queries/security/cwe-079/StoredXSS.ql b/ruby/ql/src/queries/security/cwe-079/StoredXSS.ql index a621aee00b0..a2a1752f7f4 100644 --- a/ruby/ql/src/queries/security/cwe-079/StoredXSS.ql +++ b/ruby/ql/src/queries/security/cwe-079/StoredXSS.ql @@ -4,7 +4,7 @@ * a stored cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id rb/stored-xss * @tags security diff --git a/ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.ql b/ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.ql index c1527783fc3..3fa40cd6f91 100644 --- a/ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.ql +++ b/ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.ql @@ -4,7 +4,7 @@ * user to perform a cross-site scripting attack. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id rb/html-constructed-from-input * @tags security diff --git a/ruby/ql/src/queries/security/cwe-117/LogInjection.ql b/ruby/ql/src/queries/security/cwe-117/LogInjection.ql index 624c2f90e64..50a4a718e32 100644 --- a/ruby/ql/src/queries/security/cwe-117/LogInjection.ql +++ b/ruby/ql/src/queries/security/cwe-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @security-severity 7.8 + * @security-severity 6.1 * @precision medium * @id rb/log-injection * @tags security diff --git a/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll index 298e07f4b3e..3ff04276c63 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll @@ -33,5 +33,11 @@ module Impl { result = "impl " + trait + this.getSelfTy().toAbbreviatedString() + " { ... }" ) } + + /** + * Holds if this is an inherent `impl` block, that is, one that does not implement a trait. + */ + pragma[nomagic] + predicate isInherent() { not this.hasTrait() } } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll index e5dd4cdaee6..9fad85e756f 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll @@ -6,7 +6,15 @@ module Impl { private newtype TArgumentPosition = TPositionalArgumentPosition(int i) { - i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1] + // For the type `FunctionPosition` used by type inference, we work with function-call syntax + // adjusted positions, so a call like `x.m(a, b, c)` needs positions `0` through `3`; for this + // reason, there is no `- 1` after `max(...)` below. + i in [0 .. max([ + any(ParamList l).getNumberOfParams(), + any(ArgList l).getNumberOfArgs(), + any(StructFieldList l).getNumberOfFields() // Positions are used for struct expressions in type inference + ] + )] } or TSelfArgumentPosition() or TTypeQualifierArgumentPosition() diff --git a/rust/ql/lib/codeql/rust/elements/internal/StructExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/StructExprImpl.qll index d7704894c49..897196b78cb 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/StructExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/StructExprImpl.qll @@ -50,5 +50,10 @@ module Impl { or result = this.getVariant().getStructField(name) } + + /** Gets the `i`th struct field of the instantiated struct or variant. */ + StructField getNthStructField(int i) { + result = [this.getStruct().getNthStructField(i), this.getVariant().getNthStructField(i)] + } } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll index cb4121b7224..23fa1e76d9a 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll @@ -35,6 +35,12 @@ module Impl { /** Gets a record field, if any. */ StructField getAStructField() { result = this.getStructField(_) } + /** Gets the `i`th struct field, if any. */ + pragma[nomagic] + StructField getNthStructField(int i) { + result = this.getFieldList().(StructFieldList).getField(i) + } + /** Gets the `i`th tuple field, if any. */ pragma[nomagic] TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) } diff --git a/rust/ql/lib/codeql/rust/elements/internal/StructPatImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/StructPatImpl.qll index 28afc2a5b0d..e649d2a5778 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/StructPatImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/StructPatImpl.qll @@ -42,6 +42,13 @@ module Impl { ) } + /** Gets the `i`th struct field of the instantiated struct or variant. */ + StructField getNthStructField(int i) { + exists(PathResolution::ItemNode item | item = this.getResolvedPath(_) | + result = [item.(Struct).getNthStructField(i), item.(Variant).getNthStructField(i)] + ) + } + /** Gets the struct pattern for the field `name`. */ pragma[nomagic] StructPatField getPatField(string name) { diff --git a/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll index ed8b93f6c1d..58b061049bd 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll @@ -32,6 +32,12 @@ module Impl { result.getName().getText() = name } + /** Gets the `i`th struct field, if any. */ + pragma[nomagic] + StructField getNthStructField(int i) { + result = this.getFieldList().(StructFieldList).getField(i) + } + /** Gets the `i`th tuple field, if any. */ pragma[nomagic] TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/AssociatedType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/AssociatedType.qll index 656fd8e7ec8..8469c6da092 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/AssociatedType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/AssociatedType.qll @@ -39,8 +39,8 @@ predicate pathTypeAsTraitAssoc( /** * Holds if `assoc` is accessed on `tp` in `path`. * - * That is, this is the case when `path` is of the form `::AssocType` or `tp::AssocType`; and `AssocType` resolves to `assoc`. + * That is, this is the case when `path` is of the form `::AssocType` + * or `tp::AssocType`; and `AssocType` resolves to `assoc`. */ predicate tpAssociatedType(TypeParam tp, AssocType assoc, Path path) { resolvePath(path.getQualifier()) = tp and diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll b/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll index 51781a47305..db1402280d4 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll @@ -41,16 +41,19 @@ private predicate hasFirstNonTrivialTraitBound(TypeParamItemNode tp, Trait trait */ pragma[nomagic] predicate isBlanketLike(ImplItemNode i, TypePath blanketSelfPath, TypeParam blanketTypeParam) { - blanketTypeParam = i.getBlanketImplementationTypeParam() and - blanketSelfPath.isEmpty() - or - exists(TypeMention tm, Type root, TypeParameter tp | - tm = i.(Impl).getSelfTy() and - complexSelfRoot(root, tp) and - tm.getType() = root and - tm.getTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and - blanketSelfPath = TypePath::singleton(tp) and - hasFirstNonTrivialTraitBound(blanketTypeParam, _) + i.(Impl).hasTrait() and + ( + blanketTypeParam = i.getBlanketImplementationTypeParam() and + blanketSelfPath.isEmpty() + or + exists(TypeMention tm, Type root, TypeParameter tp | + tm = i.(Impl).getSelfTy() and + complexSelfRoot(root, tp) and + tm.getType() = root and + tm.getTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and + blanketSelfPath = TypePath::singleton(tp) and + hasFirstNonTrivialTraitBound(blanketTypeParam, _) + ) ) } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll index 0f65d21dcf7..6e4cc6e2c2e 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll @@ -124,7 +124,8 @@ private predicate functionResolutionDependsOnArgumentCand( implHasSibling(impl, trait) and traitTypeParameterOccurrence(trait, _, functionName, pos, path, traitTp) and f = impl.getASuccessor(functionName) and - not pos.isSelfOrTypeQualifier() + not pos.isTypeQualifier() and + not (f instanceof Method and pos.asPosition() = 0) ) } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll index f8611ce2a3c..26627450add 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll @@ -6,17 +6,23 @@ private import TypeMention private import TypeInference private newtype TFunctionPosition = - TArgumentFunctionPosition(ArgumentPosition pos) or + TArgumentFunctionPosition(ArgumentPosition pos) { not pos.isSelf() } or TReturnFunctionPosition() /** - * A position of a type related to a function. + * A function-call adjusted position of a type related to a function. * - * Either `self`, `return`, or a positional parameter index. + * Either `return` or a positional parameter index, where `self` is translated + * to position `0` and subsequent positional parameters at index `i` are + * translated to position `i + 1`. + * + * Function-call adjusted positions are needed when resolving calls of the + * form `Foo::f(x_1, ..., x_n)`, where we do not know up front whether `f` is a + * method or a non-method, and hence we need to be able to match `x_1` against + * both a potential `self` parameter and a potential first positional parameter + * (and `x_2, ... x_n` against all subsequent positional parameters). */ class FunctionPosition extends TFunctionPosition { - predicate isSelf() { this.asArgumentPosition().isSelf() } - int asPosition() { result = this.asArgumentPosition().asPosition() } predicate isPosition() { exists(this.asPosition()) } @@ -25,29 +31,18 @@ class FunctionPosition extends TFunctionPosition { predicate isTypeQualifier() { this.asArgumentPosition().isTypeQualifier() } - predicate isSelfOrTypeQualifier() { this.isSelf() or this.isTypeQualifier() } - predicate isReturn() { this = TReturnFunctionPosition() } - /** Gets the corresponding position when `f` is invoked via a function call. */ - bindingset[f] - FunctionPosition getFunctionCallAdjusted(Function f) { - this.isReturn() and - result = this - or - if f.hasSelfParam() - then - this.isSelf() and result.asPosition() = 0 - or - result.asPosition() = this.asPosition() + 1 - else result = this - } - TypeMention getTypeMention(Function f) { - this.isSelf() and - result = getSelfParamTypeMention(f.getSelfParam()) - or - result = f.getParam(this.asPosition()).getTypeRepr() + ( + if f instanceof Method + then + result = f.getParam(this.asPosition() - 1).getTypeRepr() + or + result = getSelfParamTypeMention(f.getSelfParam()) and + this.asPosition() = 0 + else result = f.getParam(this.asPosition()).getTypeRepr() + ) or this.isReturn() and result = getReturnTypeMention(f) @@ -197,8 +192,7 @@ class AssocFunctionType extends MkAssocFunctionType { exists(Function f, ImplOrTraitItemNode i, FunctionPosition pos | this.appliesTo(f, i, pos) | result = pos.getTypeMention(f) or - pos.isSelf() and - not f.hasSelfParam() and + pos.isTypeQualifier() and result = [i.(Impl).getSelfTy().(AstNode), i.(Trait).getName()] ) } @@ -209,7 +203,7 @@ class AssocFunctionType extends MkAssocFunctionType { } pragma[nomagic] -private Trait getALookupTrait(Type t) { +Trait getALookupTrait(Type t) { result = t.(TypeParamTypeParameter).getTypeParam().(TypeParamItemNode).resolveABound() or result = t.(SelfTypeParameter).getTrait() @@ -310,10 +304,11 @@ signature module ArgsAreInstantiationsOfInputSig { * Holds if `f` inside `i` needs to have the type corresponding to type parameter * `tp` checked. * - * If `i` is an inherent implementation, `tp` is a type parameter of the type being - * implemented, otherwise `tp` is a type parameter of the trait (being implemented). + * `tp` is a type parameter of the trait being implemented by `f` or the trait to which + * `f` belongs. * - * `pos` is one of the positions in `f` in which the relevant type occours. + * `pos` is one of the function-call adjusted positions in `f` in which the relevant + * type occurs. */ predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos); @@ -360,7 +355,7 @@ module ArgsAreInstantiationsOf { private newtype TCallAndPos = MkCallAndPos(Input::Call call, FunctionPosition pos) { exists(call.getArgType(pos, _)) } - /** A call tagged with a position. */ + /** A call tagged with a function-call adjusted position. */ private class CallAndPos extends MkCallAndPos { Input::Call call; FunctionPosition pos; @@ -413,20 +408,21 @@ module ArgsAreInstantiationsOf { pragma[nomagic] private predicate argIsInstantiationOf( - Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i, Function f, int rnk + Input::Call call, ImplOrTraitItemNode i, Function f, int rnk ) { - ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and - toCheckRanked(i, f, _, pos, rnk) + exists(FunctionPosition pos | + ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and + toCheckRanked(i, f, _, pos, rnk) + ) } pragma[nomagic] private predicate argsAreInstantiationsOfToIndex( Input::Call call, ImplOrTraitItemNode i, Function f, int rnk ) { - exists(FunctionPosition pos | - argIsInstantiationOf(call, pos, i, f, rnk) and - call.hasTargetCand(i, f) - | + argIsInstantiationOf(call, i, f, rnk) and + call.hasTargetCand(i, f) and + ( rnk = 0 or argsAreInstantiationsOfToIndex(call, i, f, rnk - 1) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index 70dfe9e9005..da150a3ef39 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -343,6 +343,10 @@ private class FunctionDeclaration extends Function { } } +private class AssocFunctionDeclaration extends FunctionDeclaration { + AssocFunctionDeclaration() { this.isAssoc(_) } +} + pragma[nomagic] private TypeMention getCallExprTypeMentionArgument(CallExpr ce, TypeArgumentPosition apos) { exists(Path p, int i | p = CallExprImpl::getFunctionPath(ce) | @@ -868,185 +872,6 @@ private Type inferTypeEquality(AstNode n, TypePath path) { ) } -/** - * A matching configuration for resolving types of struct expressions - * like `Foo { bar = baz }`. - * - * This also includes nullary struct expressions like `None`. - */ -private module StructExprMatchingInput implements MatchingInputSig { - private newtype TPos = - TFieldPos(string name) { exists(any(Declaration decl).getField(name)) } or - TStructPos() - - class DeclarationPosition extends TPos { - string asFieldPos() { this = TFieldPos(result) } - - predicate isStructPos() { this = TStructPos() } - - string toString() { - result = this.asFieldPos() - or - this.isStructPos() and - result = "(struct)" - } - } - - abstract class Declaration extends AstNode { - final TypeParameter getTypeParameter(TypeParameterPosition ppos) { - typeParamMatchPosition(this.getTypeItem().getGenericParamList().getATypeParam(), result, ppos) - } - - abstract StructField getField(string name); - - abstract TypeItem getTypeItem(); - - Type getDeclaredType(DeclarationPosition dpos, TypePath path) { - // type of a field - exists(TypeMention tp | - tp = this.getField(dpos.asFieldPos()).getTypeRepr() and - result = tp.getTypeAt(path) - ) - or - // type parameter of the struct itself - dpos.isStructPos() and - result = this.getTypeParameter(_) and - path = TypePath::singleton(result) - or - // type of the struct or enum itself - dpos.isStructPos() and - path.isEmpty() and - result = TDataType(this.getTypeItem()) - } - } - - private class StructDecl extends Declaration, Struct { - StructDecl() { this.isStruct() or this.isUnit() } - - override StructField getField(string name) { result = this.getStructField(name) } - - override TypeItem getTypeItem() { result = this } - } - - private class StructVariantDecl extends Declaration, Variant { - StructVariantDecl() { this.isStruct() or this.isUnit() } - - override StructField getField(string name) { result = this.getStructField(name) } - - override TypeItem getTypeItem() { result = this.getEnum() } - } - - class AccessPosition = DeclarationPosition; - - abstract class Access extends AstNode { - pragma[nomagic] - abstract AstNode getNodeAt(AccessPosition apos); - - pragma[nomagic] - Type getInferredType(AccessPosition apos, TypePath path) { - result = inferType(this.getNodeAt(apos), path) - } - - pragma[nomagic] - abstract Path getStructPath(); - - pragma[nomagic] - Declaration getTarget() { result = resolvePath(this.getStructPath()) } - - pragma[nomagic] - Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { - // Handle constructions that use `Self {...}` syntax - exists(TypeMention tm, TypePath path0 | - tm = this.getStructPath() and - result = tm.getTypeAt(path0) and - path0.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) - ) - } - - /** - * Holds if the return type of this struct expression at `path` may have to - * be inferred from the context. - */ - pragma[nomagic] - predicate hasUnknownTypeAt(DeclarationPosition pos, TypePath path) { - exists(Declaration d, TypeParameter tp | - d = this.getTarget() and - pos.isStructPos() and - tp = d.getDeclaredType(pos, path) and - not exists(DeclarationPosition fieldPos | - not fieldPos.isStructPos() and - tp = d.getDeclaredType(fieldPos, _) - ) and - // check that no explicit type arguments have been supplied for `tp` - not exists(TypeArgumentPosition tapos | - exists(this.getTypeArgument(tapos, _)) and - TTypeParamTypeParameter(tapos.asTypeParam()) = tp - ) - ) - } - } - - private class StructExprAccess extends Access, StructExpr { - override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { - result = super.getTypeArgument(apos, path) - or - exists(TypePath suffix | - suffix.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) and - result = CertainTypeInference::inferCertainType(this, suffix) - ) - } - - override AstNode getNodeAt(AccessPosition apos) { - result = this.getFieldExpr(apos.asFieldPos()).getExpr() - or - result = this and - apos.isStructPos() - } - - override Path getStructPath() { result = this.getPath() } - } - - /** - * A potential nullary struct/variant construction such as `None`. - */ - private class PathExprAccess extends Access, PathExpr { - PathExprAccess() { not exists(CallExpr ce | this = ce.getFunction()) } - - override AstNode getNodeAt(AccessPosition apos) { - result = this and - apos.isStructPos() - } - - override Path getStructPath() { result = this.getPath() } - } - - predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) { - apos = dpos - } -} - -private module StructExprMatching = Matching; - -pragma[nomagic] -private Type inferStructExprType0(AstNode n, FunctionPosition pos, TypePath path) { - exists(StructExprMatchingInput::Access a, StructExprMatchingInput::AccessPosition apos | - n = a.getNodeAt(apos) and - if apos.isStructPos() then pos.isReturn() else pos.asPosition() = 0 // the actual position doesn't matter, as long as it is positional - | - result = StructExprMatching::inferAccessType(a, apos, path) - or - a.hasUnknownTypeAt(apos, path) and - result = TUnknownType() - ) -} - -/** - * Gets the type of `n` at `path`, where `n` is either a struct expression or - * a field expression of a struct expression. - */ -private predicate inferStructExprType = - ContextTyping::CheckContextTyping::check/2; - pragma[nomagic] private TupleType inferTupleRootType(AstNode n) { // `typeEquality` handles the non-root cases @@ -1106,6 +931,43 @@ private Trait getCallExprTraitQualifier(CallExpr ce) { ) } +pragma[nomagic] +private predicate nonAssocFunction(ItemNode i) { not i instanceof AssocFunctionDeclaration } + +/** + * A call expression that can only resolve to something that is not an associated + * function, and hence does not need type inference for resolution. + */ +private class NonAssocCallExpr extends CallExpr { + NonAssocCallExpr() { + forex(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | nonAssocFunction(i)) + } + + /** + * Gets the target of this call, which can be resolved using only path resolution. + */ + ItemNode resolveCallTargetViaPathResolution() { result = CallExprImpl::getResolvedFunction(this) } + + pragma[nomagic] + Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + result = getCallExprTypeArgument(this, apos, path) + } + + AstNode getNodeAt(FunctionPosition pos) { + result = this.getSyntacticArgument(pos.asArgumentPosition()) + or + result = this and pos.isReturn() + } + + pragma[nomagic] + Type getInferredType(FunctionPosition pos, TypePath path) { + pos.isTypeQualifier() and + result = getCallExprTypeQualifier(this, path, false) + or + result = inferType(this.getNodeAt(pos), path) + } +} + /** * Provides functionality related to context-based typing of calls. */ @@ -1157,9 +1019,7 @@ private module ContextTyping { abstract class ContextTypedCallCand extends AstNode { abstract Type getTypeArgument(TypeArgumentPosition apos, TypePath path); - private predicate hasTypeArgument(TypeArgumentPosition apos) { - exists(this.getTypeArgument(apos, _)) - } + predicate hasTypeArgument(TypeArgumentPosition apos) { exists(this.getTypeArgument(apos, _)) } /** * Holds if this call resolves to `target` inside `i`, and the return type @@ -1196,7 +1056,9 @@ private module ContextTyping { pragma[nomagic] private predicate hasUnknownType(AstNode n) { hasUnknownTypeAt(n, _) } - signature Type inferCallTypeSig(AstNode n, FunctionPosition pos, TypePath path); + signature Type inferCallTypeSig( + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path + ); /** * Given a predicate `inferCallType` for inferring the type of a call at a given @@ -1204,74 +1066,40 @@ private module ContextTyping { * predicate and checks that types are only propagated into arguments when they * are context-typed. */ - module CheckContextTyping { + module CheckContextTyping { pragma[nomagic] - private Type inferCallNonReturnType(AstNode n, FunctionPosition pos, TypePath path) { - result = inferCallType(n, pos, path) and + private Type inferCallNonReturnType( + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path + ) { + result = inferCallType(n, pos, hasReceiver, path) and not pos.isReturn() } pragma[nomagic] private Type inferCallNonReturnType( - AstNode n, FunctionPosition pos, TypePath prefix, TypePath path + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath prefix, TypePath path ) { - result = inferCallNonReturnType(n, pos, path) and + result = inferCallNonReturnType(n, pos, hasReceiver, path) and hasUnknownType(n) and prefix = path.getAPrefix() } pragma[nomagic] Type check(AstNode n, TypePath path) { - result = inferCallType(n, any(FunctionPosition pos | pos.isReturn()), path) + result = inferCallType(n, any(FunctionPosition pos | pos.isReturn()), _, path) or - exists(FunctionPosition pos, TypePath prefix | - result = inferCallNonReturnType(n, pos, prefix, path) and + exists(FunctionPosition pos, boolean hasReceiver, TypePath prefix | + result = inferCallNonReturnType(n, pos, hasReceiver, prefix, path) and hasUnknownTypeAt(n, prefix) | // Never propagate type information directly into the receiver, since its type // must already have been known in order to resolve the call - if pos.isSelf() then not prefix.isEmpty() else any() + if pos.asPosition() = 0 and hasReceiver = true then not prefix.isEmpty() else any() ) } } } -/** - * Holds if function `f` with the name `name` and the arity `arity` exists in - * `i`, and the type at position `pos` is `t`. - */ -pragma[nomagic] -private predicate assocFunctionInfo( - Function f, string name, int arity, ImplOrTraitItemNode i, FunctionPosition pos, - AssocFunctionType t -) { - f = i.getASuccessor(name) and - arity = f.getParamList().getNumberOfParams() and - t.appliesTo(f, i, pos) -} - -/** - * Holds if function `f` with the name `name` and the arity `arity` exists in - * blanket (like) implementation `impl` of `trait`, and the type at position - * `pos` is `t`. - * - * `blanketPath` points to the type `blanketTypeParam` inside `t`, which - * is the type parameter used in the blanket implementation. - */ -pragma[nomagic] -private predicate functionInfoBlanketLike( - Function f, string name, int arity, ImplItemNode impl, Trait trait, FunctionPosition pos, - AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam -) { - exists(TypePath blanketSelfPath | - assocFunctionInfo(f, name, arity, impl, pos, t) and - TTypeParamTypeParameter(blanketTypeParam) = t.getTypeAt(blanketPath) and - blanketPath = any(string s) + blanketSelfPath and - BlanketImplementation::isBlanketLike(impl, blanketSelfPath, blanketTypeParam) and - trait = impl.resolveTraitTy() - ) -} - /** * Holds if the type path `path` pointing to `type` is stripped of any leading * complex root type allowed for `self` parameters, such as `&`, `Box`, `Rc`, @@ -1327,7 +1155,7 @@ private class BorrowKind extends TBorrowKind { } /** - * Provides logic for resolving calls to methods. + * Provides logic for resolving calls to associated functions. * * When resolving a method call, a list of [candidate receiver types][1] is constructed * @@ -1361,190 +1189,342 @@ private class BorrowKind extends TBorrowKind { * * [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers */ -private module MethodResolution { +private module AssocFunctionResolution { /** - * Holds if method `m` with the name `name` and the arity `arity` exists in - * `i`, and the type of the `self` parameter is `selfType`. + * Holds if function `f` with the name `name` and the arity `arity` exists in + * `i`, and the type at function-call adjusted position `pos` is `t`. + */ + pragma[nomagic] + private predicate assocFunctionInfo( + Function f, string name, int arity, ImplOrTraitItemNode i, FunctionPosition pos, + AssocFunctionType t + ) { + f = i.getASuccessor(name) and + arity = f.getNumberOfParamsInclSelf() and + t.appliesTo(f, i, pos) + } + + /** + * Holds if the non-method trait function `f` mentions the implicit `Self` type + * parameter at position `pos`. + */ + pragma[nomagic] + private predicate traitSelfTypeParameterOccurrence( + TraitItemNode trait, NonMethodFunction f, FunctionPosition pos + ) { + FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _, TSelfTypeParameter(trait)) + } + + /** + * Holds if the non-method function `f` implements a trait function that mentions + * the implicit `Self` type parameter at position `pos`. + */ + pragma[nomagic] + private predicate traitImplSelfTypeParameterOccurrence( + ImplItemNode impl, NonMethodFunction f, FunctionPosition pos + ) { + exists(NonMethodFunction traitFunction | + f = impl.getAnAssocItem() and + f.implements(traitFunction) and + traitSelfTypeParameterOccurrence(_, traitFunction, pos) + ) + } + + private module TypeOption = Option; + + private class TypeOption = TypeOption::Option; + + /** + * Holds if function `f` with the name `name` and the arity `arity` exists in + * `i`, and the type at function-call adjusted position `selfPos` is `selfType`. * - * `strippedTypePath` points to the type `strippedType` inside `selfType`, - * which is the (possibly complex-stripped) root type of `selfType`. For example, - * if `m` has a `&self` parameter, then `strippedTypePath` is `getRefSharedTypeParameter()` + * `selfPos` is a position relevant for call resolution: either a position + * corresponding to the `self` parameter of `f` (if present); a type qualifier + * position; or a position where the implicit `Self` type parameter of some trait + * is mentioned in some non-method function `f_trait`, and either `f = f_trait` + * or `f` implements `f_trait`. + * + * `strippedTypePath` points to the type `strippedType` inside `selfType`, which + * is the (possibly complex-stripped) root type of `selfType`. For example, if + * `f` has a `&self` parameter, then `strippedTypePath` is `getRefSharedTypeParameter()` * and `strippedType` is the type inside the reference. + * + * `implType` is the type being implemented by `i` (`None` when `i` is a trait). + * + * `trait` is the trait being implemented by `i` or `i` itself (`None` when `i` is inherent). + * + * `isMethod` indicates whether `f` is a method. */ pragma[nomagic] - private predicate methodInfo( - Method m, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType + private predicate assocFunctionInfo( + Function f, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, TypeOption implType, + TypeOption trait, boolean isMethod ) { - assocFunctionInfo(m, name, arity, i, selfPos, selfType) and + assocFunctionInfo(f, name, arity, i, selfPos, selfType) and strippedType = selfType.getTypeAt(strippedTypePath) and - isComplexRootStripped(strippedTypePath, strippedType) and - selfPos.isSelfOrTypeQualifier() - } - - pragma[nomagic] - private predicate methodInfoTypeParam( - Method m, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType selfType, TypePath strippedTypePath, TypeParam tp - ) { - methodInfo(m, name, arity, selfPos, i, selfType, strippedTypePath, TTypeParamTypeParameter(tp)) - } - - /** - * Same as `methodInfo`, but restricted to non-blanket implementations, and - * allowing for any `strippedType` when the corresponding type inside `m` is - * a type parameter. - */ - pragma[inline] - private predicate methodInfoNonBlanket( - Method m, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType - ) { ( - methodInfo(m, name, arity, selfPos, i, selfType, strippedTypePath, strippedType) or - methodInfoTypeParam(m, name, arity, selfPos, i, selfType, strippedTypePath, _) + isComplexRootStripped(strippedTypePath, strippedType) + or + selfPos.isTypeQualifier() and strippedTypePath.isEmpty() ) and - not BlanketImplementation::isBlanketLike(i, _, _) + ( + f instanceof Method and + selfPos.asPosition() = 0 + or + selfPos.isTypeQualifier() + or + traitSelfTypeParameterOccurrence(i, f, selfPos) + or + traitImplSelfTypeParameterOccurrence(i, f, selfPos) + ) and + ( + implType.asSome() = resolveImplSelfTypeAt(i, TypePath::nil()) + or + i instanceof Trait and + implType.isNone() + ) and + ( + trait.asSome() = + [ + TTrait(i).(Type), + TTrait(i.(ImplItemNode).resolveTraitTy()).(Type) + ] + or + i.(Impl).isInherent() and trait.isNone() + ) and + if f instanceof Method then isMethod = true else isMethod = false } /** - * Holds if method `m` with the name `name` and the arity `arity` exists in - * blanket (like) implementation `impl` of `trait`, and the type of the `self` - * parameter is `selfType`. + * Holds if function `f` with the name `name` and the arity `arity` exists in + * blanket (like) implementation `impl`, and the type at function-call adjusted + * position `selfPos` is `selfType`. + * + * `selfPos` is a position relevant for call resolution: either a position + * corresponding to the `self` parameter of `f` (if present); a type qualifier + * position; or a position where the implicit `Self` type parameter of some trait + * is mentioned in some non-method function `f_trait`, and `f` implements `f_trait`. * * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which * is the type parameter used in the blanket implementation. + * + * `implType` is the type being implemented by `i`. + * + * `trait` is the trait being implemented by `i`. + * + * `isMethod` indicates whether `f` is a method. */ pragma[nomagic] - private predicate methodInfoBlanketLike( - Method m, string name, int arity, FunctionPosition selfPos, ImplItemNode impl, Trait trait, - AssocFunctionType selfType, TypePath blanketPath, TypeParam blanketTypeParam + private predicate assocFunctionInfoBlanketLike( + Function f, string name, int arity, ImplItemNode impl, TypeOption implType, TypeOption trait, + FunctionPosition selfPos, AssocFunctionType selfType, TypePath blanketPath, + TypeParam blanketTypeParam, boolean isMethod ) { - functionInfoBlanketLike(m, name, arity, impl, trait, selfPos, selfType, blanketPath, - blanketTypeParam) and - selfPos.isSelfOrTypeQualifier() + exists(TypePath blanketSelfPath | + assocFunctionInfo(f, name, arity, selfPos, impl, selfType, _, _, implType, trait, isMethod) and + TTypeParamTypeParameter(blanketTypeParam) = selfType.getTypeAt(blanketPath) and + blanketPath = any(string s) + blanketSelfPath and + BlanketImplementation::isBlanketLike(impl, blanketSelfPath, blanketTypeParam) + ) } pragma[nomagic] - private predicate methodTraitInfo(string name, int arity, Trait trait) { + private predicate assocFunctionTraitInfo(string name, int arity, Trait trait) { exists(ImplItemNode i | - methodInfo(_, name, arity, _, i, _, _, _) and + assocFunctionInfo(_, name, arity, i, _, _) and trait = i.resolveTraitTy() ) or - methodInfo(_, name, arity, _, trait, _, _, _) + assocFunctionInfo(_, name, arity, trait, _, _) } pragma[nomagic] - private predicate methodCallTraitCandidate(Element mc, Trait trait) { - mc = - any(MethodCall mc0 | + private predicate assocFunctionCallTraitCandidate(Element afc, Trait trait) { + afc = + any(AssocFunctionCall afc0 | exists(string name, int arity | - mc0.hasNameAndArity(name, arity) and - methodTraitInfo(name, arity, trait) - | - not mc0.hasTrait() - or - trait = mc0.getTrait() + afc0.hasNameAndArity(name, arity) and + assocFunctionTraitInfo(name, arity, trait) and + // we only need to check visibility of traits that are not mentioned explicitly + not afc0.hasATrait() ) ) } - private module MethodTraitIsVisible = TraitIsVisible; + private module AssocFunctionTraitIsVisible = TraitIsVisible; - private predicate methodCallVisibleTraitCandidate = MethodTraitIsVisible::traitIsVisible/2; - - bindingset[mc, impl] + bindingset[afc, impl] pragma[inline_late] - private predicate methodCallVisibleImplTraitCandidate(MethodCall mc, ImplItemNode impl) { - methodCallVisibleTraitCandidate(mc, impl.resolveTraitTy()) + private predicate callVisibleImplTraitCandidate(AssocFunctionCall afc, ImplItemNode impl) { + AssocFunctionTraitIsVisible::traitIsVisible(afc, impl.resolveTraitTy()) } /** - * Holds if method call `mc` may target a method in `i` with `self` parameter having - * type `selfType`. + * Checks that the explicit type qualifier of a call (if any), `typeQualifier`, + * matches the type being implemented by the target, `implType`. + */ + bindingset[implType] + private predicate callTypeQualifierCheck(TypeOption implType, TypeOption typeQualifier) { + typeQualifier = [implType, TypeOption::none_()] + } + + /** + * Checks that the explicit trait qualifier of a call (if any), `traitQualifier`, + * matches the trait being implemented by the target (or in which the target is defined), + * `trait`, and that when a receiver is present in the call, the target is a method. + */ + bindingset[trait, isMethod] + pragma[inline_late] + private predicate callTraitQualifierAndReceiverCheck( + TypeOption trait, Boolean isMethod, TypeOption traitQualifier, boolean hasReceiver + ) { + traitQualifier = [trait, TypeOption::none_()] and + hasReceiver = [isMethod, false] + } + + bindingset[implType, trait, isMethod] + private predicate callCheck( + TypeOption implType, TypeOption trait, Boolean isMethod, TypeOption typeQualifier, + TypeOption traitQualifier, boolean hasReceiver + ) { + callTypeQualifierCheck(implType, typeQualifier) and + callTraitQualifierAndReceiverCheck(trait, isMethod, traitQualifier, hasReceiver) + } + + pragma[nomagic] + private predicate assocFunctionInfoNonBlanketLikeCheck( + Function f, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, + TypeOption typeQualifier, TypeOption traitQualifier, boolean hasReceiver + ) { + exists(TypeOption implType, TypeOption trait, boolean isMethod | + assocFunctionInfo(f, name, arity, selfPos, i, selfType, strippedTypePath, strippedType, + implType, trait, isMethod) and + not BlanketImplementation::isBlanketLike(i, _, _) and + callCheck(implType, trait, isMethod, typeQualifier, traitQualifier, hasReceiver) + ) + } + + pragma[nomagic] + private predicate assocFunctionInfoNonBlanketLikeTypeParamCheck( + Function f, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, TypeOption typeQualifier, + TypeOption traitQualifier, boolean hasReceiver + ) { + assocFunctionInfoNonBlanketLikeCheck(f, name, arity, selfPos, i, selfType, strippedTypePath, + TTypeParamTypeParameter(_), typeQualifier, traitQualifier, hasReceiver) + } + + /** + * Holds if call `afc` may target function `f` in `i` with type `selfType` at + * function-call adjusted position `selfPos`. * * `strippedTypePath` points to the type `strippedType` inside `selfType`, * which is the (possibly complex-stripped) root type of `selfType`. - * - * This predicate only checks for matching method names and arities, and whether - * the trait being implemented by `i` (when `i` is not a trait itself) is visible - * at `mc`. */ - bindingset[mc, strippedTypePath, strippedType] + bindingset[afc, strippedTypePath, strippedType] pragma[inline_late] - private predicate methodCallNonBlanketCandidate( - MethodCall mc, Method m, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType self, TypePath strippedTypePath, Type strippedType + private predicate nonBlanketLikeCandidate( + AssocFunctionCall afc, Function f, FunctionPosition selfPos, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType ) { - exists(string name, int arity | - mc.hasNameAndArity(name, arity) and - methodInfoNonBlanket(m, name, arity, selfPos, i, self, strippedTypePath, strippedType) + exists( + string name, int arity, TypeOption typeQualifier, TypeOption traitQualifier, + boolean hasReceiver | - i = - any(Impl impl | - not impl.hasTrait() - or - methodCallVisibleImplTraitCandidate(mc, impl) - ) + afc.hasSyntacticInfo(name, arity, typeQualifier, traitQualifier, hasReceiver) and + if not afc.hasATrait() and i.(Impl).hasTrait() + then callVisibleImplTraitCandidate(afc, i) + else any() + | + assocFunctionInfoNonBlanketLikeCheck(f, name, arity, selfPos, i, selfType, strippedTypePath, + strippedType, typeQualifier, traitQualifier, hasReceiver) or - methodCallVisibleTraitCandidate(mc, i) - or - i.(ImplItemNode).resolveTraitTy() = mc.getTrait() + assocFunctionInfoNonBlanketLikeTypeParamCheck(f, name, arity, selfPos, i, selfType, + strippedTypePath, typeQualifier, traitQualifier, hasReceiver) + ) + } + + bindingset[name, arity, typeQualifier, traitQualifier, hasReceiver] + pragma[inline_late] + private predicate assocFunctionInfoBlanketLikeCheck( + Function f, string name, int arity, FunctionPosition selfPos, ImplItemNode impl, + AssocFunctionType selfType, TypePath blanketPath, TypeParam blanketTypeParam, + TypeOption typeQualifier, TypeOption traitQualifier, boolean hasReceiver + ) { + exists(TypeOption implType, TypeOption trait, boolean isMethod | + assocFunctionInfoBlanketLike(f, name, arity, impl, implType, trait, selfPos, selfType, + blanketPath, blanketTypeParam, isMethod) and + callTraitQualifierAndReceiverCheck(trait, isMethod, traitQualifier, hasReceiver) and + if impl.isBlanketImplementation() + then any() + else callTypeQualifierCheck(implType, typeQualifier) ) } /** - * Holds if method call `mc` may target a method in blanket (like) implementation - * `impl` with `self` parameter having type `selfType`. + * Holds if call `afc` may target function `f` in blanket (like) implementation + * `impl` with type `selfType` at function-call adjusted position `selfPos`. * * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which * is the type parameter used in the blanket implementation. - * - * This predicate only checks for matching method names and arities, and whether - * the trait being implemented by `i` (when `i` is not a trait itself) is visible - * at `mc`. */ - bindingset[mc] + bindingset[afc] pragma[inline_late] - private predicate methodCallBlanketLikeCandidate( - MethodCall mc, Method m, FunctionPosition selfPos, ImplItemNode impl, AssocFunctionType self, - TypePath blanketPath, TypeParam blanketTypeParam + private predicate blanketLikeCandidate( + AssocFunctionCall afc, Function f, FunctionPosition selfPos, ImplItemNode impl, + AssocFunctionType self, TypePath blanketPath, TypeParam blanketTypeParam ) { - exists(string name, int arity | - mc.hasNameAndArity(name, arity) and - methodInfoBlanketLike(m, name, arity, selfPos, impl, _, self, blanketPath, blanketTypeParam) + exists( + string name, int arity, TypeOption typeQualifier, TypeOption traitQualifier, + boolean hasReceiver | - methodCallVisibleImplTraitCandidate(mc, impl) - or - impl.resolveTraitTy() = mc.getTrait() + afc.hasSyntacticInfo(name, arity, typeQualifier, traitQualifier, hasReceiver) and + assocFunctionInfoBlanketLikeCheck(f, name, arity, selfPos, impl, self, blanketPath, + blanketTypeParam, typeQualifier, traitQualifier, hasReceiver) + | + if not afc.hasATrait() then callVisibleImplTraitCandidate(afc, impl) else any() ) } /** - * A (potential) method call. + * A (potential) call to an associated function. * * This is either: * - * 1. `MethodCallMethodCallExpr`: an actual method call, `x.m()`; - * 2. `MethodCallIndexExpr`: an index expression, `x[i]`, which is [syntactic sugar][1] + * 1. `AssocFunctionCallMethodCallExpr`: a method call, `x.m()`; + * 2. `AssocFunctionCallIndexExpr`: an index expression, `x[i]`, which is [syntactic sugar][1] * for `*x.index(i)`; - * 3. `MethodCallCallExpr`: a qualified function call, `Q::m(x)`, where `m` is a method; - * or - * 4. `MethodCallOperation`: an operation expression, `x + y`, which is syntactic sugar + * 3. `AssocFunctionCallCallExpr`: a qualified function call, `Q::f(x)`; or + * 4. `AssocFunctionCallOperation`: an operation expression, `x + y`, which is syntactic sugar * for `Add::add(x, y)`. * * Note that only in case 1 and 2 is auto-dereferencing and borrowing allowed. * - * Note also that only case 4 is a _potential_ method call; in all other cases, we are - * guaranteed that the target is a method. + * Note also that only case 3 is a _potential_ call; in all other cases, we are guaranteed that + * the target is an associated function (in fact, a method). * * [1]: https://doc.rust-lang.org/std/ops/trait.Index.html */ - abstract class MethodCall extends Expr { + abstract class AssocFunctionCall extends Expr { + /** + * Holds if this call targets a function named `name` with `arity` parameters + * (including `self`). + */ + pragma[nomagic] abstract predicate hasNameAndArity(string name, int arity); - abstract Expr getArg(ArgumentPosition pos); + abstract Expr getNonReturnNodeAt(FunctionPosition pos); + + AstNode getNodeAt(FunctionPosition pos) { + result = this.getNonReturnNodeAt(pos) + or + result = this and pos.isReturn() + } + + /** Holds if this call has a receiver and hence must target a method. */ + abstract predicate hasReceiver(); abstract predicate supportsAutoDerefAndBorrow(); @@ -1554,38 +1534,76 @@ private module MethodResolution { /** Holds if this call targets a trait. */ predicate hasTrait() { exists(this.getTrait()) } - AstNode getNodeAt(FunctionPosition apos) { - result = this.getArg(apos.asArgumentPosition()) + Trait getATrait() { + result = this.getTrait() or - result = this and apos.isReturn() + result = getALookupTrait(getCallExprTypeQualifier(this, TypePath::nil(), _)) } - Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { - result = inferType(this.getArg(pos), path) + predicate hasATrait() { exists(this.getATrait()) } + + private Type getNonTypeParameterTypeQualifier() { + result = getCallExprTypeQualifier(this, TypePath::nil(), _) and + not result instanceof TypeParameter } /** - * Same as `getACandidateReceiverTypeAt`, but without borrows. + * Holds if this call has the given purely syntactic information, that is, + * information that does not rely on type inference. */ pragma[nomagic] - Type getACandidateReceiverTypeAtNoBorrow( - FunctionPosition selfPos, DerefChain derefChain, TypePath path + predicate hasSyntacticInfo( + string name, int arity, TypeOption typeQualifier, TypeOption traitQualifier, + boolean hasReceiver ) { - result = this.getArgumentTypeAt(selfPos.asArgumentPosition(), path) and - selfPos.isSelfOrTypeQualifier() and - derefChain.isEmpty() - or - exists(DerefImplItemNode impl, DerefChain suffix | - result = - ImplicitDeref::getDereferencedCandidateReceiverType(this, selfPos, impl, suffix, path) and - derefChain = DerefChain::cons(impl, suffix) + this.hasNameAndArity(name, arity) and + (if this.hasReceiver() then hasReceiver = true else hasReceiver = false) and + ( + typeQualifier.asSome() = this.getNonTypeParameterTypeQualifier() + or + not exists(this.getNonTypeParameterTypeQualifier()) and + typeQualifier.isNone() + ) and + ( + traitQualifier.asSome() = TTrait(this.getATrait()) + or + not this.hasATrait() and + traitQualifier.isNone() ) } + Type getTypeAt(FunctionPosition pos, TypePath path) { + result = inferType(this.getNodeAt(pos), path) + } + /** - * Holds if the method inside `i` with matching name and arity can be ruled + * Holds if `selfPos` is a potentially relevant function-call adjusted position + * for resolving this call. + * + * Only holds when we don't know for sure that the target is a method (in those + * cases we rely on the receiver only). + */ + pragma[nomagic] + private predicate isRelevantSelfPos(FunctionPosition selfPos) { + not this.hasReceiver() and + exists(TypePath strippedTypePath, Type strippedType | + strippedType = substituteLookupTraits(this.getTypeAt(selfPos, strippedTypePath)) and + strippedType != TNeverType() and + strippedType != TUnknownType() + | + nonBlanketLikeCandidate(this, _, selfPos, _, _, strippedTypePath, strippedType) + or + blanketLikeCandidate(this, _, selfPos, _, _, strippedTypePath, _) + ) + } + + predicate hasReceiverAtPos(FunctionPosition pos) { this.hasReceiver() and pos.asPosition() = 0 } + + /** + * Holds if the function inside `i` with matching name and arity can be ruled * out as a target of this call, because the candidate receiver type represented - * by `derefChain` and `borrow` is incompatible with the `self` parameter type. + * by `derefChain` and `borrow` is incompatible with the type at function-call + * adjusted position `selfPos`. * * The types are incompatible because they disagree on a concrete type somewhere * inside `root`. @@ -1596,48 +1614,87 @@ private module MethodResolution { Type root ) { exists(TypePath path | - ReceiverIsInstantiationOfSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, selfPos, - derefChain, borrow), i, _, path) and + SelfArgIsInstantiationOf::argIsNotInstantiationOf(this, i, selfPos, derefChain, borrow, path) and path.isCons(root.getATypeParameter(), _) ) + or + exists(AssocFunctionType selfType | + SelfArgIsInstantiationOf::argIsInstantiationOf(this, i, selfPos, derefChain, borrow, + selfType) and + OverloadedCallArgsAreInstantiationsOf::argsAreNotInstantiationsOf(this, i) and + root = selfType.getTypeAt(TypePath::nil()) + ) } /** - * Holds if the method inside blanket-like implementation `impl` with matching name + * Holds if the function inside blanket-like implementation `impl` with matching name * and arity can be ruled out as a target of this call, either because the candidate - * receiver type represented by `derefChain` and `borrow` is incompatible with the `self` - * parameter type, or because the blanket constraint is not satisfied. + * receiver type represented by `derefChain` and `borrow` is incompatible with the type + * at function-call adjusted position `selfPos`, or because the blanket constraint + * is not satisfied. */ pragma[nomagic] private predicate hasIncompatibleBlanketLikeTarget( ImplItemNode impl, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { - ReceiverIsNotInstantiationOfBlanketLikeSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, + SelfArgIsNotInstantiationOfBlanketLike::argIsNotInstantiationOf(MkAssocFunctionCallCand(this, selfPos, derefChain, borrow), impl, _, _) or - ReceiverSatisfiesBlanketLikeConstraint::dissatisfiesBlanketConstraint(MkMethodCallCand(this, + ArgSatisfiesBlanketLikeConstraint::dissatisfiesBlanketConstraint(MkAssocFunctionCallCand(this, selfPos, derefChain, borrow), impl) } + pragma[nomagic] + private predicate hasNoInherentTargetCheck( + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + ) { + MkAssocFunctionCallCand(this, selfPos, derefChain, borrow) + .(AssocFunctionCallCand) + .hasNoInherentTargetCheck() + } + + pragma[nomagic] + private predicate hasNoInherentTargetTypeQualifierCheck() { + exists(FunctionPosition typeQualifierPos | + typeQualifierPos.isTypeQualifier() and + this.hasNoInherentTargetCheck(typeQualifierPos, DerefChain::nil(), TNoBorrowKind()) + ) + } + + pragma[nomagic] + predicate hasNoInherentTarget(FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow) { + this.hasNoInherentTargetCheck(selfPos, derefChain, borrow) and + if exists(this.getNonTypeParameterTypeQualifier()) and not selfPos.isTypeQualifier() + then + // If this call is of the form `Foo::bar(x)` and we are resolving with respect to the type + // of `x`, then we additionally need to check that the type qualifier does not give rise + // to an inherent target + this.hasNoInherentTargetTypeQualifierCheck() + else any() + } + /** - * Same as `getACandidateReceiverTypeAt`, but excludes pseudo types `!` and `unknown`. + * Same as `getSelfTypeAt`, but excludes pseudo types `!` and `unknown`. */ pragma[nomagic] - Type getANonPseudoCandidateReceiverTypeAt( + Type getANonPseudoSelfTypeAt( FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath path ) { - result = this.getACandidateReceiverTypeAt(selfPos, derefChain, borrow, path) and + result = this.getSelfTypeAt(selfPos, derefChain, borrow, path) and result != TNeverType() and result != TUnknownType() } pragma[nomagic] - private Type getComplexStrippedType( + private Type getComplexStrippedSelfType( FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath ) { - result = - this.getANonPseudoCandidateReceiverTypeAt(selfPos, derefChain, borrow, strippedTypePath) and - isComplexRootStripped(strippedTypePath, result) + result = this.getANonPseudoSelfTypeAt(selfPos, derefChain, borrow, strippedTypePath) and + ( + isComplexRootStripped(strippedTypePath, result) + or + selfPos.isTypeQualifier() and strippedTypePath.isEmpty() + ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] @@ -1646,7 +1703,7 @@ private module MethodResolution { Type strippedType ) { forall(ImplOrTraitItemNode i | - methodCallNonBlanketCandidate(this, _, selfPos, i, _, strippedTypePath, strippedType) + nonBlanketLikeCandidate(this, _, selfPos, i, _, strippedTypePath, strippedType) | this.hasIncompatibleTarget(i, selfPos, derefChain, borrow, strippedType) ) @@ -1659,7 +1716,7 @@ private module MethodResolution { ) { this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, strippedType) and - forall(ImplItemNode i | methodCallBlanketLikeCandidate(this, _, selfPos, i, _, _, _) | + forall(ImplItemNode i | blanketLikeCandidate(this, _, selfPos, i, _, _, _) | this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) ) } @@ -1672,7 +1729,7 @@ private module MethodResolution { this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, strippedType) and forall(ImplItemNode i | - methodCallBlanketLikeCandidate(this, _, selfPos, i, _, _, _) and + blanketLikeCandidate(this, _, selfPos, i, _, _, _) and not i.isBlanketImplementation() | this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) @@ -1685,27 +1742,23 @@ private module MethodResolution { FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n ) { - ( - this.supportsAutoDerefAndBorrow() - or - // needed for the `hasNoCompatibleTarget` check in - // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` - derefChain.isEmpty() - ) and + this.supportsAutoDerefAndBorrow() and + this.hasReceiverAtPos(selfPos) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and n = -1 or this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | + exists(Type t | + t = getNthLookupType(strippedType, n) and this.hasNoCompatibleTargetCheck(selfPos, derefChain, TNoBorrowKind(), strippedTypePath, t) ) } /** * Holds if the candidate receiver type represented by `derefChain` does not - * have a matching method target. + * have a matching call target at function-call adjusted position `selfPos`. */ pragma[nomagic] predicate hasNoCompatibleTargetNoBorrow(FunctionPosition selfPos, DerefChain derefChain) { @@ -1722,19 +1775,25 @@ private module MethodResolution { int n ) { ( - this.supportsAutoDerefAndBorrow() + this.supportsAutoDerefAndBorrow() and + this.hasReceiverAtPos(selfPos) or - // needed for the `hasNoCompatibleTarget` check in - // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` - derefChain.isEmpty() + // needed for the `hasNoCompatibleNonBlanketTarget` check in + // `ArgSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` + exists(ImplItemNode i | + derefChain.isEmpty() and + blanketLikeCandidate(this, _, selfPos, i, _, _, _) and + i.isBlanketImplementation() + ) ) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and n = -1 or this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | + exists(Type t | + t = getNthLookupType(strippedType, n) and this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TNoBorrowKind(), strippedTypePath, t) ) @@ -1742,7 +1801,7 @@ private module MethodResolution { /** * Holds if the candidate receiver type represented by `derefChain` does not have - * a matching non-blanket method target. + * a matching non-blanket call target at function-call adjusted position `selfPos`. */ pragma[nomagic] predicate hasNoCompatibleNonBlanketTargetNoBorrow( @@ -1762,12 +1821,14 @@ private module MethodResolution { ) { this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(false), + strippedTypePath) and n = -1 or this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | + exists(Type t | + t = getNthLookupType(strippedType, n) and this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath, t) ) @@ -1775,7 +1836,8 @@ private module MethodResolution { /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a shared borrow, does not have a matching method target. + * by a shared borrow, does not have a matching call target at function-call + * adjusted position `selfPos`. */ pragma[nomagic] predicate hasNoCompatibleTargetSharedBorrow(FunctionPosition selfPos, DerefChain derefChain) { @@ -1793,12 +1855,13 @@ private module MethodResolution { ) { this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and n = -1 or this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | + exists(Type t | + t = getNthLookupType(strippedType, n) and this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath, t) ) @@ -1806,7 +1869,8 @@ private module MethodResolution { /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a `mut` borrow, does not have a matching method target. + * by a `mut` borrow, does not have a matching call target at function-call + * adjusted position `selfPos`. */ pragma[nomagic] predicate hasNoCompatibleTargetMutBorrow(FunctionPosition selfPos, DerefChain derefChain) { @@ -1824,12 +1888,14 @@ private module MethodResolution { ) { this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(false), + strippedTypePath) and n = -1 or this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | + exists(Type t | + t = getNthLookupType(strippedType, n) and this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath, t) ) @@ -1837,7 +1903,8 @@ private module MethodResolution { /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a shared borrow, does not have a matching non-blanket method target. + * by a shared borrow, does not have a matching non-blanket call target at + * function-call adjusted position `selfPos`. */ pragma[nomagic] predicate hasNoCompatibleNonBlanketTargetSharedBorrow( @@ -1857,12 +1924,13 @@ private module MethodResolution { ) { this.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and n = -1 or this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | + exists(Type t | + t = getNthLookupType(strippedType, n) and this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath, t) ) @@ -1870,7 +1938,8 @@ private module MethodResolution { /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a `mut` borrow, does not have a matching non-blanket method target. + * by a `mut` borrow, does not have a matching non-blanket call target at + * function-call adjusted position `selfPos`. */ pragma[nomagic] predicate hasNoCompatibleNonBlanketTargetMutBorrow( @@ -1883,7 +1952,34 @@ private module MethodResolution { } /** - * Gets a [candidate receiver type][1] of this method call at `path`. + * Same as `getSelfTypeAt`, but without borrows. + */ + pragma[nomagic] + Type getSelfTypeAtNoBorrow(FunctionPosition selfPos, DerefChain derefChain, TypePath path) { + result = this.getTypeAt(selfPos, path) and + derefChain.isEmpty() and + ( + this.hasReceiverAtPos(selfPos) + or + selfPos.isTypeQualifier() + or + this.isRelevantSelfPos(selfPos) + ) + or + exists(DerefImplItemNode impl, DerefChain suffix | + result = + ImplicitDeref::getDereferencedCandidateReceiverType(this, selfPos, impl, suffix, path) and + derefChain = DerefChain::cons(impl, suffix) + ) + } + + /** + * Gets the type of this call at function-call adjusted position `selfPos` and + * type path `path`. + * + * In case this call supports auto-dereferencing and borrowing and `selfPos` is + * position 0 (corresponding to the receiver), the result is a + * [candidate receiver type][1]: * * The type is obtained by repeatedly dereferencing the receiver expression's type, * as long as the method cannot be resolved in an earlier candidate type, and possibly @@ -1895,15 +1991,14 @@ private module MethodResolution { * [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers */ pragma[nomagic] - Type getACandidateReceiverTypeAt( + Type getSelfTypeAt( FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath path ) { - result = this.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, path) and + result = this.getSelfTypeAtNoBorrow(selfPos, derefChain, path) and borrow.isNoBorrow() or exists(RefType rt | // first try shared borrow - this.supportsAutoDerefAndBorrow() and this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and borrow.isSharedBorrow() or @@ -1917,7 +2012,7 @@ private module MethodResolution { result = rt or exists(TypePath suffix | - result = this.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, suffix) and + result = this.getSelfTypeAtNoBorrow(selfPos, derefChain, suffix) and path = TypePath::cons(rt.getPositionalTypeParameter(0), suffix) ) ) @@ -1925,15 +2020,17 @@ private module MethodResolution { } /** - * Gets a method that this call resolves to after having applied a sequence of - * dereferences and possibly a borrow on the receiver type, encoded in `derefChain` - * and `borrow`. + * Gets a function that this call resolves to after having applied a sequence of + * dereferences and possibly a borrow on the receiver type at `selfPos`, encoded + * in `derefChain` and `borrow`. */ pragma[nomagic] - Method resolveCallTarget(ImplOrTraitItemNode i, DerefChain derefChain, BorrowKind borrow) { - exists(MethodCallCand mcc | - mcc = MkMethodCallCand(this, _, derefChain, borrow) and - result = mcc.resolveCallTarget(i) + AssocFunctionDeclaration resolveCallTarget( + ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + ) { + exists(AssocFunctionCallCand afcc | + afcc = MkAssocFunctionCallCand(this, selfPos, derefChain, borrow) and + result = afcc.resolveCallTarget(i) ) } @@ -1943,21 +2040,28 @@ private module MethodResolution { * resolve the call target. */ predicate argumentHasImplicitDerefChainBorrow(Expr arg, DerefChain derefChain, BorrowKind borrow) { - exists(this.resolveCallTarget(_, derefChain, borrow)) and - arg = this.getArg(any(ArgumentPosition apos | apos.isSelf())) and - not (derefChain.isEmpty() and borrow.isNoBorrow()) + exists(FunctionPosition selfAdj | + this.hasReceiverAtPos(selfAdj) and + exists(this.resolveCallTarget(_, selfAdj, derefChain, borrow)) and + arg = this.getNodeAt(selfAdj) and + not (derefChain.isEmpty() and borrow.isNoBorrow()) + ) } } - private class MethodCallMethodCallExpr extends MethodCall instanceof MethodCallExpr { - pragma[nomagic] + private class AssocFunctionCallMethodCallExpr extends AssocFunctionCall instanceof MethodCallExpr { override predicate hasNameAndArity(string name, int arity) { name = super.getIdentifier().getText() and - arity = super.getArgList().getNumberOfArgs() + arity = super.getNumberOfSyntacticArguments() } - override Expr getArg(ArgumentPosition pos) { - result = MethodCallExpr.super.getSyntacticArgument(pos) + override predicate hasReceiver() { any() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { + result = super.getReceiver() and + pos.asPosition() = 0 + or + result = super.getPositionalArgument(pos.asPosition() - 1) } override predicate supportsAutoDerefAndBorrow() { any() } @@ -1965,24 +2069,25 @@ private module MethodResolution { override Trait getTrait() { none() } } - private class MethodCallIndexExpr extends MethodCall instanceof IndexExpr { + private class AssocFunctionCallIndexExpr extends AssocFunctionCall, IndexExpr { private predicate isInMutableContext() { // todo: does not handle all cases yet VariableImpl::assignmentOperationDescendant(_, this) } - pragma[nomagic] override predicate hasNameAndArity(string name, int arity) { (if this.isInMutableContext() then name = "index_mut" else name = "index") and - arity = 1 + arity = 2 } - override Expr getArg(ArgumentPosition pos) { - pos.isSelf() and - result = super.getBase() - or + override predicate hasReceiver() { any() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { pos.asPosition() = 0 and - result = super.getIndex() + result = this.getBase() + or + pos.asPosition() = 1 and + result = this.getIndex() } override predicate supportsAutoDerefAndBorrow() { any() } @@ -1994,72 +2099,64 @@ private module MethodResolution { } } - private class MethodCallCallExpr extends MethodCall instanceof CallExpr { - MethodCallCallExpr() { + private class AssocFunctionCallCallExpr extends AssocFunctionCall, CallExpr { + AssocFunctionCallCallExpr() { exists(getCallExprPathQualifier(this)) and - // even if a method cannot be resolved by path resolution, it may still + // even if a target cannot be resolved by path resolution, it may still // be possible to resolve a blanket implementation (so not `forex`) - forall(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | i instanceof Method) + forall(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | + i instanceof AssocFunctionDeclaration + ) } - pragma[nomagic] override predicate hasNameAndArity(string name, int arity) { name = CallExprImpl::getFunctionPath(this).getText() and - arity = super.getArgList().getNumberOfArgs() - 1 + arity = this.getNumberOfSyntacticArguments() } - override Expr getArg(ArgumentPosition pos) { - pos.isSelf() and - result = super.getSyntacticPositionalArgument(0) - or - result = super.getSyntacticPositionalArgument(pos.asPosition() + 1) + override predicate hasReceiver() { none() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { + result = this.getSyntacticPositionalArgument(pos.asPosition()) } - override Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { - result = super.getArgumentTypeAt(pos, path) + override Type getTypeAt(FunctionPosition pos, TypePath path) { + result = super.getTypeAt(pos, path) or pos.isTypeQualifier() and result = getCallExprTypeQualifier(this, path, _) } - pragma[nomagic] - predicate hasNoInherentTarget() { - // `_` is fine below, because auto-deref/borrow is not supported - MkMethodCallCand(this, _, _, _).(MethodCallCand).hasNoInherentTarget() - } - override predicate supportsAutoDerefAndBorrow() { none() } override Trait getTrait() { result = getCallExprTraitQualifier(this) } } - final class MethodCallOperation extends MethodCall instanceof Operation { - pragma[nomagic] + final class AssocFunctionCallOperation extends AssocFunctionCall, Operation { override predicate hasNameAndArity(string name, int arity) { - super.isOverloaded(_, name, _) and - arity = super.getNumberOfOperands() - 1 + this.isOverloaded(_, name, _) and + arity = this.getNumberOfOperands() } - override Expr getArg(ArgumentPosition pos) { - pos.isSelf() and - result = super.getOperand(0) - or - result = super.getOperand(pos.asPosition() + 1) + override predicate hasReceiver() { any() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { + result = this.getOperand(pos.asPosition()) } - private predicate implicitBorrowAt(ArgumentPosition pos, boolean isMutable) { - exists(int borrows | super.isOverloaded(_, _, borrows) | - pos.isSelf() and + private predicate implicitBorrowAt(FunctionPosition pos, boolean isMutable) { + exists(int borrows | this.isOverloaded(_, _, borrows) | + pos.asPosition() = 0 and borrows >= 1 and if this instanceof CompoundAssignmentExpr then isMutable = true else isMutable = false or - pos.asPosition() = 0 and + pos.asPosition() = 1 and borrows = 2 and isMutable = false ) } - override Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { + override Type getTypeAt(FunctionPosition pos, TypePath path) { exists(boolean isMutable, RefType rt | this.implicitBorrowAt(pos, isMutable) and rt = getRefType(isMutable) @@ -2068,21 +2165,21 @@ private module MethodResolution { path.isEmpty() or exists(TypePath path0 | - result = inferType(this.getArg(pos), path0) and + result = inferType(this.getNodeAt(pos), path0) and path = TypePath::cons(rt.getPositionalTypeParameter(0), path0) ) ) or not this.implicitBorrowAt(pos, _) and - result = inferType(this.getArg(pos), path) + result = inferType(this.getNodeAt(pos), path) } override predicate argumentHasImplicitDerefChainBorrow( Expr arg, DerefChain derefChain, BorrowKind borrow ) { - exists(ArgumentPosition apos, boolean isMutable | - this.implicitBorrowAt(apos, isMutable) and - arg = this.getArg(apos) and + exists(FunctionPosition pos, boolean isMutable | + this.implicitBorrowAt(pos, isMutable) and + arg = this.getNodeAt(pos) and derefChain = DerefChain::nil() and borrow = TSomeBorrowKind(isMutable) ) @@ -2090,164 +2187,193 @@ private module MethodResolution { override predicate supportsAutoDerefAndBorrow() { none() } - override Trait getTrait() { super.isOverloaded(result, _, _) } + override Trait getTrait() { this.isOverloaded(result, _, _) } } pragma[nomagic] - private Method getMethodSuccessor(ImplOrTraitItemNode i, string name, int arity) { + private AssocFunctionDeclaration getAssocFunctionSuccessor( + ImplOrTraitItemNode i, string name, int arity + ) { result = i.getASuccessor(name) and - arity = result.getParamList().getNumberOfParams() + arity = result.getNumberOfParamsInclSelf() } - private newtype TMethodCallCand = - MkMethodCallCand( - MethodCall mc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + private newtype TAssocFunctionCallCand = + MkAssocFunctionCallCand( + AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { - exists(mc.getACandidateReceiverTypeAt(selfPos, derefChain, borrow, _)) + exists(afc.getANonPseudoSelfTypeAt(selfPos, derefChain, borrow, _)) } - /** A method call with a dereference chain and a potential borrow. */ - private class MethodCallCand extends MkMethodCallCand { - MethodCall mc_; - FunctionPosition selfPos; + /** A call with a dereference chain and a potential borrow at a given position. */ + final private class AssocFunctionCallCand extends MkAssocFunctionCallCand { + AssocFunctionCall afc_; + FunctionPosition selfPos_; DerefChain derefChain; BorrowKind borrow; - MethodCallCand() { this = MkMethodCallCand(mc_, selfPos, derefChain, borrow) } + AssocFunctionCallCand() { this = MkAssocFunctionCallCand(afc_, selfPos_, derefChain, borrow) } - MethodCall getMethodCall() { result = mc_ } + AssocFunctionCall getAssocFunctionCall() { result = afc_ } Type getTypeAt(TypePath path) { result = - substituteLookupTraits(mc_.getANonPseudoCandidateReceiverTypeAt(selfPos, derefChain, borrow, - path)) + substituteLookupTraits(afc_.getANonPseudoSelfTypeAt(selfPos_, derefChain, borrow, path)) } pragma[nomagic] predicate hasNoCompatibleNonBlanketTarget() { - mc_.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos_, derefChain) and borrow.isSharedBorrow() or - mc_.hasNoCompatibleNonBlanketTargetMutBorrow(selfPos, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetMutBorrow(selfPos_, derefChain) and borrow.isMutableBorrow() or - mc_.hasNoCompatibleNonBlanketTargetNoBorrow(selfPos, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetNoBorrow(selfPos_, derefChain) and borrow.isNoBorrow() } pragma[nomagic] predicate hasSignature( - MethodCall mc, FunctionPosition selfPos_, TypePath strippedTypePath, Type strippedType, + AssocFunctionCall afc, FunctionPosition selfPos, TypePath strippedTypePath, Type strippedType, string name, int arity ) { strippedType = this.getTypeAt(strippedTypePath) and - isComplexRootStripped(strippedTypePath, strippedType) and - mc = mc_ and - mc.hasNameAndArity(name, arity) and + ( + isComplexRootStripped(strippedTypePath, strippedType) + or + selfPos_.isTypeQualifier() and strippedTypePath.isEmpty() + ) and + afc = afc_ and + afc.hasNameAndArity(name, arity) and selfPos = selfPos_ } /** - * Holds if the inherent method inside `impl` with matching name and arity can be + * Holds if the inherent function inside `impl` with matching name and arity can be * ruled out as a candidate for this call. */ pragma[nomagic] private predicate hasIncompatibleInherentTarget(Impl impl) { - ReceiverIsNotInstantiationOfInherentSelfParam::argIsNotInstantiationOf(this, impl, _, _) + SelfArgIsNotInstantiationOfInherent::argIsNotInstantiationOf(this, impl, _, _) } - /** - * Holds if this method call has no inherent target, i.e., it does not - * resolve to a method in an `impl` block for the type of the receiver. - */ pragma[nomagic] - predicate hasNoInherentTarget() { - mc_.hasTrait() - or - exists(TypePath strippedTypePath, Type strippedType, string name, int arity | - this.hasSignature(_, selfPos, strippedTypePath, strippedType, name, arity) and + predicate hasNoInherentTargetCheck() { + exists( + TypePath strippedTypePath, Type strippedType, string name, int arity, + TypeOption typeQualifier, TypeOption traitQualifier, boolean hasReceiver, + boolean targetMustBeMethod + | + // Calls to inherent functions are always of the form `x.m(...)` or `Foo::bar(...)`, + // where `Foo` is a type. In case `bar` is a method, we can use both the type qualifier + // and the type of the first argument to rule out candidates + selfPos_.isTypeQualifier() and targetMustBeMethod = false + or + selfPos_.asPosition() = 0 and targetMustBeMethod = true + | + afc_.hasSyntacticInfo(name, arity, typeQualifier, traitQualifier, hasReceiver) and + (if hasReceiver = true then targetMustBeMethod = true else any()) and + this.hasSignature(_, selfPos_, strippedTypePath, strippedType, name, arity) and forall(Impl i | - methodInfoNonBlanket(_, name, arity, selfPos, i, _, strippedTypePath, strippedType) and - not i.hasTrait() + i.isInherent() and + ( + assocFunctionInfoNonBlanketLikeCheck(_, name, arity, selfPos_, i, _, strippedTypePath, + strippedType, typeQualifier, traitQualifier, targetMustBeMethod) + or + assocFunctionInfoNonBlanketLikeTypeParamCheck(_, name, arity, selfPos_, i, _, + strippedTypePath, typeQualifier, traitQualifier, targetMustBeMethod) + ) | this.hasIncompatibleInherentTarget(i) ) ) } + /** + * Holds if this function call has no inherent target, i.e., it does not + * resolve to a function in an `impl` block for the type of the receiver. + */ pragma[nomagic] - private predicate argIsInstantiationOf(ImplOrTraitItemNode i, string name, int arity) { - ReceiverIsInstantiationOfSelfParam::argIsInstantiationOf(this, i, _) and - mc_.hasNameAndArity(name, arity) + predicate hasNoInherentTarget() { + afc_.hasTrait() + or + afc_.hasNoInherentTarget(selfPos_, derefChain, borrow) } pragma[nomagic] - Method resolveCallTargetCand(ImplOrTraitItemNode i) { + private predicate selfArgIsInstantiationOf(ImplOrTraitItemNode i, string name, int arity) { + SelfArgIsInstantiationOf::argIsInstantiationOf(this, i, _) and + afc_.hasNameAndArity(name, arity) + } + + pragma[nomagic] + AssocFunctionDeclaration resolveCallTargetCand(ImplOrTraitItemNode i) { exists(string name, int arity | - this.argIsInstantiationOf(i, name, arity) and - result = getMethodSuccessor(i, name, arity) + this.selfArgIsInstantiationOf(i, name, arity) and + result = getAssocFunctionSuccessor(i, name, arity) ) } - /** Gets a method that matches this method call. */ + /** Gets the associated function targeted by this call, if any. */ pragma[nomagic] - Method resolveCallTarget(ImplOrTraitItemNode i) { + AssocFunctionDeclaration resolveCallTarget(ImplOrTraitItemNode i) { result = this.resolveCallTargetCand(i) and not FunctionOverloading::functionResolutionDependsOnArgument(i, result, _, _) or - MethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result) + OverloadedCallArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result) } string toString() { - result = mc_.toString() + " [" + derefChain.toString() + "; " + borrow + "]" + result = afc_ + " at " + selfPos_ + " [" + derefChain.toString() + "; " + borrow + "]" } - Location getLocation() { result = mc_.getLocation() } + Location getLocation() { result = afc_.getLocation() } } /** * Provides logic for resolving implicit `Deref::deref` calls. */ private module ImplicitDeref { - private newtype TMethodCallDerefCand = - MkMethodCallDerefCand(MethodCall mc, FunctionPosition selfPos, DerefChain derefChain) { - mc.supportsAutoDerefAndBorrow() and - mc.hasNoCompatibleTargetMutBorrow(selfPos, derefChain) and - exists(mc.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, TypePath::nil())) + private newtype TCallDerefCand = + MkCallDerefCand(AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain) { + afc.supportsAutoDerefAndBorrow() and + afc.hasReceiverAtPos(selfPos) and + afc.hasNoCompatibleTargetMutBorrow(selfPos, derefChain) and + exists(afc.getSelfTypeAtNoBorrow(selfPos, derefChain, TypePath::nil())) } - /** A method call with a dereference chain. */ - private class MethodCallDerefCand extends MkMethodCallDerefCand { - MethodCall mc; + /** A call with a dereference chain. */ + private class CallDerefCand extends MkCallDerefCand { + AssocFunctionCall afc; FunctionPosition selfPos; DerefChain derefChain; - MethodCallDerefCand() { this = MkMethodCallDerefCand(mc, selfPos, derefChain) } + CallDerefCand() { this = MkCallDerefCand(afc, selfPos, derefChain) } Type getTypeAt(TypePath path) { - result = - substituteLookupTraits(mc.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, path)) and + result = substituteLookupTraits(afc.getSelfTypeAtNoBorrow(selfPos, derefChain, path)) and result != TNeverType() and result != TUnknownType() } - string toString() { result = mc.toString() + " [" + derefChain.toString() + "]" } + string toString() { result = afc + " [" + derefChain.toString() + "]" } - Location getLocation() { result = mc.getLocation() } + Location getLocation() { result = afc.getLocation() } } - private module MethodCallSatisfiesDerefConstraintInput implements - SatisfiesConstraintInputSig + private module CallSatisfiesDerefConstraintInput implements + SatisfiesConstraintInputSig { pragma[nomagic] - predicate relevantConstraint(MethodCallDerefCand mc, Type constraint) { + predicate relevantConstraint(CallDerefCand mc, Type constraint) { exists(mc) and constraint.(TraitType).getTrait() instanceof DerefTrait } } - private module MethodCallSatisfiesDerefConstraint = - SatisfiesConstraint; + private module CallSatisfiesDerefConstraint = + SatisfiesConstraint; pragma[nomagic] private AssociatedTypeTypeParameter getDerefTargetTypeParameter() { @@ -2255,38 +2381,38 @@ private module MethodResolution { } /** - * Gets the type of the receiver of `mc` at `path` after applying the implicit + * Gets the type of the receiver of `afc` at `path` after applying the implicit * dereference inside `impl`, following the existing dereference chain `derefChain`. */ pragma[nomagic] Type getDereferencedCandidateReceiverType( - MethodCall mc, FunctionPosition selfPos, DerefImplItemNode impl, DerefChain derefChain, - TypePath path + AssocFunctionCall afc, FunctionPosition selfPos, DerefImplItemNode impl, + DerefChain derefChain, TypePath path ) { - exists(MethodCallDerefCand mcc, TypePath exprPath | - mcc = MkMethodCallDerefCand(mc, selfPos, derefChain) and - MethodCallSatisfiesDerefConstraint::satisfiesConstraintTypeThrough(mcc, impl, _, exprPath, - result) and + exists(CallDerefCand cdc, TypePath exprPath | + cdc = MkCallDerefCand(afc, selfPos, derefChain) and + CallSatisfiesDerefConstraint::satisfiesConstraintTypeThrough(cdc, impl, _, exprPath, result) and exprPath.isCons(getDerefTargetTypeParameter(), path) ) } } - private module ReceiverSatisfiesBlanketLikeConstraintInput implements - BlanketImplementation::SatisfiesBlanketConstraintInputSig + private module ArgSatisfiesBlanketLikeConstraintInput implements + BlanketImplementation::SatisfiesBlanketConstraintInputSig { pragma[nomagic] predicate hasBlanketCandidate( - MethodCallCand mcc, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam + AssocFunctionCallCand afcc, ImplItemNode impl, TypePath blanketPath, + TypeParam blanketTypeParam ) { - exists(MethodCall mc, FunctionPosition selfPos, BorrowKind borrow | - mcc = MkMethodCallCand(mc, selfPos, _, borrow) and - methodCallBlanketLikeCandidate(mc, _, selfPos, impl, _, blanketPath, blanketTypeParam) and + exists(AssocFunctionCall afc, FunctionPosition selfPos, BorrowKind borrow | + afcc = MkAssocFunctionCallCand(afc, selfPos, _, borrow) and + blanketLikeCandidate(afc, _, selfPos, impl, _, blanketPath, blanketTypeParam) and // Only apply blanket implementations when no other implementations are possible; // this is to account for codebases that use the (unstable) specialization feature // (https://rust-lang.github.io/rfcs/1210-impl-specialization.html), as well as // cases where our blanket implementation filtering is not precise enough. - (mcc.hasNoCompatibleNonBlanketTarget() or not impl.isBlanketImplementation()) + if impl.isBlanketImplementation() then afcc.hasNoCompatibleNonBlanketTarget() else any() | borrow.isNoBorrow() or @@ -2295,116 +2421,141 @@ private module MethodResolution { } } - private module ReceiverSatisfiesBlanketLikeConstraint = - BlanketImplementation::SatisfiesBlanketConstraint; + private module ArgSatisfiesBlanketLikeConstraint = + BlanketImplementation::SatisfiesBlanketConstraint; /** - * A configuration for matching the type of a receiver against the type of - * a `self` parameter. + * A configuration for matching the type of an argument against the type of + * a function at a function-call adjusted position relevant for dispatch + * (such as a `self` parameter). */ - private module ReceiverIsInstantiationOfSelfParamInput implements - IsInstantiationOfInputSig + private module SelfArgIsInstantiationOfInput implements + IsInstantiationOfInputSig { pragma[nomagic] additional predicate potentialInstantiationOf0( - MethodCallCand mcc, ImplOrTraitItemNode i, AssocFunctionType selfType + AssocFunctionCallCand afcc, ImplOrTraitItemNode i, AssocFunctionType selfType ) { exists( - MethodCall mc, FunctionPosition selfPos, Method m, TypePath strippedTypePath, + AssocFunctionCall afc, FunctionPosition selfPos, Function f, TypePath strippedTypePath, Type strippedType | - mcc.hasSignature(mc, selfPos, strippedTypePath, strippedType, _, _) + afcc.hasSignature(afc, selfPos, strippedTypePath, strippedType, _, _) | - methodCallNonBlanketCandidate(mc, m, selfPos, i, selfType, strippedTypePath, strippedType) + nonBlanketLikeCandidate(afc, f, selfPos, i, selfType, strippedTypePath, strippedType) or - methodCallBlanketLikeCandidate(mc, m, selfPos, i, selfType, _, _) and - ReceiverSatisfiesBlanketLikeConstraint::satisfiesBlanketConstraint(mcc, i) + blanketLikeCandidate(afc, f, selfPos, i, selfType, _, _) and + ArgSatisfiesBlanketLikeConstraint::satisfiesBlanketConstraint(afcc, i) ) } pragma[nomagic] predicate potentialInstantiationOf( - MethodCallCand mcc, TypeAbstraction abs, AssocFunctionType constraint + AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - potentialInstantiationOf0(mcc, abs, constraint) and + potentialInstantiationOf0(afcc, abs, constraint) and if abs.(Impl).hasTrait() then - // inherent methods take precedence over trait methods, so only allow - // trait methods when there are no matching inherent methods - mcc.hasNoInherentTarget() + // inherent functions take precedence over trait functions, so only allow + // trait functions when there are no matching inherent functions + afcc.hasNoInherentTarget() else any() } predicate relevantConstraint(AssocFunctionType constraint) { - methodInfo(_, _, _, _, _, constraint, _, _) + assocFunctionInfo(_, _, _, _, _, constraint, _, _, _, _, _) } } - private module ReceiverIsInstantiationOfSelfParam = - ArgIsInstantiationOf; + private module SelfArgIsInstantiationOf { + import ArgIsInstantiationOf + + pragma[nomagic] + predicate argIsNotInstantiationOf( + AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, + BorrowKind borrow, TypePath path + ) { + argIsNotInstantiationOf(MkAssocFunctionCallCand(afc, selfPos, derefChain, borrow), i, _, path) + } + + pragma[nomagic] + predicate argIsInstantiationOf( + AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, + BorrowKind borrow, AssocFunctionType selfType + ) { + argIsInstantiationOf(MkAssocFunctionCallCand(afc, selfPos, derefChain, borrow), i, selfType) + } + } /** - * A configuration for anti-matching the type of a receiver against the type of - * a `self` parameter belonging to a blanket (like) implementation. + * A configuration for anti-matching the type of an argument against the type of + * a function at a function-call adjusted position relevant for dispatch + * (such as a `self` parameter) in a blanket (like) implementation. */ - private module ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput implements - IsInstantiationOfInputSig + private module SelfArgIsNotInstantiationOfBlanketLikeInput implements + IsInstantiationOfInputSig { pragma[nomagic] predicate potentialInstantiationOf( - MethodCallCand mcc, TypeAbstraction abs, AssocFunctionType constraint + AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - exists(MethodCall mc, FunctionPosition selfPos | - mcc = MkMethodCallCand(mc, selfPos, _, _) and - methodCallBlanketLikeCandidate(mc, _, selfPos, abs, constraint, _, _) and + exists(AssocFunctionCall afc, FunctionPosition selfPos | + afcc = MkAssocFunctionCallCand(afc, selfPos, _, _) and + blanketLikeCandidate(afc, _, selfPos, abs, constraint, _, _) and if abs.(Impl).hasTrait() then - // inherent methods take precedence over trait methods, so only allow - // trait methods when there are no matching inherent methods - mcc.hasNoInherentTarget() + // inherent functions take precedence over trait functions, so only allow + // trait functions when there are no matching inherent functions + afcc.hasNoInherentTarget() else any() ) } } - private module ReceiverIsNotInstantiationOfBlanketLikeSelfParam = - ArgIsInstantiationOf; + private module SelfArgIsNotInstantiationOfBlanketLike = + ArgIsInstantiationOf; /** - * A configuration for anti-matching the type of a receiver against the type of - * a `self` parameter in an inherent method. + * A configuration for anti-matching the type of an argument against the type of + * a function at a function-call adjusted position relevant for dispatch (such as + * a `self` parameter) in an inherent function. */ - private module ReceiverIsNotInstantiationOfInherentSelfParamInput implements - IsInstantiationOfInputSig + private module SelfArgIsNotInstantiationOfInherentInput implements + IsInstantiationOfInputSig { pragma[nomagic] predicate potentialInstantiationOf( - MethodCallCand mcc, TypeAbstraction abs, AssocFunctionType constraint + AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - ReceiverIsInstantiationOfSelfParamInput::potentialInstantiationOf0(mcc, abs, constraint) and - abs = any(Impl i | not i.hasTrait()) + SelfArgIsInstantiationOfInput::potentialInstantiationOf0(afcc, abs, constraint) and + abs.(Impl).isInherent() and + exists(AssocFunctionCall afc, FunctionPosition selfPos | + afcc = MkAssocFunctionCallCand(afc, selfPos, _, _) + | + selfPos.isTypeQualifier() or + afc.hasReceiverAtPos(selfPos) + ) } } - private module ReceiverIsNotInstantiationOfInherentSelfParam = - ArgIsInstantiationOf; + private module SelfArgIsNotInstantiationOfInherent = + ArgIsInstantiationOf; /** * A configuration for matching the types of positional arguments against the * types of parameters, when needed to disambiguate the call. */ - private module MethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig { + private module OverloadedCallArgsAreInstantiationsOfInput implements + ArgsAreInstantiationsOfInputSig + { predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) { FunctionOverloading::functionResolutionDependsOnArgument(i, f, traitTp, pos) } - class Call extends MethodCallCand { + class Call extends AssocFunctionCallCand { Type getArgType(FunctionPosition pos, TypePath path) { - result = mc_.getArgumentTypeAt(pos.asArgumentPosition(), path) - or - pos.isReturn() and - result = inferType(mc_.getNodeAt(pos), path) + result = this.getAssocFunctionCall().getTypeAt(pos, path) } predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { @@ -2413,50 +2564,55 @@ private module MethodResolution { } } - private module MethodArgsAreInstantiationsOf = - ArgsAreInstantiationsOf; + private module OverloadedCallArgsAreInstantiationsOf { + import ArgsAreInstantiationsOf + + pragma[nomagic] + predicate argsAreNotInstantiationsOf(AssocFunctionCall afc, ImplOrTraitItemNode i) { + argsAreNotInstantiationsOf(MkAssocFunctionCallCand(afc, _, _, _), i, _) + } + } } /** - * A matching configuration for resolving types of method call expressions - * like `foo.bar(baz)`. + * A matching configuration for resolving types of function call expressions + * like `foo.bar(baz)` and `Foo::bar(baz)`. */ -private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSig { +private module FunctionCallMatchingInput implements MatchingWithEnvironmentInputSig { import FunctionPositionMatchingInput - private class MethodDeclaration extends Method, FunctionDeclaration { } - private newtype TDeclaration = - TMethodFunctionDeclaration(ImplOrTraitItemNode i, MethodDeclaration m) { m.isAssoc(i) } + TFunctionDeclaration(ImplOrTraitItemNodeOption i, FunctionDeclaration f) { f.isFor(i) } - final class Declaration extends TMethodFunctionDeclaration { - ImplOrTraitItemNode parent; - ImplOrTraitItemNodeOption someParent; - MethodDeclaration m; + final class Declaration extends TFunctionDeclaration { + ImplOrTraitItemNodeOption i; + FunctionDeclaration f; - Declaration() { - this = TMethodFunctionDeclaration(parent, m) and - someParent.asSome() = parent - } + Declaration() { this = TFunctionDeclaration(i, f) } - predicate isMethod(ImplOrTraitItemNode i, Method method) { - this = TMethodFunctionDeclaration(i, method) + predicate isAssocFunction(ImplOrTraitItemNode i_, Function f_) { + i_ = i.asSome() and + f_ = f } TypeParameter getTypeParameter(TypeParameterPosition ppos) { - result = m.getTypeParameter(someParent, ppos) + result = f.getTypeParameter(i, ppos) } - Type getDeclaredType(DeclarationPosition dpos, TypePath path) { - result = m.getParameterType(someParent, dpos, path) + Type getDeclaredType(FunctionPosition pos, TypePath path) { + result = f.getParameterType(i, pos, path) or - dpos.isReturn() and - result = m.getReturnType(someParent, path) + pos.isReturn() and + result = f.getReturnType(i, path) } - string toString() { result = m.toStringExt(parent) } + string toString() { + i.isNone() and result = f.toString() + or + result = f.toStringExt(i.asSome()) + } - Location getLocation() { result = m.getLocation() } + Location getLocation() { result = f.getLocation() } } class AccessEnvironment = string; @@ -2477,10 +2633,32 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi ) } - final private class MethodCallFinal = MethodResolution::MethodCall; + private string noDerefChainBorrow() { + exists(DerefChain derefChain, BorrowKind borrow | + derefChain.isEmpty() and + borrow.isNoBorrow() and + result = encodeDerefChainBorrow(derefChain, borrow) + ) + } - class Access extends MethodCallFinal, ContextTyping::ContextTypedCallCand { - Access() { + abstract class Access extends ContextTyping::ContextTypedCallCand { + abstract AstNode getNodeAt(FunctionPosition pos); + + bindingset[derefChainBorrow] + abstract Type getInferredType(string derefChainBorrow, FunctionPosition pos, TypePath path); + + abstract Declaration getTarget(string derefChainBorrow); + + /** + * Holds if the return type of this call at `path` may have to be inferred + * from the context. + */ + abstract predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path); + } + + private class AssocFunctionCallAccess extends Access instanceof AssocFunctionResolution::AssocFunctionCall + { + AssocFunctionCallAccess() { // handled in the `OperationMatchingInput` module not this instanceof Operation } @@ -2497,99 +2675,161 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi result = getCallExprTypeArgument(this, apos, path) } + override AstNode getNodeAt(FunctionPosition pos) { + result = AssocFunctionResolution::AssocFunctionCall.super.getNodeAt(pos) + } + pragma[nomagic] - private Type getInferredSelfType(AccessPosition apos, string derefChainBorrow, TypePath path) { + private Type getInferredSelfType(FunctionPosition pos, string derefChainBorrow, TypePath path) { exists(DerefChain derefChain, BorrowKind borrow | - result = this.getACandidateReceiverTypeAt(apos, derefChain, borrow, path) and - derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) + result = super.getSelfTypeAt(pos, derefChain, borrow, path) and + derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and + super.hasReceiverAtPos(pos) ) } pragma[nomagic] - Type getInferredNonSelfType(AccessPosition apos, TypePath path) { + private Type getInferredNonSelfType(FunctionPosition pos, TypePath path) { if // index expression `x[i]` desugars to `*x.index(i)`, so we must account for // the implicit deref - apos.isReturn() and + pos.isReturn() and this instanceof IndexExpr then path.isEmpty() and result instanceof RefType or exists(TypePath suffix | - result = inferType(this.getNodeAt(apos), suffix) and + result = super.getTypeAt(pos, suffix) and path = TypePath::cons(getRefTypeParameter(_), suffix) ) else ( - not apos.isSelf() and - result = inferType(this.getNodeAt(apos), path) + not super.hasReceiverAtPos(pos) and + result = super.getTypeAt(pos, path) ) } bindingset[derefChainBorrow] - Type getInferredType(string derefChainBorrow, AccessPosition apos, TypePath path) { - result = this.getInferredSelfType(apos, derefChainBorrow, path) + override Type getInferredType(string derefChainBorrow, FunctionPosition pos, TypePath path) { + result = this.getInferredSelfType(pos, derefChainBorrow, path) or - result = this.getInferredNonSelfType(apos, path) + result = this.getInferredNonSelfType(pos, path) } - Method getTarget(ImplOrTraitItemNode i, string derefChainBorrow) { + private AssocFunctionDeclaration getTarget(ImplOrTraitItemNode i, string derefChainBorrow) { exists(DerefChain derefChain, BorrowKind borrow | derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and - result = this.resolveCallTarget(i, derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa + result = super.resolveCallTarget(i, _, derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa ) } - Declaration getTarget(string derefChainBorrow) { - exists(ImplOrTraitItemNode i, Method m | - m = this.getTarget(i, derefChainBorrow) and - result = TMethodFunctionDeclaration(i, m) - ) + override Declaration getTarget(string derefChainBorrow) { + exists(ImplOrTraitItemNode i | result.isAssocFunction(i, this.getTarget(i, derefChainBorrow))) } - /** - * Holds if the return type of this call at `path` may have to be inferred - * from the context. - */ pragma[nomagic] - predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path) { + override predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path) { exists(ImplOrTraitItemNode i | this.hasUnknownTypeAt(i, this.getTarget(i, derefChainBorrow), pos, path) ) + or + derefChainBorrow = noDerefChainBorrow() and + forex(ImplOrTraitItemNode i, Function f | + f = CallExprImpl::getResolvedFunction(this) and + f = i.getAnAssocItem() + | + this.hasUnknownTypeAt(i, f, pos, path) + ) + } + } + + private class NonAssocFunctionCallAccess extends Access instanceof NonAssocCallExpr, + CallExprImpl::CallExprCall + { + pragma[nomagic] + override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + result = NonAssocCallExpr.super.getTypeArgument(apos, path) + } + + override AstNode getNodeAt(FunctionPosition pos) { + result = NonAssocCallExpr.super.getNodeAt(pos) + } + + pragma[nomagic] + private Type getInferredType(FunctionPosition pos, TypePath path) { + result = super.getInferredType(pos, path) + } + + bindingset[derefChainBorrow] + override Type getInferredType(string derefChainBorrow, FunctionPosition pos, TypePath path) { + exists(derefChainBorrow) and + result = this.getInferredType(pos, path) + } + + pragma[nomagic] + private Declaration getTarget() { + result = + TFunctionDeclaration(ImplOrTraitItemNodeOption::none_(), + super.resolveCallTargetViaPathResolution()) + } + + override Declaration getTarget(string derefChainBorrow) { + result = this.getTarget() and + derefChainBorrow = noDerefChainBorrow() + } + + pragma[nomagic] + override predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path) { + derefChainBorrow = noDerefChainBorrow() and + exists(FunctionDeclaration f, TypeParameter tp | + f = super.resolveCallTargetViaPathResolution() and + pos.isReturn() and + tp = f.getReturnType(_, path) and + not tp = f.getParameterType(_, _, _) and + // check that no explicit type arguments have been supplied for `tp` + not exists(TypeArgumentPosition tapos | + this.hasTypeArgument(tapos) and + TTypeParamTypeParameter(tapos.asTypeParam()) = tp + ) + ) } } } -private module MethodCallMatching = MatchingWithEnvironment; +private module FunctionCallMatching = MatchingWithEnvironment; pragma[nomagic] -private Type inferMethodCallType0( - MethodCallMatchingInput::Access a, MethodCallMatchingInput::AccessPosition apos, AstNode n, - string derefChainBorrow, TypePath path +private Type inferFunctionCallType0( + FunctionCallMatchingInput::Access call, FunctionPosition pos, AstNode n, DerefChain derefChain, + BorrowKind borrow, TypePath path ) { exists(TypePath path0 | - n = a.getNodeAt(apos) and - ( - result = MethodCallMatching::inferAccessType(a, derefChainBorrow, apos, path0) + n = call.getNodeAt(pos) and + exists(string derefChainBorrow | + FunctionCallMatchingInput::decodeDerefChainBorrow(derefChainBorrow, derefChain, borrow) + | + result = FunctionCallMatching::inferAccessType(call, derefChainBorrow, pos, path0) or - a.hasUnknownTypeAt(derefChainBorrow, apos, path0) and + call.hasUnknownTypeAt(derefChainBorrow, pos, path0) and result = TUnknownType() ) | if // index expression `x[i]` desugars to `*x.index(i)`, so we must account for // the implicit deref - apos.isReturn() and - a instanceof IndexExpr + pos.isReturn() and + call instanceof IndexExpr then path0.isCons(getRefTypeParameter(_), path) else path = path0 ) } pragma[nomagic] -private Type inferMethodCallTypeNonSelf(AstNode n, FunctionPosition pos, TypePath path) { - result = inferMethodCallType0(_, pos, n, _, path) and - not pos.isSelf() +private Type inferFunctionCallTypeNonSelf(AstNode n, FunctionPosition pos, TypePath path) { + exists(FunctionCallMatchingInput::Access call | + result = inferFunctionCallType0(call, pos, n, _, _, path) and + not call.(AssocFunctionResolution::AssocFunctionCall).hasReceiverAtPos(pos) + ) } /** @@ -2600,14 +2840,12 @@ private Type inferMethodCallTypeNonSelf(AstNode n, FunctionPosition pos, TypePat * empty, at which point the inferred type can be applied back to `n`. */ pragma[nomagic] -private Type inferMethodCallTypeSelf(MethodCall mc, AstNode n, DerefChain derefChain, TypePath path) { - exists( - MethodCallMatchingInput::AccessPosition apos, string derefChainBorrow, BorrowKind borrow, - TypePath path0 - | - result = inferMethodCallType0(mc, apos, n, derefChainBorrow, path0) and - apos.isSelf() and - MethodCallMatchingInput::decodeDerefChainBorrow(derefChainBorrow, derefChain, borrow) +private Type inferFunctionCallTypeSelf( + FunctionCallMatchingInput::Access call, AstNode n, DerefChain derefChain, TypePath path +) { + exists(FunctionPosition pos, BorrowKind borrow, TypePath path0 | + call.(AssocFunctionResolution::AssocFunctionCall).hasReceiverAtPos(pos) and + result = inferFunctionCallType0(call, pos, n, derefChain, borrow, path0) | borrow.isNoBorrow() and path = path0 @@ -2624,7 +2862,7 @@ private Type inferMethodCallTypeSelf(MethodCall mc, AstNode n, DerefChain derefC DerefChain derefChain0, Type t0, TypePath path0, DerefImplItemNode impl, Type selfParamType, TypePath selfPath | - t0 = inferMethodCallTypeSelf(mc, n, derefChain0, path0) and + t0 = inferFunctionCallTypeSelf(call, n, derefChain0, path0) and derefChain0.isCons(impl, derefChain) and selfParamType = impl.resolveSelfTypeAt(selfPath) | @@ -2641,454 +2879,36 @@ private Type inferMethodCallTypeSelf(MethodCall mc, AstNode n, DerefChain derefC ) } -private Type inferMethodCallTypePreCheck(AstNode n, FunctionPosition pos, TypePath path) { - result = inferMethodCallTypeNonSelf(n, pos, path) +private Type inferFunctionCallTypePreCheck( + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path +) { + result = inferFunctionCallTypeNonSelf(n, pos, path) and + hasReceiver = false or - exists(MethodCall mc | - result = inferMethodCallTypeSelf(mc, n, DerefChain::nil(), path) and - if mc instanceof CallExpr then pos.asPosition() = 0 else pos.isSelf() + exists(FunctionCallMatchingInput::Access a | + result = inferFunctionCallTypeSelf(a, n, DerefChain::nil(), path) and + pos.asPosition() = 0 and + if a.(AssocFunctionResolution::AssocFunctionCall).hasReceiver() + then hasReceiver = true + else hasReceiver = false ) } /** - * Gets the type of `n` at `path`, where `n` is either a method call or an - * argument/receiver of a method call. + * Gets the type of `n` at `path`, where `n` is either a function call or an + * argument/receiver of a function call. */ -private predicate inferMethodCallType = - ContextTyping::CheckContextTyping::check/2; +private predicate inferFunctionCallType = + ContextTyping::CheckContextTyping::check/2; -/** - * Provides logic for resolving calls to non-method items. This includes - * "calls" to tuple variants and tuple structs. - */ -private module NonMethodResolution { - pragma[nomagic] - private predicate traitFunctionResolutionDependsOnArgument0( - TraitItemNode trait, NonMethodFunction traitFunction, FunctionPosition pos, ImplItemNode impl, - NonMethodFunction implFunction, TypePath path, TypeParameter traitTp - ) { - implFunction = impl.getAnAssocItem() and - implFunction.implements(traitFunction) and - FunctionOverloading::traitTypeParameterOccurrence(trait, traitFunction, _, pos, path, traitTp) and - ( - traitTp = TSelfTypeParameter(trait) - or - FunctionOverloading::functionResolutionDependsOnArgument(impl, implFunction, traitTp, pos) - ) - } - - /** - * Holds if resolving the function `implFunction` in `impl` requires inspecting - * the type of applied _arguments_ or possibly knowing the return type. - * - * `traitTp` is a type parameter of the trait being implemented by `impl`, and - * we need to check that the type of `f` corresponding to `traitTp` is satisfied - * at any one of the positions `pos` in which that type occurs in `f` (at `path`). - * - * As for method resolution, we always check the type being implemented (corresponding - * to `traitTp` being the special `Self` type parameter). - */ - pragma[nomagic] - private predicate traitFunctionResolutionDependsOnArgument( - TraitItemNode trait, NonMethodFunction traitFunction, FunctionPosition pos, ImplItemNode impl, - NonMethodFunction implFunction, TypePath path, TypeParameter traitTp - ) { - traitFunctionResolutionDependsOnArgument0(trait, traitFunction, pos, impl, implFunction, path, - traitTp) and - // Exclude functions where we cannot resolve all relevant type mentions; this allows - // for blanket implementations to be applied in those cases - forall(TypeParameter traitTp0 | - traitFunctionResolutionDependsOnArgument0(trait, traitFunction, _, impl, implFunction, _, - traitTp0) - | - exists(FunctionPosition pos0, TypePath path0 | - traitFunctionResolutionDependsOnArgument0(trait, traitFunction, pos0, impl, implFunction, - path0, traitTp0) and - exists(getAssocFunctionTypeAt(implFunction, impl, pos0, path0)) - ) - ) - } - - /** - * Holds if `f` inside `i` either implements trait function `traitFunction` inside `trait` - * or is equal to `traitFunction`, and the type of `f` at `pos` and `path` is `t`, which - * corresponds to the `Self` type parameter of `trait`. - */ - pragma[nomagic] - private predicate traitFunctionHasSelfType( - TraitItemNode trait, NonMethodFunction traitFunction, FunctionPosition pos, TypePath path, - Type t, ImplOrTraitItemNode i, NonMethodFunction f - ) { - exists(ImplItemNode impl, NonMethodFunction implFunction, AssocFunctionType aft | - traitFunctionResolutionDependsOnArgument(trait, traitFunction, pos, impl, implFunction, path, - TSelfTypeParameter(trait)) and - aft.appliesTo(f, i, pos) and - t = aft.getTypeAt(path) - | - i = trait and - f = traitFunction - or - i = impl and - f = implFunction and - not BlanketImplementation::isBlanketLike(i, _, _) - ) - } - - pragma[nomagic] - private predicate functionResolutionDependsOnArgument( - ImplItemNode impl, NonMethodFunction f, FunctionPosition pos, TypeParameter tp - ) { - traitFunctionResolutionDependsOnArgument(_, _, pos, impl, f, _, tp) - or - // For inherent implementations of generic types, we also need to check the type being - // implemented. We arbitrarily choose the first type parameter of the type being implemented - // to represent this case. - f = impl.getAnAssocItem() and - not impl.(Impl).hasTrait() and - tp = TTypeParamTypeParameter(impl.resolveSelfTy().getTypeParam(0)) and - pos.isTypeQualifier() - } - - pragma[nomagic] - private predicate functionInfoBlanketLikeRelevantPos( - NonMethodFunction f, string name, int arity, ImplItemNode impl, Trait trait, - FunctionPosition pos, AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam - ) { - functionInfoBlanketLike(f, name, arity, impl, trait, pos, t, blanketPath, blanketTypeParam) and - ( - if pos.isReturn() - then - // We only check that the context of the call provides relevant type information - // when no argument can - not exists(FunctionPosition pos0 | - functionInfoBlanketLike(f, name, arity, impl, trait, pos0, _, _, _) and - not pos0.isReturn() - ) - else any() - ) - } - - pragma[nomagic] - private predicate blanketLikeCallTraitCandidate(Element fc, Trait trait) { - fc = - any(NonMethodCall nmc | - exists(string name, int arity | - nmc.hasNameAndArity(name, arity) and - functionInfoBlanketLikeRelevantPos(_, name, arity, _, trait, _, _, _, _) - | - not nmc.hasTrait() - or - trait = nmc.getTrait() - ) - ) - } - - private module BlanketTraitIsVisible = TraitIsVisible; - - /** A (potential) non-method call, `f(x)`. */ - final class NonMethodCall extends CallExpr { - NonMethodCall() { - // even if a function cannot be resolved by path resolution, it may still - // be possible to resolve a blanket implementation (so not `forex`) - forall(Function f | f = CallExprImpl::getResolvedFunction(this) | - f instanceof NonMethodFunction - ) - } - - pragma[nomagic] - predicate hasNameAndArity(string name, int arity) { - name = CallExprImpl::getFunctionPath(this).getText() and - arity = this.getArgList().getNumberOfArgs() - } - - /** - * Gets the item that this function call resolves to using path resolution, - * if any. - */ - private ItemNode getPathResolutionResolved() { - result = CallExprImpl::getResolvedFunction(this) and - not result.(Function).hasSelfParam() - } - - /** - * Gets the associated function that this function call resolves to using path - * resolution, if any. - */ - pragma[nomagic] - NonMethodFunction getPathResolutionResolved(ImplOrTraitItemNode i) { - result = this.getPathResolutionResolved() and - result = i.getAnAssocItem() - } - - /** - * Gets the blanket function that this call may resolve to, if any. - */ - pragma[nomagic] - NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) { - exists(string name | - this.hasNameAndArity(pragma[only_bind_into](name), _) and - ArgIsInstantiationOfBlanketParam::argIsInstantiationOf(MkCallAndBlanketPos(this, _), impl, _) and - result = impl.getASuccessor(pragma[only_bind_into](name)) - ) - } - - /** Gets the trait targeted by this call, if any. */ - Trait getTrait() { result = getCallExprTraitQualifier(this) } - - /** Holds if this call targets a trait. */ - predicate hasTrait() { exists(this.getTrait()) } - - AstNode getNodeAt(FunctionPosition pos) { - result = this.getSyntacticArgument(pos.asArgumentPosition()) - or - result = this and pos.isReturn() - } - - Type getTypeAt(FunctionPosition pos, TypePath path) { - result = inferType(this.getNodeAt(pos), path) - } - - pragma[nomagic] - NonMethodFunction resolveCallTargetNonBlanketCand(ImplItemNode i) { - not this.hasTrait() and - result = this.getPathResolutionResolved(i) and - not exists(this.resolveCallTargetViaPathResolution()) and - functionResolutionDependsOnArgument(i, result, _, _) - } - - pragma[nomagic] - predicate resolveCallTargetBlanketLikeCand( - ImplItemNode impl, FunctionPosition pos, TypePath blanketPath, TypeParam blanketTypeParam - ) { - exists(string name, int arity, Trait trait, AssocFunctionType t | - this.hasNameAndArity(name, arity) and - exists(this.getTypeAt(pos, blanketPath)) and - functionInfoBlanketLikeRelevantPos(_, name, arity, impl, trait, pos, t, blanketPath, - blanketTypeParam) and - BlanketTraitIsVisible::traitIsVisible(this, trait) - | - not this.hasTrait() - or - trait = this.getTrait() - ) - } - - pragma[nomagic] - predicate hasTraitResolved(TraitItemNode trait, NonMethodFunction resolved) { - resolved = this.getPathResolutionResolved() and - trait = this.getTrait() - } - - /** - * Holds if this call has no compatible non-blanket target, and it has some - * candidate blanket target. - */ - pragma[nomagic] - predicate hasNoCompatibleNonBlanketTarget() { - this.resolveCallTargetBlanketLikeCand(_, _, _, _) and - not exists(this.resolveCallTargetViaPathResolution()) and - forall(ImplOrTraitItemNode i, Function f | f = this.resolveCallTargetNonBlanketCand(i) | - NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f) - ) and - ( - not this.hasTraitResolved(_, _) - or - exists( - TraitItemNode trait, NonMethodFunction resolved, FunctionPosition pos, TypePath path, - Type t - | - this.(NonMethodArgsAreInstantiationsOfNonBlanketInput::Call) - .hasTraitResolvedSelfType(trait, resolved, pos, path, t) - | - forall(ImplOrTraitItemNode i, Function f | - traitFunctionHasSelfType(trait, resolved, pos, path, t, i, f) - | - NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f) - ) - ) - ) - } - - /** - * Gets the target of this call, which can be resolved using only path resolution. - */ - pragma[nomagic] - ItemNode resolveCallTargetViaPathResolution() { - not this.hasTrait() and - result = this.getPathResolutionResolved() and - not functionResolutionDependsOnArgument(_, result, _, _) - } - - /** - * Gets the target of this call, which can be resolved using type inference. - */ - pragma[nomagic] - NonMethodFunction resolveCallTargetViaTypeInference(ImplOrTraitItemNode i) { - result = this.resolveCallTargetBlanketCand(i) and - not FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _) - or - NonMethodArgsAreInstantiationsOfBlanket::argsAreInstantiationsOf(this, i, result) - or - NonMethodArgsAreInstantiationsOfNonBlanket::argsAreInstantiationsOf(this, i, result) - } - } - - private newtype TCallAndBlanketPos = - MkCallAndBlanketPos(NonMethodCall fc, FunctionPosition pos) { - fc.resolveCallTargetBlanketLikeCand(_, pos, _, _) - } - - /** A call tagged with a position. */ - private class CallAndBlanketPos extends MkCallAndBlanketPos { - NonMethodCall fc; - FunctionPosition pos; - - CallAndBlanketPos() { this = MkCallAndBlanketPos(fc, pos) } - - Location getLocation() { result = fc.getLocation() } - - Type getTypeAt(TypePath path) { result = fc.getTypeAt(pos, path) } - - string toString() { result = fc.toString() + " [arg " + pos + "]" } - } - - private module ArgSatisfiesBlanketConstraintInput implements - BlanketImplementation::SatisfiesBlanketConstraintInputSig - { - pragma[nomagic] - predicate hasBlanketCandidate( - CallAndBlanketPos fcp, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam - ) { - exists(NonMethodCall fc, FunctionPosition pos | - fcp = MkCallAndBlanketPos(fc, pos) and - fc.resolveCallTargetBlanketLikeCand(impl, pos, blanketPath, blanketTypeParam) and - // Only apply blanket implementations when no other implementations are possible; - // this is to account for codebases that use the (unstable) specialization feature - // (https://rust-lang.github.io/rfcs/1210-impl-specialization.html), as well as - // cases where our blanket implementation filtering is not precise enough. - (fc.hasNoCompatibleNonBlanketTarget() or not impl.isBlanketImplementation()) - ) - } - } - - private module ArgSatisfiesBlanketConstraint = - BlanketImplementation::SatisfiesBlanketConstraint; - - /** - * A configuration for matching the type of an argument against the type of - * a parameter that mentions a satisfied blanket type parameter. - */ - private module ArgIsInstantiationOfBlanketParamInput implements - IsInstantiationOfInputSig - { - pragma[nomagic] - predicate potentialInstantiationOf( - CallAndBlanketPos fcp, TypeAbstraction abs, AssocFunctionType constraint - ) { - exists(FunctionPosition pos | - ArgSatisfiesBlanketConstraint::satisfiesBlanketConstraint(fcp, abs) and - fcp = MkCallAndBlanketPos(_, pos) and - functionInfoBlanketLikeRelevantPos(_, _, _, abs, _, pos, constraint, _, _) - ) - } - - predicate relevantConstraint(AssocFunctionType constraint) { - functionInfoBlanketLikeRelevantPos(_, _, _, _, _, _, constraint, _, _) - } - } - - private module ArgIsInstantiationOfBlanketParam = - ArgIsInstantiationOf; - - private Type getArgType( - NonMethodCall call, FunctionPosition pos, TypePath path, boolean isDefaultTypeArg - ) { - result = inferType(call.getNodeAt(pos), path) and - isDefaultTypeArg = false - or - result = getCallExprTypeQualifier(call, path, isDefaultTypeArg) and - pos.isTypeQualifier() - } - - private module NonMethodArgsAreInstantiationsOfBlanketInput implements - ArgsAreInstantiationsOfInputSig - { - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos) { - functionResolutionDependsOnArgument(i, f, pos, tp) - } - - final class Call extends NonMethodCall { - Type getArgType(FunctionPosition pos, TypePath path) { - result = getArgType(this, pos, path, false) - } - - predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { - f = this.resolveCallTargetBlanketCand(i) - } - } - } - - private module NonMethodArgsAreInstantiationsOfBlanket = - ArgsAreInstantiationsOf; - - private module NonMethodArgsAreInstantiationsOfNonBlanketInput implements - ArgsAreInstantiationsOfInputSig - { - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) { - functionResolutionDependsOnArgument(i, f, pos, traitTp) - or - // Also match against the trait function itself - FunctionOverloading::traitTypeParameterOccurrence(i, f, _, pos, _, traitTp) and - traitTp = TSelfTypeParameter(i) - } - - class Call extends NonMethodCall { - Type getArgType(FunctionPosition pos, TypePath path) { - result = getArgType(this, pos, path, _) - } - - /** - * Holds if this call is of the form `Trait::function(args)`, and the type at `pos` and - * `path` matches the `Self` type parameter of `Trait`. - */ - pragma[nomagic] - predicate hasTraitResolvedSelfType( - TraitItemNode trait, NonMethodFunction function, FunctionPosition pos, TypePath path, Type t - ) { - this.hasTraitResolved(trait, function) and - FunctionOverloading::traitTypeParameterOccurrence(trait, function, _, pos, path, - TSelfTypeParameter(trait)) and - t = substituteLookupTraits(this.getArgType(pos, path)) and - t != TUnknownType() - } - - predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { - f = this.resolveCallTargetNonBlanketCand(i) - or - exists( - TraitItemNode trait, NonMethodFunction resolved, FunctionPosition pos, TypePath path, - Type t - | - this.hasTraitResolvedSelfType(trait, resolved, pos, path, t) and - traitFunctionHasSelfType(trait, resolved, pos, path, t, i, f) - ) - } - } - } - - private module NonMethodArgsAreInstantiationsOfNonBlanket = - ArgsAreInstantiationsOf; -} - -abstract private class TupleLikeConstructor extends Addressable { +abstract private class Constructor extends Addressable { final TypeParameter getTypeParameter(TypeParameterPosition ppos) { typeParamMatchPosition(this.getTypeItem().getGenericParamList().getATypeParam(), result, ppos) } abstract TypeItem getTypeItem(); - abstract TupleField getTupleField(int i); + abstract TypeRepr getParameterTypeRepr(int pos); Type getReturnType(TypePath path) { result = TDataType(this.getTypeItem()) and @@ -3099,174 +2919,63 @@ abstract private class TupleLikeConstructor extends Addressable { } Type getDeclaredType(FunctionPosition pos, TypePath path) { - result = this.getParameterType(pos, path) + result = this.getParameterType(pos.asPosition(), path) or pos.isReturn() and result = this.getReturnType(path) - or - pos.isSelf() and - result = this.getReturnType(path) } - Type getParameterType(FunctionPosition pos, TypePath path) { - result = this.getTupleField(pos.asPosition()).getTypeRepr().(TypeMention).getTypeAt(path) + Type getParameterType(int pos, TypePath path) { + result = this.getParameterTypeRepr(pos).(TypeMention).getTypeAt(path) } } -private class TupleLikeStruct extends TupleLikeConstructor instanceof Struct { - TupleLikeStruct() { this.isTuple() } - +private class StructConstructor extends Constructor instanceof Struct { override TypeItem getTypeItem() { result = this } - override TupleField getTupleField(int i) { result = Struct.super.getTupleField(i) } + override TypeRepr getParameterTypeRepr(int i) { + result = [super.getTupleField(i).getTypeRepr(), super.getNthStructField(i).getTypeRepr()] + } } -private class TupleLikeVariant extends TupleLikeConstructor instanceof Variant { - TupleLikeVariant() { this.isTuple() } - +private class VariantConstructor extends Constructor instanceof Variant { override TypeItem getTypeItem() { result = super.getEnum() } - override TupleField getTupleField(int i) { result = Variant.super.getTupleField(i) } + override TypeRepr getParameterTypeRepr(int i) { + result = [super.getTupleField(i).getTypeRepr(), super.getNthStructField(i).getTypeRepr()] + } } /** - * A matching configuration for resolving types of calls like - * `foo::bar(baz)` where the target is not a method. - * - * This also includes "calls" to tuple variants and tuple structs such - * as `Result::Ok(42)`. + * A matching configuration for resolving types of constructions of enums and + * structs, such as `Result::Ok(42)`, `Foo { bar: 1 }` and `None`. */ -private module NonMethodCallMatchingInput implements MatchingInputSig { +private module ConstructionMatchingInput implements MatchingInputSig { import FunctionPositionMatchingInput - private class NonMethodFunctionDeclaration extends NonMethodFunction, FunctionDeclaration { } + class Declaration = Constructor; - private newtype TDeclaration = - TNonMethodFunctionDeclaration(ImplOrTraitItemNodeOption i, NonMethodFunctionDeclaration f) { - f.isFor(i) - } or - TTupleLikeConstructorDeclaration(TupleLikeConstructor tc) + abstract class Access extends AstNode { + abstract Type getInferredType(FunctionPosition pos, TypePath path); - abstract class Declaration extends TDeclaration { - abstract TypeParameter getTypeParameter(TypeParameterPosition ppos); + abstract Declaration getTarget(); - pragma[nomagic] - abstract Type getParameterType(DeclarationPosition dpos, TypePath path); + abstract AstNode getNodeAt(AccessPosition apos); - abstract Type getReturnType(TypePath path); - - Type getDeclaredType(DeclarationPosition dpos, TypePath path) { - result = this.getParameterType(dpos, path) - or - dpos.isReturn() and - result = this.getReturnType(path) - } - - abstract string toString(); - - abstract Location getLocation(); - } - - private class NonMethodFunctionDecl extends Declaration, TNonMethodFunctionDeclaration { - private ImplOrTraitItemNodeOption i; - private NonMethodFunctionDeclaration f; - - NonMethodFunctionDecl() { this = TNonMethodFunctionDeclaration(i, f) } - - override TypeParameter getTypeParameter(TypeParameterPosition ppos) { - result = f.getTypeParameter(i, ppos) - } - - override Type getParameterType(DeclarationPosition dpos, TypePath path) { - result = f.getParameterType(i, dpos, path) - } - - override Type getReturnType(TypePath path) { result = f.getReturnType(i, path) } - - override string toString() { - i.isNone() and result = f.toString() - or - result = f.toStringExt(i.asSome()) - } - - override Location getLocation() { result = f.getLocation() } - } - - private class TupleLikeConstructorDeclaration extends Declaration, - TTupleLikeConstructorDeclaration - { - TupleLikeConstructor tc; - - TupleLikeConstructorDeclaration() { this = TTupleLikeConstructorDeclaration(tc) } - - override TypeParameter getTypeParameter(TypeParameterPosition ppos) { - result = tc.getTypeParameter(ppos) - } - - override Type getParameterType(DeclarationPosition dpos, TypePath path) { - result = tc.getParameterType(dpos, path) - } - - override Type getReturnType(TypePath path) { result = tc.getReturnType(path) } - - override string toString() { result = tc.toString() } - - override Location getLocation() { result = tc.getLocation() } - } - - class Access extends NonMethodResolution::NonMethodCall, ContextTyping::ContextTypedCallCand { - pragma[nomagic] - override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { - result = getCallExprTypeArgument(this, apos, path) - } - - pragma[nomagic] - Type getInferredType(AccessPosition apos, TypePath path) { - apos.isTypeQualifier() and - result = getCallExprTypeQualifier(this, path, false) - or - result = inferType(this.getNodeAt(apos), path) - } - - pragma[inline] - Declaration getTarget() { - exists(ImplOrTraitItemNodeOption i, NonMethodFunctionDeclaration f | - result = TNonMethodFunctionDeclaration(i, f) - | - f = this.resolveCallTargetViaTypeInference(i.asSome()) // mutual recursion; resolving some associated function calls requires resolving types - or - f = this.resolveCallTargetViaPathResolution() and - f.isDirectlyFor(i) - ) - or - exists(ItemNode i | i = this.resolveCallTargetViaPathResolution() | - result = TTupleLikeConstructorDeclaration(i) - ) - } + abstract Type getTypeArgument(TypeArgumentPosition apos, TypePath path); /** - * Holds if the return type of this call at `path` may have to be inferred - * from the context. + * Holds if the return type of this construction expression at `path` may + * have to be inferred from the context. For example in `Result::Ok(42)` the + * error type has to be inferred from the context. */ pragma[nomagic] predicate hasUnknownTypeAt(FunctionPosition pos, TypePath path) { - exists(ImplOrTraitItemNodeOption i, NonMethodFunctionDeclaration f | - TNonMethodFunctionDeclaration(i, f) = this.getTarget() and - this.hasUnknownTypeAt(i.asSome(), f, pos, path) - ) - or - forex(ImplOrTraitItemNode i, NonMethodFunctionDeclaration f | - f = this.getPathResolutionResolved(i) - | - this.hasUnknownTypeAt(i, f, pos, path) - ) - or - // Tuple declarations, such as `Result::Ok(...)`, may also be context typed - exists(TupleLikeConstructor tc, TypeParameter tp | - tc = this.resolveCallTargetViaPathResolution() and + exists(Declaration d, TypeParameter tp | + d = this.getTarget() and pos.isReturn() and - tp = tc.getReturnType(path) and - not tp = tc.getParameterType(_, _) and + tp = d.getReturnType(path) and + not exists(FunctionPosition pos2 | not pos2.isReturn() and tp = d.getDeclaredType(pos2, _)) and // check that no explicit type arguments have been supplied for `tp` not exists(TypeArgumentPosition tapos | exists(this.getTypeArgument(tapos, _)) and @@ -3275,22 +2984,93 @@ private module NonMethodCallMatchingInput implements MatchingInputSig { ) } } + + private class NonAssocCallAccess extends Access, NonAssocCallExpr, + ContextTyping::ContextTypedCallCand + { + NonAssocCallAccess() { + this instanceof CallExprImpl::TupleStructExpr or + this instanceof CallExprImpl::TupleVariantExpr + } + + override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + result = NonAssocCallExpr.super.getTypeArgument(apos, path) + } + + override AstNode getNodeAt(AccessPosition apos) { + result = NonAssocCallExpr.super.getNodeAt(apos) + } + + override Type getInferredType(FunctionPosition pos, TypePath path) { + result = NonAssocCallExpr.super.getInferredType(pos, path) + } + + override Declaration getTarget() { result = this.resolveCallTargetViaPathResolution() } + } + + abstract private class StructAccess extends Access instanceof PathAstNode { + pragma[nomagic] + override Type getInferredType(AccessPosition apos, TypePath path) { + result = inferType(this.getNodeAt(apos), path) + } + + pragma[nomagic] + override Declaration getTarget() { result = resolvePath(super.getPath()) } + + pragma[nomagic] + override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + // Handle constructions that use `Self {...}` syntax + exists(TypeMention tm, TypePath path0 | + tm = super.getPath() and + result = tm.getTypeAt(path0) and + path0.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) + ) + } + } + + private class StructExprAccess extends StructAccess, StructExpr { + override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + result = super.getTypeArgument(apos, path) + or + exists(TypePath suffix | + suffix.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) and + result = CertainTypeInference::inferCertainType(this, suffix) + ) + } + + override AstNode getNodeAt(AccessPosition apos) { + result = + this.getFieldExpr(this.getNthStructField(apos.asPosition()).getName().getText()).getExpr() + or + result = this and apos.isReturn() + } + } + + /** A potential nullary struct/variant construction such as `None`. */ + private class PathExprAccess extends StructAccess, PathExpr { + PathExprAccess() { not exists(CallExpr ce | this = ce.getFunction()) } + + override AstNode getNodeAt(AccessPosition apos) { result = this and apos.isReturn() } + } } -private module NonMethodCallMatching = Matching; +private module ConstructionMatching = Matching; pragma[nomagic] -private Type inferNonMethodCallType0(AstNode n, FunctionPosition pos, TypePath path) { - exists(NonMethodCallMatchingInput::Access a | n = a.getNodeAt(pos) | - result = NonMethodCallMatching::inferAccessType(a, pos, path) +private Type inferConstructionTypePreCheck( + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path +) { + hasReceiver = false and + exists(ConstructionMatchingInput::Access a | n = a.getNodeAt(pos) | + result = ConstructionMatching::inferAccessType(a, pos, path) or a.hasUnknownTypeAt(pos, path) and result = TUnknownType() ) } -private predicate inferNonMethodCallType = - ContextTyping::CheckContextTyping::check/2; +private predicate inferConstructionType = + ContextTyping::CheckContextTyping::check/2; /** * A matching configuration for resolving types of operations like `a + b`. @@ -3299,22 +3079,22 @@ private module OperationMatchingInput implements MatchingInputSig { private import codeql.rust.elements.internal.OperationImpl::Impl as OperationImpl import FunctionPositionMatchingInput - class Declaration extends MethodCallMatchingInput::Declaration { + class Declaration extends FunctionCallMatchingInput::Declaration { private Method getSelfOrImpl() { - result = m + result = f or - m.implements(result) + f.implements(result) } pragma[nomagic] - private predicate borrowsAt(DeclarationPosition pos) { + private predicate borrowsAt(FunctionPosition pos) { exists(TraitItemNode t, string path, string method | this.getSelfOrImpl() = t.getAssocItem(method) and path = t.getCanonicalPath(_) and exists(int borrows | OperationImpl::isOverloaded(_, _, path, method, borrows) | - pos.isSelf() and borrows >= 1 + pos.asPosition() = 0 and borrows >= 1 or - pos.asPosition() = 0 and + pos.asPosition() = 1 and borrows >= 2 ) ) @@ -3323,30 +3103,30 @@ private module OperationMatchingInput implements MatchingInputSig { pragma[nomagic] private predicate derefsReturn() { this.getSelfOrImpl() = any(DerefTrait t).getDerefFunction() } - Type getDeclaredType(DeclarationPosition dpos, TypePath path) { + Type getDeclaredType(FunctionPosition pos, TypePath path) { exists(TypePath path0 | - result = super.getDeclaredType(dpos, path0) and + result = super.getDeclaredType(pos, path0) and if - this.borrowsAt(dpos) + this.borrowsAt(pos) or - dpos.isReturn() and this.derefsReturn() + pos.isReturn() and this.derefsReturn() then path0.isCons(getRefTypeParameter(_), path) else path0 = path ) } } - class Access extends MethodResolution::MethodCallOperation { + class Access extends AssocFunctionResolution::AssocFunctionCallOperation { Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } pragma[nomagic] - Type getInferredType(AccessPosition apos, TypePath path) { - result = inferType(this.getNodeAt(apos), path) + Type getInferredType(FunctionPosition pos, TypePath path) { + result = inferType(this.getNodeAt(pos), path) } Declaration getTarget() { exists(ImplOrTraitItemNode i | - result.isMethod(i, this.resolveCallTarget(i, _, _)) // mutual recursion + result.isAssocFunction(i, this.resolveCallTarget(i, _, _, _)) // mutual recursion ) } } @@ -3355,15 +3135,18 @@ private module OperationMatchingInput implements MatchingInputSig { private module OperationMatching = Matching; pragma[nomagic] -private Type inferOperationType0(AstNode n, FunctionPosition pos, TypePath path) { +private Type inferOperationTypePreCheck( + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path +) { exists(OperationMatchingInput::Access a | n = a.getNodeAt(pos) and - result = OperationMatching::inferAccessType(a, pos, path) + result = OperationMatching::inferAccessType(a, pos, path) and + hasReceiver = true ) } private predicate inferOperationType = - ContextTyping::CheckContextTyping::check/2; + ContextTyping::CheckContextTyping::check/2; pragma[nomagic] private Type getFieldExprLookupType(FieldExpr fe, string name, DerefChain derefChain) { @@ -3773,100 +3556,57 @@ private Type inferDereferencedExprPtrType(AstNode n, TypePath path) { } /** - * A matching configuration for resolving types of struct patterns - * like `let Foo { bar } = ...`. + * A matching configuration for resolving types of deconstruction patterns like + * `let Foo { bar } = ...` or `let Some(x) = ...`. */ -private module StructPatMatchingInput implements MatchingInputSig { - class DeclarationPosition = StructExprMatchingInput::DeclarationPosition; - - class Declaration = StructExprMatchingInput::Declaration; - - class AccessPosition = DeclarationPosition; - - class Access extends StructPat { - Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } - - AstNode getNodeAt(AccessPosition apos) { - result = this.getPatField(apos.asFieldPos()).getPat() - or - result = this and - apos.isStructPos() - } - - Type getInferredType(AccessPosition apos, TypePath path) { - result = inferType(this.getNodeAt(apos), path) - or - // The struct/enum type is supplied explicitly as a type qualifier, e.g. - // `let Foo::Variant { ... } = ...`. - apos.isStructPos() and - result = this.getPath().(TypeMention).getTypeAt(path) - } - - Declaration getTarget() { result = resolvePath(this.getPath()) } - } - - predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) { - apos = dpos - } -} - -private module StructPatMatching = Matching; - -/** - * Gets the type of `n` at `path`, where `n` is either a struct pattern or - * a field pattern of a struct pattern. - */ -pragma[nomagic] -private Type inferStructPatType(AstNode n, TypePath path) { - exists(StructPatMatchingInput::Access a, StructPatMatchingInput::AccessPosition apos | - n = a.getNodeAt(apos) and - result = StructPatMatching::inferAccessType(a, apos, path) - ) -} - -/** - * A matching configuration for resolving types of tuple struct patterns - * like `let Some(x) = ...`. - */ -private module TupleStructPatMatchingInput implements MatchingInputSig { +private module DeconstructionPatMatchingInput implements MatchingInputSig { import FunctionPositionMatchingInput - class Declaration = TupleLikeConstructor; + class Declaration = ConstructionMatchingInput::Declaration; + + class Access extends Pat instanceof PathAstNode { + Access() { this instanceof TupleStructPat or this instanceof StructPat } - class Access extends TupleStructPat { Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } AstNode getNodeAt(AccessPosition apos) { - result = this.getField(apos.asPosition()) + this = + any(StructPat sp | + result = + sp.getPatField(sp.getNthStructField(apos.asPosition()).getName().getText()).getPat() + ) + or + result = this.(TupleStructPat).getField(apos.asPosition()) or result = this and - apos.isSelf() + apos.isReturn() } Type getInferredType(AccessPosition apos, TypePath path) { result = inferType(this.getNodeAt(apos), path) or // The struct/enum type is supplied explicitly as a type qualifier, e.g. + // `let Foo::::Variant { ... } = ...` or // `let Option::::Some(x) = ...`. - apos.isSelf() and - result = this.getPath().(TypeMention).getTypeAt(path) + apos.isReturn() and + result = super.getPath().(TypeMention).getTypeAt(path) } - Declaration getTarget() { result = resolvePath(this.getPath()) } + Declaration getTarget() { result = resolvePath(super.getPath()) } } } -private module TupleStructPatMatching = Matching; +private module DeconstructionPatMatching = Matching; /** - * Gets the type of `n` at `path`, where `n` is either a tuple struct pattern or - * a positional pattern of a tuple struct pattern. + * Gets the type of `n` at `path`, where `n` is a pattern for a constructor, + * either a struct pattern or a tuple-struct pattern. */ pragma[nomagic] -private Type inferTupleStructPatType(AstNode n, TypePath path) { - exists(TupleStructPatMatchingInput::Access a, TupleStructPatMatchingInput::AccessPosition apos | +private Type inferDeconstructionPatType(AstNode n, TypePath path) { + exists(DeconstructionPatMatchingInput::Access a, FunctionPosition apos | n = a.getNodeAt(apos) and - result = TupleStructPatMatching::inferAccessType(a, apos, path) + result = DeconstructionPatMatching::inferAccessType(a, apos, path) ) } @@ -4057,7 +3797,8 @@ private module Cached { cached predicate implicitDerefChainBorrow(Expr e, DerefChain derefChain, boolean borrow) { exists(BorrowKind bk | - any(MethodResolution::MethodCall mc).argumentHasImplicitDerefChainBorrow(e, derefChain, bk) and + any(AssocFunctionResolution::AssocFunctionCall afc) + .argumentHasImplicitDerefChainBorrow(e, derefChain, bk) and if bk.isNoBorrow() then borrow = false else borrow = true ) or @@ -4082,15 +3823,14 @@ private module Cached { cached Addressable resolveCallTarget(InvocationExpr call, boolean dispatch) { dispatch = false and - result = call.(NonMethodResolution::NonMethodCall).resolveCallTargetViaPathResolution() + result = call.(NonAssocCallExpr).resolveCallTargetViaPathResolution() or exists(ImplOrTraitItemNode i | i instanceof TraitItemNode and dispatch = true or i instanceof ImplItemNode and dispatch = false | - result = call.(MethodResolution::MethodCall).resolveCallTarget(i, _, _) or - result = call.(NonMethodResolution::NonMethodCall).resolveCallTargetViaTypeInference(i) + result = call.(AssocFunctionResolution::AssocFunctionCall).resolveCallTarget(i, _, _, _) ) } @@ -4177,11 +3917,9 @@ private module Cached { or result = inferTypeEquality(n, path) or - result = inferStructExprType(n, path) + result = inferFunctionCallType(n, path) or - result = inferMethodCallType(n, path) - or - result = inferNonMethodCallType(n, path) + result = inferConstructionType(n, path) or result = inferOperationType(n, path) or @@ -4203,9 +3941,7 @@ private module Cached { or result = inferClosureExprType(n, path) or - result = inferStructPatType(n, path) - or - result = inferTupleStructPatType(n, path) + result = inferDeconstructionPatType(n, path) ) } } @@ -4249,14 +3985,14 @@ private module Debug { t = self.getTypeAt(path) } - predicate debugInferMethodCallType(AstNode n, TypePath path, Type t) { + predicate debugInferFunctionCallType(AstNode n, TypePath path, Type t) { n = getRelevantLocatable() and - t = inferMethodCallType(n, path) + t = inferFunctionCallType(n, path) } - predicate debugInferNonMethodCallType(AstNode n, TypePath path, Type t) { + predicate debugInferConstructionType(AstNode n, TypePath path, Type t) { n = getRelevantLocatable() and - t = inferNonMethodCallType(n, path) + t = inferConstructionType(n, path) } predicate debugTypeMention(TypeMention tm, TypePath path, Type type) { diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll index 631add42d04..dcb3fc0b0f4 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll @@ -699,9 +699,13 @@ class PreTypeMention = PreTypeMention::TypeMention; /** * Holds if `path` accesses an associated type `alias` from `trait` on a * concrete type given by `tm`. + * + * `implOrTmTrait` is either the mention that resolves to `trait` when `path` + * is of the form `::AssocType`, or the enclosing `impl` block + * when `path` is of the form `Self::AssocType`. */ private predicate pathConcreteTypeAssocType( - Path path, PreTypeMention tm, TraitItemNode trait, PreTypeMention tmTrait, TypeAlias alias + Path path, PreTypeMention tm, TraitItemNode trait, AstNode implOrTmTrait, TypeAlias alias ) { exists(Path qualifier | qualifier = path.getQualifier() and @@ -710,19 +714,19 @@ private predicate pathConcreteTypeAssocType( // path of the form `::AssocType` // ^^^ tm ^^^^^^^^^ name exists(string name | - pathTypeAsTraitAssoc(path, tm, tmTrait, trait, name) and + pathTypeAsTraitAssoc(path, tm, implOrTmTrait, trait, name) and getTraitAssocType(trait, name) = alias ) or // path of the form `Self::AssocType` within an `impl` block // tm ^^^^ ^^^^^^^^^ name - exists(ImplItemNode impl | - alias = resolvePath(path) and - qualifier = impl.getASelfPath() and - tm = impl.(Impl).getSelfTy() and - trait.getAnAssocItem() = alias and - tmTrait = impl.getTraitPath() - ) + implOrTmTrait = + any(ImplItemNode impl | + alias = resolvePath(path) and + qualifier = impl.getASelfPath() and + tm = impl.(Impl).getSelfTy() and + trait.getAnAssocItem() = alias + ) ) } @@ -741,21 +745,26 @@ private module PathSatisfiesConstraint = */ private Type getPathConcreteAssocTypeAt(Path path, TypePath typePath) { exists( - PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitType t, PreTypeMention tmTrait, + PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitType t, AstNode implOrTmTrait, TypeAlias alias, TypePath path0 | - pathConcreteTypeAssocType(path, tm, trait, tmTrait, alias) and + pathConcreteTypeAssocType(path, tm, trait, implOrTmTrait, alias) and t = TTrait(trait) and PathSatisfiesConstraint::satisfiesConstraintTypeThrough(tm, impl, t, path0, result) and path0.isCons(TAssociatedTypeTypeParameter(trait, alias), typePath) | - tmTrait.getTypeAt(TypePath::nil()) != t + implOrTmTrait instanceof Impl or - not exists(TypePath path1, Type t1 | - t1 = impl.getTraitPath().(PreTypeMention).getTypeAt(path1) and - not t1 instanceof TypeParameter and - t1 != tmTrait.getTypeAt(path1) - ) + // When `path` is of the form `::AssocType` we need to check + // that `impl` is not more specific than the mentioned trait + implOrTmTrait = + any(PreTypeMention tmTrait | + not exists(TypePath path1, Type t1 | + t1 = impl.getTraitPath().(PreTypeMention).getTypeAt(path1) and + not t1 instanceof TypeParameter and + t1 != tmTrait.getTypeAt(path1) + ) + ) ) } diff --git a/rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..8bfc5be1551 --- /dev/null +++ b/rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `rust/log-injection` has been increased from 2.6 (low) to 6.1 (medium). +* The `@security-severity` metadata of `rust/xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/rust/ql/src/queries/security/CWE-079/XSS.ql b/rust/ql/src/queries/security/CWE-079/XSS.ql index 3c43f5043c7..e7609196b3e 100644 --- a/rust/ql/src/queries/security/CWE-079/XSS.ql +++ b/rust/ql/src/queries/security/CWE-079/XSS.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id rust/xss * @tags security diff --git a/rust/ql/src/queries/security/CWE-117/LogInjection.ql b/rust/ql/src/queries/security/CWE-117/LogInjection.ql index 64d9c47c790..c00ac310ef6 100644 --- a/rust/ql/src/queries/security/CWE-117/LogInjection.ql +++ b/rust/ql/src/queries/security/CWE-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @security-severity 2.6 + * @security-severity 6.1 * @precision medium * @id rust/log-injection * @tags security diff --git a/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected index 8ca58acd1d0..e69de29bb2d 100644 --- a/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected @@ -1,6 +0,0 @@ -multipleResolvedTargets -| test.rs:389:30:389:67 | pinned.poll_read(...) | -| test.rs:416:26:416:54 | pinned.poll_fill_buf(...) | -| test.rs:423:27:423:71 | ... .poll_fill_buf(...) | -| test.rs:447:30:447:67 | pinned.poll_read(...) | -| test.rs:470:26:470:54 | pinned.poll_fill_buf(...) | diff --git a/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected b/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected index 255af4cc86e..763bff966d3 100644 --- a/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected +++ b/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected @@ -100,7 +100,9 @@ edges | main.rs:161:10:161:18 | source(...) | main.rs:161:10:161:25 | ... .shr(...) | provenance | MaD:30 | | main.rs:162:19:162:27 | source(...) | main.rs:162:10:162:28 | 1i64.shr(...) | provenance | MaD:30 | | main.rs:164:10:164:18 | source(...) | main.rs:164:10:164:30 | ... .bitor(...) | provenance | MaD:19 | +| main.rs:165:10:165:18 | source(...) | main.rs:165:10:165:27 | ... .bitor(...) | provenance | MaD:19 | | main.rs:166:21:166:29 | source(...) | main.rs:166:10:166:30 | 1i64.bitor(...) | provenance | MaD:19 | +| main.rs:167:18:167:26 | source(...) | main.rs:167:10:167:27 | 1.bitor(...) | provenance | MaD:19 | | main.rs:170:5:170:5 | [post] a | main.rs:171:5:171:5 | a | provenance | | | main.rs:170:5:170:5 | [post] a | main.rs:172:5:172:5 | a | provenance | | | main.rs:170:5:170:5 | [post] a | main.rs:173:5:173:5 | a | provenance | | @@ -351,8 +353,12 @@ nodes | main.rs:162:19:162:27 | source(...) | semmle.label | source(...) | | main.rs:164:10:164:18 | source(...) | semmle.label | source(...) | | main.rs:164:10:164:30 | ... .bitor(...) | semmle.label | ... .bitor(...) | +| main.rs:165:10:165:18 | source(...) | semmle.label | source(...) | +| main.rs:165:10:165:27 | ... .bitor(...) | semmle.label | ... .bitor(...) | | main.rs:166:10:166:30 | 1i64.bitor(...) | semmle.label | 1i64.bitor(...) | | main.rs:166:21:166:29 | source(...) | semmle.label | source(...) | +| main.rs:167:10:167:27 | 1.bitor(...) | semmle.label | 1.bitor(...) | +| main.rs:167:18:167:26 | source(...) | semmle.label | source(...) | | main.rs:170:5:170:5 | [post] a | semmle.label | [post] a | | main.rs:170:18:170:26 | source(...) | semmle.label | source(...) | | main.rs:171:5:171:5 | [post] a | semmle.label | [post] a | @@ -516,7 +522,9 @@ testFailures | main.rs:161:10:161:25 | ... .shr(...) | main.rs:161:10:161:18 | source(...) | main.rs:161:10:161:25 | ... .shr(...) | $@ | main.rs:161:10:161:18 | source(...) | source(...) | | main.rs:162:10:162:28 | 1i64.shr(...) | main.rs:162:19:162:27 | source(...) | main.rs:162:10:162:28 | 1i64.shr(...) | $@ | main.rs:162:19:162:27 | source(...) | source(...) | | main.rs:164:10:164:30 | ... .bitor(...) | main.rs:164:10:164:18 | source(...) | main.rs:164:10:164:30 | ... .bitor(...) | $@ | main.rs:164:10:164:18 | source(...) | source(...) | +| main.rs:165:10:165:27 | ... .bitor(...) | main.rs:165:10:165:18 | source(...) | main.rs:165:10:165:27 | ... .bitor(...) | $@ | main.rs:165:10:165:18 | source(...) | source(...) | | main.rs:166:10:166:30 | 1i64.bitor(...) | main.rs:166:21:166:29 | source(...) | main.rs:166:10:166:30 | 1i64.bitor(...) | $@ | main.rs:166:21:166:29 | source(...) | source(...) | +| main.rs:167:10:167:27 | 1.bitor(...) | main.rs:167:18:167:26 | source(...) | main.rs:167:10:167:27 | 1.bitor(...) | $@ | main.rs:167:18:167:26 | source(...) | source(...) | | main.rs:176:10:176:10 | a | main.rs:170:18:170:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:170:18:170:26 | source(...) | source(...) | | main.rs:176:10:176:10 | a | main.rs:171:18:171:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:171:18:171:26 | source(...) | source(...) | | main.rs:176:10:176:10 | a | main.rs:172:18:172:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:172:18:172:26 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/taint/main.rs b/rust/ql/test/library-tests/dataflow/taint/main.rs index 07770cc7118..05dbd1eb702 100644 --- a/rust/ql/test/library-tests/dataflow/taint/main.rs +++ b/rust/ql/test/library-tests/dataflow/taint/main.rs @@ -162,9 +162,9 @@ fn std_ops() { sink(1i64.shr(source(2))); // $ hasTaintFlow=2 sink(source(1).bitor(2i64)); // $ hasTaintFlow=1 - sink(source(1).bitor(2)); // $ MISSING: hasTaintFlow=1 + sink(source(1).bitor(2)); // $ hasTaintFlow=1 sink(1i64.bitor(source(2))); // $ hasTaintFlow=2 - sink(1.bitor(source(2))); // $ MISSING: hasTaintFlow=2 + sink(1.bitor(source(2))); // $ hasTaintFlow=2 let mut a: i64 = 1; a.add_assign(source(2)); diff --git a/rust/ql/test/library-tests/type-inference/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/library-tests/type-inference/CONSISTENCY/PathResolutionConsistency.expected index a753b733ba3..2ac439e085b 100644 --- a/rust/ql/test/library-tests/type-inference/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/library-tests/type-inference/CONSISTENCY/PathResolutionConsistency.expected @@ -1,4 +1,4 @@ multipleResolvedTargets | main.rs:2223:9:2223:31 | ... .my_add(...) | | main.rs:2225:9:2225:29 | ... .my_add(...) | -| main.rs:2733:13:2733:17 | x.f() | +| main.rs:2740:13:2740:17 | x.f() | diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index f342d3897f4..6c9f2c801d5 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2643,6 +2643,10 @@ mod context_typed { fn f(self) {} } + fn free_function() -> T { + Default::default() // $ target=default + } + pub fn f() { let x = None; // $ type=x:T.i32 let x: Option = x; @@ -2693,6 +2697,9 @@ mod context_typed { let s = Default::default(); // $ target=default type=s:S S::f(s); // $ target=f + + let z = free_function(); // $ target=free_function type=z:i32 + x.push(z); // $ target=push } } diff --git a/rust/ql/test/library-tests/type-inference/overloading.rs b/rust/ql/test/library-tests/type-inference/overloading.rs index 0bf6598c1d1..94b5a8b69e4 100644 --- a/rust/ql/test/library-tests/type-inference/overloading.rs +++ b/rust/ql/test/library-tests/type-inference/overloading.rs @@ -400,3 +400,52 @@ mod from_default { x } } + +mod inherent_before_trait { + struct S(T); + + trait Trait { + fn foo(&self); + fn bar(&self); + } + + impl S { + // S::foo + fn foo(x: &Self) {} + + // S::bar + fn bar(&self) {} + } + + impl Trait for S { + // _as_Trait>::foo + fn foo(&self) { + S::foo(self); // $ MISSING: target=S::foo + S::::foo(self); // $ target=S::foo + self.foo() // $ target=_as_Trait>::foo + } + + // _as_Trait>::bar + fn bar(&self) { + S::bar(self); // $ target=S::bar + S::::bar(self); // $ target=S::bar + self.bar() // $ target=S::bar + } + } + + impl Trait for S { + // _as_Trait>::foo + fn foo(&self) { + // `S::foo(self);` is not valid + S::::foo(self); // $ target=_as_Trait>::foo + self.foo() // $ target=_as_Trait>::foo + } + + // _as_Trait>::bar + fn bar(&self) { + // `S::bar(self);` is not valid + S::::bar(self); // $ target=_as_Trait>::bar + self.bar() // $ target=_as_Trait>::bar + } + } +} diff --git a/rust/ql/test/library-tests/type-inference/regressions.rs b/rust/ql/test/library-tests/type-inference/regressions.rs index 9365588c64a..37c61b2b7e7 100644 --- a/rust/ql/test/library-tests/type-inference/regressions.rs +++ b/rust/ql/test/library-tests/type-inference/regressions.rs @@ -74,3 +74,35 @@ mod regression2 { let x = s1 - &s2; // $ target=S1SubRefS2 type=x:S2 } } + +mod regression3 { + trait SomeTrait {} + + trait MyFrom { + fn my_from(value: T) -> Self; + } + + impl MyFrom for T { + fn my_from(s: T) -> Self { + s + } + } + + impl MyFrom for Option { + fn my_from(val: T) -> Option { + Some(val) + } + } + + pub struct S(Ts); + + pub fn f(x: T2) -> T2 + where + T2: SomeTrait + MyFrom>, + Option: MyFrom, + { + let y = MyFrom::my_from(x); // $ target=my_from + let z = MyFrom::my_from(y); // $ target=my_from + z + } +} diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index d3ec61e9603..feba4891a66 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -3630,130 +3630,133 @@ inferCertainType | main.rs:2633:29:2633:29 | a | | {EXTERNAL LOCATION} | () | | main.rs:2643:14:2643:17 | SelfParam | | main.rs:2639:5:2640:13 | S | | main.rs:2643:20:2643:21 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2646:16:2696:5 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2648:13:2648:13 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2648:13:2648:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2652:26:2652:28 | opt | | {EXTERNAL LOCATION} | Option | -| main.rs:2652:26:2652:28 | opt | T | main.rs:2652:23:2652:23 | T | -| main.rs:2652:42:2652:42 | x | | main.rs:2652:23:2652:23 | T | -| main.rs:2652:48:2652:49 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2655:9:2655:24 | pin_option(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2662:13:2662:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2662:17:2662:39 | ...::A {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2663:13:2663:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2663:13:2663:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2663:13:2663:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2663:40:2663:40 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2664:13:2664:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2664:13:2664:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2664:17:2664:52 | ...::A {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2664:17:2664:52 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2666:13:2666:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2666:13:2666:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2666:17:2668:9 | ...::B::<...> {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2666:17:2668:9 | ...::B::<...> {...} | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2667:20:2667:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | -| main.rs:2670:29:2670:29 | e | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2670:29:2670:29 | e | T1 | main.rs:2670:26:2670:26 | T | -| main.rs:2670:29:2670:29 | e | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2670:53:2670:53 | x | | main.rs:2670:26:2670:26 | T | -| main.rs:2670:59:2670:60 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2673:13:2673:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2673:17:2675:9 | ...::B {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2674:20:2674:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | -| main.rs:2676:9:2676:27 | pin_my_either(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2676:23:2676:23 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2679:13:2679:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2679:13:2679:13 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2679:13:2679:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2683:29:2683:31 | res | | {EXTERNAL LOCATION} | Result | -| main.rs:2683:29:2683:31 | res | E | main.rs:2683:26:2683:26 | E | -| main.rs:2683:29:2683:31 | res | T | main.rs:2683:23:2683:23 | T | -| main.rs:2683:48:2683:48 | x | | main.rs:2683:26:2683:26 | E | -| main.rs:2683:54:2683:55 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2686:9:2686:28 | pin_result(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2686:23:2686:27 | false | | {EXTERNAL LOCATION} | bool | -| main.rs:2688:17:2688:17 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2688:17:2688:17 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2688:21:2688:30 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | -| main.rs:2688:21:2688:30 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2689:9:2689:9 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2689:9:2689:9 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2692:9:2692:9 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2692:9:2692:9 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2695:9:2695:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2702:14:2702:17 | SelfParam | | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:14:2705:18 | SelfParam | | {EXTERNAL LOCATION} | & | -| main.rs:2705:14:2705:18 | SelfParam | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:21:2705:25 | other | | {EXTERNAL LOCATION} | & | -| main.rs:2705:21:2705:25 | other | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:44:2707:9 | { ... } | | {EXTERNAL LOCATION} | & | -| main.rs:2705:44:2707:9 | { ... } | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2706:13:2706:16 | self | | {EXTERNAL LOCATION} | & | -| main.rs:2706:13:2706:16 | self | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2712:14:2712:17 | SelfParam | | {EXTERNAL LOCATION} | i32 | -| main.rs:2712:28:2714:9 | { ... } | | {EXTERNAL LOCATION} | i32 | -| main.rs:2713:13:2713:16 | self | | {EXTERNAL LOCATION} | i32 | -| main.rs:2719:14:2719:17 | SelfParam | | {EXTERNAL LOCATION} | usize | -| main.rs:2719:28:2721:9 | { ... } | | {EXTERNAL LOCATION} | usize | -| main.rs:2720:13:2720:16 | self | | {EXTERNAL LOCATION} | usize | -| main.rs:2726:14:2726:17 | SelfParam | | {EXTERNAL LOCATION} | & | -| main.rs:2726:14:2726:17 | SelfParam | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2726:28:2728:9 | { ... } | | {EXTERNAL LOCATION} | & | -| main.rs:2726:28:2728:9 | { ... } | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2727:13:2727:16 | self | | {EXTERNAL LOCATION} | & | -| main.rs:2727:13:2727:16 | self | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2731:25:2735:5 | { ... } | | {EXTERNAL LOCATION} | usize | -| main.rs:2737:12:2745:5 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2738:13:2738:13 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2739:13:2739:13 | y | | {EXTERNAL LOCATION} | & | -| main.rs:2739:17:2739:18 | &1 | | {EXTERNAL LOCATION} | & | -| main.rs:2740:17:2740:17 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2740:21:2740:21 | y | | {EXTERNAL LOCATION} | & | -| main.rs:2743:13:2743:13 | y | | {EXTERNAL LOCATION} | usize | -| main.rs:2744:23:2744:23 | y | | {EXTERNAL LOCATION} | usize | -| main.rs:2755:11:2790:1 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2756:5:2756:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2757:5:2757:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:5:2758:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:20:2758:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:41:2758:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2759:5:2759:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2760:5:2760:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2761:5:2761:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2762:5:2762:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2646:41:2648:5 | { ... } | | main.rs:2646:22:2646:31 | T | +| main.rs:2650:16:2703:5 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2652:13:2652:13 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2652:13:2652:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2656:26:2656:28 | opt | | {EXTERNAL LOCATION} | Option | +| main.rs:2656:26:2656:28 | opt | T | main.rs:2656:23:2656:23 | T | +| main.rs:2656:42:2656:42 | x | | main.rs:2656:23:2656:23 | T | +| main.rs:2656:48:2656:49 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2659:9:2659:24 | pin_option(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2666:13:2666:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2666:17:2666:39 | ...::A {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2667:13:2667:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2667:13:2667:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2667:13:2667:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2667:40:2667:40 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2668:13:2668:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2668:13:2668:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2668:17:2668:52 | ...::A {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2668:17:2668:52 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2670:13:2670:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2670:13:2670:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2670:17:2672:9 | ...::B::<...> {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2670:17:2672:9 | ...::B::<...> {...} | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2671:20:2671:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | +| main.rs:2674:29:2674:29 | e | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2674:29:2674:29 | e | T1 | main.rs:2674:26:2674:26 | T | +| main.rs:2674:29:2674:29 | e | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2674:53:2674:53 | x | | main.rs:2674:26:2674:26 | T | +| main.rs:2674:59:2674:60 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2677:13:2677:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2677:17:2679:9 | ...::B {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2678:20:2678:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | +| main.rs:2680:9:2680:27 | pin_my_either(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2680:23:2680:23 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2683:13:2683:13 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2683:13:2683:13 | x | E | {EXTERNAL LOCATION} | String | +| main.rs:2683:13:2683:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2687:29:2687:31 | res | | {EXTERNAL LOCATION} | Result | +| main.rs:2687:29:2687:31 | res | E | main.rs:2687:26:2687:26 | E | +| main.rs:2687:29:2687:31 | res | T | main.rs:2687:23:2687:23 | T | +| main.rs:2687:48:2687:48 | x | | main.rs:2687:26:2687:26 | E | +| main.rs:2687:54:2687:55 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2690:9:2690:28 | pin_result(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2690:23:2690:27 | false | | {EXTERNAL LOCATION} | bool | +| main.rs:2692:17:2692:17 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2692:17:2692:17 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2692:21:2692:30 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | +| main.rs:2692:21:2692:30 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2693:9:2693:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2693:9:2693:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2696:9:2696:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2696:9:2696:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2699:9:2699:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2702:9:2702:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2702:9:2702:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2709:14:2709:17 | SelfParam | | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:14:2712:18 | SelfParam | | {EXTERNAL LOCATION} | & | +| main.rs:2712:14:2712:18 | SelfParam | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:21:2712:25 | other | | {EXTERNAL LOCATION} | & | +| main.rs:2712:21:2712:25 | other | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:44:2714:9 | { ... } | | {EXTERNAL LOCATION} | & | +| main.rs:2712:44:2714:9 | { ... } | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2713:13:2713:16 | self | | {EXTERNAL LOCATION} | & | +| main.rs:2713:13:2713:16 | self | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2719:14:2719:17 | SelfParam | | {EXTERNAL LOCATION} | i32 | +| main.rs:2719:28:2721:9 | { ... } | | {EXTERNAL LOCATION} | i32 | +| main.rs:2720:13:2720:16 | self | | {EXTERNAL LOCATION} | i32 | +| main.rs:2726:14:2726:17 | SelfParam | | {EXTERNAL LOCATION} | usize | +| main.rs:2726:28:2728:9 | { ... } | | {EXTERNAL LOCATION} | usize | +| main.rs:2727:13:2727:16 | self | | {EXTERNAL LOCATION} | usize | +| main.rs:2733:14:2733:17 | SelfParam | | {EXTERNAL LOCATION} | & | +| main.rs:2733:14:2733:17 | SelfParam | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2733:28:2735:9 | { ... } | | {EXTERNAL LOCATION} | & | +| main.rs:2733:28:2735:9 | { ... } | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2734:13:2734:16 | self | | {EXTERNAL LOCATION} | & | +| main.rs:2734:13:2734:16 | self | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2738:25:2742:5 | { ... } | | {EXTERNAL LOCATION} | usize | +| main.rs:2744:12:2752:5 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2745:13:2745:13 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2746:13:2746:13 | y | | {EXTERNAL LOCATION} | & | +| main.rs:2746:17:2746:18 | &1 | | {EXTERNAL LOCATION} | & | +| main.rs:2747:17:2747:17 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2747:21:2747:21 | y | | {EXTERNAL LOCATION} | & | +| main.rs:2750:13:2750:13 | y | | {EXTERNAL LOCATION} | usize | +| main.rs:2751:23:2751:23 | y | | {EXTERNAL LOCATION} | usize | +| main.rs:2762:11:2797:1 | { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2763:5:2763:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2764:5:2764:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2765:5:2765:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2766:5:2766:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2767:5:2767:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2768:5:2768:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2769:5:2769:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2770:5:2770:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2771:5:2771:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2772:5:2772:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2773:5:2773:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2774:5:2774:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | -| main.rs:2774:5:2774:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | -| main.rs:2775:5:2775:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2776:5:2776:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2777:5:2777:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2778:5:2778:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2779:5:2779:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2780:5:2780:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2781:5:2781:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2782:5:2782:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2783:5:2783:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2784:5:2784:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2785:5:2785:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2786:5:2786:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2787:5:2787:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2788:5:2788:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2788:5:2788:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2788:5:2788:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | -| main.rs:2788:5:2788:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | -| main.rs:2788:16:2788:19 | true | | {EXTERNAL LOCATION} | bool | -| main.rs:2789:5:2789:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2764:5:2764:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:5:2765:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:20:2765:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:41:2765:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2766:5:2766:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2767:5:2767:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2768:5:2768:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2769:5:2769:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2770:5:2770:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2771:5:2771:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2772:5:2772:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2773:5:2773:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2774:5:2774:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2775:5:2775:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2776:5:2776:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2777:5:2777:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2778:5:2778:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2779:5:2779:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2780:5:2780:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2781:5:2781:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | +| main.rs:2781:5:2781:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | +| main.rs:2782:5:2782:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2783:5:2783:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2784:5:2784:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2785:5:2785:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2786:5:2786:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2787:5:2787:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2788:5:2788:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2789:5:2789:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2790:5:2790:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2791:5:2791:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2792:5:2792:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2793:5:2793:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2794:5:2794:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2795:5:2795:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2795:5:2795:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2795:5:2795:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | +| main.rs:2795:5:2795:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | +| main.rs:2795:16:2795:19 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:2796:5:2796:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | | overloading.rs:4:19:4:23 | SelfParam | | {EXTERNAL LOCATION} | & | | overloading.rs:4:19:4:23 | SelfParam | TRef | overloading.rs:2:5:11:5 | Self [trait FirstTrait] | | overloading.rs:4:34:6:9 | { ... } | | {EXTERNAL LOCATION} | bool | @@ -4012,6 +4015,70 @@ inferCertainType | overloading.rs:397:10:397:10 | b | | {EXTERNAL LOCATION} | bool | | overloading.rs:397:25:401:5 | { ... } | | overloading.rs:372:5:372:14 | S1 | | overloading.rs:398:20:398:20 | b | | {EXTERNAL LOCATION} | bool | +| overloading.rs:408:16:408:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:408:16:408:20 | SelfParam | TRef | overloading.rs:407:5:410:5 | Self [trait Trait] | +| overloading.rs:409:16:409:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:409:16:409:20 | SelfParam | TRef | overloading.rs:407:5:410:5 | Self [trait Trait] | +| overloading.rs:414:16:414:16 | x | | {EXTERNAL LOCATION} | & | +| overloading.rs:414:16:414:16 | x | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:414:16:414:16 | x | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:414:26:414:27 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:417:16:417:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:417:16:417:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:417:16:417:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:417:23:417:24 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:422:16:422:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:422:16:422:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:422:16:422:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:422:23:426:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:423:13:423:24 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:423:20:423:23 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:423:20:423:23 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:423:20:423:23 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:424:13:424:31 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:424:27:424:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:424:27:424:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:424:27:424:30 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:425:13:425:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:425:13:425:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:425:13:425:16 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:429:16:429:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:429:16:429:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:429:16:429:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:429:23:433:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:430:13:430:24 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:430:20:430:23 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:430:20:430:23 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:430:20:430:23 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:431:13:431:31 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:431:27:431:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:431:27:431:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:431:27:431:30 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:432:13:432:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:432:13:432:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:432:13:432:16 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:438:16:438:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:438:16:438:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:438:16:438:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:438:23:442:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:440:13:440:31 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:440:27:440:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:440:27:440:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:440:27:440:30 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:441:13:441:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:441:13:441:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:441:13:441:16 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:445:16:445:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:445:16:445:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:445:16:445:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:445:23:449:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:447:13:447:31 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:447:27:447:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:447:27:447:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:447:27:447:30 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:448:13:448:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:448:13:448:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:448:13:448:16 | self | TRef.T | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:13:26:133:1 | { ... } | T | {EXTERNAL LOCATION} | () | | pattern_matching.rs:15:5:18:5 | if ... {...} | | {EXTERNAL LOCATION} | () | @@ -4960,6 +5027,17 @@ inferCertainType | regressions.rs:67:29:67:33 | other | TRef | regressions.rs:41:5:42:14 | S2 | | regressions.rs:71:14:75:5 | { ... } | | {EXTERNAL LOCATION} | () | | regressions.rs:74:22:74:24 | &s2 | | {EXTERNAL LOCATION} | & | +| regressions.rs:82:20:82:24 | value | | regressions.rs:81:18:81:18 | T | +| regressions.rs:86:20:86:20 | s | | regressions.rs:85:10:85:10 | T | +| regressions.rs:86:34:88:9 | { ... } | | regressions.rs:85:10:85:10 | T | +| regressions.rs:87:13:87:13 | s | | regressions.rs:85:10:85:10 | T | +| regressions.rs:92:20:92:22 | val | | regressions.rs:91:10:91:10 | T | +| regressions.rs:92:41:94:9 | { ... } | | {EXTERNAL LOCATION} | Option | +| regressions.rs:92:41:94:9 | { ... } | T | regressions.rs:91:10:91:10 | T | +| regressions.rs:93:18:93:20 | val | | regressions.rs:91:10:91:10 | T | +| regressions.rs:99:22:99:22 | x | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:103:5:107:5 | { ... } | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:33:104:33 | x | | regressions.rs:99:18:99:19 | T2 | inferType | associated_types.rs:5:15:5:18 | SelfParam | | associated_types.rs:1:1:2:21 | Wrapper | | associated_types.rs:5:15:5:18 | SelfParam | A | associated_types.rs:4:6:4:6 | A | @@ -11976,249 +12054,258 @@ inferType | main.rs:2634:9:2634:9 | 0 | | {EXTERNAL LOCATION} | i32 | | main.rs:2643:14:2643:17 | SelfParam | | main.rs:2639:5:2640:13 | S | | main.rs:2643:20:2643:21 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2646:16:2696:5 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2647:13:2647:13 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2647:13:2647:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2647:17:2647:20 | None | | {EXTERNAL LOCATION} | Option | -| main.rs:2647:17:2647:20 | None | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2648:13:2648:13 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2648:13:2648:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2648:30:2648:30 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2648:30:2648:30 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2649:13:2649:13 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2649:13:2649:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2649:17:2649:35 | ...::None | | {EXTERNAL LOCATION} | Option | -| main.rs:2649:17:2649:35 | ...::None | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2650:13:2650:13 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2650:13:2650:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2650:17:2650:35 | ...::None::<...> | | {EXTERNAL LOCATION} | Option | -| main.rs:2650:17:2650:35 | ...::None::<...> | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2652:26:2652:28 | opt | | {EXTERNAL LOCATION} | Option | -| main.rs:2652:26:2652:28 | opt | T | main.rs:2652:23:2652:23 | T | -| main.rs:2652:42:2652:42 | x | | main.rs:2652:23:2652:23 | T | -| main.rs:2652:48:2652:49 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2646:41:2648:5 | { ... } | | main.rs:2646:22:2646:31 | T | +| main.rs:2647:9:2647:26 | ...::default(...) | | main.rs:2646:22:2646:31 | T | +| main.rs:2650:16:2703:5 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2651:13:2651:13 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2651:13:2651:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2651:17:2651:20 | None | | {EXTERNAL LOCATION} | Option | +| main.rs:2651:17:2651:20 | None | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2652:13:2652:13 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2652:13:2652:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2652:30:2652:30 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2652:30:2652:30 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2653:13:2653:13 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2653:13:2653:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2653:17:2653:35 | ...::None | | {EXTERNAL LOCATION} | Option | +| main.rs:2653:17:2653:35 | ...::None | T | {EXTERNAL LOCATION} | i32 | | main.rs:2654:13:2654:13 | x | | {EXTERNAL LOCATION} | Option | | main.rs:2654:13:2654:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2654:17:2654:20 | None | | {EXTERNAL LOCATION} | Option | -| main.rs:2654:17:2654:20 | None | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2655:9:2655:24 | pin_option(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2655:20:2655:20 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2655:20:2655:20 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2655:23:2655:23 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2662:13:2662:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2662:13:2662:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2662:13:2662:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2662:17:2662:39 | ...::A {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2662:17:2662:39 | ...::A {...} | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2662:17:2662:39 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2662:37:2662:37 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2663:13:2663:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2663:13:2663:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2663:13:2663:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2663:40:2663:40 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2663:40:2663:40 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2663:40:2663:40 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2664:13:2664:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2664:13:2664:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2664:13:2664:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2664:17:2664:52 | ...::A {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2664:17:2664:52 | ...::A {...} | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2664:17:2664:52 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2664:50:2664:50 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2666:13:2666:13 | x | | main.rs:2657:9:2660:9 | MyEither | +| main.rs:2654:17:2654:35 | ...::None::<...> | | {EXTERNAL LOCATION} | Option | +| main.rs:2654:17:2654:35 | ...::None::<...> | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2656:26:2656:28 | opt | | {EXTERNAL LOCATION} | Option | +| main.rs:2656:26:2656:28 | opt | T | main.rs:2656:23:2656:23 | T | +| main.rs:2656:42:2656:42 | x | | main.rs:2656:23:2656:23 | T | +| main.rs:2656:48:2656:49 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2658:13:2658:13 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2658:13:2658:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2658:17:2658:20 | None | | {EXTERNAL LOCATION} | Option | +| main.rs:2658:17:2658:20 | None | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2659:9:2659:24 | pin_option(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2659:20:2659:20 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2659:20:2659:20 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2659:23:2659:23 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2666:13:2666:13 | x | | main.rs:2661:9:2664:9 | MyEither | | main.rs:2666:13:2666:13 | x | T1 | {EXTERNAL LOCATION} | i32 | | main.rs:2666:13:2666:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2666:17:2668:9 | ...::B::<...> {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2666:17:2668:9 | ...::B::<...> {...} | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2666:17:2668:9 | ...::B::<...> {...} | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2667:20:2667:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | -| main.rs:2670:29:2670:29 | e | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2670:29:2670:29 | e | T1 | main.rs:2670:26:2670:26 | T | -| main.rs:2670:29:2670:29 | e | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2670:53:2670:53 | x | | main.rs:2670:26:2670:26 | T | -| main.rs:2670:59:2670:60 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2673:13:2673:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2673:13:2673:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2673:13:2673:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2673:17:2675:9 | ...::B {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2673:17:2675:9 | ...::B {...} | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2673:17:2675:9 | ...::B {...} | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2674:20:2674:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | -| main.rs:2676:9:2676:27 | pin_my_either(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2676:23:2676:23 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2676:23:2676:23 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2676:23:2676:23 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2676:26:2676:26 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2678:13:2678:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2678:13:2678:13 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2678:13:2678:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2678:17:2678:29 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | -| main.rs:2678:17:2678:29 | ...::Ok(...) | E | {EXTERNAL LOCATION} | String | -| main.rs:2678:17:2678:29 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2678:28:2678:28 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2679:13:2679:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2679:13:2679:13 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2679:13:2679:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2679:38:2679:38 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2679:38:2679:38 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2679:38:2679:38 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2680:13:2680:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2680:13:2680:13 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2680:13:2680:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2680:17:2680:44 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | -| main.rs:2680:17:2680:44 | ...::Ok(...) | E | {EXTERNAL LOCATION} | String | -| main.rs:2680:17:2680:44 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2680:43:2680:43 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2681:13:2681:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2681:13:2681:13 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2681:13:2681:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2681:17:2681:44 | ...::Ok::<...>(...) | | {EXTERNAL LOCATION} | Result | -| main.rs:2681:17:2681:44 | ...::Ok::<...>(...) | E | {EXTERNAL LOCATION} | String | -| main.rs:2681:17:2681:44 | ...::Ok::<...>(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2681:43:2681:43 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2683:29:2683:31 | res | | {EXTERNAL LOCATION} | Result | -| main.rs:2683:29:2683:31 | res | E | main.rs:2683:26:2683:26 | E | -| main.rs:2683:29:2683:31 | res | T | main.rs:2683:23:2683:23 | T | -| main.rs:2683:48:2683:48 | x | | main.rs:2683:26:2683:26 | E | -| main.rs:2683:54:2683:55 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2666:17:2666:39 | ...::A {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2666:17:2666:39 | ...::A {...} | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2666:17:2666:39 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2666:37:2666:37 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2667:13:2667:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2667:13:2667:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2667:13:2667:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2667:40:2667:40 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2667:40:2667:40 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2667:40:2667:40 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2668:13:2668:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2668:13:2668:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2668:13:2668:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2668:17:2668:52 | ...::A {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2668:17:2668:52 | ...::A {...} | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2668:17:2668:52 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2668:50:2668:50 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2670:13:2670:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2670:13:2670:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2670:13:2670:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2670:17:2672:9 | ...::B::<...> {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2670:17:2672:9 | ...::B::<...> {...} | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2670:17:2672:9 | ...::B::<...> {...} | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2671:20:2671:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | +| main.rs:2674:29:2674:29 | e | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2674:29:2674:29 | e | T1 | main.rs:2674:26:2674:26 | T | +| main.rs:2674:29:2674:29 | e | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2674:53:2674:53 | x | | main.rs:2674:26:2674:26 | T | +| main.rs:2674:59:2674:60 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2677:13:2677:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2677:13:2677:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2677:13:2677:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2677:17:2679:9 | ...::B {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2677:17:2679:9 | ...::B {...} | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2677:17:2679:9 | ...::B {...} | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2678:20:2678:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | +| main.rs:2680:9:2680:27 | pin_my_either(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2680:23:2680:23 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2680:23:2680:23 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2680:23:2680:23 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2680:26:2680:26 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2682:13:2682:13 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2682:13:2682:13 | x | E | {EXTERNAL LOCATION} | String | +| main.rs:2682:13:2682:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2682:17:2682:29 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | +| main.rs:2682:17:2682:29 | ...::Ok(...) | E | {EXTERNAL LOCATION} | String | +| main.rs:2682:17:2682:29 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2682:28:2682:28 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2683:13:2683:13 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2683:13:2683:13 | x | E | {EXTERNAL LOCATION} | String | +| main.rs:2683:13:2683:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2683:38:2683:38 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2683:38:2683:38 | x | E | {EXTERNAL LOCATION} | String | +| main.rs:2683:38:2683:38 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2684:13:2684:13 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2684:13:2684:13 | x | E | {EXTERNAL LOCATION} | String | +| main.rs:2684:13:2684:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2684:17:2684:44 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | +| main.rs:2684:17:2684:44 | ...::Ok(...) | E | {EXTERNAL LOCATION} | String | +| main.rs:2684:17:2684:44 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2684:43:2684:43 | 0 | | {EXTERNAL LOCATION} | i32 | | main.rs:2685:13:2685:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2685:13:2685:13 | x | E | {EXTERNAL LOCATION} | bool | +| main.rs:2685:13:2685:13 | x | E | {EXTERNAL LOCATION} | String | | main.rs:2685:13:2685:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2685:17:2685:29 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | -| main.rs:2685:17:2685:29 | ...::Ok(...) | E | {EXTERNAL LOCATION} | bool | -| main.rs:2685:17:2685:29 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2685:28:2685:28 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2686:9:2686:28 | pin_result(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2686:20:2686:20 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2686:20:2686:20 | x | E | {EXTERNAL LOCATION} | bool | -| main.rs:2686:20:2686:20 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2686:23:2686:27 | false | | {EXTERNAL LOCATION} | bool | -| main.rs:2688:17:2688:17 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2688:17:2688:17 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2688:17:2688:17 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2688:21:2688:30 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | -| main.rs:2688:21:2688:30 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2688:21:2688:30 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2689:9:2689:9 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2689:9:2689:9 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2689:9:2689:9 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2689:9:2689:17 | x.push(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2689:16:2689:16 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2691:13:2691:13 | y | | {EXTERNAL LOCATION} | i32 | -| main.rs:2691:17:2691:34 | ...::default(...) | | {EXTERNAL LOCATION} | i32 | -| main.rs:2692:9:2692:9 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2692:9:2692:9 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2692:9:2692:9 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2692:9:2692:17 | x.push(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2692:16:2692:16 | y | | {EXTERNAL LOCATION} | i32 | -| main.rs:2694:13:2694:13 | s | | main.rs:2639:5:2640:13 | S | -| main.rs:2694:17:2694:34 | ...::default(...) | | main.rs:2639:5:2640:13 | S | -| main.rs:2695:9:2695:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2695:14:2695:14 | s | | main.rs:2639:5:2640:13 | S | -| main.rs:2702:14:2702:17 | SelfParam | | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:14:2705:18 | SelfParam | | {EXTERNAL LOCATION} | & | -| main.rs:2705:14:2705:18 | SelfParam | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:21:2705:25 | other | | {EXTERNAL LOCATION} | & | -| main.rs:2705:21:2705:25 | other | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:44:2707:9 | { ... } | | {EXTERNAL LOCATION} | & | -| main.rs:2705:44:2707:9 | { ... } | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2706:13:2706:16 | self | | {EXTERNAL LOCATION} | & | -| main.rs:2706:13:2706:16 | self | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2706:13:2706:20 | self.f() | | {EXTERNAL LOCATION} | & | -| main.rs:2706:13:2706:20 | self.f() | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2712:14:2712:17 | SelfParam | | {EXTERNAL LOCATION} | i32 | -| main.rs:2712:28:2714:9 | { ... } | | {EXTERNAL LOCATION} | i32 | -| main.rs:2713:13:2713:16 | self | | {EXTERNAL LOCATION} | i32 | -| main.rs:2719:14:2719:17 | SelfParam | | {EXTERNAL LOCATION} | usize | -| main.rs:2719:28:2721:9 | { ... } | | {EXTERNAL LOCATION} | usize | -| main.rs:2720:13:2720:16 | self | | {EXTERNAL LOCATION} | usize | -| main.rs:2726:14:2726:17 | SelfParam | | {EXTERNAL LOCATION} | & | -| main.rs:2726:14:2726:17 | SelfParam | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2726:28:2728:9 | { ... } | | {EXTERNAL LOCATION} | & | -| main.rs:2726:28:2728:9 | { ... } | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2727:13:2727:16 | self | | {EXTERNAL LOCATION} | & | -| main.rs:2727:13:2727:16 | self | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2731:25:2735:5 | { ... } | | {EXTERNAL LOCATION} | usize | -| main.rs:2732:17:2732:17 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2732:17:2732:17 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2732:21:2732:21 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2732:21:2732:21 | 0 | | {EXTERNAL LOCATION} | usize | -| main.rs:2733:9:2733:9 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2733:9:2733:9 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2733:9:2733:17 | ... = ... | | {EXTERNAL LOCATION} | () | -| main.rs:2733:13:2733:13 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2733:13:2733:13 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2733:13:2733:17 | x.f() | | {EXTERNAL LOCATION} | i32 | -| main.rs:2733:13:2733:17 | x.f() | | {EXTERNAL LOCATION} | usize | -| main.rs:2734:9:2734:9 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2734:9:2734:9 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2737:12:2745:5 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2738:13:2738:13 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2738:24:2738:24 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2738:24:2738:24 | 0 | | {EXTERNAL LOCATION} | usize | -| main.rs:2739:13:2739:13 | y | | {EXTERNAL LOCATION} | & | -| main.rs:2739:13:2739:13 | y | TRef | {EXTERNAL LOCATION} | i32 | -| main.rs:2739:17:2739:18 | &1 | | {EXTERNAL LOCATION} | & | -| main.rs:2739:17:2739:18 | &1 | TRef | {EXTERNAL LOCATION} | i32 | -| main.rs:2739:18:2739:18 | 1 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2740:13:2740:13 | z | | {EXTERNAL LOCATION} | & | -| main.rs:2740:13:2740:13 | z | TRef | {EXTERNAL LOCATION} | usize | -| main.rs:2740:17:2740:17 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2740:17:2740:22 | x.g(...) | | {EXTERNAL LOCATION} | & | -| main.rs:2740:17:2740:22 | x.g(...) | TRef | {EXTERNAL LOCATION} | usize | -| main.rs:2740:21:2740:21 | y | | {EXTERNAL LOCATION} | & | -| main.rs:2740:21:2740:21 | y | TRef | {EXTERNAL LOCATION} | i32 | -| main.rs:2742:13:2742:13 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2742:17:2742:17 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2743:13:2743:13 | y | | {EXTERNAL LOCATION} | usize | -| main.rs:2743:24:2743:24 | 1 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2743:24:2743:24 | 1 | | {EXTERNAL LOCATION} | usize | -| main.rs:2744:13:2744:13 | z | | {EXTERNAL LOCATION} | i32 | -| main.rs:2744:17:2744:17 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2744:17:2744:24 | x.max(...) | | {EXTERNAL LOCATION} | i32 | -| main.rs:2744:23:2744:23 | y | | {EXTERNAL LOCATION} | usize | -| main.rs:2755:11:2790:1 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2756:5:2756:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2757:5:2757:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:5:2758:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:20:2758:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:41:2758:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2759:5:2759:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2760:5:2760:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2761:5:2761:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2762:5:2762:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2685:17:2685:44 | ...::Ok::<...>(...) | | {EXTERNAL LOCATION} | Result | +| main.rs:2685:17:2685:44 | ...::Ok::<...>(...) | E | {EXTERNAL LOCATION} | String | +| main.rs:2685:17:2685:44 | ...::Ok::<...>(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2685:43:2685:43 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2687:29:2687:31 | res | | {EXTERNAL LOCATION} | Result | +| main.rs:2687:29:2687:31 | res | E | main.rs:2687:26:2687:26 | E | +| main.rs:2687:29:2687:31 | res | T | main.rs:2687:23:2687:23 | T | +| main.rs:2687:48:2687:48 | x | | main.rs:2687:26:2687:26 | E | +| main.rs:2687:54:2687:55 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2689:13:2689:13 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2689:13:2689:13 | x | E | {EXTERNAL LOCATION} | bool | +| main.rs:2689:13:2689:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2689:17:2689:29 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | +| main.rs:2689:17:2689:29 | ...::Ok(...) | E | {EXTERNAL LOCATION} | bool | +| main.rs:2689:17:2689:29 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2689:28:2689:28 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2690:9:2690:28 | pin_result(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2690:20:2690:20 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2690:20:2690:20 | x | E | {EXTERNAL LOCATION} | bool | +| main.rs:2690:20:2690:20 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2690:23:2690:27 | false | | {EXTERNAL LOCATION} | bool | +| main.rs:2692:17:2692:17 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2692:17:2692:17 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2692:17:2692:17 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2692:21:2692:30 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | +| main.rs:2692:21:2692:30 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2692:21:2692:30 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2693:9:2693:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2693:9:2693:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2693:9:2693:9 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2693:9:2693:17 | x.push(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2693:16:2693:16 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2695:13:2695:13 | y | | {EXTERNAL LOCATION} | i32 | +| main.rs:2695:17:2695:34 | ...::default(...) | | {EXTERNAL LOCATION} | i32 | +| main.rs:2696:9:2696:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2696:9:2696:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2696:9:2696:9 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2696:9:2696:17 | x.push(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2696:16:2696:16 | y | | {EXTERNAL LOCATION} | i32 | +| main.rs:2698:13:2698:13 | s | | main.rs:2639:5:2640:13 | S | +| main.rs:2698:17:2698:34 | ...::default(...) | | main.rs:2639:5:2640:13 | S | +| main.rs:2699:9:2699:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2699:14:2699:14 | s | | main.rs:2639:5:2640:13 | S | +| main.rs:2701:13:2701:13 | z | | {EXTERNAL LOCATION} | i32 | +| main.rs:2701:17:2701:31 | free_function(...) | | {EXTERNAL LOCATION} | i32 | +| main.rs:2702:9:2702:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2702:9:2702:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2702:9:2702:9 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2702:9:2702:17 | x.push(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2702:16:2702:16 | z | | {EXTERNAL LOCATION} | i32 | +| main.rs:2709:14:2709:17 | SelfParam | | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:14:2712:18 | SelfParam | | {EXTERNAL LOCATION} | & | +| main.rs:2712:14:2712:18 | SelfParam | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:21:2712:25 | other | | {EXTERNAL LOCATION} | & | +| main.rs:2712:21:2712:25 | other | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:44:2714:9 | { ... } | | {EXTERNAL LOCATION} | & | +| main.rs:2712:44:2714:9 | { ... } | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2713:13:2713:16 | self | | {EXTERNAL LOCATION} | & | +| main.rs:2713:13:2713:16 | self | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2713:13:2713:20 | self.f() | | {EXTERNAL LOCATION} | & | +| main.rs:2713:13:2713:20 | self.f() | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2719:14:2719:17 | SelfParam | | {EXTERNAL LOCATION} | i32 | +| main.rs:2719:28:2721:9 | { ... } | | {EXTERNAL LOCATION} | i32 | +| main.rs:2720:13:2720:16 | self | | {EXTERNAL LOCATION} | i32 | +| main.rs:2726:14:2726:17 | SelfParam | | {EXTERNAL LOCATION} | usize | +| main.rs:2726:28:2728:9 | { ... } | | {EXTERNAL LOCATION} | usize | +| main.rs:2727:13:2727:16 | self | | {EXTERNAL LOCATION} | usize | +| main.rs:2733:14:2733:17 | SelfParam | | {EXTERNAL LOCATION} | & | +| main.rs:2733:14:2733:17 | SelfParam | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2733:28:2735:9 | { ... } | | {EXTERNAL LOCATION} | & | +| main.rs:2733:28:2735:9 | { ... } | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2734:13:2734:16 | self | | {EXTERNAL LOCATION} | & | +| main.rs:2734:13:2734:16 | self | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2738:25:2742:5 | { ... } | | {EXTERNAL LOCATION} | usize | +| main.rs:2739:17:2739:17 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2739:17:2739:17 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2739:21:2739:21 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2739:21:2739:21 | 0 | | {EXTERNAL LOCATION} | usize | +| main.rs:2740:9:2740:9 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2740:9:2740:9 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2740:9:2740:17 | ... = ... | | {EXTERNAL LOCATION} | () | +| main.rs:2740:13:2740:13 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2740:13:2740:13 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2740:13:2740:17 | x.f() | | {EXTERNAL LOCATION} | i32 | +| main.rs:2740:13:2740:17 | x.f() | | {EXTERNAL LOCATION} | usize | +| main.rs:2741:9:2741:9 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2741:9:2741:9 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2744:12:2752:5 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2745:13:2745:13 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2745:24:2745:24 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2745:24:2745:24 | 0 | | {EXTERNAL LOCATION} | usize | +| main.rs:2746:13:2746:13 | y | | {EXTERNAL LOCATION} | & | +| main.rs:2746:13:2746:13 | y | TRef | {EXTERNAL LOCATION} | i32 | +| main.rs:2746:17:2746:18 | &1 | | {EXTERNAL LOCATION} | & | +| main.rs:2746:17:2746:18 | &1 | TRef | {EXTERNAL LOCATION} | i32 | +| main.rs:2746:18:2746:18 | 1 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2747:13:2747:13 | z | | {EXTERNAL LOCATION} | & | +| main.rs:2747:13:2747:13 | z | TRef | {EXTERNAL LOCATION} | usize | +| main.rs:2747:17:2747:17 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2747:17:2747:22 | x.g(...) | | {EXTERNAL LOCATION} | & | +| main.rs:2747:17:2747:22 | x.g(...) | TRef | {EXTERNAL LOCATION} | usize | +| main.rs:2747:21:2747:21 | y | | {EXTERNAL LOCATION} | & | +| main.rs:2747:21:2747:21 | y | TRef | {EXTERNAL LOCATION} | i32 | +| main.rs:2749:13:2749:13 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2749:17:2749:17 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2750:13:2750:13 | y | | {EXTERNAL LOCATION} | usize | +| main.rs:2750:24:2750:24 | 1 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2750:24:2750:24 | 1 | | {EXTERNAL LOCATION} | usize | +| main.rs:2751:13:2751:13 | z | | {EXTERNAL LOCATION} | i32 | +| main.rs:2751:17:2751:17 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2751:17:2751:24 | x.max(...) | | {EXTERNAL LOCATION} | i32 | +| main.rs:2751:23:2751:23 | y | | {EXTERNAL LOCATION} | usize | +| main.rs:2762:11:2797:1 | { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2763:5:2763:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2764:5:2764:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2765:5:2765:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2766:5:2766:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2767:5:2767:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2768:5:2768:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2769:5:2769:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2770:5:2770:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2771:5:2771:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2772:5:2772:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2773:5:2773:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2774:5:2774:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | -| main.rs:2774:5:2774:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | -| main.rs:2775:5:2775:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2776:5:2776:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2777:5:2777:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2778:5:2778:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2779:5:2779:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2780:5:2780:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2781:5:2781:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2782:5:2782:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2783:5:2783:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2784:5:2784:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2785:5:2785:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2786:5:2786:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2787:5:2787:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2788:5:2788:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2788:5:2788:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2788:5:2788:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | -| main.rs:2788:5:2788:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | -| main.rs:2788:16:2788:19 | true | | {EXTERNAL LOCATION} | bool | -| main.rs:2789:5:2789:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2764:5:2764:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:5:2765:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:20:2765:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:41:2765:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2766:5:2766:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2767:5:2767:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2768:5:2768:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2769:5:2769:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2770:5:2770:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2771:5:2771:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2772:5:2772:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2773:5:2773:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2774:5:2774:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2775:5:2775:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2776:5:2776:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2777:5:2777:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2778:5:2778:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2779:5:2779:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2780:5:2780:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2781:5:2781:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | +| main.rs:2781:5:2781:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | +| main.rs:2782:5:2782:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2783:5:2783:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2784:5:2784:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2785:5:2785:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2786:5:2786:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2787:5:2787:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2788:5:2788:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2789:5:2789:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2790:5:2790:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2791:5:2791:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2792:5:2792:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2793:5:2793:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2794:5:2794:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2795:5:2795:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2795:5:2795:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2795:5:2795:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | +| main.rs:2795:5:2795:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | +| main.rs:2795:16:2795:19 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:2796:5:2796:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | | overloading.rs:4:19:4:23 | SelfParam | | {EXTERNAL LOCATION} | & | | overloading.rs:4:19:4:23 | SelfParam | TRef | overloading.rs:2:5:11:5 | Self [trait FirstTrait] | | overloading.rs:4:34:6:9 | { ... } | | {EXTERNAL LOCATION} | bool | @@ -12675,6 +12762,74 @@ inferType | overloading.rs:399:17:399:29 | ...::from(...) | | overloading.rs:372:5:372:14 | S1 | | overloading.rs:399:28:399:28 | s | | overloading.rs:364:5:365:13 | S | | overloading.rs:400:9:400:9 | x | | overloading.rs:372:5:372:14 | S1 | +| overloading.rs:408:16:408:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:408:16:408:20 | SelfParam | TRef | overloading.rs:407:5:410:5 | Self [trait Trait] | +| overloading.rs:409:16:409:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:409:16:409:20 | SelfParam | TRef | overloading.rs:407:5:410:5 | Self [trait Trait] | +| overloading.rs:414:16:414:16 | x | | {EXTERNAL LOCATION} | & | +| overloading.rs:414:16:414:16 | x | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:414:16:414:16 | x | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:414:26:414:27 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:417:16:417:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:417:16:417:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:417:16:417:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:417:23:417:24 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:422:16:422:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:422:16:422:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:422:16:422:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:422:23:426:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:423:13:423:24 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:423:20:423:23 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:423:20:423:23 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:423:20:423:23 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:424:13:424:31 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:424:27:424:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:424:27:424:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:424:27:424:30 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:425:13:425:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:425:13:425:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:425:13:425:16 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:425:13:425:22 | self.foo() | | {EXTERNAL LOCATION} | () | +| overloading.rs:429:16:429:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:429:16:429:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:429:16:429:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:429:23:433:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:430:13:430:24 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:430:20:430:23 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:430:20:430:23 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:430:20:430:23 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:431:13:431:31 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:431:27:431:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:431:27:431:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:431:27:431:30 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:432:13:432:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:432:13:432:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:432:13:432:16 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:432:13:432:22 | self.bar() | | {EXTERNAL LOCATION} | () | +| overloading.rs:438:16:438:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:438:16:438:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:438:16:438:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:438:23:442:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:440:13:440:31 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:440:27:440:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:440:27:440:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:440:27:440:30 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:441:13:441:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:441:13:441:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:441:13:441:16 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:441:13:441:22 | self.foo() | | {EXTERNAL LOCATION} | () | +| overloading.rs:445:16:445:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:445:16:445:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:445:16:445:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:445:23:449:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:447:13:447:31 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:447:27:447:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:447:27:447:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:447:27:447:30 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:448:13:448:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:448:13:448:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:448:13:448:16 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:448:13:448:22 | self.bar() | | {EXTERNAL LOCATION} | () | | pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:13:26:133:1 | { ... } | T | {EXTERNAL LOCATION} | () | | pattern_matching.rs:14:9:14:13 | value | | {EXTERNAL LOCATION} | Option | @@ -14818,4 +14973,29 @@ inferType | regressions.rs:74:22:74:24 | &s2 | | {EXTERNAL LOCATION} | & | | regressions.rs:74:22:74:24 | &s2 | TRef | regressions.rs:41:5:42:14 | S2 | | regressions.rs:74:23:74:24 | s2 | | regressions.rs:41:5:42:14 | S2 | +| regressions.rs:82:20:82:24 | value | | regressions.rs:81:18:81:18 | T | +| regressions.rs:86:20:86:20 | s | | regressions.rs:85:10:85:10 | T | +| regressions.rs:86:34:88:9 | { ... } | | regressions.rs:85:10:85:10 | T | +| regressions.rs:87:13:87:13 | s | | regressions.rs:85:10:85:10 | T | +| regressions.rs:92:20:92:22 | val | | regressions.rs:91:10:91:10 | T | +| regressions.rs:92:41:94:9 | { ... } | | {EXTERNAL LOCATION} | Option | +| regressions.rs:92:41:94:9 | { ... } | T | regressions.rs:91:10:91:10 | T | +| regressions.rs:93:13:93:21 | Some(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:93:13:93:21 | Some(...) | T | regressions.rs:91:10:91:10 | T | +| regressions.rs:93:18:93:20 | val | | regressions.rs:91:10:91:10 | T | +| regressions.rs:99:22:99:22 | x | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:103:5:107:5 | { ... } | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:33:104:33 | x | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | | regressions.rs:99:18:99:19 | T2 | testFailures diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected index ef0a9e0d806..a04fd96739c 100644 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected @@ -21,3 +21,9 @@ | test_cipher.rs:109:23:109:56 | ...::new_with_eff_key_len(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:109:23:109:56 | ...::new_with_eff_key_len(...) | The cryptographic algorithm RC2 | | test_cipher.rs:114:23:114:50 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:114:23:114:50 | ...::new(...) | The cryptographic algorithm RC5 | | test_cipher.rs:118:23:118:55 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:118:23:118:55 | ...::new_from_slice(...) | The cryptographic algorithm RC5 | +| test_cipher.rs:136:23:136:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:136:23:136:76 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:139:23:139:64 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:139:23:139:64 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:142:23:142:76 | ...::new_from_slices(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:142:23:142:76 | ...::new_from_slices(...) | The cryptographic algorithm DES | +| test_cipher.rs:145:23:145:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:145:23:145:76 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:171:23:171:65 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:171:23:171:65 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:175:23:175:65 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:175:23:175:65 | ...::new(...) | The cryptographic algorithm RC2 | diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/CONSISTENCY/PathResolutionConsistency.expected deleted file mode 100644 index 18400b7ab59..00000000000 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/CONSISTENCY/PathResolutionConsistency.expected +++ /dev/null @@ -1,2 +0,0 @@ -multipleResolvedTargets -| test_cipher.rs:114:23:114:50 | ...::new(...) | diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs index 17db0f9ceb1..81964436720 100644 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs @@ -133,16 +133,16 @@ fn test_cbc( _ = aes_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); // des (broken) - let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher2.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher3.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher4.encrypt_padded_b2b_mut::(input, data).unwrap(); } @@ -168,10 +168,10 @@ fn test_ecb( _ = aes_cipher4.encrypt_padded_b2b_mut::(input, data).unwrap(); // des with ECB (broken cipher + weak block mode) - let des_cipher1 = ecb::Encryptor::::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher1 = ecb::Encryptor::::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); // rc2 with ECB (broken cipher + weak block mode) - let rc2_cipher1 = ecb::Encryptor::::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let rc2_cipher1 = ecb::Encryptor::::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = rc2_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); } diff --git a/shared/util/codeql/util/Option.qll b/shared/util/codeql/util/Option.qll index 77cc89504f5..2be9e10fef5 100644 --- a/shared/util/codeql/util/Option.qll +++ b/shared/util/codeql/util/Option.qll @@ -56,6 +56,9 @@ module Option { /** Gets the given element wrapped as an `Option`. */ Some some(T c) { result = TSome(c) } + + /** Gets the `None` value. */ + None none_() { any() } } /** diff --git a/swift/extractor/main.cpp b/swift/extractor/main.cpp index 8019d1bfc66..6da464d7194 100644 --- a/swift/extractor/main.cpp +++ b/swift/extractor/main.cpp @@ -76,11 +76,12 @@ static void processFrontendOptions(codeql::SwiftExtractorState& state, } } -static void turnOffSilVerifications(swift::SILOptions& options) { +static void turnOffSilVerificationsAndStackProtection(swift::SILOptions& options) { options.VerifyAll = false; options.VerifyExclusivity = false; options.VerifyNone = true; options.VerifySILOwnership = false; + options.EnableStackProtection = false; // Causes crashes on Linux } codeql::TrapDomain invocationTrapDomain(codeql::SwiftExtractorState& state); @@ -98,7 +99,7 @@ class Observer : public swift::FrontendObserver { options.KeepASTContext = true; lockOutputSwiftModuleTraps(state, options); processFrontendOptions(state, options); - turnOffSilVerifications(invocation.getSILOptions()); + turnOffSilVerificationsAndStackProtection(invocation.getSILOptions()); } void configuredCompiler(swift::CompilerInstance& instance) override { diff --git a/swift/ql/integration-tests/posix/deduplication/test.py b/swift/ql/integration-tests/posix/deduplication/test.py index d9915ed3770..3e52638fdc0 100644 --- a/swift/ql/integration-tests/posix/deduplication/test.py +++ b/swift/ql/integration-tests/posix/deduplication/test.py @@ -1,6 +1,8 @@ +import pytest import runs_on @runs_on.posix +@pytest.mark.ql_test("DB-CHECK", xfail=runs_on.linux) def test(codeql, swift): codeql.database.create(command="swift build", keep_trap=True) diff --git a/swift/ql/integration-tests/posix/hello-world/test.py b/swift/ql/integration-tests/posix/hello-world/test.py index 2b81f139383..eb0ccd23b46 100644 --- a/swift/ql/integration-tests/posix/hello-world/test.py +++ b/swift/ql/integration-tests/posix/hello-world/test.py @@ -1,9 +1,9 @@ import pytest - import runs_on @runs_on.posix +@pytest.mark.ql_test("DB-CHECK", xfail=runs_on.linux) def test(codeql, swift): codeql.database.create(command="swift build") diff --git a/swift/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/swift/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..a46302ed146 --- /dev/null +++ b/swift/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,4 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `swift/unsafe-webview-fetch` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql b/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql index 5aec16da4ef..0de0cb1ae1a 100644 --- a/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql +++ b/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql @@ -9,4 +9,4 @@ import swift -select sum(File f | | f.getNumberOfLinesOfCode()) +select sum(File f | exists(f.getRelativePath()) | f.getNumberOfLinesOfCode()) diff --git a/swift/ql/src/queries/Security/CWE-079/UnsafeWebViewFetch.ql b/swift/ql/src/queries/Security/CWE-079/UnsafeWebViewFetch.ql index 7243d2216a5..3a2de3fa80a 100644 --- a/swift/ql/src/queries/Security/CWE-079/UnsafeWebViewFetch.ql +++ b/swift/ql/src/queries/Security/CWE-079/UnsafeWebViewFetch.ql @@ -3,7 +3,7 @@ * @description Fetching data in a WebView without restricting the base URL may allow an attacker to access sensitive local data, or enable cross-site scripting attack. * @kind path-problem * @problem.severity warning - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id swift/unsafe-webview-fetch * @tags security diff --git a/swift/ql/test/query-tests/Diagnostics/SuccessfullyExtractedLines.expected b/swift/ql/test/query-tests/Diagnostics/SuccessfullyExtractedLines.expected index beaf5bb6a1f..b5a514b9ffa 100644 --- a/swift/ql/test/query-tests/Diagnostics/SuccessfullyExtractedLines.expected +++ b/swift/ql/test/query-tests/Diagnostics/SuccessfullyExtractedLines.expected @@ -1 +1 @@ -| 299 | +| 4 |