Skip to content

Commit 7ab06fc

Browse files
authored
Merge pull request #18275 from owen-mc/go/mad/variadic-params-sources
Go: Make models-as-data source models for variadic parameters work
2 parents 0c5e260 + e9dcd69 commit 7ab06fc

File tree

7 files changed

+97
-21
lines changed

7 files changed

+97
-21
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Source models defined using models-as-data now work for variadic parameters.

go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,3 +458,13 @@ class ContentApprox = Unit;
458458
/** Gets an approximated value for content `c`. */
459459
pragma[inline]
460460
ContentApprox getContentApprox(Content c) { any() }
461+
462+
/**
463+
* Holds if the the content `c` is a container.
464+
*/
465+
predicate containerContent(ContentSet c) {
466+
c instanceof ArrayContent or
467+
c instanceof CollectionContent or
468+
c instanceof MapKeyContent or
469+
c instanceof MapValueContent
470+
}

go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,21 @@ predicate localExprTaint(Expr src, Expr sink) {
2727
* Holds if taint can flow in one local step from `src` to `sink`.
2828
*/
2929
predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
30-
DataFlow::localFlowStep(src, sink) or
31-
localAdditionalTaintStep(src, sink, _) or
30+
DataFlow::localFlowStep(src, sink)
31+
or
32+
localAdditionalTaintStep(src, sink, _)
33+
or
3234
// Simple flow through library code is included in the exposed local
3335
// step relation, even though flow is technically inter-procedural
3436
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(src, sink, _)
37+
or
38+
// Treat container flow as taint for the local taint flow relation
39+
exists(DataFlow::Content c | DataFlowPrivate::containerContent(c) |
40+
DataFlowPrivate::readStep(src, c, sink) or
41+
DataFlowPrivate::storeStep(src, c, sink) or
42+
FlowSummaryImpl::Private::Steps::summaryGetterStep(src, c, sink, _) or
43+
FlowSummaryImpl::Private::Steps::summarySetterStep(src, c, sink, _)
44+
)
3545
}
3646

3747
private Type getElementType(Type containerType) {
@@ -88,12 +98,18 @@ class AdditionalTaintStep extends Unit {
8898
*/
8999
predicate localAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ, string model) {
90100
(
91-
referenceStep(pred, succ) or
92-
elementWriteStep(pred, succ) or
93-
fieldReadStep(pred, succ) or
94-
elementStep(pred, succ) or
95-
tupleStep(pred, succ) or
96-
stringConcatStep(pred, succ) or
101+
referenceStep(pred, succ)
102+
or
103+
elementWriteStep(pred, succ)
104+
or
105+
fieldReadStep(pred, succ)
106+
or
107+
elementStep(pred, succ)
108+
or
109+
tupleStep(pred, succ)
110+
or
111+
stringConcatStep(pred, succ)
112+
or
97113
sliceStep(pred, succ)
98114
) and
99115
model = ""
@@ -163,6 +179,12 @@ predicate elementStep(DataFlow::Node pred, DataFlow::Node succ) {
163179
// only step into the value, not the index
164180
succ.asInstruction() = IR::extractTupleElement(nextEntry, 1)
165181
)
182+
or
183+
exists(DataFlow::ImplicitVarargsSlice ivs |
184+
pred.(DataFlow::PostUpdateNode).getPreUpdateNode() = ivs and
185+
succ.(DataFlow::PostUpdateNode).getPreUpdateNode() =
186+
ivs.getCallNode().getAnImplicitVarargsArgument()
187+
)
166188
}
167189

168190
/** Holds if taint flows from `pred` to `succ` via an extract tuple operation. */

go/ql/test/library-tests/semmle/go/dataflow/FlowSteps/LocalTaintStep.expected

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,36 @@
55
| main.go:38:19:38:19 | 3 | main.go:38:7:38:20 | slice literal |
66
| main.go:39:8:39:25 | []type{args} | main.go:39:8:39:25 | call to append |
77
| main.go:39:15:39:15 | s | main.go:39:8:39:25 | call to append |
8+
| main.go:39:18:39:18 | 4 | main.go:39:8:39:25 | []type{args} |
9+
| main.go:39:21:39:21 | 5 | main.go:39:8:39:25 | []type{args} |
10+
| main.go:39:24:39:24 | 6 | main.go:39:8:39:25 | []type{args} |
811
| main.go:40:15:40:15 | s | main.go:40:8:40:23 | call to append |
912
| main.go:40:18:40:19 | s1 | main.go:40:8:40:23 | call to append |
1013
| main.go:42:10:42:11 | s4 | main.go:38:2:38:2 | definition of s |
1114
| main.go:47:20:47:21 | next key-value pair in range | main.go:47:2:50:2 | range statement[0] |
1215
| main.go:47:20:47:21 | next key-value pair in range | main.go:47:2:50:2 | range statement[1] |
1316
| main.go:47:20:47:21 | xs | main.go:47:2:50:2 | range statement[1] |
17+
| main.go:56:8:56:11 | true | main.go:56:2:56:3 | ch |
18+
| main.go:57:4:57:5 | ch | main.go:57:2:57:5 | <-... |
1419
| strings.go:9:24:9:24 | s | strings.go:9:8:9:38 | call to Replace |
1520
| strings.go:9:32:9:34 | "_" | strings.go:9:8:9:38 | call to Replace |
1621
| strings.go:10:27:10:27 | s | strings.go:10:8:10:42 | call to ReplaceAll |
1722
| strings.go:10:35:10:41 | "&amp;" | strings.go:10:8:10:42 | call to ReplaceAll |
23+
| strings.go:11:9:11:26 | []type{args} | strings.go:11:9:11:26 | call to Sprint |
1824
| strings.go:11:9:11:26 | call to Sprint | strings.go:11:9:11:50 | ...+... |
1925
| strings.go:11:9:11:50 | ...+... | strings.go:11:9:11:69 | ...+... |
26+
| strings.go:11:20:11:21 | s2 | strings.go:11:9:11:26 | []type{args} |
2027
| strings.go:11:20:11:21 | s2 | strings.go:11:9:11:26 | call to Sprint |
28+
| strings.go:11:24:11:25 | s3 | strings.go:11:9:11:26 | []type{args} |
2129
| strings.go:11:24:11:25 | s3 | strings.go:11:9:11:26 | call to Sprint |
30+
| strings.go:11:30:11:50 | []type{args} | strings.go:11:30:11:50 | call to Sprintf |
2231
| strings.go:11:30:11:50 | call to Sprintf | strings.go:11:9:11:50 | ...+... |
2332
| strings.go:11:42:11:45 | "%q" | strings.go:11:30:11:50 | call to Sprintf |
33+
| strings.go:11:48:11:49 | s2 | strings.go:11:30:11:50 | []type{args} |
2434
| strings.go:11:48:11:49 | s2 | strings.go:11:30:11:50 | call to Sprintf |
35+
| strings.go:11:54:11:69 | []type{args} | strings.go:11:54:11:69 | call to Sprintln |
2536
| strings.go:11:54:11:69 | call to Sprintln | strings.go:11:9:11:69 | ...+... |
37+
| strings.go:11:67:11:68 | s3 | strings.go:11:54:11:69 | []type{args} |
2638
| strings.go:11:67:11:68 | s3 | strings.go:11:54:11:69 | call to Sprintln |
2739
| url.go:12:14:12:48 | call to PathUnescape | url.go:12:3:12:48 | ... = ...[0] |
2840
| url.go:12:14:12:48 | call to PathUnescape | url.go:12:3:12:48 | ... = ...[1] |
@@ -39,17 +51,25 @@
3951
| url.go:27:9:27:30 | call to ParseRequestURI | url.go:27:2:27:30 | ... = ...[1] |
4052
| url.go:27:29:27:29 | s | url.go:27:2:27:30 | ... = ...[0] |
4153
| url.go:28:14:28:14 | u | url.go:28:14:28:28 | call to EscapedPath |
54+
| url.go:28:14:28:28 | call to EscapedPath | url.go:28:2:28:29 | []type{args} |
4255
| url.go:29:14:29:14 | u | url.go:29:14:29:25 | call to Hostname |
56+
| url.go:29:14:29:25 | call to Hostname | url.go:29:2:29:26 | []type{args} |
4357
| url.go:30:11:30:11 | u | url.go:30:2:30:27 | ... := ...[0] |
4458
| url.go:30:11:30:27 | call to MarshalBinary | url.go:30:2:30:27 | ... := ...[0] |
4559
| url.go:30:11:30:27 | call to MarshalBinary | url.go:30:2:30:27 | ... := ...[1] |
60+
| url.go:31:2:31:16 | []type{args} | url.go:30:2:30:3 | definition of bs |
61+
| url.go:31:14:31:15 | bs | url.go:31:2:31:16 | []type{args} |
4662
| url.go:32:9:32:9 | u | url.go:32:2:32:23 | ... = ...[0] |
4763
| url.go:32:9:32:23 | call to Parse | url.go:32:2:32:23 | ... = ...[0] |
4864
| url.go:32:9:32:23 | call to Parse | url.go:32:2:32:23 | ... = ...[1] |
4965
| url.go:32:17:32:22 | "/foo" | url.go:32:2:32:23 | ... = ...[0] |
5066
| url.go:33:14:33:14 | u | url.go:33:14:33:21 | call to Port |
67+
| url.go:33:14:33:21 | call to Port | url.go:33:2:33:22 | []type{args} |
68+
| url.go:34:2:34:23 | []type{args} | url.go:34:14:34:22 | call to Query |
5169
| url.go:34:14:34:14 | u | url.go:34:14:34:22 | call to Query |
70+
| url.go:34:14:34:22 | call to Query | url.go:34:2:34:23 | []type{args} |
5271
| url.go:35:14:35:14 | u | url.go:35:14:35:27 | call to RequestURI |
72+
| url.go:35:14:35:27 | call to RequestURI | url.go:35:2:35:28 | []type{args} |
5373
| url.go:36:6:36:6 | u | url.go:36:6:36:26 | call to ResolveReference |
5474
| url.go:36:25:36:25 | u | url.go:36:6:36:26 | call to ResolveReference |
5575
| url.go:41:17:41:20 | "me" | url.go:41:8:41:21 | call to User |
@@ -58,27 +78,35 @@
5878
| url.go:43:11:43:12 | ui | url.go:43:2:43:23 | ... := ...[0] |
5979
| url.go:43:11:43:23 | call to Password | url.go:43:2:43:23 | ... := ...[0] |
6080
| url.go:43:11:43:23 | call to Password | url.go:43:2:43:23 | ... := ...[1] |
81+
| url.go:44:14:44:15 | pw | url.go:44:2:44:16 | []type{args} |
6182
| url.go:45:14:45:15 | ui | url.go:45:14:45:26 | call to Username |
83+
| url.go:45:14:45:26 | call to Username | url.go:45:2:45:27 | []type{args} |
6284
| url.go:50:10:50:26 | call to ParseQuery | url.go:50:2:50:26 | ... := ...[0] |
6385
| url.go:50:10:50:26 | call to ParseQuery | url.go:50:2:50:26 | ... := ...[1] |
6486
| url.go:50:25:50:25 | q | url.go:50:2:50:26 | ... := ...[0] |
6587
| url.go:51:14:51:14 | v | url.go:51:14:51:23 | call to Encode |
88+
| url.go:51:14:51:23 | call to Encode | url.go:51:2:51:24 | []type{args} |
6689
| url.go:52:14:52:14 | v | url.go:52:14:52:26 | call to Get |
90+
| url.go:52:14:52:26 | call to Get | url.go:52:2:52:27 | []type{args} |
6791
| url.go:57:16:57:39 | call to JoinPath | url.go:57:2:57:39 | ... := ...[0] |
6892
| url.go:57:16:57:39 | call to JoinPath | url.go:57:2:57:39 | ... := ...[1] |
6993
| url.go:57:29:57:29 | q | url.go:57:2:57:39 | ... := ...[0] |
7094
| url.go:57:32:57:38 | "clean" | url.go:57:2:57:39 | ... := ...[0] |
95+
| url.go:57:32:57:38 | "clean" | url.go:57:16:57:39 | []type{args} |
7196
| url.go:58:16:58:45 | call to JoinPath | url.go:58:2:58:45 | ... := ...[0] |
7297
| url.go:58:16:58:45 | call to JoinPath | url.go:58:2:58:45 | ... := ...[1] |
7398
| url.go:58:29:58:35 | "clean" | url.go:58:2:58:45 | ... := ...[0] |
7499
| url.go:58:38:58:44 | joined1 | url.go:58:2:58:45 | ... := ...[0] |
100+
| url.go:58:38:58:44 | joined1 | url.go:58:16:58:45 | []type{args} |
75101
| url.go:59:14:59:31 | call to Parse | url.go:59:2:59:31 | ... := ...[0] |
76102
| url.go:59:14:59:31 | call to Parse | url.go:59:2:59:31 | ... := ...[1] |
77103
| url.go:59:24:59:30 | joined2 | url.go:59:2:59:31 | ... := ...[0] |
78104
| url.go:60:15:60:19 | asUrl | url.go:60:15:60:37 | call to JoinPath |
105+
| url.go:60:30:60:36 | "clean" | url.go:60:15:60:37 | []type{args} |
79106
| url.go:60:30:60:36 | "clean" | url.go:60:15:60:37 | call to JoinPath |
80107
| url.go:65:17:65:48 | call to Parse | url.go:65:2:65:48 | ... := ...[0] |
81108
| url.go:65:17:65:48 | call to Parse | url.go:65:2:65:48 | ... := ...[1] |
82109
| url.go:65:27:65:47 | "http://harmless.org" | url.go:65:2:65:48 | ... := ...[0] |
83110
| url.go:66:9:66:16 | cleanUrl | url.go:66:9:66:28 | call to JoinPath |
111+
| url.go:66:27:66:27 | q | url.go:66:9:66:28 | []type{args} |
84112
| url.go:66:27:66:27 | q | url.go:66:9:66:28 | call to JoinPath |

go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/main.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ func main() {
4444

4545
var variadicSource string
4646
test.VariadicSource(&variadicSource)
47-
sink(variadicSource) // $ MISSING: hasTaintFlow="variadicSource"
47+
sink(variadicSource) // $ hasTaintFlow="variadicSource"
48+
sink(&variadicSource) // $ hasTaintFlow="&..."
49+
50+
var variadicSourcePtr *string
51+
test.VariadicSource(variadicSourcePtr)
52+
sink(variadicSourcePtr) // $ hasTaintFlow="variadicSourcePtr"
53+
sink(*variadicSourcePtr) // $ hasTaintFlow="star expression"
4854

4955
test.VariadicSink(source()) // $ hasTaintFlow="[]type{args}"
5056

go/ql/test/library-tests/semmle/go/frameworks/TaintSteps/TaintStep.expected

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ invalidModelRow
1010
| io.go:14:31:14:43 | "some string" | io.go:14:13:14:44 | call to NewReader |
1111
| io.go:16:3:16:3 | definition of w | io.go:16:23:16:27 | &... |
1212
| io.go:16:3:16:3 | definition of w | io.go:16:30:16:34 | &... |
13+
| io.go:16:8:16:35 | []type{args} | io.go:16:23:16:27 | &... |
14+
| io.go:16:8:16:35 | []type{args} | io.go:16:30:16:34 | &... |
1315
| io.go:16:23:16:27 | &... | io.go:15:7:15:10 | definition of buf1 |
16+
| io.go:16:23:16:27 | &... | io.go:16:8:16:35 | []type{args} |
1417
| io.go:16:24:16:27 | buf1 | io.go:16:23:16:27 | &... |
1518
| io.go:16:30:16:34 | &... | io.go:15:13:15:16 | definition of buf2 |
19+
| io.go:16:30:16:34 | &... | io.go:16:8:16:35 | []type{args} |
1620
| io.go:16:31:16:34 | buf2 | io.go:16:30:16:34 | &... |
1721
| io.go:18:14:18:19 | reader | io.go:16:3:16:3 | definition of w |
1822
| io.go:22:31:22:43 | "some string" | io.go:22:13:22:44 | call to NewReader |
@@ -27,8 +31,10 @@ invalidModelRow
2731
| io.go:39:11:39:19 | call to Pipe | io.go:39:3:39:19 | ... := ...[0] |
2832
| io.go:39:11:39:19 | call to Pipe | io.go:39:3:39:19 | ... := ...[1] |
2933
| io.go:40:17:40:31 | "some string\\n" | io.go:39:6:39:6 | definition of w |
34+
| io.go:40:17:40:31 | "some string\\n" | io.go:40:3:40:32 | []type{args} |
3035
| io.go:43:16:43:16 | r | io.go:42:3:42:5 | definition of buf |
3136
| io.go:44:13:44:15 | buf | io.go:44:13:44:24 | call to String |
37+
| io.go:44:13:44:24 | call to String | io.go:44:3:44:25 | []type{args} |
3238
| io.go:48:31:48:43 | "some string" | io.go:48:13:48:44 | call to NewReader |
3339
| io.go:50:18:50:23 | reader | io.go:49:3:49:5 | definition of buf |
3440
| io.go:54:31:54:43 | "some string" | io.go:54:13:54:44 | call to NewReader |
@@ -46,8 +52,14 @@ invalidModelRow
4652
| io.go:82:27:82:36 | "reader1 " | io.go:82:9:82:37 | call to NewReader |
4753
| io.go:83:27:83:36 | "reader2 " | io.go:83:9:83:37 | call to NewReader |
4854
| io.go:84:27:84:35 | "reader3" | io.go:84:9:84:36 | call to NewReader |
55+
| io.go:85:8:85:33 | []type{args} | io.go:82:3:82:4 | definition of r1 |
56+
| io.go:85:8:85:33 | []type{args} | io.go:83:3:83:4 | definition of r2 |
57+
| io.go:85:8:85:33 | []type{args} | io.go:84:3:84:4 | definition of r3 |
58+
| io.go:85:23:85:24 | r1 | io.go:85:8:85:33 | []type{args} |
4959
| io.go:85:23:85:24 | r1 | io.go:85:8:85:33 | call to MultiReader |
60+
| io.go:85:27:85:28 | r2 | io.go:85:8:85:33 | []type{args} |
5061
| io.go:85:27:85:28 | r2 | io.go:85:8:85:33 | call to MultiReader |
62+
| io.go:85:31:85:32 | r3 | io.go:85:8:85:33 | []type{args} |
5163
| io.go:85:31:85:32 | r3 | io.go:85:8:85:33 | call to MultiReader |
5264
| io.go:86:22:86:22 | r | io.go:86:11:86:19 | selection of Stdout |
5365
| io.go:89:26:89:38 | "some string" | io.go:89:8:89:39 | call to NewReader |

go/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,13 @@ edges
6666
| passwords.go:34:28:34:35 | password | passwords.go:34:14:34:35 | ...+... | provenance | Config |
6767
| passwords.go:36:2:36:5 | definition of obj1 | passwords.go:39:14:39:17 | obj1 | provenance | |
6868
| passwords.go:36:2:36:5 | definition of obj1 | passwords.go:39:14:39:17 | obj1 | provenance | |
69-
| passwords.go:36:10:38:2 | struct literal | passwords.go:39:14:39:17 | obj1 | provenance | |
70-
| passwords.go:36:10:38:2 | struct literal | passwords.go:39:14:39:17 | obj1 | provenance | |
69+
| passwords.go:36:10:38:2 | struct literal | passwords.go:36:2:36:5 | definition of obj1 | provenance | |
7170
| passwords.go:37:13:37:13 | x | passwords.go:36:10:38:2 | struct literal | provenance | Config |
7271
| passwords.go:39:2:39:18 | []type{args} [array] | passwords.go:36:2:36:5 | definition of obj1 | provenance | |
7372
| passwords.go:39:14:39:17 | obj1 | passwords.go:39:2:39:18 | []type{args} [array] | provenance | |
7473
| passwords.go:41:2:41:5 | definition of obj2 | passwords.go:44:14:44:17 | obj2 | provenance | |
7574
| passwords.go:41:2:41:5 | definition of obj2 | passwords.go:44:14:44:17 | obj2 | provenance | |
76-
| passwords.go:41:10:43:2 | struct literal | passwords.go:44:14:44:17 | obj2 | provenance | |
77-
| passwords.go:41:10:43:2 | struct literal | passwords.go:44:14:44:17 | obj2 | provenance | |
75+
| passwords.go:41:10:43:2 | struct literal | passwords.go:41:2:41:5 | definition of obj2 | provenance | |
7876
| passwords.go:42:6:42:13 | password | passwords.go:41:10:43:2 | struct literal | provenance | Config |
7977
| passwords.go:44:2:44:18 | []type{args} [array] | passwords.go:41:2:41:5 | definition of obj2 | provenance | |
8078
| passwords.go:44:14:44:17 | obj2 | passwords.go:44:2:44:18 | []type{args} [array] | provenance | |
@@ -85,8 +83,7 @@ edges
8583
| passwords.go:48:11:48:18 | password | passwords.go:46:6:46:9 | definition of obj3 | provenance | Config |
8684
| passwords.go:85:2:85:14 | definition of utilityObject | passwords.go:88:14:88:26 | utilityObject | provenance | |
8785
| passwords.go:85:2:85:14 | definition of utilityObject | passwords.go:88:14:88:26 | utilityObject | provenance | |
88-
| passwords.go:85:19:87:2 | struct literal | passwords.go:88:14:88:26 | utilityObject | provenance | |
89-
| passwords.go:85:19:87:2 | struct literal | passwords.go:88:14:88:26 | utilityObject | provenance | |
86+
| passwords.go:85:19:87:2 | struct literal | passwords.go:85:2:85:14 | definition of utilityObject | provenance | |
9087
| passwords.go:86:16:86:36 | call to make | passwords.go:85:19:87:2 | struct literal | provenance | Config |
9188
| passwords.go:88:2:88:27 | []type{args} [array] | passwords.go:85:2:85:14 | definition of utilityObject | provenance | |
9289
| passwords.go:88:14:88:26 | utilityObject | passwords.go:88:2:88:27 | []type{args} [array] | provenance | |
@@ -102,12 +99,9 @@ edges
10299
| passwords.go:118:2:118:7 | definition of config [x] | passwords.go:126:14:126:19 | config [x] | provenance | |
103100
| passwords.go:118:2:118:7 | definition of config [y] | passwords.go:125:14:125:19 | config [y] | provenance | |
104101
| passwords.go:118:2:118:7 | definition of config [y] | passwords.go:127:14:127:19 | config [y] | provenance | |
105-
| passwords.go:118:12:123:2 | struct literal | passwords.go:125:14:125:19 | config | provenance | |
106-
| passwords.go:118:12:123:2 | struct literal | passwords.go:125:14:125:19 | config | provenance | |
107-
| passwords.go:118:12:123:2 | struct literal [x] | passwords.go:125:14:125:19 | config [x] | provenance | |
108-
| passwords.go:118:12:123:2 | struct literal [x] | passwords.go:126:14:126:19 | config [x] | provenance | |
109-
| passwords.go:118:12:123:2 | struct literal [y] | passwords.go:125:14:125:19 | config [y] | provenance | |
110-
| passwords.go:118:12:123:2 | struct literal [y] | passwords.go:127:14:127:19 | config [y] | provenance | |
102+
| passwords.go:118:12:123:2 | struct literal | passwords.go:118:2:118:7 | definition of config | provenance | |
103+
| passwords.go:118:12:123:2 | struct literal [x] | passwords.go:118:2:118:7 | definition of config [x] | provenance | |
104+
| passwords.go:118:12:123:2 | struct literal [y] | passwords.go:118:2:118:7 | definition of config [y] | provenance | |
111105
| passwords.go:119:13:119:13 | x | passwords.go:118:12:123:2 | struct literal | provenance | Config |
112106
| passwords.go:121:13:121:20 | password | passwords.go:118:12:123:2 | struct literal | provenance | Config |
113107
| passwords.go:121:13:121:20 | password | passwords.go:118:12:123:2 | struct literal [x] | provenance | |

0 commit comments

Comments
 (0)