diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll index 29da7f7204c0..123d99ca75c0 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll @@ -115,6 +115,7 @@ private import new.DataFlow private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil +private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes as Nodes private import internal.FlowSummaryImpl private import internal.FlowSummaryImpl::Public private import internal.FlowSummaryImpl::Private @@ -952,9 +953,7 @@ private module Cached { */ cached predicate sourceNode(DataFlow::Node node, string kind, string model) { - exists(SourceSinkInterpretationInput::InterpretNode n | - isSourceNode(n, kind, model) and n.asNode() = node - ) + node.(Nodes::FlowSummaryNode).isSource(kind, model) } /** diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll index 66b33b1ed522..a8ec65e395aa 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll @@ -13,13 +13,11 @@ private import semmle.code.cpp.dataflow.ExternalFlow private import semmle.code.cpp.ir.IR module Input implements InputSig { - private import codeql.util.Void - class SummarizedCallableBase = Function; - class SourceBase = Void; + class SourceBase = Function; - class SinkBase = Void; + class SinkBase = Function; class FlowSummaryCallBase = CallInstruction; @@ -132,11 +130,99 @@ module Input implements InputSig { private import Make as Impl -private module StepsInput implements Impl::Private::StepsInputSig { - Impl::Private::SummaryNode getSummaryNode(Node n) { - result = n.(FlowSummaryNode).getSummaryNode() +module Input2 implements Impl::Private::InputSig2 { + class SourceSinkReportingElement extends Element { + private Function getEnclosingFunction() { + result = this.(StmtParent).getEnclosingFunction() + or + this = result.getAParameter() + } + + DataFlowCallable getEnclosingCallable() { + result.asSourceCallable() = this.getEnclosingFunction() + } + } + + private SourceSinkReportingElement getSourceSinkArgumentElement( + Call call, Impl::Private::SummaryComponent sc + ) { + exists(Position pos, int i | + sc = Impl::Private::SummaryComponent::argument(pos) and + i = pos.getArgumentIndex() + | + result = call.getArgument(i) + or + i = -1 and + result = call.getQualifier() + ) } + SourceSinkReportingElement getSourceEntryElement( + Impl::Public::SourceElement source, Impl::Private::SummaryComponentStack s + ) { + s.headOfSingleton() = Impl::Private::SummaryComponent::return(_) and + result.(Call).getTarget() = source + or + exists(Position pos, Function f | + s.head() = Impl::Private::SummaryComponent::parameter(pos) and + result = f.getParameter(pos.getArgumentIndex()) + | + // TODO: callbacks + // exists(Call call | + // call.getTarget() = source and + // f = getSourceSinkArgumentElement(call, s.tail().headOfSingleton()) + // ) + // or + s.length() = 1 and + f = source + ) + or + exists(Call call | + call.getTarget() = source and + result = getSourceSinkArgumentElement(call, s.headOfSingleton()) + ) + } + + private ArgumentNode getSourceNodeArgument(Call c, Impl::Private::SummaryComponent sc) { + exists(Position pos, DataFlowCall call | + sc = Impl::Private::SummaryComponent::argument(pos) and + c = call.asCallInstruction().getUnconvertedResultExpression() and + result.argumentOf(call, pos) + ) + } + + bindingset[e, s] + Node getSourceExitNode(SourceSinkReportingElement e, Impl::Private::SummaryComponentStack s) { + exists(ReturnKind rk, DataFlowCall call | + s.head() = Impl::Private::SummaryComponent::return(rk) and + call.asCallInstruction().getUnconvertedResultExpression() = e and + result = getAnOutNode(call, rk) + ) + or + result.(ParameterNode).getParameter() = e + or + exists(Call call, Impl::Private::SummaryComponent arg | + arg = s.headOfSingleton() and + e = getSourceSinkArgumentElement(call, arg) and + result.(PostUpdateNode).getPreUpdateNode() = getSourceNodeArgument(call, arg) + ) + } + + bindingset[e, sc] + Node getSinkEntryNode(SourceSinkReportingElement e, Impl::Private::SummaryComponent sc) { none() } + + SourceSinkReportingElement getSinkExitElement( + Impl::Public::SinkElement sink, Impl::Private::SummaryComponent sc + ) { + none() + } +} + +private import Impl::Private::Make2 as Impl2 + +private module StepsInput implements Impl2::StepsInputSig { + Impl2::SummaryNode getSummaryNode(Node n) { result = n.(FlowSummaryNode).getSummaryNode() } + DataFlowCall getACall(Public::SummarizedCallable sc) { result.getStaticCallTarget().getUnderlyingCallable() = sc } @@ -148,12 +234,6 @@ private module StepsInput implements Impl::Private::StepsInputSig { pragma[only_bind_out](out.getIndirectionIndex()) ) } - - DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() } - - Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() } - - Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() } } module SourceSinkInterpretationInput implements @@ -270,8 +350,9 @@ module SourceSinkInterpretationInput implements module Private { import Impl::Private + import Impl2 - module Steps = Impl::Private::Steps; + module Steps = Impl2::Steps; module External { import Impl::Private::External @@ -310,3 +391,23 @@ module Private { } module Public = Impl::Public; + +private class SourceModel extends Public::SourceElement { + private string namespace; + private string type; + private boolean subtypes; + private string name; + private string signature; + private string ext; + + SourceModel() { + sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) and + this = interpretElement(namespace, type, subtypes, name, signature, ext) + } + + override predicate isSource( + string output, string kind, Public::Provenance provenance, string model + ) { + sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) + } +} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll index abcff398420c..a467c94a3d1f 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll @@ -1527,18 +1527,25 @@ class FlowSummaryNode extends Node, TFlowSummaryNode { */ FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) } - /** - * Gets the summarized callable that this node belongs to. - */ - FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() { - result = this.getSummaryNode().getSummarizedCallable() + /** Holds if this node is a source node of kind `kind`. */ + predicate isSource(string kind, string model) { + this.getSummaryNode().(FlowSummaryImpl::Private::SourceOutputNode).isEntry(kind, model) + } + + /** Holds if this node is a sink node of kind `kind`. */ + predicate isSink(string kind, string model) { + this.getSummaryNode().(FlowSummaryImpl::Private::SinkInputNode).isExit(kind, model) } + /** + * Gets the enclosing callable. For a `FlowSummaryNode` this is always the + * summarized function this node is part of. + */ override DataFlowCallable getEnclosingCallable() { - result = FlowSummaryImpl::Private::getEnclosingCallable(this.getSummaryNode()) + result = this.getSummaryNode().getEnclosingCallable() } - override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() } + override Location getLocationImpl() { result = this.getSummaryNode().getLocation() } override string toStringImpl() { result = this.getSummaryNode().toString() } } @@ -1780,7 +1787,7 @@ class SummaryParameterNode extends AbstractParameterNode, FlowSummaryNode { override predicate isSummaryParameterOf( FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition p ) { - c = this.getSummarizedCallable() and + c = this.getSummaryNode().getSummarizedCallable() and p = this.getPosition() } } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index cdcbaa438d3a..c2d205174768 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -121,6 +121,8 @@ private module Cached { // models-as-data summarized flow FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(), n2.(FlowSummaryNode).getSummaryNode()) + or + FlowSummaryImpl::Private::Steps::sourceJumpStep(n1.(FlowSummaryNode).getSummaryNode(), n2) } /** diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 2e3274c82c7c..1de1ae7931dd 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -160,6 +160,12 @@ private module Cached { // models-as-data summarized flow FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo.(FlowSummaryNode).getSummaryNode(), true, model) + or + FlowSummaryImpl::Private::Steps::sourceLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), + nodeTo, model) + or + FlowSummaryImpl::Private::Steps::sinkLocalStep(nodeFrom, + nodeTo.(FlowSummaryNode).getSummaryNode(), model) } private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) { diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index 641804364501..d74f8ea3dfd7 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -23,98 +23,99 @@ models | 22 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | | 23 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | | 24 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | -| 25 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | -| 26 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | -| 27 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | -| 28 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | -| 29 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | -| 30 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | -| 31 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | -| 32 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | -| 33 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | -| 34 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 35 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 36 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 37 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | -| 38 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 39 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 40 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 41 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | -| 42 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 43 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | -| 44 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 45 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 46 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | -| 47 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | -| 48 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | -| 49 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 50 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | -| 51 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | -| 52 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | -| 53 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | -| 54 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 55 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 56 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | -| 57 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | -| 58 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | -| 59 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | -| 60 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | -| 61 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 62 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 63 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | -| 64 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 65 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 25 | Source: ; ; false; ymlFieldSource; ; ; ReturnValue.Field[SourceWrapper::value]; local; manual | +| 26 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | +| 27 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | +| 28 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | +| 29 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | +| 30 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | +| 31 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | +| 32 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | +| 33 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | +| 34 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | +| 35 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 36 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 37 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 38 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | +| 39 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 40 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 41 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 42 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | +| 43 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 44 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | +| 45 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 46 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 47 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | +| 48 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | +| 49 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | +| 50 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 51 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | +| 52 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | +| 53 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | +| 54 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | +| 55 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | +| 56 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 57 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | +| 58 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | +| 59 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | +| 60 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | +| 61 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | +| 62 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 63 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 64 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | +| 65 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 66 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:32 | -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:32 Sink:MaD:2 | +| asio_streams.cpp:87:34:87:44 | recv_buffer | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:33 MaD:33 | +| asio_streams.cpp:87:34:87:44 | recv_buffer | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:33 MaD:33 Sink:MaD:2 | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:65 | -| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:29 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:66 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | | -| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:61 | +| azure.cpp:253:48:253:60 | call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:30 MaD:30 | +| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:62 | | azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | | -| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:62 | +| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:63 | | azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | | -| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:63 | +| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:64 | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | | | azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | | -| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:28 | +| azure.cpp:273:52:273:61 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:29 MaD:29 | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:10:274:29 | call to operator[] | provenance | | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:14:274:29 | call to operator[] | provenance | | -| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:27 | +| azure.cpp:277:38:277:44 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:28 MaD:28 | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | | -| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:26 | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | | -| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:63 | +| azure.cpp:281:68:281:84 | call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:27 MaD:27 | +| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:64 | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | | -| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:64 | +| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:65 | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | | -| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:30 | +| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:31 MaD:31 | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:290:10:290:20 | headerValue | azure.cpp:290:10:290:20 | headerValue | provenance | | -| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:31 | +| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:32 MaD:32 | | azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:294:38:294:53 | call to operator[] | provenance | TaintFunction | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | | | test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | | | test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | | -| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:26 MaD:26 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:1 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:17:24:17:24 | x | provenance | | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:21:27:21:27 | x | provenance | | @@ -122,13 +123,13 @@ edges | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:32:41:32:41 | x | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 | -| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:53 | +| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:54 | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 | -| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:52 | +| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:53 | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:54 | +| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:55 | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 | | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | | @@ -138,84 +139,87 @@ edges | test.cpp:48:13:48:13 | *s [x] | test.cpp:48:16:48:16 | x | provenance | Sink:MaD:1 | | test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | | | test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | | -| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:25 | -| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:49 | +| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:26 MaD:26 | +| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:50 | | test.cpp:68:22:68:22 | y | test.cpp:69:11:69:11 | y | provenance | Sink:MaD:1 | | test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 | | test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 | | test.cpp:88:22:88:22 | y | test.cpp:89:11:89:11 | y | provenance | Sink:MaD:1 | -| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:26 MaD:26 | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:97:26:97:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:104:62:104:62 | x | provenance | | -| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:47 | -| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:47 | -| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:47 | -| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:47 | -| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:48 | +| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:48 | +| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:48 | +| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:48 | +| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:26 MaD:26 | | test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:48 | -| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:49 | +| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:26 MaD:26 | | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:1 | -| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:59 | -| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:60 | +| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:26 MaD:26 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:1 | -| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:60 | -| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:61 | +| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:26 MaD:26 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:1 | -| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:60 | +| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:61 | | test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | | -| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:58 | -| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:59 | +| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:26 MaD:26 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:1 | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | | -| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:58 | +| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:59 | | test.cpp:186:2:186:2 | *s [post update] [myField] | test.cpp:187:33:187:34 | *& ... [myField] | provenance | | | test.cpp:186:2:186:24 | ... = ... | test.cpp:186:2:186:2 | *s [post update] [myField] | provenance | | -| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:25 | +| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:26 MaD:26 | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:188:10:188:10 | x | provenance | Sink:MaD:1 | -| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:50 | +| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:51 | | test.cpp:199:2:199:2 | *s [post update] [myField] | test.cpp:200:35:200:36 | *& ... [myField] | provenance | | | test.cpp:199:2:199:24 | ... = ... | test.cpp:199:2:199:2 | *s [post update] [myField] | provenance | | -| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:25 | +| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:26 MaD:26 | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:201:10:201:10 | x | provenance | Sink:MaD:1 | -| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:51 | +| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:52 | | test.cpp:216:3:216:4 | get_ptr output argument [value] | test.cpp:217:11:217:12 | *rf [value] | provenance | | -| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:57 | -| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:25 | +| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:58 | +| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:26 MaD:26 | | test.cpp:217:11:217:12 | *rf [value] | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:218:11:218:11 | x | provenance | Sink:MaD:1 | | test.cpp:222:3:222:3 | operator[] output argument | test.cpp:223:12:223:12 | *s | provenance | | -| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:56 | -| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:25 | -| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:55 | +| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:57 | +| test.cpp:222:10:222:18 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:26 MaD:26 | +| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:56 | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:223:13:223:15 | call to operator[] | provenance | | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:224:11:224:11 | c | provenance | Sink:MaD:1 | -| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 | +| test.cpp:235:26:235:39 | call to ymlFieldSource | test.cpp:235:26:235:39 | call to ymlFieldSource [value] | provenance | Src:MaD:25 | +| test.cpp:235:26:235:39 | call to ymlFieldSource [value] | test.cpp:236:10:236:16 | *wrapper [value] | provenance | | +| test.cpp:236:10:236:16 | *wrapper [value] | test.cpp:236:18:236:22 | value | provenance | Sink:MaD:1 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:24:8:24:11 | * ... | provenance | | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | | +| windows.cpp:22:15:22:29 | call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 MaD:3 | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:30:8:30:15 | * ... | provenance | | -| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:33 | -| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 | +| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:34 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:36:10:36:13 | * ... | provenance | | -| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 | +| windows.cpp:34:17:34:38 | call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 MaD:4 | +| windows.cpp:39:36:39:38 | buf | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 MaD:5 | | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | windows.cpp:149:42:149:53 | *lpOverlapped [*hEvent] | provenance | | | windows.cpp:149:18:149:62 | *hEvent | windows.cpp:149:18:149:62 | *hEvent | provenance | | | windows.cpp:149:18:149:62 | *hEvent | windows.cpp:151:8:151:14 | * ... | provenance | | @@ -227,37 +231,37 @@ edges | windows.cpp:159:12:159:55 | hEvent | windows.cpp:160:8:160:8 | c | provenance | | | windows.cpp:159:35:159:46 | *lpOverlapped [hEvent] | windows.cpp:159:12:159:55 | hEvent | provenance | | | windows.cpp:159:35:159:46 | *lpOverlapped [hEvent] | windows.cpp:159:12:159:55 | hEvent | provenance | | -| windows.cpp:168:35:168:40 | ReadFile output argument | windows.cpp:170:10:170:16 | * ... | provenance | Src:MaD:17 | -| windows.cpp:177:23:177:28 | ReadFileEx output argument | windows.cpp:179:10:179:16 | * ... | provenance | Src:MaD:18 | -| windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:17 | +| windows.cpp:168:35:168:40 | buffer | windows.cpp:170:10:170:16 | * ... | provenance | Src:MaD:17 MaD:17 | +| windows.cpp:177:23:177:28 | buffer | windows.cpp:179:10:179:16 | * ... | provenance | Src:MaD:18 MaD:18 | +| windows.cpp:189:21:189:26 | buffer | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:17 MaD:17 | | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | windows.cpp:192:53:192:63 | *& ... [*hEvent] | provenance | | | windows.cpp:190:5:190:56 | *... = ... | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | provenance | | -| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:37 | -| windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:17 | +| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:38 | +| windows.cpp:198:21:198:26 | buffer | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:17 MaD:17 | | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | windows.cpp:201:53:201:63 | *& ... [hEvent] | provenance | | | windows.cpp:199:5:199:57 | ... = ... | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | provenance | | -| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:37 | -| windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:16 | -| windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:12 | +| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:38 | +| windows.cpp:209:84:209:89 | buffer | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:16 MaD:16 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:287:20:287:52 | *pMapView | provenance | | +| windows.cpp:286:23:286:35 | call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:12 MaD:12 | | windows.cpp:287:20:287:52 | *pMapView | windows.cpp:289:10:289:16 | * ... | provenance | | -| windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | provenance | Src:MaD:9 | | windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | windows.cpp:294:20:294:52 | *pMapView | provenance | | +| windows.cpp:293:23:293:36 | call to MapViewOfFile2 | windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | provenance | Src:MaD:9 MaD:9 | | windows.cpp:294:20:294:52 | *pMapView | windows.cpp:296:10:296:16 | * ... | provenance | | -| windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | provenance | Src:MaD:10 | | windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | windows.cpp:303:20:303:52 | *pMapView | provenance | | +| windows.cpp:302:23:302:36 | call to MapViewOfFile3 | windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | provenance | Src:MaD:10 MaD:10 | | windows.cpp:303:20:303:52 | *pMapView | windows.cpp:305:10:305:16 | * ... | provenance | | -| windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | provenance | Src:MaD:11 | | windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | windows.cpp:312:20:312:52 | *pMapView | provenance | | +| windows.cpp:311:23:311:43 | call to MapViewOfFile3FromApp | windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | provenance | Src:MaD:11 MaD:11 | | windows.cpp:312:20:312:52 | *pMapView | windows.cpp:314:10:314:16 | * ... | provenance | | -| windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | provenance | Src:MaD:13 | | windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | windows.cpp:319:20:319:52 | *pMapView | provenance | | +| windows.cpp:318:23:318:37 | call to MapViewOfFileEx | windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | provenance | Src:MaD:13 MaD:13 | | windows.cpp:319:20:319:52 | *pMapView | windows.cpp:321:10:321:16 | * ... | provenance | | -| windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | provenance | Src:MaD:14 | | windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | windows.cpp:326:20:326:52 | *pMapView | provenance | | +| windows.cpp:325:23:325:42 | call to MapViewOfFileFromApp | windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | provenance | Src:MaD:14 MaD:14 | | windows.cpp:326:20:326:52 | *pMapView | windows.cpp:328:10:328:16 | * ... | provenance | | -| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | provenance | Src:MaD:15 | | windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:333:20:333:52 | *pMapView | provenance | | +| windows.cpp:332:23:332:40 | call to MapViewOfFileNuma2 | windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | provenance | Src:MaD:15 MaD:15 | | windows.cpp:333:20:333:52 | *pMapView | windows.cpp:335:10:335:16 | * ... | provenance | | | windows.cpp:403:26:403:36 | *lpParameter [x] | windows.cpp:405:10:405:25 | *lpParameter [x] | provenance | | | windows.cpp:405:10:405:25 | *lpParameter [x] | windows.cpp:406:8:406:8 | *s [x] | provenance | | @@ -273,9 +277,9 @@ edges | windows.cpp:431:3:431:3 | *s [post update] [x] | windows.cpp:464:7:464:8 | *& ... [x] | provenance | | | windows.cpp:431:3:431:16 | ... = ... | windows.cpp:431:3:431:3 | *s [post update] [x] | provenance | | | windows.cpp:431:9:431:14 | call to source | windows.cpp:431:3:431:16 | ... = ... | provenance | | -| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:36 | -| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:34 | -| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:35 | +| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:37 | +| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:35 | +| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:36 | | windows.cpp:533:11:533:16 | call to source | windows.cpp:533:11:533:16 | call to source | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:537:40:537:41 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:542:38:542:39 | *& ... | provenance | | @@ -284,61 +288,61 @@ edges | windows.cpp:533:11:533:16 | call to source | windows.cpp:568:32:568:33 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:573:40:573:41 | *& ... | provenance | | | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | windows.cpp:538:10:538:23 | access to array | provenance | | -| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:42 | +| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:43 | | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | windows.cpp:543:10:543:23 | access to array | provenance | | -| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:38 | +| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:39 | | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | windows.cpp:548:10:548:23 | access to array | provenance | | -| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:39 | +| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:40 | | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | windows.cpp:553:10:553:23 | access to array | provenance | | -| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:40 | +| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:41 | | windows.cpp:559:5:559:24 | ... = ... | windows.cpp:561:39:561:44 | *buffer | provenance | | | windows.cpp:559:17:559:24 | call to source | windows.cpp:559:5:559:24 | ... = ... | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:562:10:562:19 | *src_string [*Buffer] | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:563:40:563:50 | *& ... [*Buffer] | provenance | | -| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:43 | +| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:44 | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:21:562:26 | *Buffer | provenance | | | windows.cpp:562:21:562:26 | *Buffer | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | provenance | | -| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:41 | +| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:42 | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:22:564:27 | *Buffer | provenance | | | windows.cpp:564:22:564:27 | *Buffer | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | windows.cpp:569:10:569:23 | access to array | provenance | | -| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:44 | +| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:45 | | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | windows.cpp:574:10:574:23 | access to array | provenance | | -| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:45 | -| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:23 | -| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:24 | -| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:19 | -| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:21 | -| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:22 | -| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:20 | +| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:46 | +| windows.cpp:645:45:645:50 | buffer | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:23 MaD:23 | +| windows.cpp:652:48:652:53 | buffer | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:24 MaD:24 | +| windows.cpp:659:47:659:52 | buffer | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:19 MaD:19 | +| windows.cpp:669:70:669:79 | headerName | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:21 MaD:21 | +| windows.cpp:669:82:669:87 | buffer | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:22 MaD:22 | +| windows.cpp:669:105:669:112 | & ... | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:20 MaD:20 | | windows.cpp:728:5:728:28 | ... = ... | windows.cpp:729:35:729:35 | *x | provenance | | | windows.cpp:728:12:728:28 | call to source | windows.cpp:728:5:728:28 | ... = ... | provenance | | -| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:46 | +| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:47 | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:731:10:731:36 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:733:10:733:35 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:735:10:735:37 | * ... | provenance | | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:901:15:901:53 | *& ... | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:905:10:905:31 | * ... | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:907:10:907:42 | * ... | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:909:10:909:57 | * ... | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:911:10:911:60 | * ... | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:912:54:912:63 | FileHandle | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:914:10:914:70 | * ... | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:916:10:916:72 | * ... | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:918:10:918:64 | * ... | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:920:10:920:51 | * ... | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:922:10:922:52 | * ... | provenance | Src:MaD:7 | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | windows.cpp:924:10:924:63 | * ... | provenance | Src:MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:901:15:901:53 | *& ... | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:905:10:905:31 | * ... | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:907:10:907:42 | * ... | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:909:10:909:57 | * ... | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:911:10:911:60 | * ... | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:912:54:912:63 | FileHandle | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:914:10:914:70 | * ... | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:916:10:916:72 | * ... | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:918:10:918:64 | * ... | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:920:10:920:51 | * ... | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:922:10:922:52 | * ... | provenance | Src:MaD:7 MaD:7 | +| windows.cpp:900:64:900:77 | & ... | windows.cpp:924:10:924:63 | * ... | provenance | Src:MaD:7 MaD:7 | | windows.cpp:901:15:901:53 | *& ... | windows.cpp:903:10:903:11 | * ... | provenance | | -| windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | windows.cpp:931:10:931:16 | * ... | provenance | Src:MaD:8 | -| windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:937:15:937:48 | *& ... | provenance | Src:MaD:6 | -| windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:941:10:941:31 | * ... | provenance | Src:MaD:6 | +| windows.cpp:929:70:929:75 | buffer | windows.cpp:931:10:931:16 | * ... | provenance | Src:MaD:8 MaD:8 | +| windows.cpp:936:70:936:78 | & ... | windows.cpp:937:15:937:48 | *& ... | provenance | Src:MaD:6 MaD:6 | +| windows.cpp:936:70:936:78 | & ... | windows.cpp:941:10:941:31 | * ... | provenance | Src:MaD:6 MaD:6 | | windows.cpp:937:15:937:48 | *& ... | windows.cpp:939:10:939:11 | * ... | provenance | | nodes -| asio_streams.cpp:87:34:87:44 | read_until output argument | semmle.label | read_until output argument | +| asio_streams.cpp:87:34:87:44 | recv_buffer | semmle.label | recv_buffer | | asio_streams.cpp:91:7:91:17 | recv_buffer | semmle.label | recv_buffer | | asio_streams.cpp:93:29:93:39 | *recv_buffer | semmle.label | *recv_buffer | | asio_streams.cpp:97:37:97:44 | call to source | semmle.label | call to source | @@ -349,7 +353,7 @@ nodes | asio_streams.cpp:101:7:101:17 | send_buffer | semmle.label | send_buffer | | asio_streams.cpp:103:29:103:39 | *send_buffer | semmle.label | *send_buffer | | azure.cpp:253:48:253:60 | *call to GetBodyStream | semmle.label | *call to GetBodyStream | -| azure.cpp:253:48:253:60 | *call to GetBodyStream | semmle.label | *call to GetBodyStream | +| azure.cpp:253:48:253:60 | call to GetBodyStream | semmle.label | call to GetBodyStream | | azure.cpp:257:5:257:8 | *resp | semmle.label | *resp | | azure.cpp:257:16:257:21 | Read output argument | semmle.label | Read output argument | | azure.cpp:258:10:258:16 | * ... | semmle.label | * ... | @@ -361,19 +365,19 @@ nodes | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | semmle.label | call to ReadToEnd [element] | | azure.cpp:267:10:267:12 | vec | semmle.label | vec | | azure.cpp:267:10:267:12 | vec [element] | semmle.label | vec [element] | -| azure.cpp:273:62:273:64 | call to GetHeaders | semmle.label | call to GetHeaders | +| azure.cpp:273:52:273:61 | call to GetHeaders | semmle.label | call to GetHeaders | | azure.cpp:273:62:273:64 | call to GetHeaders | semmle.label | call to GetHeaders | | azure.cpp:274:10:274:29 | call to operator[] | semmle.label | call to operator[] | | azure.cpp:274:14:274:29 | call to operator[] | semmle.label | call to operator[] | | azure.cpp:274:14:274:29 | call to operator[] | semmle.label | call to operator[] | | azure.cpp:274:14:274:29 | call to operator[] | semmle.label | call to operator[] | -| azure.cpp:277:45:277:47 | call to GetBody | semmle.label | call to GetBody | +| azure.cpp:277:38:277:44 | call to GetBody | semmle.label | call to GetBody | | azure.cpp:277:45:277:47 | call to GetBody | semmle.label | call to GetBody | | azure.cpp:278:10:278:13 | body | semmle.label | body | | azure.cpp:278:10:278:13 | body | semmle.label | body | | azure.cpp:278:10:278:13 | body | semmle.label | body | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | semmle.label | *call to ExtractBodyStream | -| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | semmle.label | *call to ExtractBodyStream | +| azure.cpp:281:68:281:84 | call to ExtractBodyStream | semmle.label | call to ExtractBodyStream | | azure.cpp:282:10:282:38 | call to ReadToEnd | semmle.label | call to ReadToEnd | | azure.cpp:282:21:282:23 | *call to get | semmle.label | *call to get | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | semmle.label | call to ReadToEnd [element] | @@ -494,22 +498,26 @@ nodes | test.cpp:218:11:218:11 | x | semmle.label | x | | test.cpp:222:3:222:3 | operator[] output argument | semmle.label | operator[] output argument | | test.cpp:222:3:222:20 | ... = ... | semmle.label | ... = ... | -| test.cpp:222:10:222:20 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:222:10:222:18 | call to ymlSource | semmle.label | call to ymlSource | | test.cpp:223:12:223:12 | *s | semmle.label | *s | | test.cpp:223:13:223:15 | call to operator[] | semmle.label | call to operator[] | | test.cpp:223:13:223:15 | call to operator[] | semmle.label | call to operator[] | | test.cpp:224:11:224:11 | c | semmle.label | c | +| test.cpp:235:26:235:39 | call to ymlFieldSource | semmle.label | call to ymlFieldSource | +| test.cpp:235:26:235:39 | call to ymlFieldSource [value] | semmle.label | call to ymlFieldSource [value] | +| test.cpp:236:10:236:16 | *wrapper [value] | semmle.label | *wrapper [value] | +| test.cpp:236:18:236:22 | value | semmle.label | value | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | semmle.label | *call to GetCommandLineA | -| windows.cpp:22:15:22:29 | *call to GetCommandLineA | semmle.label | *call to GetCommandLineA | +| windows.cpp:22:15:22:29 | call to GetCommandLineA | semmle.label | call to GetCommandLineA | | windows.cpp:24:8:24:11 | * ... | semmle.label | * ... | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | semmle.label | **call to CommandLineToArgvA | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | semmle.label | **call to CommandLineToArgvA | | windows.cpp:27:36:27:38 | *cmd | semmle.label | *cmd | | windows.cpp:30:8:30:15 | * ... | semmle.label | * ... | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | semmle.label | *call to GetEnvironmentStringsA | -| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | semmle.label | *call to GetEnvironmentStringsA | +| windows.cpp:34:17:34:38 | call to GetEnvironmentStringsA | semmle.label | call to GetEnvironmentStringsA | | windows.cpp:36:10:36:13 | * ... | semmle.label | * ... | -| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | semmle.label | GetEnvironmentVariableA output argument | +| windows.cpp:39:36:39:38 | buf | semmle.label | buf | | windows.cpp:41:10:41:13 | * ... | semmle.label | * ... | | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | semmle.label | *lpOverlapped [*hEvent] | | windows.cpp:149:18:149:62 | *hEvent | semmle.label | *hEvent | @@ -522,46 +530,46 @@ nodes | windows.cpp:159:12:159:55 | hEvent | semmle.label | hEvent | | windows.cpp:159:35:159:46 | *lpOverlapped [hEvent] | semmle.label | *lpOverlapped [hEvent] | | windows.cpp:160:8:160:8 | c | semmle.label | c | -| windows.cpp:168:35:168:40 | ReadFile output argument | semmle.label | ReadFile output argument | +| windows.cpp:168:35:168:40 | buffer | semmle.label | buffer | | windows.cpp:170:10:170:16 | * ... | semmle.label | * ... | -| windows.cpp:177:23:177:28 | ReadFileEx output argument | semmle.label | ReadFileEx output argument | +| windows.cpp:177:23:177:28 | buffer | semmle.label | buffer | | windows.cpp:179:10:179:16 | * ... | semmle.label | * ... | -| windows.cpp:189:21:189:26 | ReadFile output argument | semmle.label | ReadFile output argument | +| windows.cpp:189:21:189:26 | buffer | semmle.label | buffer | | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | semmle.label | *overlapped [post update] [*hEvent] | | windows.cpp:190:5:190:56 | *... = ... | semmle.label | *... = ... | | windows.cpp:192:53:192:63 | *& ... [*hEvent] | semmle.label | *& ... [*hEvent] | -| windows.cpp:198:21:198:26 | ReadFile output argument | semmle.label | ReadFile output argument | +| windows.cpp:198:21:198:26 | buffer | semmle.label | buffer | | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | semmle.label | *overlapped [post update] [hEvent] | | windows.cpp:199:5:199:57 | ... = ... | semmle.label | ... = ... | | windows.cpp:201:53:201:63 | *& ... [hEvent] | semmle.label | *& ... [hEvent] | -| windows.cpp:209:84:209:89 | NtReadFile output argument | semmle.label | NtReadFile output argument | +| windows.cpp:209:84:209:89 | buffer | semmle.label | buffer | | windows.cpp:211:10:211:16 | * ... | semmle.label | * ... | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | semmle.label | *call to MapViewOfFile | -| windows.cpp:286:23:286:35 | *call to MapViewOfFile | semmle.label | *call to MapViewOfFile | +| windows.cpp:286:23:286:35 | call to MapViewOfFile | semmle.label | call to MapViewOfFile | | windows.cpp:287:20:287:52 | *pMapView | semmle.label | *pMapView | | windows.cpp:289:10:289:16 | * ... | semmle.label | * ... | | windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | semmle.label | *call to MapViewOfFile2 | -| windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | semmle.label | *call to MapViewOfFile2 | +| windows.cpp:293:23:293:36 | call to MapViewOfFile2 | semmle.label | call to MapViewOfFile2 | | windows.cpp:294:20:294:52 | *pMapView | semmle.label | *pMapView | | windows.cpp:296:10:296:16 | * ... | semmle.label | * ... | | windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | semmle.label | *call to MapViewOfFile3 | -| windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | semmle.label | *call to MapViewOfFile3 | +| windows.cpp:302:23:302:36 | call to MapViewOfFile3 | semmle.label | call to MapViewOfFile3 | | windows.cpp:303:20:303:52 | *pMapView | semmle.label | *pMapView | | windows.cpp:305:10:305:16 | * ... | semmle.label | * ... | | windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | semmle.label | *call to MapViewOfFile3FromApp | -| windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | semmle.label | *call to MapViewOfFile3FromApp | +| windows.cpp:311:23:311:43 | call to MapViewOfFile3FromApp | semmle.label | call to MapViewOfFile3FromApp | | windows.cpp:312:20:312:52 | *pMapView | semmle.label | *pMapView | | windows.cpp:314:10:314:16 | * ... | semmle.label | * ... | | windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | semmle.label | *call to MapViewOfFileEx | -| windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | semmle.label | *call to MapViewOfFileEx | +| windows.cpp:318:23:318:37 | call to MapViewOfFileEx | semmle.label | call to MapViewOfFileEx | | windows.cpp:319:20:319:52 | *pMapView | semmle.label | *pMapView | | windows.cpp:321:10:321:16 | * ... | semmle.label | * ... | | windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | semmle.label | *call to MapViewOfFileFromApp | -| windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | semmle.label | *call to MapViewOfFileFromApp | +| windows.cpp:325:23:325:42 | call to MapViewOfFileFromApp | semmle.label | call to MapViewOfFileFromApp | | windows.cpp:326:20:326:52 | *pMapView | semmle.label | *pMapView | | windows.cpp:328:10:328:16 | * ... | semmle.label | * ... | | windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | semmle.label | *call to MapViewOfFileNuma2 | -| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | semmle.label | *call to MapViewOfFileNuma2 | +| windows.cpp:332:23:332:40 | call to MapViewOfFileNuma2 | semmle.label | call to MapViewOfFileNuma2 | | windows.cpp:333:20:333:52 | *pMapView | semmle.label | *pMapView | | windows.cpp:335:10:335:16 | * ... | semmle.label | * ... | | windows.cpp:403:26:403:36 | *lpParameter [x] | semmle.label | *lpParameter [x] | @@ -614,15 +622,15 @@ nodes | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | semmle.label | RtlMoveVolatileMemory output argument | | windows.cpp:573:40:573:41 | *& ... | semmle.label | *& ... | | windows.cpp:574:10:574:23 | access to array | semmle.label | access to array | -| windows.cpp:645:45:645:50 | WinHttpReadData output argument | semmle.label | WinHttpReadData output argument | +| windows.cpp:645:45:645:50 | buffer | semmle.label | buffer | | windows.cpp:647:10:647:16 | * ... | semmle.label | * ... | -| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | semmle.label | WinHttpReadDataEx output argument | +| windows.cpp:652:48:652:53 | buffer | semmle.label | buffer | | windows.cpp:654:10:654:16 | * ... | semmle.label | * ... | -| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | semmle.label | WinHttpQueryHeaders output argument | +| windows.cpp:659:47:659:52 | buffer | semmle.label | buffer | | windows.cpp:661:10:661:16 | * ... | semmle.label | * ... | -| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | semmle.label | WinHttpQueryHeadersEx output argument | -| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | semmle.label | WinHttpQueryHeadersEx output argument | -| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | semmle.label | WinHttpQueryHeadersEx output argument | +| windows.cpp:669:70:669:79 | headerName | semmle.label | headerName | +| windows.cpp:669:82:669:87 | buffer | semmle.label | buffer | +| windows.cpp:669:105:669:112 | & ... | semmle.label | & ... | | windows.cpp:671:10:671:16 | * ... | semmle.label | * ... | | windows.cpp:673:10:673:29 | * ... | semmle.label | * ... | | windows.cpp:675:10:675:27 | * ... | semmle.label | * ... | @@ -633,7 +641,7 @@ nodes | windows.cpp:731:10:731:36 | * ... | semmle.label | * ... | | windows.cpp:733:10:733:35 | * ... | semmle.label | * ... | | windows.cpp:735:10:735:37 | * ... | semmle.label | * ... | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | semmle.label | HttpReceiveHttpRequest output argument | +| windows.cpp:900:64:900:77 | & ... | semmle.label | & ... | | windows.cpp:901:15:901:53 | *& ... | semmle.label | *& ... | | windows.cpp:903:10:903:11 | * ... | semmle.label | * ... | | windows.cpp:905:10:905:31 | * ... | semmle.label | * ... | @@ -647,9 +655,9 @@ nodes | windows.cpp:920:10:920:51 | * ... | semmle.label | * ... | | windows.cpp:922:10:922:52 | * ... | semmle.label | * ... | | windows.cpp:924:10:924:63 | * ... | semmle.label | * ... | -| windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | semmle.label | HttpReceiveRequestEntityBody output argument | +| windows.cpp:929:70:929:75 | buffer | semmle.label | buffer | | windows.cpp:931:10:931:16 | * ... | semmle.label | * ... | -| windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | semmle.label | HttpReceiveClientCertificate output argument | +| windows.cpp:936:70:936:78 | & ... | semmle.label | & ... | | windows.cpp:937:15:937:48 | *& ... | semmle.label | *& ... | | windows.cpp:939:10:939:11 | * ... | semmle.label | * ... | | windows.cpp:941:10:941:31 | * ... | semmle.label | * ... | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.ext.yml b/cpp/ql/test/library-tests/dataflow/external-models/flow.ext.yml index 130e13a92571..1327617425af 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.ext.yml +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.ext.yml @@ -4,6 +4,7 @@ extensions: extensible: sourceModel data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance - ["", "", False, "ymlSource", "", "", "ReturnValue", "local", "manual"] + - ["", "", False, "ymlFieldSource", "", "", "ReturnValue.Field[SourceWrapper::value]", "local", "manual"] - addsTo: pack: codeql/cpp-all extensible: sinkModel diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected b/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected index a1f44de81589..04071183829c 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected @@ -23,3 +23,4 @@ | test.cpp:201:10:201:10 | x | test-sink | | test.cpp:218:11:218:11 | x | test-sink | | test.cpp:224:11:224:11 | c | test-sink | +| test.cpp:236:18:236:22 | value | test-sink | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected index 6585c88dc6dd..cf3fbcd5fd58 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -1,8 +1,8 @@ -| asio_streams.cpp:87:34:87:44 | read_until output argument | remote | -| azure.cpp:253:48:253:60 | *call to GetBodyStream | remote | -| azure.cpp:273:62:273:64 | call to GetHeaders | remote | -| azure.cpp:277:45:277:47 | call to GetBody | remote | -| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | remote | +| asio_streams.cpp:87:34:87:44 | recv_buffer | remote | +| azure.cpp:253:48:253:60 | call to GetBodyStream | remote | +| azure.cpp:273:52:273:61 | call to GetHeaders | remote | +| azure.cpp:277:38:277:44 | call to GetBody | remote | +| azure.cpp:281:68:281:84 | call to ExtractBodyStream | remote | | azure.cpp:289:32:289:40 | call to GetHeader | remote | | azure.cpp:293:58:293:67 | call to GetHeaders | remote | | test.cpp:10:10:10:18 | call to ymlSource | local | @@ -16,30 +16,30 @@ | test.cpp:186:14:186:22 | call to ymlSource | local | | test.cpp:199:14:199:22 | call to ymlSource | local | | test.cpp:216:18:216:26 | call to ymlSource | local | -| test.cpp:222:10:222:20 | call to ymlSource | local | -| windows.cpp:22:15:22:29 | *call to GetCommandLineA | local | -| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | local | -| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | local | -| windows.cpp:168:35:168:40 | ReadFile output argument | local | -| windows.cpp:177:23:177:28 | ReadFileEx output argument | local | -| windows.cpp:189:21:189:26 | ReadFile output argument | local | -| windows.cpp:192:23:192:29 | ReadFileEx output argument | local | -| windows.cpp:198:21:198:26 | ReadFile output argument | local | -| windows.cpp:201:23:201:29 | ReadFileEx output argument | local | -| windows.cpp:209:84:209:89 | NtReadFile output argument | local | -| windows.cpp:286:23:286:35 | *call to MapViewOfFile | local | -| windows.cpp:293:23:293:36 | *call to MapViewOfFile2 | local | -| windows.cpp:302:23:302:36 | *call to MapViewOfFile3 | local | -| windows.cpp:311:23:311:43 | *call to MapViewOfFile3FromApp | local | -| windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | local | -| windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | local | -| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | local | -| windows.cpp:645:45:645:50 | WinHttpReadData output argument | remote | -| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | remote | -| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | remote | -| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | remote | -| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | remote | -| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | remote | -| windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | remote | -| windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | remote | -| windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | remote | +| test.cpp:222:10:222:18 | call to ymlSource | local | +| windows.cpp:22:15:22:29 | call to GetCommandLineA | local | +| windows.cpp:34:17:34:38 | call to GetEnvironmentStringsA | local | +| windows.cpp:39:36:39:38 | buf | local | +| windows.cpp:168:35:168:40 | buffer | local | +| windows.cpp:177:23:177:28 | buffer | local | +| windows.cpp:189:21:189:26 | buffer | local | +| windows.cpp:192:23:192:29 | buffer2 | local | +| windows.cpp:198:21:198:26 | buffer | local | +| windows.cpp:201:23:201:29 | buffer2 | local | +| windows.cpp:209:84:209:89 | buffer | local | +| windows.cpp:286:23:286:35 | call to MapViewOfFile | local | +| windows.cpp:293:23:293:36 | call to MapViewOfFile2 | local | +| windows.cpp:302:23:302:36 | call to MapViewOfFile3 | local | +| windows.cpp:311:23:311:43 | call to MapViewOfFile3FromApp | local | +| windows.cpp:318:23:318:37 | call to MapViewOfFileEx | local | +| windows.cpp:325:23:325:42 | call to MapViewOfFileFromApp | local | +| windows.cpp:332:23:332:40 | call to MapViewOfFileNuma2 | local | +| windows.cpp:645:45:645:50 | buffer | remote | +| windows.cpp:652:48:652:53 | buffer | remote | +| windows.cpp:659:47:659:52 | buffer | remote | +| windows.cpp:669:70:669:79 | headerName | remote | +| windows.cpp:669:82:669:87 | buffer | remote | +| windows.cpp:669:105:669:112 | & ... | remote | +| windows.cpp:900:64:900:77 | & ... | remote | +| windows.cpp:929:70:929:75 | buffer | remote | +| windows.cpp:936:70:936:78 | & ... | remote | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/test.cpp b/cpp/ql/test/library-tests/dataflow/external-models/test.cpp index ebb20bab6497..aa021b967afc 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/test.cpp @@ -223,4 +223,16 @@ void test_reverse_flow(unsigned i, unsigned j) { char c = s[j]; ymlSink(c); // $ ir } -} \ No newline at end of file +} + +struct SourceWrapper { + int value; +}; + +SourceWrapper ymlFieldSource(); + +void test_source_access_path() { + SourceWrapper wrapper = ymlFieldSource(); + ymlSink(wrapper.value); // $ ir +} + diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.expected b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.expected index 7d1e2bc9327a..7600f71b421e 100644 --- a/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.expected +++ b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.expected @@ -18,6 +18,10 @@ postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow +| tests.cpp:60:30:60:31 | remoteMadSourceIndirectArg0 output argument | PostUpdateNode should not be the target of local flow. | +| tests.cpp:63:33:63:33 | remoteMadSourceIndirectArg1 output argument | PostUpdateNode should not be the target of local flow. | +| tests.cpp:295:39:295:40 | memberRemoteMadSourceIndirectArg0 output argument | PostUpdateNode should not be the target of local flow. | +| tests.cpp:369:2:369:4 | qualifierSource output argument | PostUpdateNode should not be the target of local flow. | viableImplInCallContextTooLarge uniqueParameterNodeAtPosition uniqueParameterNodePosition @@ -283,6 +287,22 @@ sourceCallables | tests.cpp:433:6:433:10 | array | | tests.cpp:434:6:434:6 | y | flowSummaryNode +| tests.cpp:36:7:36:20 | call to localMadSource | | | test_sources | +| tests.cpp:37:7:37:21 | call to remoteMadSource | | | test_sources | +| tests.cpp:39:7:39:24 | call to localMadSourceVoid | | | test_sources | +| tests.cpp:40:7:40:27 | call to localMadSourceHasBody | | | test_sources | +| tests.cpp:45:10:45:23 | call to localMadSource | | | test_sources | +| tests.cpp:53:7:53:29 | call to remoteMadSourceIndirect | | | test_sources | +| tests.cpp:54:8:54:30 | call to remoteMadSourceIndirect | | | test_sources | +| tests.cpp:55:8:55:36 | call to remoteMadSourceDoubleIndirect | | | test_sources | +| tests.cpp:56:9:56:37 | call to remoteMadSourceDoubleIndirect | | | test_sources | +| tests.cpp:60:30:60:31 | & ... | | | test_sources | +| tests.cpp:63:33:63:33 | d | | | test_sources | +| tests.cpp:67:10:67:23 | call to localMadSource | | | test_sources | +| tests.cpp:70:7:70:57 | call to namespace2LocalMadSource | | | test_sources | +| tests.cpp:75:32:75:32 | x | | | remoteMadSourceParam0 | +| tests.cpp:111:14:111:27 | call to localMadSource | | | test_sinks | +| tests.cpp:112:22:112:44 | call to remoteMadSourceIndirect | | | test_sinks | | tests.cpp:127:5:127:19 | [summary param] 0 in madArg0ToReturn | ParameterNode | madArg0ToReturn | madArg0ToReturn | | tests.cpp:127:5:127:19 | [summary] to write: ReturnValue in madArg0ToReturn | ReturnNode | madArg0ToReturn | madArg0ToReturn | | tests.cpp:128:6:128:28 | [summary param] 0 in madArg0ToReturnIndirect | ParameterNode | madArg0ToReturnIndirect | madArg0ToReturnIndirect | @@ -325,6 +345,8 @@ flowSummaryNode | tests.cpp:148:13:148:40 | [summary param] 0 in madArg0ToReturnFieldIndirect | ParameterNode | madArg0ToReturnFieldIndirect | madArg0ToReturnFieldIndirect | | tests.cpp:148:13:148:40 | [summary] to write: ReturnValue in madArg0ToReturnFieldIndirect | ReturnNode | madArg0ToReturnFieldIndirect | madArg0ToReturnFieldIndirect | | tests.cpp:148:13:148:40 | [summary] to write: ReturnValue.Field[*MyContainer::ptr]/Field[*ptr] in madArg0ToReturnFieldIndirect | | madArg0ToReturnFieldIndirect | madArg0ToReturnFieldIndirect | +| tests.cpp:225:30:225:44 | call to remoteMadSource | | | test_summaries | +| tests.cpp:226:39:226:53 | call to remoteMadSource | | | test_summaries | | tests.cpp:250:7:250:19 | [summary param] 0 in madArg0ToSelf | ParameterNode | madArg0ToSelf | madArg0ToSelf | | tests.cpp:250:7:250:19 | [summary param] this in madArg0ToSelf | ParameterNode | madArg0ToSelf | madArg0ToSelf | | tests.cpp:250:7:250:19 | [summary] to write: Argument[this] in madArg0ToSelf | PostUpdateNode | madArg0ToSelf | madArg0ToSelf | @@ -339,6 +361,13 @@ flowSummaryNode | tests.cpp:254:6:254:21 | [summary] to write: ReturnValue in madFieldToReturn | ReturnNode | madFieldToReturn | madFieldToReturn | | tests.cpp:277:7:277:30 | [summary param] this in namespaceMadSelfToReturn | ParameterNode | namespaceMadSelfToReturn | namespaceMadSelfToReturn | | tests.cpp:277:7:277:30 | [summary] to write: ReturnValue in namespaceMadSelfToReturn | ReturnNode | namespaceMadSelfToReturn | namespaceMadSelfToReturn | +| tests.cpp:292:10:292:30 | call to memberRemoteMadSource | | | test_class_members | +| tests.cpp:295:39:295:40 | & ... | | | test_class_members | +| tests.cpp:300:11:300:31 | call to memberRemoteMadSource | | | test_class_members | +| tests.cpp:301:11:301:33 | call to subtypeRemoteMadSource1 | | | test_class_members | +| tests.cpp:303:11:303:33 | call to subtypeRemoteMadSource2 | | | test_class_members | +| tests.cpp:351:26:351:46 | call to memberRemoteMadSource | | | test_class_members | +| tests.cpp:369:2:369:4 | mc8 | | | test_class_members | | tests.cpp:392:5:392:29 | [summary param] 0 in madCallArg0ReturnToReturn | ParameterNode | madCallArg0ReturnToReturn | madCallArg0ReturnToReturn | | tests.cpp:392:5:392:29 | [summary] read: Argument[0].Parameter[this pointer] in madCallArg0ReturnToReturn | PostUpdateNode | madCallArg0ReturnToReturn | madCallArg0ReturnToReturn | | tests.cpp:392:5:392:29 | [summary] read: Argument[0].ReturnValue in madCallArg0ReturnToReturn | OutNode | madCallArg0ReturnToReturn | madCallArg0ReturnToReturn | diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.ql b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.ql index 4b89b7da4093..40081923bb8d 100644 --- a/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.ql +++ b/cpp/ql/test/library-tests/dataflow/models-as-data/testModels.ql @@ -69,6 +69,6 @@ string describe(DataFlow::Node n) { query predicate flowSummaryNode(FlowSummaryNode n, string str1, string str2, string str3) { str1 = concat(describe(n), ", ") and - str2 = concat(n.getSummarizedCallable().toString(), ", ") and + str2 = concat(n.getSummaryNode().getSummarizedCallable().toString(), ", ") and str3 = concat(n.getEnclosingCallable().toString(), ", ") } diff --git a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll index b0828c3384bb..14c7926cfb84 100644 --- a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll @@ -19,6 +19,8 @@ signature module InputSig Lang> { class SummarizedCallableBase { bindingset[this] string toString(); + + Location getLocation(); } /** Holds if `c` is defined in source code. */ @@ -32,6 +34,8 @@ signature module InputSig Lang> { class SourceBase { bindingset[this] string toString(); + + Location getLocation(); } /** @@ -41,6 +45,8 @@ signature module InputSig Lang> { class SinkBase { bindingset[this] string toString(); + + Location getLocation(); } /** @@ -59,15 +65,15 @@ signature module InputSig Lang> { */ class FlowSummaryCallBase { string toString(); + + Location getLocation(); } /** Gets a call that targets summarized callable `sc`. */ default FlowSummaryCallBase getASourceCall(SummarizedCallableBase sc) { none() } /** Gets the callable corresponding to summarized callable `c`. */ - default Lang::DataFlowCallable getSummarizedCallableAsDataFlowCallable(SummarizedCallableBase c) { - none() - } + Lang::DataFlowCallable getSummarizedCallableAsDataFlowCallable(SummarizedCallableBase c); /** Gets the enclosing callable of `call`. */ default Lang::DataFlowCallable getSourceCallEnclosingCallable(FlowSummaryCallBase call) { none() } @@ -1181,12 +1187,14 @@ module Make< pragma[nomagic] private predicate sourceOutputState( - SourceElement source, SummaryComponentStack s, string kind, string model + SourceElement source, SummaryComponentStack entry, SummaryComponentStack s, string kind, + string model ) { - sourceOutputStateEntry(source, s, kind, model) + sourceOutputStateEntry(source, s, kind, model) and + entry = s or exists(SummaryComponentStack out | - sourceOutputState(source, out, kind, model) and + sourceOutputState(source, entry, out, kind, model) and out.head() = TContentSummaryComponent(_) and s = out.tail() ) @@ -1218,7 +1226,7 @@ module Make< private newtype TSummaryNodeState = TSummaryNodeInputState(SummaryComponentStack s) { inputState(_, s) } or TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) } or - TSourceOutputState(SummaryComponentStack s) { sourceOutputState(_, s, _, _) } or + TSourceOutputState(SummaryComponentStack s) { sourceOutputState(_, _, s, _, _) } or TSinkInputState(SummaryComponentStack s) { sinkInputState(_, s, _, _) } /** @@ -1258,9 +1266,10 @@ module Make< /** Holds if this state is a valid output state for `source`. */ pragma[nomagic] predicate isSourceOutputState( - SourceElement source, SummaryComponentStack s, string kind, string model + SourceElement source, SummaryComponentStack entry, SummaryComponentStack s, string kind, + string model ) { - sourceOutputState(source, s, kind, model) and + sourceOutputState(source, entry, s, kind, model) and this = TSourceOutputState(s) } @@ -1297,847 +1306,1047 @@ module Make< } } - private newtype TSummaryNode = - TSummaryInternalNode(SummarizedCallable c, SummaryNodeState state) { - summaryNodeRange(c, state) - } or - TSummaryParameterNode(SummarizedCallable c, ParameterPosition pos) { - summaryParameterNodeRange(c, pos) - } or - TSummaryReturnArgumentNode(FlowSummaryCallBase call, ReturnKind rk) { - exists(SummarizedCallable sc | - call = getASourceCall(sc) and - relevantFlowSummaryPosition(sc, rk) - ) - } or - TSourceOutputNode(SourceElement source, SummaryNodeState state, string kind, string model) { - state.isSourceOutputState(source, _, kind, model) - } or - TSinkInputNode(SinkElement sink, SummaryNodeState state, string kind, string model) { - state.isSinkInputState(sink, _, kind, model) - } - - abstract class SummaryNode extends TSummaryNode { - abstract string toString(); - - abstract SummarizedCallable getSummarizedCallable(); - - abstract SourceElement getSourceElement(); - - abstract SinkElement getSinkElement(); - - predicate isHidden() { any() } - } + signature module InputSig2 { + /** + * An element used to represent sources before possible stores and sinks + * after possible reads. + * + * These elements will be embedded into the data flow graph and serve as the + * sources/sinks that the user sees in the output. + */ + class SourceSinkReportingElement { + DataFlowCallable getEnclosingCallable(); - private class SummaryInternalNode extends SummaryNode, TSummaryInternalNode { - private SummarizedCallable c; - private SummaryNodeState state; + string toString(); - SummaryInternalNode() { this = TSummaryInternalNode(c, state) } + Location getLocation(); + } - override string toString() { result = "[summary] " + state + " in " + c } + /** + * Gets an element corresponding to the `s` part of `source`. + * + * `s` is typically `ReturnValue` and the result is the node that + * represents the return value of `source`. + */ + SourceSinkReportingElement getSourceEntryElement(SourceElement source, SummaryComponentStack s); - override SummarizedCallable getSummarizedCallable() { result = c } + /** + * Gets a data flow node corresponding to the `s` part of `e`. + * + * In the final path graph there will be an edge from the node that embeds + * `e = getSourceEntryElement(_, s)` to the result of this predicate, + * and any stores will happen between them. + */ + bindingset[e, s] + Node getSourceExitNode(SourceSinkReportingElement e, SummaryComponentStack s); - override SourceElement getSourceElement() { none() } + /** + * Gets a data flow node corresponding to the `sc` part of `e`. + * + * `sc` is typically `Argument[i]` and the result is the node that + * represents the `i`th argument of `sink`. + */ + bindingset[e, sc] + Node getSinkEntryNode(SourceSinkReportingElement e, SummaryComponent sc); - override SinkElement getSinkElement() { none() } + /** + * Gets an element corresponding to the `sc` part of `sink`. + * + * In the final path graph there will be an edge from `getSinkEntryNode(result, sc)` + * to the node that embeds the result of this predicate, and any reads will happen + * between them. + */ + SourceSinkReportingElement getSinkExitElement(SinkElement sink, SummaryComponent sc); } - private class SummaryParamNode extends SummaryNode, TSummaryParameterNode { - private SummarizedCallable c; - private ParameterPosition pos; + module Make2 { + private import Input2 - SummaryParamNode() { this = TSummaryParameterNode(c, pos) } + private newtype TSummaryNode = + TSummaryInternalNode(SummarizedCallable c, SummaryNodeState state) { + summaryNodeRange(c, state) + } or + TSummaryParameterNode(SummarizedCallable c, ParameterPosition pos) { + summaryParameterNodeRange(c, pos) + } or + TSummaryReturnArgumentNode(FlowSummaryCallBase call, ReturnKind rk) { + exists(SummarizedCallable sc | + call = getASourceCall(sc) and + relevantFlowSummaryPosition(sc, rk) + ) + } or + TSourceOutputNode( + SourceElement source, SummaryNodeState state, SummaryComponentStack exit, + SourceSinkReportingElement e, string kind, string model + ) { + exists(SummaryComponentStack entry | + state.isSourceOutputState(source, entry, _, kind, model) and + sourceOutputState(source, entry, exit, kind, model) and + not exit.head() instanceof TContentSummaryComponent and + e = getSourceEntryElement(source, exit) + ) + } or + TSinkInputNode( + SinkElement sink, SummaryNodeState state, SourceSinkReportingElement e, string kind, + string model + ) { + exists(SummaryComponentStack s | + state.isSinkInputState(sink, s, kind, model) and + e = getSinkExitElement(sink, s.bottom()) + ) + } - override string toString() { result = "[summary param] " + pos + " in " + c } + abstract class SummaryNode extends TSummaryNode { + abstract string toString(); - override SummarizedCallable getSummarizedCallable() { result = c } + abstract SummarizedCallable getSummarizedCallable(); - override SourceElement getSourceElement() { none() } + abstract SourceElement getSourceElement(); - override SinkElement getSinkElement() { none() } - } + abstract SinkElement getSinkElement(); - private class SummaryReturnArgumentNode extends SummaryNode, TSummaryReturnArgumentNode { - private FlowSummaryCallBase call; - private ReturnKind rk; + abstract SourceSinkReportingElement getSourceSinkReportingElement(); - SummaryReturnArgumentNode() { this = TSummaryReturnArgumentNode(call, rk) } + abstract DataFlowCallable getEnclosingCallable(); - override string toString() { result = "[summary] value written to " + rk + " at " + call } + abstract Location getLocation(); - override SummarizedCallable getSummarizedCallable() { none() } + predicate isHidden() { any() } + } - override SourceElement getSourceElement() { none() } + private class SummaryInternalNode extends SummaryNode, TSummaryInternalNode { + private SummarizedCallable c; + private SummaryNodeState state; - override SinkElement getSinkElement() { none() } - } + SummaryInternalNode() { this = TSummaryInternalNode(c, state) } - /** - * Gets the summary node that represents the argument node used to transfer - * flow into the caller when a value is written to the value returned by - * `call` with kind `rk`. - */ - SummaryNode summaryArgumentNode(FlowSummaryCallBase call, ReturnKind rk) { - result = TSummaryReturnArgumentNode(call, rk) - } + override string toString() { result = "[summary] " + state + " in " + c } - /** Gets the enclosing callable for summary node `sn`. */ - DataFlowCallable getEnclosingCallable(SummaryNode sn) { - result = getSummarizedCallableAsDataFlowCallable(sn.getSummarizedCallable()) - or - exists(FlowSummaryCallBase call | - sn = TSummaryReturnArgumentNode(call, _) and - result = getSourceCallEnclosingCallable(call) - ) - } + override SummarizedCallable getSummarizedCallable() { result = c } - class SourceOutputNode extends SummaryNode, TSourceOutputNode { - private SourceElement source_; - private SummaryNodeState state_; - private string kind_; - private string model_; + override SourceElement getSourceElement() { none() } - SourceOutputNode() { this = TSourceOutputNode(source_, state_, kind_, model_) } + override SinkElement getSinkElement() { none() } - /** - * Holds if this node is an entry node, i.e. before any stores have been performed. - * - * This node should be used as the actual source node in data flow configurations. - */ - predicate isEntry(string kind, string model) { - model = model_ and - exists(SummaryComponentStack out | - sourceOutputStateEntry(source_, out, kind, model_) and - state_.isSourceOutputState(source_, out, kind, model_) - ) - } + override SourceSinkReportingElement getSourceSinkReportingElement() { none() } - /** - * Holds if this node is an exit node, i.e. after all stores have been performed. - * - * A local flow step should be added from this node to a data flow node representing - * `s` inside `source`. - */ - predicate isExit(SourceElement source, SummaryComponentStack s, string model) { - source = source_ and - model = model_ and - state_.isSourceOutputState(source, s, _, model) + override DataFlowCallable getEnclosingCallable() { + result = getSummarizedCallableAsDataFlowCallable(c) + } + + override Location getLocation() { result = c.getLocation() } } - override predicate isHidden() { not this.isEntry(_, _) } + private class SummaryParamNode extends SummaryNode, TSummaryParameterNode { + private SummarizedCallable c; + private ParameterPosition pos; - override string toString() { - if this.isEntry(_, _) - then result = source_.toString() - else result = "[source] " + state_ + " at " + source_ - } + SummaryParamNode() { this = TSummaryParameterNode(c, pos) } - override SummarizedCallable getSummarizedCallable() { none() } + override string toString() { result = "[summary param] " + pos + " in " + c } - override SourceElement getSourceElement() { result = source_ } + override SummarizedCallable getSummarizedCallable() { result = c } - override SinkElement getSinkElement() { none() } - } + override SourceElement getSourceElement() { none() } - class SinkInputNode extends SummaryNode, TSinkInputNode { - private SinkElement sink_; - private SummaryNodeState state_; - private string kind_; - private string model_; + override SinkElement getSinkElement() { none() } - SinkInputNode() { this = TSinkInputNode(sink_, state_, kind_, model_) } + override SourceSinkReportingElement getSourceSinkReportingElement() { none() } - /** - * Holds if this node is an entry node, i.e. before any reads have been performed. - * - * A local flow step should be added to this node from a data flow node representing - * `sc` inside `sink`. - */ - predicate isEntry(SinkElement sink, SummaryComponent sc, string model) { - sink = sink_ and - model = model_ and - state_.isSinkInputState(sink, TSingletonSummaryComponentStack(sc), _, model) - } + override DataFlowCallable getEnclosingCallable() { + result = getSummarizedCallableAsDataFlowCallable(c) + } - /** - * Holds if this node is an exit node, i.e. after all reads have been performed. - * - * This node should be used as the actual sink node in data flow configurations. - */ - predicate isExit(string kind, string model) { - kind = kind_ and - model = model_ and - exists(SummaryComponentStack inp | - sinkInputStateExit(sink_, inp, kind, model_) and - state_.isSinkInputState(sink_, inp, kind, model_) - ) + override Location getLocation() { result = c.getLocation() } } - override predicate isHidden() { not this.isExit(_, _) } + private class SummaryReturnArgumentNode extends SummaryNode, TSummaryReturnArgumentNode { + private FlowSummaryCallBase call; + private ReturnKind rk; - override string toString() { - if this.isExit(_, _) - then result = sink_.toString() - else result = "[sink] " + state_ + " at " + sink_ - } + SummaryReturnArgumentNode() { this = TSummaryReturnArgumentNode(call, rk) } - override SummarizedCallable getSummarizedCallable() { none() } + override string toString() { result = "[summary] value written to " + rk + " at " + call } - override SourceElement getSourceElement() { none() } + override SummarizedCallable getSummarizedCallable() { none() } - override SinkElement getSinkElement() { result = sink_ } - } + override SourceElement getSourceElement() { none() } - /** - * Holds if `state` represents having read from a parameter at position - * `pos` in `c`. In this case we are not synthesizing a data-flow node, - * but instead assume that a relevant parameter node already exists. - */ - private predicate parameterReadState( - SummarizedCallable c, SummaryNodeState state, ParameterPosition pos - ) { - state.isInputState(c, SummaryComponentStack::argument(pos)) - or - exists(ReturnKind rk | - relevantFlowSummaryPosition(c, rk) and - state.isInputState(c, SummaryComponentStack::return(rk)) and - pos = getFlowSummaryParameterPosition(rk) - ) - } + override SinkElement getSinkElement() { none() } - /** - * Holds if a synthesized summary node is needed for the state `state` in summarized - * callable `c`. - */ - private predicate summaryNodeRange(SummarizedCallable c, SummaryNodeState state) { - state.isInputState(c, _) and - not parameterReadState(c, state, _) - or - state.isOutputState(c, _) - } + override SourceSinkReportingElement getSourceSinkReportingElement() { none() } - pragma[noinline] - private SummaryNode summaryNodeInputState(SummarizedCallable c, SummaryComponentStack s) { - exists(SummaryNodeState state | state.isInputState(c, s) | - result = TSummaryInternalNode(c, state) - or - exists(ParameterPosition pos | - parameterReadState(c, state, pos) and - result = TSummaryParameterNode(c, pos) - ) - ) - } + override DataFlowCallable getEnclosingCallable() { + result = getSourceCallEnclosingCallable(call) + } - pragma[noinline] - private SummaryNode summaryNodeOutputState(SummarizedCallable c, SummaryComponentStack s) { - exists(SummaryNodeState state | - state.isOutputState(c, s) and - result = TSummaryInternalNode(c, state) - ) - } + override Location getLocation() { result = call.getLocation() } + } - pragma[noinline] - private SummaryNode sourceElementOutputState(SourceElement source, SummaryComponentStack s) { - exists(SummaryNodeState state, string kind, string model | - state.isSourceOutputState(source, s, kind, model) and - result = TSourceOutputNode(source, state, kind, model) - ) - } + /** + * Gets the summary node that represents the argument node used to transfer + * flow into the caller when a value is written to the value returned by + * `call` with kind `rk`. + */ + SummaryNode summaryArgumentNode(FlowSummaryCallBase call, ReturnKind rk) { + result = TSummaryReturnArgumentNode(call, rk) + } - pragma[noinline] - private SummaryNode sinkElementInputState(SinkElement sink, SummaryComponentStack s) { - exists(SummaryNodeState state, string kind, string model | - state.isSinkInputState(sink, s, kind, model) and - result = TSinkInputNode(sink, state, kind, model) - ) - } + class SourceOutputNode extends SummaryNode, TSourceOutputNode { + private SourceElement source_; + private SummaryNodeState state_; + SummaryComponentStack exit; + private SourceSinkReportingElement e_; + private string kind_; + private string model_; - /** - * Holds if a write targets `post`, which is a post-update node for a - * parameter at position `pos` in `c`. - */ - private predicate isParameterPostUpdate( - SummaryNode post, SummarizedCallable c, ParameterPosition pos - ) { - post = summaryNodeOutputState(c, SummaryComponentStack::argument(pos)) - } + SourceOutputNode() { this = TSourceOutputNode(source_, state_, exit, e_, kind_, model_) } - /** Holds if a parameter node at position `pos` is required for `c`. */ - private predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) { - parameterReadState(c, _, pos) - or - // Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context - any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos)) - } + /** + * Holds if this node is an entry node, i.e. before any stores have been performed. + * + * This node should be used as the actual source node in data flow configurations. + */ + predicate isEntry(string kind, string model) { + model = model_ and + exists(SummaryComponentStack out | + state_.isSourceOutputState(source_, out, out, kind, model_) + ) + } - private predicate callbackOutput( - SummarizedCallable c, SummaryComponentStack s, SummaryNode receiver, ReturnKind rk - ) { - any(SummaryNodeState state).isInputState(c, s) and - s.head() = TReturnSummaryComponent(rk) and - receiver = summaryNodeInputState(c, s.tail()) - } + /** + * Holds if this node is an exit node, i.e. after all stores have been performed. + * + * A local flow step should be added from this node to a data flow node representing + * `s` inside `source`. + */ + predicate isExit( + SourceElement source, SummaryComponentStack s, SourceSinkReportingElement e, string model + ) { + source = source_ and + model = model_ and + s = exit and + e = e_ + } - private predicate callbackInput( - SummarizedCallable c, SummaryComponentStack s, SummaryNode receiver, ArgumentPosition pos - ) { - any(SummaryNodeState state).isOutputState(c, s) and - s.head() = TParameterSummaryComponent(pos) and - receiver = summaryNodeInputState(c, s.tail()) - } + override predicate isHidden() { not this.isEntry(_, _) } - /** Holds if a call targeting `receiver` should be synthesized inside `c`. */ - predicate summaryCallbackRange(SummarizedCallable c, SummaryNode receiver) { - callbackOutput(c, _, receiver, _) - or - callbackInput(c, _, receiver, _) - } + override string toString() { + if this.isEntry(_, _) + then result = e_.toString() + else result = "[source] " + state_ + " at " + e_ + } - /** Holds if summary node `p` is a parameter with position `pos`. */ - predicate summaryParameterNode(SummaryNode p, ParameterPosition pos) { - p = TSummaryParameterNode(_, pos) - } + override SummarizedCallable getSummarizedCallable() { none() } - /** Holds if summary node `out` contains output of kind `rk` from a call targeting `receiver`. */ - predicate summaryOutNode(SummaryNode receiver, SummaryNode out, ReturnKind rk) { - exists(SummarizedCallable callable, SummaryComponentStack s | - callbackOutput(callable, s, receiver, rk) and - out = summaryNodeInputState(callable, s) - ) - } + override SourceElement getSourceElement() { result = source_ } - /** Holds if summary node `arg` is at position `pos` in a call targeting `receiver`. */ - predicate summaryArgumentNode(SummaryNode receiver, SummaryNode arg, ArgumentPosition pos) { - exists(SummarizedCallable callable, SummaryComponentStack s | - callbackInput(callable, s, receiver, pos) and - arg = summaryNodeOutputState(callable, s) - ) - } + override SinkElement getSinkElement() { none() } - /** Holds if summary node `post` is a post-update node with pre-update node `pre`. */ - predicate summaryPostUpdateNode(SummaryNode post, SummaryNode pre) { - exists(SummarizedCallable c, ParameterPosition pos | - isParameterPostUpdate(post, c, pos) and - pre = TSummaryParameterNode(c, pos) - ) - or - exists(SummarizedCallable callable, SummaryComponentStack s | - callbackInput(callable, s, _, _) and - pre = summaryNodeOutputState(callable, s) and - post = summaryNodeInputState(callable, s) - ) - } + override SourceSinkReportingElement getSourceSinkReportingElement() { result = e_ } - /** Holds if summary node `ret` is a return node of kind `rk`. */ - predicate summaryReturnNode(SummaryNode ret, ReturnKind rk) { - exists(SummaryComponentStack s | - ret = summaryNodeOutputState(_, s) and - s = TSingletonSummaryComponentStack(TReturnSummaryComponent(rk)) - ) - } + override DataFlowCallable getEnclosingCallable() { result = e_.getEnclosingCallable() } - /** Holds if return kind `rk` is a relevant return kind for flow summary modeling. */ - predicate relevantFlowSummaryPosition(ReturnKind rk) { relevantFlowSummaryPosition(_, rk) } + override Location getLocation() { result = e_.getLocation() } + } - /** - * Holds if flow is allowed to pass from the parameter at position `pos` of `c`, - * to a return node, and back out to the parameter. - */ - predicate summaryAllowParameterReturnInSelf(SummarizedCallable c, ParameterPosition ppos) { - exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents | - summary(c, inputContents, outputContents, _, _) and - inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and - outputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) - ) - } + class SinkInputNode extends SummaryNode, TSinkInputNode { + private SinkElement sink_; + private SummaryNodeState state_; + private SourceSinkReportingElement e_; + private string kind_; + private string model_; - /** - * Holds if `barrier` is a relevant barrier element with output specification `outSpec`. - */ - predicate barrierSpec( - BarrierElement barrier, SummaryComponentStack outSpec, string kind, string model - ) { - exists(string output | - isRelevantBarrier(barrier, output, kind, _, model) and - External::interpretSpec(output, outSpec) - ) - } + SinkInputNode() { this = TSinkInputNode(sink_, state_, e_, kind_, model_) } - /** - * Holds if `barrierGuard` is a relevant barrier guard element with input specification `inSpec`. - */ - predicate barrierGuardSpec( - BarrierGuardElement barrierGuard, SummaryComponentStack inSpec, string acceptingValue, - string kind, string model - ) { - exists(string input | - isRelevantBarrierGuard(barrierGuard, input, acceptingValue, kind, _, model) and - External::interpretSpec(input, inSpec) - ) - } + /** + * Holds if this node is an entry node, i.e. before any reads have been performed. + * + * A local flow step should be added to this node from a data flow node representing + * `sc` inside `sink`. + */ + predicate isEntry( + SinkElement sink, SummaryComponent sc, SourceSinkReportingElement e, string model + ) { + sink = sink_ and + model = model_ and + e = e_ and + state_.isSinkInputState(sink, TSingletonSummaryComponentStack(sc), _, model) + } - signature module TypesInputSig { - /** Gets the type of content `c`. */ - DataFlowType getContentType(ContentSet c); + /** + * Holds if this node is an exit node, i.e. after all reads have been performed. + * + * This node should be used as the actual sink node in data flow configurations. + */ + predicate isExit(string kind, string model) { + kind = kind_ and + model = model_ and + exists(SummaryComponentStack inp | + sinkInputStateExit(sink_, inp, kind, model_) and + state_.isSinkInputState(sink_, inp, kind, model_) + ) + } - /** Gets the type of the parameter at the given position. */ - bindingset[c, pos] - DataFlowType getParameterType(SummarizedCallable c, ParameterPosition pos); + override predicate isHidden() { not this.isExit(_, _) } - /** Gets the return type of kind `rk` for callable `c`. */ - bindingset[c, rk] - DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk); + override string toString() { + if this.isExit(_, _) + then result = sink_.toString() + else result = "[sink] " + state_ + " at " + sink_ + } - /** - * Gets the type of the `i`th parameter in a synthesized call that targets a - * callback of type `t`. - */ - bindingset[t, pos] - DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos); + override SummarizedCallable getSummarizedCallable() { none() } - /** - * Gets the return type of kind `rk` in a synthesized call that targets a - * callback of type `t`. - */ - bindingset[t, rk] - DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk); + override SourceElement getSourceElement() { none() } - DataFlowType getSyntheticGlobalType(SyntheticGlobal sg); + override SinkElement getSinkElement() { result = sink_ } - DataFlowType getSourceType(SourceBase source, SummaryComponentStack sc); + override SourceSinkReportingElement getSourceSinkReportingElement() { result = e_ } - DataFlowType getSinkType(SinkBase sink, SummaryComponent sc); - } + override DataFlowCallable getEnclosingCallable() { result = e_.getEnclosingCallable() } - /** - * Provides the predicate `summaryNodeType` for associating types with summary nodes. - * - * Only relevant for typed languages. - */ - module Types { - private import TypesInput + override Location getLocation() { result = e_.getLocation() } + } /** - * Gets the type of synthesized summary node `n`. - * - * The type is computed based on the language-specific predicates - * `getContentType()`, `getReturnType()`, `getCallbackParameterType()`, and - * `getCallbackReturnType()`. + * Holds if `state` represents having read from a parameter at position + * `pos` in `c`. In this case we are not synthesizing a data-flow node, + * but instead assume that a relevant parameter node already exists. */ - DataFlowType summaryNodeType(SummaryNode n) { - exists(SummaryNode pre | - summaryPostUpdateNode(n, pre) and - result = summaryNodeType(pre) - ) - or - exists(SummarizedCallable c, SummaryComponentStack s, SummaryComponent head | - head = s.head() - | - n = summaryNodeInputState(c, s) and - ( - exists(ContentSet cont | result = getContentType(cont) | - head = TContentSummaryComponent(cont) or - head = TWithContentSummaryComponent(cont) - ) - or - head = TWithoutContentSummaryComponent(_) and - result = summaryNodeType(summaryNodeInputState(c, s.tail())) - or - exists(ReturnKind rk | - head = TReturnSummaryComponent(rk) and - result = - getCallbackReturnType(summaryNodeType(summaryNodeInputState(pragma[only_bind_out](c), - s.tail())), rk) - ) - or - exists(SyntheticGlobal sg | - head = TSyntheticGlobalSummaryComponent(sg) and - result = getSyntheticGlobalType(sg) - ) - or - exists(ParameterPosition pos | - head = TArgumentSummaryComponent(pos) and - result = getParameterType(c, pos) - ) - ) - or - n = summaryNodeOutputState(c, s) and - ( - exists(ContentSet cont | - head = TContentSummaryComponent(cont) and result = getContentType(cont) - ) - or - s.length() = 1 and - exists(ReturnKind rk | - head = TReturnSummaryComponent(rk) and - result = getReturnType(c, rk) - ) - or - exists(ArgumentPosition pos | head = TParameterSummaryComponent(pos) | - result = - getCallbackParameterType(summaryNodeType(summaryNodeInputState(pragma[only_bind_out](c), - s.tail())), pos) - ) - or - exists(SyntheticGlobal sg | - head = TSyntheticGlobalSummaryComponent(sg) and - result = getSyntheticGlobalType(sg) - ) - ) - ) + private predicate parameterReadState( + SummarizedCallable c, SummaryNodeState state, ParameterPosition pos + ) { + state.isInputState(c, SummaryComponentStack::argument(pos)) or - exists(SourceElement source | - exists(SummaryComponentStack s | - n.(SourceOutputNode).isExit(source, s, _) and - result = getSourceType(source, s) - ) - or - exists(SummaryComponentStack s, ContentSet cont | - n = sourceElementOutputState(source, s) and - s.head() = TContentSummaryComponent(cont) and - result = getContentType(cont) - ) + exists(ReturnKind rk | + relevantFlowSummaryPosition(c, rk) and + state.isInputState(c, SummaryComponentStack::return(rk)) and + pos = getFlowSummaryParameterPosition(rk) ) + } + + /** + * Holds if a synthesized summary node is needed for the state `state` in summarized + * callable `c`. + */ + private predicate summaryNodeRange(SummarizedCallable c, SummaryNodeState state) { + state.isInputState(c, _) and + not parameterReadState(c, state, _) or - exists(SinkElement sink | - exists(SummaryComponent sc | - n.(SinkInputNode).isEntry(sink, sc, _) and - result = getSinkType(sink, sc) - ) + state.isOutputState(c, _) + } + + pragma[noinline] + private SummaryNode summaryNodeInputState(SummarizedCallable c, SummaryComponentStack s) { + exists(SummaryNodeState state | state.isInputState(c, s) | + result = TSummaryInternalNode(c, state) or - exists(SummaryComponentStack s, ContentSet cont | - n = sinkElementInputState(sink, s) and - s.head() = TContentSummaryComponent(cont) and - result = getContentType(cont) + exists(ParameterPosition pos | + parameterReadState(c, state, pos) and + result = TSummaryParameterNode(c, pos) ) ) } - } - - signature module StepsInputSig { - /** Gets the summary node represented by data-flow node `n`, if any. */ - SummaryNode getSummaryNode(Node n); - /** Gets a call that targets summarized callable `sc`. */ - DataFlowCall getACall(SummarizedCallable sc); + pragma[noinline] + private SummaryNode summaryNodeOutputState(SummarizedCallable c, SummaryComponentStack s) { + exists(SummaryNodeState state | + state.isOutputState(c, s) and + result = TSummaryInternalNode(c, state) + ) + } - /** Gets the out node of kind `rk` for `call`, if any. */ - default Node getSourceOutNode(FlowSummaryCallBase call, ReturnKind rk) { none() } + pragma[noinline] + private SummaryNode sourceElementOutputState( + SourceElement source, SourceSinkReportingElement e, SummaryComponentStack s + ) { + result = TSourceOutputNode(source, TSourceOutputState(s), _, e, _, _) + } - /** Gets the enclosing callable of `source`. */ - DataFlowCallable getSourceNodeEnclosingCallable(SourceBase source); + pragma[noinline] + private SummaryNode sinkElementInputState( + SinkElement sink, SourceSinkReportingElement e, SummaryComponentStack s + ) { + result = TSinkInputNode(sink, TSinkInputState(s), e, _, _) + } /** - * Gets a data flow node corresponding to the `s` part of `source`. - * - * `s` is typically `ReturnValue` and the result is the node that - * represents the return value of `source`. + * Holds if a write targets `post`, which is a post-update node for a + * parameter at position `pos` in `c`. */ - Node getSourceNode(SourceBase source, SummaryComponentStack s); + private predicate isParameterPostUpdate( + SummaryNode post, SummarizedCallable c, ParameterPosition pos + ) { + post = summaryNodeOutputState(c, SummaryComponentStack::argument(pos)) + } - /** - * Gets a data flow node corresponding to the `sc` part of `sink`. - * - * `sc` is typically `Argument[i]` and the result is the node that - * represents the `i`th argument of `sink`. - */ - Node getSinkNode(SinkBase sink, SummaryComponent sc); - } + /** Holds if a parameter node at position `pos` is required for `c`. */ + private predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) { + parameterReadState(c, _, pos) + or + // Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context + any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos)) + } - /** Provides a compilation of flow summaries to atomic data-flow steps. */ - module Steps { - /** - * Holds if there is a local step from `pred` to `succ`, which is synthesized - * from a flow summary. - */ - private predicate summaryLocalStepImpl( - SummaryNode pred, SummaryNode succ, boolean preservesValue, string model + private predicate callbackOutput( + SummarizedCallable c, SummaryComponentStack s, SummaryNode receiver, ReturnKind rk ) { - exists( - SummarizedCallable c, SummaryComponentStack inputContents, - SummaryComponentStack outputContents - | - summary(c, inputContents, outputContents, preservesValue, model) and - pred = summaryNodeInputState(pragma[only_bind_into](c), inputContents) and - succ = summaryNodeOutputState(pragma[only_bind_into](c), outputContents) - | - preservesValue = true - or - preservesValue = false and not summary(c, inputContents, outputContents, true, _) - ) + any(SummaryNodeState state).isInputState(c, s) and + s.head() = TReturnSummaryComponent(rk) and + receiver = summaryNodeInputState(c, s.tail()) + } + + private predicate callbackInput( + SummarizedCallable c, SummaryComponentStack s, SummaryNode receiver, ArgumentPosition pos + ) { + any(SummaryNodeState state).isOutputState(c, s) and + s.head() = TParameterSummaryComponent(pos) and + receiver = summaryNodeInputState(c, s.tail()) + } + + /** Holds if a call targeting `receiver` should be synthesized inside `c`. */ + predicate summaryCallbackRange(SummarizedCallable c, SummaryNode receiver) { + callbackOutput(c, _, receiver, _) or - exists(SummarizedCallable c, SummaryComponentStack s | - pred = summaryNodeInputState(c, s.tail()) and - succ = summaryNodeInputState(c, s) and - s.head() = [SummaryComponent::withContent(_), SummaryComponent::withoutContent(_)] and - preservesValue = true and - model = "" - ) + callbackInput(c, _, receiver, _) } - predicate sourceStep(SourceOutputNode nodeFrom, Node nodeTo, string model, boolean local) { - exists(SummaryComponentStack sc, SourceElement source | - nodeFrom.isExit(source, sc, model) and - nodeTo = StepsInput::getSourceNode(source, sc) and - if StepsInput::getSourceNodeEnclosingCallable(source) = getNodeEnclosingCallable(nodeTo) - then local = true - else local = false - ) + /** Holds if summary node `p` is a parameter with position `pos`. */ + predicate summaryParameterNode(SummaryNode p, ParameterPosition pos) { + p = TSummaryParameterNode(_, pos) } - predicate sourceLocalStep(SourceOutputNode nodeFrom, Node nodeTo, string model) { - sourceStep(nodeFrom, nodeTo, model, true) + /** Holds if summary node `out` contains output of kind `rk` from a call targeting `receiver`. */ + predicate summaryOutNode(SummaryNode receiver, SummaryNode out, ReturnKind rk) { + exists(SummarizedCallable callable, SummaryComponentStack s | + callbackOutput(callable, s, receiver, rk) and + out = summaryNodeInputState(callable, s) + ) } - predicate sinkLocalStep(Node nodeFrom, SinkInputNode nodeTo, string model) { - exists(SummaryComponent sc, SinkElement sink | - nodeFrom = StepsInput::getSinkNode(sink, sc) and - nodeTo.isEntry(sink, sc, model) + /** Holds if summary node `arg` is at position `pos` in a call targeting `receiver`. */ + predicate summaryArgumentNode(SummaryNode receiver, SummaryNode arg, ArgumentPosition pos) { + exists(SummarizedCallable callable, SummaryComponentStack s | + callbackInput(callable, s, receiver, pos) and + arg = summaryNodeOutputState(callable, s) ) } - /** Holds if there is a local step between data-flow nodes synthesized from a flow summary. */ - predicate summaryLocalStep(Node pred, SummaryNode succ, boolean preservesValue, string model) { - exists(SummaryNode predSummary | - predSummary = StepsInput::getSummaryNode(pred) and - summaryLocalStepImpl(predSummary, succ, preservesValue, model) + /** Holds if summary node `post` is a post-update node with pre-update node `pre`. */ + predicate summaryPostUpdateNode(SummaryNode post, SummaryNode pre) { + exists(SummarizedCallable c, ParameterPosition pos | + isParameterPostUpdate(post, c, pos) and + pre = TSummaryParameterNode(c, pos) ) or - exists(FlowSummaryCallBase summaryCall, ReturnKind rk, SummarizedCallable sc | - pred = StepsInput::getSourceOutNode(summaryCall, rk) and - summaryCall = getASourceCall(sc) and - summary(sc, SummaryComponentStack::return(rk), _, preservesValue, model) and - succ = TSummaryReturnArgumentNode(summaryCall, rk) + exists(SummarizedCallable callable, SummaryComponentStack s | + callbackInput(callable, s, _, _) and + pre = summaryNodeOutputState(callable, s) and + post = summaryNodeInputState(callable, s) ) } - /** Holds if the value of `succ` is uniquely determined by the value of `pred`. */ - predicate summaryLocalMustFlowStep(SummaryNode pred, SummaryNode succ) { - pred = unique(SummaryNode n1 | summaryLocalStepImpl(n1, succ, true, _)) + /** Holds if summary node `ret` is a return node of kind `rk`. */ + predicate summaryReturnNode(SummaryNode ret, ReturnKind rk) { + exists(SummaryComponentStack s | + ret = summaryNodeOutputState(_, s) and + s = TSingletonSummaryComponentStack(TReturnSummaryComponent(rk)) + ) } + /** Holds if return kind `rk` is a relevant return kind for flow summary modeling. */ + predicate relevantFlowSummaryPosition(ReturnKind rk) { relevantFlowSummaryPosition(_, rk) } + /** - * Holds if there is a read step of content `c` from `pred` to `succ`, which - * is synthesized from a flow summary. + * Holds if flow is allowed to pass from the parameter at position `pos` of `c`, + * to a return node, and back out to the parameter. */ - predicate summaryReadStep(SummaryNode pred, ContentSet c, SummaryNode succ) { - exists(SummarizedCallable sc, SummaryComponentStack s | - pred = summaryNodeInputState(sc, s.tail()) and - succ = summaryNodeInputState(sc, s) and - SummaryComponent::content(c) = s.head() - ) - or - exists(SinkElement sink, SummaryComponentStack s | - pred = sinkElementInputState(sink, s.tail()) and - succ = sinkElementInputState(sink, s) and - SummaryComponent::content(c) = s.head() + predicate summaryAllowParameterReturnInSelf(SummarizedCallable c, ParameterPosition ppos) { + exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents | + summary(c, inputContents, outputContents, _, _) and + inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and + outputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) ) } /** - * Holds if there is a store step of content `c` from `pred` to `succ`, which - * is synthesized from a flow summary. + * Holds if `barrier` is a relevant barrier element with output specification `outSpec`. */ - predicate summaryStoreStep(SummaryNode pred, ContentSet c, SummaryNode succ) { - exists(SummarizedCallable sc, SummaryComponentStack s | - pred = summaryNodeOutputState(sc, s) and - succ = summaryNodeOutputState(sc, s.tail()) and - SummaryComponent::content(c) = s.head() - ) - or - exists(SourceElement source, SummaryComponentStack s | - pred = sourceElementOutputState(source, s) and - succ = sourceElementOutputState(source, s.tail()) and - SummaryComponent::content(c) = s.head() + predicate barrierSpec( + BarrierElement barrier, SummaryComponentStack outSpec, string kind, string model + ) { + exists(string output | + isRelevantBarrier(barrier, output, kind, _, model) and + External::interpretSpec(output, outSpec) ) } /** - * Holds if there is a jump step from `pred` to `succ`, which is synthesized - * from a flow summary. + * Holds if `barrierGuard` is a relevant barrier guard element with input specification `inSpec`. */ - predicate summaryJumpStep(SummaryNode pred, SummaryNode succ) { - exists(SummaryComponentStack s | - s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and - pred = summaryNodeOutputState(_, s) and - succ = summaryNodeInputState(_, s) + predicate barrierGuardSpec( + BarrierGuardElement barrierGuard, SummaryComponentStack inSpec, string acceptingValue, + string kind, string model + ) { + exists(string input | + isRelevantBarrierGuard(barrierGuard, input, acceptingValue, kind, _, model) and + External::interpretSpec(input, inSpec) ) } - predicate sourceJumpStep(SourceOutputNode nodeFrom, Node nodeTo) { - sourceStep(nodeFrom, nodeTo, _, false) - } + signature module TypesInputSig { + /** Gets the type of content `c`. */ + DataFlowType getContentType(ContentSet c); - /** - * Holds if values stored inside content `c` are cleared at `n`. `n` is a - * synthesized summary node, so in order for values to be cleared at calls - * to the relevant method, it is important that flow does not pass over - * the argument, either via use-use flow or def-use flow. - * - * Example: - * - * ``` - * a.b = taint; - * a.clearB(); // assume we have a flow summary for `clearB` that clears `b` on the qualifier - * sink(a.b); - * ``` - * - * In the above, flow should not pass from `a` on the first line (or the second - * line) to `a` on the third line. Instead, there will be synthesized flow from - * `a` on line 2 to the post-update node for `a` on that line (via an intermediate - * node where field `b` is cleared). - */ - predicate summaryClearsContent(SummaryNode n, ContentSet c) { - exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack | - n = TSummaryInternalNode(sc, state) and - state.isInputState(sc, stack) and - stack.head() = SummaryComponent::withoutContent(c) - ) - } + /** Gets the type of the parameter at the given position. */ + bindingset[c, pos] + DataFlowType getParameterType(SummarizedCallable c, ParameterPosition pos); - /** - * Holds if the value that is being tracked is expected to be stored inside - * content `c` at `n`. - */ - predicate summaryExpectsContent(SummaryNode n, ContentSet c) { - exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack | - n = TSummaryInternalNode(sc, state) and - state.isInputState(sc, stack) and - stack.head() = SummaryComponent::withContent(c) - ) - } + /** Gets the return type of kind `rk` for callable `c`. */ + bindingset[c, rk] + DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk); - pragma[noinline] - private predicate viableParam( - DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, SummaryParamNode p - ) { - p = TSummaryParameterNode(sc, ppos) and - call = StepsInput::getACall(sc) - } + /** + * Gets the type of the `i`th parameter in a synthesized call that targets a + * callback of type `t`. + */ + bindingset[t, pos] + DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos); - pragma[nomagic] - private SummaryParamNode summaryArgParam(DataFlowCall call, ArgNode arg, SummarizedCallable sc) { - exists(ParameterPosition ppos | - argumentPositionMatch(call, arg, ppos) and - viableParam(call, sc, ppos, result) - ) - } + /** + * Gets the return type of kind `rk` in a synthesized call that targets a + * callback of type `t`. + */ + bindingset[t, rk] + DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk); - /** - * Holds if `p` can reach `n` in a summarized callable, using only value-preserving - * local steps. `clearsOrExpects` records whether any node on the path from `p` to - * `n` either clears or expects contents. - */ - private predicate paramReachesLocal(SummaryParamNode p, SummaryNode n, boolean clearsOrExpects) { - viableParam(_, _, _, p) and - n = p and - clearsOrExpects = false - or - exists(SummaryNode mid, boolean clearsOrExpectsMid | - paramReachesLocal(p, mid, clearsOrExpectsMid) and - summaryLocalStepImpl(mid, n, true, _) and - if - summaryClearsContent(n, _) or - summaryExpectsContent(n, _) - then clearsOrExpects = true - else clearsOrExpects = clearsOrExpectsMid - ) + DataFlowType getSyntheticGlobalType(SyntheticGlobal sg); + + DataFlowType getSourceType(SourceBase source, SummaryComponentStack sc); + + DataFlowType getSinkType(SinkBase sink, SummaryComponent sc); } /** - * Holds if use-use flow starting from `arg` should be prohibited. + * Provides the predicate `summaryNodeType` for associating types with summary nodes. * - * This is the case when `arg` is the argument of a call that targets a - * flow summary where the corresponding parameter either clears contents - * or expects contents. + * Only relevant for typed languages. */ - pragma[nomagic] - predicate prohibitsUseUseFlow(ArgNode arg, SummarizedCallable sc) { - exists(SummaryParamNode p, ParameterPosition ppos, SummaryNode ret | - paramReachesLocal(p, ret, true) and - p = summaryArgParam(_, arg, sc) and - p = TSummaryParameterNode(_, pragma[only_bind_into](ppos)) and - isParameterPostUpdate(ret, _, pragma[only_bind_into](ppos)) - ) - } + module Types { + private import TypesInput - pragma[nomagic] - private predicate summaryReturnNodeExt(SummaryNode ret, ReturnKindExt rk) { - summaryReturnNode(ret, rk.(ValueReturnKind).getKind()) - or - exists(SummaryParamNode p, SummaryNode pre, ParameterPosition pos | - paramReachesLocal(p, pre, _) and - summaryPostUpdateNode(ret, pre) and - p = TSummaryParameterNode(_, pos) and - rk.(ParamUpdateReturnKind).getPosition() = pos - ) + /** + * Gets the type of synthesized summary node `n`. + * + * The type is computed based on the language-specific predicates + * `getContentType()`, `getReturnType()`, `getCallbackParameterType()`, and + * `getCallbackReturnType()`. + */ + DataFlowType summaryNodeType(SummaryNode n) { + exists(SummaryNode pre | + summaryPostUpdateNode(n, pre) and + result = summaryNodeType(pre) + ) + or + exists(SummarizedCallable c, SummaryComponentStack s, SummaryComponent head | + head = s.head() + | + n = summaryNodeInputState(c, s) and + ( + exists(ContentSet cont | result = getContentType(cont) | + head = TContentSummaryComponent(cont) or + head = TWithContentSummaryComponent(cont) + ) + or + head = TWithoutContentSummaryComponent(_) and + result = summaryNodeType(summaryNodeInputState(c, s.tail())) + or + exists(ReturnKind rk | + head = TReturnSummaryComponent(rk) and + result = + getCallbackReturnType(summaryNodeType(summaryNodeInputState(pragma[only_bind_out](c), + s.tail())), rk) + ) + or + exists(SyntheticGlobal sg | + head = TSyntheticGlobalSummaryComponent(sg) and + result = getSyntheticGlobalType(sg) + ) + or + exists(ParameterPosition pos | + head = TArgumentSummaryComponent(pos) and + result = getParameterType(c, pos) + ) + ) + or + n = summaryNodeOutputState(c, s) and + ( + exists(ContentSet cont | + head = TContentSummaryComponent(cont) and result = getContentType(cont) + ) + or + s.length() = 1 and + exists(ReturnKind rk | + head = TReturnSummaryComponent(rk) and + result = getReturnType(c, rk) + ) + or + exists(ArgumentPosition pos | head = TParameterSummaryComponent(pos) | + result = + getCallbackParameterType(summaryNodeType(summaryNodeInputState(pragma[only_bind_out](c), + s.tail())), pos) + ) + or + exists(SyntheticGlobal sg | + head = TSyntheticGlobalSummaryComponent(sg) and + result = getSyntheticGlobalType(sg) + ) + ) + ) + or + exists(SourceElement source | + exists(SummaryComponentStack s | + n.(SourceOutputNode).isExit(source, s, _, _) and + result = getSourceType(source, s) + ) + or + exists(SummaryComponentStack s, ContentSet cont | + n = sourceElementOutputState(source, _, s) and + s.head() = TContentSummaryComponent(cont) and + result = getContentType(cont) + ) + ) + or + exists(SinkElement sink | + exists(SummaryComponent sc | + n.(SinkInputNode).isEntry(sink, sc, _, _) and + result = getSinkType(sink, sc) + ) + or + exists(SummaryComponentStack s, ContentSet cont | + n = sinkElementInputState(sink, _, s) and + s.head() = TContentSummaryComponent(cont) and + result = getContentType(cont) + ) + ) + } } - bindingset[ret] - private SummaryParamNode summaryArgParamRetOut( - ArgNode arg, SummaryNode ret, OutNodeExt out, SummarizedCallable sc - ) { - exists(DataFlowCall call, ReturnKindExt rk | - result = summaryArgParam(call, arg, sc) and - summaryReturnNodeExt(ret, pragma[only_bind_into](rk)) and - out = getAnOutNodeExt(call, pragma[only_bind_into](rk)) - ) - } + signature module StepsInputSig { + /** Gets the summary node represented by data-flow node `n`, if any. */ + SummaryNode getSummaryNode(Node n); - /** - * Holds if `arg` flows to `out` using a simple value-preserving flow - * summary, that is, a flow summary without reads and stores. - * - * NOTE: This step should not be used in global data-flow/taint-tracking, but may - * be useful to include in the exposed local data-flow/taint-tracking relations. - */ - predicate summaryThroughStepValue(ArgNode arg, Node out, SummarizedCallable sc) { - exists(SummaryNode ret | - summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), ret, true, _) - ) - } + /** Gets a call that targets summarized callable `sc`. */ + DataFlowCall getACall(SummarizedCallable sc); - /** - * Holds if `arg` flows to `out` using a simple flow summary involving taint - * step, that is, a flow summary without reads and stores. - * - * NOTE: This step should not be used in global data-flow/taint-tracking, but may - * be useful to include in the exposed local data-flow/taint-tracking relations. - */ - predicate summaryThroughStepTaint(ArgNode arg, Node out, SummarizedCallable sc) { - exists(SummaryNode ret | - summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), ret, false, _) - ) + /** Gets the out node of kind `rk` for `call`, if any. */ + default Node getSourceOutNode(FlowSummaryCallBase call, ReturnKind rk) { none() } } - /** - * Holds if there is a read(+taint) of `c` from `arg` to `out` using a - * flow summary. - * - * NOTE: This step should not be used in global data-flow/taint-tracking, but may - * be useful to include in the exposed local data-flow/taint-tracking relations. - */ - predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) { - exists(SummaryNode mid, SummaryNode ret | - summaryReadStep(summaryArgParamRetOut(arg, ret, out, sc), c, mid) and - summaryLocalStepImpl(mid, ret, _, _) - ) + /** Provides a compilation of flow summaries to atomic data-flow steps. */ + module Steps { + /** + * Holds if there is a local step from `pred` to `succ`, which is synthesized + * from a flow summary. + */ + private predicate summaryLocalStepImpl( + SummaryNode pred, SummaryNode succ, boolean preservesValue, string model + ) { + exists( + SummarizedCallable c, SummaryComponentStack inputContents, + SummaryComponentStack outputContents + | + summary(c, inputContents, outputContents, preservesValue, model) and + pred = summaryNodeInputState(pragma[only_bind_into](c), inputContents) and + succ = summaryNodeOutputState(pragma[only_bind_into](c), outputContents) + | + preservesValue = true + or + preservesValue = false and not summary(c, inputContents, outputContents, true, _) + ) + or + exists(SummarizedCallable c, SummaryComponentStack s | + pred = summaryNodeInputState(c, s.tail()) and + succ = summaryNodeInputState(c, s) and + s.head() = [SummaryComponent::withContent(_), SummaryComponent::withoutContent(_)] and + preservesValue = true and + model = "" + ) + } + + predicate sourceStep(SourceOutputNode nodeFrom, Node nodeTo, string model, boolean local) { + exists(SummaryComponentStack sc, SourceSinkReportingElement e | + nodeFrom.isExit(_, sc, e, model) and + nodeTo = getSourceExitNode(e, sc) and + if e.getEnclosingCallable() = getNodeEnclosingCallable(nodeTo) + then local = true + else local = false + ) + } + + predicate sourceLocalStep(SourceOutputNode nodeFrom, Node nodeTo, string model) { + sourceStep(nodeFrom, nodeTo, model, true) + } + + predicate sinkLocalStep(Node nodeFrom, SinkInputNode nodeTo, string model) { + exists(SummaryComponent sc, SinkElement sink, SourceSinkReportingElement e | + nodeFrom = getSinkEntryNode(e, sc) and + nodeTo.isEntry(sink, sc, e, model) + ) + } + + /** Holds if there is a local step between data-flow nodes synthesized from a flow summary. */ + predicate summaryLocalStep(Node pred, SummaryNode succ, boolean preservesValue, string model) { + exists(SummaryNode predSummary | + predSummary = StepsInput::getSummaryNode(pred) and + summaryLocalStepImpl(predSummary, succ, preservesValue, model) + ) + or + exists(FlowSummaryCallBase summaryCall, ReturnKind rk, SummarizedCallable sc | + pred = StepsInput::getSourceOutNode(summaryCall, rk) and + summaryCall = getASourceCall(sc) and + summary(sc, SummaryComponentStack::return(rk), _, preservesValue, model) and + succ = TSummaryReturnArgumentNode(summaryCall, rk) + ) + } + + /** Holds if the value of `succ` is uniquely determined by the value of `pred`. */ + predicate summaryLocalMustFlowStep(SummaryNode pred, SummaryNode succ) { + pred = unique(SummaryNode n1 | summaryLocalStepImpl(n1, succ, true, _)) + } + + /** + * Holds if there is a read step of content `c` from `pred` to `succ`, which + * is synthesized from a flow summary. + */ + predicate summaryReadStep(SummaryNode pred, ContentSet c, SummaryNode succ) { + exists(SummarizedCallable sc, SummaryComponentStack s | + pred = summaryNodeInputState(sc, s.tail()) and + succ = summaryNodeInputState(sc, s) and + SummaryComponent::content(c) = s.head() + ) + or + exists(SinkElement sink, SourceSinkReportingElement e, SummaryComponentStack s | + pred = sinkElementInputState(sink, e, s.tail()) and + succ = sinkElementInputState(sink, e, s) and + SummaryComponent::content(c) = s.head() + ) + } + + /** + * Holds if there is a store step of content `c` from `pred` to `succ`, which + * is synthesized from a flow summary. + */ + predicate summaryStoreStep(SummaryNode pred, ContentSet c, SummaryNode succ) { + exists(SummarizedCallable sc, SummaryComponentStack s | + pred = summaryNodeOutputState(sc, s) and + succ = summaryNodeOutputState(sc, s.tail()) and + SummaryComponent::content(c) = s.head() + ) + or + exists(SourceElement source, SourceSinkReportingElement e, SummaryComponentStack s | + pred = sourceElementOutputState(source, e, s) and + succ = sourceElementOutputState(source, e, s.tail()) and + SummaryComponent::content(c) = s.head() + ) + } + + /** + * Holds if there is a jump step from `pred` to `succ`, which is synthesized + * from a flow summary. + */ + predicate summaryJumpStep(SummaryNode pred, SummaryNode succ) { + exists(SummaryComponentStack s | + s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and + pred = summaryNodeOutputState(_, s) and + succ = summaryNodeInputState(_, s) + ) + } + + predicate sourceJumpStep(SourceOutputNode nodeFrom, Node nodeTo) { + sourceStep(nodeFrom, nodeTo, _, false) + } + + /** + * Holds if values stored inside content `c` are cleared at `n`. `n` is a + * synthesized summary node, so in order for values to be cleared at calls + * to the relevant method, it is important that flow does not pass over + * the argument, either via use-use flow or def-use flow. + * + * Example: + * + * ``` + * a.b = taint; + * a.clearB(); // assume we have a flow summary for `clearB` that clears `b` on the qualifier + * sink(a.b); + * ``` + * + * In the above, flow should not pass from `a` on the first line (or the second + * line) to `a` on the third line. Instead, there will be synthesized flow from + * `a` on line 2 to the post-update node for `a` on that line (via an intermediate + * node where field `b` is cleared). + */ + predicate summaryClearsContent(SummaryNode n, ContentSet c) { + exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack | + n = TSummaryInternalNode(sc, state) and + state.isInputState(sc, stack) and + stack.head() = SummaryComponent::withoutContent(c) + ) + } + + /** + * Holds if the value that is being tracked is expected to be stored inside + * content `c` at `n`. + */ + predicate summaryExpectsContent(SummaryNode n, ContentSet c) { + exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack | + n = TSummaryInternalNode(sc, state) and + state.isInputState(sc, stack) and + stack.head() = SummaryComponent::withContent(c) + ) + } + + pragma[noinline] + private predicate viableParam( + DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, SummaryParamNode p + ) { + p = TSummaryParameterNode(sc, ppos) and + call = StepsInput::getACall(sc) + } + + pragma[nomagic] + private SummaryParamNode summaryArgParam( + DataFlowCall call, ArgNode arg, SummarizedCallable sc + ) { + exists(ParameterPosition ppos | + argumentPositionMatch(call, arg, ppos) and + viableParam(call, sc, ppos, result) + ) + } + + /** + * Holds if `p` can reach `n` in a summarized callable, using only value-preserving + * local steps. `clearsOrExpects` records whether any node on the path from `p` to + * `n` either clears or expects contents. + */ + private predicate paramReachesLocal( + SummaryParamNode p, SummaryNode n, boolean clearsOrExpects + ) { + viableParam(_, _, _, p) and + n = p and + clearsOrExpects = false + or + exists(SummaryNode mid, boolean clearsOrExpectsMid | + paramReachesLocal(p, mid, clearsOrExpectsMid) and + summaryLocalStepImpl(mid, n, true, _) and + if + summaryClearsContent(n, _) or + summaryExpectsContent(n, _) + then clearsOrExpects = true + else clearsOrExpects = clearsOrExpectsMid + ) + } + + /** + * Holds if use-use flow starting from `arg` should be prohibited. + * + * This is the case when `arg` is the argument of a call that targets a + * flow summary where the corresponding parameter either clears contents + * or expects contents. + */ + pragma[nomagic] + predicate prohibitsUseUseFlow(ArgNode arg, SummarizedCallable sc) { + exists(SummaryParamNode p, ParameterPosition ppos, SummaryNode ret | + paramReachesLocal(p, ret, true) and + p = summaryArgParam(_, arg, sc) and + p = TSummaryParameterNode(_, pragma[only_bind_into](ppos)) and + isParameterPostUpdate(ret, _, pragma[only_bind_into](ppos)) + ) + } + + pragma[nomagic] + private predicate summaryReturnNodeExt(SummaryNode ret, ReturnKindExt rk) { + summaryReturnNode(ret, rk.(ValueReturnKind).getKind()) + or + exists(SummaryParamNode p, SummaryNode pre, ParameterPosition pos | + paramReachesLocal(p, pre, _) and + summaryPostUpdateNode(ret, pre) and + p = TSummaryParameterNode(_, pos) and + rk.(ParamUpdateReturnKind).getPosition() = pos + ) + } + + bindingset[ret] + private SummaryParamNode summaryArgParamRetOut( + ArgNode arg, SummaryNode ret, OutNodeExt out, SummarizedCallable sc + ) { + exists(DataFlowCall call, ReturnKindExt rk | + result = summaryArgParam(call, arg, sc) and + summaryReturnNodeExt(ret, pragma[only_bind_into](rk)) and + out = getAnOutNodeExt(call, pragma[only_bind_into](rk)) + ) + } + + /** + * Holds if `arg` flows to `out` using a simple value-preserving flow + * summary, that is, a flow summary without reads and stores. + * + * NOTE: This step should not be used in global data-flow/taint-tracking, but may + * be useful to include in the exposed local data-flow/taint-tracking relations. + */ + predicate summaryThroughStepValue(ArgNode arg, Node out, SummarizedCallable sc) { + exists(SummaryNode ret | + summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), ret, true, _) + ) + } + + /** + * Holds if `arg` flows to `out` using a simple flow summary involving taint + * step, that is, a flow summary without reads and stores. + * + * NOTE: This step should not be used in global data-flow/taint-tracking, but may + * be useful to include in the exposed local data-flow/taint-tracking relations. + */ + predicate summaryThroughStepTaint(ArgNode arg, Node out, SummarizedCallable sc) { + exists(SummaryNode ret | + summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), ret, false, _) + ) + } + + /** + * Holds if there is a read(+taint) of `c` from `arg` to `out` using a + * flow summary. + * + * NOTE: This step should not be used in global data-flow/taint-tracking, but may + * be useful to include in the exposed local data-flow/taint-tracking relations. + */ + predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) { + exists(SummaryNode mid, SummaryNode ret | + summaryReadStep(summaryArgParamRetOut(arg, ret, out, sc), c, mid) and + summaryLocalStepImpl(mid, ret, _, _) + ) + } + + /** + * Holds if there is a (taint+)store of `arg` into content `c` of `out` using a + * flow summary. + * + * NOTE: This step should not be used in global data-flow/taint-tracking, but may + * be useful to include in the exposed local data-flow/taint-tracking relations. + */ + predicate summarySetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) { + exists(SummaryNode mid, SummaryNode ret | + summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), mid, _, _) and + summaryStoreStep(mid, c, ret) + ) + } } /** - * Holds if there is a (taint+)store of `arg` into content `c` of `out` using a - * flow summary. + * Provides query predicates for rendering the generated data flow graph for + * a summarized callable. * - * NOTE: This step should not be used in global data-flow/taint-tracking, but may - * be useful to include in the exposed local data-flow/taint-tracking relations. + * Import this module into a `.ql` file of `@kind graph` to render the graph. + * The graph is restricted to callables from `RelevantSummarizedCallable`. */ - predicate summarySetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) { - exists(SummaryNode mid, SummaryNode ret | - summaryLocalStepImpl(summaryArgParamRetOut(arg, ret, out, sc), mid, _, _) and - summaryStoreStep(mid, c, ret) - ) + module RenderSummarizedCallable { + private module PrivateSteps = Steps; + + /** A summarized callable to include in the graph. */ + abstract class RelevantSummarizedCallable instanceof SummarizedCallable { + string toString() { result = super.toString() } + } + + private newtype TNodeOrCall = + MkNode(SummaryNode n) { + exists(RelevantSummarizedCallable c | + n = TSummaryInternalNode(c, _) + or + n = TSummaryParameterNode(c, _) + ) + } or + MkCall(SummaryNode receiver) { + receiver.getSummarizedCallable() instanceof RelevantSummarizedCallable and + ( + callbackInput(_, _, receiver, _) or + callbackOutput(_, _, receiver, _) + ) + } + + private class NodeOrCall extends TNodeOrCall { + SummaryNode asNode() { this = MkNode(result) } + + SummaryNode asCallReceiver() { this = MkCall(result) } + + string toString() { + result = this.asNode().toString() + or + result = this.asCallReceiver().toString() + } + + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + filepath = "" and + startline = 0 and + startcolumn = 0 and + endline = 0 and + endcolumn = 0 + } + } + + query predicate nodes(NodeOrCall n, string key, string val) { + key = "semmle.label" and val = n.toString() + } + + private Node getNode(SummaryNode sn) { sn = StepsInput::getSummaryNode(result) } + + private predicate edgesComponent(NodeOrCall a, NodeOrCall b, string value) { + exists(boolean preservesValue | + PrivateSteps::summaryLocalStep(getNode(a.asNode()), b.asNode(), preservesValue, _) and + if preservesValue = true then value = "value" else value = "taint" + ) + or + exists(ContentSet c | + PrivateSteps::summaryReadStep(a.asNode(), c, b.asNode()) and + value = "read (" + c + ")" + or + PrivateSteps::summaryStoreStep(a.asNode(), c, b.asNode()) and + value = "store (" + c + ")" + or + PrivateSteps::summaryClearsContent(a.asNode(), c) and + b = a and + value = "clear (" + c + ")" + or + PrivateSteps::summaryExpectsContent(a.asNode(), c) and + b = a and + value = "expect (" + c + ")" + ) + or + summaryPostUpdateNode(b.asNode(), a.asNode()) and + value = "post-update" + or + b.asCallReceiver() = a.asNode() and + value = "receiver" + or + exists(ArgumentPosition pos | + summaryArgumentNode(b.asCallReceiver(), a.asNode(), pos) and + value = "argument (" + pos + ")" + ) + } + + query predicate edges(NodeOrCall a, NodeOrCall b, string key, string value) { + key = "semmle.label" and + value = strictconcat(string s | edgesComponent(a, b, s) | s, " / ") + } } } @@ -2786,111 +2995,5 @@ module Make< ) } } - - /** - * Provides query predicates for rendering the generated data flow graph for - * a summarized callable. - * - * Import this module into a `.ql` file of `@kind graph` to render the graph. - * The graph is restricted to callables from `RelevantSummarizedCallable`. - */ - module RenderSummarizedCallable { - private module PrivateSteps = Private::Steps; - - /** A summarized callable to include in the graph. */ - abstract class RelevantSummarizedCallable instanceof SummarizedCallable { - string toString() { result = super.toString() } - } - - private newtype TNodeOrCall = - MkNode(SummaryNode n) { - exists(RelevantSummarizedCallable c | - n = TSummaryInternalNode(c, _) - or - n = TSummaryParameterNode(c, _) - ) - } or - MkCall(SummaryNode receiver) { - receiver.getSummarizedCallable() instanceof RelevantSummarizedCallable and - ( - callbackInput(_, _, receiver, _) or - callbackOutput(_, _, receiver, _) - ) - } - - private class NodeOrCall extends TNodeOrCall { - SummaryNode asNode() { this = MkNode(result) } - - SummaryNode asCallReceiver() { this = MkCall(result) } - - string toString() { - result = this.asNode().toString() - or - result = this.asCallReceiver().toString() - } - - /** - * Holds if this element is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). - */ - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - filepath = "" and - startline = 0 and - startcolumn = 0 and - endline = 0 and - endcolumn = 0 - } - } - - query predicate nodes(NodeOrCall n, string key, string val) { - key = "semmle.label" and val = n.toString() - } - - private Node getNode(SummaryNode sn) { sn = StepsInput::getSummaryNode(result) } - - private predicate edgesComponent(NodeOrCall a, NodeOrCall b, string value) { - exists(boolean preservesValue | - PrivateSteps::summaryLocalStep(getNode(a.asNode()), b.asNode(), preservesValue, _) and - if preservesValue = true then value = "value" else value = "taint" - ) - or - exists(ContentSet c | - PrivateSteps::summaryReadStep(a.asNode(), c, b.asNode()) and - value = "read (" + c + ")" - or - PrivateSteps::summaryStoreStep(a.asNode(), c, b.asNode()) and - value = "store (" + c + ")" - or - PrivateSteps::summaryClearsContent(a.asNode(), c) and - b = a and - value = "clear (" + c + ")" - or - PrivateSteps::summaryExpectsContent(a.asNode(), c) and - b = a and - value = "expect (" + c + ")" - ) - or - summaryPostUpdateNode(b.asNode(), a.asNode()) and - value = "post-update" - or - b.asCallReceiver() = a.asNode() and - value = "receiver" - or - exists(ArgumentPosition pos | - summaryArgumentNode(b.asCallReceiver(), a.asNode(), pos) and - value = "argument (" + pos + ")" - ) - } - - query predicate edges(NodeOrCall a, NodeOrCall b, string key, string value) { - key = "semmle.label" and - value = strictconcat(string s | edgesComponent(a, b, s) | s, " / ") - } - } } }