Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-7573] Overridden class function with generic constraint causes unsafe behavior #50115

Closed
swift-ci opened this issue Apr 30, 2018 · 4 comments
Closed

Comments

@swift-ci
Copy link
Collaborator

@swift-ci swift-ci commented Apr 30, 2018

Previous ID SR-7573
Radar rdar://problem/39868032
Original Reporter benpious (JIRA User)
Type Bug
Status Resolved
Resolution Duplicate
Environment

Xcode 9.3, tested in a playground.

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, AcceptsInvalid
Assignee None
Priority Medium

md5: c5c2fa906d0f758365411aed2ecf1e4d

duplicates:

  • SR-4206 Override checking does not properly enforce requirements

Issue Description:

Class C defines a function f. Class D overrides it, but has a different generic constraint. Calling f from an instance of C using type(of:) type-checks as though C.f will be called, but at runtime D.f is called.

class C<T> {
    
    let t: T
    
    init(t: T) {
        self.t = t
        type(of: self).f()(self)
    }
    
    class func f<U>() -> (U) -> () where U: C  {
        return { (u: U) in
            print(u.t)
        }
    }
}

class E {
    let g = "Expected to Print"
}

class D: C<E> {
    override class func f<U>() -> (U) -> () where U: E {
        return { (u: E) in
            print(u.g)
        }
    }
}

let d = D(t: E()) // prints random garbage

Because D.f tries to access a member of E, the program reads random memory, leading to undefined behavior.

As an aside, the ability to tighten type constraints on overrides is actually very useful in the context of the code I was working on when I discovered this. I'd like to be able to write things like var functionToRunWhenSomethingChanges: (Self, Context) -> (), which creates similar issues to this when used in the context of classes. So my solution was to make var functionToRunWhenSomethingChanges: (Any, Context) -> (), and have a setFunctionToRunWhenSomethingChanges<T>(on subject: T, _ function: (T, Context) -> ()), which ensures that things are still type safe. So It's useful to be able to add generic constraints that require that a particular class func only works for subclasses of the type that it's implemented for. Hopefully when/if this is fixed it's still possible to do that.

@belkadan
Copy link
Contributor

@belkadan belkadan commented May 1, 2018

Yikes! Thanks, Ben.

@swift-ci create

@belkadan
Copy link
Contributor

@belkadan belkadan commented May 1, 2018

cc @huonw

@huonw
Copy link
Mannequin

@huonw huonw mannequin commented May 8, 2018

With compiler/runtime assertions on this gives:

Fatal error: invalid unsafeDowncast: file /Users/huon/projects/swift4/swift/stdlib/public/core/Builtin.swift, line 253
Current stack trace:
0    libswiftCore.dylib                 0x00000001012c73f0 _swift_stdlib_reportFatalErrorInFile + 214
1    libswiftCore.dylib                 0x0000000101249e00 partial apply for closure #&#8203;1 in closure #&#8203;1 in closure #&#8203;1 in _fatalErrorMessage(_:_:file:line:flags:) + 364
2    libswiftCore.dylib                 0x0000000101249b20 partial apply for closure #&#8203;1 in closure #&#8203;1 in closure #&#8203;1 in _fatalErrorMessage(_:_:file:line:flags:) + 25
3    libswiftCore.dylib                 0x0000000100f26980 specialized StaticString.withUTF8Buffer<A>(_:) + 58
4    libswiftCore.dylib                 0x0000000101249d10 partial apply for closure #&#8203;1 in closure #&#8203;1 in _assertionFailure(_:_:file:line:flags:) + 141
5    libswiftCore.dylib                 0x0000000101249ae0 partial apply for closure #&#8203;1 in closure #&#8203;1 in _fatalErrorMessage(_:_:file:line:flags:) + 23
6    libswiftCore.dylib                 0x0000000100f26980 specialized StaticString.withUTF8Buffer<A>(_:) + 58
7    libswiftCore.dylib                 0x00000001011c4be0 partial apply for closure #&#8203;1 in _fatalErrorMessage(_:_:file:line:flags:) + 154
8    libswiftCore.dylib                 0x00000001011c4b80 partial apply for closure #&#8203;1 in _fatalErrorMessage(_:_:file:line:flags:) + 23
9    libswiftCore.dylib                 0x0000000100f26980 specialized StaticString.withUTF8Buffer<A>(_:) + 58
10   libswiftCore.dylib                 0x0000000100f26200 _fatalErrorMessage(_:_:file:line:flags:) + 136
11   libswiftCore.dylib                 0x000000010113b360 specialized _StringGuts._unmanagedASCIIView.getter + 552
12   libswiftCore.dylib                 0x0000000101165190 specialized _Stdout.write(_:) + 430
13   libswiftCore.dylib                 0x000000010104edf0 protocol witness for TextOutputStream.write(_:) in conformance _Stdout + 9
14   libswiftCore.dylib                 0x000000010104e420 String.write<A>(to:) + 29
15   libswiftCore.dylib                 0x000000010104ee80 protocol witness for TextOutputStreamable.write<A>(to:) in conformance String + 26
16   libswiftCore.dylib                 0x0000000100fa4940 _print_unlocked<A, B>(_:_:) + 485
17   libswiftCore.dylib                 0x00000001011f6a00 specialized _print<A>(_:separator:terminator:to:) + 328
18   libswiftCore.dylib                 0x00000001011f7120 specialized print(_:separator:terminator:) + 276
19   libswiftCore.dylib                 0x0000000101053b10 print(_:separator:terminator:) + 16
20   sr7573                             0x0000000100e9d7a0 closure #&#8203;1 in static D.f<A>() + 175
21   sr7573                             0x0000000100e9d370 C.init(t:) + 213
22   sr7573                             0x0000000100e9d940 D.init(t:) + 60
23   sr7573                             0x0000000100e9d870 D.__allocating_init(t:) + 67
24   sr7573                             0x0000000100e9d1d0 main + 72
25   libdyld.dylib                      0x00007fff509ca014 start + 1

Definitely looks like something is getting confused.

@huonw
Copy link
Mannequin

@huonw huonw mannequin commented May 8, 2018

Also, slightly reduced:

class C<T> {
    var x: Int = 0
    func f<U>(_ u: U) -> () where U: C {}
}

class E {
    let g = "Expected to Print"
}

class D: C<E> {
    override func f<U>(_ u: U) -> () where U: E {
        print(u.g)
    }
}

let c: C<E> = D()
c.f(c)

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants