mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Merge pull request #492 from owen-mc/promoted-field-data-flow-non-pointer-type
Add control flow nodes for implicit fields reads when reading a promoted field
This commit is contained in:
2
change-notes/2021-03-05-dataflow-promoted-fields.md
Normal file
2
change-notes/2021-03-05-dataflow-promoted-fields.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The data-flow library has been improved to represent reads and writes of promoted fields correctly, which may lead to more alerts.
|
||||
@@ -593,6 +593,33 @@ class SelectorExpr extends @selectorexpr, Expr {
|
||||
override string getAPrimaryQlClass() { result = "SelectorExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A selector expression that refers to a promoted field or a promoted method. These
|
||||
* selectors may implicitly address an embedded struct of their base type - for example,
|
||||
* the selector `x.field` may implicitly address `x.Embedded.field`). Note they may also
|
||||
* explicitly address `field`; being a `PromotedSelector` only indicates the addressed
|
||||
* field or method may be promoted, not that it is promoted in this particular context.
|
||||
*/
|
||||
class PromotedSelector extends SelectorExpr {
|
||||
PromotedSelector() {
|
||||
exists(ValueEntity ve | this.refersTo(ve) |
|
||||
ve instanceof PromotedField or ve instanceof PromotedMethod
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying struct type of this selector's base. Note because this selector
|
||||
* addresses a promoted field, the addressed field may not directly occur in the returned
|
||||
* struct type.
|
||||
*/
|
||||
StructType getSelectedStructType() {
|
||||
exists(Type baseType | baseType = this.getBase().getType().getUnderlyingType() |
|
||||
pragma[only_bind_into](result) =
|
||||
[baseType, baseType.(PointerType).getBaseType().getUnderlyingType()]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An index expression, that is, a base expression followed by an index.
|
||||
*
|
||||
|
||||
@@ -353,6 +353,15 @@ class Field extends Variable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A field that belongs to a struct that may be embedded within another struct.
|
||||
*
|
||||
* When a selector addresses such a field, it is possible it is implicitly addressing a nested struct.
|
||||
*/
|
||||
class PromotedField extends Field {
|
||||
PromotedField() { this = any(StructType t).getFieldOfEmbedded(_, _, _, _) }
|
||||
}
|
||||
|
||||
/** A built-in or declared function. */
|
||||
class Function extends ValueEntity, @functionobject {
|
||||
/** Gets a call to this function. */
|
||||
@@ -530,6 +539,15 @@ class Method extends Function {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method whose receiver may be embedded within a struct.
|
||||
*
|
||||
* When a selector addresses such a method, it is possible it is implicitly addressing a nested struct.
|
||||
*/
|
||||
class PromotedMethod extends Method {
|
||||
PromotedMethod() { this = any(StructType t).getMethodOfEmbedded(_, _, _) }
|
||||
}
|
||||
|
||||
/** A declared function. */
|
||||
class DeclaredFunction extends Function, DeclaredEntity, @declfunctionobject {
|
||||
override FuncDecl getFuncDecl() { result.getNameExpr() = this.getDeclaration() }
|
||||
|
||||
@@ -375,39 +375,59 @@ class StructType extends @structtype, CompositeType {
|
||||
this.hasOwnField(_, name, _, isEmbedded)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is an embedded field at `depth`, with either type `tp` or a pointer to `tp`.
|
||||
*/
|
||||
private predicate hasEmbeddedField(Type tp, int depth) {
|
||||
hasFieldOrMethodCand(_, tp, depth, true, false)
|
||||
or
|
||||
exists(PointerType embeddedPtr |
|
||||
hasFieldOrMethodCand(_, embeddedPtr, depth, true, false) and
|
||||
tp = embeddedPtr.getBaseType()
|
||||
exists(Field f | this.hasFieldCand(_, f, depth, true) |
|
||||
tp = f.getType() or
|
||||
tp = f.getType().(PointerType).getBaseType()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFieldOrMethodCand(
|
||||
string name, Type tp, int depth, boolean isEmbedded, boolean isMethod
|
||||
) {
|
||||
hasOwnField(_, name, tp, isEmbedded) and depth = 0 and isMethod = false
|
||||
or
|
||||
not hasOwnField(_, name, _, _) and
|
||||
exists(Type embedded | hasEmbeddedField(embedded, depth - 1) |
|
||||
embedded.getUnderlyingType().(StructType).hasOwnField(_, name, tp, isEmbedded) and
|
||||
isMethod = false
|
||||
/**
|
||||
* Gets a field of `embeddedParent`, which is then embedded into this struct type.
|
||||
*/
|
||||
Field getFieldOfEmbedded(Field embeddedParent, string name, int depth, boolean isEmbedded) {
|
||||
// embeddedParent is a field of 'this' at depth 'depth - 1'
|
||||
this.hasFieldCand(_, embeddedParent, depth - 1, true) and
|
||||
// embeddedParent's type has the result field
|
||||
exists(StructType embeddedType, Type fieldType |
|
||||
fieldType = embeddedParent.getType().getUnderlyingType() and
|
||||
pragma[only_bind_into](embeddedType) =
|
||||
[fieldType, fieldType.(PointerType).getBaseType().getUnderlyingType()]
|
||||
|
|
||||
result = embeddedType.getOwnField(name, isEmbedded)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a method of `embeddedParent`, which is then embedded into this struct type.
|
||||
*/
|
||||
Method getMethodOfEmbedded(Field embeddedParent, string name, int depth) {
|
||||
// embeddedParent is a field of 'this' at depth 'depth - 1'
|
||||
this.hasFieldCand(_, embeddedParent, depth - 1, true) and
|
||||
result.getName() = name and
|
||||
(
|
||||
result.getReceiverBaseType() = embeddedParent.getType()
|
||||
or
|
||||
exists(MethodDecl md | md.getReceiverType() = embedded |
|
||||
name = md.getName() and
|
||||
tp = md.getType()
|
||||
) and
|
||||
isEmbedded = false and
|
||||
isMethod = true
|
||||
result.getReceiverBaseType() = embeddedParent.getType().(PointerType).getBaseType()
|
||||
or
|
||||
methodhosts(result, embeddedParent.getType())
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFieldOrMethod(string name, Type tp, boolean isMethod) {
|
||||
exists(int mindepth |
|
||||
mindepth = min(int depth | hasFieldOrMethodCand(name, _, depth, _, _)) and
|
||||
hasFieldOrMethodCand(name, tp, mindepth, _, isMethod) and
|
||||
(strictcount(getFieldCand(name, mindepth, _)) = 1 or isMethod = true)
|
||||
private predicate hasFieldCand(string name, Field f, int depth, boolean isEmbedded) {
|
||||
f = this.getOwnField(name, isEmbedded) and depth = 0
|
||||
or
|
||||
not this.hasOwnField(_, name, _, _) and
|
||||
f = this.getFieldOfEmbedded(_, name, depth, isEmbedded)
|
||||
}
|
||||
|
||||
private predicate hasMethodCand(string name, Method m, int depth) {
|
||||
name = m.getName() and
|
||||
exists(Type embedded | this.hasEmbeddedField(embedded, depth - 1) |
|
||||
m.getReceiverType() = embedded
|
||||
)
|
||||
}
|
||||
|
||||
@@ -415,7 +435,12 @@ class StructType extends @structtype, CompositeType {
|
||||
* Holds if this struct contains a field `name` with type `tp`, possibly inside a (nested)
|
||||
* embedded field.
|
||||
*/
|
||||
predicate hasField(string name, Type tp) { hasFieldOrMethod(name, tp, false) }
|
||||
predicate hasField(string name, Type tp) {
|
||||
exists(int mindepth |
|
||||
mindepth = min(int depth | this.hasFieldCand(name, _, depth, _)) and
|
||||
tp = unique(Field f | f = this.getFieldCand(name, mindepth, _)).getType()
|
||||
)
|
||||
}
|
||||
|
||||
private Field getFieldCand(string name, int depth, boolean isEmbedded) {
|
||||
result = this.getOwnField(name, isEmbedded) and depth = 0
|
||||
@@ -425,15 +450,33 @@ class StructType extends @structtype, CompositeType {
|
||||
)
|
||||
}
|
||||
|
||||
override Field getField(string name) {
|
||||
exists(int mindepth |
|
||||
mindepth = min(int depth | exists(getFieldCand(name, depth, _))) and
|
||||
result = getFieldCand(name, mindepth, _) and
|
||||
strictcount(getFieldCand(name, mindepth, _)) = 1
|
||||
)
|
||||
override Field getField(string name) { result = getFieldAtDepth(name, _) }
|
||||
|
||||
/**
|
||||
* Gets the field `f` with depth `depth` of this type.
|
||||
*
|
||||
* This includes fields promoted from an embedded field. It is not possible
|
||||
* to access a field that is shadowed by a promoted field with this function.
|
||||
* The number of embedded fields traversed to reach `f` is called its depth.
|
||||
* The depth of a field `f` declared in this type is zero.
|
||||
*/
|
||||
Field getFieldAtDepth(string name, int depth) {
|
||||
depth = min(int depthCand | exists(getFieldCand(name, depthCand, _))) and
|
||||
result = getFieldCand(name, depth, _) and
|
||||
strictcount(getFieldCand(name, depth, _)) = 1
|
||||
}
|
||||
|
||||
override predicate hasMethod(string name, SignatureType tp) { hasFieldOrMethod(name, tp, true) }
|
||||
Method getMethodAtDepth(string name, int depth) {
|
||||
depth = min(int depthCand | hasMethodCand(name, _, depthCand)) and
|
||||
result = unique(Method m | hasMethodCand(name, m, depth))
|
||||
}
|
||||
|
||||
override predicate hasMethod(string name, SignatureType tp) {
|
||||
exists(int mindepth |
|
||||
mindepth = min(int depth | this.hasMethodCand(name, _, depth)) and
|
||||
tp = unique(Method m | this.hasMethodCand(name, m, mindepth)).getType()
|
||||
)
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
override string pp() {
|
||||
|
||||
@@ -46,9 +46,9 @@ private TVariableWithFields accessPath(IR::Instruction insn) {
|
||||
* by variable with fields value `base`.
|
||||
*/
|
||||
private IR::Instruction fieldAccessPathAux(TVariableWithFields base, Field f) {
|
||||
exists(IR::FieldReadInstruction fr, IR::EvalInstruction frb |
|
||||
exists(IR::FieldReadInstruction fr, IR::Instruction frb |
|
||||
fr.getBase() = frb or
|
||||
fr.getBase() = IR::implicitDerefInstruction(frb.getExpr())
|
||||
fr.getBase() = IR::implicitDerefInstruction(frb.(IR::EvalInstruction).getExpr())
|
||||
|
|
||||
base = accessPath(frb) and
|
||||
f = fr.getField() and
|
||||
@@ -61,9 +61,9 @@ private IR::Instruction fieldAccessPathAux(TVariableWithFields base, Field f) {
|
||||
* by variable with fields value `base`.
|
||||
*/
|
||||
private IR::WriteTarget fieldWriteAccessPathAux(TVariableWithFields base, Field f) {
|
||||
exists(IR::FieldTarget ft, IR::EvalInstruction ftb |
|
||||
exists(IR::FieldTarget ft, IR::Instruction ftb |
|
||||
ft.getBase() = ftb or
|
||||
ft.getBase() = IR::implicitDerefInstruction(ftb.getExpr())
|
||||
ft.getBase() = IR::implicitDerefInstruction(ftb.(IR::EvalInstruction).getExpr())
|
||||
|
|
||||
base = accessPath(ftb) and
|
||||
ft.getField() = f and
|
||||
|
||||
@@ -48,6 +48,47 @@ private predicate isCond(Expr e) {
|
||||
e = any(ParenExpr par | isCond(par)).getExpr()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` implicitly reads the embedded field `implicitField`.
|
||||
*
|
||||
* The `index` is the distance from the promoted field. For example, if `A` contains an embedded
|
||||
* field `B`, `B` contains an embedded field `C` and `C` contains the non-embedded field `x`.
|
||||
* Then `a.x` implicitly reads `C` with index 1 and `B` with index 2.
|
||||
*/
|
||||
private predicate implicitFieldSelectionForField(PromotedSelector e, int index, Field implicitField) {
|
||||
exists(StructType baseType, PromotedField child, int implicitFieldDepth |
|
||||
baseType = e.getSelectedStructType() and
|
||||
(
|
||||
e.refersTo(child)
|
||||
or
|
||||
implicitFieldSelectionForField(e, implicitFieldDepth + 1, child)
|
||||
)
|
||||
|
|
||||
child = baseType.getFieldOfEmbedded(implicitField, _, implicitFieldDepth + 1, _) and
|
||||
exists(PromotedField explicitField, int explicitFieldDepth |
|
||||
e.refersTo(explicitField) and baseType.getFieldAtDepth(_, explicitFieldDepth) = explicitField
|
||||
|
|
||||
index = explicitFieldDepth - implicitFieldDepth
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate implicitFieldSelectionForMethod(PromotedSelector e, int index, Field implicitField) {
|
||||
exists(StructType baseType, PromotedMethod method, int mDepth, int implicitFieldDepth |
|
||||
baseType = e.getSelectedStructType() and
|
||||
e.refersTo(method) and
|
||||
baseType.getMethodAtDepth(_, mDepth) = method and
|
||||
index = mDepth - implicitFieldDepth
|
||||
|
|
||||
method = baseType.getMethodOfEmbedded(implicitField, _, implicitFieldDepth + 1)
|
||||
or
|
||||
exists(PromotedField child |
|
||||
child = baseType.getFieldOfEmbedded(implicitField, _, implicitFieldDepth + 1, _) and
|
||||
implicitFieldSelectionForMethod(e, implicitFieldDepth + 1, child)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A node in the intra-procedural control-flow graph of a Go function or file.
|
||||
*
|
||||
@@ -301,6 +342,17 @@ newtype TControlFlowNode =
|
||||
e = any(SliceExpr se).getBase()
|
||||
)
|
||||
} or
|
||||
/**
|
||||
* A control-flow node that represents the implicit selection of a field when
|
||||
* accessing a promoted field.
|
||||
*
|
||||
* If that field has a pointer type then this control-flow node also
|
||||
* represents an implicit dereference of it.
|
||||
*/
|
||||
MkImplicitFieldSelection(PromotedSelector e, int i, Field implicitField) {
|
||||
implicitFieldSelectionForField(e, i, implicitField) or
|
||||
implicitFieldSelectionForMethod(e, i, implicitField)
|
||||
} or
|
||||
/**
|
||||
* A control-flow node that represents the start of the execution of a function or file.
|
||||
*/
|
||||
@@ -1692,9 +1744,9 @@ module CFG {
|
||||
}
|
||||
|
||||
private class SelectorExprTree extends ControlFlowTree, SelectorExpr {
|
||||
SelectorExprTree() { getBase() instanceof ValueExpr }
|
||||
SelectorExprTree() { this.getBase() instanceof ValueExpr }
|
||||
|
||||
override predicate firstNode(ControlFlow::Node first) { firstNode(getBase(), first) }
|
||||
override predicate firstNode(ControlFlow::Node first) { firstNode(this.getBase(), first) }
|
||||
|
||||
override predicate lastNode(ControlFlow::Node last, Completion cmpl) {
|
||||
ControlFlowTree.super.lastNode(last, cmpl)
|
||||
@@ -1708,16 +1760,29 @@ module CFG {
|
||||
}
|
||||
|
||||
override predicate succ(ControlFlow::Node pred, ControlFlow::Node succ) {
|
||||
lastNode(getBase(), pred, normalCompletion()) and
|
||||
(
|
||||
succ = MkImplicitDeref(this.getBase())
|
||||
or
|
||||
not exists(MkImplicitDeref(this.getBase())) and
|
||||
succ = mkExprOrSkipNode(this)
|
||||
)
|
||||
exists(int i | pred = this.getStepWithRank(i) and succ = this.getStepWithRank(i + 1))
|
||||
}
|
||||
|
||||
private ControlFlow::Node getStepOrdered(int i) {
|
||||
i = -2 and lastNode(this.getBase(), result, normalCompletion())
|
||||
or
|
||||
pred = MkImplicitDeref(this.getBase()) and
|
||||
succ = mkExprOrSkipNode(this)
|
||||
i = -1 and result = MkImplicitDeref(this.getBase())
|
||||
or
|
||||
exists(int maxIndex |
|
||||
maxIndex = max(int k | k = 0 or exists(MkImplicitFieldSelection(this, k, _)))
|
||||
|
|
||||
result = MkImplicitFieldSelection(this, maxIndex - i, _)
|
||||
or
|
||||
i = maxIndex and
|
||||
result = mkExprOrSkipNode(this)
|
||||
)
|
||||
}
|
||||
|
||||
private ControlFlow::Node getStepWithRank(int i) {
|
||||
exists(int j |
|
||||
result = this.getStepOrdered(j) and
|
||||
j = rank[i + 1](int k | exists(this.getStepOrdered(k)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,14 +48,15 @@ module IR {
|
||||
this instanceof MkImplicitLowerSliceBound or
|
||||
this instanceof MkImplicitUpperSliceBound or
|
||||
this instanceof MkImplicitMaxSliceBound or
|
||||
this instanceof MkImplicitDeref
|
||||
this instanceof MkImplicitDeref or
|
||||
this instanceof MkImplicitFieldSelection
|
||||
}
|
||||
|
||||
/** Holds if this instruction reads the value of variable or constant `v`. */
|
||||
predicate reads(ValueEntity v) { readsField(_, v) or readsMethod(_, v) }
|
||||
predicate reads(ValueEntity v) { this.readsField(_, v) or this.readsMethod(_, v) }
|
||||
|
||||
/** Holds if this instruction updates variable or constant `v` to the value of `rhs`. */
|
||||
predicate writes(ValueEntity v, Instruction rhs) { writesField(_, v, rhs) }
|
||||
predicate writes(ValueEntity v, Instruction rhs) { this.writesField(_, v, rhs) }
|
||||
|
||||
/** Holds if this instruction reads the value of field `f` on the value of `base`. */
|
||||
predicate readsField(Instruction base, Field f) { none() }
|
||||
@@ -173,6 +174,8 @@ module IR {
|
||||
this instanceof MkImplicitMaxSliceBound and result = "implicit maximum"
|
||||
or
|
||||
this instanceof MkImplicitDeref and result = "implicit dereference"
|
||||
or
|
||||
this instanceof MkImplicitFieldSelection and result = "implicit field selection"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,20 +233,30 @@ module IR {
|
||||
)
|
||||
or
|
||||
this instanceof ReadResultInstruction
|
||||
or
|
||||
this instanceof MkImplicitFieldSelection
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the effective base of a selector, index or slice expression, taking implicit dereferences
|
||||
* into account.
|
||||
* and implicit field reads into account.
|
||||
*
|
||||
* For a selector expression `b.f`, this will either be the implicit dereference `*b`, or just
|
||||
* `b` if there is no implicit dereferencing.
|
||||
* For a selector expression `b.f`, this could be the implicit dereference `*b`, or the implicit
|
||||
* field access `b.Embedded` if the field `f` is promoted from an embedded type `Embedded`, or a
|
||||
* combination of both `*(b.Embedded)`, or simply `b` if neither case applies.
|
||||
*/
|
||||
private Instruction selectorBase(Expr e) {
|
||||
exists(ImplicitFieldReadInstruction fri | fri.getSelectorExpr() = e and fri.getIndex() = 1 |
|
||||
result = fri
|
||||
)
|
||||
or
|
||||
not exists(ImplicitFieldReadInstruction fri | fri.getSelectorExpr() = e and fri.getIndex() = 1) and
|
||||
exists(Expr base |
|
||||
base = e.(SelectorExpr).getBase() or
|
||||
base = e.(IndexExpr).getBase() or
|
||||
base = e.(SelectorExpr).getBase()
|
||||
or
|
||||
base = e.(IndexExpr).getBase()
|
||||
or
|
||||
base = e.(SliceExpr).getBase()
|
||||
|
|
||||
result = MkImplicitDeref(base)
|
||||
@@ -258,16 +271,24 @@ module IR {
|
||||
*
|
||||
* This is either a field of a struct, or an element of an array, map, slice or string.
|
||||
*/
|
||||
class ComponentReadInstruction extends ReadInstruction, EvalInstruction {
|
||||
class ComponentReadInstruction extends ReadInstruction {
|
||||
ComponentReadInstruction() {
|
||||
e instanceof IndexExpr
|
||||
exists(Expr e | e = this.(EvalInstruction).getExpr() |
|
||||
e instanceof IndexExpr
|
||||
or
|
||||
e.(SelectorExpr).getBase() instanceof ValueExpr and
|
||||
not e.(SelectorExpr).getSelector() = any(Method method).getAReference()
|
||||
)
|
||||
or
|
||||
e.(SelectorExpr).getBase() instanceof ValueExpr and
|
||||
not e.(SelectorExpr).getSelector() = any(Method method).getAReference()
|
||||
this instanceof MkImplicitFieldSelection
|
||||
}
|
||||
|
||||
/** Gets the instruction computing the base value on which the field or element is read. */
|
||||
Instruction getBase() { result = selectorBase(e) }
|
||||
Instruction getBase() {
|
||||
result = this.(ImplicitFieldReadInstruction).getBaseInstruction()
|
||||
or
|
||||
result = selectorBase(this.(EvalInstruction).getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -277,12 +298,77 @@ module IR {
|
||||
* misclassified as field reads.
|
||||
*/
|
||||
class FieldReadInstruction extends ComponentReadInstruction {
|
||||
override SelectorExpr e;
|
||||
SelectorExpr e;
|
||||
int index;
|
||||
Field field;
|
||||
|
||||
FieldReadInstruction() {
|
||||
e = this.(EvalInstruction).getExpr() and
|
||||
index = 0 and
|
||||
field.getAReference() = e.getSelector()
|
||||
or
|
||||
this = MkImplicitFieldSelection(e, index, field)
|
||||
}
|
||||
|
||||
/** Gets the `SelectorExpr` of this field read. */
|
||||
SelectorExpr getSelectorExpr() { result = e }
|
||||
|
||||
/** Gets the index of this field read. */
|
||||
int getIndex() { result = index }
|
||||
|
||||
/** Gets the field being read. */
|
||||
Field getField() { e.getSelector() = result.getAReference() }
|
||||
Field getField() { result = field }
|
||||
|
||||
override predicate readsField(Instruction base, Field f) { base = getBase() and f = getField() }
|
||||
Instruction getBaseInstruction() {
|
||||
exists(ImplicitFieldReadInstruction fri |
|
||||
fri.getSelectorExpr() = e and fri.getIndex() = pragma[only_bind_into](index + 1)
|
||||
|
|
||||
result = fri
|
||||
)
|
||||
or
|
||||
not exists(ImplicitFieldReadInstruction fri |
|
||||
fri.getSelectorExpr() = e and fri.getIndex() = pragma[only_bind_into](index + 1)
|
||||
) and
|
||||
(
|
||||
result = MkImplicitDeref(e.getBase())
|
||||
or
|
||||
not exists(MkImplicitDeref(e.getBase())) and
|
||||
result = evalExprInstruction(e.getBase())
|
||||
)
|
||||
}
|
||||
|
||||
override predicate readsField(Instruction base, Field f) {
|
||||
base = this.getBaseInstruction() and f = field
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR instruction for an implicit field read as part of reading a
|
||||
* promoted field.
|
||||
*
|
||||
* If the field that is being implicitly read has a pointer type then this
|
||||
* instruction represents an implicit dereference of it.
|
||||
*/
|
||||
class ImplicitFieldReadInstruction extends FieldReadInstruction, MkImplicitFieldSelection {
|
||||
ImplicitFieldReadInstruction() { this = MkImplicitFieldSelection(e, index, field) }
|
||||
|
||||
override predicate reads(ValueEntity v) { v = field }
|
||||
|
||||
override Type getResultType() {
|
||||
if field.getType() instanceof PointerType
|
||||
then result = field.getType().(PointerType).getBaseType()
|
||||
else result = field.getType()
|
||||
}
|
||||
|
||||
override ControlFlow::Root getRoot() { result.isRootOf(e) }
|
||||
|
||||
override string toString() { result = "implicit read of field " + field.toString() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
e.getBase().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,7 +394,7 @@ module IR {
|
||||
/**
|
||||
* An IR instruction that reads an element of an array, slice, map or string.
|
||||
*/
|
||||
class ElementReadInstruction extends ComponentReadInstruction {
|
||||
class ElementReadInstruction extends ComponentReadInstruction, EvalInstruction {
|
||||
override IndexExpr e;
|
||||
|
||||
/** Gets the instruction computing the index of the element being looked up. */
|
||||
@@ -1395,7 +1481,7 @@ module IR {
|
||||
}
|
||||
|
||||
/** Get the type of the base of this field access, that is, the type that contains the field. */
|
||||
Type getBaseType() { result = this.getBase().(EvalInstruction).getExpr().getType() }
|
||||
Type getBaseType() { result = this.getBase().getResultType() }
|
||||
|
||||
override predicate refersTo(ValueEntity e) {
|
||||
exists(SelectorExpr sel | this = MkLhs(_, sel) | sel.uses(e))
|
||||
|
||||
@@ -319,9 +319,9 @@ private TSsaWithFields accessPath(IR::Instruction insn) {
|
||||
* by ssa-with-fields value `base`.
|
||||
*/
|
||||
private IR::Instruction accessPathAux(TSsaWithFields base, Field f) {
|
||||
exists(IR::FieldReadInstruction fr, IR::EvalInstruction frb |
|
||||
exists(IR::FieldReadInstruction fr, IR::Instruction frb |
|
||||
fr.getBase() = frb or
|
||||
fr.getBase() = IR::implicitDerefInstruction(frb.getExpr())
|
||||
fr.getBase() = IR::implicitDerefInstruction(frb.(IR::EvalInstruction).getExpr())
|
||||
|
|
||||
base = accessPath(frb) and
|
||||
f = fr.getField() and
|
||||
|
||||
@@ -279,6 +279,11 @@ module Revel {
|
||||
override DataFlow::Node getADataArgument() { result = this.getArgumentVariable().getAUse() }
|
||||
}
|
||||
|
||||
private IR::EvalInstruction skipImplicitFieldReads(IR::Instruction insn) {
|
||||
result = insn or
|
||||
result = skipImplicitFieldReads(insn.(IR::ImplicitFieldReadInstruction).getBase())
|
||||
}
|
||||
|
||||
/** A call to `Controller.Render`. */
|
||||
private class ControllerRender extends TemplateRender, DataFlow::MethodCallNode {
|
||||
ControllerRender() { this.getTarget().hasQualifiedName(packagePath(), "Controller", "Render") }
|
||||
@@ -286,8 +291,9 @@ module Revel {
|
||||
override DataFlow::Node getTemplateArgument() { none() }
|
||||
|
||||
override File getRenderedFile() {
|
||||
exists(string controllerRe, string handlerRe, string pathRe |
|
||||
controllerRe = "\\Q" + this.getReceiver().getType().getName() + "\\E" and
|
||||
exists(Type controllerType, string controllerRe, string handlerRe, string pathRe |
|
||||
controllerType = skipImplicitFieldReads(this.getReceiver().asInstruction()).getResultType() and
|
||||
controllerRe = "\\Q" + controllerType.getName() + "\\E" and
|
||||
handlerRe = "\\Q" + this.getEnclosingCallable().getName() + "\\E" and
|
||||
// find a file named '/views/<controller>/<handler>(.<template type>).html
|
||||
pathRe = "/views/" + controllerRe + "/" + handlerRe + "(\\..*)?\\.html?"
|
||||
|
||||
@@ -2,11 +2,16 @@
|
||||
| cyclic.go:8:3:8:3 | u | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| cyclic.go:9:2:9:2 | f | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| cyclic.go:13:2:13:2 | t | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| cyclic.go:17:2:17:2 | s | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| depth.go:6:2:6:2 | b | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| depth.go:7:2:7:2 | c | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| depth.go:11:2:11:2 | f | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| depth.go:15:2:15:2 | d | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| depth.go:19:2:19:2 | f | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| embedded.go:4:2:4:2 | A | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| embedded.go:8:3:8:5 | Baz | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| embedded.go:13:2:13:4 | Qux | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| embedded.go:14:2:14:4 | Baz | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types |
|
||||
| pkg1/embedding.go:19:23:19:26 | base | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 |
|
||||
| pkg1/embedding.go:22:27:22:30 | base | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 |
|
||||
| pkg1/embedding.go:25:24:25:31 | embedder | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 |
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
| cyclic.go:9:2:9:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.u | f |
|
||||
| cyclic.go:13:2:13:2 | t | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.t | t |
|
||||
| cyclic.go:13:2:13:2 | t | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.u | t |
|
||||
| cyclic.go:17:2:17:2 | s | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.v | s |
|
||||
| depth.go:6:2:6:2 | b | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.a | b |
|
||||
| depth.go:7:2:7:2 | c | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.a | c |
|
||||
| depth.go:11:2:11:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.a | f |
|
||||
@@ -13,6 +14,11 @@
|
||||
| depth.go:15:2:15:2 | d | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.c | d |
|
||||
| depth.go:19:2:19:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.c | f |
|
||||
| depth.go:19:2:19:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.d | f |
|
||||
| embedded.go:4:2:4:2 | A | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.Baz | A |
|
||||
| embedded.go:4:2:4:2 | A | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.Qux | A |
|
||||
| embedded.go:8:3:8:5 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.Qux | Baz |
|
||||
| embedded.go:13:2:13:4 | Qux | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsBaz | Qux |
|
||||
| embedded.go:14:2:14:4 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsBaz | Baz |
|
||||
| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder | base |
|
||||
| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder2 | base |
|
||||
| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder3 | base |
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
| cyclic.go:9:2:9:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | u | f |
|
||||
| cyclic.go:13:2:13:2 | t | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | t | t |
|
||||
| cyclic.go:13:2:13:2 | t | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | u | t |
|
||||
| cyclic.go:17:2:17:2 | s | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | v | s |
|
||||
| depth.go:6:2:6:2 | b | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | a | b |
|
||||
| depth.go:7:2:7:2 | c | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | a | c |
|
||||
| depth.go:11:2:11:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | a | f |
|
||||
@@ -13,6 +14,11 @@
|
||||
| depth.go:15:2:15:2 | d | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | c | d |
|
||||
| depth.go:19:2:19:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | c | f |
|
||||
| depth.go:19:2:19:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | d | f |
|
||||
| embedded.go:4:2:4:2 | A | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | Baz | A |
|
||||
| embedded.go:4:2:4:2 | A | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | Qux | A |
|
||||
| embedded.go:8:3:8:5 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | Qux | Baz |
|
||||
| embedded.go:13:2:13:4 | Qux | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | EmbedsBaz | Qux |
|
||||
| embedded.go:14:2:14:4 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | EmbedsBaz | Baz |
|
||||
| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder | base |
|
||||
| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder2 | base |
|
||||
| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder3 | base |
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
| embedder | f | func() int |
|
||||
| embedder2 | f | func() int |
|
||||
| embedder3 | f | func() int |
|
||||
| embedder4 | f | func() int |
|
||||
| ptrembedder | f | func() int |
|
||||
| ptrembedder | g | func() int |
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
| AExtended | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.AExtended |
|
||||
| B | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.B |
|
||||
| Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Bar |
|
||||
| Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.Baz |
|
||||
| C | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.C |
|
||||
| EmbedsBaz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsBaz |
|
||||
| Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Foo |
|
||||
| G | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.G |
|
||||
| Qux | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.Qux |
|
||||
| T | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T |
|
||||
| T | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.T |
|
||||
| T2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T2 |
|
||||
@@ -26,3 +29,4 @@
|
||||
| s | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.s |
|
||||
| t | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.t |
|
||||
| u | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.u |
|
||||
| v | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.v |
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
| Bar | pkg1/tst.go:29:10:31:1 | struct type | flag | bool |
|
||||
| Baz | embedded.go:3:10:5:1 | struct type | A | string |
|
||||
| EmbedsBaz | embedded.go:12:16:15:1 | struct type | Baz | string |
|
||||
| EmbedsBaz | embedded.go:12:16:15:1 | struct type | Qux | Qux |
|
||||
| Foo | pkg1/tst.go:24:10:27:1 | struct type | flag | bool |
|
||||
| Foo | pkg1/tst.go:24:10:27:1 | struct type | val | int |
|
||||
| G | pkg2/tst.go:3:8:5:1 | struct type | g | int |
|
||||
| G | pkg2/tst.go:7:8:9:1 | struct type | g | int |
|
||||
| Qux | embedded.go:7:10:9:1 | struct type | A | string |
|
||||
| Qux | embedded.go:7:10:9:1 | struct type | Baz | * Baz |
|
||||
| T | pkg1/tst.go:3:8:7:1 | struct type | Bar | Bar |
|
||||
| T | pkg1/tst.go:3:8:7:1 | struct type | Foo | Foo |
|
||||
| T | pkg1/tst.go:3:8:7:1 | struct type | f | int |
|
||||
@@ -46,3 +51,4 @@
|
||||
| u | cyclic.go:12:8:14:1 | struct type | f | int |
|
||||
| u | cyclic.go:12:8:14:1 | struct type | t | t |
|
||||
| u | cyclic.go:12:8:14:1 | struct type | u | * u |
|
||||
| v | cyclic.go:16:8:18:1 | struct type | s | s |
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
| AExtended | AExtended |
|
||||
| B | B |
|
||||
| Bar | Bar |
|
||||
| Baz | Baz |
|
||||
| C | C |
|
||||
| EmbedsBaz | EmbedsBaz |
|
||||
| Foo | Foo |
|
||||
| G | G |
|
||||
| Qux | Qux |
|
||||
| T | T |
|
||||
| T | T |
|
||||
| T2 | T2 |
|
||||
@@ -26,3 +29,4 @@
|
||||
| s | s |
|
||||
| t | t |
|
||||
| u | u |
|
||||
| v | v |
|
||||
|
||||
@@ -12,3 +12,12 @@ type t struct {
|
||||
type u struct {
|
||||
t
|
||||
}
|
||||
|
||||
type v struct {
|
||||
s
|
||||
}
|
||||
|
||||
// the below will cause the test to not terminate
|
||||
// type w struct {
|
||||
// v
|
||||
// }
|
||||
|
||||
15
ql/test/library-tests/semmle/go/Types/embedded.go
Normal file
15
ql/test/library-tests/semmle/go/Types/embedded.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
type Baz struct {
|
||||
A string
|
||||
}
|
||||
|
||||
type Qux struct {
|
||||
*Baz
|
||||
}
|
||||
|
||||
// EmbedsBaz should have a field A but does not
|
||||
type EmbedsBaz struct {
|
||||
Qux
|
||||
Baz string
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class SourceFunction extends Function {
|
||||
SourceFunction() { this.getName() = "source" }
|
||||
}
|
||||
|
||||
class SinkFunction extends Function {
|
||||
SinkFunction() { this.getName() = "sink" }
|
||||
}
|
||||
|
||||
class TestConfig extends DataFlow::Configuration {
|
||||
TestConfig() { this = "testconfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(SourceFunction f).getACall().getAResult()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(SinkFunction f).getACall().getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
class PromotedFieldsTest extends InlineExpectationsTest {
|
||||
PromotedFieldsTest() { this = "PromotedFieldsTest" }
|
||||
|
||||
override string getARelevantTag() { result = "promotedfields" }
|
||||
|
||||
override predicate hasActualResult(string file, int line, string element, string tag, string value) {
|
||||
exists(TestConfig config, DataFlow::PathNode source, DataFlow::PathNode sink |
|
||||
config.hasFlowPath(source, sink) and
|
||||
sink.hasLocationInfo(file, line, _, _, _) and
|
||||
element = sink.toString() and
|
||||
value = "" and
|
||||
tag = "promotedfields"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
| main.go:3:6:3:11 | function source | main.go:23:31:23:36 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:31:31:31:36 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:40:30:40:35 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:46:32:46:37 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:54:17:54:22 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:62:18:62:23 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:72:17:72:22 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:80:18:80:23 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:91:16:91:21 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:98:17:98:22 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:107:22:107:27 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:114:23:114:28 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:123:23:123:28 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:130:24:130:29 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:139:29:139:34 | source |
|
||||
| main.go:3:6:3:11 | function source | main.go:146:30:146:35 | source |
|
||||
| main.go:7:6:7:9 | function sink | main.go:25:2:25:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:26:2:26:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:27:2:27:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:28:2:28:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:33:2:33:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:34:2:34:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:35:2:35:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:36:2:36:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:41:2:41:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:42:2:42:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:43:2:43:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:44:2:44:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:47:2:47:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:48:2:48:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:49:2:49:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:50:2:50:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:57:2:57:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:58:2:58:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:59:2:59:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:60:2:60:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:65:2:65:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:66:2:66:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:67:2:67:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:68:2:68:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:75:2:75:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:76:2:76:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:77:2:77:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:78:2:78:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:83:2:83:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:84:2:84:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:85:2:85:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:86:2:86:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:92:2:92:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:93:2:93:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:94:2:94:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:95:2:95:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:99:2:99:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:100:2:100:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:101:2:101:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:102:2:102:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:108:2:108:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:109:2:109:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:110:2:110:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:111:2:111:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:115:2:115:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:116:2:116:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:117:2:117:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:118:2:118:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:124:2:124:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:125:2:125:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:126:2:126:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:127:2:127:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:131:2:131:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:132:2:132:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:133:2:133:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:134:2:134:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:140:2:140:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:141:2:141:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:142:2:142:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:143:2:143:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:147:2:147:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:148:2:148:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:149:2:149:5 | sink |
|
||||
| main.go:7:6:7:9 | function sink | main.go:150:2:150:5 | sink |
|
||||
| main.go:22:2:22:6 | definition of outer | main.go:25:7:25:11 | outer |
|
||||
| main.go:22:2:22:6 | definition of outer | main.go:26:7:26:11 | outer |
|
||||
| main.go:22:2:22:6 | definition of outer | main.go:27:7:27:11 | outer |
|
||||
| main.go:22:2:22:6 | definition of outer | main.go:28:7:28:11 | outer |
|
||||
| main.go:22:11:24:2 | struct literal | main.go:22:2:22:6 | definition of outer |
|
||||
| main.go:30:2:30:7 | definition of outerp | main.go:33:7:33:12 | outerp |
|
||||
| main.go:30:2:30:7 | definition of outerp | main.go:34:7:34:12 | outerp |
|
||||
| main.go:30:2:30:7 | definition of outerp | main.go:35:7:35:12 | outerp |
|
||||
| main.go:30:2:30:7 | definition of outerp | main.go:36:7:36:12 | outerp |
|
||||
| main.go:30:12:32:2 | &... | main.go:30:2:30:7 | definition of outerp |
|
||||
| main.go:40:2:40:6 | definition of outer | main.go:41:7:41:11 | outer |
|
||||
| main.go:40:2:40:6 | definition of outer | main.go:42:7:42:11 | outer |
|
||||
| main.go:40:2:40:6 | definition of outer | main.go:43:7:43:11 | outer |
|
||||
| main.go:40:2:40:6 | definition of outer | main.go:44:7:44:11 | outer |
|
||||
| main.go:40:11:40:40 | struct literal | main.go:40:2:40:6 | definition of outer |
|
||||
| main.go:46:2:46:7 | definition of outerp | main.go:47:7:47:12 | outerp |
|
||||
| main.go:46:2:46:7 | definition of outerp | main.go:48:7:48:12 | outerp |
|
||||
| main.go:46:2:46:7 | definition of outerp | main.go:49:7:49:12 | outerp |
|
||||
| main.go:46:2:46:7 | definition of outerp | main.go:50:7:50:12 | outerp |
|
||||
| main.go:46:12:46:42 | &... | main.go:46:2:46:7 | definition of outerp |
|
||||
| main.go:54:2:54:6 | definition of inner | main.go:55:19:55:23 | inner |
|
||||
| main.go:54:11:54:25 | struct literal | main.go:54:2:54:6 | definition of inner |
|
||||
| main.go:55:2:55:7 | definition of middle | main.go:56:17:56:22 | middle |
|
||||
| main.go:55:12:55:24 | struct literal | main.go:55:2:55:7 | definition of middle |
|
||||
| main.go:56:2:56:6 | definition of outer | main.go:57:7:57:11 | outer |
|
||||
| main.go:56:2:56:6 | definition of outer | main.go:58:7:58:11 | outer |
|
||||
| main.go:56:2:56:6 | definition of outer | main.go:59:7:59:11 | outer |
|
||||
| main.go:56:2:56:6 | definition of outer | main.go:60:7:60:11 | outer |
|
||||
| main.go:56:11:56:23 | struct literal | main.go:56:2:56:6 | definition of outer |
|
||||
| main.go:62:2:62:7 | definition of innerp | main.go:63:20:63:25 | innerp |
|
||||
| main.go:62:12:62:26 | struct literal | main.go:62:2:62:7 | definition of innerp |
|
||||
| main.go:63:2:63:8 | definition of middlep | main.go:64:18:64:24 | middlep |
|
||||
| main.go:63:13:63:26 | struct literal | main.go:63:2:63:8 | definition of middlep |
|
||||
| main.go:64:2:64:7 | definition of outerp | main.go:65:7:65:12 | outerp |
|
||||
| main.go:64:2:64:7 | definition of outerp | main.go:66:7:66:12 | outerp |
|
||||
| main.go:64:2:64:7 | definition of outerp | main.go:67:7:67:12 | outerp |
|
||||
| main.go:64:2:64:7 | definition of outerp | main.go:68:7:68:12 | outerp |
|
||||
| main.go:64:12:64:25 | struct literal | main.go:64:2:64:7 | definition of outerp |
|
||||
| main.go:72:2:72:6 | definition of inner | main.go:73:26:73:30 | inner |
|
||||
| main.go:72:11:72:25 | struct literal | main.go:72:2:72:6 | definition of inner |
|
||||
| main.go:73:2:73:7 | definition of middle | main.go:74:25:74:30 | middle |
|
||||
| main.go:73:12:73:31 | struct literal | main.go:73:2:73:7 | definition of middle |
|
||||
| main.go:74:2:74:6 | definition of outer | main.go:75:7:75:11 | outer |
|
||||
| main.go:74:2:74:6 | definition of outer | main.go:76:7:76:11 | outer |
|
||||
| main.go:74:2:74:6 | definition of outer | main.go:77:7:77:11 | outer |
|
||||
| main.go:74:2:74:6 | definition of outer | main.go:78:7:78:11 | outer |
|
||||
| main.go:74:11:74:31 | struct literal | main.go:74:2:74:6 | definition of outer |
|
||||
| main.go:80:2:80:7 | definition of innerp | main.go:81:27:81:32 | innerp |
|
||||
| main.go:80:12:80:26 | struct literal | main.go:80:2:80:7 | definition of innerp |
|
||||
| main.go:81:2:81:8 | definition of middlep | main.go:82:26:82:32 | middlep |
|
||||
| main.go:81:13:81:33 | struct literal | main.go:81:2:81:8 | definition of middlep |
|
||||
| main.go:82:2:82:7 | definition of outerp | main.go:83:7:83:12 | outerp |
|
||||
| main.go:82:2:82:7 | definition of outerp | main.go:84:7:84:12 | outerp |
|
||||
| main.go:82:2:82:7 | definition of outerp | main.go:85:7:85:12 | outerp |
|
||||
| main.go:82:2:82:7 | definition of outerp | main.go:86:7:86:12 | outerp |
|
||||
| main.go:82:12:82:33 | struct literal | main.go:82:2:82:7 | definition of outerp |
|
||||
| main.go:90:6:90:10 | definition of outer | main.go:91:2:91:6 | outer |
|
||||
| main.go:90:6:90:10 | definition of outer | main.go:92:7:92:11 | outer |
|
||||
| main.go:90:6:90:10 | definition of outer | main.go:93:7:93:11 | outer |
|
||||
| main.go:90:6:90:10 | definition of outer | main.go:94:7:94:11 | outer |
|
||||
| main.go:90:6:90:10 | definition of outer | main.go:95:7:95:11 | outer |
|
||||
| main.go:90:6:90:10 | zero value for outer | main.go:90:6:90:10 | definition of outer |
|
||||
| main.go:97:6:97:11 | definition of outerp | main.go:98:2:98:7 | outerp |
|
||||
| main.go:97:6:97:11 | definition of outerp | main.go:99:7:99:12 | outerp |
|
||||
| main.go:97:6:97:11 | definition of outerp | main.go:100:7:100:12 | outerp |
|
||||
| main.go:97:6:97:11 | definition of outerp | main.go:101:7:101:12 | outerp |
|
||||
| main.go:97:6:97:11 | definition of outerp | main.go:102:7:102:12 | outerp |
|
||||
| main.go:97:6:97:11 | zero value for outerp | main.go:97:6:97:11 | definition of outerp |
|
||||
| main.go:106:6:106:10 | definition of outer | main.go:107:2:107:6 | outer |
|
||||
| main.go:106:6:106:10 | definition of outer | main.go:108:7:108:11 | outer |
|
||||
| main.go:106:6:106:10 | definition of outer | main.go:109:7:109:11 | outer |
|
||||
| main.go:106:6:106:10 | definition of outer | main.go:110:7:110:11 | outer |
|
||||
| main.go:106:6:106:10 | definition of outer | main.go:111:7:111:11 | outer |
|
||||
| main.go:106:6:106:10 | zero value for outer | main.go:106:6:106:10 | definition of outer |
|
||||
| main.go:113:6:113:11 | definition of outerp | main.go:114:2:114:7 | outerp |
|
||||
| main.go:113:6:113:11 | definition of outerp | main.go:115:7:115:12 | outerp |
|
||||
| main.go:113:6:113:11 | definition of outerp | main.go:116:7:116:12 | outerp |
|
||||
| main.go:113:6:113:11 | definition of outerp | main.go:117:7:117:12 | outerp |
|
||||
| main.go:113:6:113:11 | definition of outerp | main.go:118:7:118:12 | outerp |
|
||||
| main.go:113:6:113:11 | zero value for outerp | main.go:113:6:113:11 | definition of outerp |
|
||||
| main.go:122:6:122:10 | definition of outer | main.go:123:2:123:6 | outer |
|
||||
| main.go:122:6:122:10 | definition of outer | main.go:124:7:124:11 | outer |
|
||||
| main.go:122:6:122:10 | definition of outer | main.go:125:7:125:11 | outer |
|
||||
| main.go:122:6:122:10 | definition of outer | main.go:126:7:126:11 | outer |
|
||||
| main.go:122:6:122:10 | definition of outer | main.go:127:7:127:11 | outer |
|
||||
| main.go:122:6:122:10 | zero value for outer | main.go:122:6:122:10 | definition of outer |
|
||||
| main.go:129:6:129:11 | definition of outerp | main.go:130:2:130:7 | outerp |
|
||||
| main.go:129:6:129:11 | definition of outerp | main.go:131:7:131:12 | outerp |
|
||||
| main.go:129:6:129:11 | definition of outerp | main.go:132:7:132:12 | outerp |
|
||||
| main.go:129:6:129:11 | definition of outerp | main.go:133:7:133:12 | outerp |
|
||||
| main.go:129:6:129:11 | definition of outerp | main.go:134:7:134:12 | outerp |
|
||||
| main.go:129:6:129:11 | zero value for outerp | main.go:129:6:129:11 | definition of outerp |
|
||||
| main.go:138:6:138:10 | definition of outer | main.go:139:2:139:6 | outer |
|
||||
| main.go:138:6:138:10 | definition of outer | main.go:140:7:140:11 | outer |
|
||||
| main.go:138:6:138:10 | definition of outer | main.go:141:7:141:11 | outer |
|
||||
| main.go:138:6:138:10 | definition of outer | main.go:142:7:142:11 | outer |
|
||||
| main.go:138:6:138:10 | definition of outer | main.go:143:7:143:11 | outer |
|
||||
| main.go:138:6:138:10 | zero value for outer | main.go:138:6:138:10 | definition of outer |
|
||||
| main.go:145:6:145:11 | definition of outerp | main.go:146:2:146:7 | outerp |
|
||||
| main.go:145:6:145:11 | definition of outerp | main.go:147:7:147:12 | outerp |
|
||||
| main.go:145:6:145:11 | definition of outerp | main.go:148:7:148:12 | outerp |
|
||||
| main.go:145:6:145:11 | definition of outerp | main.go:149:7:149:12 | outerp |
|
||||
| main.go:145:6:145:11 | definition of outerp | main.go:150:7:150:12 | outerp |
|
||||
| main.go:145:6:145:11 | zero value for outerp | main.go:145:6:145:11 | definition of outerp |
|
||||
@@ -0,0 +1,5 @@
|
||||
import go
|
||||
|
||||
from DataFlow::Node nd, DataFlow::Node succ
|
||||
where DataFlow::localFlowStep(nd, succ)
|
||||
select nd, succ
|
||||
151
ql/test/library-tests/semmle/go/dataflow/PromotedFields/main.go
Normal file
151
ql/test/library-tests/semmle/go/dataflow/PromotedFields/main.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package main
|
||||
|
||||
func source() string {
|
||||
return "hello world"
|
||||
}
|
||||
|
||||
func sink(s string) {}
|
||||
|
||||
type Inner struct {
|
||||
field string
|
||||
}
|
||||
|
||||
type Middle struct {
|
||||
Inner
|
||||
}
|
||||
|
||||
type Outer struct {
|
||||
Middle
|
||||
}
|
||||
|
||||
func testPromotedFieldNamedInitialization() {
|
||||
outer := Outer{
|
||||
Middle: Middle{Inner: Inner{source()}},
|
||||
}
|
||||
sink(outer.field) // $promotedfields
|
||||
sink(outer.Inner.field) // $promotedfields
|
||||
sink(outer.Middle.field) // $promotedfields
|
||||
sink(outer.Middle.Inner.field) // $promotedfields
|
||||
|
||||
outerp := &Outer{
|
||||
Middle: Middle{Inner: Inner{source()}},
|
||||
}
|
||||
sink(outerp.field) // $promotedfields
|
||||
sink(outerp.Inner.field) // $promotedfields
|
||||
sink(outerp.Middle.field) // $promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $promotedfields
|
||||
}
|
||||
|
||||
func testPromotedFieldUnnamedInitialization() {
|
||||
outer := Outer{Middle{Inner{source()}}}
|
||||
sink(outer.field) // $promotedfields
|
||||
sink(outer.Inner.field) // $promotedfields
|
||||
sink(outer.Middle.field) // $promotedfields
|
||||
sink(outer.Middle.Inner.field) // $promotedfields
|
||||
|
||||
outerp := &Outer{Middle{Inner{source()}}}
|
||||
sink(outerp.field) // $promotedfields
|
||||
sink(outerp.Inner.field) // $promotedfields
|
||||
sink(outerp.Middle.field) // $promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $promotedfields
|
||||
}
|
||||
|
||||
func testPromotedFieldUnnamedInitializationFromVariable() {
|
||||
inner := Inner{source()}
|
||||
middle := Middle{inner}
|
||||
outer := Outer{middle}
|
||||
sink(outer.field) // $promotedfields
|
||||
sink(outer.Inner.field) // $promotedfields
|
||||
sink(outer.Middle.field) // $promotedfields
|
||||
sink(outer.Middle.Inner.field) // $promotedfields
|
||||
|
||||
innerp := Inner{source()}
|
||||
middlep := Middle{innerp}
|
||||
outerp := Outer{middlep}
|
||||
sink(outerp.field) // $promotedfields
|
||||
sink(outerp.Inner.field) // $promotedfields
|
||||
sink(outerp.Middle.field) // $promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $promotedfields
|
||||
}
|
||||
|
||||
func testPromotedFieldNamedInitializationFromVariable() {
|
||||
inner := Inner{source()}
|
||||
middle := Middle{Inner: inner}
|
||||
outer := Outer{Middle: middle}
|
||||
sink(outer.field) // $promotedfields
|
||||
sink(outer.Inner.field) // $promotedfields
|
||||
sink(outer.Middle.field) // $promotedfields
|
||||
sink(outer.Middle.Inner.field) // $promotedfields
|
||||
|
||||
innerp := Inner{source()}
|
||||
middlep := Middle{Inner: innerp}
|
||||
outerp := Outer{Middle: middlep}
|
||||
sink(outerp.field) // $promotedfields
|
||||
sink(outerp.Inner.field) // $promotedfields
|
||||
sink(outerp.Middle.field) // $promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $promotedfields
|
||||
}
|
||||
|
||||
func testPromotedFieldDirectAssignment() {
|
||||
var outer Outer
|
||||
outer.field = source()
|
||||
sink(outer.field) // $promotedfields
|
||||
sink(outer.Inner.field) // $promotedfields
|
||||
sink(outer.Middle.field) // $promotedfields
|
||||
sink(outer.Middle.Inner.field) // $promotedfields
|
||||
|
||||
var outerp Outer
|
||||
outerp.field = source()
|
||||
sink(outerp.field) // $promotedfields
|
||||
sink(outerp.Inner.field) // $promotedfields
|
||||
sink(outerp.Middle.field) // $promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $promotedfields
|
||||
}
|
||||
|
||||
func testPromotedFieldIndirectAssignment1() {
|
||||
var outer Outer
|
||||
outer.Inner.field = source()
|
||||
sink(outer.field) // $promotedfields
|
||||
sink(outer.Inner.field) // $promotedfields
|
||||
sink(outer.Middle.field) // $promotedfields
|
||||
sink(outer.Middle.Inner.field) // $promotedfields
|
||||
|
||||
var outerp Outer
|
||||
outerp.Inner.field = source()
|
||||
sink(outerp.field) // $promotedfields
|
||||
sink(outerp.Inner.field) // $promotedfields
|
||||
sink(outerp.Middle.field) // $promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $promotedfields
|
||||
}
|
||||
|
||||
func testPromotedFieldIndirectAssignment2() {
|
||||
var outer Outer
|
||||
outer.Middle.field = source()
|
||||
sink(outer.field) // $promotedfields
|
||||
sink(outer.Inner.field) // $promotedfields
|
||||
sink(outer.Middle.field) // $promotedfields
|
||||
sink(outer.Middle.Inner.field) // $promotedfields
|
||||
|
||||
var outerp Outer
|
||||
outerp.Middle.field = source()
|
||||
sink(outerp.field) // $promotedfields
|
||||
sink(outerp.Inner.field) // $promotedfields
|
||||
sink(outerp.Middle.field) // $promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $promotedfields
|
||||
}
|
||||
|
||||
func testPromotedFieldIndirectAssignment3() {
|
||||
var outer Outer
|
||||
outer.Middle.Inner.field = source()
|
||||
sink(outer.field) // $promotedfields
|
||||
sink(outer.Inner.field) // $promotedfields
|
||||
sink(outer.Middle.field) // $promotedfields
|
||||
sink(outer.Middle.Inner.field) // $promotedfields
|
||||
|
||||
var outerp Outer
|
||||
outerp.Middle.Inner.field = source()
|
||||
sink(outerp.field) // $promotedfields
|
||||
sink(outerp.Inner.field) // $promotedfields
|
||||
sink(outerp.Middle.field) // $promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $promotedfields
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class SourceFunction extends Function {
|
||||
SourceFunction() { this.getName() = "source" }
|
||||
}
|
||||
|
||||
class SinkFunction extends Function {
|
||||
SinkFunction() { this.getName() = "sink" }
|
||||
}
|
||||
|
||||
class TestConfig extends DataFlow::Configuration {
|
||||
TestConfig() { this = "testconfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(SourceFunction f).getACall().getAResult()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(SinkFunction f).getACall().getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
class PromotedMethodsTest extends InlineExpectationsTest {
|
||||
PromotedMethodsTest() { this = "PromotedMethodsTest" }
|
||||
|
||||
override string getARelevantTag() { result = "promotedmethods" }
|
||||
|
||||
override predicate hasActualResult(string file, int line, string element, string tag, string value) {
|
||||
exists(TestConfig config, DataFlow::Node source, DataFlow::Node sink |
|
||||
config.hasFlow(source, sink)
|
||||
|
|
||||
sink.hasLocationInfo(file, line, _, _, _) and
|
||||
element = sink.toString() and
|
||||
value = source.getEnclosingCallable().getName() and
|
||||
tag = "promotedmethods"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package main
|
||||
|
||||
func source() string {
|
||||
return "hello world"
|
||||
}
|
||||
|
||||
func sink(s string) {}
|
||||
|
||||
type Embedded struct {
|
||||
field string
|
||||
}
|
||||
|
||||
type Base1 struct {
|
||||
Embedded
|
||||
}
|
||||
|
||||
type Base2 struct {
|
||||
*Embedded
|
||||
}
|
||||
|
||||
func (e Embedded) sinkFieldOnEmbeddedNonPointerReceiver() {
|
||||
sink(e.field) // $promotedmethods=nonPointerSender1 $promotedmethods=pointerSender1 $promotedmethods=nonPointerSender2 $promotedmethods=pointerSender2
|
||||
}
|
||||
|
||||
func (e *Embedded) sinkFieldOnEmbeddedPointerReceiver() {
|
||||
sink(e.field) // $f-:promotedmethods=nonPointerSender1 $f-:promotedmethods=pointerSender1 $f-:promotedmethods=nonPointerSender2 $f-:promotedmethods=pointerSender2
|
||||
}
|
||||
|
||||
func (base1 Base1) sinkFieldOnBase1NonPointerReceiver() {
|
||||
sink(base1.field) // $promotedmethods=nonPointerSender1 $promotedmethods=pointerSender1
|
||||
}
|
||||
|
||||
func (base1 *Base1) sinkFieldOnBase1PointerReceiver() {
|
||||
sink(base1.field) // $f-:promotedmethods=nonPointerSender1 $promotedmethods=pointerSender1
|
||||
}
|
||||
|
||||
func (base2 Base2) sinkFieldOnBase2NonPointerReceiver() {
|
||||
sink(base2.field) // $promotedmethods=nonPointerSender2 $promotedmethods=pointerSender2
|
||||
}
|
||||
|
||||
func (base2 *Base2) sinkFieldOnBase2PointerReceiver() {
|
||||
sink(base2.field) // $f-:promotedmethods=nonPointerSender2 $promotedmethods=pointerSender2
|
||||
}
|
||||
|
||||
func nonPointerSender1() {
|
||||
var base1 Base1
|
||||
base1.field = source()
|
||||
base1.sinkFieldOnEmbeddedNonPointerReceiver()
|
||||
base1.sinkFieldOnEmbeddedPointerReceiver()
|
||||
base1.sinkFieldOnBase1NonPointerReceiver()
|
||||
base1.sinkFieldOnBase1PointerReceiver()
|
||||
}
|
||||
|
||||
func pointerSender1() {
|
||||
var base1 Base1
|
||||
base1.field = source()
|
||||
base1p := &base1
|
||||
base1p.sinkFieldOnEmbeddedNonPointerReceiver()
|
||||
base1p.sinkFieldOnEmbeddedPointerReceiver()
|
||||
base1p.sinkFieldOnBase1NonPointerReceiver()
|
||||
base1p.sinkFieldOnBase1PointerReceiver()
|
||||
}
|
||||
|
||||
func nonPointerSender2() {
|
||||
var base2 Base2
|
||||
base2.field = source()
|
||||
base2.sinkFieldOnEmbeddedNonPointerReceiver()
|
||||
base2.sinkFieldOnEmbeddedPointerReceiver()
|
||||
base2.sinkFieldOnBase2NonPointerReceiver()
|
||||
base2.sinkFieldOnBase2PointerReceiver()
|
||||
}
|
||||
|
||||
func pointerSender2() {
|
||||
var base2 Base2
|
||||
base2.field = source()
|
||||
base2p := &base2
|
||||
base2p.sinkFieldOnEmbeddedNonPointerReceiver()
|
||||
base2p.sinkFieldOnEmbeddedPointerReceiver()
|
||||
base2p.sinkFieldOnBase2NonPointerReceiver()
|
||||
base2p.sinkFieldOnBase2PointerReceiver()
|
||||
}
|
||||
@@ -15,17 +15,23 @@ edges
|
||||
| UnsafeUnzipSymlinkGood.go:76:70:76:75 | implicit dereference : Header | UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name : string |
|
||||
| UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name : string | UnsafeUnzipSymlinkGood.go:52:24:52:32 | definition of candidate : string |
|
||||
| ZipSlip.go:11:2:15:2 | range statement[1] : pointer type | ZipSlip.go:12:24:12:24 | implicit dereference : File |
|
||||
| ZipSlip.go:11:2:15:2 | range statement[1] : pointer type | ZipSlip.go:12:24:12:24 | implicit read of field FileHeader : FileHeader |
|
||||
| ZipSlip.go:11:2:15:2 | range statement[1] : pointer type | ZipSlip.go:14:20:14:20 | p |
|
||||
| ZipSlip.go:12:24:12:24 | implicit dereference : File | ZipSlip.go:12:24:12:24 | implicit dereference : File |
|
||||
| ZipSlip.go:12:24:12:24 | implicit dereference : File | ZipSlip.go:12:24:12:24 | implicit read of field FileHeader : FileHeader |
|
||||
| ZipSlip.go:12:24:12:24 | implicit dereference : File | ZipSlip.go:14:20:14:20 | p |
|
||||
| ZipSlip.go:12:24:12:24 | implicit read of field FileHeader : FileHeader | ZipSlip.go:14:20:14:20 | p |
|
||||
| tarslip.go:15:2:15:30 | ... := ...[0] : pointer type | tarslip.go:16:14:16:34 | call to Dir |
|
||||
| tarslip.go:15:2:15:30 | ... := ...[0] : pointer type | tarslip.go:16:23:16:28 | implicit dereference : Header |
|
||||
| tarslip.go:16:23:16:28 | implicit dereference : Header | tarslip.go:16:14:16:34 | call to Dir |
|
||||
| tarslip.go:16:23:16:28 | implicit dereference : Header | tarslip.go:16:23:16:28 | implicit dereference : Header |
|
||||
| tst.go:23:2:43:2 | range statement[1] : pointer type | tst.go:24:11:24:11 | implicit dereference : File |
|
||||
| tst.go:23:2:43:2 | range statement[1] : pointer type | tst.go:24:11:24:11 | implicit read of field FileHeader : FileHeader |
|
||||
| tst.go:23:2:43:2 | range statement[1] : pointer type | tst.go:29:20:29:23 | path |
|
||||
| tst.go:24:11:24:11 | implicit dereference : File | tst.go:24:11:24:11 | implicit dereference : File |
|
||||
| tst.go:24:11:24:11 | implicit dereference : File | tst.go:24:11:24:11 | implicit read of field FileHeader : FileHeader |
|
||||
| tst.go:24:11:24:11 | implicit dereference : File | tst.go:29:20:29:23 | path |
|
||||
| tst.go:24:11:24:11 | implicit read of field FileHeader : FileHeader | tst.go:29:20:29:23 | path |
|
||||
nodes
|
||||
| UnsafeUnzipSymlinkGood.go:52:24:52:32 | definition of candidate : string | semmle.label | definition of candidate : string |
|
||||
| UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | semmle.label | call to Join |
|
||||
@@ -36,12 +42,14 @@ nodes
|
||||
| UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name : string | semmle.label | selection of Name : string |
|
||||
| ZipSlip.go:11:2:15:2 | range statement[1] : pointer type | semmle.label | range statement[1] : pointer type |
|
||||
| ZipSlip.go:12:24:12:24 | implicit dereference : File | semmle.label | implicit dereference : File |
|
||||
| ZipSlip.go:12:24:12:24 | implicit read of field FileHeader : FileHeader | semmle.label | implicit read of field FileHeader : FileHeader |
|
||||
| ZipSlip.go:14:20:14:20 | p | semmle.label | p |
|
||||
| tarslip.go:15:2:15:30 | ... := ...[0] : pointer type | semmle.label | ... := ...[0] : pointer type |
|
||||
| tarslip.go:16:14:16:34 | call to Dir | semmle.label | call to Dir |
|
||||
| tarslip.go:16:23:16:28 | implicit dereference : Header | semmle.label | implicit dereference : Header |
|
||||
| tst.go:23:2:43:2 | range statement[1] : pointer type | semmle.label | range statement[1] : pointer type |
|
||||
| tst.go:24:11:24:11 | implicit dereference : File | semmle.label | implicit dereference : File |
|
||||
| tst.go:24:11:24:11 | implicit read of field FileHeader : FileHeader | semmle.label | implicit read of field FileHeader : FileHeader |
|
||||
| tst.go:29:20:29:23 | path | semmle.label | path |
|
||||
#select
|
||||
| UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] : pointer type | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | Unsanitized archive entry, which may contain '..', is used in a $@. | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | file system operation |
|
||||
|
||||
Reference in New Issue
Block a user