Add implicit field reads for promoted fields

This may not work when the embedded fields are pointer types, as
we don't have anything corresponding to MkImplicitDeref
This commit is contained in:
Owen Mansel-Chan
2021-02-24 16:08:08 +00:00
parent 7ded91e81d
commit 2d3caf48c1
8 changed files with 507 additions and 23 deletions

View File

@@ -301,6 +301,22 @@ 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.
*/
MkImplicitFieldSelection(SelectorExpr e, int i, Field implicitField) {
exists(Type baseType, StructType baseStructType, Field eField, int minDepth |
eField.getAReference() = e.getSelector() and
baseType = e.getBase().getType().getUnderlyingType() and
baseStructType = [baseType, baseType.(PointerType).getBaseType().getUnderlyingType()] and
baseStructType.getFieldAtDepth(_, minDepth) = eField
|
baseStructType.getFieldAtDepth(_, i) = implicitField and
implicitField.getType().getUnderlyingType().(StructType).getFieldAtDepth(_, minDepth - i - 1) =
eField
)
} or
/**
* A control-flow node that represents the start of the execution of a function or file.
*/
@@ -1708,16 +1724,25 @@ 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
result = MkImplicitFieldSelection(this, i, _)
or
i = max(int k | k = -1 or exists(MkImplicitFieldSelection(this, k, _))) + 1 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)))
)
}
}

View File

@@ -48,7 +48,8 @@ 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`. */
@@ -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,6 +233,8 @@ module IR {
)
or
this instanceof ReadResultInstruction
or
this instanceof ImplicitFieldReadInstruction
}
}
@@ -241,9 +246,16 @@ module IR {
* `b` if there is no implicit dereferencing.
*/
private Instruction selectorBase(Expr e) {
exists(Field field | field.getAReference() = e.(SelectorExpr).getSelector() |
result = selectorBase(e, field)
)
or
exists(Expr base |
base = e.(SelectorExpr).getBase() or
base = e.(IndexExpr).getBase() or
base = e.(SelectorExpr).getBase() and
e.(SelectorExpr).getSelector() = any(Method m).getAReference()
or
base = e.(IndexExpr).getBase()
or
base = e.(SliceExpr).getBase()
|
result = MkImplicitDeref(base)
@@ -253,21 +265,51 @@ module IR {
)
}
private Instruction selectorBase(SelectorExpr se, Field field) {
exists(Type baseType, StructType baseStructType |
baseType = se.getBase().getType().getUnderlyingType() and
baseStructType = [baseType, baseType.(PointerType).getBaseType().getUnderlyingType()]
|
if field = baseStructType.getOwnField(_, _)
then
result = MkImplicitDeref(se.getBase())
or
not exists(MkImplicitDeref(se.getBase())) and
result = evalExprInstruction(se.getBase())
else
exists(ImplicitFieldReadInstruction ifri |
ifri.getSelectorExpr() = se and
ifri.getField().getType().getUnderlyingType().(StructType).getOwnField(_, _) = field
|
result = ifri
)
)
}
/**
* An IR instruction that reads a component from a composite object.
*
* 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 ImplicitFieldReadInstruction
}
/** Gets the instruction computing the base value on which the field or element is read. */
Instruction getBase() { result = selectorBase(e) }
Instruction getBase() {
result = selectorBase(this.(EvalInstruction).getExpr()) or
result =
selectorBase(this.(ImplicitFieldReadInstruction).getSelectorExpr(),
this.(ImplicitFieldReadInstruction).getField())
}
}
/**
@@ -277,12 +319,51 @@ module IR {
* misclassified as field reads.
*/
class FieldReadInstruction extends ComponentReadInstruction {
override SelectorExpr e;
SelectorExpr e;
Field field;
FieldReadInstruction() {
e = this.(EvalInstruction).getExpr() and
field.getAReference() = this.(EvalInstruction).getExpr().(SelectorExpr).getSelector()
or
e = this.(ImplicitFieldReadInstruction).getSelectorExpr() and
field = this.(ImplicitFieldReadInstruction).getField()
}
/** 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() }
override predicate readsField(Instruction base, Field f) {
base = selectorBase(e, f) and f = field
}
}
/**
* An IR instruction for an implicit field read as part of reading a promoted field.
*/
class ImplicitFieldReadInstruction extends Instruction, MkImplicitFieldSelection {
SelectorExpr e;
Field implicitField;
ImplicitFieldReadInstruction() { this = MkImplicitFieldSelection(e, _, implicitField) }
SelectorExpr getSelectorExpr() { result = e }
Field getField() { result = implicitField }
override predicate reads(ValueEntity v) { v = implicitField }
override Type getResultType() { result = implicitField.getType() }
override ControlFlow::Root getRoot() { result.isRootOf(e) }
override string toString() { result = "implicit read of field " + implicitField.toString() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
e.getBase().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
/**
@@ -308,7 +389,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. */

View File

@@ -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

View File

@@ -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"
)
}
}

View File

@@ -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 |

View File

@@ -0,0 +1,5 @@
import go
from DataFlow::Node nd, DataFlow::Node succ
where DataFlow::localFlowStep(nd, succ)
select nd, succ

View 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
}