blob: ce8c8a43df5a03a6a4077531302c8dd546dfc61c [file] [log] [blame]
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -emit-library -o %t/dlopen_race.dylib %S/Inputs/dlopen_race_dylib.swift
// RUN: %target-build-swift -o %t/dlopen_race %s
// RUN: %target-codesign %t/dlopen_race %t/dlopen_race.dylib
// RUN: %target-run %t/dlopen_race %t/dlopen_race.dylib
// REQUIRES: executable_test
// REQUIRES: objc_interop
import StdlibUnittest
import Darwin
var DlopenRaceTests = TestSuite("DlopenRace")
typealias add_image_callback = @convention(c) (UnsafeRawPointer?, Int) -> Void
func register_func_for_add_image(_ f: add_image_callback) {
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
let _dyld_register_func_for_add_image_ptr =
dlsym(RTLD_DEFAULT, "_dyld_register_func_for_add_image")
expectNotNil(_dyld_register_func_for_add_image_ptr)
typealias _dyld_register_func_for_add_image_func =
@convention(c) (add_image_callback) -> Void
let _dyld_register_func_for_add_image = unsafeBitCast(
_dyld_register_func_for_add_image_ptr,
to: _dyld_register_func_for_add_image_func.self)
_dyld_register_func_for_add_image(f)
}
// Make sure Swift doesn't register newly opened images before ObjC is ready
// for them to be used. rdar://problem/49742015
var add_image_count = 0
DlopenRaceTests.test("race") {
// This test is expected to fail unless the ObjC notification is supported.
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
let objc_addLoadImageFunc = dlsym(RTLD_DEFAULT, "objc_addLoadImageFunc");
if objc_addLoadImageFunc == nil { return }
register_func_for_add_image({ header, slide in
// The protocol conformance check in the print call is enough to trigger
// ObjC class initialization in the newly opened image if Swift has
// registered the conformance records in that image. While we would be
// unlikely to make this sort of call directly in the callback in a real
// program, it could happen at this time in another thread.
print(header, slide)
add_image_count += 1
})
let dylibPath = CommandLine.arguments.last!
let beforeCount = add_image_count
let handle = dlopen(dylibPath, RTLD_LAZY)
expectNotNil(handle, String(cString: dlerror()))
expectEqual(add_image_count, beforeCount + 1)
}
runAllTests()