Qual è un modo affidabile per arrestare un'app iOS?


136

Voglio testare i rapporti sugli arresti anomali della mia app sul campo deliberatamente facendoli arrestare quando l'utente esegue un'azione particolare che è improbabile che un utente reale esegua accidentalmente.

Ma qual è un buon modo affidabile per bloccare l'app che non crea un avviso in fase di compilazione?

Modifica: nota che molte risposte apparentemente ovvie a questa domanda comportano eccezioni che vengono catturate da Cocoa e quindi non provocano l'arresto anomalo dell'app.


WebKit discarded an uncaught exceptionFinora sto ricevendo tutte queste idee! Chi sapeva che era così difficile far crashare un'app in questi giorni?
Nestor,

Non credo che nessuno di questi abbia a che fare con WebKit ...
BoltClock

23
Sì, apri Safari su un iPad 1 e vai a una pagina con molte immagini. Funziona sempre per me. : /
Alan B,

4
(void)0/0;,(void)*(char*)0;
Kevin,

1
Fai attenzione con alcune delle risposte qui invocando un comportamento indefinito . Questo è in realtà un consiglio molto brutto!
usr

Risposte:


140

in Objective-C usa C direttamente per causare un accesso errato

strcpy(0, "bla");

Nota: mentre questo funziona su qualsiasi sistema che conosco, in una versione futura di C runtime O del compilatore questo potrebbe non causare più un arresto anomalo. vedi Il comportamento null dereference non è definito in Objective-C? )

(in breve tempo dovresti passare a objC per farlo)


questo è l'IMHO il modo più affidabile
Michał Kreft,

Ah sì, anche questo WebKit discarded an uncaught exceptionrisolve il problema.
Nestor,

c'era ancora un refuso: D no @ "bla" ma "bla"
Daij-Djan

4
Apparentemente ( stackoverflow.com/questions/13651642/… ), questo è un comportamento indefinito e in realtà una pessima risposta! Il compilatore può ottimizzare legalmente entrambe le istruzioni e semplicemente non fare nulla. Ti suggerisco di eliminare questa risposta. Potrebbe indurre le persone a farlo davvero.
usr

3
su iOS e OSX e Windows e Redhat è sempre andato in crash, quindi nel contesto dato, direi che è valido. Aggiungerò una dichiarazione di non responsabilità
Daij-Djan,

97

Il mio preferito attuale:

assert(! "crashing on purpose to test <insert your reason here>");

Un classico:

kill( getpid(), SIGABRT );

E alcuni pr0n:

*(long*)0 = 0xB16B00B5;

Tutti loro generano arresti anomali catturati dal mio strumento di segnalazione degli arresti anomali.


14
assert non si arresta in modo anomalo nelle versioni di rilascio, ecco perché è
un'asserzione

6
dipende dalle impostazioni della build; inoltre, penso che la domanda riguardi i test, sembra ok per mantenere
assert

3
Molte persone (incluso me) lasciano affermazioni nelle build di rilascio. Non c'è motivo di disabilitarli.
Sulthan,

5
@Sulthan: assert()è una funzione di debug, ha poco senso lasciare tale cruft nelle build di rilascio. Ci sono test unitari per questo.
MestreLion,

18
IMHO assertnon è una funzionalità di debug. Un'asserzione fallita è un bug che ritenevi impossibile. È meglio interrompere, anche una build di rilascio, che continuare a eseguire un programma con conseguenze imprevedibili.
djromero,

27

Dal momento che tutti usiamo Clang per iOS, questo è abbastanza affidabile:

__builtin_trap();

Questo ha il vantaggio di essere progettato esattamente per questo scopo, quindi non dovrebbe generare avvisi o errori del compilatore.



22

Che ne dici di un buon vecchio overflow dello stack :)

- (void)stackOverflow
{
    [self stackOverflow];
}

16

Il più popolare: arresto anomalo del selettore non riconosciuto:

NSObject *object = [[NSObject alloc] init];
[object performSelector:@selector(asfd)];

Assicurati di non aver implementato il metodo -asdf in quella classe haha

O indice oltre l'eccezione associata:

NSArray * array = [NSArray array];
[array objectAtIndex:5];

Ed ovviamente kill( getpid(), SIGABRT );


12

Penso che in Swift potresti facilmente lanciare un errore fatale:

func foo() {
    fatalError("crash!")
}

In realtà è addirittura destinato a utilizzare questa funzione nel caso in cui qualcosa vada storto al fine di far arrestare l'app.

Per evitare un'istruzione if in un caso speciale, puoi anche usare precondition. È simile a assert, rende quindi l'intenzione (se voluto) abbastanza chiara e non viene rimossa nella versione finale come assert. È usato come precondition(myBoolean, "This is a helpful error message for debugging.").


9

Invia un messaggio a un oggetto deallocato


34
Questo è in realtà molto inaffidabile. Puoi comunque inviare messaggi a oggetti deallocati purché la loro memoria non venga riutilizzata. Questo è il motivo per cui le persone hanno storicamente avuto molto difficile eseguire il debug di errori a doppio rilascio. È solo quando la memoria viene recuperata da un altro oggetto che l'invio di un messaggio può causare un'eccezione.
Mike Weller,

7
exit(0);

(deve ... digitare ... 30 caratteri)


Grazie per i voti positivi, ma in realtà questo farà terminare l'app e tornare a Springboard, che, sebbene possa essere utile in sé, non è ciò che OP voleva, che è quello di innescare un'eccezione non intrappolata
Steve Rogers

6

Puoi anche sollevare un'eccezione:

[NSException raise:NSInternalInconsistencyException
            format:@"I want to test app crashes!."];

2
Non penso che l'eccezione sia quella buona, catturare l'eccezione è comune, quindi potresti prenderla accidentalmente. La cattura dei segnali non è così comune, quindi un cattivo accesso o cose simili sarebbero più affidabili. :)
Michał Kreft il

3

Aggiungi un riconoscimento dei gesti a una vista che riconosce un tocco di 10 dita (5 dita per iPhone poiché 10 possono diventare un po 'affollate). Il GR ha un metodo collegato ad esso che esegue chiunque dei metodi infallibili precedentemente menzionati per far arrestare l'app in modo anomalo. La maggior parte degli utenti non porrà 10 dita sulla tua app, quindi sei al sicuro dall'utente generico che causa accidentalmente l'incidente.

Tuttavia, dovresti essere in grado di utilizzare qualcosa come Testflight o semplicemente distribuirlo su dispositivi personali e testare in natura prima di inviarlo ad Apple. Avere un arresto forzato potrebbe far rifiutare la tua app da Apple.


La mia app Cocos2d si arresta in modo anomalo quando eseguo un multi touch estremo e l'ho trovato come un bug non risolto. Non ho alcun GR, ma ho abilitato il multitouch in Cocos2d. Vivo l'incidente che descrivi? Vuoi dire che questo è un comportamento atteso / voluto?
Fredrik Johansson,

@Fredrik Non credo che ci si aspetta un crash che stai descrivendo (non dovrebbero mai esserci crash IMO e personalmente non penso che sia una buona idea metterne uno intenzionalmente nella tua app). Potresti provare a simboleggiare il crash e scoprire esattamente quale metodo sta causando il crash dell'app. Potrebbe essere qualcosa all'interno del framework Cocos2d che sta causando l'incidente quando si verifica l'estremo multi touch. In tal caso, la soluzione migliore è presentare un bug con i ragazzi di Cocos2d.
Jhelzer,

2

potrebbe provare qualcosa del genere

NSArray* crashingArray = [NSArray arrayWithCapacity:1];
[crashingArray release];

dovrebbe arrestarsi in modo anomalo su un EXC_BAD_ACCESS (potrebbe essere necessario rilasciarlo una seconda volta, ma normalmente dovrebbe bloccarsi in questo modo già)


3
Non compilare con ARC abilitato.
vikingosegundo,

bene, se usi ARC, puoi anche farlo: NSArray * crashingArray = [NSArray arrayWithCapacity: 1]; [crashingArray objectAtIndex: 0]; questo dovrebbe andare in crash
Saliom

1

Andrò con:int raise(int sig);

Per ottenere maggiori informazioni >man raise


0

Vorrei semplicemente uccidere il processo normalmente:

kill(getpid(), SIGKILL);

Quindi se installi un gestore con segnale puoi anche gestire l'arresto anomalo, finendo di scrivere file aperti e queste cose.


questo è già incluso nella risposta di
madmw

0

Io uso

[self doesNotRecognizeSelector:_cmd]; 

2
Questo post viene automaticamente contrassegnato come di bassa qualità perché è solo un codice. Ti dispiacerebbe espanderlo aggiungendo del testo per spiegare perché questo risolve il problema?
gung - Ripristina Monica il

0

Quando lavoro con RubyMotion uso questo:

    n=Pointer.new ('c', 1)
    n[1000] ='h'

0

Prova questo:

- (IBAction)Button:(id)sender
{
    NSArray *array = [NSArray new];
    NSLog(@"%@",[array objectAtIndex:8]);
}

-1

una NSLogdichiarazione sbagliata lo farà

NSLog(@"%@",1);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.