Просмотр исходного кода

Fixed encoder segfault.

I was being an absolute moron and not adjusting my two access
pointers to the data buffer after a realloc.
pull/8/merge
Paul J. Davis 14 лет назад
Родитель
Сommit
0ec13a0aef
1 измененных файлов: 59 добавлений и 50 удалений
  1. +59
    -50
      c_src/encoder.c

+ 59
- 50
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)) {

Загрузка…
Отмена
Сохранить