Skip to content

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

@swift-ci

Description

@swift-ci
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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    accepts invalidBug: Accepts invalidbugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itself

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions