Blob Blame History Raw
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