From 0ec13a0aefa83e45ac8f6b53c34236ff6d5f3c4b Mon Sep 17 00:00:00 2001 From: "Paul J. Davis" Date: Mon, 4 Apr 2011 20:44:03 -0400 Subject: [PATCH] Fixed encoder segfault. I was being an absolute moron and not adjusting my two access pointers to the data buffer after a realloc. --- c_src/encoder.c | 109 ++++++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/c_src/encoder.c b/c_src/encoder.c index 1238cd7..67c87c5 100644 --- a/c_src/encoder.c +++ b/c_src/encoder.c @@ -7,6 +7,7 @@ #define BIN_INC_SIZE 1024 + typedef struct { ErlNifEnv* env; jiffy_st* atoms; @@ -14,8 +15,7 @@ typedef struct { int count; ERL_NIF_TERM iolist; - ErlNifBinary curr; - int cleared; + ErlNifBinary* curr; char* p; unsigned char* u; @@ -23,21 +23,23 @@ typedef struct { } Encoder; int -enc_init(Encoder* e, ErlNifEnv* env) +enc_init(Encoder* e, ErlNifEnv* env, ErlNifBinary* bin) { e->env = env; e->atoms = enif_priv_data(env); - e->count = 0; + e->iolist = enif_make_list(env, 0); - if(!enif_alloc_binary(BIN_INC_SIZE, &(e->curr))) { + e->curr = bin; + if(!enif_alloc_binary(BIN_INC_SIZE, e->curr)) { return 0; } - e->cleared = 0; - e->p = (char*) e->curr.data; - e->u = (unsigned char*) e->curr.data; + memset(e->curr->data, 0, e->curr->size); + + e->p = (char*) e->curr->data; + e->u = (unsigned char*) e->curr->data; e->i = 0; return 1; @@ -46,8 +48,8 @@ enc_init(Encoder* e, ErlNifEnv* env) void enc_destroy(Encoder* e) { - if(!e->cleared) { - enif_release_binary(&(e->curr)); + if(e->curr != NULL) { + enif_release_binary(e->curr); } } @@ -61,14 +63,14 @@ enc_error(Encoder* e, const char* msg) int enc_result(Encoder* e, ERL_NIF_TERM* value) { - if(e->i != e->curr.size) { - if(!enif_realloc_binary(&(e->curr), e->i)) { + if(e->i != e->curr->size) { + if(!enif_realloc_binary(e->curr, e->i)) { return 0; } } - *value = enif_make_binary(e->env, &(e->curr)); - e->cleared = 1; + *value = enif_make_binary(e->env, e->curr); + e->curr = NULL; return 1; } @@ -77,19 +79,21 @@ enc_ensure(Encoder* e, size_t req) { size_t new_sz; - if(req < e->curr.size - e->i) { + if(req < e->curr->size - e->i) { return 1; } - new_sz = req - (e->curr.size - e->i); + new_sz = req - (e->curr->size - e->i) + e->curr->size; new_sz += BIN_INC_SIZE - (new_sz % BIN_INC_SIZE); - assert(new_sz % BIN_INC_SIZE == 0 && "Invalid modulo math."); - - if(!enif_realloc_binary(&(e->curr), new_sz)) { + assert(new_sz > e->curr->size && "Invalid size calculation."); + + if(!enif_realloc_binary(e->curr, new_sz)) { return 0; } - - memset(&(e->u[e->i]), 0, e->curr.size - e->i); + e->p = (char*) e->curr->data; + e->u = (unsigned char*) e->curr->data; + + memset(&(e->u[e->i]), 0, e->curr->size - e->i); return 1; } @@ -113,6 +117,9 @@ enc_string(Encoder* e, ERL_NIF_TERM val) ErlNifBinary bin; char atom[512]; + unsigned char* data; + size_t size; + int esc_extra = 0; int ulen; int ui; @@ -122,20 +129,21 @@ enc_string(Encoder* e, ERL_NIF_TERM val) if(!enif_inspect_binary(e->env, val, &bin)) { return 0; } + data = bin.data; + size = bin.size; } else if(enif_is_atom(e->env, val)) { if(!enif_get_atom(e->env, val, atom, 512, ERL_NIF_LATIN1)) { return 0; } - // Fake as a binary for code below. - bin.data = (unsigned char*) atom; - bin.size = strlen(atom); + data = (unsigned char*) atom; + size = strlen(atom); } else { return 0; } i = 0; - while(i < bin.size) { - switch((char) bin.data[i]) { + while(i < size) { + switch((char) data[i]) { case '\"': case '\\': case '/': @@ -148,71 +156,71 @@ enc_string(Encoder* e, ERL_NIF_TERM val) i++; continue; default: - if(bin.data[i] < 0x20) { + if(data[i] < 0x20) { esc_extra += 5; i++; continue; - } else if(bin.data[i] < 0x80) { + } else if(data[i] < 0x80) { i++; continue; } ulen = -1; - if((bin.data[i] & 0xE0) == 0xC0) { + if((data[i] & 0xE0) == 0xC0) { ulen = 1; - } else if((bin.data[i] & 0xF0) == 0xE0) { + } else if((data[i] & 0xF0) == 0xE0) { ulen = 2; - } else if((bin.data[i] & 0xF8) == 0xF0) { + } else if((data[i] & 0xF8) == 0xF0) { ulen = 3; - } else if((bin.data[i] & 0xFC) == 0xF8) { + } else if((data[i] & 0xFC) == 0xF8) { ulen = 4; - } else if((bin.data[i] & 0xFE) == 0xFC) { + } else if((data[i] & 0xFE) == 0xFC) { ulen = 5; } if(ulen < 0) { return 0; } - if(i+1+ulen > bin.size) { + if(i+1+ulen > size) { return 0; } for(ui = 0; ui < ulen; ui++) { - if((bin.data[i+1+ui] & 0xC0) != 0x80) { + if((data[i+1+ui] & 0xC0) != 0x80) { return 0; } } if(ulen == 1) { - if((bin.data[i] & 0x1E) == 0) + if((data[i] & 0x1E) == 0) return 0; } else if(ulen == 2) { - if((bin.data[i] & 0x0F) + (bin.data[i+1] & 0x20) == 0) + if((data[i] & 0x0F) + (data[i+1] & 0x20) == 0) return 0; } else if(ulen == 3) { - if((bin.data[i] & 0x07) + (bin.data[i+1] & 0x30) == 0) + if((data[i] & 0x07) + (data[i+1] & 0x30) == 0) return 0; } else if(ulen == 4) { - if((bin.data[i] & 0x03) + (bin.data[i+1] & 0x38) == 0) + if((data[i] & 0x03) + (data[i+1] & 0x38) == 0) return 0; } else if(ulen == 5) { - if((bin.data[i] & 0x01) + (bin.data[i+1] & 0x3C) == 0) + if((data[i] & 0x01) + (data[i+1] & 0x3C) == 0) return 0; } i += 1 + ulen; } } - if(!enc_ensure(e, bin.size + esc_extra + 2)) { + if(!enc_ensure(e, size + esc_extra + 2)) { return 0; } e->p[e->i++] = '\"'; i = 0; - while(i < bin.size) { - switch((char) bin.data[i]) { + while(i < size) { + switch((char) data[i]) { case '\"': case '\\': case '/': e->p[e->i++] = '\\'; - e->u[e->i++] = bin.data[i]; + e->u[e->i++] = data[i]; i++; continue; case '\b': @@ -241,16 +249,16 @@ enc_string(Encoder* e, ERL_NIF_TERM val) i++; continue; default: - if(bin.data[i] < 0x20) { + if(data[i] < 0x20) { e->p[e->i++] = '\\'; e->p[e->i++] = 'u'; - if(!int_to_hex(bin.data[i], &(e->p[e->i]))) { + if(!int_to_hex(data[i], &(e->p[e->i]))) { return 0; } e->i += 4; i++; } else { - e->u[e->i++] = bin.data[i++]; + e->u[e->i++] = data[i++]; } } } @@ -282,7 +290,7 @@ enc_double(Encoder* e, double val) return 0; } - snprintf(&(e->p[e->i]), 32, "%g", val); + snprintf(&(e->p[e->i]), 31, "%g", val); e->i += strlen(&(e->p[e->i])); e->count++; @@ -344,6 +352,7 @@ encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) Encoder enc; Encoder* e = &enc; + ErlNifBinary bin; ERL_NIF_TERM ret; ERL_NIF_TERM stack; @@ -360,7 +369,7 @@ encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return enif_make_badarg(env); } - if(!enc_init(e, env)) { + if(!enc_init(e, env, &bin)) { return enif_make_badarg(env); } @@ -412,7 +421,7 @@ encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) stack = enif_make_list_cell(env, tuple[1], stack); } else if(enif_is_identical(curr, e->atoms->ref_array)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { - ret = enc_error(e, "internal_error.5"); + ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) {