diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2016-11-16 21:48:11 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2016-11-16 21:53:09 +0900 |
commit | f948f359b71d908e362bafa6bdad95b3398c339c (patch) | |
tree | 5e52243a70108c0cd51d7f8f45bf8e2b4ee480b4 /ext | |
parent | 18d13b1df09504548feb4cb9b259fed552d6a4d5 (diff) | |
download | psych-f948f359b71d908e362bafa6bdad95b3398c339c.zip |
Make Psych::Emitter store the IO object in an instance variable
The IO object given to Psych::Emitter#initialize is saved inside
LibYAML, yaml_emitter_t. This is a problem because Ruby's GC marker
can't find it, and can lead to use after free.
So, store the IO object in an instance variable and fetch from it every
time the write handler is called.
The segmentation fault can be reproduced with the following snippet:
emitter = Psych::Emitter.new(open("/dev/null", "w"))
GC.start
emitter.start_stream(Psych::Parser::UTF16BE) # make it write something
emitter.end_stream
Diffstat (limited to 'ext')
-rw-r--r-- | ext/psych/psych_emitter.c | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/ext/psych/psych_emitter.c b/ext/psych/psych_emitter.c index 371c285..52d1b70 100644 --- a/ext/psych/psych_emitter.c +++ b/ext/psych/psych_emitter.c @@ -8,6 +8,7 @@ #endif VALUE cPsychEmitter; +static ID id_io; static ID id_write; static ID id_line_width; static ID id_indentation; @@ -21,7 +22,7 @@ static void emit(yaml_emitter_t * emitter, yaml_event_t * event) static int writer(void *ctx, unsigned char *buffer, size_t size) { - VALUE io = (VALUE)ctx; + VALUE self = (VALUE)ctx, io = rb_attr_get(self, id_io); #ifdef HAVE_RUBY_ENCODING_H VALUE str = rb_enc_str_new((const char *)buffer, (long)size, rb_utf8_encoding()); #else @@ -94,7 +95,8 @@ static VALUE initialize(int argc, VALUE *argv, VALUE self) yaml_emitter_set_canonical(emitter, Qtrue == canonical ? 1 : 0); } - yaml_emitter_set_output(emitter, writer, (void *)io); + rb_ivar_set(self, id_io, io); + yaml_emitter_set_output(emitter, writer, (void *)self); return self; } @@ -562,6 +564,7 @@ void Init_psych_emitter(void) rb_define_method(cPsychEmitter, "line_width", line_width, 0); rb_define_method(cPsychEmitter, "line_width=", set_line_width, 1); + id_io = rb_intern("io"); id_write = rb_intern("write"); id_line_width = rb_intern("line_width"); id_indentation = rb_intern("indentation"); |