[ruby/json] Fix a memory leak in #to_json methods
Fix: https://github.com/ruby/json/issues/460 The various `to_json` methods must rescue exceptions to free the buffer. ``` require 'json' data = 10_000.times.to_a << BasicObject.new 20.times do 100.times do begin data.to_json rescue NoMethodError end end puts `ps -o rss= -p #{$$}` end ``` ``` 20128 24992 29920 34672 39600 44336 49136 53936 58816 63616 68416 73232 78032 82896 87696 92528 97408 102208 107008 111808 ``` https://github.com/ruby/json/commit/d227d225ca
This commit is contained in:
parent
783dde2159
commit
d329896fb5
@ -397,7 +397,9 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|||||||
*/
|
*/
|
||||||
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
GENERATE_JSON(object);
|
rb_check_arity(argc, 0, 1);
|
||||||
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
||||||
|
return cState_partial_generate(Vstate, self, generate_json_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -409,7 +411,9 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
|||||||
* produced JSON string output further.
|
* produced JSON string output further.
|
||||||
*/
|
*/
|
||||||
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
||||||
GENERATE_JSON(array);
|
rb_check_arity(argc, 0, 1);
|
||||||
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
||||||
|
return cState_partial_generate(Vstate, self, generate_json_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RUBY_INTEGER_UNIFICATION
|
#ifdef RUBY_INTEGER_UNIFICATION
|
||||||
@ -420,7 +424,9 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
|||||||
*/
|
*/
|
||||||
static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
GENERATE_JSON(integer);
|
rb_check_arity(argc, 0, 1);
|
||||||
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
||||||
|
return cState_partial_generate(Vstate, self, generate_json_integer);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -431,7 +437,9 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
|||||||
*/
|
*/
|
||||||
static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
GENERATE_JSON(fixnum);
|
rb_check_arity(argc, 0, 1);
|
||||||
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
||||||
|
return cState_partial_generate(Vstate, self, generate_json_fixnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -441,7 +449,9 @@ static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
|||||||
*/
|
*/
|
||||||
static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
GENERATE_JSON(bignum);
|
rb_check_arity(argc, 0, 1);
|
||||||
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
||||||
|
return cState_partial_generate(Vstate, self, generate_json_bignum);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -452,7 +462,9 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
|||||||
*/
|
*/
|
||||||
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
GENERATE_JSON(float);
|
rb_check_arity(argc, 0, 1);
|
||||||
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
||||||
|
return cState_partial_generate(Vstate, self, generate_json_float);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -475,7 +487,9 @@ static VALUE mString_included_s(VALUE self, VALUE modul) {
|
|||||||
*/
|
*/
|
||||||
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
|
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
GENERATE_JSON(string);
|
rb_check_arity(argc, 0, 1);
|
||||||
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
||||||
|
return cState_partial_generate(Vstate, self, generate_json_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -530,7 +544,8 @@ static VALUE mString_Extend_json_create(VALUE self, VALUE o)
|
|||||||
*/
|
*/
|
||||||
static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
GENERATE_JSON(true);
|
rb_check_arity(argc, 0, 1);
|
||||||
|
return rb_utf8_str_new("true", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -540,7 +555,8 @@ static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
|||||||
*/
|
*/
|
||||||
static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
GENERATE_JSON(false);
|
rb_check_arity(argc, 0, 1);
|
||||||
|
return rb_utf8_str_new("false", 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -550,7 +566,8 @@ static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
|||||||
*/
|
*/
|
||||||
static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
GENERATE_JSON(null);
|
rb_check_arity(argc, 0, 1);
|
||||||
|
return rb_utf8_str_new("null", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -567,7 +584,7 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
|||||||
rb_scan_args(argc, argv, "01", &state);
|
rb_scan_args(argc, argv, "01", &state);
|
||||||
Check_Type(string, T_STRING);
|
Check_Type(string, T_STRING);
|
||||||
state = cState_from_state_s(cState, state);
|
state = cState_from_state_s(cState, state);
|
||||||
return cState_partial_generate(state, string);
|
return cState_partial_generate(state, string, generate_json_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void State_free(void *ptr)
|
static void State_free(void *ptr)
|
||||||
@ -834,6 +851,7 @@ static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_
|
|||||||
generate_json_bignum(buffer, Vstate, state, obj);
|
generate_json_bignum(buffer, Vstate, state, obj);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
||||||
{
|
{
|
||||||
double value = RFLOAT_VALUE(obj);
|
double value = RFLOAT_VALUE(obj);
|
||||||
@ -910,13 +928,14 @@ struct generate_json_data {
|
|||||||
VALUE vstate;
|
VALUE vstate;
|
||||||
JSON_Generator_State *state;
|
JSON_Generator_State *state;
|
||||||
VALUE obj;
|
VALUE obj;
|
||||||
|
void (*func)(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
static VALUE generate_json_try(VALUE d)
|
static VALUE generate_json_try(VALUE d)
|
||||||
{
|
{
|
||||||
struct generate_json_data *data = (struct generate_json_data *)d;
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
||||||
|
|
||||||
generate_json(data->buffer, data->vstate, data->state, data->obj);
|
data->func(data->buffer, data->vstate, data->state, data->obj);
|
||||||
|
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
@ -931,7 +950,7 @@ static VALUE generate_json_rescue(VALUE d, VALUE exc)
|
|||||||
return Qundef;
|
return Qundef;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
static VALUE cState_partial_generate(VALUE self, VALUE obj, void (*func)(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj))
|
||||||
{
|
{
|
||||||
GET_STATE(self);
|
GET_STATE(self);
|
||||||
|
|
||||||
@ -942,7 +961,8 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
|||||||
.buffer = &buffer,
|
.buffer = &buffer,
|
||||||
.vstate = self,
|
.vstate = self,
|
||||||
.state = state,
|
.state = state,
|
||||||
.obj = obj
|
.obj = obj,
|
||||||
|
.func = func
|
||||||
};
|
};
|
||||||
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
||||||
|
|
||||||
@ -958,7 +978,7 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
|||||||
*/
|
*/
|
||||||
static VALUE cState_generate(VALUE self, VALUE obj)
|
static VALUE cState_generate(VALUE self, VALUE obj)
|
||||||
{
|
{
|
||||||
VALUE result = cState_partial_generate(self, obj);
|
VALUE result = cState_partial_generate(self, obj, generate_json);
|
||||||
GET_STATE(self);
|
GET_STATE(self);
|
||||||
(void)state;
|
(void)state;
|
||||||
return result;
|
return result;
|
||||||
|
@ -54,18 +54,6 @@ typedef struct JSON_Generator_StateStruct {
|
|||||||
JSON_Generator_State *state; \
|
JSON_Generator_State *state; \
|
||||||
GET_STATE_TO(self, state)
|
GET_STATE_TO(self, state)
|
||||||
|
|
||||||
#define GENERATE_JSON(type) \
|
|
||||||
VALUE Vstate; \
|
|
||||||
JSON_Generator_State *state; \
|
|
||||||
\
|
|
||||||
rb_scan_args(argc, argv, "01", &Vstate); \
|
|
||||||
Vstate = cState_from_state_s(cState, Vstate); \
|
|
||||||
TypedData_Get_Struct(Vstate, JSON_Generator_State, &JSON_Generator_State_type, state); \
|
|
||||||
FBuffer buffer = {0}; \
|
|
||||||
fbuffer_init(&buffer, state->buffer_initial_length); \
|
|
||||||
generate_json_##type(&buffer, Vstate, state, self); \
|
|
||||||
return fbuffer_to_s(&buffer)
|
|
||||||
|
|
||||||
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self);
|
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self);
|
||||||
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self);
|
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self);
|
||||||
#ifdef RUBY_INTEGER_UNIFICATION
|
#ifdef RUBY_INTEGER_UNIFICATION
|
||||||
@ -99,7 +87,7 @@ static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_
|
|||||||
static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
|
static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
|
||||||
static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
|
static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
|
||||||
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
|
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
|
||||||
static VALUE cState_partial_generate(VALUE self, VALUE obj);
|
static VALUE cState_partial_generate(VALUE self, VALUE obj, void (*func)(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj));
|
||||||
static VALUE cState_generate(VALUE self, VALUE obj);
|
static VALUE cState_generate(VALUE self, VALUE obj);
|
||||||
static VALUE cState_from_state_s(VALUE self, VALUE opts);
|
static VALUE cState_from_state_s(VALUE self, VALUE opts);
|
||||||
static VALUE cState_indent(VALUE self);
|
static VALUE cState_indent(VALUE self);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user