@DTS Engineer you are right, the KERN_PROTECTION_ERROR really through me off. I updated today to Xcode 26 beta 5 and with my dylib compiled with debug symbols all of the sudden I can see where the null invocation is happening
However, I don't have any idea why the compiler is stripping this symbols when packaging for TestFlight/Debugging. I've already added a lot of preprocessor directives to try to keep the symbols intact. Any idea what could I try?
#define EXPORT __attribute__((visibility("default"), used, retain))
extern "C" {
EXPORT void ios_prepare_request(const char *url) {
NSString *urlString = [NSString stringWithUTF8String:url];
request =
[NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
}
void force_symbol_registration() {
// Force these symbols to be included in the binary by referencing them
volatile void *ptrs[] = {(void *)ios_prepare_request,
(void *)ios_set_request_header,
(void *)ios_present_webview,
(void *)ios_close_webview,
(void *)ios_get_browser_cookies_for_current_url,
(void *)ios_get_browser_cookies_for_domain,
(void *)get_ip_address,
(void *)is_rooted,
(void *)is_wifi_connected,
(void *)is_location_services_enabled,
(void *)get_os_name,
(void *)get_os_version,
(void *)is_emulator,
(void *)get_battery_level,
(void *)get_battery_status
};
// Prevent compiler from optimizing away the array
// (void)ptrs;
// Actually use the pointers to prevent optimization
for (int i = 0; i < 6; i++) {
if (ptrs[i] == NULL) {
printf("Symbol %d is NULL\n", i);
}
}
}
// Add this to ensure symbols are not stripped
__attribute__((constructor)) static void ensure_symbols_retained() {
force_symbol_registration();
}
static void *__attribute__((used)) symbol_references[] = {
(void *)ios_prepare_request,
(void *)ios_set_request_header,
(void *)ios_present_webview,
(void *)ios_close_webview,
(void *)ios_get_browser_cookies_for_current_url,
(void *)ios_get_browser_cookies_for_domain,
(void *)get_ip_address,
nullptr};
EXPORT void ensure_symbols_loaded() {
volatile void **ptr = (volatile void **)symbol_references;
while (*ptr) {
// Just touch the memory to ensure it's loaded
ptr++;
}
}
When my library is loaded I do:
opacity::force_symbol_registration();
opacity::ensure_symbols_loaded();
// Make sure the main executable's symbols are available
dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
NSBundle *frameworkBundle =
[NSBundle bundleWithIdentifier:@"com.opacitylabs.sdk"];
if (![frameworkBundle isLoaded]) {
BOOL success = [frameworkBundle load];
if (!success) {
NSString *errorMessage = @"Failed to load framework";
*error =
[NSError errorWithDomain:@"OpacitySDKDylibError"
code:1002
userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
return -1;
}
}
// Validate function pointers before registration
void *functions[] = {(void *)opacity::ios_prepare_request,
(void *)opacity::ios_set_request_header,
(void *)opacity::ios_present_webview,
(void *)opacity::ios_close_webview,
(void *)opacity::ios_get_browser_cookies_for_current_url,
(void *)opacity::ios_get_browser_cookies_for_domain,
(void *)opacity::get_ip_address};
for (int i = 0; i < 6; i++) {
if (functions[i] == NULL || functions[i] == (void *)0x1) {
NSString *errorMessage = [NSString
stringWithFormat:@"Invalid function pointer at index %d", i];
*error =
[NSError errorWithDomain:@"OpacitySDKCallbackError"
code:1004
userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
return -1;
}
}
__sync_synchronize();
On my podspec linker flags I have added
s.pod_target_xcconfig = {
'OTHER_LDFLAGS' => '-undefined dynamic_lookup -Wl,-keep_private_externs -Wl,-no_deduplicate'
}