diff --git a/csharp/ql/lib/semmle/code/csharp/hashcons/HashCons.qll b/csharp/ql/lib/semmle/code/csharp/hashcons/HashCons.qll new file mode 100644 index 00000000000..a235f49ffd5 --- /dev/null +++ b/csharp/ql/lib/semmle/code/csharp/hashcons/HashCons.qll @@ -0,0 +1,743 @@ +import csharp + +/** + * A hash-cons representation of an expression. + * + * Note: Here is how you go about adding a hash cons for a new expression: + * + * Step 1: Add a branch to this IPA type. + * Step 2: Add a disjunct to `numberableExpr`. + * Step 3: Add a disjunct to `nonUniqueHashCons`. + * + * Notes on performance: + * - Care must be taken not to have `numberableExpr` depend on `THashCons`. + * Since `THashCons` already depends on `numberableExpr` this would introduce + * unnecessary recursion that would ruin performance. + * - This library uses lots of non-linear recursion (i.e., more than one + * recursive call in a single disjunct). Care must be taken to ensure good + * performance when dealing with non-linear recursion. For example, consider + * a snippet such as: + * ```ql + * predicate foo(BinaryExpr bin) { + * interesting(bin) and + * foo(bin.getLeft()) and + * foo(bin.getRight()) + * } + * ``` + * to ensure that `foo` is joined optimally it should be rewritten to: + * + * ```ql + * pragma[nomagic] + * predicate fooLeft(BinaryExpr bin) { + * interesting(bin) and + * foo(bin.getLeft()) + * } + * + * pragma[nomagic] + * predicate fooRight(BinaryExpr bin) { + * interesting(bin) and + * foo(bin.getRight()) + * } + * + * predicate foo(BinaryExpr bin) { + * fooLeft(bin) and + * fooRight(bin) + * } + * ``` + */ +cached +private newtype THashCons = + TVariableAccessHashCons(LocalScopeVariable v) { variableAccessHashCons(_, v) } or + TConstantHashCons(Type type, string value) { constantHashCons(_, type, value) } or + TFieldAccessHashCons(Field field, THashCons qualifier) { + fieldAccessHashCons(_, field, qualifier) + } or + TPropertyAccessHashCons(Property prop, THashCons qualifier) { + propertyAccessHashCons(_, prop, qualifier) + } or + TBinaryHashCons(string operator, THashCons left, THashCons right) { + binaryHashCons(_, operator, left, right) + } or + TThisHashCons() or + TBaseHashCons() or + TTypeAccessHashCons(Type t) { typeAccessHashCons(_, t) } or + TDefaultValueWithoutTypeHashCons() or + TDefaultValueWithTypeHashCons(THashCons typeAccess) { + defaultValueWithTypeHashCons(_, typeAccess) + } or + TIndexerAccessHashCons(Indexer i) { indexerAccessHashCons(_, i) } or + TEventAccessHashCons(Event ev) { eventAccessHashCons(_, ev) } or + TDynamicMemberAccessHashCons(DynamicMember dm) { dynamicMemberAccessHashCons(_, dm) } or + TTypeOfHashCons(THashCons typeAccess) { typeOfHashCons(_, typeAccess) } or + TUnaryHashCons(string operator, THashCons operand) { unaryHashCons(_, operator, operand) } or + TConditionalHashCons(THashCons cond, THashCons then_, THashCons else_) { + conditionalHashCons(_, cond, then_, else_) + } or + TMethodCallHashCons(string name, CallHashCons::TListPartialHashCons args) { + methodCallHashCons(_, name, args) + } or + TConstructorInitializerCallHashCons(string name, CallHashCons::TListPartialHashCons args) { + constructorInitializerCallHashCons(_, name, args) + } or + TOperatorCallHashCons(string name, CallHashCons::TListPartialHashCons args) { + operatorCallHashCons(_, name, args) + } or + TDelegateLikeCallHashCons(THashCons expr, CallHashCons::TListPartialHashCons args) { + delegateLikeCallHashCons(_, expr, args) + } or + TObjectCreationHashCons(string name, CallHashCons::TListPartialHashCons args) { + objectCreationHashCons(_, name, args) + } or + TCastHashCons(Type targetType, THashCons expr) { castHashCons(_, targetType, expr) } or + TAssignmentHashCons(string operator, THashCons left, THashCons right) { + assignmentHashCons(_, operator, left, right) + } or + TArrayAccessHashCons(THashCons index, THashCons qualifier) { + arrayAccessHashCons(_, index, qualifier) + } or + TArrayInitializerHashCons(ArrayInitializerHashCons::TListPartialHashCons list) { + arrayInitializerHashCons(_, list) + } or + TArrayCreationHashCons(THashCons initializer, ArrayCreationHashCons::TListPartialHashCons lengths) { + arrayCreationHashCons(_, initializer, lengths) + } or + TLocalVariableDeclWithInitializerHashCons(Variable v, THashCons initializer) { + localVariableDeclWithInitializerHashCons(_, v, initializer) + } or + TLocalVariableDeclWithoutInitializerHashCons(Variable v) { + localVariableDeclWithoutInitializerHashCons(_, v) + } or + TDefineSymbolHashCons(string name) { defineSymbolHashCons(_, name) } or + TUniqueHashCons(Expr e) { uniqueHashCons(e) } + +private predicate variableAccessHashCons(LocalScopeVariableAccess va, LocalScopeVariable v) { + numberableExpr(va) and + va.getTarget() = v +} + +private predicate constantHashCons(Literal lit, Type t, string value) { + numberableExpr(lit) and + lit.getType() = t and + lit.getValue() = value +} + +private predicate fieldAccessHashCons(FieldAccess fa, Field f, THashCons qualifier) { + numberableExpr(fa) and + hashCons(fa.getQualifier()) = qualifier and + fa.getTarget() = f +} + +private predicate propertyAccessHashCons(PropertyAccess pa, Property prop, THashCons qualifier) { + numberableExpr(pa) and + hashCons(pa.getQualifier()) = qualifier and + pa.getTarget() = prop +} + +pragma[nomagic] +private predicate binaryHashConsLeft(BinaryOperation binary, THashCons h) { + numberableExpr(binary) and + hashCons(binary.getLeftOperand()) = h +} + +pragma[nomagic] +private predicate binaryHashConsRight(BinaryOperation binary, THashCons h) { + numberableExpr(binary) and + hashCons(binary.getRightOperand()) = h +} + +private predicate binaryHashCons( + BinaryOperation binary, string operator, THashCons left, THashCons right +) { + binaryHashConsLeft(binary, left) and + binaryHashConsRight(binary, right) and + binary.getOperator() = operator +} + +private predicate unaryHashCons(UnaryOperation unary, string operator, THashCons operand) { + numberableExpr(unary) and + hashCons(unary.getOperand()) = operand and + unary.getOperator() = operator +} + +pragma[nomagic] +private predicate conditionalHashConsCond(ConditionalExpr condExpr, THashCons cond) { + numberableExpr(condExpr) and + hashCons(condExpr.getCondition()) = cond +} + +pragma[nomagic] +private predicate conditionalHashConsThen(ConditionalExpr condExpr, THashCons then_) { + numberableExpr(condExpr) and + hashCons(condExpr.getThen()) = then_ +} + +pragma[nomagic] +private predicate conditionalHashConsElse(ConditionalExpr condExpr, THashCons else_) { + numberableExpr(condExpr) and + hashCons(condExpr.getElse()) = else_ +} + +private predicate conditionalHashCons( + ConditionalExpr condExpr, THashCons cond, THashCons then_, THashCons else_ +) { + numberableExpr(condExpr) and + conditionalHashConsCond(condExpr, cond) and + conditionalHashConsThen(condExpr, then_) and + conditionalHashConsElse(condExpr, else_) +} + +private predicate typeAccessHashCons(TypeAccess ta, Type t) { ta.getTarget() = t } + +private predicate indexerAccessHashCons(IndexerAccess ia, Indexer i) { ia.getTarget() = i } + +private predicate eventAccessHashCons(EventAccess ea, Event e) { ea.getTarget() = e } + +private predicate dynamicMemberAccessHashCons(DynamicMemberAccess dma, DynamicMember dm) { + dma.getTarget() = dm +} + +private predicate thisHashCons(ThisAccess ta) { any() } + +private predicate baseHashCons(BaseAccess ba) { any() } + +private predicate defaultValueWithTypeHashCons(DefaultValueExpr dve, THashCons typeAccess) { + hashCons(dve.getTypeAccess()) = typeAccess +} + +private predicate defaultValueWithoutTypeHashCons(DefaultValueExpr dve) { + not exists(dve.getTypeAccess()) +} + +private predicate castHashCons(Cast cast, Type targetType, THashCons expr) { + // By not using hashCons(cast.getTypeAccess) we avoid unnecessary non-linear recursion + targetType = cast.getType() and + hashCons(cast.getExpr()) = expr +} + +pragma[nomagic] +private predicate assignmentHashConsLeft(Assignment a, THashCons left) { + numberableAssignment(a) and + hashCons(a.getLValue()) = left +} + +pragma[nomagic] +private predicate assignmentHashConsRight(Assignment a, THashCons right) { + numberableAssignment(a) and + hashCons(a.getRValue()) = right +} + +private predicate assignmentHashCons(Assignment a, string operator, THashCons left, THashCons right) { + a.getOperator() = operator and + assignmentHashConsLeft(a, left) and + assignmentHashConsRight(a, right) +} + +private predicate typeOfHashCons(TypeofExpr typeOf, THashCons typeAccess) { + numberableExpr(typeOf) and + hashCons(typeOf.getTypeAccess()) = typeAccess +} + +private predicate arrayAccessHashCons(ArrayAccess aa, THashCons index, THashCons qualifier) { + numberableExpr(aa) and + // TODO: This is a bit lazy. We should really do something similar to what we do for all arguments + index = hashCons(unique( | | aa.getAnIndex())) and + qualifier = hashCons(aa.getQualifier()) +} + +private signature module ListHashConsInputSig { + class List { + string toString(); + } + + Expr getExpr(List l, int i); +} + +private module ListHashCons { + private import Input + + int getNumberOfExprs(List list) { result = count(int i | exists(getExpr(list, i)) | i) } + + private predicate listArgsAreNumberable(List list, int remaining) { + getNumberOfExprs(list) = remaining + or + exists(Expr e | + listArgsAreNumberable(list, remaining + 1) and + e = getExpr(list, remaining) and + numberableExpr(e) + ) + } + + final class FinalList = List; + + class NumberableList extends FinalList { + NumberableList() { listArgsAreNumberable(this, 0) } + } + + pragma[nomagic] + predicate listHashCons(NumberableList list, TListPartialHashCons args) { + listPartialHashCons(list, getNumberOfExprs(list), args) + } + + pragma[nomagic] + private predicate listPartialHashCons(NumberableList list, int index, TListPartialHashCons head) { + exists(list) and + index = 0 and + head = TNilArgument() + or + exists(TListPartialHashCons prev, THashCons prevHashCons | + listPartialHashCons(list, index - 1, pragma[only_bind_out](prev)) and + listArgHashCons(list, index - 1, pragma[only_bind_into](prevHashCons)) and + head = TArgument(prev, prevHashCons) + ) + } + + pragma[nomagic] + private predicate listArgHashCons(NumberableList list, int index, THashCons arg) { + hashCons(getExpr(list, index)) = arg + } + + newtype TListPartialHashCons = + TNilArgument() or + TArgument(TListPartialHashCons head, THashCons arg) { + exists(NumberableList call, int index | + listArgHashCons(call, index, arg) and + listPartialHashCons(call, index, head) + ) + } +} + +private module CallHashConsInput implements ListHashConsInputSig { + class List = Call; + + Expr getExpr(List l, int i) { result = l.getArgument(i) } +} + +private module CallHashCons = ListHashCons; + +private predicate methodCallHashCons( + MethodCall call, string name, CallHashCons::TListPartialHashCons args +) { + numberableExpr(call) and + call.getTarget().getName() = name and + CallHashCons::listHashCons(call, args) +} + +private predicate constructorInitializerCallHashCons( + ConstructorInitializer call, string name, CallHashCons::TListPartialHashCons args +) { + CallHashCons::listHashCons(call, args) and + call.getTarget().getName() = name +} + +private predicate operatorCallHashCons( + OperatorCall call, string name, CallHashCons::TListPartialHashCons args +) { + CallHashCons::listHashCons(call, args) and + call.getTarget().getName() = name +} + +private predicate delegateLikeCallHashCons( + DelegateLikeCall call, THashCons expr, CallHashCons::TListPartialHashCons args +) { + numberableExpr(call) and + CallHashCons::listHashCons(call, args) and + hashCons(call.getExpr()) = expr +} + +private predicate objectCreationHashCons( + ObjectCreation oc, string name, CallHashCons::TListPartialHashCons args +) { + oc.getTarget().getName() = name and + CallHashCons::listHashCons(oc, args) +} + +private module ArrayInitializerHashConsInput implements ListHashConsInputSig { + class List extends ArrayInitializer { + List() { + // For performance reasons we restrict this to "small" array initializers. + this.getNumberOfElements() < 256 + } + } + + Expr getExpr(List l, int i) { result = l.getElement(i) } +} + +private module ArrayInitializerHashCons = ListHashCons; + +private module ArrayCreationHashConsInput implements ListHashConsInputSig { + class List = ArrayCreation; + + Expr getExpr(List l, int i) { result = l.getLengthArgument(i) } +} + +private module ArrayCreationHashCons = ListHashCons; + +private predicate arrayCreationHashCons( + ArrayCreation ac, THashCons initializer, ArrayCreationHashCons::TListPartialHashCons lengths +) { + tHashCons(ac.getInitializer()) = initializer and + ArrayCreationHashCons::listHashCons(ac, lengths) +} + +private predicate arrayInitializerHashCons( + ArrayInitializer ai, ArrayInitializerHashCons::TListPartialHashCons list +) { + ArrayInitializerHashCons::listHashCons(ai, list) +} + +private predicate localVariableDeclWithInitializerHashCons( + LocalVariableDeclExpr lvd, LocalVariable v, THashCons initializer +) { + lvd.getVariable() = v and + tHashCons(lvd.getInitializer()) = initializer +} + +private predicate localVariableDeclWithoutInitializerHashCons( + LocalVariableDeclExpr lvd, LocalVariable v +) { + lvd.getVariable() = v and + not exists(lvd.getInitializer()) +} + +private predicate defineSymbolHashCons(DefineSymbolExpr dse, string name) { dse.getName() = name } + +pragma[nomagic] +private predicate numberableBinaryLeftExpr(BinaryOperation binary) { + numberableExpr(binary.getLeftOperand()) +} + +pragma[nomagic] +private predicate numberableBinaryRightExpr(BinaryOperation binary) { + numberableExpr(binary.getRightOperand()) +} + +private predicate numberableBinaryExpr(BinaryOperation binary) { + numberableBinaryLeftExpr(binary) and + numberableBinaryRightExpr(binary) +} + +pragma[nomagic] +private predicate numberableDelegateLikeCallExpr(DelegateLikeCall dc) { + numberableExpr(dc.getExpr()) +} + +private predicate numberableCall(Call c) { + c instanceof CallHashCons::NumberableList and + ( + c instanceof MethodCall + or + c instanceof ConstructorInitializer + or + c instanceof OperatorCall + or + numberableDelegateLikeCallExpr(c) + or + c instanceof ObjectCreation + ) +} + +pragma[nomagic] +private predicate numberableConditionalCond(ConditionalExpr cond) { + numberableExpr(cond.getCondition()) +} + +pragma[nomagic] +private predicate numberableConditionalThen(ConditionalExpr cond) { numberableExpr(cond.getThen()) } + +pragma[nomagic] +private predicate numberableConditionalElse(ConditionalExpr cond) { numberableExpr(cond.getElse()) } + +private predicate numberableConditional(ConditionalExpr cond) { + numberableConditionalCond(cond) and + numberableConditionalThen(cond) and + numberableConditionalElse(cond) +} + +private predicate numberableDefaultValue(DefaultValueExpr dve) { + not exists(dve.getTypeAccess()) + or + numberableExpr(dve.getTypeAccess()) +} + +private predicate numberableCast(Cast cast) { numberableExpr(cast.getExpr()) } + +private predicate numberableAssignment(Assignment a) { + numberableExpr(a.getLValue()) and + numberableExpr(a.getRValue()) +} + +private predicate numberableTypeOfAccess(TypeofExpr typeOf) { + numberableExpr(typeOf.getTypeAccess()) +} + +private predicate numberableArrayAccess(ArrayAccess aa) { + numberableExpr(aa.getQualifier()) and + count(aa.getAnIndex()) = 1 +} + +private predicate numberableArrayInitializer(ArrayInitializer init) { + init.getNumberOfElements() < 256 and + init instanceof ArrayInitializerHashCons::NumberableList +} + +private predicate numberableArrayCreation(ArrayCreation ac) { + numberableExpr(ac.getInitializer()) and + ac instanceof ArrayCreationHashCons::NumberableList +} + +private predicate numberableLocalVariableDecl(LocalVariableDeclExpr lvd) { + not exists(lvd.getInitializer()) + or + numberableExpr(lvd.getInitializer()) +} + +/** + * Holds if `e` can be assigned a non-unique hashcons. + * + * Note: This predicate _must not_ depend on `THashCons`. + */ +private predicate numberableExpr(Expr e) { + e instanceof LocalScopeVariableAccess + or + e instanceof FieldAccess + or + e instanceof Literal + or + e instanceof TypeAccess + or + e instanceof IndexerAccess + or + e instanceof EventAccess + or + e instanceof DynamicMemberAccess + or + e instanceof DefineSymbolExpr + or + numberableExpr(e.(FieldAccess).getQualifier()) + or + numberableExpr(e.(PropertyAccess).getQualifier()) + or + numberableBinaryExpr(e) + or + numberableExpr(e.(UnaryOperation).getOperand()) + or + numberableCall(e) + or + numberableConditional(e) + or + e instanceof ThisAccess + or + e instanceof BaseAccess + or + numberableDefaultValue(e) + or + numberableCast(e) + or + numberableAssignment(e) + or + numberableTypeOfAccess(e) + or + numberableArrayAccess(e) + or + numberableArrayInitializer(e) + or + numberableArrayCreation(e) + or + numberableLocalVariableDecl(e) +} + +/** + * Gets the non-unique hashcons for `e`, if any. + */ +private THashCons nonUniqueHashCons(Expr e) { + exists(LocalScopeVariable v | + variableAccessHashCons(e, v) and + result = TVariableAccessHashCons(v) + ) + or + exists(Type type, string value | + constantHashCons(e, type, value) and + result = TConstantHashCons(type, value) + ) + or + exists(Field field, THashCons qualifier | + fieldAccessHashCons(e, field, qualifier) and + result = TFieldAccessHashCons(field, qualifier) + ) + or + exists(Property prop, THashCons qualifier | + propertyAccessHashCons(e, prop, qualifier) and + result = TPropertyAccessHashCons(prop, qualifier) + ) + or + exists(string operator, THashCons left, THashCons right | + binaryHashCons(e, operator, left, right) and + result = TBinaryHashCons(operator, left, right) + ) + or + exists(string operator, THashCons operand | + unaryHashCons(e, operator, operand) and + result = TUnaryHashCons(operator, operand) + ) + or + exists(THashCons cond, THashCons then_, THashCons else_ | + conditionalHashCons(e, cond, then_, else_) and + result = TConditionalHashCons(cond, then_, else_) + ) + or + exists(Type t | + typeAccessHashCons(e, t) and + result = TTypeAccessHashCons(t) + ) + or + exists(Indexer i | + indexerAccessHashCons(e, i) and + result = TIndexerAccessHashCons(i) + ) + or + exists(Event ev | + eventAccessHashCons(e, ev) and + result = TEventAccessHashCons(ev) + ) + or + exists(DynamicMember dm | + dynamicMemberAccessHashCons(e, dm) and + result = TDynamicMemberAccessHashCons(dm) + ) + or + exists(string name, CallHashCons::TListPartialHashCons args | + methodCallHashCons(e, name, args) and + result = TMethodCallHashCons(name, args) + ) + or + exists(string name, CallHashCons::TListPartialHashCons args | + constructorInitializerCallHashCons(e, name, args) and + result = TConstructorInitializerCallHashCons(name, args) + ) + or + exists(string name, CallHashCons::TListPartialHashCons args | + operatorCallHashCons(e, name, args) and + result = TOperatorCallHashCons(name, args) + ) + or + exists(THashCons expr, CallHashCons::TListPartialHashCons args | + delegateLikeCallHashCons(e, expr, args) and + result = TDelegateLikeCallHashCons(expr, args) + ) + or + exists(string name, CallHashCons::TListPartialHashCons args | + objectCreationHashCons(e, name, args) and + result = TObjectCreationHashCons(name, args) + ) + or + thisHashCons(e) and + result = TThisHashCons() + or + baseHashCons(e) and + result = TBaseHashCons() + or + defaultValueWithoutTypeHashCons(e) and + result = TDefaultValueWithoutTypeHashCons() + or + exists(THashCons typeAccess | + defaultValueWithTypeHashCons(e, typeAccess) and + result = TDefaultValueWithTypeHashCons(typeAccess) + ) + or + exists(THashCons operand, Type targetType | + castHashCons(e, targetType, operand) and + result = TCastHashCons(targetType, operand) + ) + or + exists(string operator, THashCons left, THashCons right | + assignmentHashCons(e, operator, left, right) and + result = TAssignmentHashCons(operator, left, right) + ) + or + exists(THashCons typeAccess | + typeOfHashCons(e, typeAccess) and + result = TTypeOfHashCons(typeAccess) + ) + or + exists(THashCons index, THashCons qualifier | + arrayAccessHashCons(e, index, qualifier) and + result = TArrayAccessHashCons(index, qualifier) + ) + or + exists(ArrayInitializerHashCons::TListPartialHashCons list | + arrayInitializerHashCons(e, list) and + result = TArrayInitializerHashCons(list) + ) + or + exists(THashCons initializer, ArrayCreationHashCons::TListPartialHashCons lengths | + arrayCreationHashCons(e, initializer, lengths) and + result = TArrayCreationHashCons(initializer, lengths) + ) + or + exists(Variable v, THashCons initializer | + localVariableDeclWithInitializerHashCons(e, v, initializer) and + result = TLocalVariableDeclWithInitializerHashCons(v, initializer) + ) + or + exists(Variable v | + localVariableDeclWithoutInitializerHashCons(e, v) and + result = TLocalVariableDeclWithoutInitializerHashCons(v) + ) + or + exists(string name | + defineSymbolHashCons(e, name) and + result = TDefineSymbolHashCons(name) + ) +} + +private predicate uniqueHashCons(Expr e) { not numberableExpr(e) } + +private THashCons tHashCons(Expr e) { + result = nonUniqueHashCons(e) + or + uniqueHashCons(e) and + result = TUniqueHashCons(e) +} + +/** + * Gets the hashcons of `e`, if any. + * + * To check if `e1` has the same structure as `e2` + * use `hashCons(e1).getAnExpr() = e2`. + */ +cached +HashCons hashCons(Expr e) { result = tHashCons(e) } + +/** + * A representation of the "structure" of an expression. + */ +class HashCons extends THashCons { + Expr getAnExpr() { this = hashCons(result) } + + /** Gets the unique representative expression with this hashcons. */ + private Expr getReprExpr() { + result = + min(Location loc, Expr e | + e = this.getAnExpr() and + loc = e.getLocation() + | + e order by loc.getFile().getAbsolutePath(), loc.getStartLine(), loc.getStartColumn() + ) + } + + /** + * Gets the string representation of this hash cons. + * + * This is the `toString` of an arbitrarily chosen expression with this + * hashcons. + */ + string toString() { result = this.getReprExpr().toString() } + + /** + * Gets the location of this hashcons. + * + * This is the location of an arbitrarily chosen expression with this + * hashcons. + */ + Location getLocation() { result = this.getReprExpr().getLocation() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll b/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll index 8634161e5a0..78b84587908 100644 --- a/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll +++ b/powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll @@ -527,13 +527,25 @@ module API { pred = MkNamespaceOfTypeNameNode(typeName) and succ = getForwardStartNode(typeName) ) - // or - // TODO: Handle getAMember when the predecessor is a MkUsingNode? + or + pred = MkRoot() and + exists(DataFlow::AutomaticVariableNode automatic | + automatic.getName() = name and + succ = getForwardStartNode(automatic) + ) + or + exists(MemberExprReadAccess read | + read.getMemberName().toLowerCase() = name and + pred = getForwardEndNode(getALocalSourceStrict(getNodeFromExpr(read.getQualifier()))) and + succ = getForwardStartNode(getNodeFromExpr(read)) + ) } cached predicate methodEdge(Node pred, string name, Node succ) { - exists(DataFlow::CallNode call | succ = MkMethodAccessNode(call) and name = call.getName() | + exists(DataFlow::CallNode call | + succ = MkMethodAccessNode(call) and name = call.getName().toLowerCase() + | pred = getForwardEndNode(getALocalSourceStrict(call.getQualifier())) ) } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll index 4acc6683d76..772aab474ae 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll @@ -32,8 +32,6 @@ newtype ChildIndex = // hasMemberInType(_, _, i, _) } or ThisVar() or - PipelineParamVar() or - PipelineByPropertyNameVar(Raw::PipelineByPropertyNameParameter p) or PipelineIteratorVar() or PipelineByPropertyNameIteratorVar(Raw::PipelineByPropertyNameParameter p) or RealVar(string name) { name = variableNameInScope(_, _) } or @@ -85,9 +83,6 @@ string stringOfChildIndex(ChildIndex i) { i = ThisVar() and result = "ThisVar" or - i = PipelineParamVar() and - result = "PipelineParamVar" - or i = PipelineIteratorVar() and result = "PipelineIteratorVar" or diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll index 8a0a82f06ab..6a3bc757ead 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Parameter.qll @@ -34,23 +34,49 @@ class Parameter extends Variable instanceof ParameterImpl { class ThisParameter extends Parameter instanceof ThisParameterImpl { } -class PipelineParameter extends Parameter { - PipelineParameter() { any(Synthesis s).isPipelineParameter(this) } +/** The pipeline parameter of a function. */ +class PipelineParameter extends Parameter instanceof PipelineParameterImpl { + ScriptBlock getScriptBlock() { result = super.getScriptBlock() } } -class PipelineByPropertyNameParameter extends Parameter { - PipelineByPropertyNameParameter() { - exists(NamedAttributeArgument namedAttribute | - this.getAnAttribute().(Attribute).getANamedArgument() = namedAttribute and - namedAttribute.getName().toLowerCase() = "valuefrompipelinebypropertyname" - | - namedAttribute.getValue().getValue().asBoolean() = true - or - not exists(namedAttribute.getValue().getValue().asBoolean()) - ) - } +/** + * The iterator variable associated with a pipeline parameter. + * + * This is the variable that is bound to the current element in the pipeline. + */ +class PipelineIteratorVariable extends Variable instanceof PipelineIteratorVariableImpl { + ProcessBlock getProcessBlock() { result = super.getProcessBlock() } +} - string getPropertyName() { result = this.getName() } +/** + * A pipeline-by-property-name parameter of a function. + */ +class PipelineByPropertyNameParameter extends Parameter instanceof PipelineByPropertyNameParameterImpl +{ + ScriptBlock getScriptBlock() { result = super.getScriptBlock() } + string getPropertyName() { result = super.getName() } + + /** + * Gets the iterator variable that is used to iterate over the elements in the pipeline. + */ PipelineByPropertyNameIteratorVariable getIteratorVariable() { result.getParameter() = this } } + +/** + * The iterator variable associated with a pipeline-by-property-name parameter. + * + * This is the variable that is bound to the current element in the pipeline. + */ +class PipelineByPropertyNameIteratorVariable extends Variable instanceof PipelineByPropertyNameIteratorVariableImpl +{ + ProcessBlock getProcessBlock() { result = super.getProcessBlock() } + + string getPropertyName() { result = super.getPropertyName() } + + /** + * Gets the pipeline-by-property-name parameter that this variable + * iterates over. + */ + PipelineByPropertyNameParameter getParameter() { result = super.getParameter() } +} \ No newline at end of file diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll index 343cd8927f1..899bb8d805a 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll @@ -88,12 +88,7 @@ class ScriptBlock extends Ast, TScriptBlock { ) } - Parameter getParameter(int i) { - synthChild(getRawAst(this), funParam(i), result) - or - any(Synthesis s).pipelineParameterHasIndex(this, i) and - synthChild(getRawAst(this), PipelineParamVar(), result) - } + Parameter getParameter(int i) { synthChild(getRawAst(this), funParam(i), result) } Parameter getThisParameter() { synthChild(getRawAst(this), ThisVar(), result) } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll index 2fee3dd99d6..f504942e05a 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -23,7 +23,6 @@ private import AutomaticVariable newtype VarKind = ThisVarKind() or ParamVarRealKind() or - ParamVarPipelineKind() or PipelineIteratorKind() or PipelineByPropertyNameIteratorKind(string name) { exists(Raw::ProcessBlock pb | @@ -78,9 +77,7 @@ class Synthesis extends TSynthesis { predicate parameterStaticType(Parameter p, string type) { none() } - predicate isPipelineParameter(Parameter p) { none() } - - predicate pipelineParameterHasIndex(ScriptBlock s, int i) { none() } + predicate pipelineParameterHasIndex(Raw::ScriptBlock s, int i) { none() } predicate functionName(FunctionBase f, string name) { none() } @@ -167,33 +164,28 @@ private module SetVariableAssignment { } } +/** Gets the pipeline parameter associated with `s`. */ +TVariable getPipelineParameter(Raw::ScriptBlock s) { + exists(ChildIndex i | + any(ParameterSynth::ParameterSynth ps).isPipelineParameterChild(s, _, i, _, _) and + result = TVariableSynth(s, i) + ) +} + /** * Syntesize parameters from parameter blocks and function definitions * so that they have a uniform API. */ private module ParameterSynth { - private class ParameterSynth extends Synthesis { + class ParameterSynth extends Synthesis { final override predicate isRelevant(Raw::Ast a) { a = any(Scope::Range r).getAParameter() } - private predicate parameter( - Raw::Ast parent, ChildIndex i, Raw::Parameter p, Child child, boolean isPipelineParameter - ) { + private predicate parameter(Raw::Ast parent, ChildIndex i, Raw::Parameter p, Child child) { exists(Scope::Range r, int index | p = r.getParameter(index) and parent = r and i = funParam(index) and - child = SynthChild(VarSynthKind(ParamVarRealKind())) and - if p instanceof Raw::PipelineParameter - then isPipelineParameter = true - else isPipelineParameter = false - ) - } - - final override predicate isPipelineParameter(Parameter p) { - exists(Raw::Ast parent, ChildIndex i | - parent = getRawAst(p.getFunction().getBody()) and - this.isPipelineParameterChild(parent, _, i) and - p = TVariableSynth(parent, i) + child = SynthChild(VarSynthKind(ParamVarRealKind())) ) } @@ -205,47 +197,49 @@ private module ParameterSynth { } final override predicate variableSynthName(VariableSynth v, string name) { - exists(Raw::Ast parent, int i, Raw::Parameter p | - this.parameter(parent, FunParam(i), p, _, false) and - v = TVariableSynth(parent, FunParam(i)) and - name = p.getName() - ) - or - exists(Raw::Ast parent | - this.child(parent, PipelineParamVar(), _) and - v = TVariableSynth(parent, PipelineParamVar()) and + exists(Raw::Ast parent, ChildIndex i | v = TVariableSynth(parent, i) | + exists(Raw::Parameter p | + this.parameter(parent, i, p, _) and + name = p.getName() + ) + or + this.isPipelineParameterChild(parent, _, i, _, true) and name = "[synth] pipeline" ) } - private predicate isPipelineParameterChild(Raw::Ast parent, int index, ChildIndex i) { - exists(Scope::Range r | parent = r and i = PipelineParamVar() | - r.getParameter(index) instanceof Raw::PipelineParameter + predicate isPipelineParameterChild( + Raw::Ast parent, int index, ChildIndex i, Child child, boolean synthesized + ) { + exists(Scope::Range r | + parent = r and + i = funParam(index) and + child = SynthChild(VarSynthKind(ParamVarRealKind())) + | + r.getParameter(index) instanceof Raw::PipelineParameter and + synthesized = false or not r.getAParameter() instanceof Raw::PipelineParameter and - index = synthPipelineParameterChildIndex(r) + index = synthPipelineParameterChildIndex(r) and + synthesized = true ) } - final override predicate pipelineParameterHasIndex(ScriptBlock s, int i) { - exists(Raw::ScriptBlock scriptBlock | - s = TScriptBlock(scriptBlock) and - this.isPipelineParameterChild(scriptBlock, i, _) - ) + final override predicate pipelineParameterHasIndex(Raw::ScriptBlock s, int i) { + this.isPipelineParameterChild(s, i, _, _, _) } final override predicate child(Raw::Ast parent, ChildIndex i, Child child) { // Synthesize parameters - this.parameter(parent, i, _, child, false) + this.parameter(parent, i, _, child) or - // Synthesize pipeline parameter - child = SynthChild(VarSynthKind(ParamVarPipelineKind())) and - this.isPipelineParameterChild(parent, _, i) + // Synthesize implicit pipeline parameter, if necessary + this.isPipelineParameterChild(parent, _, i, child, true) or // Synthesize default values exists(Raw::Parameter q | parent = q and - this.parameter(_, _, q, _, _) + this.parameter(_, _, q, _) | i = paramDefaultVal() and child = childRef(getResultAst(q.getDefaultValue())) @@ -258,30 +252,30 @@ private module ParameterSynth { } final override Parameter getResultAstImpl(Raw::Ast r) { - exists(Raw::Ast parent, int i | - this.parameter(parent, FunParam(i), r, _, false) and - result = TVariableSynth(parent, FunParam(i)) - ) - or - exists(Scope::Range scope, int i, ChildIndex index | - scope.getParameter(i) = r and - this.isPipelineParameterChild(scope, i, index) and - result = TVariableSynth(scope, index) + exists(Raw::Ast parent, ChildIndex i | + this.parameter(parent, i, r, _) and + result = TVariableSynth(parent, i) ) } final override Location getLocation(Ast n) { - exists(Raw::Ast parent, Raw::Parameter p, int i | - this.parameter(parent, _, p, _, _) and - n = TVariableSynth(parent, FunParam(i)) and - result = p.getLocation() + exists(Raw::Ast parent, ChildIndex i | n = TVariableSynth(parent, i) | + exists(Raw::Parameter p | + this.parameter(parent, i, p, _) and + result = p.getLocation() + ) + or + this.isPipelineParameterChild(parent, _, i, _, true) and + result = parent.getLocation() ) } final override predicate parameterStaticType(Parameter n, string type) { - exists(Raw::Ast parent, int i, Raw::Parameter p | - this.parameter(parent, FunParam(i), p, _, false) and - n = TVariableSynth(parent, FunParam(i)) and + exists(Raw::Ast parent, Raw::Parameter p, ChildIndex i | + // No need to consider the synthesized pipeline parameter as it never + // has a static type. + this.parameter(parent, i, p, _) and + n = TVariableSynth(parent, i) and type = p.getStaticType() ) } @@ -440,6 +434,11 @@ private module FunctionSynth { n = TFunctionSynth(fundefStmt, _) and result = fundefStmt.getLocation() ) + or + exists(Raw::TopLevelScriptBlock topLevelScriptBlock | + n = TTopLevelFunction(topLevelScriptBlock) and + result = topLevelScriptBlock.getLocation() + ) } } } @@ -857,8 +856,10 @@ private module IteratorAccessSynth { result = cmdExpr.getLocation() ) or - exists(Raw::Ast parent | - n = TVariableSynth(parent, _) and + exists(Raw::Ast parent, ChildIndex i | + i instanceof PipelineIteratorVar or i instanceof PipelineByPropertyNameIteratorVar + | + n = TVariableSynth(parent, i) and result = parent.getLocation() ) } @@ -870,12 +871,12 @@ private module PipelineAccess { final override predicate child(Raw::Ast parent, ChildIndex i, Child child) { exists(Raw::ProcessBlock pb | parent = pb | i = processBlockPipelineVarReadAccess() and - exists(PipelineVariable pipelineVar | - pipelineVar = TVariableSynth(pb.getScriptBlock(), PipelineParamVar()) and + exists(PipelineParameter pipelineVar | + pipelineVar = getPipelineParameter(pb.getScriptBlock()) and child = SynthChild(VarAccessSynthKind(pipelineVar)) ) or - exists(PipelineByPropertyNameVariable pipelineVar, Raw::PipelineByPropertyNameParameter p | + exists(PipelineByPropertyNameParameter pipelineVar, Raw::PipelineByPropertyNameParameter p | i = processBlockPipelineByPropertyNameVarReadAccess(p.getName()) and getResultAst(p) = pipelineVar and child = SynthChild(VarAccessSynthKind(pipelineVar)) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll index 73f1d1fe371..92c015e9e13 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TypeExpression.qll @@ -25,6 +25,11 @@ class TypeNameExpr extends Expr, TTypeNameExpr { override string toString() { result = this.getName() } predicate isQualified() { this.getNamespace() != "" } + + predicate hasQualifiedName(string namespace, string typename) { + this.isQualified() and + this.parseName(namespace, typename) + } } class QualifiedTypeNameExpr extends TypeNameExpr { diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll index c1d0a53edfb..bfff89bdd20 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll @@ -38,7 +38,7 @@ module Private { override string getNameImpl() { any(Synthesis s).variableSynthName(this, result) } - override Location getLocationImpl() { result = scope.getLocation() } + override Location getLocationImpl() { result = any(Synthesis s).getLocation(this) } override Scope::Range getDeclaringScopeImpl() { result = scope } } @@ -46,7 +46,6 @@ module Private { class ParameterImpl extends VariableSynth { ParameterImpl() { i instanceof FunParam or - i instanceof PipelineParamVar or i instanceof ThisVar } } @@ -55,14 +54,21 @@ module Private { override ThisVar i; } - class PipelineVariableImpl extends ParameterImpl { - override PipelineParamVar i; + class PipelineParameterImpl extends ParameterImpl { + override FunParam i; + + PipelineParameterImpl() { + exists(int index | + i = FunParam(index) and + any(Synthesis s).pipelineParameterHasIndex(super.getDeclaringScopeImpl(), index) + ) + } ScriptBlock getScriptBlock() { this = TVariableSynth(getRawAst(result), _) } } - class PipelineByPropertyNameVariableImpl extends ParameterImpl { - PipelineByPropertyNameVariableImpl() { + class PipelineByPropertyNameParameterImpl extends ParameterImpl { + PipelineByPropertyNameParameterImpl() { getRawAst(this) instanceof Raw::PipelineByPropertyNameParameter } @@ -167,28 +173,6 @@ module Public { class VarReadAccess extends VarAccess { VarReadAccess() { not this instanceof VarWriteAccess } } - - class PipelineByPropertyNameIteratorVariable extends Variable instanceof PipelineByPropertyNameIteratorVariableImpl - { - ProcessBlock getProcessBlock() { result = super.getProcessBlock() } - - string getPropertyName() { result = super.getPropertyName() } - - PipelineByPropertyNameParameter getParameter() { result = super.getParameter() } - } - - class PipelineVariable extends Variable instanceof PipelineVariableImpl { - ScriptBlock getScriptBlock() { result = super.getScriptBlock() } - } - - class PipelineByPropertyNameVariable extends Variable instanceof PipelineByPropertyNameVariableImpl - { - ScriptBlock getScriptBlock() { result = super.getScriptBlock() } - } - - class PipelineIteratorVariable extends Variable instanceof PipelineIteratorVariableImpl { - ProcessBlock getProcessBlock() { result = super.getProcessBlock() } - } } import Public diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll index 58ca40b5e71..ba638404462 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll @@ -291,11 +291,11 @@ class ProcessBlockCfgNode extends NamedBlockCfgNode { ScriptBlockCfgNode getScriptBlock() { result.getProcessBlock() = this } - PipelineVariable getPipelineVariable() { + PipelineParameter getPipelineParameter() { result.getScriptBlock() = this.getScriptBlock().getAstNode() } - ExprNodes::VarReadAccessCfgNode getPipelineVariableAccess() { + ExprNodes::VarReadAccessCfgNode getPipelineParameterAccess() { block.hasCfgChild(block.getPipelineParameterAccess(), this, result) } @@ -685,14 +685,24 @@ module ExprNodes { string getPossiblyQualifiedName() { result = e.getPossiblyQualifiedName() } predicate isQualified() { e.isQualified() } + + predicate hasQualifiedName(string namespace, string typename) { + e.hasQualifiedName(namespace, typename) + } + } + + private class QualifiedTypeNameExprChildMapping extends TypeNameExprChildMapping, + QualifiedTypeNameExpr + { + override predicate relevantChild(Ast child) { super.relevantChild(child) } } class QualifiedTypeNameExprCfgNode extends TypeNameExprCfgNode { - QualifiedTypeNameExprCfgNode() { e.isQualified() } + override QualifiedTypeNameExprChildMapping e; + + override TypeNameExpr getExpr() { result = e } override string getAPrimaryQlClass() { result = "QualifiedTypeNameExprCfgNode" } - - override QualifiedTypeNameExpr getExpr() { result = e } } private class ErrorExprChildMapping extends ExprChildMapping, ErrorExpr { @@ -1061,6 +1071,20 @@ module ExprNodes { ExprCfgNode getAnOperand() { e.hasCfgChild(e.getAnOperand(), this, result) } } + + private class AutomaticVariableChildMapping extends ExprChildMapping, AutomaticVariable { + override predicate relevantChild(Ast child) { none() } + } + + class AutomaticVariableCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "AutomaticVariableCfgNode" } + + override AutomaticVariableChildMapping e; + + override AutomaticVariable getExpr() { result = e } + + string getName() { result = e.getName() } + } } module StmtNodes { diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowDispatch.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowDispatch.qll index 6619cb9887d..3c3dba5cfd7 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowDispatch.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowDispatch.qll @@ -242,6 +242,12 @@ class AdditionalCallTarget extends Unit { abstract DataFlowCallable viableTarget(CfgNodes::ExprNodes::CallExprCfgNode call); } +DataFlowCallable viableSourceCallable(DataFlowCall call) { + result.asCfgScope() = getTargetInstance(call.asCall()) + or + result = any(AdditionalCallTarget t).viableTarget(call.asCall()) +} + /** Holds if `call` may resolve to the returned summarized library method. */ DataFlowCallable viableLibraryCallable(DataFlowCall call) { exists(LibraryCallable callable | @@ -269,13 +275,13 @@ private module Cached { /** Gets a viable run-time target for the call `call`. */ cached DataFlowCallable viableCallable(DataFlowCall call) { - result.asCfgScope() = getTargetInstance(call.asCall()) + result = viableSourceCallable(call) or - result = any(AdditionalCallTarget t).viableTarget(call.asCall()) + result = viableLibraryCallable(call) } cached - CfgScope getTarget(DataFlowCall call) { result = viableCallable(call).asCfgScope() } + CfgScope getTarget(DataFlowCall call) { result = viableSourceCallable(call).asCfgScope() } cached newtype TArgumentPosition = diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll index 2197b71317c..2c520b60a56 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll @@ -171,7 +171,7 @@ module LocalFlow { nodeTo = TProcessPropertyByNameNode(pbNode.getAccess().getVariable(), false) ) or - nodeTo.(PreProcessNode).getProcessBlock().getPipelineVariableAccess() = nodeFrom.asExpr() + nodeTo.(PreProcessNode).getProcessBlock().getPipelineParameterAccess() = nodeFrom.asExpr() or nodeTo.(ProcessNode).getProcessBlock() = nodeFrom.(PreProcessNode).getProcessBlock() } @@ -994,7 +994,7 @@ predicate readStep(Node node1, ContentSet c, Node node2) { or c.isAnyPositional() and exists(CfgNodes::ProcessBlockCfgNode processBlock | - processBlock.getPipelineVariableAccess() = node1.asExpr() and + processBlock.getPipelineParameterAccess() = node1.asExpr() and node2 = TProcessNode(processBlock) ) or diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll index 28cfd4ed304..9be635555c9 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll @@ -544,6 +544,10 @@ class TypeNameNode extends ExprNode { predicate isQualified() { n.isQualified() } + predicate hasQualifiedName(string namespace, string typename) { + n.hasQualifiedName(namespace, typename) + } + string getNamespace() { result = n.getNamespace() } string getPossiblyQualifiedName() { result = n.getPossiblyQualifiedName() } @@ -555,3 +559,12 @@ class QualifiedTypeNameNode extends TypeNameNode { final override CfgNodes::ExprNodes::QualifiedTypeNameExprCfgNode getExprNode() { result = n } } + +/** A use of an automatic variable, viewed as a node in a data flow graph. */ +class AutomaticVariableNode extends ExprNode { + override CfgNodes::ExprNodes::AutomaticVariableCfgNode n; + + final override CfgNodes::ExprNodes::AutomaticVariableCfgNode getExprNode() { result = n } + + string getName() { result = n.getName() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll index 9c6132c7a29..d4fe6b6151b 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingPrivate.qll @@ -3,6 +3,7 @@ private import DataFlowPrivate private import TaintTrackingPublic private import semmle.code.powershell.Cfg private import semmle.code.powershell.dataflow.DataFlow +private import FlowSummaryImpl as FlowSummaryImpl /** * Holds if `node` should be a sanitizer in all global taint flow configurations @@ -58,6 +59,16 @@ private module Cached { ) ) and model = "" + or + FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), + nodeTo.(FlowSummaryNode).getSummaryNode(), false, model) + } + + cached + predicate summaryThroughStepTaint( + DataFlow::Node arg, DataFlow::Node out, FlowSummaryImpl::Public::SummarizedCallable sc + ) { + FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(arg, out, sc) } /** @@ -67,7 +78,10 @@ private module Cached { cached predicate localTaintStepCached(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { DataFlow::localFlowStep(nodeFrom, nodeTo) or - defaultAdditionalTaintStep(nodeFrom, nodeTo, _) + defaultAdditionalTaintStep(nodeFrom, nodeTo, _) or + // Simple flow through library code is included in the exposed local + // step relation, even though flow is technically inter-procedural + summaryThroughStepTaint(nodeFrom, nodeTo, _) } } diff --git a/powershell/ql/lib/semmle/code/powershell/frameworks/SystemManagementAutomation/model.yml b/powershell/ql/lib/semmle/code/powershell/frameworks/SystemManagementAutomation/model.yml index e6f507d6a29..856a958b8bc 100644 --- a/powershell/ql/lib/semmle/code/powershell/frameworks/SystemManagementAutomation/model.yml +++ b/powershell/ql/lib/semmle/code/powershell/frameworks/SystemManagementAutomation/model.yml @@ -1820,3 +1820,9 @@ extensions: - ["System.Collections.ObjectModel.ReadOnlyCollection", "System.Management.Automation.FunctionInfo", "Property[OutputType]"] - ["System.Management.Automation.Language.ParseError[]", "System.Management.Automation.ParseException", "Property[Errors]"] - ["System.Management.Automation.DSCResourceRunAsCredential", "System.Management.Automation.DscResourceAttribute", "Property[RunAsCredential]"] + + - addsTo: + pack: microsoft-sdl/powershell-all + extensible: summaryModel + data: + - ["System.Management.Automation.Language.CodeGeneration!", "Method[escapesinglequotedstringcontent]", "Argument[0]", "ReturnValue", "taint"] \ No newline at end of file diff --git a/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll b/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll index c2061c238b2..ef34f8c4f00 100644 --- a/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -69,12 +69,23 @@ API::Node getExtraNodeFromPath(string type, AccessPath path, int n) { } /** Gets a Powershell-specific interpretation of the given `type`. */ -API::Node getExtraNodeFromType(string type) { - exists(string consts, string suffix | parseRelevantType(type, consts, suffix) | - none() // TODO +API::Node getExtraNodeFromType(string rawType) { + exists( + string type, string suffix, DataFlow::QualifiedTypeNameNode qualifiedTypeName, string namespace, + string typename + | + parseRelevantType(rawType, type, suffix) and + qualifiedTypeName.hasQualifiedName(namespace, typename) and + namespace + "." + typename = type + | + suffix = "!" and + result = qualifiedTypeName.(DataFlow::LocalSourceNode).track() + or + suffix = "" and + result = qualifiedTypeName.(DataFlow::LocalSourceNode).track().getInstance() ) or - type = "" and + rawType = "" and result = API::root() } diff --git a/powershell/ql/test/library-tests/ast/Blocks/blocks.expected b/powershell/ql/test/library-tests/ast/Blocks/blocks.expected index 0d4882c4c41..82ef295aa52 100644 --- a/powershell/ql/test/library-tests/ast/Blocks/blocks.expected +++ b/powershell/ql/test/library-tests/ast/Blocks/blocks.expected @@ -1,2 +1,2 @@ -| ParamBlock.ps1:1:1:5:1 | {...} | 0 | ParamBlock.ps1:1:1:5:1 | Parameter | +| ParamBlock.ps1:1:1:5:1 | {...} | 0 | ParamBlock.ps1:3:5:4:22 | Parameter | | ParamBlock.ps1:1:1:5:1 | {...} | 1 | ParamBlock.ps1:1:1:5:1 | [synth] pipeline | diff --git a/powershell/ql/test/library-tests/ast/Statements/statements.expected b/powershell/ql/test/library-tests/ast/Statements/statements.expected index 6f85c09bdd1..f8994f47694 100644 --- a/powershell/ql/test/library-tests/ast/Statements/statements.expected +++ b/powershell/ql/test/library-tests/ast/Statements/statements.expected @@ -22,4 +22,4 @@ | Try.ps1:11:9:13:1 | {...} | | Try.ps1:12:5:12:36 | [Stmt] The finally block is executed. | | UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | def of Get-Number | -| UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | (no string representation) | +| UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | [Stmt] Number | diff --git a/powershell/ql/test/library-tests/ast/parent.expected b/powershell/ql/test/library-tests/ast/parent.expected index 7fc8f9f9f72..7c27e930667 100644 --- a/powershell/ql/test/library-tests/ast/parent.expected +++ b/powershell/ql/test/library-tests/ast/parent.expected @@ -2,8 +2,8 @@ | Arrays/Arrays.ps1:1:1:1:7 | array1 | Arrays/Arrays.ps1:1:1:1:36 | ...=... | | Arrays/Arrays.ps1:1:1:1:7 | array1 | Arrays/Arrays.ps1:1:1:15:14 | {...} | | Arrays/Arrays.ps1:1:1:1:36 | ...=... | Arrays/Arrays.ps1:1:1:15:14 | {...} | +| Arrays/Arrays.ps1:1:1:15:14 | {...} | Arrays/Arrays.ps1:1:1:15:14 | toplevel function for Arrays.ps1 | | Arrays/Arrays.ps1:1:1:15:14 | {...} | Arrays/Arrays.ps1:1:1:15:14 | {...} | -| Arrays/Arrays.ps1:1:1:15:14 | {...} | file://:0:0:0:0 | toplevel function for Arrays.ps1 | | Arrays/Arrays.ps1:1:11:1:11 | 1 | Arrays/Arrays.ps1:1:11:1:36 | ...,... | | Arrays/Arrays.ps1:1:11:1:36 | ...,... | Arrays/Arrays.ps1:1:1:1:36 | ...=... | | Arrays/Arrays.ps1:1:13:1:13 | 2 | Arrays/Arrays.ps1:1:11:1:36 | ...,... | @@ -84,17 +84,17 @@ | Arrays/Arrays.ps1:15:9:15:11 | Add | Arrays/Arrays.ps1:15:1:15:14 | Call to Add | | Arrays/Arrays.ps1:15:13:15:13 | 1 | Arrays/Arrays.ps1:15:1:15:14 | Call to Add | | Blocks/ParamBlock.ps1:1:1:1:17 | CmdletBinding | Blocks/ParamBlock.ps1:1:1:5:1 | {...} | -| Blocks/ParamBlock.ps1:1:1:5:1 | Parameter | Blocks/ParamBlock.ps1:1:1:5:1 | {...} | | Blocks/ParamBlock.ps1:1:1:5:1 | [synth] pipeline | Blocks/ParamBlock.ps1:1:1:5:1 | {...} | -| Blocks/ParamBlock.ps1:1:1:5:1 | {...} | file://:0:0:0:0 | toplevel function for ParamBlock.ps1 | +| Blocks/ParamBlock.ps1:1:1:5:1 | {...} | Blocks/ParamBlock.ps1:1:1:5:1 | toplevel function for ParamBlock.ps1 | | Blocks/ParamBlock.ps1:2:1:5:1 | {...} | Blocks/ParamBlock.ps1:1:1:5:1 | {...} | -| Blocks/ParamBlock.ps1:3:5:3:17 | Parameter | Blocks/ParamBlock.ps1:1:1:5:1 | Parameter | -| Blocks/ParamBlock.ps1:4:5:4:12 | string | Blocks/ParamBlock.ps1:1:1:5:1 | Parameter | +| Blocks/ParamBlock.ps1:3:5:3:17 | Parameter | Blocks/ParamBlock.ps1:3:5:4:22 | Parameter | +| Blocks/ParamBlock.ps1:3:5:4:22 | Parameter | Blocks/ParamBlock.ps1:1:1:5:1 | {...} | +| Blocks/ParamBlock.ps1:4:5:4:12 | string | Blocks/ParamBlock.ps1:3:5:4:22 | Parameter | | Dynamic/DynamicExecution.ps1:1:1:1:4 | foo | Dynamic/DynamicExecution.ps1:1:1:1:16 | ...=... | | Dynamic/DynamicExecution.ps1:1:1:1:4 | foo | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | | Dynamic/DynamicExecution.ps1:1:1:1:16 | ...=... | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | +| Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | Dynamic/DynamicExecution.ps1:1:1:5:7 | toplevel function for DynamicExecution.ps1 | | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | -| Dynamic/DynamicExecution.ps1:1:1:5:7 | {...} | file://:0:0:0:0 | toplevel function for DynamicExecution.ps1 | | Dynamic/DynamicExecution.ps1:1:8:1:16 | cmd.exe | Dynamic/DynamicExecution.ps1:1:1:1:16 | ...=... | | Dynamic/DynamicExecution.ps1:2:1:2:17 | Invoke-Expression | Dynamic/DynamicExecution.ps1:2:1:2:22 | Call to Invoke-Expression | | Dynamic/DynamicExecution.ps1:2:1:2:22 | Call to Invoke-Expression | Dynamic/DynamicExecution.ps1:2:1:2:22 | [Stmt] Call to Invoke-Expression | @@ -118,12 +118,12 @@ | Dynamic/DynamicExecution.ps1:5:3:5:6 | foo | Dynamic/DynamicExecution.ps1:5:2:5:7 | $foo | | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | ExecuteAThing | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | def of ExecuteAThing | | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | def of ExecuteAThing | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | toplevel function for DynamicExecutionWithFunc.ps1 | | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | {...} | file://:0:0:0:0 | toplevel function for DynamicExecutionWithFunc.ps1 | | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | [synth] pipeline | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | -| Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | userInput | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:1:1:11:1 | ExecuteAThing | | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:29 | {...} | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | +| Dynamic/DynamicExecutionWithFunc.ps1:3:9:3:18 | userInput | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | | Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:8 | foo | Dynamic/DynamicExecutionWithFunc.ps1:1:24:11:1 | {...} | | Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:8 | foo | Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:33 | ...=... | | Dynamic/DynamicExecutionWithFunc.ps1:5:5:5:33 | ...=... | Dynamic/DynamicExecutionWithFunc.ps1:2:5:10:29 | {...} | @@ -160,8 +160,8 @@ | Expressions/BinaryExpression.ps1:1:1:1:5 | val1 | Expressions/BinaryExpression.ps1:1:1:1:9 | ...=... | | Expressions/BinaryExpression.ps1:1:1:1:5 | val1 | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | | Expressions/BinaryExpression.ps1:1:1:1:9 | ...=... | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | +| Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | Expressions/BinaryExpression.ps1:1:1:4:7 | toplevel function for BinaryExpression.ps1 | | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | -| Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | file://:0:0:0:0 | toplevel function for BinaryExpression.ps1 | | Expressions/BinaryExpression.ps1:1:9:1:9 | 1 | Expressions/BinaryExpression.ps1:1:1:1:9 | ...=... | | Expressions/BinaryExpression.ps1:2:1:2:5 | val2 | Expressions/BinaryExpression.ps1:1:1:4:7 | {...} | | Expressions/BinaryExpression.ps1:2:1:2:5 | val2 | Expressions/BinaryExpression.ps1:2:1:2:9 | ...=... | @@ -178,8 +178,8 @@ | Expressions/ConvertWithSecureString.ps1:1:1:1:10 | UserInput | Expressions/ConvertWithSecureString.ps1:1:1:1:54 | ...=... | | Expressions/ConvertWithSecureString.ps1:1:1:1:10 | UserInput | Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | | Expressions/ConvertWithSecureString.ps1:1:1:1:54 | ...=... | Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | +| Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | Expressions/ConvertWithSecureString.ps1:1:1:2:79 | toplevel function for ConvertWithSecureString.ps1 | | Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | -| Expressions/ConvertWithSecureString.ps1:1:1:2:79 | {...} | file://:0:0:0:0 | toplevel function for ConvertWithSecureString.ps1 | | Expressions/ConvertWithSecureString.ps1:1:14:1:22 | Read-Host | Expressions/ConvertWithSecureString.ps1:1:14:1:54 | Call to Read-Host | | Expressions/ConvertWithSecureString.ps1:1:14:1:54 | Call to Read-Host | Expressions/ConvertWithSecureString.ps1:1:1:1:54 | ...=... | | Expressions/ConvertWithSecureString.ps1:1:24:1:54 | Please enter your secure code | Expressions/ConvertWithSecureString.ps1:1:14:1:54 | Call to Read-Host | @@ -191,8 +191,8 @@ | Expressions/ConvertWithSecureString.ps1:2:50:2:59 | UserInput | Expressions/ConvertWithSecureString.ps1:2:19:2:79 | Call to ConvertTo-SecureString | | Expressions/ExpandableString.ps1:1:1:1:39 | Date: $([DateTime]::Now)\nName: $name | Expressions/ExpandableString.ps1:1:1:1:39 | [Stmt] Date: $([DateTime]::Now)\nName: $name | | Expressions/ExpandableString.ps1:1:1:1:39 | [Stmt] Date: $([DateTime]::Now)\nName: $name | Expressions/ExpandableString.ps1:1:1:1:39 | {...} | +| Expressions/ExpandableString.ps1:1:1:1:39 | {...} | Expressions/ExpandableString.ps1:1:1:1:39 | toplevel function for ExpandableString.ps1 | | Expressions/ExpandableString.ps1:1:1:1:39 | {...} | Expressions/ExpandableString.ps1:1:1:1:39 | {...} | -| Expressions/ExpandableString.ps1:1:1:1:39 | {...} | file://:0:0:0:0 | toplevel function for ExpandableString.ps1 | | Expressions/ExpandableString.ps1:1:21:1:38 | $(...) | Expressions/ExpandableString.ps1:1:1:1:39 | Date: $([DateTime]::Now)\nName: $name | | Expressions/ExpandableString.ps1:1:23:1:32 | DateTime | Expressions/ExpandableString.ps1:1:23:1:37 | Now | | Expressions/ExpandableString.ps1:1:23:1:37 | Now | Expressions/ExpandableString.ps1:1:23:1:37 | [Stmt] Now | @@ -202,8 +202,8 @@ | Expressions/SubExpression.ps1:1:1:1:11 | $(...) | Expressions/SubExpression.ps1:1:1:1:23 | Call to AddDays | | Expressions/SubExpression.ps1:1:1:1:23 | Call to AddDays | Expressions/SubExpression.ps1:1:1:1:23 | [Stmt] Call to AddDays | | Expressions/SubExpression.ps1:1:1:1:23 | [Stmt] Call to AddDays | Expressions/SubExpression.ps1:1:1:2:21 | {...} | +| Expressions/SubExpression.ps1:1:1:2:21 | {...} | Expressions/SubExpression.ps1:1:1:2:21 | toplevel function for SubExpression.ps1 | | Expressions/SubExpression.ps1:1:1:2:21 | {...} | Expressions/SubExpression.ps1:1:1:2:21 | {...} | -| Expressions/SubExpression.ps1:1:1:2:21 | {...} | file://:0:0:0:0 | toplevel function for SubExpression.ps1 | | Expressions/SubExpression.ps1:1:3:1:10 | Call to Get-Date | Expressions/SubExpression.ps1:1:3:1:10 | [Stmt] Call to Get-Date | | Expressions/SubExpression.ps1:1:3:1:10 | Get-Date | Expressions/SubExpression.ps1:1:3:1:10 | Call to Get-Date | | Expressions/SubExpression.ps1:1:3:1:10 | [Stmt] Call to Get-Date | Expressions/SubExpression.ps1:1:3:1:10 | {...} | @@ -221,8 +221,8 @@ | Expressions/TernaryExpression.ps1:1:1:1:4 | var | Expressions/TernaryExpression.ps1:1:1:1:22 | ...=... | | Expressions/TernaryExpression.ps1:1:1:1:4 | var | Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | | Expressions/TernaryExpression.ps1:1:1:1:22 | ...=... | Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | +| Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | Expressions/TernaryExpression.ps1:1:1:1:22 | toplevel function for TernaryExpression.ps1 | | Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | -| Expressions/TernaryExpression.ps1:1:1:1:22 | {...} | file://:0:0:0:0 | toplevel function for TernaryExpression.ps1 | | Expressions/TernaryExpression.ps1:1:8:1:16 | (...) | Expressions/TernaryExpression.ps1:1:8:1:22 | ...?...:... | | Expressions/TernaryExpression.ps1:1:8:1:22 | ...?...:... | Expressions/TernaryExpression.ps1:1:1:1:22 | ...=... | | Expressions/TernaryExpression.ps1:1:9:1:9 | 6 | Expressions/TernaryExpression.ps1:1:9:1:15 | ... -gt ... | @@ -231,8 +231,8 @@ | Expressions/TernaryExpression.ps1:1:20:1:20 | 1 | Expressions/TernaryExpression.ps1:1:8:1:22 | ...?...:... | | Expressions/TernaryExpression.ps1:1:22:1:22 | 2 | Expressions/TernaryExpression.ps1:1:8:1:22 | ...?...:... | | Loops/DoUntil.ps1:1:1:7:18 | do...until... | Loops/DoUntil.ps1:1:1:7:18 | {...} | +| Loops/DoUntil.ps1:1:1:7:18 | {...} | Loops/DoUntil.ps1:1:1:7:18 | toplevel function for DoUntil.ps1 | | Loops/DoUntil.ps1:1:1:7:18 | {...} | Loops/DoUntil.ps1:1:1:7:18 | {...} | -| Loops/DoUntil.ps1:1:1:7:18 | {...} | file://:0:0:0:0 | toplevel function for DoUntil.ps1 | | Loops/DoUntil.ps1:2:1:7:1 | {...} | Loops/DoUntil.ps1:1:1:7:18 | do...until... | | Loops/DoUntil.ps1:3:2:3:19 | Starting Loop $a | Loops/DoUntil.ps1:3:2:3:19 | [Stmt] Starting Loop $a | | Loops/DoUntil.ps1:3:2:3:19 | [Stmt] Starting Loop $a | Loops/DoUntil.ps1:2:1:7:1 | {...} | @@ -244,8 +244,8 @@ | Loops/DoUntil.ps1:7:10:7:17 | ... -le ... | Loops/DoUntil.ps1:1:1:7:18 | do...until... | | Loops/DoUntil.ps1:7:17:7:17 | 5 | Loops/DoUntil.ps1:7:10:7:17 | ... -le ... | | Loops/DoWhile.ps1:1:1:7:18 | do...while... | Loops/DoWhile.ps1:1:1:7:18 | {...} | +| Loops/DoWhile.ps1:1:1:7:18 | {...} | Loops/DoWhile.ps1:1:1:7:18 | toplevel function for DoWhile.ps1 | | Loops/DoWhile.ps1:1:1:7:18 | {...} | Loops/DoWhile.ps1:1:1:7:18 | {...} | -| Loops/DoWhile.ps1:1:1:7:18 | {...} | file://:0:0:0:0 | toplevel function for DoWhile.ps1 | | Loops/DoWhile.ps1:2:1:7:1 | {...} | Loops/DoWhile.ps1:1:1:7:18 | do...while... | | Loops/DoWhile.ps1:3:2:3:19 | Starting Loop $a | Loops/DoWhile.ps1:3:2:3:19 | [Stmt] Starting Loop $a | | Loops/DoWhile.ps1:3:2:3:19 | [Stmt] Starting Loop $a | Loops/DoWhile.ps1:2:1:7:1 | {...} | @@ -259,8 +259,8 @@ | Loops/While.ps1:1:1:1:4 | var | Loops/While.ps1:1:1:1:8 | ...=... | | Loops/While.ps1:1:1:1:4 | var | Loops/While.ps1:1:1:13:1 | {...} | | Loops/While.ps1:1:1:1:8 | ...=... | Loops/While.ps1:1:1:13:1 | {...} | +| Loops/While.ps1:1:1:13:1 | {...} | Loops/While.ps1:1:1:13:1 | toplevel function for While.ps1 | | Loops/While.ps1:1:1:13:1 | {...} | Loops/While.ps1:1:1:13:1 | {...} | -| Loops/While.ps1:1:1:13:1 | {...} | file://:0:0:0:0 | toplevel function for While.ps1 | | Loops/While.ps1:1:8:1:8 | 1 | Loops/While.ps1:1:1:1:8 | ...=... | | Loops/While.ps1:2:1:13:1 | while(...) {...} | Loops/While.ps1:1:1:13:1 | {...} | | Loops/While.ps1:2:8:2:11 | var | Loops/While.ps1:2:8:2:17 | ... -le ... | @@ -290,8 +290,8 @@ | Loops/While.ps1:11:9:11:13 | break | Loops/While.ps1:10:5:12:5 | {...} | | Redirections/FileRedirection.ps1:1:1:3:1 | $(...) | Redirections/FileRedirection.ps1:1:1:3:19 | [Stmt] $(...) | | Redirections/FileRedirection.ps1:1:1:3:19 | [Stmt] $(...) | Redirections/FileRedirection.ps1:1:1:3:19 | {...} | +| Redirections/FileRedirection.ps1:1:1:3:19 | {...} | Redirections/FileRedirection.ps1:1:1:3:19 | toplevel function for FileRedirection.ps1 | | Redirections/FileRedirection.ps1:1:1:3:19 | {...} | Redirections/FileRedirection.ps1:1:1:3:19 | {...} | -| Redirections/FileRedirection.ps1:1:1:3:19 | {...} | file://:0:0:0:0 | toplevel function for FileRedirection.ps1 | | Redirections/FileRedirection.ps1:2:5:2:8 | Here | Redirections/FileRedirection.ps1:2:5:2:31 | Call to Here | | Redirections/FileRedirection.ps1:2:5:2:31 | Call to Here | Redirections/FileRedirection.ps1:2:5:2:31 | [Stmt] Call to Here | | Redirections/FileRedirection.ps1:2:5:2:31 | [Stmt] Call to Here | Redirections/FileRedirection.ps1:2:5:2:31 | {...} | @@ -302,14 +302,14 @@ | Redirections/FileRedirection.ps1:2:26:2:31 | script | Redirections/FileRedirection.ps1:2:5:2:31 | Call to Here | | Redirections/FileRedirection.ps1:3:10:3:19 | output.txt | Redirections/FileRedirection.ps1:3:8:3:19 | FileRedirection | | Statements/ExitStatement.ps1:1:1:1:7 | exit ... | Statements/ExitStatement.ps1:1:1:1:7 | {...} | +| Statements/ExitStatement.ps1:1:1:1:7 | {...} | Statements/ExitStatement.ps1:1:1:1:7 | toplevel function for ExitStatement.ps1 | | Statements/ExitStatement.ps1:1:1:1:7 | {...} | Statements/ExitStatement.ps1:1:1:1:7 | {...} | -| Statements/ExitStatement.ps1:1:1:1:7 | {...} | file://:0:0:0:0 | toplevel function for ExitStatement.ps1 | | Statements/ExitStatement.ps1:1:6:1:7 | -1 | Statements/ExitStatement.ps1:1:1:1:7 | exit ... | | Statements/IfStatement.ps1:1:1:1:2 | x | Statements/IfStatement.ps1:1:1:1:6 | ...=... | | Statements/IfStatement.ps1:1:1:1:2 | x | Statements/IfStatement.ps1:1:1:8:1 | {...} | | Statements/IfStatement.ps1:1:1:1:6 | ...=... | Statements/IfStatement.ps1:1:1:8:1 | {...} | +| Statements/IfStatement.ps1:1:1:8:1 | {...} | Statements/IfStatement.ps1:1:1:8:1 | toplevel function for IfStatement.ps1 | | Statements/IfStatement.ps1:1:1:8:1 | {...} | Statements/IfStatement.ps1:1:1:8:1 | {...} | -| Statements/IfStatement.ps1:1:1:8:1 | {...} | file://:0:0:0:0 | toplevel function for IfStatement.ps1 | | Statements/IfStatement.ps1:1:6:1:6 | 4 | Statements/IfStatement.ps1:1:1:1:6 | ...=... | | Statements/IfStatement.ps1:3:1:8:1 | [Stmt] if (...) {...} else {...} | Statements/IfStatement.ps1:1:1:8:1 | {...} | | Statements/IfStatement.ps1:3:1:8:1 | if (...) {...} else {...} | Statements/IfStatement.ps1:3:1:8:1 | [Stmt] if (...) {...} else {...} | @@ -326,8 +326,8 @@ | Statements/IfStatement.ps1:7:3:7:4 | x | Statements/IfStatement.ps1:7:2:7:20 | $x is less than 3 | | Statements/TrapStatement.ps1:1:1:4:1 | TrapTest | Statements/TrapStatement.ps1:1:1:4:1 | def of TrapTest | | Statements/TrapStatement.ps1:1:1:4:1 | def of TrapTest | Statements/TrapStatement.ps1:1:1:6:8 | {...} | +| Statements/TrapStatement.ps1:1:1:6:8 | {...} | Statements/TrapStatement.ps1:1:1:6:8 | toplevel function for TrapStatement.ps1 | | Statements/TrapStatement.ps1:1:1:6:8 | {...} | Statements/TrapStatement.ps1:1:1:6:8 | {...} | -| Statements/TrapStatement.ps1:1:1:6:8 | {...} | file://:0:0:0:0 | toplevel function for TrapStatement.ps1 | | Statements/TrapStatement.ps1:1:19:4:1 | [synth] pipeline | Statements/TrapStatement.ps1:1:19:4:1 | {...} | | Statements/TrapStatement.ps1:1:19:4:1 | {...} | Statements/TrapStatement.ps1:1:1:4:1 | TrapTest | | Statements/TrapStatement.ps1:2:5:2:25 | trap {...} | Statements/TrapStatement.ps1:2:5:3:18 | {...} | @@ -342,8 +342,8 @@ | Statements/TrapStatement.ps1:6:1:6:8 | TrapTest | Statements/TrapStatement.ps1:6:1:6:8 | Call to TrapTest | | Statements/TrapStatement.ps1:6:1:6:8 | [Stmt] Call to TrapTest | Statements/TrapStatement.ps1:1:1:6:8 | {...} | | Statements/Try.ps1:1:1:13:1 | try {...} | Statements/Try.ps1:1:1:13:1 | {...} | +| Statements/Try.ps1:1:1:13:1 | {...} | Statements/Try.ps1:1:1:13:1 | toplevel function for Try.ps1 | | Statements/Try.ps1:1:1:13:1 | {...} | Statements/Try.ps1:1:1:13:1 | {...} | -| Statements/Try.ps1:1:1:13:1 | {...} | file://:0:0:0:0 | toplevel function for Try.ps1 | | Statements/Try.ps1:1:5:4:1 | {...} | Statements/Try.ps1:1:1:13:1 | try {...} | | Statements/Try.ps1:2:4:2:13 | Exception | Statements/Try.ps1:1:1:13:1 | {...} | | Statements/Try.ps1:2:4:2:13 | Exception | Statements/Try.ps1:2:4:2:94 | ...=... | @@ -374,14 +374,15 @@ | Statements/Try.ps1:12:5:12:36 | [Stmt] The finally block is executed. | Statements/Try.ps1:11:9:13:1 | {...} | | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | Get-Number | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | def of Get-Number | | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | def of Get-Number | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | +| Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | toplevel function for UseProcessBlockForPipelineCommand.ps1 | | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | -| Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | file://:0:0:0:0 | toplevel function for UseProcessBlockForPipelineCommand.ps1 | -| Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | [synth] pipeline | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | Get-Number | | Statements/UseProcessBlockForPipelineCommand.ps1:3:5:3:21 | CmdletBinding | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | | Statements/UseProcessBlockForPipelineCommand.ps1:4:5:10:11 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | -| Statements/UseProcessBlockForPipelineCommand.ps1:5:9:5:38 | ValueFromPipeline | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | [synth] pipeline | +| Statements/UseProcessBlockForPipelineCommand.ps1:5:9:5:38 | ValueFromPipeline | Statements/UseProcessBlockForPipelineCommand.ps1:5:9:7:15 | Number | +| Statements/UseProcessBlockForPipelineCommand.ps1:5:9:7:15 | Number | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | | Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:36 | (no string representation) | Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:36 | ValueFromPipeline | | Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:36 | ValueFromPipeline | Statements/UseProcessBlockForPipelineCommand.ps1:5:9:5:38 | ValueFromPipeline | -| Statements/UseProcessBlockForPipelineCommand.ps1:6:9:6:13 | int | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | [synth] pipeline | -| Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | (no string representation) | Statements/UseProcessBlockForPipelineCommand.ps1:4:5:10:11 | {...} | +| Statements/UseProcessBlockForPipelineCommand.ps1:6:9:6:13 | int | Statements/UseProcessBlockForPipelineCommand.ps1:5:9:7:15 | Number | +| Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | Number | Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | [Stmt] Number | +| Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | [Stmt] Number | Statements/UseProcessBlockForPipelineCommand.ps1:4:5:10:11 | {...} | diff --git a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected index 51cfda6735d..ad0746a58c4 100644 --- a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -6,9 +6,9 @@ | conditionals.ps1:1:18:9:1 | [synth] pipeline | conditionals.ps1:2:5:8:13 | {...} | | | conditionals.ps1:1:18:9:1 | enter {...} | conditionals.ps1:1:18:9:1 | {...} | | | conditionals.ps1:1:18:9:1 | exit {...} (normal) | conditionals.ps1:1:18:9:1 | exit {...} | | -| conditionals.ps1:1:18:9:1 | myBool | conditionals.ps1:1:18:9:1 | [synth] pipeline | | -| conditionals.ps1:1:18:9:1 | {...} | conditionals.ps1:1:18:9:1 | myBool | | +| conditionals.ps1:1:18:9:1 | {...} | conditionals.ps1:2:11:2:17 | myBool | | | conditionals.ps1:2:5:8:13 | {...} | conditionals.ps1:4:5:7:5 | [Stmt] if (...) {...} | | +| conditionals.ps1:2:11:2:17 | myBool | conditionals.ps1:1:18:9:1 | [synth] pipeline | | | conditionals.ps1:4:5:7:5 | [Stmt] if (...) {...} | conditionals.ps1:4:8:4:14 | myBool | | | conditionals.ps1:4:5:7:5 | if (...) {...} | conditionals.ps1:8:5:8:13 | return ... | | | conditionals.ps1:4:8:4:14 | myBool | conditionals.ps1:4:5:7:5 | if (...) {...} | false | @@ -22,9 +22,9 @@ | conditionals.ps1:11:23:22:1 | [synth] pipeline | conditionals.ps1:12:5:21:5 | {...} | | | conditionals.ps1:11:23:22:1 | enter {...} | conditionals.ps1:11:23:22:1 | {...} | | | conditionals.ps1:11:23:22:1 | exit {...} (normal) | conditionals.ps1:11:23:22:1 | exit {...} | | -| conditionals.ps1:11:23:22:1 | myBool | conditionals.ps1:11:23:22:1 | [synth] pipeline | | -| conditionals.ps1:11:23:22:1 | {...} | conditionals.ps1:11:23:22:1 | myBool | | +| conditionals.ps1:11:23:22:1 | {...} | conditionals.ps1:12:11:12:17 | myBool | | | conditionals.ps1:12:5:21:5 | {...} | conditionals.ps1:14:5:21:5 | [Stmt] if (...) {...} else {...} | | +| conditionals.ps1:12:11:12:17 | myBool | conditionals.ps1:11:23:22:1 | [synth] pipeline | | | conditionals.ps1:14:5:21:5 | [Stmt] if (...) {...} else {...} | conditionals.ps1:14:8:14:14 | myBool | | | conditionals.ps1:14:5:21:5 | if (...) {...} else {...} | conditionals.ps1:11:23:22:1 | exit {...} (normal) | | | conditionals.ps1:14:8:14:14 | myBool | conditionals.ps1:15:5:17:5 | {...} | true | @@ -39,10 +39,10 @@ | conditionals.ps1:24:23:32:1 | [synth] pipeline | conditionals.ps1:25:5:31:13 | {...} | | | conditionals.ps1:24:23:32:1 | enter {...} | conditionals.ps1:24:23:32:1 | {...} | | | conditionals.ps1:24:23:32:1 | exit {...} (normal) | conditionals.ps1:24:23:32:1 | exit {...} | | -| conditionals.ps1:24:23:32:1 | myBool1 | conditionals.ps1:24:23:32:1 | myBool2 | | -| conditionals.ps1:24:23:32:1 | myBool2 | conditionals.ps1:24:23:32:1 | [synth] pipeline | | -| conditionals.ps1:24:23:32:1 | {...} | conditionals.ps1:24:23:32:1 | myBool1 | | +| conditionals.ps1:24:23:32:1 | {...} | conditionals.ps1:25:11:25:18 | myBool1 | | | conditionals.ps1:25:5:31:13 | {...} | conditionals.ps1:27:5:30:5 | [Stmt] if (...) {...} | | +| conditionals.ps1:25:11:25:18 | myBool1 | conditionals.ps1:25:21:25:28 | myBool2 | | +| conditionals.ps1:25:21:25:28 | myBool2 | conditionals.ps1:24:23:32:1 | [synth] pipeline | | | conditionals.ps1:27:5:30:5 | [Stmt] if (...) {...} | conditionals.ps1:27:8:27:15 | myBool1 | | | conditionals.ps1:27:5:30:5 | if (...) {...} | conditionals.ps1:31:5:31:13 | return ... | | | conditionals.ps1:27:8:27:15 | myBool1 | conditionals.ps1:27:22:27:29 | myBool2 | false, true | @@ -59,10 +59,10 @@ | conditionals.ps1:34:28:45:1 | [synth] pipeline | conditionals.ps1:35:5:44:5 | {...} | | | conditionals.ps1:34:28:45:1 | enter {...} | conditionals.ps1:34:28:45:1 | {...} | | | conditionals.ps1:34:28:45:1 | exit {...} (normal) | conditionals.ps1:34:28:45:1 | exit {...} | | -| conditionals.ps1:34:28:45:1 | myBool1 | conditionals.ps1:34:28:45:1 | myBool2 | | -| conditionals.ps1:34:28:45:1 | myBool2 | conditionals.ps1:34:28:45:1 | [synth] pipeline | | -| conditionals.ps1:34:28:45:1 | {...} | conditionals.ps1:34:28:45:1 | myBool1 | | +| conditionals.ps1:34:28:45:1 | {...} | conditionals.ps1:35:11:35:18 | myBool1 | | | conditionals.ps1:35:5:44:5 | {...} | conditionals.ps1:37:5:44:5 | [Stmt] if (...) {...} else {...} | | +| conditionals.ps1:35:11:35:18 | myBool1 | conditionals.ps1:35:21:35:28 | myBool2 | | +| conditionals.ps1:35:21:35:28 | myBool2 | conditionals.ps1:34:28:45:1 | [synth] pipeline | | | conditionals.ps1:37:5:44:5 | [Stmt] if (...) {...} else {...} | conditionals.ps1:37:8:37:15 | myBool1 | | | conditionals.ps1:37:5:44:5 | if (...) {...} else {...} | conditionals.ps1:34:28:45:1 | exit {...} (normal) | | | conditionals.ps1:37:8:37:15 | myBool1 | conditionals.ps1:37:22:37:29 | myBool2 | false, true | @@ -80,10 +80,10 @@ | conditionals.ps1:47:23:55:1 | [synth] pipeline | conditionals.ps1:48:5:54:13 | {...} | | | conditionals.ps1:47:23:55:1 | enter {...} | conditionals.ps1:47:23:55:1 | {...} | | | conditionals.ps1:47:23:55:1 | exit {...} (normal) | conditionals.ps1:47:23:55:1 | exit {...} | | -| conditionals.ps1:47:23:55:1 | myBool1 | conditionals.ps1:47:23:55:1 | myBool2 | | -| conditionals.ps1:47:23:55:1 | myBool2 | conditionals.ps1:47:23:55:1 | [synth] pipeline | | -| conditionals.ps1:47:23:55:1 | {...} | conditionals.ps1:47:23:55:1 | myBool1 | | +| conditionals.ps1:47:23:55:1 | {...} | conditionals.ps1:48:11:48:18 | myBool1 | | | conditionals.ps1:48:5:54:13 | {...} | conditionals.ps1:50:5:53:5 | [Stmt] if (...) {...} | | +| conditionals.ps1:48:11:48:18 | myBool1 | conditionals.ps1:48:21:48:28 | myBool2 | | +| conditionals.ps1:48:21:48:28 | myBool2 | conditionals.ps1:47:23:55:1 | [synth] pipeline | | | conditionals.ps1:50:5:53:5 | [Stmt] if (...) {...} | conditionals.ps1:50:8:50:15 | myBool1 | | | conditionals.ps1:50:5:53:5 | if (...) {...} | conditionals.ps1:54:5:54:13 | return ... | | | conditionals.ps1:50:8:50:15 | myBool1 | conditionals.ps1:50:21:50:28 | myBool2 | false, true | @@ -100,10 +100,10 @@ | conditionals.ps1:57:28:68:1 | [synth] pipeline | conditionals.ps1:58:5:67:5 | {...} | | | conditionals.ps1:57:28:68:1 | enter {...} | conditionals.ps1:57:28:68:1 | {...} | | | conditionals.ps1:57:28:68:1 | exit {...} (normal) | conditionals.ps1:57:28:68:1 | exit {...} | | -| conditionals.ps1:57:28:68:1 | myBool1 | conditionals.ps1:57:28:68:1 | myBool2 | | -| conditionals.ps1:57:28:68:1 | myBool2 | conditionals.ps1:57:28:68:1 | [synth] pipeline | | -| conditionals.ps1:57:28:68:1 | {...} | conditionals.ps1:57:28:68:1 | myBool1 | | +| conditionals.ps1:57:28:68:1 | {...} | conditionals.ps1:58:11:58:18 | myBool1 | | | conditionals.ps1:58:5:67:5 | {...} | conditionals.ps1:60:5:67:5 | [Stmt] if (...) {...} else {...} | | +| conditionals.ps1:58:11:58:18 | myBool1 | conditionals.ps1:58:21:58:28 | myBool2 | | +| conditionals.ps1:58:21:58:28 | myBool2 | conditionals.ps1:57:28:68:1 | [synth] pipeline | | | conditionals.ps1:60:5:67:5 | [Stmt] if (...) {...} else {...} | conditionals.ps1:60:8:60:15 | myBool1 | | | conditionals.ps1:60:5:67:5 | if (...) {...} else {...} | conditionals.ps1:57:28:68:1 | exit {...} (normal) | | | conditionals.ps1:60:8:60:15 | myBool1 | conditionals.ps1:60:21:60:28 | myBool2 | false, true | @@ -121,10 +121,10 @@ | conditionals.ps1:70:23:82:1 | [synth] pipeline | conditionals.ps1:71:5:81:13 | {...} | | | conditionals.ps1:70:23:82:1 | enter {...} | conditionals.ps1:70:23:82:1 | {...} | | | conditionals.ps1:70:23:82:1 | exit {...} (normal) | conditionals.ps1:70:23:82:1 | exit {...} | | -| conditionals.ps1:70:23:82:1 | myBool1 | conditionals.ps1:70:23:82:1 | myBool2 | | -| conditionals.ps1:70:23:82:1 | myBool2 | conditionals.ps1:70:23:82:1 | [synth] pipeline | | -| conditionals.ps1:70:23:82:1 | {...} | conditionals.ps1:70:23:82:1 | myBool1 | | +| conditionals.ps1:70:23:82:1 | {...} | conditionals.ps1:71:11:71:18 | myBool1 | | | conditionals.ps1:71:5:81:13 | {...} | conditionals.ps1:73:5:80:5 | [Stmt] if (...) {...} | | +| conditionals.ps1:71:11:71:18 | myBool1 | conditionals.ps1:71:21:71:28 | myBool2 | | +| conditionals.ps1:71:21:71:28 | myBool2 | conditionals.ps1:70:23:82:1 | [synth] pipeline | | | conditionals.ps1:73:5:80:5 | [Stmt] if (...) {...} | conditionals.ps1:73:8:73:15 | myBool1 | | | conditionals.ps1:73:5:80:5 | if (...) {...} | conditionals.ps1:81:5:81:13 | return ... | | | conditionals.ps1:73:8:73:15 | myBool1 | conditionals.ps1:73:5:80:5 | if (...) {...} | false | @@ -138,10 +138,10 @@ | conditionals.ps1:84:28:99:1 | [synth] pipeline | conditionals.ps1:85:5:98:5 | {...} | | | conditionals.ps1:84:28:99:1 | enter {...} | conditionals.ps1:84:28:99:1 | {...} | | | conditionals.ps1:84:28:99:1 | exit {...} (normal) | conditionals.ps1:84:28:99:1 | exit {...} | | -| conditionals.ps1:84:28:99:1 | myBool1 | conditionals.ps1:84:28:99:1 | myBool2 | | -| conditionals.ps1:84:28:99:1 | myBool2 | conditionals.ps1:84:28:99:1 | [synth] pipeline | | -| conditionals.ps1:84:28:99:1 | {...} | conditionals.ps1:84:28:99:1 | myBool1 | | +| conditionals.ps1:84:28:99:1 | {...} | conditionals.ps1:85:11:85:18 | myBool1 | | | conditionals.ps1:85:5:98:5 | {...} | conditionals.ps1:87:5:98:5 | [Stmt] if (...) {...} else {...} | | +| conditionals.ps1:85:11:85:18 | myBool1 | conditionals.ps1:85:21:85:28 | myBool2 | | +| conditionals.ps1:85:21:85:28 | myBool2 | conditionals.ps1:84:28:99:1 | [synth] pipeline | | | conditionals.ps1:87:5:98:5 | [Stmt] if (...) {...} else {...} | conditionals.ps1:87:8:87:15 | myBool1 | | | conditionals.ps1:87:5:98:5 | if (...) {...} else {...} | conditionals.ps1:84:28:99:1 | exit {...} (normal) | | | conditionals.ps1:87:8:87:15 | myBool1 | conditionals.ps1:88:5:90:5 | {...} | true | @@ -153,11 +153,11 @@ | conditionals.ps1:97:9:97:17 | return ... | conditionals.ps1:97:16:97:17 | 12 | | | conditionals.ps1:97:16:97:17 | 12 | conditionals.ps1:87:5:98:5 | if (...) {...} else {...} | | | conditionals.ps1:101:1:108:1 | def of test-switch | conditionals.ps1:110:1:121:1 | def of test-switch-default | | +| conditionals.ps1:101:22:101:23 | n | conditionals.ps1:101:26:108:1 | [synth] pipeline | | | conditionals.ps1:101:26:108:1 | [synth] pipeline | conditionals.ps1:102:5:107:5 | {...} | | | conditionals.ps1:101:26:108:1 | enter {...} | conditionals.ps1:101:26:108:1 | {...} | | | conditionals.ps1:101:26:108:1 | exit {...} (normal) | conditionals.ps1:101:26:108:1 | exit {...} | | -| conditionals.ps1:101:26:108:1 | n | conditionals.ps1:101:26:108:1 | [synth] pipeline | | -| conditionals.ps1:101:26:108:1 | {...} | conditionals.ps1:101:26:108:1 | n | | +| conditionals.ps1:101:26:108:1 | {...} | conditionals.ps1:101:22:101:23 | n | | | conditionals.ps1:102:5:107:5 | switch(...) {...} | conditionals.ps1:102:12:102:13 | n | | | conditionals.ps1:102:5:107:5 | {...} | conditionals.ps1:102:5:107:5 | switch(...) {...} | | | conditionals.ps1:102:12:102:13 | n | conditionals.ps1:104:9:104:10 | 0: | | @@ -177,11 +177,11 @@ | conditionals.ps1:106:14:106:21 | return ... | conditionals.ps1:106:21:106:21 | 2 | | | conditionals.ps1:106:21:106:21 | 2 | conditionals.ps1:101:26:108:1 | exit {...} (normal) | | | conditionals.ps1:110:1:121:1 | def of test-switch-default | conditionals.ps1:123:1:129:1 | def of test-switch-assign | | +| conditionals.ps1:110:30:110:31 | n | conditionals.ps1:110:34:121:1 | [synth] pipeline | | | conditionals.ps1:110:34:121:1 | [synth] pipeline | conditionals.ps1:111:5:120:5 | {...} | | | conditionals.ps1:110:34:121:1 | enter {...} | conditionals.ps1:110:34:121:1 | {...} | | | conditionals.ps1:110:34:121:1 | exit {...} (normal) | conditionals.ps1:110:34:121:1 | exit {...} | | -| conditionals.ps1:110:34:121:1 | n | conditionals.ps1:110:34:121:1 | [synth] pipeline | | -| conditionals.ps1:110:34:121:1 | {...} | conditionals.ps1:110:34:121:1 | n | | +| conditionals.ps1:110:34:121:1 | {...} | conditionals.ps1:110:30:110:31 | n | | | conditionals.ps1:111:5:120:5 | switch(...) {...} | conditionals.ps1:111:12:111:13 | n | | | conditionals.ps1:111:5:120:5 | {...} | conditionals.ps1:111:5:120:5 | switch(...) {...} | | | conditionals.ps1:111:12:111:13 | n | conditionals.ps1:113:9:113:10 | 0: | | @@ -210,11 +210,11 @@ | conditionals.ps1:118:13:118:20 | return ... | conditionals.ps1:118:20:118:20 | 3 | | | conditionals.ps1:118:20:118:20 | 3 | conditionals.ps1:110:34:121:1 | exit {...} (normal) | | | conditionals.ps1:123:1:129:1 | def of test-switch-assign | conditionals.ps1:1:1:129:1 | exit {...} (normal) | | +| conditionals.ps1:123:29:123:30 | n | conditionals.ps1:123:33:129:1 | [synth] pipeline | | | conditionals.ps1:123:33:129:1 | [synth] pipeline | conditionals.ps1:124:5:128:5 | {...} | | | conditionals.ps1:123:33:129:1 | enter {...} | conditionals.ps1:123:33:129:1 | {...} | | | conditionals.ps1:123:33:129:1 | exit {...} (normal) | conditionals.ps1:123:33:129:1 | exit {...} | | -| conditionals.ps1:123:33:129:1 | n | conditionals.ps1:123:33:129:1 | [synth] pipeline | | -| conditionals.ps1:123:33:129:1 | {...} | conditionals.ps1:123:33:129:1 | n | | +| conditionals.ps1:123:33:129:1 | {...} | conditionals.ps1:123:29:123:30 | n | | | conditionals.ps1:124:5:124:6 | a | conditionals.ps1:123:33:129:1 | exit {...} (normal) | | | conditionals.ps1:124:5:128:5 | ...=... | conditionals.ps1:124:5:124:6 | a | | | conditionals.ps1:124:5:128:5 | {...} | conditionals.ps1:124:5:128:5 | ...=... | | @@ -226,37 +226,37 @@ | functions.ps1:1:32:9:1 | [synth] pipeline | functions.ps1:3:5:8:23 | {...} | | | functions.ps1:1:32:9:1 | enter {...} | functions.ps1:1:32:9:1 | {...} | | | functions.ps1:1:32:9:1 | exit {...} (normal) | functions.ps1:1:32:9:1 | exit {...} | | -| functions.ps1:1:32:9:1 | number1 | functions.ps1:1:32:9:1 | number2 | | -| functions.ps1:1:32:9:1 | number2 | functions.ps1:1:32:9:1 | [synth] pipeline | | -| functions.ps1:1:32:9:1 | {...} | functions.ps1:1:32:9:1 | number1 | | +| functions.ps1:1:32:9:1 | {...} | functions.ps1:4:9:4:22 | number1 | | | functions.ps1:3:5:8:23 | {...} | functions.ps1:8:5:8:23 | [Stmt] ...+... | | +| functions.ps1:4:9:4:22 | number1 | functions.ps1:5:9:5:22 | number2 | | +| functions.ps1:5:9:5:22 | number2 | functions.ps1:1:32:9:1 | [synth] pipeline | | | functions.ps1:8:5:8:12 | number1 | functions.ps1:8:16:8:23 | number2 | | | functions.ps1:8:5:8:23 | ...+... | functions.ps1:1:32:9:1 | exit {...} (normal) | | | functions.ps1:8:5:8:23 | [Stmt] ...+... | functions.ps1:8:5:8:12 | number1 | | | functions.ps1:8:16:8:23 | number2 | functions.ps1:8:5:8:23 | ...+... | | | functions.ps1:11:1:11:28 | def of foo | functions.ps1:13:1:20:1 | def of Default-Arguments | | | functions.ps1:11:16:11:28 | [synth] pipeline | functions.ps1:11:18:11:26 | {...} | | -| functions.ps1:11:16:11:28 | a | functions.ps1:11:16:11:28 | [synth] pipeline | | | functions.ps1:11:16:11:28 | enter {...} | functions.ps1:11:16:11:28 | {...} | | | functions.ps1:11:16:11:28 | exit {...} (normal) | functions.ps1:11:16:11:28 | exit {...} | | -| functions.ps1:11:16:11:28 | {...} | functions.ps1:11:16:11:28 | a | | +| functions.ps1:11:16:11:28 | {...} | functions.ps1:11:24:11:25 | a | | | functions.ps1:11:18:11:26 | {...} | functions.ps1:11:16:11:28 | exit {...} (normal) | | +| functions.ps1:11:24:11:25 | a | functions.ps1:11:16:11:28 | [synth] pipeline | | | functions.ps1:13:1:20:1 | def of Default-Arguments | functions.ps1:22:1:34:1 | def of Add-Numbers-From-Array | | | functions.ps1:13:28:20:1 | [synth] pipeline | functions.ps1:14:5:19:18 | {...} | | | functions.ps1:13:28:20:1 | enter {...} | functions.ps1:13:28:20:1 | {...} | | | functions.ps1:13:28:20:1 | exit {...} (normal) | functions.ps1:13:28:20:1 | exit {...} | | -| functions.ps1:13:28:20:1 | name0 | functions.ps1:13:28:20:1 | name1 | | -| functions.ps1:13:28:20:1 | name1 | functions.ps1:13:28:20:1 | name2 | | -| functions.ps1:13:28:20:1 | name1 | functions.ps1:16:24:16:24 | 0 | | -| functions.ps1:13:28:20:1 | name2 | functions.ps1:13:28:20:1 | [synth] pipeline | | -| functions.ps1:13:28:20:1 | name2 | functions.ps1:17:24:17:29 | name1 | | | functions.ps1:13:28:20:1 | {...} | functions.ps1:16:24:16:24 | 0 | | | functions.ps1:14:5:19:18 | {...} | functions.ps1:19:5:19:18 | [Stmt] ...+... | | -| functions.ps1:16:24:16:24 | 0 | functions.ps1:13:28:20:1 | name2 | | +| functions.ps1:15:9:15:20 | name0 | functions.ps1:16:9:16:24 | name1 | | +| functions.ps1:16:9:16:24 | name1 | functions.ps1:16:24:16:24 | 0 | | +| functions.ps1:16:9:16:24 | name1 | functions.ps1:17:9:17:33 | name2 | | +| functions.ps1:16:24:16:24 | 0 | functions.ps1:17:9:17:33 | name2 | | | functions.ps1:16:24:16:24 | 0 | functions.ps1:17:24:17:29 | name1 | | +| functions.ps1:17:9:17:33 | name2 | functions.ps1:13:28:20:1 | [synth] pipeline | | +| functions.ps1:17:9:17:33 | name2 | functions.ps1:17:24:17:29 | name1 | | | functions.ps1:17:24:17:29 | name1 | functions.ps1:17:33:17:33 | 1 | | | functions.ps1:17:24:17:33 | ...+... | functions.ps1:13:28:20:1 | [synth] pipeline | | -| functions.ps1:17:24:17:33 | ...+... | functions.ps1:13:28:20:1 | name0 | | +| functions.ps1:17:24:17:33 | ...+... | functions.ps1:15:9:15:20 | name0 | | | functions.ps1:17:33:17:33 | 1 | functions.ps1:17:24:17:33 | ...+... | | | functions.ps1:19:5:19:18 | ...+... | functions.ps1:13:28:20:1 | exit {...} (normal) | | | functions.ps1:19:5:19:18 | [Stmt] ...+... | functions.ps1:19:13:19:18 | name2 | | @@ -265,9 +265,9 @@ | functions.ps1:22:33:34:1 | [synth] pipeline | functions.ps1:24:5:33:8 | {...} | | | functions.ps1:22:33:34:1 | enter {...} | functions.ps1:22:33:34:1 | {...} | | | functions.ps1:22:33:34:1 | exit {...} (normal) | functions.ps1:22:33:34:1 | exit {...} | | -| functions.ps1:22:33:34:1 | numbers | functions.ps1:22:33:34:1 | [synth] pipeline | | -| functions.ps1:22:33:34:1 | {...} | functions.ps1:22:33:34:1 | numbers | | +| functions.ps1:22:33:34:1 | {...} | functions.ps1:25:9:25:24 | numbers | | | functions.ps1:24:5:33:8 | {...} | functions.ps1:28:5:28:12 | ...=... | | +| functions.ps1:25:9:25:24 | numbers | functions.ps1:22:33:34:1 | [synth] pipeline | | | functions.ps1:28:5:28:8 | sum | functions.ps1:28:12:28:12 | 0 | | | functions.ps1:28:5:28:12 | ...=... | functions.ps1:28:5:28:8 | sum | | | functions.ps1:28:12:28:12 | 0 | functions.ps1:29:25:29:32 | numbers | | @@ -285,8 +285,8 @@ | functions.ps1:36:36:52:1 | [synth] pipeline | functions.ps1:41:5:43:5 | {...} | | | functions.ps1:36:36:52:1 | enter {...} | functions.ps1:36:36:52:1 | {...} | | | functions.ps1:36:36:52:1 | exit {...} (normal) | functions.ps1:36:36:52:1 | exit {...} | | -| functions.ps1:36:36:52:1 | numbers | functions.ps1:36:36:52:1 | [synth] pipeline | | -| functions.ps1:36:36:52:1 | {...} | functions.ps1:36:36:52:1 | numbers | | +| functions.ps1:36:36:52:1 | {...} | functions.ps1:39:9:39:24 | numbers | | +| functions.ps1:39:9:39:24 | numbers | functions.ps1:36:36:52:1 | [synth] pipeline | | | functions.ps1:41:5:43:5 | {...} | functions.ps1:42:9:42:16 | ...=... | | | functions.ps1:42:9:42:12 | sum | functions.ps1:42:16:42:16 | 0 | | | functions.ps1:42:9:42:16 | ...=... | functions.ps1:42:9:42:12 | sum | | @@ -506,11 +506,11 @@ | try.ps1:7:5:7:12 | return ... | try.ps1:7:12:7:12 | 1 | | | try.ps1:7:12:7:12 | 1 | try.ps1:1:25:8:1 | exit {...} (normal) | | | try.ps1:10:1:19:1 | def of test-try-with-throw-catch | try.ps1:21:1:30:1 | def of test-try-with-throw-catch-with-throw | | +| try.ps1:10:36:10:37 | b | try.ps1:10:40:19:1 | [synth] pipeline | | | try.ps1:10:40:19:1 | [synth] pipeline | try.ps1:11:5:18:12 | {...} | | -| try.ps1:10:40:19:1 | b | try.ps1:10:40:19:1 | [synth] pipeline | | | try.ps1:10:40:19:1 | enter {...} | try.ps1:10:40:19:1 | {...} | | | try.ps1:10:40:19:1 | exit {...} (normal) | try.ps1:10:40:19:1 | exit {...} | | -| try.ps1:10:40:19:1 | {...} | try.ps1:10:40:19:1 | b | | +| try.ps1:10:40:19:1 | {...} | try.ps1:10:36:10:37 | b | | | try.ps1:11:5:17:5 | try {...} | try.ps1:11:9:15:5 | {...} | | | try.ps1:11:5:18:12 | {...} | try.ps1:11:5:17:5 | try {...} | | | try.ps1:11:9:15:5 | {...} | try.ps1:12:9:14:9 | [Stmt] if (...) {...} | | @@ -524,11 +524,11 @@ | try.ps1:18:5:18:12 | return ... | try.ps1:18:12:18:12 | 1 | | | try.ps1:18:12:18:12 | 1 | try.ps1:10:40:19:1 | exit {...} (normal) | | | try.ps1:21:1:30:1 | def of test-try-with-throw-catch-with-throw | try.ps1:32:1:41:1 | def of test-try-with-throw-catch-with-rethrow | | +| try.ps1:21:47:21:48 | b | try.ps1:21:51:30:1 | [synth] pipeline | | | try.ps1:21:51:30:1 | [synth] pipeline | try.ps1:22:5:29:12 | {...} | | -| try.ps1:21:51:30:1 | b | try.ps1:21:51:30:1 | [synth] pipeline | | | try.ps1:21:51:30:1 | enter {...} | try.ps1:21:51:30:1 | {...} | | | try.ps1:21:51:30:1 | exit {...} (normal) | try.ps1:21:51:30:1 | exit {...} | | -| try.ps1:21:51:30:1 | {...} | try.ps1:21:51:30:1 | b | | +| try.ps1:21:51:30:1 | {...} | try.ps1:21:47:21:48 | b | | | try.ps1:22:5:28:5 | try {...} | try.ps1:22:9:26:5 | {...} | | | try.ps1:22:5:29:12 | {...} | try.ps1:22:5:28:5 | try {...} | | | try.ps1:22:9:26:5 | {...} | try.ps1:23:9:25:9 | [Stmt] if (...) {...} | | @@ -542,11 +542,11 @@ | try.ps1:29:5:29:12 | return ... | try.ps1:29:12:29:12 | 1 | | | try.ps1:29:12:29:12 | 1 | try.ps1:21:51:30:1 | exit {...} (normal) | | | try.ps1:32:1:41:1 | def of test-try-with-throw-catch-with-rethrow | try.ps1:43:1:50:1 | def of test-try-catch-specific-1 | | +| try.ps1:32:49:32:50 | b | try.ps1:32:53:41:1 | [synth] pipeline | | | try.ps1:32:53:41:1 | [synth] pipeline | try.ps1:33:5:40:12 | {...} | | -| try.ps1:32:53:41:1 | b | try.ps1:32:53:41:1 | [synth] pipeline | | | try.ps1:32:53:41:1 | enter {...} | try.ps1:32:53:41:1 | {...} | | | try.ps1:32:53:41:1 | exit {...} (normal) | try.ps1:32:53:41:1 | exit {...} | | -| try.ps1:32:53:41:1 | {...} | try.ps1:32:53:41:1 | b | | +| try.ps1:32:53:41:1 | {...} | try.ps1:32:49:32:50 | b | | | try.ps1:33:5:39:5 | try {...} | try.ps1:33:9:37:5 | {...} | | | try.ps1:33:5:40:12 | {...} | try.ps1:33:5:39:5 | try {...} | | | try.ps1:33:9:37:5 | {...} | try.ps1:34:9:36:9 | [Stmt] if (...) {...} | | diff --git a/powershell/ql/test/library-tests/controlflow/graph/consistency.expected b/powershell/ql/test/library-tests/controlflow/graph/consistency.expected index 6f6c4e8dca3..0a8f7a69ad2 100644 --- a/powershell/ql/test/library-tests/controlflow/graph/consistency.expected +++ b/powershell/ql/test/library-tests/controlflow/graph/consistency.expected @@ -4,14 +4,14 @@ breakInvariant3 breakInvariant4 breakInvariant5 multipleSuccessors -| functions.ps1:13:28:20:1 | name1 | successor | functions.ps1:13:28:20:1 | name2 | -| functions.ps1:13:28:20:1 | name1 | successor | functions.ps1:16:24:16:24 | 0 | -| functions.ps1:13:28:20:1 | name2 | successor | functions.ps1:13:28:20:1 | [synth] pipeline | -| functions.ps1:13:28:20:1 | name2 | successor | functions.ps1:17:24:17:29 | name1 | -| functions.ps1:16:24:16:24 | 0 | successor | functions.ps1:13:28:20:1 | name2 | +| functions.ps1:16:9:16:24 | name1 | successor | functions.ps1:16:24:16:24 | 0 | +| functions.ps1:16:9:16:24 | name1 | successor | functions.ps1:17:9:17:33 | name2 | +| functions.ps1:16:24:16:24 | 0 | successor | functions.ps1:17:9:17:33 | name2 | | functions.ps1:16:24:16:24 | 0 | successor | functions.ps1:17:24:17:29 | name1 | +| functions.ps1:17:9:17:33 | name2 | successor | functions.ps1:13:28:20:1 | [synth] pipeline | +| functions.ps1:17:9:17:33 | name2 | successor | functions.ps1:17:24:17:29 | name1 | | functions.ps1:17:24:17:33 | ...+... | successor | functions.ps1:13:28:20:1 | [synth] pipeline | -| functions.ps1:17:24:17:33 | ...+... | successor | functions.ps1:13:28:20:1 | name0 | +| functions.ps1:17:24:17:33 | ...+... | successor | functions.ps1:15:9:15:20 | name0 | | functions.ps1:46:17:46:18 | __pipeline_iterator | successor | functions.ps1:44:5:47:5 | [synth] pipeline | | functions.ps1:46:17:46:18 | __pipeline_iterator | successor | functions.ps1:48:5:51:5 | {...} | | loops.ps1:45:14:45:19 | ...+... | successor | loops.ps1:44:18:44:19 | i | diff --git a/powershell/ql/test/library-tests/dataflow/local/taint.expected b/powershell/ql/test/library-tests/dataflow/local/taint.expected index 1d2bd8ef34b..9b7f161a330 100644 --- a/powershell/ql/test/library-tests/dataflow/local/taint.expected +++ b/powershell/ql/test/library-tests/dataflow/local/taint.expected @@ -1,3 +1,4 @@ +| file://:0:0:0:0 | [summary param] pos(0, {}) in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | file://:0:0:0:0 | [summary] to write: ReturnValue in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | | test.ps1:1:1:1:3 | a1 | test.ps1:2:6:2:8 | a1 | | test.ps1:1:1:24:22 | implicit unwrapping of {...} | test.ps1:1:1:24:22 | return value for {...} | | test.ps1:1:1:24:22 | pre-return value for {...} | test.ps1:1:1:24:22 | implicit unwrapping of {...} | diff --git a/powershell/ql/test/library-tests/dataflow/mad/flow.expected b/powershell/ql/test/library-tests/dataflow/mad/flow.expected new file mode 100644 index 00000000000..fb2743556a9 --- /dev/null +++ b/powershell/ql/test/library-tests/dataflow/mad/flow.expected @@ -0,0 +1,19 @@ +models +edges +| file://:0:0:0:0 | [summary param] pos(0, {}) in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | file://:0:0:0:0 | [summary] to write: ReturnValue in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | provenance | | +| test.ps1:1:6:1:15 | Call to Source | test.ps1:2:94:2:95 | x | provenance | | +| test.ps1:2:6:2:96 | Call to EscapeSingleQuotedStringContent | test.ps1:3:6:3:7 | y | provenance | | +| test.ps1:2:94:2:95 | x | file://:0:0:0:0 | [summary param] pos(0, {}) in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | provenance | | +| test.ps1:2:94:2:95 | x | test.ps1:2:6:2:96 | Call to EscapeSingleQuotedStringContent | provenance | | +nodes +| file://:0:0:0:0 | [summary param] pos(0, {}) in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | semmle.label | [summary param] pos(0, {}) in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | +| file://:0:0:0:0 | [summary] to write: ReturnValue in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | semmle.label | [summary] to write: ReturnValue in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | +| test.ps1:1:6:1:15 | Call to Source | semmle.label | Call to Source | +| test.ps1:2:6:2:96 | Call to EscapeSingleQuotedStringContent | semmle.label | Call to EscapeSingleQuotedStringContent | +| test.ps1:2:94:2:95 | x | semmle.label | x | +| test.ps1:3:6:3:7 | y | semmle.label | y | +subpaths +| test.ps1:2:94:2:95 | x | file://:0:0:0:0 | [summary param] pos(0, {}) in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | file://:0:0:0:0 | [summary] to write: ReturnValue in System.Management.Automation.Language.CodeGeneration!;Method[escapesinglequotedstringcontent] | test.ps1:2:6:2:96 | Call to EscapeSingleQuotedStringContent | +testFailures +#select +| test.ps1:3:6:3:7 | y | test.ps1:1:6:1:15 | Call to Source | test.ps1:3:6:3:7 | y | $@ | test.ps1:1:6:1:15 | Call to Source | Call to Source | diff --git a/powershell/ql/test/library-tests/dataflow/mad/flow.ql b/powershell/ql/test/library-tests/dataflow/mad/flow.ql new file mode 100644 index 00000000000..33fcac2162e --- /dev/null +++ b/powershell/ql/test/library-tests/dataflow/mad/flow.ql @@ -0,0 +1,13 @@ +/** + * @kind path-problem + */ + +import powershell +import semmle.code.powershell.dataflow.DataFlow +private import TestUtilities.InlineFlowTest +import DefaultFlowTest +import TaintFlow::PathGraph + +from TaintFlow::PathNode source, TaintFlow::PathNode sink +where TaintFlow::flowPath(source, sink) +select sink, source, sink, "$@", source, source.toString() diff --git a/powershell/ql/test/library-tests/dataflow/mad/test.ps1 b/powershell/ql/test/library-tests/dataflow/mad/test.ps1 new file mode 100644 index 00000000000..8f1e23b9907 --- /dev/null +++ b/powershell/ql/test/library-tests/dataflow/mad/test.ps1 @@ -0,0 +1,3 @@ +$x = Source "1" +$y = [System.Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent($x) +Sink $y # $ hasTaintFlow=1 \ No newline at end of file diff --git a/powershell/ql/test/library-tests/dataflow/params/test.expected b/powershell/ql/test/library-tests/dataflow/params/test.expected index fa4b4a3bf85..d4009c646e9 100644 --- a/powershell/ql/test/library-tests/dataflow/params/test.expected +++ b/powershell/ql/test/library-tests/dataflow/params/test.expected @@ -1,15 +1,15 @@ models edges -| global.ps1:1:1:6:32 | Source1 | global.ps1:3:6:3:13 | Source1 | provenance | | -| global.ps1:1:1:6:32 | Source2 | global.ps1:4:6:4:13 | Source2 | provenance | | -| global.ps1:1:1:6:32 | Source3 | global.ps1:5:6:5:13 | Source3 | provenance | | -| global.ps1:1:1:6:32 | Source4 | global.ps1:6:6:6:13 | Source4 | provenance | | -| test.ps1:1:18:3:1 | a | test.ps1:2:10:2:11 | a | provenance | | +| global.ps1:1:7:1:22 | Source1 | global.ps1:3:6:3:13 | Source1 | provenance | | +| global.ps1:1:25:1:40 | Source2 | global.ps1:4:6:4:13 | Source2 | provenance | | +| global.ps1:1:43:1:58 | Source3 | global.ps1:5:6:5:13 | Source3 | provenance | | +| global.ps1:1:61:1:76 | Source4 | global.ps1:6:6:6:13 | Source4 | provenance | | +| test.ps1:1:14:1:15 | a | test.ps1:2:10:2:11 | a | provenance | | | test.ps1:5:6:5:15 | Call to Source | test.ps1:6:5:6:6 | x | provenance | | -| test.ps1:6:5:6:6 | x | test.ps1:1:18:3:1 | a | provenance | | -| test.ps1:8:32:12:1 | x | test.ps1:9:10:9:11 | x | provenance | | -| test.ps1:8:32:12:1 | y | test.ps1:10:10:10:11 | y | provenance | | -| test.ps1:8:32:12:1 | z | test.ps1:11:10:11:11 | z | provenance | | +| test.ps1:6:5:6:6 | x | test.ps1:1:14:1:15 | a | provenance | | +| test.ps1:8:20:8:21 | x | test.ps1:9:10:9:11 | x | provenance | | +| test.ps1:8:24:8:25 | y | test.ps1:10:10:10:11 | y | provenance | | +| test.ps1:8:28:8:29 | z | test.ps1:11:10:11:11 | z | provenance | | | test.ps1:14:10:14:19 | Call to Source | test.ps1:18:11:18:16 | first | provenance | | | test.ps1:14:10:14:19 | Call to Source | test.ps1:19:22:19:27 | first | provenance | | | test.ps1:14:10:14:19 | Call to Source | test.ps1:20:14:20:19 | first | provenance | | @@ -76,91 +76,91 @@ edges | test.ps1:16:10:16:19 | Call to Source | test.ps1:37:14:37:19 | third | provenance | | | test.ps1:16:10:16:19 | Call to Source | test.ps1:38:14:38:19 | third | provenance | | | test.ps1:16:10:16:19 | Call to Source | test.ps1:39:14:39:19 | third | provenance | | -| test.ps1:18:11:18:16 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:18:18:18:24 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:18:26:18:31 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:19:11:19:17 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:19:22:19:27 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:19:29:19:34 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:20:14:20:19 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:20:21:20:27 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:20:29:20:34 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:21:11:21:16 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:21:21:21:27 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:21:29:21:34 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:22:14:22:20 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:22:22:22:27 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:22:29:22:34 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:23:11:23:17 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:23:22:23:27 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:23:32:23:37 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:24:14:24:19 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:24:21:24:27 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:24:32:24:37 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:25:11:25:16 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:25:21:25:27 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:25:32:25:37 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:26:14:26:20 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:26:22:26:27 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:26:32:26:37 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:27:11:27:17 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:27:22:27:27 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:27:32:27:37 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:28:14:28:19 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:28:24:28:29 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:28:31:28:37 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:29:11:29:16 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:29:21:29:27 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:29:32:29:37 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:30:14:30:20 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:30:25:30:30 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:30:32:30:37 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:31:11:31:17 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:31:22:31:27 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:31:32:31:37 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:32:14:32:19 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:32:24:32:29 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:32:31:32:37 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:33:11:33:16 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:33:21:33:26 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:33:31:33:37 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:34:14:34:20 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:34:25:34:30 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:34:32:34:37 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:35:14:35:19 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:35:24:35:30 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:35:32:35:37 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:36:14:36:19 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:36:21:36:27 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:36:32:36:37 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:37:14:37:19 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:37:24:37:29 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:37:31:37:37 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:38:14:38:19 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:38:21:38:26 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:38:31:38:37 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:39:14:39:19 | third | test.ps1:8:32:12:1 | z | provenance | | -| test.ps1:39:24:39:30 | second | test.ps1:8:32:12:1 | y | provenance | | -| test.ps1:39:32:39:37 | first | test.ps1:8:32:12:1 | x | provenance | | -| test.ps1:42:1:45:1 | UserInput | test.ps1:44:10:44:19 | UserInput | provenance | | +| test.ps1:18:11:18:16 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:18:18:18:24 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:18:26:18:31 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:19:11:19:17 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:19:22:19:27 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:19:29:19:34 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:20:14:20:19 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:20:21:20:27 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:20:29:20:34 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:21:11:21:16 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:21:21:21:27 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:21:29:21:34 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:22:14:22:20 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:22:22:22:27 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:22:29:22:34 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:23:11:23:17 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:23:22:23:27 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:23:32:23:37 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:24:14:24:19 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:24:21:24:27 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:24:32:24:37 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:25:11:25:16 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:25:21:25:27 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:25:32:25:37 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:26:14:26:20 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:26:22:26:27 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:26:32:26:37 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:27:11:27:17 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:27:22:27:27 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:27:32:27:37 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:28:14:28:19 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:28:24:28:29 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:28:31:28:37 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:29:11:29:16 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:29:21:29:27 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:29:32:29:37 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:30:14:30:20 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:30:25:30:30 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:30:32:30:37 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:31:11:31:17 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:31:22:31:27 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:31:32:31:37 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:32:14:32:19 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:32:24:32:29 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:32:31:32:37 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:33:11:33:16 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:33:21:33:26 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:33:31:33:37 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:34:14:34:20 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:34:25:34:30 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:34:32:34:37 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:35:14:35:19 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:35:24:35:30 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:35:32:35:37 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:36:14:36:19 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:36:21:36:27 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:36:32:36:37 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:37:14:37:19 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:37:24:37:29 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:37:31:37:37 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:38:14:38:19 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:38:21:38:26 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:38:31:38:37 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:39:14:39:19 | third | test.ps1:8:28:8:29 | z | provenance | | +| test.ps1:39:24:39:30 | second | test.ps1:8:24:8:25 | y | provenance | | +| test.ps1:39:32:39:37 | first | test.ps1:8:20:8:21 | x | provenance | | +| test.ps1:43:11:43:20 | UserInput | test.ps1:44:10:44:19 | UserInput | provenance | | | test.ps1:47:10:47:19 | Call to Source | test.ps1:48:46:48:51 | input | provenance | | -| test.ps1:48:46:48:51 | input | test.ps1:42:1:45:1 | UserInput | provenance | | +| test.ps1:48:46:48:51 | input | test.ps1:43:11:43:20 | UserInput | provenance | | nodes -| global.ps1:1:1:6:32 | Source1 | semmle.label | Source1 | -| global.ps1:1:1:6:32 | Source2 | semmle.label | Source2 | -| global.ps1:1:1:6:32 | Source3 | semmle.label | Source3 | -| global.ps1:1:1:6:32 | Source4 | semmle.label | Source4 | +| global.ps1:1:7:1:22 | Source1 | semmle.label | Source1 | +| global.ps1:1:25:1:40 | Source2 | semmle.label | Source2 | +| global.ps1:1:43:1:58 | Source3 | semmle.label | Source3 | +| global.ps1:1:61:1:76 | Source4 | semmle.label | Source4 | | global.ps1:3:6:3:13 | Source1 | semmle.label | Source1 | | global.ps1:4:6:4:13 | Source2 | semmle.label | Source2 | | global.ps1:5:6:5:13 | Source3 | semmle.label | Source3 | | global.ps1:6:6:6:13 | Source4 | semmle.label | Source4 | -| test.ps1:1:18:3:1 | a | semmle.label | a | +| test.ps1:1:14:1:15 | a | semmle.label | a | | test.ps1:2:10:2:11 | a | semmle.label | a | | test.ps1:5:6:5:15 | Call to Source | semmle.label | Call to Source | | test.ps1:6:5:6:6 | x | semmle.label | x | -| test.ps1:8:32:12:1 | x | semmle.label | x | -| test.ps1:8:32:12:1 | y | semmle.label | y | -| test.ps1:8:32:12:1 | z | semmle.label | z | +| test.ps1:8:20:8:21 | x | semmle.label | x | +| test.ps1:8:24:8:25 | y | semmle.label | y | +| test.ps1:8:28:8:29 | z | semmle.label | z | | test.ps1:9:10:9:11 | x | semmle.label | x | | test.ps1:10:10:10:11 | y | semmle.label | y | | test.ps1:11:10:11:11 | z | semmle.label | z | @@ -233,17 +233,17 @@ nodes | test.ps1:39:14:39:19 | third | semmle.label | third | | test.ps1:39:24:39:30 | second | semmle.label | second | | test.ps1:39:32:39:37 | first | semmle.label | first | -| test.ps1:42:1:45:1 | UserInput | semmle.label | UserInput | +| test.ps1:43:11:43:20 | UserInput | semmle.label | UserInput | | test.ps1:44:10:44:19 | UserInput | semmle.label | UserInput | | test.ps1:47:10:47:19 | Call to Source | semmle.label | Call to Source | | test.ps1:48:46:48:51 | input | semmle.label | input | subpaths testFailures #select -| global.ps1:3:6:3:13 | Source1 | global.ps1:1:1:6:32 | Source1 | global.ps1:3:6:3:13 | Source1 | $@ | global.ps1:1:1:6:32 | Source1 | Source1 | -| global.ps1:4:6:4:13 | Source2 | global.ps1:1:1:6:32 | Source2 | global.ps1:4:6:4:13 | Source2 | $@ | global.ps1:1:1:6:32 | Source2 | Source2 | -| global.ps1:5:6:5:13 | Source3 | global.ps1:1:1:6:32 | Source3 | global.ps1:5:6:5:13 | Source3 | $@ | global.ps1:1:1:6:32 | Source3 | Source3 | -| global.ps1:6:6:6:13 | Source4 | global.ps1:1:1:6:32 | Source4 | global.ps1:6:6:6:13 | Source4 | $@ | global.ps1:1:1:6:32 | Source4 | Source4 | +| global.ps1:3:6:3:13 | Source1 | global.ps1:1:7:1:22 | Source1 | global.ps1:3:6:3:13 | Source1 | $@ | global.ps1:1:7:1:22 | Source1 | Source1 | +| global.ps1:4:6:4:13 | Source2 | global.ps1:1:25:1:40 | Source2 | global.ps1:4:6:4:13 | Source2 | $@ | global.ps1:1:25:1:40 | Source2 | Source2 | +| global.ps1:5:6:5:13 | Source3 | global.ps1:1:43:1:58 | Source3 | global.ps1:5:6:5:13 | Source3 | $@ | global.ps1:1:43:1:58 | Source3 | Source3 | +| global.ps1:6:6:6:13 | Source4 | global.ps1:1:61:1:76 | Source4 | global.ps1:6:6:6:13 | Source4 | $@ | global.ps1:1:61:1:76 | Source4 | Source4 | | test.ps1:2:10:2:11 | a | test.ps1:5:6:5:15 | Call to Source | test.ps1:2:10:2:11 | a | $@ | test.ps1:5:6:5:15 | Call to Source | Call to Source | | test.ps1:9:10:9:11 | x | test.ps1:14:10:14:19 | Call to Source | test.ps1:9:10:9:11 | x | $@ | test.ps1:14:10:14:19 | Call to Source | Call to Source | | test.ps1:10:10:10:11 | y | test.ps1:15:11:15:20 | Call to Source | test.ps1:10:10:10:11 | y | $@ | test.ps1:15:11:15:20 | Call to Source | Call to Source | diff --git a/powershell/ql/test/library-tests/dataflow/pipeline/test.expected b/powershell/ql/test/library-tests/dataflow/pipeline/test.expected index b94675c879d..b80489a6fae 100644 --- a/powershell/ql/test/library-tests/dataflow/pipeline/test.expected +++ b/powershell/ql/test/library-tests/dataflow/pipeline/test.expected @@ -6,18 +6,18 @@ edges | test.ps1:5:5:5:6 | x | test.ps1:17:1:17:7 | Call to produce [unknown index] | provenance | | | test.ps1:6:5:6:6 | y | test.ps1:17:1:17:7 | Call to produce [unknown index] | provenance | | | test.ps1:6:9:6:10 | z | test.ps1:17:1:17:7 | Call to produce [unknown index] | provenance | | -| test.ps1:9:29:15:1 | [synth] pipeline [element 0] | test.ps1:12:5:14:5 | [synth] pipeline [element 0] | provenance | | -| test.ps1:9:29:15:1 | [synth] pipeline [element 1] | test.ps1:12:5:14:5 | [synth] pipeline [element 1] | provenance | | -| test.ps1:9:29:15:1 | [synth] pipeline [unknown index] | test.ps1:12:5:14:5 | [synth] pipeline [unknown index] | provenance | | -| test.ps1:12:5:14:5 | [synth] pipeline [element 0] | test.ps1:13:9:13:15 | __pipeline_iterator | provenance | | -| test.ps1:12:5:14:5 | [synth] pipeline [element 1] | test.ps1:13:9:13:15 | __pipeline_iterator | provenance | | -| test.ps1:12:5:14:5 | [synth] pipeline [unknown index] | test.ps1:13:9:13:15 | __pipeline_iterator | provenance | | -| test.ps1:17:1:17:7 | Call to produce [unknown index] | test.ps1:9:29:15:1 | [synth] pipeline [unknown index] | provenance | | +| test.ps1:10:11:10:43 | x [element 0] | test.ps1:12:5:14:5 | x [element 0] | provenance | | +| test.ps1:10:11:10:43 | x [element 1] | test.ps1:12:5:14:5 | x [element 1] | provenance | | +| test.ps1:10:11:10:43 | x [unknown index] | test.ps1:12:5:14:5 | x [unknown index] | provenance | | +| test.ps1:12:5:14:5 | x [element 0] | test.ps1:13:9:13:15 | __pipeline_iterator | provenance | | +| test.ps1:12:5:14:5 | x [element 1] | test.ps1:13:9:13:15 | __pipeline_iterator | provenance | | +| test.ps1:12:5:14:5 | x [unknown index] | test.ps1:13:9:13:15 | __pipeline_iterator | provenance | | +| test.ps1:17:1:17:7 | Call to produce [unknown index] | test.ps1:10:11:10:43 | x [unknown index] | provenance | | | test.ps1:19:6:19:15 | Call to Source | test.ps1:21:1:21:2 | x | provenance | | | test.ps1:20:6:20:15 | Call to Source | test.ps1:21:5:21:6 | y | provenance | | | test.ps1:21:1:21:2 | x | test.ps1:21:1:21:6 | ...,... [element 0] | provenance | | -| test.ps1:21:1:21:6 | ...,... [element 0] | test.ps1:9:29:15:1 | [synth] pipeline [element 0] | provenance | | -| test.ps1:21:1:21:6 | ...,... [element 1] | test.ps1:9:29:15:1 | [synth] pipeline [element 1] | provenance | | +| test.ps1:21:1:21:6 | ...,... [element 0] | test.ps1:10:11:10:43 | x [element 0] | provenance | | +| test.ps1:21:1:21:6 | ...,... [element 1] | test.ps1:10:11:10:43 | x [element 1] | provenance | | | test.ps1:21:5:21:6 | y | test.ps1:21:1:21:6 | ...,... [element 1] | provenance | | | test.ps1:23:38:27:1 | [synth] pipeline [element 0] | test.ps1:24:5:26:5 | [synth] pipeline [element 0] | provenance | | | test.ps1:23:38:27:1 | [synth] pipeline [element 1] | test.ps1:24:5:26:5 | [synth] pipeline [element 1] | provenance | | @@ -29,16 +29,16 @@ edges | test.ps1:31:1:31:6 | ...,... [element 0] | test.ps1:23:38:27:1 | [synth] pipeline [element 0] | provenance | | | test.ps1:31:1:31:6 | ...,... [element 1] | test.ps1:23:38:27:1 | [synth] pipeline [element 1] | provenance | | | test.ps1:31:5:31:6 | y | test.ps1:31:1:31:6 | ...,... [element 1] | provenance | | -| test.ps1:42:60:48:1 | x [element 0, element x] | test.ps1:45:5:47:5 | x [element 0, element x] | provenance | | -| test.ps1:42:60:48:1 | x [element 1, element x] | test.ps1:45:5:47:5 | x [element 1, element x] | provenance | | -| test.ps1:42:60:48:1 | x [element 2, element x] | test.ps1:45:5:47:5 | x [element 2, element x] | provenance | | +| test.ps1:43:11:43:57 | x [element 0, element x] | test.ps1:45:5:47:5 | x [element 0, element x] | provenance | | +| test.ps1:43:11:43:57 | x [element 1, element x] | test.ps1:45:5:47:5 | x [element 1, element x] | provenance | | +| test.ps1:43:11:43:57 | x [element 2, element x] | test.ps1:45:5:47:5 | x [element 2, element x] | provenance | | | test.ps1:45:5:47:5 | x [element 0, element x] | test.ps1:46:9:46:15 | __pipeline_iterator for x | provenance | | | test.ps1:45:5:47:5 | x [element 1, element x] | test.ps1:46:9:46:15 | __pipeline_iterator for x | provenance | | | test.ps1:45:5:47:5 | x [element 2, element x] | test.ps1:46:9:46:15 | __pipeline_iterator for x | provenance | | | test.ps1:50:1:50:33 | [...]... [element x] | test.ps1:50:1:50:105 | ...,... [element 0, element x] | provenance | | -| test.ps1:50:1:50:105 | ...,... [element 0, element x] | test.ps1:42:60:48:1 | x [element 0, element x] | provenance | | -| test.ps1:50:1:50:105 | ...,... [element 1, element x] | test.ps1:42:60:48:1 | x [element 1, element x] | provenance | | -| test.ps1:50:1:50:105 | ...,... [element 2, element x] | test.ps1:42:60:48:1 | x [element 2, element x] | provenance | | +| test.ps1:50:1:50:105 | ...,... [element 0, element x] | test.ps1:43:11:43:57 | x [element 0, element x] | provenance | | +| test.ps1:50:1:50:105 | ...,... [element 1, element x] | test.ps1:43:11:43:57 | x [element 1, element x] | provenance | | +| test.ps1:50:1:50:105 | ...,... [element 2, element x] | test.ps1:43:11:43:57 | x [element 2, element x] | provenance | | | test.ps1:50:17:50:33 | ${...} [element x] | test.ps1:50:1:50:33 | [...]... [element x] | provenance | | | test.ps1:50:23:50:32 | Call to Source | test.ps1:50:17:50:33 | ${...} [element x] | provenance | | | test.ps1:50:36:50:69 | [...]... [element x] | test.ps1:50:1:50:105 | ...,... [element 1, element x] | provenance | | @@ -54,12 +54,12 @@ nodes | test.ps1:5:5:5:6 | x | semmle.label | x | | test.ps1:6:5:6:6 | y | semmle.label | y | | test.ps1:6:9:6:10 | z | semmle.label | z | -| test.ps1:9:29:15:1 | [synth] pipeline [element 0] | semmle.label | [synth] pipeline [element 0] | -| test.ps1:9:29:15:1 | [synth] pipeline [element 1] | semmle.label | [synth] pipeline [element 1] | -| test.ps1:9:29:15:1 | [synth] pipeline [unknown index] | semmle.label | [synth] pipeline [unknown index] | -| test.ps1:12:5:14:5 | [synth] pipeline [element 0] | semmle.label | [synth] pipeline [element 0] | -| test.ps1:12:5:14:5 | [synth] pipeline [element 1] | semmle.label | [synth] pipeline [element 1] | -| test.ps1:12:5:14:5 | [synth] pipeline [unknown index] | semmle.label | [synth] pipeline [unknown index] | +| test.ps1:10:11:10:43 | x [element 0] | semmle.label | x [element 0] | +| test.ps1:10:11:10:43 | x [element 1] | semmle.label | x [element 1] | +| test.ps1:10:11:10:43 | x [unknown index] | semmle.label | x [unknown index] | +| test.ps1:12:5:14:5 | x [element 0] | semmle.label | x [element 0] | +| test.ps1:12:5:14:5 | x [element 1] | semmle.label | x [element 1] | +| test.ps1:12:5:14:5 | x [unknown index] | semmle.label | x [unknown index] | | test.ps1:13:9:13:15 | __pipeline_iterator | semmle.label | __pipeline_iterator | | test.ps1:17:1:17:7 | Call to produce [unknown index] | semmle.label | Call to produce [unknown index] | | test.ps1:19:6:19:15 | Call to Source | semmle.label | Call to Source | @@ -79,9 +79,9 @@ nodes | test.ps1:31:1:31:6 | ...,... [element 0] | semmle.label | ...,... [element 0] | | test.ps1:31:1:31:6 | ...,... [element 1] | semmle.label | ...,... [element 1] | | test.ps1:31:5:31:6 | y | semmle.label | y | -| test.ps1:42:60:48:1 | x [element 0, element x] | semmle.label | x [element 0, element x] | -| test.ps1:42:60:48:1 | x [element 1, element x] | semmle.label | x [element 1, element x] | -| test.ps1:42:60:48:1 | x [element 2, element x] | semmle.label | x [element 2, element x] | +| test.ps1:43:11:43:57 | x [element 0, element x] | semmle.label | x [element 0, element x] | +| test.ps1:43:11:43:57 | x [element 1, element x] | semmle.label | x [element 1, element x] | +| test.ps1:43:11:43:57 | x [element 2, element x] | semmle.label | x [element 2, element x] | | test.ps1:45:5:47:5 | x [element 0, element x] | semmle.label | x [element 0, element x] | | test.ps1:45:5:47:5 | x [element 1, element x] | semmle.label | x [element 1, element x] | | test.ps1:45:5:47:5 | x [element 2, element x] | semmle.label | x [element 2, element x] | diff --git a/powershell/ql/test/library-tests/ssa/ssa.expected b/powershell/ql/test/library-tests/ssa/ssa.expected index b7615522d8e..dbf962aea84 100644 --- a/powershell/ql/test/library-tests/ssa/ssa.expected +++ b/powershell/ql/test/library-tests/ssa/ssa.expected @@ -1,6 +1,6 @@ | explicit.ps1:5:5:5:6 | a | explicit.ps1:5:5:5:6 | a | | explicit.ps1:6:5:6:6 | b | explicit.ps1:6:5:6:6 | b | -| parameters.ps1:1:45:3:1 | n1 | parameters.ps1:1:45:3:1 | n1 | -| parameters.ps1:1:45:3:1 | n2 | parameters.ps1:1:45:3:1 | n2 | -| parameters.ps1:5:22:11:1 | a | parameters.ps1:5:22:11:1 | a | -| parameters.ps1:5:22:11:1 | b | parameters.ps1:5:22:11:1 | b | +| parameters.ps1:1:25:1:32 | n1 | parameters.ps1:1:25:1:32 | n1 | +| parameters.ps1:1:35:1:42 | n2 | parameters.ps1:1:35:1:42 | n2 | +| parameters.ps1:7:9:7:15 | a | parameters.ps1:7:9:7:15 | a | +| parameters.ps1:8:9:8:15 | b | parameters.ps1:8:9:8:15 | b |