#2384·rapidjson

Pointer::Create/Set with a large array index allocates unboundedly (resource exhaustion)

Author: OwenSanzasCreated May 31, 2026Updated May 31, 2026

Pointer::Create/Set with a large array index allocates unboundedly (resource exhaustion via untrusted JSON Pointer)

Summary

GenericPointer::Create() / Set(), when resolving a token whose array index is large, extends the array up to that index — Reserve(index + 1) then PushBack of index + 1 - size null values. A JSON Pointer such as /6626666666 (array index ~6.6 billion) therefore drives a ~37 GB allocation (MemoryPoolAllocator::Reallocmalloc), exhausting memory.

We want to be upfront: this looks like intended behavior — Create/Set on a non-existent array index is documented to extend the array to that index. So the realistic mitigation is caller-side: validate indices in untrusted JSON Pointers before Set/Create. We are reporting to ask whether you would consider a guard (or a documentation note), or whether this is by-design.

Detail

cpp
/* include/rapidjson/pointer.h — GenericPointer::Create() */
if (v->IsArray()) {
    if (t->index >= v->Size()) {
        v->Reserve(t->index + 1, allocator);          // index 6.6e9 -> Reserve(6.6e9+1)
        while (t->index >= v->Size())
            v->PushBack(ValueType().Move(), allocator);
        ...
    }
    v = &((*v)[t->index]);
}

Reserve(6.6e9+1) calls GenericValue::ReserveMemoryPoolAllocator::Reallocmalloc(~37e9) (trace in sanitizer.txt). There is no upper bound because the extension is intentional.

Reproduction

Minimal standalone using only the public Pointer/Document API (no fuzzer):

cpp
#include <rapidjson/document.h>
#include <rapidjson/pointer.h>
int main() {
  rapidjson::Document doc; doc.Parse("[]");                 // empty array root
  rapidjson::Pointer("/6626666666").Create(doc, doc.GetAllocator());  // index 6.6e9
  return 0;
}

Build: clang++ -O1 -I<rapidjson>/include poc.cpp -o poc, run ./poc. Create calls Reserve(6626666667)MemoryPoolAllocator::Realloc → a ~37 GB malloc → OOM. (Verified here: under a constrained address space the allocation is attempted and fails; the trace malloc(37307189960) ... #12 Pointer::Create pointer.h:480 is in sanitizer.txt.) Aside: on allocation failure MemoryPoolAllocator does not fail gracefully (it crashes) — but the primary issue is the unbounded size.