From e5d41874ec0d2aaf2037d10dd92091edd2405924 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 16 Jun 2010 17:58:35 +0200 Subject: 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) --- erts/emulator/beam/external.c | 53 +++++++---- erts/emulator/test/hash_SUITE.erl | 8 +- lib/erl_interface/src/legacy/erl_marshal.c | 93 ++++++++----------- lib/erl_interface/test/ei_decode_SUITE.erl | 34 ++++--- .../test/ei_decode_SUITE_data/ei_decode_test.c | 50 ++++++---- .../test/erl_eterm_SUITE_data/eterm_test.c | 102 ++++++++++++++++++--- 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 #include #include +#include #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); } -- cgit v1.2.3