File 1212-lists_to_integer-friends-Don-t-crash-for-overlong-li.patch of Package erlang

From 47ef6142984c312ee6b39257dc40f5dab00534eb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Sun, 29 May 2022 10:34:39 +0200
Subject: [PATCH] lists_to_integer() & friends: Don't crash for overlong lists

Let `list_to_integer/1` and `list_to_integer/2` raise a `system_limit`
exception when the result doesn't fit in a bignum. Let
`string:to_integer/1` return `{error,system_limit}` when the result
doesn't fit.
---
 erts/emulator/beam/bif.c              | 38 ++++++++++++++++-----------
 erts/emulator/beam/big.c              |  5 ++++
 erts/emulator/beam/big.h              |  3 ++-
 erts/emulator/test/list_bif_SUITE.erl | 11 ++++++--
 erts/emulator/test/num_bif_SUITE.erl  |  8 +++---
 5 files changed, 44 insertions(+), 21 deletions(-)

diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index fa359c5e28..c4687f04b8 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -3357,6 +3357,9 @@ BIF_RETTYPE string_list_to_integer_1(BIF_ALIST_1)
      case LTI_NO_INTEGER:
 	 hp = HAlloc(BIF_P,3);
 	 BIF_RET(TUPLE2(hp, am_error, am_no_integer));
+     case LTI_SYSTEM_LIMIT:
+	 hp = HAlloc(BIF_P,3);
+	 BIF_RET(TUPLE2(hp, am_error, am_system_limit));
      default:
 	 hp = HAlloc(BIF_P,3);
 	 BIF_RET(TUPLE2(hp, res, tail));
@@ -3365,25 +3368,27 @@ BIF_RETTYPE string_list_to_integer_1(BIF_ALIST_1)
 
 BIF_RETTYPE list_to_integer_1(BIF_ALIST_1)
  {
-   /* Using erts_list_to_integer is about twice as fast as using
-      erts_chars_to_integer because we do not have to copy the 
-      entire list */
+     /* Using erts_list_to_integer() is about twice as fast as using
+      * erts_chars_to_integer() because we do not have to copy the
+      * entire list. */
      Eterm res;
      Eterm dummy;
      /* must be a list */
-     if (erts_list_to_integer(BIF_P, BIF_ARG_1, 10,
-                              &res, &dummy) != LTI_ALL_INTEGER) {
-	 BIF_ERROR(BIF_P,BADARG);
+     switch (erts_list_to_integer(BIF_P, BIF_ARG_1, 10, &res, &dummy)) {
+     case LTI_ALL_INTEGER:
+         BIF_RET(res);
+     case LTI_SYSTEM_LIMIT:
+	 BIF_ERROR(BIF_P, SYSTEM_LIMIT);
+     default:
+	 BIF_ERROR(BIF_P, BADARG);
      }
-     BIF_RET(res);
  }
 
 BIF_RETTYPE list_to_integer_2(BIF_ALIST_2)
 {
-  /* Bif implementation is about 50% faster than pure erlang,
-     and since we have erts_chars_to_integer now it is simpler
-     as well. This could be optimized further if we did not have to
-     copy the list to buf. */
+    /* The BIF implementation is about 50% faster than pure Erlang,
+     * and since we now have erts_list_to_integer() it is simpler as
+     * well. */
     Sint i;
     Eterm res, dummy;
     int base;
@@ -3399,11 +3404,14 @@ BIF_RETTYPE list_to_integer_2(BIF_ALIST_2)
         BIF_ERROR(BIF_P, BADARG);
     }
 
-    if (erts_list_to_integer(BIF_P, BIF_ARG_1, base,
-                             &res, &dummy) != LTI_ALL_INTEGER) {
-        BIF_ERROR(BIF_P,BADARG);
+    switch (erts_list_to_integer(BIF_P, BIF_ARG_1, base, &res, &dummy)) {
+    case LTI_ALL_INTEGER:
+        BIF_RET(res);
+    case LTI_SYSTEM_LIMIT:
+        BIF_ERROR(BIF_P, SYSTEM_LIMIT);
+    default:
+        BIF_ERROR(BIF_P, BADARG);
     }
-    BIF_RET(res);
 }
 
 /**********************************************************************/
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index 5a8f6216c7..8439a8c08f 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -3008,6 +3008,11 @@ LTI_result_t erts_list_to_integer(Process *BIF_P, Eterm orig_list,
          m  = (lg2+D_EXP-1)/D_EXP; /* number of digits */
          m  = BIG_NEED_SIZE(m);    /* number of words + thing */
 
+         if (m > BIG_ARITY_MAX) {
+             error_res = LTI_SYSTEM_LIMIT;
+             goto error;
+         }
+
          hp = HAlloc(BIF_P, m);
          hp_end = hp + m;
 
diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h
index 8fe9fb1cc4..73505569b3 100644
--- a/erts/emulator/beam/big.h
+++ b/erts/emulator/beam/big.h
@@ -188,7 +188,8 @@ typedef enum {
     LTI_BAD_STRUCTURE = 0,
     LTI_NO_INTEGER    = 1,
     LTI_SOME_INTEGER  = 2,
-    LTI_ALL_INTEGER   = 3
+    LTI_ALL_INTEGER   = 3,
+    LTI_SYSTEM_LIMIT  = 4,
 } LTI_result_t;
 
 LTI_result_t erts_list_to_integer(Process *BIF_P, Eterm orig_list,
diff --git a/erts/emulator/test/list_bif_SUITE.erl b/erts/emulator/test/list_bif_SUITE.erl
index b6941bfa43..2e43e9ad5a 100644
--- a/erts/emulator/test/list_bif_SUITE.erl
+++ b/erts/emulator/test/list_bif_SUITE.erl
@@ -50,14 +50,21 @@ t_list_to_integer(Config) when is_list(Config) ->
     12373 = (catch list_to_integer("12373")),
     -12373 =  (catch list_to_integer("-12373")),
     12373 = (catch list_to_integer("+12373")),
-    {'EXIT',{badarg,_}} = ( catch list_to_integer(abc)),
+    {'EXIT',{badarg,_}} = (catch list_to_integer(abc)),
     {'EXIT',{badarg,_}} = (catch list_to_integer("")),
     {12373281903728109372810937209817320981321,"ABC"} = string:to_integer("12373281903728109372810937209817320981321ABC"),
     {-12373281903728109372810937209817320981321,"ABC"} = string:to_integer("-12373281903728109372810937209817320981321ABC"),
     {12,[345]} = string:to_integer([$1,$2,345]),
-    {error, badarg} = string:to_integer([$1,$2,a]),
+    {error,badarg} = string:to_integer([$1,$2,a]),
     {error,no_integer} = string:to_integer([$A]),
     {error,badarg} = string:to_integer($A),
+
+    %% System limit.
+    Digits = lists:duplicate(11_000_000, $9),
+    {'EXIT',{system_limit,_}} = catch list_to_integer(Digits),
+    {'EXIT',{system_limit,_}} = catch list_to_integer(Digits, 16),
+    {error,system_limit} = string:to_integer(Digits),
+
     ok.
 
 %% Test hd/1 with correct and incorrect arguments.
diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl
index 78a232de8a..3b9aa4df30 100644
--- a/erts/emulator/test/num_bif_SUITE.erl
+++ b/erts/emulator/test/num_bif_SUITE.erl
@@ -670,9 +670,11 @@ t_string_to_integer(Config) when is_list(Config) ->
                    {"10",''}                    %Base 20
                   ]),
 
-    %% log2 calculation overflow bug in do_integer_to_list (OTP-12624).
-    %% Would crash with segmentation fault.
-    0 = list_to_integer(lists:duplicate(10000000,$0)),
+    %% System limit
+    Digits = lists:duplicate(11_000_000, $9),
+    {'EXIT',{system_limit,_}} = catch list_to_integer(Digits),
+    {'EXIT',{system_limit,_}} = catch list_to_integer(Digits, 16),
+    {error,system_limit} = string:to_integer(Digits),
 
     ok.
 
-- 
2.35.3

openSUSE Build Service is sponsored by