Fixed encoder segfault.
I was being an absolute moron and not adjusting my two access
pointers to the data buffer after a realloc.
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 @@
int count;
ERL_NIF_TERM iolist;
- ErlNifBinary curr;
- int cleared;
+ ErlNifBinary* curr;
char* p;
unsigned char* u;
@@ -23,21 +23,23 @@
} 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 @@
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 @@
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 @@
{
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 @@
ErlNifBinary bin;
char atom[512];
+ unsigned char* data;
+ size_t size;
+
int esc_extra = 0;
int ulen;
int ui;
@@ -122,20 +129,21 @@
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 @@
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 @@
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 @@
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 @@
Encoder enc;
Encoder* e = &enc;
+ ErlNifBinary bin;
ERL_NIF_TERM ret;
ERL_NIF_TERM stack;
@@ -360,7 +369,7 @@
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 @@
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)) {