Package: rrdtool
Version: 1.2.15-0.3
Severity: critical
Tags: patch,upstream,fixed-upstream

The non-threadsafe version of the rrdtool library has a wrong length for
the buffers of error strings, causing a segfaults in the python or perl
bindings.

This is a known upstream bug :
http://oss.oetiker.ch/rrdtool-trac/ticket/65

It has been fixed in version 1.2.16, with the following patch:
http://oss.oetiker.ch/rrdtool-trac/changeset?new=938&new_path=branches%
2F1.2%2Fprogram%2Fsrc%2Frrd_not_thread_safe.c&old=920&old_path=branches%
2F1.2%2Fprogram%2Fsrc%2Frrd_not_thread_safe.c
This patch is attached to this mail.

I'm also attaching a python script which reproduces this bug. It depends
on python-rrd. See the first lines for more explanations
Index: branches/1.2/program/src/rrd_not_thread_safe.c
===================================================================
--- branches/1.2/program/src/rrd_not_thread_safe.c (revision 860)
+++ branches/1.2/program/src/rrd_not_thread_safe.c (revision 935)
@@ -15,18 +15,24 @@
 #define ERRBUFLEN 256
 
-static char rrd_error[MAXLEN] = "\0";
-static char rrd_liberror[ERRBUFLEN] = "\0";
+static char rrd_error[MAXLEN+10];
+static char rrd_liberror[ERRBUFLEN+10];
+static int  rrd_context_init = 0;
 /* The global context is very useful in the transition period to even
    more thread-safe stuff, it can be used whereever we need a context
    and do not need to worry about concurrency. */
 static struct rrd_context global_ctx = {
-    sizeof(rrd_error),
-    sizeof(rrd_liberror),
+    MAXLEN,
+    ERRBUFLEN,
     rrd_error, 
     rrd_liberror
 };
-#include <stdarg.h>
+/* #include <stdarg.h> */
 
-struct rrd_context *rrd_get_context() {
+struct rrd_context *rrd_get_context(void) {
+    if (! rrd_context_init ){
+	rrd_context_init = 1;
+        global_ctx.rrd_error[0]='\0';
+        global_ctx.lib_errstr[0]='\0';
+    }
     return &global_ctx;
 }
#!/usr/bin/env python

# Depends: python-rrd

# Number of ds to use. 40 does not trigger the bug, 45 does
#ds_number = 40
ds_number = 45

import time, os, rrdtool

filename = "/tmp/test.rrd"
if os.path.exists(filename):
    os.remove(filename)
rrd_cmd = [filename, "--step", "300", "--start", str( int(time.time()) - 10 ), 'RRA:AVERAGE:0.5:1:12']
for i in range(ds_number):
    rrd_cmd.append("DS:ds%s:COUNTER:600:U:U" % i)
rrdtool.create(*rrd_cmd)

data = str(int(time.time()))
for i in range(ds_number + 1):
    data += ":1000"

print "updating..."
rrdtool.update(filename, data)

Reply via email to