为什么这个方法会引发Segmentation错误?

时间:2013-08-06 15:34:43

标签: c json parsing segmentation-fault token

我正在使用jsmn JSON parsersource code)从JSON获取一些文本。 jsmn将数据存储在令牌中,但令牌不包含任何数据,它们只是指向JSON字符串中的令牌边界。例如,jsmn将创建令牌,如:

  • 对象[0..31]
  • String [3..7],String [12..16],String [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示例:

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

将第一个示例JSON传递给方法后,我得到了从方法返回的“test”的预期值。但是,在将空JSON传递给方法时,我在条件for语句的if循环的第8次迭代中得到了Segmentation错误。

有什么建议吗?

以下是十六进制值:

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

2 个答案:

答案 0 :(得分:4)

编辑查看源代码后......

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

初始化所有结构但是 - &gt; start和 - &gt; end将等于-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));
    }
}

在 - &gt; start或 - &gt; end中检查-1值就足够了。

答案 1 :(得分:1)

您的tokens[]数组在传递给parseJson()之前未初始化,所以一旦您迭代到最后一个令牌(第二个示例中的第七个),您就会尝试运行{{ 1}}关于未初始化的无意义地址值。这导致你的seg错误。将memcmp()初始化为某些内容,然后在tokens[]循环期间检查开始/结束字段中的初始化值。

例如,我可能会将for()初始化为零(通过tokens[])并在循环的每次迭代期间检查长度为零(memset(&tokens, 0, sizeof(tokens));)以查看是否令牌在传递给key->end - key->start之前实际上是有效的。如果令牌的长度为零,则使用memcmp()退出循环。

(或者,如果令牌可以具有合法的零长度,请使用其他值。)