[ruby/json] generator.c: don't start with a stack buffer in IO case

It was never intended to be initialized with a stack buffer
in that case, as when dumping into an IO we want larger chunks.

https://github.com/ruby/json/commit/996bac686d
This commit is contained in:
Jean Boussier 2026-06-08 09:11:20 +02:00 committed by git
parent f7047b300f
commit 9ac37cd626
2 changed files with 25 additions and 30 deletions

View File

@ -37,13 +37,17 @@ static void fbuffer_append_long(FBuffer *fb, long number);
static inline void fbuffer_append_char(FBuffer *fb, char newchr);
static VALUE fbuffer_finalize(FBuffer *fb);
static void fbuffer_stack_init(FBuffer *fb, size_t initial_length, char *stack_buffer, size_t stack_buffer_size)
static void fbuffer_init(FBuffer *fb, size_t initial_length, VALUE io, char *stack_buffer, size_t stack_buffer_size)
{
fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
if (stack_buffer) {
if (RTEST(io)) {
JSON_ASSERT(fb->type == FBUFFER_HEAP_ALLOCATED);
fb->io = io;
fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_IO_BUFFER_SIZE;
} else {
fb->type = FBUFFER_STACK_ALLOCATED;
fb->ptr = stack_buffer;
fb->capa = stack_buffer_size;
fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
}
#if JSON_DEBUG
fb->requested = 0;
@ -79,45 +83,40 @@ static void fbuffer_flush(FBuffer *fb)
fbuffer_clear(fb);
}
static void fbuffer_realloc(FBuffer *fb, size_t required)
static void fbuffer_realloc(FBuffer *fb, size_t new_capa)
{
if (required > fb->capa) {
if (new_capa > fb->capa) {
if (fb->type == FBUFFER_STACK_ALLOCATED) {
const char *old_buffer = fb->ptr;
fb->ptr = ALLOC_N(char, required);
fb->ptr = ALLOC_N(char, new_capa);
fb->type = FBUFFER_HEAP_ALLOCATED;
MEMCPY(fb->ptr, old_buffer, char, fb->len);
} else {
JSON_SIZED_REALLOC_N(fb->ptr, char, required, fb->capa);
JSON_SIZED_REALLOC_N(fb->ptr, char, new_capa, fb->capa);
}
fb->capa = required;
fb->capa = new_capa;
}
}
static void fbuffer_do_inc_capa(FBuffer *fb, size_t requested)
{
if (RB_UNLIKELY(fb->io)) {
if (fb->capa < FBUFFER_IO_BUFFER_SIZE) {
fbuffer_realloc(fb, FBUFFER_IO_BUFFER_SIZE);
} else {
if (fb->capa != 0) {
fbuffer_flush(fb);
}
if (RB_LIKELY(requested < fb->capa)) {
return;
if (RB_LIKELY(requested < fb->capa)) {
return;
}
}
}
size_t required;
size_t new_capa = fb->capa ? fb->capa : fb->initial_length;
size_t needed_capa = requested + fb->len;
if (RB_UNLIKELY(!fb->ptr)) {
fb->ptr = ALLOC_N(char, fb->initial_length);
fb->capa = fb->initial_length;
while (new_capa < needed_capa) {
new_capa *= 2;
}
for (required = fb->capa; requested > required - fb->len; required <<= 1);
fbuffer_realloc(fb, required);
fbuffer_realloc(fb, new_capa);
}
static inline void fbuffer_inc_capa(FBuffer *fb, size_t requested)

View File

@ -1308,10 +1308,8 @@ static inline VALUE cState_partial_generate(VALUE self, VALUE obj, generator_fun
GET_STATE(self);
char stack_buffer[FBUFFER_STACK_SIZE];
FBuffer buffer = {
.io = RTEST(io) ? io : Qfalse,
};
fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
FBuffer buffer = { 0 };
fbuffer_init(&buffer, state->buffer_initial_length, io, stack_buffer, FBUFFER_STACK_SIZE);
struct generate_json_data data = {
.buffer = &buffer,
@ -1870,10 +1868,8 @@ static VALUE cState_m_do_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io,
configure_state(&state, Qfalse, opts);
char stack_buffer[FBUFFER_STACK_SIZE];
FBuffer buffer = {
.io = RTEST(io) ? io : Qfalse,
};
fbuffer_stack_init(&buffer, state.buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
FBuffer buffer = { 0 };
fbuffer_init(&buffer, state.buffer_initial_length, io, stack_buffer, FBUFFER_STACK_SIZE);
struct generate_json_data data = {
.buffer = &buffer,