Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

### Unreleased

* Integrate with Ruby 4.1 `ruby_sized_xfree`.

### 2026-06-03 (2.19.8)

* Fix 1-byte buffer overread on EOS errors.
Expand Down
4 changes: 2 additions & 2 deletions ext/json/ext/fbuffer/fbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ static inline void fbuffer_consumed(FBuffer *fb, size_t consumed)
static void fbuffer_free(FBuffer *fb)
{
if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) {
ruby_xfree(fb->ptr);
JSON_SIZED_FREE_N(fb->ptr, fb->capa);
}
}

Expand All @@ -88,7 +88,7 @@ static void fbuffer_realloc(FBuffer *fb, size_t required)
fb->type = FBUFFER_HEAP_ALLOCATED;
MEMCPY(fb->ptr, old_buffer, char, fb->len);
} else {
REALLOC_N(fb->ptr, char, required);
JSON_SIZED_REALLOC_N(fb->ptr, char, required, fb->capa);
}
fb->capa = required;
}
Expand Down
1 change: 1 addition & 0 deletions ext/json/ext/generator/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
else
append_cflags("-std=c99")
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
have_func("ruby_xfree_sized", "ruby.h") # RUBY_VERSION >= 4.1

$defs << "-DJSON_GENERATOR"
$defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
Expand Down
18 changes: 18 additions & 0 deletions ext/json/ext/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ typedef unsigned char _Bool;
#endif
#endif

#ifndef HAVE_RUBY_XFREE_SIZED
static inline void ruby_xfree_sized(void *ptr, size_t oldsize)
{
ruby_xfree(ptr);
}

static inline void *ruby_xrealloc2_sized(void *ptr, size_t new_elems, size_t elem_size, size_t old_elems)
{
return ruby_xrealloc2(ptr, new_elems, elem_size);
}
#endif

# define JSON_SIZED_REALLOC_N(v, T, m, n) \
((v) = (T *)ruby_xrealloc2_sized((void *)(v), (m), sizeof(T), (n)))

# define JSON_SIZED_FREE(v) ruby_xfree_sized((void *)(v), sizeof(*(v)))
# define JSON_SIZED_FREE_N(v, n) ruby_xfree_sized((void *)(v), sizeof(*(v)) * (n))

#ifndef HAVE_RB_EXT_RACTOR_SAFE
# undef RUBY_TYPED_FROZEN_SHAREABLE
# define RUBY_TYPED_FROZEN_SHAREABLE 0
Expand Down
1 change: 1 addition & 0 deletions ext/json/ext/parser/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2
have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby
have_func("ruby_xfree_sized", "ruby.h") # RUBY_VERSION >= 4.1

if RUBY_ENGINE == "ruby"
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
Expand Down
6 changes: 3 additions & 3 deletions ext/json/ext/parser/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ static rvalue_stack *rvalue_stack_grow(rvalue_stack *stack, VALUE *handle, rvalu
if (stack->type == RVALUE_STACK_STACK_ALLOCATED) {
stack = rvalue_stack_spill(stack, handle, stack_ref);
} else {
REALLOC_N(stack->ptr, VALUE, required);
JSON_SIZED_REALLOC_N(stack->ptr, VALUE, required, stack->capa);
stack->capa = required;
}
return stack;
Expand Down Expand Up @@ -250,7 +250,7 @@ static void rvalue_stack_mark(void *ptr)

static void rvalue_stack_free_buffer(rvalue_stack *stack)
{
ruby_xfree(stack->ptr);
JSON_SIZED_FREE_N(stack->ptr, stack->capa);
stack->ptr = NULL;
}

Expand All @@ -260,7 +260,7 @@ static void rvalue_stack_free(void *ptr)
if (stack) {
rvalue_stack_free_buffer(stack);
#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
ruby_xfree(stack);
JSON_SIZED_FREE(stack);
#endif
}
}
Expand Down
Loading