~ chicken-core (chicken-5) 76a84c3c444631b62a875cfda682ea3ee322a447


commit 76a84c3c444631b62a875cfda682ea3ee322a447
Author:     Peter Bex <peter@more-magic.net>
AuthorDate: Thu Mar 31 21:40:29 2016 +0200
Commit:     Evan Hanson <evhan@foldling.org>
CommitDate: Sun Apr 3 17:18:40 2016 +1200

    Fix invalid base handling of string->number
    
    Before, we'd segfault when given absurd base arguments like 60,
    depending on how the libc implemented this undefined behaviour.  Now we
    detect it early and bail out.
    
    The handling of invalid values is slightly improved as well; we might
    get a return value of 0 from strtod and strtol(l) on error: HUGE_VAL /
    (LONG_)LONG_{MAX,MIN} are only returned on overflow/underflow, and the
    errno might have a different value from ERANGE as pointed out by the
    glibc manual page, even though the spec is silent about other errnos.
    At least if the string couldn't be converted eptr will be mutated to
    point to str.  But otherwise, all bets are off.
    
    The spec for strtod() even says:
    
     "If the result underflows (7.12.1), the functions return a value whose
     magnitude is no greater than the smallest normalized positive number in
     the return type; whether errno acquires the value ERANGE is
     implementation-defined"
    
    Attempting to write C code: not even once...
    
    Fixes #1272.
    
    Signed-off-by: Evan Hanson <evhan@foldling.org>

diff --git a/NEWS b/NEWS
index 39334649..78e41d1c 100644
--- a/NEWS
+++ b/NEWS
@@ -49,6 +49,8 @@
     with srfi-1 in the argument order of comparison procedures.
   - Unit "lolevel": locative-ref has been fixed for locatives of u32
     and s32vectors (thanks to Joerg Wittenberger for pointing this out).
+  - string->number now signals exceptions if passed a bad base instead
+    of segfaulting (#1272; reported by "Tilpner" on IRC).
 
 - Tools
   - A debugger is now available, known as "feathers", which allows
diff --git a/runtime.c b/runtime.c
index 8e89ea37..f11789ae 100644
--- a/runtime.c
+++ b/runtime.c
@@ -7695,6 +7695,9 @@ C_a_i_string_to_number(C_word **a, int c, C_word str, C_word radix0)
   if(radix0 & C_FIXNUM_BIT) radix = C_unfix(radix0);
   else barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "string->number", radix0);
 
+  if (radix < 2 || radix > 36) /* Makes no sense and isn't supported */
+    barf(C_BAD_ARGUMENT_TYPE_BAD_BASE_ERROR, "string->number", radix0);
+
   if(C_immediatep(str) || C_header_bits(str) != C_STRING_TYPE)
     barf(C_BAD_ARGUMENT_TYPE_ERROR, "string->number", str);
 
@@ -7883,14 +7886,14 @@ C_regparm C_word C_fcall convert_string_to_number(C_char *str, int radix, C_word
   errno = 0;
   n = C_strtow(str, &eptr, radix);
   
-  if(((n == C_LONG_MAX || n == C_LONG_MIN) && errno == ERANGE) || *eptr != '\0') {
+  if(((n == C_LONG_MAX || n == C_LONG_MIN) && errno != 0) || *eptr != '\0') {
     if(radix != 10)
       return from_n_nary(str, radix, flo) ? 2 : 0;
 
     errno = 0;
     fn = C_strtod(str, &eptr2);
 
-    if(fn == HUGE_VAL && errno == ERANGE) return 0;
+    if((fn == HUGE_VAL && errno != 0) || fn == -HUGE_VAL) return 0;
     else if(eptr2 == str) return 0;
     else if(*eptr2 == '\0' || (eptr != eptr2 && !C_strncmp(eptr2, ".0", C_strlen(eptr2)))) {
       *flo = fn;
Trap