2013-08-06 37 views
5

我正在使用jsmn JSON parsersource code)從JSON獲取一些文本。 jsmn將數據存儲在令牌中,但令牌不包含任何數據,它們只是指向JSON字符串中的令牌邊界。例如,jsmn將創建像標記:爲什麼此方法會引發分段錯誤?

  • 對象[0..31]
  • 字符串[3..7],字符串[12..16],字符串[20..23]
  • 號碼[27..29]

此方法被用來檢索這些值之間的實際的字符(字符串對象):

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; 
} 

下面是一些例子JSON就是Wo ULD被扔進解析器:

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

一旦通過第一示例JSON該方法,我得到的「測試」的預期值從方法返回。但是,在將空JSON傳遞給方法時,在條件if語句的for循環的第8次迭代中,我得到了分段錯誤。

有什麼建議嗎?

這裏是十六進制值:

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

你真的想通過'&賈森[..]''到memcpy'? –

+0

@UchiaItachi在該方法中沒有'memcpy' ... – syb0rg

+1

在循環中放置一個'printf()'語句來打印'(key-> start)'和'(key-> end - key - > start)'in hex(ie:'printf(「0x%08X」,val)'。我傾向於輸入字符串'json',比預期的要短,並且傳遞了一個無效指針 – DevNull

回答

1

tokens[]數組初始化。這是導致你的seg故障。初始化tokens[],然後在for()循環中檢查開始/結束字段中的初始化值。

例如,我可能會初始化(通過memset(&tokens, 0, sizeof(tokens));)和長度爲零(key->end - key->start)迴路檢測的每次迭代中tokens[]爲零,看是否令牌將它傳遞給memcmp()之前實際上是有效的。如果令牌長度爲零,則退出break;循環。

(或者,如果一個令牌可以有一個合法的零長度,使用一些其他的價值。)

+2

我打算接受這個答案,因爲它讓我離解決方案最近。我按照你的建議做了,但我還添加了一個空白標記('if(! )返回NULL;')。現在代碼不會出現分段錯誤。 – syb0rg

4

編輯查看源代碼後...

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

它初始化所有的結構,但 - >啓動和 - >結束將等於-1,這就是爲什麼memcmp失敗。

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)); 
    } 
} 

在 - > start或 - > end中檢查-1值應該足夠。你把它傳遞給parseJson()之前,所以一旦你迭代超過最後令牌(在你的第二個例子第七之一)你試圖在未初始化的廢話地址值運行memcmp()

+0

仍然出現分段錯誤:/ – syb0rg

+0

@ syb0rg - 您從不檢查parseJson(...)的結果,只有當該函數返回JSMN_SUCCESS時才應該繼續。 –

+0

我已更新方法,它引入了一個測試條件,它仍然給出了一個Segmentation錯誤 – syb0rg

相關問題