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-4249] Result of String.cstring(using:) deallocated prematurely when passed into bridged C function #46832

Closed
swift-ci opened this issue Mar 15, 2017 · 6 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior.

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-4249
Radar None
Original Reporter deckard (JIRA User)
Type Bug
Status Resolved
Resolution Duplicate

Attachment: Download

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

md5: 83e016767daba6b9dfe93e338be127af

duplicates:

  • SR-3231 Generated C string doesn't survive until called C function returns

Issue Description:

Steps to reproduce:

  • Open the attached project

  • Run the test_set_stringField_SUCCEEDS test and see it pass

  • Run the test_set_stringField_FAILS test and see that it crashes at the strnlen() call inside the wrapped C++ class

The only difference between the two tests is which setter method they call on the Wrapper. One of them saves the result of cstring(using: ) in a local variable before passing it to the C setter, and the other does it inline. For some reason, in the latter case the result seems to be getting freed up before the function it is being passed into is finished executing, resulting in the crash

@belkadan
Copy link
Contributor

Workaround: use if let or guard let to guard your use of the C string array.

@swift-ci
Copy link
Collaborator Author

Comment by Matt Deckard (JIRA)

@belkadan, this bug doesn't involve optionals at all so I'm not sure how if let or guard let are workarounds. In fact, just a simple let cstr = newValue.cString(using: .utf8) appears to work around the issue.

@swift-ci
Copy link
Collaborator Author

Comment by Matt Deckard (JIRA)

Including a snippet from the attached project for illustration

    public func setStringFieldUnsafely(_ newValue: String) {
        // For some reason this will sometimes dealloc before the C function is done with it
        // Probably a compiler bug?
        Wrapped_setStringField(wrapped, newValue.cString(using: .utf8))
    }
    
    public func setStringFieldSafely(_ newValue: String) {
        // For some reason this works, while the above method does not
        let cstr = newValue.cString(using: .utf8)
        Wrapped_setStringField(wrapped, cstr)
    }

@belkadan
Copy link
Contributor

cString(using:) produces an optional Array of CChar, in case it can't convert the string to the encoding you picked.

@swift-ci
Copy link
Collaborator Author

Comment by Matt Deckard (JIRA)

@belkadan, but just extracting the result into a local variable is enough to workaround the issue, even if that variable is still an optional type. The example above already illustrates this but even if you make it the type explicitly optional the bug still does not occur:

    public func setStringFieldSafely(_ newValue: String) {
        // For some reason this works, while the above method does not
        let cstr : [CChar]? = newValue.cString(using: .utf8)
        Wrapped_setStringField(wrapped, cstr)
    }

@belkadan
Copy link
Contributor

I suspect we just don't optimize the destruction of named variables quite as much as we do temporaries. Or maybe it will reoccur with optimizations on, but not when they're off.

@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
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior.
Projects
None yet
Development

No branches or pull requests

2 participants