Browse files

Free vasprintf() results with Ruby Enterprise Edition's system_free()…

… API if possible, and fix some potential memory leaks while we're at it.

REE uses tcmalloc by default, but on OS X libc's vasprintf() allocates
memory with the system's malloc() function instead of tcmalloc's. If we
were to free its result with tcmalloc's free(), it will cause a crash.
This commit makes use of REE system_free() function to free vasprintf()
results. More info: https://github.com/FooBarWidget/rubyenterpriseedition187-330/blob/release/system_allocator.c

Some functions also leak string memory if an exception is raised. This
patch makes sure those strings are freed no matter what.
  • Loading branch information...
1 parent 984a554 commit 5a4b95519c0143bb23dd7faf6702220553c484b2 @FooBarWidget committed Feb 15, 2011
Showing with 38 additions and 6 deletions.
  1. +24 −1 ext/nokogiri/nokogiri.c
  2. +9 −4 ext/nokogiri/xml_sax_parser.c
  3. +5 −1 ext/nokogiri/xslt_stylesheet.c
View
25 ext/nokogiri/nokogiri.c
@@ -23,14 +23,37 @@ int vasprintf (char **strp, const char *fmt, va_list ap)
}
#endif
+#ifdef USING_SYSTEM_ALLOCATOR_LIBRARY /* Ruby Enterprise Edition with tcmalloc */
+void vasprintf_free (void *p)
+{
+ system_free(p);
+}
+#else
+void vasprintf_free (void *p)
+{
+ free(p);
+}
+#endif
+
+#ifndef __MACRUBY__
+/* Allocate strdupped strings with the same memory allocator Ruby uses. */
+static char *ruby_strdup(const char *s)
+{
+ size_t len = strlen(s);
+ char *result = ruby_xmalloc((ssize_t) (len + 1));
+ memcpy(result, s, len + 1);
+ return result;
+}
+#endif
+
void Init_nokogiri()
{
#ifndef __MACRUBY__
xmlMemSetup(
(xmlFreeFunc)ruby_xfree,
(xmlMallocFunc)ruby_xmalloc,
(xmlReallocFunc)ruby_xrealloc,
- strdup
+ ruby_strdup
);
#endif
View
13 ext/nokogiri/xml_sax_parser.c
@@ -1,6 +1,7 @@
#include <xml_sax_parser.h>
int vasprintf (char **strp, const char *fmt, va_list ap);
+void vasprintf_free (void *p);
static ID id_start_document, id_end_document, id_start_element, id_end_element;
static ID id_start_element_namespace, id_end_element_namespace;
@@ -198,29 +199,33 @@ static void warning_func(void * ctx, const char *msg, ...)
VALUE self = NOKOGIRI_SAX_SELF(ctx);
VALUE doc = rb_iv_get(self, "@document");
char * message;
+ VALUE ruby_message;
va_list args;
va_start(args, msg);
vasprintf(&message, msg, args);
va_end(args);
- rb_funcall(doc, id_warning, 1, NOKOGIRI_STR_NEW2(message));
- free(message);
+ ruby_message = NOKOGIRI_STR_NEW2(message);
+ vasprintf_free(message);
+ rb_funcall(doc, id_warning, 1, ruby_message);
}
static void error_func(void * ctx, const char *msg, ...)
{
VALUE self = NOKOGIRI_SAX_SELF(ctx);
VALUE doc = rb_iv_get(self, "@document");
char * message;
+ VALUE ruby_message;
va_list args;
va_start(args, msg);
vasprintf(&message, msg, args);
va_end(args);
- rb_funcall(doc, id_error, 1, NOKOGIRI_STR_NEW2(message));
- free(message);
+ ruby_message = NOKOGIRI_STR_NEW2(message);
+ vasprintf_free(message);
+ rb_funcall(doc, id_error, 1, ruby_message);
}
static void cdata_block(void * ctx, const xmlChar * value, int len)
View
6 ext/nokogiri/xslt_stylesheet.c
@@ -8,6 +8,7 @@
VALUE xslt;
int vasprintf (char **strp, const char *fmt, va_list ap);
+void vasprintf_free (void *p);
static void dealloc(xsltStylesheetPtr doc)
{
@@ -20,13 +21,16 @@ NORETURN(static void xslt_generic_error_handler(void * ctx, const char *msg, ...
static void xslt_generic_error_handler(void * ctx, const char *msg, ...)
{
char * message;
+ VALUE exception;
va_list args;
va_start(args, msg);
vasprintf(&message, msg, args);
va_end(args);
- rb_exc_raise(rb_exc_new2(rb_eRuntimeError, message));
+ exception = rb_exc_new2(rb_eRuntimeError, message);
+ vasprintf_free(message);
+ rb_exc_raise(exception);
}
/*

0 comments on commit 5a4b955

Please sign in to comment.