From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= <egil@erlang.org>
Date: Fri, 10 Jun 2016 16:40:38 +0200
Subject: [PATCH] Fix decoding of LLONG_MIN in erl_decode
Reported-by: Peter Lemenkov
diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c
index a4216c9..6a1b573 100644
--- a/lib/erl_interface/src/legacy/erl_marshal.c
+++ b/lib/erl_interface/src/legacy/erl_marshal.c
@@ -727,6 +727,13 @@ static ETERM *erl_decode_it(unsigned char **ext)
((*ext)[2]) << 8 |((*ext)[3]);
*ext += 4;
big_cont:
+
+#ifdef _MSC_VER
+#define MAX_TO_NEGATE 0x8000000000000000Ui64
+#else
+#define MAX_TO_NEGATE 0x8000000000000000ULL
+#endif
+
sign = *(*ext)++;
if (arity > 8)
goto big_truncate;
@@ -763,23 +770,28 @@ static ETERM *erl_decode_it(unsigned char **ext)
*ext += arity;
return ep;
} else {
- /* Fits in a long long */
- int x;
- long long l = 0LL;
-
- for(x = 0 ; x < arity ; x++) {
- l |= ((long long)(*ext)[x]) << ((long long)(8*x));
- }
- if (sign) {
- l = -l;
- if (l > 0) goto big_truncate;
- }
-
- ERL_TYPE(ep) = ERL_LONGLONG;
- ep->uval.llval.i = l;
- *ext += arity;
- return ep;
+ /* Fits in a signed long long */
+ int x;
+ unsigned long long l = 0LL;
+ long long sl;
+
+ for(x = 0 ; x < arity ; x++) {
+ l |= ((unsigned long long)(*ext)[x]) << ((unsigned long long)(8*x));
+ }
+
+ sl = (long long)l;
+
+ if (sign && l != MAX_TO_NEGATE) {
+ sl = -sl;
+ if (sl > 0) goto big_truncate;
+ }
+
+ ERL_TYPE(ep) = ERL_LONGLONG;
+ ep->uval.llval.i = sl;
+ *ext += arity;
+ return ep;
}
+#undef MAX_TO_NEGATE
big_truncate:
/* truncate to: (+/-) 1 */
#ifdef DEBUG