ext/yajl/yajl_buf.c in yajl-ruby-1.4.1 vs ext/yajl/yajl_buf.c in yajl-ruby-1.4.2
- old
+ new
@@ -33,47 +33,118 @@
#include "yajl_buf.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <stdio.h>
#define YAJL_BUF_INIT_SIZE 2048
struct yajl_buf_t {
+ yajl_buf_state state;
unsigned int len;
unsigned int used;
unsigned char * data;
yajl_alloc_funcs * alloc;
};
+static void *noop_realloc(void *ctx, void *ptr, unsigned int sz) {
+ fprintf(stderr, "Attempt to allocate on invalid yajl_buf_t\n");
+ abort();
+}
+static void *noop_malloc(void *ctx, unsigned int sz) { return noop_realloc(ctx, NULL, sz); }
+static void noop_free(void *ctx, void *ptr) { }
+
+static yajl_alloc_funcs noop_allocs = {
+ .malloc = &noop_malloc,
+ .realloc = &noop_realloc,
+ .free = &noop_free,
+};
+
+// A buffer to be returned if the initial allocation fails
+static struct yajl_buf_t buf_alloc_error = {
+ .state = yajl_buf_alloc_failed,
+ .alloc = &noop_allocs
+};
+
+#include <stdio.h>
+
+yajl_buf_state yajl_buf_err(yajl_buf buf)
+{
+ assert(buf);
+ return buf->state;
+}
+
static
-void yajl_buf_ensure_available(yajl_buf buf, unsigned int want)
+yajl_buf_state yajl_buf_set_error(yajl_buf buf, yajl_buf_state err)
{
+ buf->state = err;
+
+ // free and clear all data from the buffer
+ YA_FREE(buf->alloc, buf->data);
+ buf->len = 0;
+ buf->data = 0;
+ buf->used = 0;
+
+ return err;
+}
+
+static
+yajl_buf_state yajl_buf_ensure_available(yajl_buf buf, unsigned int want)
+{
unsigned int need;
assert(buf != NULL);
+ if (buf->state != yajl_buf_ok) {
+ return buf->state;
+ }
+
/* first call */
if (buf->data == NULL) {
buf->len = YAJL_BUF_INIT_SIZE;
buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len);
+ if (buf->data == NULL) {
+ return yajl_buf_set_error(buf, yajl_buf_overflow);
+ }
+
buf->data[0] = 0;
}
+ if (want == 0) {
+ return yajl_buf_ok;
+ }
+
need = buf->len;
while (want >= (need - buf->used)) need <<= 1;
+ // Check for overflow
+ if (need < buf->used) {
+ return yajl_buf_set_error(buf, yajl_buf_overflow);
+ }
+
if (need != buf->len) {
buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need);
+
+ if (buf->data == NULL) {
+ return yajl_buf_set_error(buf, yajl_buf_overflow);
+ }
+
buf->len = need;
}
+
+ return yajl_buf_ok;
}
yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc)
{
yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t));
+ if (b == NULL) {
+ return &buf_alloc_error;
+ }
+
memset((void *) b, 0, sizeof(struct yajl_buf_t));
b->alloc = alloc;
return b;
}
@@ -84,36 +155,46 @@
YA_FREE(buf->alloc, buf);
}
void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len)
{
- yajl_buf_ensure_available(buf, len);
+ if (yajl_buf_ensure_available(buf, len)) {
+ return;
+ }
if (len > 0) {
assert(data != NULL);
memcpy(buf->data + buf->used, data, len);
buf->used += len;
buf->data[buf->used] = 0;
}
}
void yajl_buf_clear(yajl_buf buf)
{
+ assert(buf);
+ assert(!yajl_buf_err(buf));
buf->used = 0;
if (buf->data) buf->data[buf->used] = 0;
}
const unsigned char * yajl_buf_data(yajl_buf buf)
{
+ assert(buf);
+ assert(!yajl_buf_err(buf));
return buf->data;
}
unsigned int yajl_buf_len(yajl_buf buf)
{
+ assert(buf);
+ assert(!yajl_buf_err(buf));
return buf->used;
}
void
yajl_buf_truncate(yajl_buf buf, unsigned int len)
{
+ assert(buf);
+ assert(!yajl_buf_err(buf));
assert(len <= buf->used);
buf->used = len;
}