Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

[cJSON_Utils] decode_pointer_inplace off-by-one causes incorrect decoding of "~1" (JSON Pointer)

未关闭
#977 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 12 天内回复

还没有人认领这个 Issue。

  • #998 来自 @某人 —— 已关闭,未合并

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
55/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
停滞
技术栈
c
领域
backend

调研方向

从 cJSON_Utils.c 的 decode_pointer_inplace() 开始,查看第 370 行附近的代码,并将其对 1 的处理与提供的复现进行比较。使用文档中记录的 gcc 命令构建并运行 poc_decode_pointer.c,然后验证应用 /a1b 会将现有的 "a/b" 键更新为 2,而不会创建 "a~/"。

由索引模型根据 Issue 内容生成。

描述

Description

decode_pointer_inplace() (used by JSON Patch helpers) writes decoded slashes to decoded_string[1] instead of the current output slot. As a result, pointers containing ~1 are decoded incorrectly during patch application—values are written under mutated object keys like "a~/" instead of the intended "a/b". The function reports success even though it corrupted the object.

Reproduction steps
  1. Clone cJSON (current master).
  2. Drop the PoC below into poc_decode_pointer.c at repo root.
  3. Build and run:
    cd cJSON
    gcc -std=c99 -Wall -Wextra poc_decode_pointer.c cJSON.c cJSON_Utils.c -o poc_decode_pointer
    ./poc_decode_pointer
    
PoC source
#include <stdio.h>
#include <stdlib.h>

#include "cJSON.h"
#include "cJSON_Utils.h"

static void print_json(const char *label, cJSON *item)
{
    char *rendered = cJSON_PrintUnformatted(item);
    if (rendered == NULL)
    {
        fprintf(stderr, "%s: <print error>\n", label);
        return;
    }

    printf("%s: %s\n", label, rendered);
    cJSON_free(rendered);
}

int main(void)
{
    const char *document_text = "{\"a/b\":1}";
    const char *patch_text = "[{\"op\":\"add\",\"path\":\"/a~1b\",\"value\":2}]";
    cJSON *document = NULL;
    cJSON *patches = NULL;
    cJSON *value = NULL;
    int status = 0;

    document = cJSON_Parse(document_text);
    patches = cJSON_Parse(patch_text);
    if ((document == NULL) || (patches == NULL))
    {
        fprintf(stderr, "failed to parse JSON input\n");
        goto cleanup;
    }

    print_json("Original document", document);
    print_json("Patch", patches);

    status = cJSONUtils_ApplyPatches(document, patches);
    printf("cJSONUtils_ApplyPatches returned %d\n", status);

    print_json("Document after patch", document);

    value = cJSON_GetObjectItemCaseSensitive(document, "a/b");
    if (value != NULL)
    {
        printf("a/b = %d\n", value->valueint);
    }
    else
    {
        printf("a/b key is missing!\n");
    }

    value = cJSON_GetObjectItemCaseSensitive(document, "a~/");
    if (value != NULL)
    {
        printf("Corrupted key a~/ = %d\n", value->valueint);
    }

cleanup:
    if (document != NULL)
    {
        cJSON_Delete(document);
    }
    if (patches != NULL)
    {
        cJSON_Delete(patches);
    }

    return status;
}
PoC Output
zc@docker:~/cJSON$ ./poc_decode_pointer 
Original document: {"a/b":1}
Patch: [{"op":"add","path":"/a~1b","value":2}]
cJSONUtils_ApplyPatches returned 0
Document after patch: {"a/b":1,"a~/":2}
a/b = 1
Corrupted key a~/ = 2
Expected vs. actual results
  • Expected: Applying the patch that targets /a~1b updates key "a/b" to 2.
  • Actual: cJSONUtils_ApplyPatches returns success but leaves "a/b" unchanged and inserts a new key "a~/" with value 2, proving the decoded pointer got corrupted.
Suggested fix

In decode_pointer_inplace() (around line 370), write the decoded slash to decoded_string[0] and ensure the output pointer only advances once per decoded character:

diff --git a/cJSON_Utils.c b/cJSON_Utils.c
index 8fa24f8..8a3d881 100644
--- a/cJSON_Utils.c
+++ b/cJSON_Utils.c
@@ -374,7 +374,7 @@ static void decode_pointer_inplace(unsigned char
*string)
             }
             else if (string[1] == '1')
             {
-                decoded_string[1] = '/';
+                decoded_string[0] = '/';
             }
             else
             {
@@ -383,7 +383,10 @@ static void decode_pointer_inplace(unsigned char
*string)
             }

             string++;
+            continue;
         }
+
+        decoded_string[0] = string[0];
     }

     decoded_string[0] = '\0';

This change keeps the decoded pointer aligned with the output buffer so /a~1b resolves to "a/b" during JSON Patch operations.

Output after fix
zc@docker:~/cJSON$ ./poc_decode_pointer 
Original document: {"a/b":1}
Patch: [{"op":"add","path":"/a~1b","value":2}]
cJSONUtils_ApplyPatches returned 0
Document after patch: {"a/b":2}
a/b = 2
主要语言
C
星标
13.1k
派生
3.6k
PR 合并指标
30 天内没有已合并 PR

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

DaveGamble/cJSON 的其他 Issue

查看 DaveGamble/cJSON 的全部 Issue

相似的 Issue

更多 C Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。