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

Passing a C++ type to a C-style Swift function crashes: malloc: Heap corruption detected *** #78292

Open
mrousavy opened this issue Dec 19, 2024 · 4 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels

Comments

@mrousavy
Copy link

mrousavy commented Dec 19, 2024

Description

I have a C-style Swift function that will be called from C++ later. This is my "callback":

func callCppCode() {
  func __callback(value: SharedPtrOfString) {
    let string = String(value.pointee)
    print("Got value from C++: \(value)")
  }
  myCppFunc(__callback)
}

And on the C++ side, myCppFunc looks like this:

#pragma once

#include <string>
#include <memory>

using SharedPtrOfString = std::shared_ptr<std::string>;

inline void myCppFunc(void(* _Nonnull call)(SharedPtrOfString)) {
  auto shared = std::make_shared<std::string>("HELLO!");
  call(shared);
}

When running this, it crashes with the following error:

- SwiftSharedPointerTest(33577,0x1e6e6f840) malloc: Heap corruption detected, free list is damaged at 0x600002b91a10
- *** Incorrect guard value: 1
- SwiftSharedPointerTest(33577,0x1e6e6f840) malloc: *** set a breakpoint in malloc_error_break to debug

Note

When I replaced SharedPtrOfString with Double or even std.string, it works. It's just std::shared_ptr<...> that makes it crash with a heap corruption error.

Reproduction

func callCppCode() {
  func __callback(value: SharedPtrOfString) {
    let string = String(value.pointee)
    print("Got value from C++: \(value)")
  }
  myCppFunc(__callback)
}
#pragma once

#include <string>
#include <memory>

using SharedPtrOfString = std::shared_ptr<std::string>;

inline void myCppFunc(void(* _Nonnull call)(SharedPtrOfString)) {
  auto shared = std::make_shared<std::string>("HELLO!");
  call(shared);
}

Stack dump

Got value from C++: shared_ptr<basic_string<CChar, char_traits<CChar>, allocator<CChar>>>()
SwiftSharedPointerTest(34066,0x1e6e6f840) malloc: Heap corruption detected, free list is damaged at 0x600001726730
*** Incorrect guard value: 7813868916180873059
SwiftSharedPointerTest(34066,0x1e6e6f840) malloc: *** set a breakpoint in malloc_error_break to debug

Expected behavior

I expect the shared_ptr to be free'd fine instead of corrupting the heap.

Environment

swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0

Additional information

I have created a reproduction repro here: https://github.com/mrousavy/SwiftSharedPointerBugRepro

Just download and run this (I chose "Run on my Mac (Designed for iPad)") to see the bug.

@mrousavy mrousavy added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels labels Dec 19, 2024
@ChrisSchofieldCheckatrade

Possibly related: #67355 (comment)

@mrousavy
Copy link
Author

Pretty stupid, but if I just do an unbalanced +1 ref-count increment on the shared_ptr before passing it to the Swift C-Style callback function it works!

Screenshot 2024-12-19 at 18 22 49

It also properly calls the destructor of std::string after the shared_ptr goes out of scope, so I can confirm that the Swift compiler accidentally seems to destroy the shared_ptr twice when it's being passed to a C-style Swift function.

Does anyone have any pointers on where to look in the Swift compiler codebase? I'd love to tackle this myself but can't really seem to grasp the structure here. Not a compiler engineer.

@mrousavy mrousavy changed the title Passing a std::shared_ptr<...> from C++ to a C-style Swift function crashes: malloc: Heap corruption detected *** Passing a C++ type to a C-style Swift function crashes: malloc: Heap corruption detected *** Dec 19, 2024
@mrousavy
Copy link
Author

So apparently this does not only happen with shared_ptr, but also with any other type - e.g.:

struct SomeType {
  SomeType() {
    printf("constructed!");
  }
  ~SomeType() {
    printf("destructed!");
  }
};

@EvgenijLutz
Copy link

@mrousavy Yes, same here. As a workaround for now, I wrap callback parameters that are ported c++ classes and structs with custom destructors in a wrapper that checks itself if it already was destroyed

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. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels
Projects
None yet
Development

No branches or pull requests

3 participants