зеркало из https://github.com/github/codeql.git
Merge pull request #15230 from geoffw0/swiftui
Swift: Add dataflow tests for property wrappers and SwiftUI
This commit is contained in:
Коммит
2f6f376d2d
|
@ -1,5 +1,8 @@
|
|||
edges
|
||||
| file://:0:0:0:0 | .wrappedValue | test.swift:949:15:949:15 | x |
|
||||
| file://:0:0:0:0 | .wrappedValue | test.swift:951:15:951:15 | x |
|
||||
| file://:0:0:0:0 | KeyPathComponent [some:0] | test.swift:663:13:663:29 | exit #keyPath(...) [some:0] |
|
||||
| file://:0:0:0:0 | [post] self [wrappedValue] | file://:0:0:0:0 | self [wrappedValue] |
|
||||
| file://:0:0:0:0 | self [a, x] | file://:0:0:0:0 | .a [x] |
|
||||
| file://:0:0:0:0 | self [s, x] | file://:0:0:0:0 | .s [x] |
|
||||
| file://:0:0:0:0 | self [str] | file://:0:0:0:0 | .str |
|
||||
|
@ -7,6 +10,7 @@ edges
|
|||
| file://:0:0:0:0 | self [v2] | file://:0:0:0:0 | .v2 |
|
||||
| file://:0:0:0:0 | self [v3] | file://:0:0:0:0 | .v3 |
|
||||
| file://:0:0:0:0 | self [v] | file://:0:0:0:0 | .v |
|
||||
| file://:0:0:0:0 | self [wrappedValue] | test.swift:958:9:958:9 | self [wrappedValue] |
|
||||
| file://:0:0:0:0 | self [x, some:0] | file://:0:0:0:0 | .x [some:0] |
|
||||
| file://:0:0:0:0 | self [x] | file://:0:0:0:0 | .x |
|
||||
| file://:0:0:0:0 | self [x] | file://:0:0:0:0 | .x |
|
||||
|
@ -14,8 +18,12 @@ edges
|
|||
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [v2] |
|
||||
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [v3] |
|
||||
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [v] |
|
||||
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [wrappedValue] |
|
||||
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [x] |
|
||||
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [x] |
|
||||
| file://:0:0:0:0 | value | test.swift:938:9:938:9 | newValue |
|
||||
| file://:0:0:0:0 | value | test.swift:957:9:957:9 | value |
|
||||
| file://:0:0:0:0 | value | test.swift:965:9:965:9 | newValue |
|
||||
| file://:0:0:0:0 | value [some:0] | file://:0:0:0:0 | [post] self [v2, some:0] |
|
||||
| file://:0:0:0:0 | value [some:0] | file://:0:0:0:0 | [post] self [x, some:0] |
|
||||
| test.swift:6:19:6:26 | call to source() | test.swift:7:15:7:15 | t1 |
|
||||
|
@ -606,6 +614,24 @@ edges
|
|||
| test.swift:908:19:908:26 | call to source() | test.swift:904:13:904:18 | call to ... |
|
||||
| test.swift:927:12:927:31 | call to source(_:) | test.swift:927:12:927:31 | OpenExistentialExpr |
|
||||
| test.swift:929:12:929:57 | call to source(_:) | test.swift:929:12:929:57 | OpenExistentialExpr |
|
||||
| test.swift:937:22:937:29 | call to source() | file://:0:0:0:0 | .wrappedValue |
|
||||
| test.swift:938:9:938:9 | newValue | test.swift:938:25:938:25 | newValue |
|
||||
| test.swift:941:10:941:24 | wrappedValue | test.swift:942:19:942:19 | wrappedValue |
|
||||
| test.swift:943:29:943:36 | call to source() | test.swift:938:9:938:9 | newValue |
|
||||
| test.swift:948:33:948:33 | value | file://:0:0:0:0 | value |
|
||||
| test.swift:948:42:948:49 | call to source() | test.swift:941:10:941:24 | wrappedValue |
|
||||
| test.swift:950:9:950:16 | call to source() | test.swift:948:33:948:33 | value |
|
||||
| test.swift:957:9:957:9 | value | file://:0:0:0:0 | value |
|
||||
| test.swift:958:9:958:9 | self [wrappedValue] | test.swift:959:23:959:23 | self [wrappedValue] |
|
||||
| test.swift:959:23:959:23 | self [wrappedValue] | test.swift:959:23:959:23 | .wrappedValue |
|
||||
| test.swift:965:9:965:9 | newValue | test.swift:967:28:967:28 | newValue |
|
||||
| test.swift:967:28:967:28 | newValue | test.swift:957:9:957:9 | value |
|
||||
| test.swift:971:10:971:24 | wrappedValue | test.swift:972:19:972:19 | wrappedValue |
|
||||
| test.swift:978:34:978:34 | value | file://:0:0:0:0 | value |
|
||||
| test.swift:980:9:980:16 | call to source() | test.swift:978:34:978:34 | value |
|
||||
| test.swift:983:38:983:45 | call to source() | test.swift:971:10:971:24 | wrappedValue |
|
||||
| test.swift:988:34:988:34 | value | file://:0:0:0:0 | value |
|
||||
| test.swift:991:10:991:17 | call to source() | test.swift:988:34:988:34 | value |
|
||||
nodes
|
||||
| file://:0:0:0:0 | .a [x] | semmle.label | .a [x] |
|
||||
| file://:0:0:0:0 | .s [x] | semmle.label | .s [x] |
|
||||
|
@ -614,6 +640,7 @@ nodes
|
|||
| file://:0:0:0:0 | .v2 | semmle.label | .v2 |
|
||||
| file://:0:0:0:0 | .v2 [some:0] | semmle.label | .v2 [some:0] |
|
||||
| file://:0:0:0:0 | .v3 | semmle.label | .v3 |
|
||||
| file://:0:0:0:0 | .wrappedValue | semmle.label | .wrappedValue |
|
||||
| file://:0:0:0:0 | .x | semmle.label | .x |
|
||||
| file://:0:0:0:0 | .x | semmle.label | .x |
|
||||
| file://:0:0:0:0 | .x | semmle.label | .x |
|
||||
|
@ -623,6 +650,7 @@ nodes
|
|||
| file://:0:0:0:0 | [post] self [v2] | semmle.label | [post] self [v2] |
|
||||
| file://:0:0:0:0 | [post] self [v3] | semmle.label | [post] self [v3] |
|
||||
| file://:0:0:0:0 | [post] self [v] | semmle.label | [post] self [v] |
|
||||
| file://:0:0:0:0 | [post] self [wrappedValue] | semmle.label | [post] self [wrappedValue] |
|
||||
| file://:0:0:0:0 | [post] self [x, some:0] | semmle.label | [post] self [x, some:0] |
|
||||
| file://:0:0:0:0 | [post] self [x] | semmle.label | [post] self [x] |
|
||||
| file://:0:0:0:0 | [post] self [x] | semmle.label | [post] self [x] |
|
||||
|
@ -633,6 +661,7 @@ nodes
|
|||
| file://:0:0:0:0 | self [v2] | semmle.label | self [v2] |
|
||||
| file://:0:0:0:0 | self [v3] | semmle.label | self [v3] |
|
||||
| file://:0:0:0:0 | self [v] | semmle.label | self [v] |
|
||||
| file://:0:0:0:0 | self [wrappedValue] | semmle.label | self [wrappedValue] |
|
||||
| file://:0:0:0:0 | self [x, some:0] | semmle.label | self [x, some:0] |
|
||||
| file://:0:0:0:0 | self [x] | semmle.label | self [x] |
|
||||
| file://:0:0:0:0 | self [x] | semmle.label | self [x] |
|
||||
|
@ -642,6 +671,10 @@ nodes
|
|||
| file://:0:0:0:0 | value | semmle.label | value |
|
||||
| file://:0:0:0:0 | value | semmle.label | value |
|
||||
| file://:0:0:0:0 | value | semmle.label | value |
|
||||
| file://:0:0:0:0 | value | semmle.label | value |
|
||||
| file://:0:0:0:0 | value | semmle.label | value |
|
||||
| file://:0:0:0:0 | value | semmle.label | value |
|
||||
| file://:0:0:0:0 | value | semmle.label | value |
|
||||
| file://:0:0:0:0 | value [some:0] | semmle.label | value [some:0] |
|
||||
| file://:0:0:0:0 | value [some:0] | semmle.label | value [some:0] |
|
||||
| test.swift:6:19:6:26 | call to source() | semmle.label | call to source() |
|
||||
|
@ -1262,6 +1295,30 @@ nodes
|
|||
| test.swift:929:12:929:57 | OpenExistentialExpr | semmle.label | OpenExistentialExpr |
|
||||
| test.swift:929:12:929:57 | call to source(_:) | semmle.label | call to source(_:) |
|
||||
| test.swift:930:12:930:65 | call to source(_:) | semmle.label | call to source(_:) |
|
||||
| test.swift:937:22:937:29 | call to source() | semmle.label | call to source() |
|
||||
| test.swift:938:9:938:9 | newValue | semmle.label | newValue |
|
||||
| test.swift:938:25:938:25 | newValue | semmle.label | newValue |
|
||||
| test.swift:941:10:941:24 | wrappedValue | semmle.label | wrappedValue |
|
||||
| test.swift:942:19:942:19 | wrappedValue | semmle.label | wrappedValue |
|
||||
| test.swift:943:29:943:36 | call to source() | semmle.label | call to source() |
|
||||
| test.swift:948:33:948:33 | value | semmle.label | value |
|
||||
| test.swift:948:42:948:49 | call to source() | semmle.label | call to source() |
|
||||
| test.swift:949:15:949:15 | x | semmle.label | x |
|
||||
| test.swift:950:9:950:16 | call to source() | semmle.label | call to source() |
|
||||
| test.swift:951:15:951:15 | x | semmle.label | x |
|
||||
| test.swift:957:9:957:9 | value | semmle.label | value |
|
||||
| test.swift:958:9:958:9 | self [wrappedValue] | semmle.label | self [wrappedValue] |
|
||||
| test.swift:959:23:959:23 | .wrappedValue | semmle.label | .wrappedValue |
|
||||
| test.swift:959:23:959:23 | self [wrappedValue] | semmle.label | self [wrappedValue] |
|
||||
| test.swift:965:9:965:9 | newValue | semmle.label | newValue |
|
||||
| test.swift:967:28:967:28 | newValue | semmle.label | newValue |
|
||||
| test.swift:971:10:971:24 | wrappedValue | semmle.label | wrappedValue |
|
||||
| test.swift:972:19:972:19 | wrappedValue | semmle.label | wrappedValue |
|
||||
| test.swift:978:34:978:34 | value | semmle.label | value |
|
||||
| test.swift:980:9:980:16 | call to source() | semmle.label | call to source() |
|
||||
| test.swift:983:38:983:45 | call to source() | semmle.label | call to source() |
|
||||
| test.swift:988:34:988:34 | value | semmle.label | value |
|
||||
| test.swift:991:10:991:17 | call to source() | semmle.label | call to source() |
|
||||
subpaths
|
||||
| test.swift:75:22:75:22 | x | test.swift:65:16:65:28 | arg1 | test.swift:65:1:70:1 | arg2[return] | test.swift:75:32:75:32 | [post] y |
|
||||
| test.swift:114:19:114:19 | arg | test.swift:109:9:109:14 | arg | test.swift:110:12:110:12 | arg | test.swift:114:12:114:22 | call to ... |
|
||||
|
@ -1463,3 +1520,11 @@ subpaths
|
|||
| test.swift:928:12:928:31 | call to source(_:) | test.swift:928:12:928:31 | call to source(_:) | test.swift:928:12:928:31 | call to source(_:) | result |
|
||||
| test.swift:929:12:929:57 | OpenExistentialExpr | test.swift:929:12:929:57 | call to source(_:) | test.swift:929:12:929:57 | OpenExistentialExpr | result |
|
||||
| test.swift:930:12:930:65 | call to source(_:) | test.swift:930:12:930:65 | call to source(_:) | test.swift:930:12:930:65 | call to source(_:) | result |
|
||||
| test.swift:938:25:938:25 | newValue | test.swift:943:29:943:36 | call to source() | test.swift:938:25:938:25 | newValue | result |
|
||||
| test.swift:938:25:938:25 | newValue | test.swift:950:9:950:16 | call to source() | test.swift:938:25:938:25 | newValue | result |
|
||||
| test.swift:942:19:942:19 | wrappedValue | test.swift:948:42:948:49 | call to source() | test.swift:942:19:942:19 | wrappedValue | result |
|
||||
| test.swift:949:15:949:15 | x | test.swift:937:22:937:29 | call to source() | test.swift:949:15:949:15 | x | result |
|
||||
| test.swift:951:15:951:15 | x | test.swift:937:22:937:29 | call to source() | test.swift:951:15:951:15 | x | result |
|
||||
| test.swift:959:23:959:23 | .wrappedValue | test.swift:980:9:980:16 | call to source() | test.swift:959:23:959:23 | .wrappedValue | result |
|
||||
| test.swift:959:23:959:23 | .wrappedValue | test.swift:991:10:991:17 | call to source() | test.swift:959:23:959:23 | .wrappedValue | result |
|
||||
| test.swift:972:19:972:19 | wrappedValue | test.swift:983:38:983:45 | call to source() | test.swift:972:19:972:19 | wrappedValue | result |
|
||||
|
|
|
@ -1165,3 +1165,57 @@
|
|||
| test.swift:926:45:926:48 | y | test.swift:926:45:926:48 | SSA def(y) |
|
||||
| test.swift:927:12:927:31 | call to source(_:) | test.swift:927:12:927:31 | OpenExistentialExpr |
|
||||
| test.swift:929:12:929:57 | call to source(_:) | test.swift:929:12:929:57 | OpenExistentialExpr |
|
||||
| test.swift:936:9:936:9 | self | test.swift:936:9:936:9 | SSA def(self) |
|
||||
| test.swift:937:9:937:9 | SSA def(self) | test.swift:937:9:937:31 | self[return] |
|
||||
| test.swift:937:9:937:9 | self | test.swift:937:9:937:9 | SSA def(self) |
|
||||
| test.swift:938:9:938:9 | SSA def(newValue) | test.swift:938:25:938:25 | newValue |
|
||||
| test.swift:938:9:938:9 | SSA def(self) | test.swift:938:9:938:35 | self[return] |
|
||||
| test.swift:938:9:938:9 | newValue | test.swift:938:9:938:9 | SSA def(newValue) |
|
||||
| test.swift:938:9:938:9 | self | test.swift:938:9:938:9 | SSA def(self) |
|
||||
| test.swift:941:5:941:5 | SSA def(self) | test.swift:943:9:943:9 | self |
|
||||
| test.swift:941:5:941:5 | self | test.swift:941:5:941:5 | SSA def(self) |
|
||||
| test.swift:941:10:941:24 | SSA def(wrappedValue) | test.swift:942:19:942:19 | wrappedValue |
|
||||
| test.swift:941:10:941:24 | wrappedValue | test.swift:941:10:941:24 | SSA def(wrappedValue) |
|
||||
| test.swift:943:9:943:9 | [post] self | test.swift:941:5:944:5 | self[return] |
|
||||
| test.swift:943:9:943:9 | self | test.swift:941:5:944:5 | self[return] |
|
||||
| test.swift:948:6:948:49 | call to MyTaintPropertyWrapper.init(wrappedValue:) | test.swift:948:33:948:36 | ... as ... |
|
||||
| test.swift:948:33:948:33 | value | test.swift:948:33:948:33 | SSA def(value) |
|
||||
| test.swift:948:33:948:36 | ... as ... | test.swift:948:33:948:33 | x |
|
||||
| test.swift:957:9:957:9 | self | test.swift:957:9:957:9 | SSA def(self) |
|
||||
| test.swift:957:9:957:9 | self | test.swift:957:9:957:9 | SSA def(self) |
|
||||
| test.swift:957:9:957:9 | self | test.swift:957:9:957:9 | SSA def(self) |
|
||||
| test.swift:957:9:957:9 | value | test.swift:957:9:957:9 | SSA def(value) |
|
||||
| test.swift:958:9:958:9 | SSA def(self) | test.swift:959:23:959:23 | self |
|
||||
| test.swift:958:9:958:9 | self | test.swift:958:9:958:9 | SSA def(self) |
|
||||
| test.swift:959:23:959:23 | [post] self | test.swift:958:9:960:9 | self[return] |
|
||||
| test.swift:959:23:959:23 | self | test.swift:958:9:960:9 | self[return] |
|
||||
| test.swift:963:9:963:9 | self | test.swift:963:9:963:9 | SSA def(self) |
|
||||
| test.swift:964:9:964:9 | SSA def(self) | test.swift:964:15:964:15 | self |
|
||||
| test.swift:964:9:964:9 | self | test.swift:964:9:964:9 | SSA def(self) |
|
||||
| test.swift:964:15:964:15 | [post] self | test.swift:964:9:964:28 | self[return] |
|
||||
| test.swift:964:15:964:15 | self | test.swift:964:9:964:28 | self[return] |
|
||||
| test.swift:965:9:965:9 | SSA def(newValue) | test.swift:967:28:967:28 | newValue |
|
||||
| test.swift:965:9:965:9 | SSA def(self) | test.swift:966:23:966:23 | self |
|
||||
| test.swift:965:9:965:9 | newValue | test.swift:965:9:965:9 | SSA def(newValue) |
|
||||
| test.swift:965:9:965:9 | self | test.swift:965:9:965:9 | SSA def(self) |
|
||||
| test.swift:966:23:966:23 | [post] self | test.swift:967:13:967:13 | self |
|
||||
| test.swift:966:23:966:23 | self | test.swift:967:13:967:13 | self |
|
||||
| test.swift:967:13:967:13 | [post] self | test.swift:965:9:968:9 | self[return] |
|
||||
| test.swift:967:13:967:13 | self | test.swift:965:9:968:9 | self[return] |
|
||||
| test.swift:971:5:971:5 | SSA def(self) | test.swift:973:9:973:9 | self |
|
||||
| test.swift:971:5:971:5 | self | test.swift:971:5:971:5 | SSA def(self) |
|
||||
| test.swift:971:10:971:24 | SSA def(wrappedValue) | test.swift:972:19:972:19 | wrappedValue |
|
||||
| test.swift:971:10:971:24 | wrappedValue | test.swift:971:10:971:24 | SSA def(wrappedValue) |
|
||||
| test.swift:972:19:972:19 | [post] wrappedValue | test.swift:973:29:973:29 | wrappedValue |
|
||||
| test.swift:972:19:972:19 | wrappedValue | test.swift:973:29:973:29 | wrappedValue |
|
||||
| test.swift:973:9:973:9 | [post] self | test.swift:971:5:974:5 | self[return] |
|
||||
| test.swift:973:9:973:9 | self | test.swift:971:5:974:5 | self[return] |
|
||||
| test.swift:978:6:978:38 | call to MySimplePropertyWrapper.init(wrappedValue:) | test.swift:978:34:978:34 | a |
|
||||
| test.swift:978:34:978:34 | value | test.swift:978:34:978:34 | SSA def(value) |
|
||||
| test.swift:978:34:978:34 | value | test.swift:978:34:978:34 | SSA def(value) |
|
||||
| test.swift:983:6:983:45 | call to MySimplePropertyWrapper.init(wrappedValue:) | test.swift:983:34:983:34 | b |
|
||||
| test.swift:983:34:983:34 | value | test.swift:983:34:983:34 | SSA def(value) |
|
||||
| test.swift:983:34:983:34 | value | test.swift:983:34:983:34 | SSA def(value) |
|
||||
| test.swift:988:6:988:38 | call to MySimplePropertyWrapper.init(wrappedValue:) | test.swift:988:34:988:34 | c |
|
||||
| test.swift:988:34:988:34 | value | test.swift:988:34:988:34 | SSA def(value) |
|
||||
| test.swift:988:34:988:34 | value | test.swift:988:34:988:34 | SSA def(value) |
|
||||
|
|
|
@ -931,3 +931,64 @@ func testOpenExistentialExpr(x: MyProtocol, y: MyProcotolImpl) {
|
|||
}
|
||||
|
||||
// ---
|
||||
|
||||
@propertyWrapper struct MyTaintPropertyWrapper {
|
||||
var wrappedValue: Int {
|
||||
get { return source() }
|
||||
set { sink(arg: newValue) } // $ flow=943 flow=950
|
||||
}
|
||||
|
||||
init(wrappedValue: Int) {
|
||||
sink(arg: wrappedValue) // $ flow=948
|
||||
self.wrappedValue = source()
|
||||
}
|
||||
}
|
||||
|
||||
func test_my_taint_property_wrapper() {
|
||||
@MyTaintPropertyWrapper var x: Int = source()
|
||||
sink(arg: x) // $ flow=937
|
||||
x = source()
|
||||
sink(arg: x) // $ flow=937
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
@propertyWrapper struct MySimplePropertyWrapper {
|
||||
var wrappedValue: Int {
|
||||
didSet {
|
||||
sink(arg: wrappedValue) // $ flow=980 flow=991
|
||||
}
|
||||
}
|
||||
|
||||
var projectedValue: Int {
|
||||
get { wrappedValue }
|
||||
set {
|
||||
sink(arg: wrappedValue) // $ MISSING: flow=991
|
||||
wrappedValue = newValue
|
||||
}
|
||||
}
|
||||
|
||||
init(wrappedValue: Int) {
|
||||
sink(arg: wrappedValue) // $ flow=983
|
||||
self.wrappedValue = wrappedValue
|
||||
}
|
||||
}
|
||||
|
||||
func test_my_property_wrapper() {
|
||||
@MySimplePropertyWrapper var a = 0
|
||||
sink(arg: a)
|
||||
a = source()
|
||||
sink(arg: a) // $ MISSING: flow=980
|
||||
|
||||
@MySimplePropertyWrapper var b = source()
|
||||
sink(arg: b) // $ MISSING: flow=983
|
||||
b = 0
|
||||
sink(arg: b)
|
||||
|
||||
@MySimplePropertyWrapper var c = 0
|
||||
sink(arg: c)
|
||||
sink(arg: $c)
|
||||
$c = source()
|
||||
sink(arg: c) // $ MISSING: flow=991
|
||||
sink(arg: $c) // $ MISSING: flow=991
|
||||
}
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
|
||||
// --- stubs ---
|
||||
|
||||
protocol View {
|
||||
}
|
||||
|
||||
struct Binding<Value> {
|
||||
}
|
||||
|
||||
@propertyWrapper
|
||||
struct State<Value> { // an @State
|
||||
var wrappedValue: Value
|
||||
var projectedValue: Binding<Value> { get { return 0 as! Binding<Value> } } // what you get with `$`
|
||||
}
|
||||
|
||||
struct LocalizedStringKey : ExpressibleByStringLiteral {
|
||||
typealias StringLiteralType = String
|
||||
|
||||
init(stringLiteral value: Self.StringLiteralType) {
|
||||
}
|
||||
}
|
||||
|
||||
struct Label<Title, Icon> : View where Title : View, Icon : View {
|
||||
}
|
||||
|
||||
struct Text : View {
|
||||
}
|
||||
|
||||
struct TextField<Label> : View where Label : View {
|
||||
init(_ titleKey: LocalizedStringKey, text: Binding<String>) where Label == Text { }
|
||||
}
|
||||
|
||||
struct SecureField<Label> : View where Label : View {
|
||||
init(_ titleKey: LocalizedStringKey, text: Binding<String>, prompt: Text?) where Label == Text { }
|
||||
}
|
||||
|
||||
struct TextEditor : View {
|
||||
init(text: Binding<String>) { }
|
||||
}
|
||||
|
||||
struct SubmitTriggers {
|
||||
init(rawValue: UInt) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
var rawValue: UInt
|
||||
|
||||
static let text = SubmitTriggers(rawValue: 1)
|
||||
}
|
||||
|
||||
extension View {
|
||||
func onSubmit(
|
||||
of triggers: SubmitTriggers = .text,
|
||||
_ action: @escaping (() -> Void)
|
||||
) -> some View {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
// --- tests ---
|
||||
|
||||
func sink(arg: Any) { }
|
||||
|
||||
func mkHarmlessBinding(text: Binding<String>) { }
|
||||
|
||||
struct MyStruct {
|
||||
@State var input: String = "default value"
|
||||
@State var harmless: String = "default value"
|
||||
@State var harmless2: String = "default value"
|
||||
|
||||
var myView1: some View {
|
||||
TextField("title", text: $input)
|
||||
.onSubmit {
|
||||
sink(arg: input) // $ MISSING: tainted
|
||||
sink(arg: harmless)
|
||||
mkHarmlessBinding(text: $harmless2)
|
||||
sink(arg: harmless2)
|
||||
}
|
||||
}
|
||||
|
||||
@State var secureInput: String = "default value"
|
||||
|
||||
var myView2: some View {
|
||||
SecureField("title", text: $secureInput, prompt: nil)
|
||||
.onSubmit {
|
||||
sink(arg: secureInput) // $ MISSING: tainted
|
||||
}
|
||||
}
|
||||
|
||||
@State var longInput: String = "default value"
|
||||
|
||||
var myView3: some View {
|
||||
TextEditor(text: $longInput)
|
||||
.onSubmit {
|
||||
sink(arg: longInput) // $ MISSING: tainted
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
|
||||
// --- stubs ---
|
||||
|
||||
protocol View {
|
||||
}
|
||||
|
||||
struct Binding<Value> {
|
||||
}
|
||||
|
||||
@propertyWrapper
|
||||
struct State<Value> { // an @State
|
||||
var wrappedValue: Value
|
||||
var projectedValue: Binding<Value> { get { return 0 as! Binding<Value> } } // what you get with `$`
|
||||
}
|
||||
|
||||
struct LocalizedStringKey : ExpressibleByStringLiteral {
|
||||
typealias StringLiteralType = String
|
||||
|
||||
init(stringLiteral value: Self.StringLiteralType) {
|
||||
}
|
||||
}
|
||||
|
||||
struct Label<Title, Icon> : View where Title : View, Icon : View {
|
||||
}
|
||||
|
||||
struct Text : View {
|
||||
}
|
||||
|
||||
struct TextField<Label> : View where Label : View {
|
||||
init(_ titleKey: LocalizedStringKey, text: Binding<String>) where Label == Text { }
|
||||
}
|
||||
|
||||
struct SecureField<Label> : View where Label : View {
|
||||
init(_ titleKey: LocalizedStringKey, text: Binding<String>, prompt: Text?) where Label == Text { }
|
||||
}
|
||||
|
||||
struct SubmitTriggers {
|
||||
init(rawValue: UInt) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
var rawValue: UInt
|
||||
|
||||
static let text = SubmitTriggers(rawValue: 1)
|
||||
}
|
||||
|
||||
extension View {
|
||||
func onSubmit(
|
||||
of triggers: SubmitTriggers = .text,
|
||||
_ action: @escaping (() -> Void)
|
||||
) -> some View {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
struct URL
|
||||
{
|
||||
init?(string: String) {}
|
||||
init?(string: String, relativeTo: URL?) {}
|
||||
}
|
||||
|
||||
// --- tests ---
|
||||
|
||||
func mkHarmlessBinding(text: Binding<String>) { }
|
||||
|
||||
struct MyStruct {
|
||||
@State var textInput: String = "default value"
|
||||
@State var secureInput: String = "default value"
|
||||
|
||||
var myView1: some View {
|
||||
TextField("title", text: $textInput)
|
||||
.onSubmit {
|
||||
_ = URL(string: "http://example.com/page?text=\(textInput)"); // GOOD (not sensitive)
|
||||
}
|
||||
}
|
||||
|
||||
var myView2: some View {
|
||||
SecureField("title", text: $secureInput, prompt: nil)
|
||||
.onSubmit {
|
||||
_ = URL(string: "http://example.com/login?key=\(secureInput)"); // BAD [NOT DETECTED]
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче