2013-08-06 12 views
5

Sto usando il jsmn JSON parser (source code) per ottenere del testo da un JSON. jsmn memorizza i dati nei token, ma i token non contengono alcun dato, puntano invece ai limiti del token nella stringa JSON. Ad esempio, jsmn creerà gettoni come:Perché questo metodo genera un errore di segmentazione?

  • Object [0..31]
  • String [3..7], String [12..16], String [20..23]
  • Number [27..29]

Questo metodo viene utilizzato per recuperare i caratteri effettivi tra questi valori (per gli oggetti stringa):

char* getTextFromJSON(const char *json) 
{ 
    if (!json) return NULL; 

    json_parser p; 
    #define N_TOKENS 15 // this normally would be at the start of the file 
    jsontok_t tokens[N_TOKENS]; 

    initJsonParser(&p); 
    int err parseJson(&p, json, tokens, N_TOKENS); 
    if (err) { 
    fprintf(stdout, "Error parsing JSON: %d\n", err); 
    return NULL; 
    } 
    for (int i = 0; i < N_TOKENS; ++i) { 
     jsontok_t *key = &tokens[i]; 
     if (!memcmp("utterance", &json[key->start], (size_t) (key->end - key->start))) { 
      ++key; 
      return strndup(&json[key->start], (size_t)(key->end - key->start)); 
     } 
    } 
    return NULL; 
} 

Ecco alcuni esempi JSON che wo ULD essere gettato nel parser:

  • {"status":0,"id":"432eac38858968c108899cc6c3a4bade-1","hypotheses":[{"utterance":"test","confidence":0.84134156}]}
  • {"status":5,"id":"695118aaa3d01dc2ac4aa8054d1e5bb0-1","hypotheses":[]}

Appena passato il primo esempio JSON al metodo, ottengo il valore atteso di "test" restituito dal metodo. Tuttavia, passando il metodo JSON vuoto al metodo, viene visualizzato un errore di segmentazione nell'ottava iterazione del ciclo for nell'istruzione condizionale if.

Qualche suggerimento?

Qui ci sono i valori esadecimali:

key->start: 0x00000000 
key->end - key->start: 0x00000046 
key->start: 0x00000002 
key->end - key->start: 0x00000006 
key->start: 0x0000000A 
key->end - key->start: 0x00000001 
key->start: 0x0000000D 
key->end - key->start: 0x00000002 
key->start: 0x00000012 
key->end - key->start: 0x00000022 
key->start: 0x00000037 
key->end - key->start: 0x0000000A 
key->start: 0x00000043 
key->end - key->start: 0x00000002 
key->start: 0x3A7B3188 
key->end - key->start: 0x7A0F0766 
+0

Vuoi davvero passare '& jason [..]' a 'memcpy'? –

+0

@UchiaItachi Non c'è 'memcpy' in quel metodo ... – syb0rg

+1

Inserisci un'istruzione' printf() 'nel tuo ciclo per stampare i valori per' (tasto-> start) ', e' (tasto-> tasto fine -) -> start) 'in esadecimale (es .:' printf ("0x% 08X", val) '. Mi sto appoggiando alla stringa di input,' json', essendo più corto del previsto, e stai passando un puntatore non valido – DevNull

risposta

1

vostro array tokens[] è inizializzato prima di passare a parseJson(), così una volta di eseguire iterazioni oltre l'ultimo token (il settimo nel secondo esempio) si sta cercando di correre memcmp() su valori di indirizzo senza senso non inizializzati. Ciò sta causando il tuo difetto di seg. Inizializzare tokens[] in qualcosa e quindi verificare il valore di inizializzazione nei campi di inizio/fine durante il ciclo for().

Ad esempio, probabilmente inizializzare tokens[] a zero (via memset(&tokens, 0, sizeof(tokens));) e durante ogni iterazione del ciclo per controllo lunghezza zero (key->end - key->start) per vedere se il token è in realtà valida prima di passarlo a memcmp(). Salvare il ciclo con un break; se il token ha lunghezza zero.

(Oppure, se un token può avere un legittimo lunghezza zero, utilizzare un altro valore.)

+2

Ho intenzione di accettare questa risposta perché mi ha ottenuto il più vicino alla soluzione. Ho fatto come suggerito, ma ho anche aggiunto un test case per un token vuoto ('if (! Memcmp (" ", & json [key-> start], (size_t) (chiave-> end - chiave-> start))) restituisce NULL; '). Ora il codice non dà un errore di segmentazione. – syb0rg

4

EDIT Dopo aver guardato il codice sorgente ...

for (i = parser->toknext; i < num_tokens; i++) { 
    jsmn_fill_token(&tokens[i], JSMN_PRIMITIVE, -1, -1); 
} 

inizializza tutte le strutture, ma -> Start e-> fine sarà uguale a -1, motivo per cui memcmp sta fallendo.

for (int i = 0; i < N_TOKENS; ++i) { 
    jsontok_t *key = &tokens[i]; 
    if (key->start == -1) return NULL; 
    if (!memcmp("utterance", &json[key->start], (size_t) (key->end - key->start))) { 
     ++key; 
     return strndup(&json[key->start], (size_t)(key->end - key->start)); 
    } 
} 

Il controllo di un valore -1 in -> inizio o -> fine dovrebbe essere sufficiente.

+0

Ancora un errore di segmentazione:/ – syb0rg

+0

@ syb0rg - Non si controlla mai il risultato di parseJson (...), si dovrebbe procedere solo se tale funzione restituisce JSMN_SUCCESS. –

+0

Ho aggiornato il metodo che introduce una condizione di test, fornisce comunque un errore di segmentazione – syb0rg

Problemi correlati