mirror of
https://github.com/github/codeql.git
synced 2025-12-22 11:46:32 +01:00
C++: Port implementation to CPP.
This commit is contained in:
@@ -13,8 +13,8 @@
|
||||
*
|
||||
* The interpretation of a row is similar to API-graphs with a left-to-right
|
||||
* reading.
|
||||
* 1. The `namespace` column selects a package.
|
||||
* 2. The `type` column selects a type within that package.
|
||||
* 1. The `namespace` column selects a namespace.
|
||||
* 2. The `type` column selects a type within that namespace.
|
||||
* 3. The `subtypes` is a boolean that indicates whether to jump to an
|
||||
* arbitrary subtype of that type. Set this to `false` if leaving the `type`
|
||||
* blank (for example, a free function).
|
||||
@@ -65,16 +65,14 @@
|
||||
* globally applicable value-preserving step.
|
||||
*/
|
||||
|
||||
import swift
|
||||
private import internal.DataFlowDispatch
|
||||
private import internal.DataFlowPrivate
|
||||
private import internal.DataFlowPublic
|
||||
import cpp
|
||||
private import new.DataFlow
|
||||
private import internal.FlowSummaryImpl
|
||||
private import internal.FlowSummaryImpl::Public
|
||||
private import internal.FlowSummaryImpl::Private
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import FlowSummary as FlowSummary
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A unit class for adding additional source model rows.
|
||||
@@ -354,13 +352,13 @@ private predicate elementSpec(
|
||||
private string paramsStringPart(Function c, int i) {
|
||||
i = -1 and result = "(" and exists(c)
|
||||
or
|
||||
exists(int n, string p | c.getParam(n).getType().toString() = p |
|
||||
exists(int n, string p | c.getParameter(n).getType().toString() = p |
|
||||
i = 2 * n and result = p
|
||||
or
|
||||
i = 2 * n - 1 and result = "," and n != 0
|
||||
)
|
||||
or
|
||||
i = 2 * c.getNumberOfParams() and result = ")"
|
||||
i = 2 * c.getNumberOfParameters() and result = ")"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,42 +399,42 @@ private Element interpretElement0(
|
||||
type = "" and
|
||||
matchesSignature(func, signature) and
|
||||
subtypes = false and
|
||||
not result instanceof Method and
|
||||
not exists(func.getDeclaringType()) and
|
||||
result = func
|
||||
)
|
||||
or
|
||||
// Member functions
|
||||
exists(NominalTypeDecl namedTypeDecl, Decl declWithMethod, Method method |
|
||||
exists(Class namedClass, Class classWithMethod, Function method |
|
||||
method.getName() = name and
|
||||
method = declWithMethod.getAMember() and
|
||||
namedTypeDecl.getFullName() = type and
|
||||
method = classWithMethod.getAMember() and
|
||||
namedClass.getName() = type and
|
||||
matchesSignature(method, signature) and
|
||||
result = method
|
||||
|
|
||||
// member declared in the named type or a subtype of it (or an extension of any)
|
||||
// member declared in the named type or a subtype of it
|
||||
subtypes = true and
|
||||
declWithMethod.asNominalTypeDecl() = namedTypeDecl.getADerivedTypeDecl*()
|
||||
classWithMethod = namedClass.getADerivedClass*()
|
||||
or
|
||||
// member declared directly in the named type (or an extension of it)
|
||||
// member declared directly in the named type
|
||||
subtypes = false and
|
||||
declWithMethod.asNominalTypeDecl() = namedTypeDecl
|
||||
classWithMethod = namedClass
|
||||
)
|
||||
or
|
||||
// Fields
|
||||
// Member variables
|
||||
signature = "" and
|
||||
exists(NominalTypeDecl namedTypeDecl, Decl declWithField, FieldDecl field |
|
||||
field.getName() = name and
|
||||
field = declWithField.getAMember() and
|
||||
namedTypeDecl.getFullName() = type and
|
||||
result = field
|
||||
exists(Class namedClass, Class classWithMember, MemberVariable member |
|
||||
member.getName() = name and
|
||||
member = classWithMember.getAMember() and
|
||||
namedClass.getName() = type and
|
||||
result = member
|
||||
|
|
||||
// field declared in the named type or a subtype of it (or an extension of any)
|
||||
subtypes = true and
|
||||
declWithField.asNominalTypeDecl() = namedTypeDecl.getADerivedTypeDecl*()
|
||||
classWithMember = namedClass.getADerivedClass*()
|
||||
or
|
||||
// field declared directly in the named type (or an extension of it)
|
||||
subtypes = false and
|
||||
declWithField.asNominalTypeDecl() = namedTypeDecl
|
||||
classWithMember = namedClass
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -451,44 +449,6 @@ Element interpretElement(
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate parseField(AccessPathToken c, Content::FieldContent f) {
|
||||
exists(string fieldRegex, string name |
|
||||
c.getName() = "Field" and
|
||||
fieldRegex = "^([^.]+)$" and
|
||||
name = c.getAnArgument().regexpCapture(fieldRegex, 1) and
|
||||
f.getField().getName() = name
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate parseTuple(AccessPathToken c, Content::TupleContent t) {
|
||||
c.getName() = "TupleElement" and
|
||||
t.getIndex() = c.getAnArgument().toInt()
|
||||
}
|
||||
|
||||
deprecated private predicate parseEnum(AccessPathToken c, Content::EnumContent e) {
|
||||
c.getName() = "EnumElement" and
|
||||
c.getAnArgument() = e.getSignature()
|
||||
or
|
||||
c.getName() = "OptionalSome" and
|
||||
e.getSignature() = "some:0"
|
||||
}
|
||||
|
||||
/** Holds if the specification component parses as a `Content`. */
|
||||
deprecated predicate parseContent(AccessPathToken component, Content content) {
|
||||
parseField(component, content)
|
||||
or
|
||||
parseTuple(component, content)
|
||||
or
|
||||
parseEnum(component, content)
|
||||
or
|
||||
// map legacy "ArrayElement" specification components to `CollectionContent`
|
||||
component.getName() = "ArrayElement" and
|
||||
content instanceof Content::CollectionContent
|
||||
or
|
||||
component.getName() = "CollectionElement" and
|
||||
content instanceof Content::CollectionContent
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
@@ -496,7 +456,7 @@ private module Cached {
|
||||
* model.
|
||||
*/
|
||||
cached
|
||||
predicate sourceNode(Node node, string kind) {
|
||||
predicate sourceNode(DataFlow::Node node, string kind) {
|
||||
exists(SourceSinkInterpretationInput::InterpretNode n |
|
||||
isSourceNode(n, kind) and n.asNode() = node
|
||||
)
|
||||
@@ -507,7 +467,7 @@ private module Cached {
|
||||
* model.
|
||||
*/
|
||||
cached
|
||||
predicate sinkNode(Node node, string kind) {
|
||||
predicate sinkNode(DataFlow::Node node, string kind) {
|
||||
exists(SourceSinkInterpretationInput::InterpretNode n |
|
||||
isSinkNode(n, kind) and n.asNode() = node
|
||||
)
|
||||
@@ -567,7 +527,7 @@ private class NeutralCallableAdapter extends NeutralCallable {
|
||||
string provenance_;
|
||||
|
||||
NeutralCallableAdapter() {
|
||||
// Neutral models have not been implemented for Swift.
|
||||
// Neutral models have not been implemented for CPP.
|
||||
none() and
|
||||
exists(this) and
|
||||
exists(kind) and
|
||||
|
||||
@@ -2,21 +2,20 @@
|
||||
* Provides classes and predicates for defining flow summaries.
|
||||
*/
|
||||
|
||||
private import swift
|
||||
private import cpp
|
||||
private import codeql.dataflow.internal.FlowSummaryImpl
|
||||
private import codeql.dataflow.internal.AccessPathSyntax as AccessPath
|
||||
private import DataFlowImplSpecific as DataFlowImplSpecific
|
||||
private import DataFlowImplSpecific::Private
|
||||
private import DataFlowImplSpecific::Public
|
||||
private import DataFlowImplCommon
|
||||
private import codeql.swift.dataflow.ExternalFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific as DataFlowImplSpecific
|
||||
private import semmle.code.cpp.dataflow.ExternalFlow
|
||||
|
||||
module Input implements InputSig<DataFlowImplSpecific::SwiftDataFlow> {
|
||||
module Input implements InputSig<DataFlowImplSpecific::CppDataFlow> {
|
||||
class SummarizedCallableBase = Function;
|
||||
|
||||
ArgumentPosition callbackSelfParameterPosition() { result instanceof ThisArgumentPosition }
|
||||
ArgumentPosition callbackSelfParameterPosition() { result = TDirectPosition(-1) }
|
||||
|
||||
ReturnKind getStandardReturnValueKind() { result instanceof NormalReturnKind }
|
||||
ReturnKind getStandardReturnValueKind() { result.(NormalReturnKind).getIndirectionIndex() = 0 }
|
||||
|
||||
string encodeParameterPosition(ParameterPosition pos) { result = pos.toString() }
|
||||
|
||||
@@ -29,37 +28,40 @@ module Input implements InputSig<DataFlowImplSpecific::SwiftDataFlow> {
|
||||
}
|
||||
|
||||
string encodeContent(ContentSet cs, string arg) {
|
||||
exists(Content::FieldContent c |
|
||||
exists(FieldContent c |
|
||||
cs.isSingleton(c) and
|
||||
result = "Field" and
|
||||
arg = c.getField().getName()
|
||||
)
|
||||
or
|
||||
exists(Content::TupleContent c |
|
||||
cs.isSingleton(c) and
|
||||
result = "TupleElement" and
|
||||
arg = c.getIndex().toString()
|
||||
)
|
||||
or
|
||||
exists(Content::EnumContent c, string sig |
|
||||
cs.isSingleton(c) and
|
||||
sig = c.getSignature()
|
||||
|
|
||||
if sig = "some:0"
|
||||
then
|
||||
result = "OptionalSome" and
|
||||
arg = ""
|
||||
else (
|
||||
result = "EnumElement" and
|
||||
arg = sig
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Content::CollectionContent c |
|
||||
cs.isSingleton(c) and
|
||||
result = "CollectionElement" and
|
||||
arg = ""
|
||||
)
|
||||
/*
|
||||
* or
|
||||
* exists(Content::TupleContent c |
|
||||
* cs.isSingleton(c) and
|
||||
* result = "TupleElement" and
|
||||
* arg = c.getIndex().toString()
|
||||
* )
|
||||
* or
|
||||
* exists(Content::EnumContent c, string sig |
|
||||
* cs.isSingleton(c) and
|
||||
* sig = c.getSignature()
|
||||
* |
|
||||
* if sig = "some:0"
|
||||
* then
|
||||
* result = "OptionalSome" and
|
||||
* arg = ""
|
||||
* else (
|
||||
* result = "EnumElement" and
|
||||
* arg = sig
|
||||
* )
|
||||
* )
|
||||
* or
|
||||
* exists(Content::CollectionContent c |
|
||||
* cs.isSingleton(c) and
|
||||
* result = "CollectionElement" and
|
||||
* arg = ""
|
||||
* )
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
string encodeWithoutContent(ContentSet c, string arg) {
|
||||
@@ -68,24 +70,12 @@ module Input implements InputSig<DataFlowImplSpecific::SwiftDataFlow> {
|
||||
|
||||
string encodeWithContent(ContentSet c, string arg) { result = "WithContent" + c and arg = "" }
|
||||
|
||||
bindingset[token]
|
||||
ContentSet decodeUnknownContent(AccessPath::AccessPathTokenBase token) {
|
||||
// map legacy "ArrayElement" specification components to `CollectionContent`
|
||||
token.getName() = "ArrayElement" and
|
||||
result.isSingleton(any(Content::CollectionContent c))
|
||||
or
|
||||
token.getName() = "CollectionElement" and
|
||||
result.isSingleton(any(Content::CollectionContent c))
|
||||
}
|
||||
|
||||
bindingset[token]
|
||||
ParameterPosition decodeUnknownParameterPosition(AccessPath::AccessPathTokenBase token) {
|
||||
// needed to support `Argument[x..y]` ranges and `Argument[-1]`
|
||||
token.getName() = "Argument" and
|
||||
exists(int pos | pos = AccessPath::parseInt(token.getAnArgument()) |
|
||||
result.(PositionalParameterPosition).getIndex() = pos
|
||||
or
|
||||
pos = -1 and result instanceof ThisParameterPosition
|
||||
result = TDirectPosition(pos)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -94,24 +84,21 @@ module Input implements InputSig<DataFlowImplSpecific::SwiftDataFlow> {
|
||||
// needed to support `Parameter[x..y]` ranges and `Parameter[-1]`
|
||||
token.getName() = "Parameter" and
|
||||
exists(int pos | pos = AccessPath::parseInt(token.getAnArgument()) |
|
||||
result.(PositionalArgumentPosition).getIndex() = pos
|
||||
or
|
||||
pos = -1 and
|
||||
result instanceof ThisArgumentPosition
|
||||
result = TDirectPosition(pos)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private import Make<DataFlowImplSpecific::SwiftDataFlow, Input> as Impl
|
||||
/*private*/ import Make<DataFlowImplSpecific::CppDataFlow, Input> as Impl
|
||||
|
||||
private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
DataFlowCall getACall(Public::SummarizedCallable sc) { result.asCall().getStaticTarget() = sc }
|
||||
DataFlowCall getACall(Public::SummarizedCallable sc) { result.getStaticCallTarget() = sc }
|
||||
}
|
||||
|
||||
module SourceSinkInterpretationInput implements
|
||||
Impl::Private::External::SourceSinkInterpretationInputSig<Location>
|
||||
{
|
||||
class Element = AstNode;
|
||||
class Element = Element;
|
||||
|
||||
class SourceOrSinkElement = Element;
|
||||
|
||||
@@ -158,10 +145,12 @@ module SourceSinkInterpretationInput implements
|
||||
DataFlowCall asCall() { this = TDataFlowCall_(result) }
|
||||
|
||||
/** Gets the callable that this node corresponds to, if any. */
|
||||
DataFlowCallable asCallable() { result.getUnderlyingCallable() = this.asElement() }
|
||||
DataFlowCallable asCallable() { result.(Function) = this.asElement() }
|
||||
|
||||
/** Gets the target of this call, if any. */
|
||||
Element getCallTarget() { result = this.asCall().asCall().getStaticTarget() }
|
||||
Element getCallTarget() {
|
||||
result = this.asNode().asExpr().(Call).getTarget()
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this node. */
|
||||
string toString() {
|
||||
@@ -186,31 +175,31 @@ module SourceSinkInterpretationInput implements
|
||||
bindingset[c]
|
||||
predicate interpretOutput(string c, InterpretNode mid, InterpretNode node) {
|
||||
// Allow fields to be picked as output nodes.
|
||||
exists(Node n, AstNode ast |
|
||||
exists(Node n, Element ast |
|
||||
n = node.asNode() and
|
||||
ast = mid.asElement()
|
||||
|
|
||||
c = "" and
|
||||
n.asExpr().(MemberRefExpr).getMember() = ast
|
||||
n.asExpr().(VariableAccess).getTarget() = ast
|
||||
)
|
||||
}
|
||||
|
||||
/** Provides additional source specification logic. */
|
||||
bindingset[c]
|
||||
predicate interpretInput(string c, InterpretNode mid, InterpretNode node) {
|
||||
exists(Node n, AstNode ast, MemberRefExpr e |
|
||||
exists(Node n, Element ast, VariableAccess e |
|
||||
n = node.asNode() and
|
||||
ast = mid.asElement() and
|
||||
e.getMember() = ast
|
||||
e.getTarget() = ast
|
||||
|
|
||||
// Allow fields to be picked as input nodes.
|
||||
c = "" and
|
||||
e.getBase() = n.asExpr()
|
||||
e.getQualifier() = n.asExpr()
|
||||
or
|
||||
// Allow post update nodes to be picked as input nodes when the `input` column
|
||||
// of the row is `PostUpdate`.
|
||||
c = "PostUpdate" and
|
||||
e.getBase() = n.(PostUpdateNode).getPreUpdateNode().asExpr()
|
||||
e.getQualifier() = n.(PostUpdateNode).getPreUpdateNode().asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,11 +458,13 @@ class ReturnKind extends TReturnKind {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
private class NormalReturnKind extends ReturnKind, TNormalReturnKind {
|
||||
class NormalReturnKind extends ReturnKind, TNormalReturnKind {
|
||||
int index;
|
||||
|
||||
NormalReturnKind() { this = TNormalReturnKind(index) }
|
||||
|
||||
int getIndirectionIndex() { result = index }
|
||||
|
||||
override string toString() { result = "indirect return" }
|
||||
}
|
||||
|
||||
|
||||
@@ -2330,6 +2330,12 @@ class UnionContent extends Content, TUnionContent {
|
||||
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
|
||||
*/
|
||||
class ContentSet instanceof Content {
|
||||
/**
|
||||
* Holds if this content set is the singleton `{c}`. At present, this is
|
||||
* the only kind of content set supported in C/C++.
|
||||
*/
|
||||
predicate isSingleton(Content c) { this = c }
|
||||
|
||||
/** Gets a content that may be stored into when storing into this set. */
|
||||
Content getAStoreContent() { result = this }
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import cpp
|
||||
import FunctionInputsAndOutputs
|
||||
import semmle.code.cpp.models.Models
|
||||
import semmle.code.cpp.dataflow.ExternalFlow
|
||||
|
||||
/**
|
||||
* A library function that returns data that may be read from a network connection.
|
||||
|
||||
@@ -20,6 +20,9 @@ abstract class RemoteFlowSource extends FlowSource { }
|
||||
/** A data flow source of local user input. */
|
||||
abstract class LocalFlowSource extends FlowSource { }
|
||||
|
||||
/**
|
||||
* A remote data flow source that is defined through a `RemoteFlowSourceFunction` model.
|
||||
*/
|
||||
private class RemoteModelSource extends RemoteFlowSource {
|
||||
string sourceType;
|
||||
|
||||
@@ -34,6 +37,9 @@ private class RemoteModelSource extends RemoteFlowSource {
|
||||
override string getSourceType() { result = sourceType }
|
||||
}
|
||||
|
||||
/**
|
||||
* A local data flow source that is defined through a `LocalFlowSourceFunction` model.
|
||||
*/
|
||||
private class LocalModelSource extends LocalFlowSource {
|
||||
string sourceType;
|
||||
|
||||
@@ -48,6 +54,9 @@ private class LocalModelSource extends LocalFlowSource {
|
||||
override string getSourceType() { result = sourceType }
|
||||
}
|
||||
|
||||
/**
|
||||
* A local data flow source that the `argv` parameter to `main`.
|
||||
*/
|
||||
private class ArgvSource extends LocalFlowSource {
|
||||
ArgvSource() {
|
||||
exists(Function main, Parameter argv |
|
||||
@@ -60,6 +69,24 @@ private class ArgvSource extends LocalFlowSource {
|
||||
override string getSourceType() { result = "a command-line argument" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A remote data flow source that is defined through 'models as data'.
|
||||
*/
|
||||
private class ExternalRemoteFlowSource extends RemoteFlowSource {
|
||||
ExternalRemoteFlowSource() { sourceNode(this, "remote") }
|
||||
|
||||
override string getSourceType() { result = "external" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A local data flow source that is defined through 'models as data'.
|
||||
*/
|
||||
private class ExternalLocalFlowSource extends LocalFlowSource {
|
||||
ExternalLocalFlowSource() { sourceNode(this, "local") }
|
||||
|
||||
override string getSourceType() { result = "external" }
|
||||
}
|
||||
|
||||
/** A remote data flow sink. */
|
||||
abstract class RemoteFlowSink extends DataFlow::Node {
|
||||
/** Gets a string that describes the type of this flow sink. */
|
||||
|
||||
@@ -1588,7 +1588,8 @@ module Make<DF::InputSig DataFlowLang, InputSig<DataFlowLang> Input> {
|
||||
SourceSinkAccessPath output, int n, InterpretNode ref, InterpretNode node
|
||||
) {
|
||||
sourceElementRef(ref, output, _) and
|
||||
n = 0 and
|
||||
//n = 0 and
|
||||
n = [0,1] and // TODO: fix this, there's no good reason for it.
|
||||
(
|
||||
if output = ""
|
||||
then
|
||||
|
||||
Reference in New Issue
Block a user