cJSON_Delete()调用致应用崩溃问题排查及cJSON变量复用疑问
Hey there, let's break down exactly what's happening here and clear up your confusion around reusing cJSON variables.
问题根源:双重释放内存
The crash you're seeing is 100% caused by double-freeing memory when you add the same cjTimeZone cJSON object to two different parent objects (cjStart and cjEnd). Here's why:
When you call cJSON_AddItemToObject(), cJSON takes ownership of the child object you pass in. That means when you later call cJSON_Delete(cjMsg), it will recursively traverse all child objects and free their memory.
In your code:
- You create
cjTimeZoneonce withcJSON_CreateString(TZ) - You add it to
cjStart - You then add the same exact pointer to
cjEnd
When cJSON_Delete() processes cjStart, it frees cjTimeZone. Then when it gets to cjEnd, it tries to free that same pointer again—this is a classic double-free bug, which almost always causes a crash.
为什么复用cjDateTime没出问题?
You mentioned reusing cjDateTime didn't cause issues, but let's look at what you actually did there:
strcpy(dateStr, "2025-06-01T14:00:00"); cjDateTime = cJSON_CreateString(dateStr); // 创建新对象,分配新内存 cJSON_AddItemToObject(cjStart, "dateTime", cjDateTime); strcpy(dateStr, "2025-06-01T15:00:00"); cjDateTime = cJSON_CreateString(dateStr); // 再次创建新对象,指向不同内存 cJSON_AddItemToObject(cjEnd, "dateTime", cjDateTime);
你其实并没有复用同一个cJSON对象——只是复用了指针变量,但每次调用cJSON_CreateString()时,都会在内存中分配一个全新的cJSON对象。旧的cjDateTime指针已经交给cjStart(并由它接管所有权),所以覆盖指针变量并不会影响已有的对象,这就是为什么没有崩溃的原因。
正确的解决方案
针对cjTimeZone的问题,你有两种可行的修复方式:
创建两个独立的cJSON字符串对象,就像你用
cjDateTime2那样:cjTimeZone = cJSON_CreateString(TZ); cJSON_AddItemToObject(cjStart, "timeZone", cjTimeZone); cJSON *cjTimeZone2 = cJSON_CreateString(TZ); cJSON_AddItemToObject(cjEnd, "timeZone", cjTimeZone2);这种方式简单安全——每个父对象都拥有自己的字符串对象副本,不会出现双重释放的问题。
使用引用计数(如果你的cJSON版本支持)
一些较新的cJSON版本提供了cJSON_Duplicate()或引用计数相关函数。如果你想复用同一个对象而不复制它,可以在添加到第二个父对象前增加它的引用计数。但对于这种简单字符串,直接复制通常更简单且不易出错。
关于cJSON变量复用的核心规则
为了避免未来再出现这类崩溃,记住这几条黄金规则:
- 永远不要将同一个cJSON对象指针添加到多个父对象中——每次添加都会转移所有权,当父对象被删除时,该对象会被多次释放。
- 复用指针变量是没问题的,但复用实际的cJSON对象(它指向的内存)不行,除非你显式处理引用计数或复制对象。
- 务必牢记:cJSON_AddItemTo*系列函数会接管子对象的所有权——你之后不能自己释放它,也不能将它传递给另一个添加函数。
内容来源于stack exchange

