在替换嵌套值时避免 cJSON 解析无限循环中的核心转储

Avoiding core dump in cJSON parse endless loop while replacing nested values

提问人:couscous 提问时间:11/11/2023 最后编辑:couscous 更新时间:11/11/2023 访问量:37

问:

我有一个 cJSON 树,我在其中保存了我在 while 循环中生成的余弦的 x 和 y 值。

它看起来像这样:

"myXY": [{
        "x":    2.0110001564025879,
        "y":    0.99761265516281128
    }]

myXY 是一个数组,我将其添加到 cJSON:“myJSON”,如下所示:

cJSON *myXY = NULL;
myXY = cJSON_AddArrayToObject(myJSON, "myXY");

然后,我通过创建一个对象“myNestedArray”并将其添加到“myXY”来添加值:

cJSON_AddNumberToObject(myNestedArray, "x", pOutput->x);
cJSON_AddNumberToObject(myNestedArray, "y", pOutput->y);


cJSON_AddItemToArray(myXY, myNestedArray);

(pOutput 是我传递给我的“parse_output_to_json”函数的结构。

最后,我将带有 stdout 的“cJSON-string”管道传输到我的第二个程序“receiver.c”。

char *string = cJSON_Print(myJSON);
write(1, string, strlen(string));

到目前为止,一切正常。

现在我想用sinf("x" /*the "x" value in "myXY"*/)

事实证明,这比我想象的要复杂得多:

int main() {

  /* variables*/
  char buffer[50];
  char *string = NULL;

  /* master-loop*/
  while (1) {
    /* cJSON variables*/
    cJSON *myNewJSON = NULL;
    cJSON *myNewXY = NULL;
    cJSON *xValJSON = NULL;
    
    /* parsing the pipe*/
    read(0, buffer, 50);
    myNewJSON = cJSON_Parse(buffer);
    
    /* adjusting setter parameters*/
    myNewXY = cJSON_GetObjectItem(myNewJSON, "myXY");
    xValJSON = cJSON_GetArrayItem(myNewXY, 0);

    /* setting the new (sin) value*/
    cJSON_SetNumberValue(myNewXY, sinf(cJSON_GetNumberValue(xValJSON)));

    /* printing the new values*/
    string = cJSON_Print(myNewJSON);
    write(1, string, strlen(string));
    
    /*avoiding stack overflow?*/
    free(string);
    cJSON_Delete(myNewJSON);
  }

  return 0;
}

到目前为止,我的代码编译,打印出第一个值(cos(0)),然后给我一个核心哑巴并停止。喜欢这个:

./cos_generator | ./receiver 
{
    "myXY": [{
            "x":    0,
            "y":    1
        }]
}Speicherzugriffsfehler (Speicherabzug geschrieben)

编辑:我的 cos_generator.c 代码是:

/* includes*/
#include "cJSON.c"
#include <math.h>
#include <unistd.h>

#define MY_PI 3.141592
/* OutputData struct*/
struct OutputData {
  float x;
  float y;
};

/*parser-function*/
void parse_output_to_json(cJSON *pJson, struct OutputData *pOutput);

/*main function*/
int main() {

  cJSON *myJSON = cJSON_CreateObject(); /* Object is named 'myJSON'*/

  /* generator loop*/
  while (1) {
    static int counter = 0;
    float t_s = counter * 0.001f;
    float f = 1;

    struct OutputData current = {
        .x = t_s,
        .y = cosf(2 * MY_PI * f * t_s),
    };

    parse_output_to_json(myJSON, &current);

    char *string = cJSON_Print(myJSON);
    write(1, string, strlen(string));

    cJSON_free(string);

    usleep(1000);
    counter++;
  }

  cJSON_Delete(myJSON);

  /* Return val of main*/
  return 0;
}

void parse_output_to_json(cJSON *pJson, struct OutputData *pOutput) {
  /* Variables*/
  char *string = NULL; /* string to be written to*/
  cJSON *myXY = NULL;  // cJSON array
  size_t index = 0;

  /* Add Array 'myXY' to the myJSON*/
  myXY = cJSON_AddArrayToObject(pJson, "myXY");

  /* Add mySinXY to myNestedArray*/
  /* make array object inside the master object??*/
  cJSON *myNestedArray = cJSON_CreateObject();
  /* add numbers of mySinXY*/
  cJSON_AddNumberToObject(myNestedArray, "x", pOutput->x);
  cJSON_AddNumberToObject(myNestedArray, "y", pOutput->y);

  /* Add item 'myNestedArray' to myXY in myJSON*/
  cJSON_AddItemToArray(myXY, myNestedArray);
}
c 解析 管道 cjson

评论

0赞 Shawn 11/11/2023
cJSON_Parse()需要一个正常的以 0 结尾的 C 字符串。你没有给它一个。
0赞 Shawn 11/11/2023
肯定需要添加错误检查,并且可能想摆脱这种无休止的循环。
0赞 Harith 11/11/2023
考虑使用:它将解析 JSON 并分配表示它的项目树。一旦它返回,您就全权负责在使用 后解除分配它。请参阅文档:github.com/DaveGamble/cJSON#parsing-jsoncJSON_ParseWithLength(string, buffer_length);cJSONcJSON_Delete

答:

0赞 couscous 11/23/2023 #1

我的代码有多个问题,例如缓冲区长度太短。 在修复所有语法和“愚蠢”错误的同时,仍然存在一个问题:

  • 它无法正确解析

与我的同事一起工作了一个小时,得到了以下启示:

即使嵌套的 Array 只包含一个元素,例如“x”只包含整数“1”,你也必须遍历“x”。 我没有找到一种方法来访问“x”。

这完全是从 cJSON 页面上的示例中接管的。

我将解析放入结构中,这应该适用于许多类似的用例:

struct OutputData {
  float x;
  float y;
};

struct OutputData parseStruct(cJSON *json) {
  cJSON *myNewXY = NULL;
  cJSON *xValJSON = NULL;
  cJSON *yValJSON = NULL;
  cJSON *resolution = NULL;
  /* adjusting setter parameters*/
  myNewXY = cJSON_GetObjectItemCaseSensitive(json, "myXY");

  cJSON_ArrayForEach(resolution, myNewXY) {
    xValJSON = cJSON_GetObjectItemCaseSensitive(resolution, "x");
    yValJSON = cJSON_GetObjectItemCaseSensitive(resolution, "y");
  }
  struct OutputData result = {
      .x = (float)cJSON_GetNumberValue(xValJSON),
      .y = (float)cJSON_GetNumberValue(yValJSON),
  };

  return result;
}