Objective-C
(Probabilmente solo se compilato con clang su Mac OS X)
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
void unusedFunction(void) {
printf("huh?\n");
exit(0);
}
int main() {
NSString *string;
string = (__bridge id)(void*)0x2A27; // Is this really valid?
NSLog(@"%@", [string stringByAppendingString:@"foo"]);
return 0;
}
@interface MyClass : NSObject
@end
@implementation MyClass
+ (void)load {
Class newClass = objc_allocateClassPair([NSValue class], "MyClass2", 0);
IMP imp = class_getMethodImplementation(self, @selector(unusedMethod));
class_addMethod(object_getClass(newClass), _cmd, imp, "");
objc_registerClassPair(newClass);
[newClass load];
}
- (void)unusedMethod {
Class class = [self superclass];
IMP imp = (IMP)unusedFunction;
class_addMethod(class, @selector(doesNotRecognizeSelector:), imp, "");
}
@end
Questo codice utilizza diversi trucchi per accedere alla funzione non utilizzata. Il primo è il valore 0x2A27. Questo è un puntatore con tag per l'intero 42, che codifica il valore nel puntatore per evitare di allocare un oggetto.
Il prossimo è MyClass. Non viene mai utilizzato, ma il runtime chiama il +loadmetodo quando viene caricato, prima main. Questo crea e registra dinamicamente una nuova classe, usando NSValuecome superclasse. Aggiunge anche un +loadmetodo per quella classe, usando MyClass's -unusedMethodcome implementazione. Dopo la registrazione, chiama il metodo di caricamento sulla nuova classe (per qualche motivo non viene chiamato automaticamente).
Poiché il metodo di caricamento della nuova classe utilizza la stessa implementazione di unusedMethod, viene effettivamente chiamato. Prende la superclasse di se stesso e aggiunge unusedFunctioncome implementazione il doesNotRecognizeSelector:metodo di quella classe . Questo metodo era originariamente un metodo di istanza attivo MyClass, ma viene chiamato come metodo di classe nella nuova classe, così selfcome il nuovo oggetto classe. Pertanto, la superclasse è NSValue, che è anche la superclasse per NSNumber.
Finalmente maincorre. Prende il valore del puntatore e lo inserisce in una NSString *variabile (il __bridgeprimo e il cast per void *consentirne l'utilizzo con o senza ARC). Quindi, tenta di richiamare stringByAppendingString:quella variabile. Poiché in realtà è un numero, che non implementa quel metodo, doesNotRecognizeSelector:viene invece chiamato il metodo, che viaggia attraverso la gerarchia di classi fino a NSValuedove viene implementato usando unusedFunction.
Nota: l'incompatibilità con altri sistemi è dovuta all'utilizzo del puntatore con tag, che non credo sia stato implementato da altre implementazioni. Se questo è stato sostituito con un numero normalmente creato, il resto del codice dovrebbe funzionare correttamente.