I'm using Unmanaged to create a C accessible library in Swift. Swift exposes two functions to C, to create and destroy an object. The Object is defined as an opaque pointer in C:
@_cdecl("ObjectCreate")
public func ObjectCreate() -> OpaquePointer
{
let retained = Unmanaged.passRetained(MyClass()).toOpaque();
return OpaquePointer(retained);
}
@_cdecl("ObjectRelease")
public func ObjectRelease(pointer: OpaquePointer?) -> Void
{
Unmanaged<MyClass>.fromOpaque(UnsafeRawPointer(pointer!)).release();
// Also tried takeRetainedValue()
}
How am I not getting a segmentation fault when executing the following C code:
typedef struct Object *ObjectRef;
int
main()
{
ObjectRef test = ObjectCreate();
ObjectRelease(test);
printf("%u\n", *(int*)(test)); // How is this legal?
int *intPtr = (int*)(test);
*intPtr = 123; // How is this also legal?
return 0;
}
Note that I'm using the Embedded flag when compiling.
The only reason you'd get a segmentation fault is if test was pointing into unmapped memory or memory that your process didn't own. If you did the same thing with malloc and free you still probably wouldn't get a segfault.
It's entirely coincidental whether it will or not on any given environment. The fact that it rarely causes something as obvious as a segfault is why use after free is such a pernicious bug.
The only thing I can think of off the top of my head is that ObjectFree can take a pointer to the pointer and reset it to nil after you free it.
@_cdecl("ObjectRelease")
public func ObjectRelease(pointer: inout OpaquePointer?) -> Void
{
Unmanaged<MyClass>.fromOpaque(UnsafeRawPointer(pointer!)).release();
pointer = nil
// Also tried takeRetainedValue()
}
typedef struct Object *ObjectRef;
int
main()
{
ObjectRef test = ObjectCreate();
ObjectRelease(&test);
printf("%u\n", *(int*)(test)); // How is this legal?
int *intPtr = (int*)(test);
*intPtr = 123; // How is this also legal?
return 0;
}