[erlang-bugs] Bug in ei_decode_big, implementation for ei_*encode_big
Paul Guyot
pguyot@REDACTED
Fri Oct 3 16:05:53 CEST 2008
Hello,
ei.h has the following FIXME notice before the prototype of the big
functions:
/* FIXME: is this really the best way to handle bignums? */
The thing is that ei_decode_big has a bug that makes it unusable,
around line 54 of decode_big.c:
for (i = 0; i < b->arity; ++i) {
dt[i] = u[i*2];
dt[i] |= ((unsigned short) u[(i*2)+1]) << 8; <--- this
is line 54
}
The high order bits of the 16-bits digit (short) are read, even if
the byte (at u[(i*2)+1]) doesn't belong to the big. In other words,
big numbers such as 16#1234567890 with an odd number of bytes are
decoded with a garbage byte (i.e. 16#XX1234567890).
The following change fixes the problem:
for (i = 0; i < b->arity; ++i) {
dt[i] = u[i*2];
if ((i*2 + 1) < digit_bytes)
{
dt[i] |= ((unsigned short) u[(i*2)+1]) << 8;
}
}
Also, ei_*encode_big is missing. Here is a sample implementation:
int ei_encode_big(char *buf, int *index, erlang_big* big)
{
unsigned short* digits = big->digits;
char *s = buf + *index;
char *s0 = s;
int arity = big->arity;
long digit_bytes = (arity * 2);
if (digit_bytes < 256)
{
if (buf != NULL)
{
put8(s, ERL_SMALL_BIG_EXT);
put8(s, digit_bytes);
} else {
s += 2;
}
} else {
if (buf != NULL)
{
put8(s, ERL_LARGE_BIG_EXT);
put32be(s, digit_bytes);
} else {
s += 5;
}
}
if (buf != NULL)
{
put8(s, big->is_neg);
int i;
for (i = 0; i < arity; ++i)
{
put16le(s, digits[i]);
}
} else {
s += 1 + (arity * 2);
}
*index += s-s0;
return 0;
}
int ei_x_encode_big(ei_x_buff* x, erlang_big* big)
{
int i = x->index;
ei_encode_big(NULL, &i, big);
if (!x_fix_buff(x, i))
return -1;
return ei_encode_big(x->buff, &x->index, big);
}
Regards,
Paul
More information about the erlang-bugs
mailing list