aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2010-06-16 17:58:35 +0200
committerSverker Eriksson <[email protected]>2010-07-05 15:29:17 +0200
commite5d41874ec0d2aaf2037d10dd92091edd2405924 (patch)
tree29bd6fc639f50c35555cfbadeacaf711bef12bde
parentfdf51bf4a7127883705d71dab1bbd4556b28e05a (diff)
downloadotp-e5d41874ec0d2aaf2037d10dd92091edd2405924.tar.gz
otp-e5d41874ec0d2aaf2037d10dd92091edd2405924.tar.bz2
otp-e5d41874ec0d2aaf2037d10dd92091edd2405924.zip
term_to_binary use all 32 bits of INTEGER_EXT
Earlier, external format INTEGER_EXT was only produced for 28-bit signed integers. Now full 32-bit signed integers are produced as INTEGER_EXT to avoid the more costly SMALL_BIG_EXT format. Both old and new code can read 32-bit INTEGER_EXT. Also fixed integer encoding bugs in erl_interface erl_encode/erl_decode. (Thanks to Alexander Demidenko for reporting)
-rw-r--r--erts/emulator/beam/external.c53
-rw-r--r--erts/emulator/test/hash_SUITE.erl8
-rw-r--r--lib/erl_interface/src/legacy/erl_marshal.c93
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE.erl34
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c50
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c102
6 files changed, 216 insertions, 124 deletions
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index f41b61d73d..466165f26f 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -65,11 +65,9 @@
# endif
#endif
-/*
- * For backward compatibility reasons, only encode integers that
- * fit in 28 bits (signed) using INTEGER_EXT.
+/* Does Sint fit in Sint32?
*/
-#define IS_SSMALL28(x) (((Uint) (((x) >> (28-1)) + 1)) < 2)
+#define IS_SSMALL32(x) (((Uint) (((x) >> (32-1)) + 1)) < 2)
/*
* Valid creations for nodes are 1, 2, or 3. 0 can also be sent
@@ -1571,13 +1569,15 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags)
case SMALL_DEF:
{
+ /* From R14B we no longer restrict INTEGER_EXT to 28 bits,
+ * as done earlier for backward compatibility reasons. */
Sint val = signed_val(obj);
if ((Uint)val < 256) {
*ep++ = SMALL_INTEGER_EXT;
put_int8(val, ep);
ep++;
- } else if (sizeof(Sint) == 4 || IS_SSMALL28(val)) {
+ } else if (sizeof(Sint) == 4 || IS_SSMALL32(val)) {
*ep++ = INTEGER_EXT;
put_int32(val, ep);
ep += 4;
@@ -1599,18 +1599,32 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags)
break;
case BIG_DEF:
- if ((n = big_bytes(obj)) < 256) {
- *ep++ = SMALL_BIG_EXT;
- put_int8(n, ep);
- ep += 1;
- }
- else {
- *ep++ = LARGE_BIG_EXT;
- put_int32(n, ep);
- ep += 4;
+ {
+ int sign = big_sign(obj);
+ n = big_bytes(obj);
+ if (sizeof(Sint)==4 && n<=4) {
+ Uint dig = big_digit(obj,0);
+ Sint val = sign ? -dig : dig;
+ if ((val<0) == sign) {
+ *ep++ = INTEGER_EXT;
+ put_int32(val, ep);
+ ep += 4;
+ break;
+ }
+ }
+ if (n < 256) {
+ *ep++ = SMALL_BIG_EXT;
+ put_int8(n, ep);
+ ep += 1;
+ }
+ else {
+ *ep++ = LARGE_BIG_EXT;
+ put_int32(n, ep);
+ ep += 4;
+ }
+ *ep++ = sign;
+ ep = big_to_bytes(obj, ep);
}
- *ep++ = big_sign(obj);
- ep = big_to_bytes(obj, ep);
break;
case PID_DEF:
@@ -2687,7 +2701,7 @@ encode_size_struct2(ErtsAtomCacheMap *acmp, Eterm obj, unsigned dflags)
if ((Uint)val < 256)
result += 1 + 1; /* SMALL_INTEGER_EXT */
- else if (sizeof(Sint) == 4 || IS_SSMALL28(val))
+ else if (sizeof(Sint) == 4 || IS_SSMALL32(val))
result += 1 + 4; /* INTEGER_EXT */
else {
DeclareTmpHeapNoproc(tmp_big,2);
@@ -2699,7 +2713,10 @@ encode_size_struct2(ErtsAtomCacheMap *acmp, Eterm obj, unsigned dflags)
}
break;
case BIG_DEF:
- if ((i = big_bytes(obj)) < 256)
+ i = big_bytes(obj);
+ if (sizeof(Sint)==4 && i <= 4 && (big_digit(obj,0)-big_sign(obj)) < (1<<31))
+ result += 1 + 4; /* INTEGER_EXT */
+ else if (i < 256)
result += 1 + 1 + 1 + i; /* tag,size,sign,digits */
else
result += 1 + 4 + 1 + i; /* tag,size,sign,digits */
diff --git a/erts/emulator/test/hash_SUITE.erl b/erts/emulator/test/hash_SUITE.erl
index 85bdb8bff8..f5d1871bfb 100644
--- a/erts/emulator/test/hash_SUITE.erl
+++ b/erts/emulator/test/hash_SUITE.erl
@@ -480,14 +480,14 @@ otp_5292_test() ->
S2 = md5([md5(hash_int(S, E, PH)) || {Start, N, Sz} <- d(),
{S, E} <- int(Start, N, Sz)]),
?line Comment = case S1 of
- <<43,186,76,102,87,4,110,245,203,177,206,6,130,69,43,99>> ->
+ <<4,248,208,156,200,131,7,1,173,13,239,173,112,81,16,174>> ->
?line big = erlang:system_info(endian),
"Big endian machine";
- <<21,206,139,15,149,28,167,81,98,225,132,254,49,125,174,195>> ->
+ <<180,28,33,231,239,184,71,125,76,47,227,241,78,184,176,233>> ->
?line little = erlang:system_info(endian),
"Little endian machine"
end,
- ?line <<140,37,79,80,26,242,130,22,20,229,123,240,223,244,43,99>> = S2,
+ ?line <<124,81,198,121,174,233,19,137,10,83,33,80,226,111,238,99>> = S2,
?line 2 = erlang:hash(1, (1 bsl 27) -1),
?line {'EXIT', _} = (catch erlang:hash(1, (1 bsl 27))),
{comment, Comment}.
@@ -507,7 +507,7 @@ hash_int(Start, End, F) ->
{Start, End, md5(HL)}.
md5(T) ->
- erlang:md5(term_to_binary(T)).
+ erlang:md5(term_to_binary(T)).
bit_level_binaries() ->
?line [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c
index c57c552b90..18315bfbd3 100644
--- a/lib/erl_interface/src/legacy/erl_marshal.c
+++ b/lib/erl_interface/src/legacy/erl_marshal.c
@@ -26,6 +26,7 @@
#include <ctype.h>
#include <sys/types.h>
#include <string.h>
+#include <limits.h>
#include "erl_interface.h"
#include "erl_marshal.h"
@@ -178,26 +179,14 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
return 0;
case ERL_INTEGER:
- i = ep->uval.ival.i;
- /* ERL_SMALL_BIG */
- if ((i > ERL_MAX) || (i < ERL_MIN)) {
- *(*ext)++ = ERL_SMALL_BIG_EXT;
- *(*ext)++ = 4; /* four bytes */
- if ((*(*ext)++ = ((i>>31) & 0x01))) /* sign byte */
- i = -i;
- *(*ext)++ = i & 0xff; /* LSB first */
- *(*ext)++ = (i >> 8) & 0xff;
- *(*ext)++ = (i >> 16) & 0xff;
- *(*ext)++ = (i >> 24) & 0x7f; /* Don't include the sign bit */
- return 0;
- }
+ i = ep->uval.ival.i;
/* SMALL_INTEGER */
if ((i < 256) && (i >= 0)) {
*(*ext)++ = ERL_SMALL_INTEGER_EXT;
*(*ext)++ = i & 0xff;
return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (i >> 24) & 0xff;
*(*ext)++ = (i >> 16) & 0xff;
@@ -208,23 +197,23 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
case ERL_U_INTEGER:
u = ep->uval.uival.u;
/* ERL_U_SMALL_BIG */
- if (u > ERL_MAX) {
- *(*ext)++ = ERL_SMALL_BIG_EXT;
- *(*ext)++ = 4; /* four bytes */
- *(*ext)++ = 0; /* sign byte */
- *(*ext)++ = u & 0xff; /* LSB first */
- *(*ext)++ = (u >> 8) & 0xff;
- *(*ext)++ = (u >> 16) & 0xff;
- *(*ext)++ = (u >> 24) & 0xff;
- return 0;
+ if ((int)u < 0) {
+ *(*ext)++ = ERL_SMALL_BIG_EXT;
+ *(*ext)++ = 4; /* four bytes */
+ *(*ext)++ = 0; /* sign byte */
+ *(*ext)++ = u & 0xff; /* LSB first */
+ *(*ext)++ = (u >> 8) & 0xff;
+ *(*ext)++ = (u >> 16) & 0xff;
+ *(*ext)++ = (u >> 24) & 0xff;
+ return 0;
}
/* SMALL_INTEGER */
- if ((u < 256) && (u >= 0)) {
+ if (u < 256) {
*(*ext)++ = ERL_SMALL_INTEGER_EXT;
*(*ext)++ = u & 0xff;
return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (u >> 24) & 0xff;
*(*ext)++ = (u >> 16) & 0xff;
@@ -234,29 +223,28 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
case ERL_LONGLONG:
l = ep->uval.llval.i;
/* ERL_SMALL_BIG */
- if ((l > ((long long) ERL_MAX)) ||
- (l < ((long long) ERL_MIN))) {
- *(*ext)++ = ERL_SMALL_BIG_EXT;
- *(*ext)++ = 8; /* eight bytes */
- if ((*(*ext)++ = ((l>>63) & 0x01))) /* sign byte */
+ if (l > ((long long) INT_MAX) || l < ((long long) INT_MIN)) {
+ *(*ext)++ = ERL_SMALL_BIG_EXT;
+ *(*ext)++ = 8;
+ if ((*(*ext)++ = (l<0))) /* sign byte */
l = -l;
- *(*ext)++ = l & 0xff; /* LSB first */
+ *(*ext)++ = l & 0xff; /* LSB first */
*(*ext)++ = (l >> 8) & 0xff;
*(*ext)++ = (l >> 16) & 0xff;
- *(*ext)++ = (l >> 24) & 0xff;
- *(*ext)++ = (l >> 32) & 0xff;
- *(*ext)++ = (l >> 40) & 0xff;
- *(*ext)++ = (l >> 48) & 0xff;
- *(*ext)++ = (l >> 56) & 0x7f; /* Don't include the sign bit */
+ *(*ext)++ = (l >> 24) & 0xff;
+ *(*ext)++ = (l >> 32) & 0xff;
+ *(*ext)++ = (l >> 40) & 0xff;
+ *(*ext)++ = (l >> 48) & 0xff;
+ *(*ext)++ = (l >> 56) & 0xff;
return 0;
}
/* SMALL_INTEGER */
if ((l < 256) && (l >= 0)) {
- *(*ext)++ = ERL_SMALL_INTEGER_EXT;
- *(*ext)++ = l & 0xff;
- return 0;
+ *(*ext)++ = ERL_SMALL_INTEGER_EXT;
+ *(*ext)++ = l & 0xff;
+ return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (l >> 24) & 0xff;
*(*ext)++ = (l >> 16) & 0xff;
@@ -267,7 +255,7 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
case ERL_U_LONGLONG:
ul = ep->uval.ullval.u;
/* ERL_U_SMALL_BIG */
- if (ul > ((unsigned long long) ERL_MAX)) {
+ if (ul > ((unsigned long long) INT_MAX)) {
*(*ext)++ = ERL_SMALL_BIG_EXT;
*(*ext)++ = 8; /* eight bytes */
*(*ext)++ = 0; /* sign byte */
@@ -287,7 +275,7 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
*(*ext)++ = ul & 0xff;
return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (ul >> 24) & 0xff;
*(*ext)++ = (ul >> 16) & 0xff;
@@ -732,11 +720,6 @@ static ETERM *erl_decode_it(unsigned char **ext)
if (arity > 8)
goto big_truncate;
- if (arity == 8 && ((*ext)[7] & 0x80) && sign) {
- /* MSB already occupied ! */
- goto big_truncate;
- }
-
if (arity == 4 && ((*ext)[3] & 0x80) && !sign) {
/* It will fit into an unsigned int !! */
u = (((*ext)[3] << 24)|((*ext)[2])<< 16|((*ext)[1]) << 8 |(**ext));
@@ -747,14 +730,10 @@ static ETERM *erl_decode_it(unsigned char **ext)
return ep;
} else if (arity == 4 && !((*ext)[3] & 0x80)) {
/* It will fit into an int !!
- * Note: It comes in "one's-complement notation"
*/
- if (sign)
- i = (int) (~(((*ext)[3] << 24) | ((*ext)[2])<< 16 |
- ((*ext)[1]) << 8 | (**ext)) | (unsigned int) sign);
- else
- i = (int) (((*ext)[3] << 24) | ((*ext)[2])<< 16 |
- ((*ext)[1]) << 8 | (**ext));
+ i = (int) (((*ext)[3] << 24) | ((*ext)[2])<< 16 |
+ ((*ext)[1]) << 8 | (**ext));
+ if (sign) i = -i;
ERL_TYPE(ep) = ERL_INTEGER;
ep->uval.ival.i = i;
*ext += arity;
@@ -780,8 +759,10 @@ static ETERM *erl_decode_it(unsigned char **ext)
for(x = 0 ; x < arity ; x++) {
l |= ((long long)(*ext)[x]) << ((long long)(8*x));
}
-
- if (sign) l = (long long) (~l | (unsigned long long) sign);
+ if (sign) {
+ l = -l;
+ if (l > 0) goto big_truncate;
+ }
ERL_TYPE(ep) = ERL_LONGLONG;
ep->uval.llval.i = l;
diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl
index c6858b45ad..09a37409f2 100644
--- a/lib/erl_interface/test/ei_decode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_SUITE.erl
@@ -222,14 +222,16 @@ send_integers(P) ->
?line send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*)
?line send_term_as_binary(P,-1), % INTEGER_EXT largest neg
- ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT largest (28 bits)
- ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT smallest
- ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT smallest pos(*)
- ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT largest neg (*)
-
- ?line send_term_as_binary(P, 16#7fffffff), % SMALL_BIG_EXT largest i32
- ?line send_term_as_binary(P,-16#80000000), % SMALL_BIG_EXT smallest i32
-
+ ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT old largest (28 bits)
+ ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT old smallest
+ ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT old smallest pos(*)
+ ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT old largest neg (*)
+
+ ?line send_term_as_binary(P, 16#7fffffff), % INTEGER_EXT new largest (32 bits)
+ ?line send_term_as_binary(P,-16#80000000), % INTEGER_EXT new smallest (32 bis)
+ ?line send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*)
+ ?line send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*)
+
case erlang:system_info(wordsize) of
4 ->
?line send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32
@@ -266,15 +268,17 @@ send_integers2(P) ->
?line send_term_as_binary(P,255), % SMALL_INTEGER_EXT largest
?line send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*)
?line send_term_as_binary(P,-1), % INTEGER_EXT largest neg
+
+ ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT old largest (28 bits)
+ ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT old smallest
+ ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT old smallest pos(*)
+ ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT old largest neg (*)
- ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT largest (28 bits)
- ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT smallest
- ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT smallest pos(*)
- ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT largest neg (*)
+ ?line send_term_as_binary(P, 16#7fffffff), % INTEGER_EXT new largest (32 bits)
+ ?line send_term_as_binary(P,-16#80000000), % INTEGER_EXT new smallest
+ ?line send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*)
+ ?line send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*)
- ?line send_term_as_binary(P, 16#7fffffff), % SMALL_BIG_EXT largest i32
- ?line send_term_as_binary(P,-16#80000000), % SMALL_BIG_EXT smallest i32
- ?line send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32
?line send_term_as_binary(P, 16#ffffffff),% SMALL_BIG_EXT largest u32
?line send_term_as_binary(P, 16#7fffffffffff), % largest i48
diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
index 5447e2deb3..b349138ae9 100644
--- a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
+++ b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
@@ -246,13 +246,23 @@ TESTCASE(test_ei_decode_long)
EI_DECODE_2 (decode_long, 5, long, 256);
EI_DECODE_2 (decode_long, 5, long, -1);
+ /* Old 28 bit limits for INTEGER_EXT */
EI_DECODE_2 (decode_long, 5, long, 0x07ffffff);
EI_DECODE_2 (decode_long, 5, long, -0x08000000);
- EI_DECODE_2 (decode_long, 7, long, 0x08000000);
- EI_DECODE_2 (decode_long, 7, long, -0x08000001);
+ EI_DECODE_2 (decode_long, 5, long, 0x08000000);
+ EI_DECODE_2 (decode_long, 5, long, -0x08000001);
- EI_DECODE_2 (decode_long, 7, long, 0x7fffffff);
- EI_DECODE_2 (decode_long, 7, long, -ll(0x80000000)); /* Strange :-( */
+ /* New 32 bit limits for INTEGER_EXT */
+ EI_DECODE_2 (decode_long, 5, long, 0x7fffffff);
+ EI_DECODE_2 (decode_long, 5, long, -ll(0x80000000)); /* Strange :-( */
+ if (sizeof(long) > 4) {
+ EI_DECODE_2(decode_long, 7, long, 0x80000000);
+ EI_DECODE_2(decode_long, 7, long, -ll(0x80000001));
+ }
+ else {
+ EI_DECODE_2_FAIL(decode_long, 7, long, 0x80000000);
+ EI_DECODE_2_FAIL(decode_long, 7, long, -ll(0x80000001));
+ }
EI_DECODE_2_FAIL(decode_long, 7, long, 0x80000000);
EI_DECODE_2_FAIL(decode_long, 7, long, 0xffffffff);
@@ -280,11 +290,13 @@ TESTCASE(test_ei_decode_ulong)
EI_DECODE_2 (decode_ulong, 5, unsigned long, 0x07ffffff);
EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -0x08000000);
- EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x08000000);
- EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -0x08000001);
+ EI_DECODE_2 (decode_ulong, 5, unsigned long, 0x08000000);
+ EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -0x08000001);
- EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x7fffffff);
- EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -ll(0x80000000));
+ EI_DECODE_2 (decode_ulong, 5, unsigned long, 0x7fffffff);
+ EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -ll(0x80000000));
+ EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x80000000);
+ EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -ll(0x80000001));
if (sizeof(long) > 4) {
EI_DECODE_2 (decode_ulong, 11, unsigned long, ll(0x8000000000000000));
@@ -319,13 +331,14 @@ TESTCASE(test_ei_decode_longlong)
EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 0x07ffffff);
EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -0x08000000);
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x08000000);
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -0x08000001);
-
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x7fffffff);
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -ll(0x80000000));
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 0x08000000);
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -0x08000001);
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 0x7fffffff);
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -ll(0x80000000));
EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x80000000);
+ EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -ll(0x80000001));
+
EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0xffffffff);
EI_DECODE_2 (decode_longlong, 9, EI_LONGLONG, ll(0x7fffffffffff));
@@ -352,13 +365,14 @@ TESTCASE(test_ei_decode_ulonglong)
EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 0x07ffffff);
EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -0x08000000);
- EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x08000000);
- EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -0x08000001);
-
- EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x7fffffff);
- EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -ll(0x80000000));
+ EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 0x08000000);
+ EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -0x08000001);
+ EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 0x7fffffff);
+ EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -ll(0x80000000));
EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x80000000);
+ EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -0x80000001);
+
EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0xffffffff);
EI_DECODE_2 (decode_ulonglong, 9, EI_ULONGLONG, ll(0x7fffffffffff));
diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
index 6b2ec8f766..f273efd532 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
+++ b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
@@ -63,32 +63,108 @@ TESTCASE(build_terms)
report(1);
}
+static int abs_and_sign(ETERM* v, unsigned long long* av, int* sign)
+{
+ long long sv;
+ switch (ERL_TYPE(v)) {
+ case ERL_INTEGER: sv = ERL_INT_VALUE(v); break;
+ case ERL_U_INTEGER: *av = ERL_INT_UVALUE(v); *sign = 0; return 1;
+ case ERL_LONGLONG: sv = ERL_LL_VALUE(v); break;
+ case ERL_U_LONGLONG: *av = ERL_LL_UVALUE(v); *sign = 0; return 1;
+ default: return 0;
+ }
+ if (sv < 0) {
+ *av = -sv;
+ *sign = 1;
+ }
+ else {
+ *av = sv;
+ *sign = 0;
+ }
+ return 1;
+}
+
+/* Shouldn't erl_match() cope with this?
+*/
+static int eq_ints(ETERM* a, ETERM* b)
+{
+ unsigned long long a_abs, b_abs;
+ int a_sign, b_sign;
+ return abs_and_sign(a, &a_abs, &a_sign) && abs_and_sign(b, &b_abs, &b_sign)
+ && (a_abs == b_abs) && (a_sign == b_sign);
+}
+
+static void encode_decode(ETERM* original, const char* text)
+{
+ static unsigned char encoded[16*1024];
+ ETERM* new_terms;
+ int bytes = erl_encode(original, encoded);
+
+ if (bytes == 0) {
+ fail("failed to encode terms");
+ }
+ else if (bytes > sizeof(encoded)) {
+ fail("encoded terms buffer overflow");
+ }
+ else if ((new_terms = erl_decode(encoded)) == NULL) {
+ fail("failed to decode terms");
+ }
+ else if (!erl_match(original, new_terms) && !eq_ints(original, new_terms)) {
+ erl_print_term(stderr, original);
+ fprintf(stderr, "(%i) != (%i)", ERL_TYPE(original), ERL_TYPE(new_terms));
+ erl_print_term(stderr, new_terms);
+ fprintf(stderr, " [%s]\r\n", text);
+ fail("decoded terms didn't match original");
+ }
+ erl_free_term(original);
+ erl_free_term(new_terms);
+}
/*
* Converts an Erlang term to the external term format and back again.
*/
TESTCASE(round_trip_conversion)
{
- ETERM* original;
- ETERM* new_terms;
- char encoded[16*1024];
- int n;
+ int n, i;
erl_init(NULL, 0);
- original = all_types();
- if (erl_encode(original, encoded) == 0)
+ encode_decode(all_types(), "ALL");
+
{
- fail("failed to encode terms");
- } else if ((new_terms = erl_decode(encoded)) == NULL)
+ int v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_int(v+i), "INT");
+ encode_decode(erl_mk_int(-(v+i)), "NEG INT");
+ }
+ }
+ }
{
- fail("failed to decode terms");
- } else if (!erl_match(original, new_terms))
+ unsigned int v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_uint(v+i), "UINT");
+ }
+ }
+ }
{
- fail("decoded terms didn't match original");
+ long long v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_longlong(v+i), "LONGLONG");
+ encode_decode(erl_mk_longlong(-(v+i)), "NEG LONGLONG");
+ }
+ }
+ }
+ {
+ unsigned long long v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_ulonglong(v+i), "ULONGLONG");
+ }
+ }
}
- erl_free_term(original);
- erl_free_term(new_terms);
report(1);
}