From 0ab23bee53082513402dbb9422207a7844c6d70d Mon Sep 17 00:00:00 2001 From: Pete French Date: Sat, 25 May 2019 19:36:08 +0100 Subject: [PATCH] Refactor ABI check to allow the functions to execute in either order As dynamic and static linking call the old and new load functions in the opposite order then the ABI mix check code needs to handle both cases. We take the approach of setting a flag if a (non Protocol) new class has been loaded and if any old class has been loaded, and at the end of each function we error if both flags are set to YES. This passes the basic check that a simple pieces of objectve C can be compiled and run both staticly and dynamicly using both the old and the new ABI. --- loader.c | 57 ++++++++++++++++++++++++-------------------------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/loader.c b/loader.c index 9b6d060b..d5f68bdd 100644 --- a/loader.c +++ b/loader.c @@ -176,11 +176,8 @@ struct objc_init #include #endif -static enum { - LegacyABI, - NewABI, - UnknownABI -} CurrentABI = UnknownABI; +BOOL loadedNewABIClasses = NO; +BOOL loadedOldABIClasses = NO; void registerProtocol(Protocol *proto); @@ -199,19 +196,6 @@ OBJC_PUBLIC void __objc_load(struct objc_init *init) } #endif LOCK_RUNTIME_FOR_SCOPE(); - BOOL isFirstLoad = NO; - switch (CurrentABI) - { - case LegacyABI: - fprintf(stderr, "Version 2 Objective-C ABI may not be mixed with earlier versions.\n"); - abort(); - case UnknownABI: - isFirstLoad = YES; - CurrentABI = NewABI; - break; - case NewABI: - break; - } // If we've already loaded this module, don't load it again. if (init->version == ULONG_MAX) @@ -251,17 +235,23 @@ OBJC_PUBLIC void __objc_load(struct objc_init *init) assert(p); *proto = p; } + + BOOL testedFirstName = NO; for (Class *cls = init->cls_begin ; cls < init->cls_end ; cls++) { if (*cls == NULL) { continue; } - // As a special case, allow using legacy ABI code with a new runtime. - if (isFirstLoad && (strcmp((*cls)->name, "Protocol") == 0)) + if(!testedFirstName) { - CurrentABI = UnknownABI; + if(strcmp((*cls)->name, "Protocol") != 0) + { + loadedNewABIClasses = YES; + } + testedFirstName = YES; } + // As a special case, allow using legacy ABI code with a new runtime. #ifdef DEBUG_LOADING fprintf(stderr, "Loading class %s\n", (*cls)->name); #endif @@ -322,6 +312,12 @@ OBJC_PUBLIC void __objc_load(struct objc_init *init) } #endif init->version = ULONG_MAX; + + /* make sure we are not mixing ABIs */ + if(loadedNewABIClasses && loadedOldABIClasses) { + fprintf(stderr, "Version 2 Objective-C ABI may not be mixed with earlier versions.\n"); + abort(); + } } #ifdef OLDABI_COMPAT @@ -329,18 +325,6 @@ OBJC_PUBLIC void __objc_exec_class(struct objc_module_abi_8 *module) { init_runtime(); - switch (CurrentABI) - { - case UnknownABI: - CurrentABI = LegacyABI; - break; - case LegacyABI: - break; - case NewABI: - fprintf(stderr, "Version 2 Objective-C ABI may not be mixed with earlier versions.\n"); - abort(); - } - // Check that this module uses an ABI version that we recognise. // In future, we should pass the ABI version to the class / category load // functions so that we can change various structures more easily. @@ -363,6 +347,7 @@ OBJC_PUBLIC void __objc_exec_class(struct objc_module_abi_8 *module) // Load the classes from this module for (unsigned short i=0 ; iclass_count ; i++) { + loadedOldABIClasses = YES; objc_load_class(objc_upgrade_class(symbols->definitions[defs++])); } unsigned int category_start = defs; @@ -394,5 +379,11 @@ OBJC_PUBLIC void __objc_exec_class(struct objc_module_abi_8 *module) objc_send_load_message(class); } } + + /* make sure we are not mixing ABIs */ + if(loadedNewABIClasses && loadedOldABIClasses) { + fprintf(stderr, "Version 2 Objective-C ABI may not be mixed with earlier versions.\n"); + abort(); + } } #endif