summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-11-16 21:48:11 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-11-16 21:53:09 +0900
commitf948f359b71d908e362bafa6bdad95b3398c339c (patch)
tree5e52243a70108c0cd51d7f8f45bf8e2b4ee480b4 /ext
parent18d13b1df09504548feb4cb9b259fed552d6a4d5 (diff)
downloadpsych-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.c7
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");