guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] GNU Guile branch, stable-2.0, updated. v2.0.9-234-g3aecd


From: Mark H Weaver
Subject: [Guile-commits] GNU Guile branch, stable-2.0, updated. v2.0.9-234-g3aecd36
Date: Wed, 12 Mar 2014 02:34:20 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=3aecd36464b1d916991bcc57acd6ec42e1cabbdc

The branch, stable-2.0 has been updated
       via  3aecd36464b1d916991bcc57acd6ec42e1cabbdc (commit)
       via  e293c94c65d49171c54bb1893c355e36c66806b8 (commit)
       via  7f8ad91b994d4922efdd7f9f89400b1ebddeed8f (commit)
       via  9fcee9da3f28b4b190d6976aeea72ab3c9f62bb2 (commit)
       via  03cce0ce5fba210e4abd8fa5dfddb04022a27e75 (commit)
       via  5fbf0e0f99431f54da032bda47d8125f9d34b4b1 (commit)
       via  19c0bd22a8f5e7cd76cf1435504c8eca342285ff (commit)
      from  3b7601cb34b068a231f6992ad9bbd3c50659efd4 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 3aecd36464b1d916991bcc57acd6ec42e1cabbdc
Author: Mark H Weaver <address@hidden>
Date:   Tue Mar 11 21:33:48 2014 -0400

    SCM_I_INUM: Rewrite to avoid unspecified behavior when not using GNU C.
    
    * libguile/numbers.h (SCM_I_INUM): Unless using GNU C, use a portable
      implementation that avoids unspecified behavior.

commit e293c94c65d49171c54bb1893c355e36c66806b8
Author: Mark H Weaver <address@hidden>
Date:   Tue Mar 11 21:27:21 2014 -0400

    SCM_SRS: Improve fallback implemention to avoid unspecified behavior.
    
    * libguile/numbers.h (SCM_SRS): Rewrite preprocessor test to avoid
      left-shifting negative integers, and to test more comprehensively for
      the behavior we need.  Rewrite fallback implementation to avoid
      unspecified behavior.

commit 7f8ad91b994d4922efdd7f9f89400b1ebddeed8f
Author: Mark H Weaver <address@hidden>
Date:   Tue Mar 11 20:34:28 2014 -0400

    SRFI-60: Reimplement 'rotate-bit-field' on inums to be more portable.
    
    * libguile/srfi-60.c (scm_srfi60_rotate_bit_field): Avoid division by
      zero in the (start == end) case.  Rewrite inum case to work with
      unsigned integers in two's complement format.
    
    * test-suite/tests/srfi-60.test ("rotate-bit-field"): Add more tests.

commit 9fcee9da3f28b4b190d6976aeea72ab3c9f62bb2
Author: Mark H Weaver <address@hidden>
Date:   Tue Mar 11 20:31:38 2014 -0400

    Use 'offsetof' to avoid undefined behavior.
    
    * libguile/socket.c (SUN_LEN): Use 'offsetof'.

commit 03cce0ce5fba210e4abd8fa5dfddb04022a27e75
Author: Mark H Weaver <address@hidden>
Date:   Tue Mar 11 20:19:17 2014 -0400

    Avoid undefined behavior regarding signed integers and left shifts.
    
    * libguile/numbers.c (scm_logbit_p): If the requested bit is the sign
      bit (or above), check the sign portably.  Otherwise, ensure that we're
      testing the bit in a two's complement representation.
      (left_shift_exact_integer): Avoid left-shifting negative integers.
    
    * libguile/vm-i-scheme.c (ash): Avoid left-shifting negative integers.

commit 5fbf0e0f99431f54da032bda47d8125f9d34b4b1
Author: Mark H Weaver <address@hidden>
Date:   Tue Mar 11 20:15:27 2014 -0400

    Avoid signed overflow in random.c.
    
    * libguile/random.c (scm_i_mask32): Avoid signed overflow from shifting
      an unsigned char (promoted to signed int) 24 bits to the left.

commit 19c0bd22a8f5e7cd76cf1435504c8eca342285ff
Author: Mark H Weaver <address@hidden>
Date:   Tue Mar 11 20:12:32 2014 -0400

    Avoid side effects in argument to SCM_I_INUM.
    
    * libguile/vm-i-system.c (halt): Avoid side effects in argument to
      SCM_I_INUM.

-----------------------------------------------------------------------

Summary of changes:
 libguile/numbers.c            |   18 ++++++---
 libguile/numbers.h            |   38 ++++++++++++++---
 libguile/random.c             |    2 +-
 libguile/socket.c             |    2 +-
 libguile/srfi-60.c            |   60 +++++++++++++++++++---------
 libguile/vm-i-scheme.c        |    7 ++-
 libguile/vm-i-system.c        |    5 ++-
 test-suite/tests/srfi-60.test |   89 +++++++++++++++++++++++++++++++----------
 8 files changed, 163 insertions(+), 58 deletions(-)

diff --git a/libguile/numbers.c b/libguile/numbers.c
index 51e813a..c197eee 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -1,6 +1,6 @@
 /* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- *   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
- *   2013 Free Software Foundation, Inc.
+ *   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
+ *   2014 Free Software Foundation, Inc.
  *
  * Portions Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories
  * and Bellcore.  See scm_divide.
@@ -4680,9 +4680,15 @@ SCM_DEFINE (scm_logbit_p, "logbit?", 2, 0, 0,
 
   if (SCM_I_INUMP (j))
     {
-      /* bits above what's in an inum follow the sign bit */
-      iindex = min (iindex, SCM_LONG_BIT - 1);
-      return scm_from_bool ((1L << iindex) & SCM_I_INUM (j));
+      if (iindex < SCM_LONG_BIT - 1)
+        /* Arrange for the number to be converted to unsigned before
+           checking the bit, to ensure that we're testing the bit in a
+           two's complement representation (regardless of the native
+           representation.  */
+        return scm_from_bool ((1UL << iindex) & SCM_I_INUM (j));
+      else
+        /* Portably check the sign.  */
+        return scm_from_bool (SCM_I_INUM (j) < 0);
     }
   else if (SCM_BIGP (j))
     {
@@ -4992,7 +4998,7 @@ left_shift_exact_integer (SCM n, long count)
       else if (count < SCM_I_FIXNUM_BIT-1 &&
                ((scm_t_bits) (SCM_SRS (nn, (SCM_I_FIXNUM_BIT-1 - count)) + 1)
                 <= 1))
-        return SCM_I_MAKINUM (nn << count);
+        return SCM_I_MAKINUM (nn < 0 ? -(-nn << count) : (nn << count));
       else
         {
           SCM result = scm_i_inum2big (nn);
diff --git a/libguile/numbers.h b/libguile/numbers.h
index b4202f2..b929b7a 100644
--- a/libguile/numbers.h
+++ b/libguile/numbers.h
@@ -49,19 +49,43 @@ typedef scm_t_int32 scm_t_wchar;
 #define SCM_MOST_POSITIVE_FIXNUM ((SCM_T_SIGNED_BITS_MAX-3)/4)
 #define SCM_MOST_NEGATIVE_FIXNUM (-SCM_MOST_POSITIVE_FIXNUM-1)
 
-/* SCM_SRS is signed right shift */
-#if (-1 == (((-1) << 2) + 2) >> 2)
-# define SCM_SRS(x, y) ((x) >> (y))
+/* SCM_SRS (X, Y) is signed right shift, defined as floor (X / 2^Y),
+   where Y must be non-negative and less than the width in bits of X.
+   It's common for >> to do this, but the C standards do not specify
+   what happens when X is negative.
+
+   NOTE: X must not perform side effects.  */
+#if (-1 >> 2 == -1) && (-4 >> 2 == -1) && (-5 >> 2 == -2) && (-8 >> 2 == -2)
+# define SCM_SRS(x, y)  ((x) >> (y))
 #else
-# define SCM_SRS(x, y) ((x) < 0 ? ~((~(x)) >> (y)) : ((x) >> (y)))
-#endif /* (-1 == (((-1) << 2) + 2) >> 2) */
+# define SCM_SRS(x, y)                                   \
+  ((x) < 0                                               \
+   ? -1 - (scm_t_signed_bits) (~(scm_t_bits)(x) >> (y))  \
+   : ((x) >> (y)))
+#endif
+
+
+/* The first implementation of SCM_I_INUM below depends on behavior that
+   is specified by GNU C but not by C standards, namely that when
+   casting to a signed integer of width N, the value is reduced modulo
+   2^N to be within range of the type.  The second implementation below
+   should be portable to all conforming C implementations, but may be
+   less efficient if the compiler is not sufficiently clever.
 
+   NOTE: X must not perform side effects.  */
+#ifdef __GNUC__
+# define SCM_I_INUM(x)  (SCM_SRS ((scm_t_signed_bits) SCM_UNPACK (x), 2))
+#else
+# define SCM_I_INUM(x)                                \
+  (SCM_UNPACK (x) > LONG_MAX                          \
+   ? -1 - (scm_t_signed_bits) (~SCM_UNPACK (x) >> 2)  \
+   : (scm_t_signed_bits) (SCM_UNPACK (x) >> 2))
+#endif
 
 #define SCM_I_INUMP(x) (2 & SCM_UNPACK (x))
 #define SCM_I_NINUMP(x) (!SCM_I_INUMP (x))
 #define SCM_I_MAKINUM(x) \
   (SCM_PACK ((((scm_t_bits) (x)) << 2) + scm_tc2_int))
-#define SCM_I_INUM(x)   (SCM_SRS ((scm_t_signed_bits) SCM_UNPACK (x), 2))
 
 /* SCM_FIXABLE is true if its long argument can be encoded in an SCM_INUM. */
 #define SCM_POSFIXABLE(n) ((n) <= SCM_MOST_POSITIVE_FIXNUM)
diff --git a/libguile/random.c b/libguile/random.c
index 18737aa..4051d1f 100644
--- a/libguile/random.c
+++ b/libguile/random.c
@@ -255,7 +255,7 @@ scm_i_mask32 (scm_t_uint32 m)
             ? scm_masktab[m >> 8] << 8 | 0xff
             : (m < 0x1000000
                ? scm_masktab[m >> 16] << 16 | 0xffff
-               : scm_masktab[m >> 24] << 24 | 0xffffff)));
+               : ((scm_t_uint32) scm_masktab[m >> 24]) << 24 | 0xffffff)));
 }
 
 scm_t_uint32
diff --git a/libguile/socket.c b/libguile/socket.c
index c0faae1..5b17a74 100644
--- a/libguile/socket.c
+++ b/libguile/socket.c
@@ -64,7 +64,7 @@
 
 
 #if defined (HAVE_UNIX_DOMAIN_SOCKETS) && !defined (SUN_LEN)
-#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+#define SUN_LEN(ptr) (offsetof (struct sockaddr_un, sun_path) \
                      + strlen ((ptr)->sun_path))
 #endif
 
diff --git a/libguile/srfi-60.c b/libguile/srfi-60.c
index 1ed3c9e..de97cbc 100644
--- a/libguile/srfi-60.c
+++ b/libguile/srfi-60.c
@@ -1,6 +1,6 @@
 /* srfi-60.c --- Integers as Bits
  *
- * Copyright (C) 2005, 2006, 2008, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2005, 2006, 2008, 2010, 2014 Free Software Foundation, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -155,7 +155,12 @@ SCM_DEFINE (scm_srfi60_rotate_bit_field, 
"rotate-bit-field", 4, 0, 0,
   SCM_ASSERT_RANGE (3, end, (ee >= ss));
   ww = ee - ss;
 
-  cc = scm_to_ulong (scm_modulo (count, scm_difference (end, start)));
+  /* we must avoid division by zero, and a field whose width is 0 or 1
+     will be left unchanged anyway, so in that case we set cc to 0. */
+  if (ww <= 1)
+    cc = 0;
+  else
+    cc = scm_to_ulong (scm_modulo (count, scm_difference (end, start)));
 
   if (SCM_I_INUMP (n))
     {
@@ -163,22 +168,40 @@ SCM_DEFINE (scm_srfi60_rotate_bit_field, 
"rotate-bit-field", 4, 0, 0,
 
       if (ee <= SCM_LONG_BIT-1)
         {
-          /* all within a long */
-          long below = nn & ((1L << ss) - 1);  /* before start */
-          long above = nn & (-1L << ee);       /* above end */
-          long fmask = (-1L << ss) & ((1L << ee) - 1);  /* field mask */
-          long ff = nn & fmask;                /* field */
-
-          return scm_from_long (above
-                                | ((ff << cc) & fmask)
-                                | ((ff >> (ww-cc)) & fmask)
-                                | below);
+          /* Everything fits within a long.  To avoid undefined behavior
+             when shifting negative numbers, we do all operations using
+             unsigned values, and then convert to signed at the end. */
+          unsigned long unn = nn;
+          unsigned long below = unn &  ((1UL << ss) - 1);  /* below start */
+          unsigned long above = unn & ~((1UL << ee) - 1);  /* above end */
+          unsigned long fmask = ((1UL << ww) - 1) << ss;   /* field mask */
+          unsigned long ff = unn & fmask;                  /* field */
+          unsigned long uresult = (above
+                                   | ((ff << cc) & fmask)
+                                   | ((ff >> (ww-cc)) & fmask)
+                                   | below);
+          long result;
+
+          if (uresult > LONG_MAX)
+            /* The high bit is set in uresult, so the result is
+               negative.  We have to handle the conversion to signed
+               integer carefully, to avoid undefined behavior.  First we
+               compute ~uresult, equivalent to (ULONG_MAX - uresult),
+               which will be between 0 and LONG_MAX (inclusive): exactly
+               the set of numbers that can be represented as both signed
+               and unsigned longs and thus convertible between them.  We
+               cast that difference to a signed long and then substract
+               it from -1. */
+            result = -1 - (long) ~uresult;
+          else
+            result = (long) uresult;
+
+          return scm_from_long (result);
         }
       else
         {
-          /* either no movement, or a field of only 0 or 1 bits, result
-             unchanged, avoid creating a bignum */
-          if (cc == 0 || ww <= 1)
+          /* if there's no movement, avoid creating a bignum. */
+          if (cc == 0)
             return n;
 
           n = scm_i_long2big (nn);
@@ -190,9 +213,8 @@ SCM_DEFINE (scm_srfi60_rotate_bit_field, 
"rotate-bit-field", 4, 0, 0,
       mpz_t tmp;
       SCM r;
 
-      /* either no movement, or in a field of only 0 or 1 bits, result
-         unchanged, avoid creating a new bignum */
-      if (cc == 0 || ww <= 1)
+      /* if there's no movement, avoid creating a new bignum. */
+      if (cc == 0)
         return n;
 
     big:
@@ -209,7 +231,7 @@ SCM_DEFINE (scm_srfi60_rotate_bit_field, 
"rotate-bit-field", 4, 0, 0,
       mpz_mul_2exp (tmp, tmp, ss + cc);
       mpz_ior (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), tmp);
 
-      /* field high part, count bits from end-count go to start */
+      /* field low part, count bits from end-count go to start */
       mpz_fdiv_q_2exp (tmp, SCM_I_BIG_MPZ (n), ee - cc);
       mpz_fdiv_r_2exp (tmp, tmp, cc);
       mpz_mul_2exp (tmp, tmp, ss);
diff --git a/libguile/vm-i-scheme.c b/libguile/vm-i-scheme.c
index dd2150d..587aa95 100644
--- a/libguile/vm-i-scheme.c
+++ b/libguile/vm-i-scheme.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, 
Inc.
+/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013,
+ *   2014 Free Software Foundation, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -505,7 +506,9 @@ VM_DEFINE_FUNCTION (159, ash, "ash", 2)
               && ((scm_t_bits)
                   (SCM_SRS (nn, (SCM_I_FIXNUM_BIT-1 - bits_to_shift)) + 1)
                   <= 1))
-            RETURN (SCM_I_MAKINUM (nn << bits_to_shift));
+            RETURN (SCM_I_MAKINUM (nn < 0
+                                   ? -(-nn << bits_to_shift)
+                                   : (nn << bits_to_shift)));
           /* fall through */
         }
       /* fall through */
diff --git a/libguile/vm-i-system.c b/libguile/vm-i-system.c
index e54a99b..5057fb0 100644
--- a/libguile/vm-i-system.c
+++ b/libguile/vm-i-system.c
@@ -32,8 +32,11 @@ VM_DEFINE_INSTRUCTION (0, nop, "nop", 0, 0, 0)
 VM_DEFINE_INSTRUCTION (1, halt, "halt", 0, 0, 0)
 {
   SCM ret;
+  SCM nvalues_scm;
 
-  nvalues = SCM_I_INUM (*sp--);
+  nvalues_scm = *sp--;  /* SCM_I_INUM may evaluate its argument
+                           more than once. */
+  nvalues = SCM_I_INUM (nvalues_scm);
   NULLSTACK (1);
 
   if (nvalues == 1)
diff --git a/test-suite/tests/srfi-60.test b/test-suite/tests/srfi-60.test
index 940934f..1c91943 100644
--- a/test-suite/tests/srfi-60.test
+++ b/test-suite/tests/srfi-60.test
@@ -268,27 +268,74 @@
 ;;
 
 (with-test-prefix "rotate-bit-field"
-  (pass-if (eqv? #b110  (rotate-bit-field #b110 1 1 2)))
-  (pass-if (eqv? #b1010 (rotate-bit-field #b110 1 2 4)))
-  (pass-if (eqv? #b1011 (rotate-bit-field #b0111 -1 1 4)))
-
-  (pass-if (eqv? #b0  (rotate-bit-field #b0 128 0 256)))
-  (pass-if (eqv? #b1  (rotate-bit-field #b1 128 1 256)))
-  (pass-if
-      (eqv? #x100000000000000000000000000000000
-           (rotate-bit-field #x100000000000000000000000000000000 128 0 64)))
-  (pass-if
-      (eqv? #x100000000000000000000000000000008
-           (rotate-bit-field #x100000000000000000000000000000001 3 0 64)))
-  (pass-if
-      (eqv? #x100000000000000002000000000000000
-           (rotate-bit-field #x100000000000000000000000000000001 -3 0 64)))
-
-  (pass-if (eqv? #b110 (rotate-bit-field #b110 0 0 10)))
-  (pass-if (eqv? #b110 (rotate-bit-field #b110 0 0 256)))
-
-  (pass-if "bignum becomes inum"
-    (eqv? 1 (rotate-bit-field #x100000000000000000000000000000000 1 0 129))))
+  (define-syntax-rule (check expected x count start end)
+    (begin
+      (pass-if-equal expected (rotate-bit-field x count start end))
+      (pass-if-equal (lognot expected)
+          (rotate-bit-field (lognot x) count start end))))
+
+  (check #b110  #b110 1 1 2)
+  (check #b1010 #b110 1 2 4)
+  (check #b1011 #b0111 -1 1 4)
+
+  (check #b0 #b0 128 0 256)
+  (check #b1 #b1 128 1 256)
+  (check #x100000000000000000000000000000000
+         #x100000000000000000000000000000000 128 0 64)
+  (check #x100000000000000000000000000000008
+         #x100000000000000000000000000000001 3 0 64)
+  (check #x100000000000000002000000000000000
+         #x100000000000000000000000000000001 -3 0 64)
+
+  (check #b110 #b110 0 0 10)
+  (check #b110 #b110 0 0 256)
+
+  (check #b110  #b110 1 1 1)
+
+  (check #b10111010001100111101110010101
+         #b11010001100111101110001110101 -26 5 28)
+  (check #b11000110011110111000111011001
+         #b11010001100111101110001110101 28 2 28)
+
+  (check #b01111010001100111101110010101
+         #b11010001100111101110001110101 -3 5 29)
+  (check #b10100011001111011100011101101
+         #b11010001100111101110001110101 28 2 29)
+
+  (check #b110110100011001111011100010101
+         #b011010001100111101110001110101 48 5 30)
+  (check #b110100011001111011100011101001
+         #b011010001100111101110001110101 85 2 30)
+  (check #b011010001100111101110001110101
+         #b110100011001111011100011101001 83 2 30)
+
+  (check
+   #b1101100110101001110000111110011010000111011101011101110111011
+   #b1100110101001110000111110011010000111011101011101110110111011 -3 5 60)
+  (check
+   #b1011010100111000011111001101000011101110101110111011011101110
+   #b1100110101001110000111110011010000111011101011101110110111011 62 0 60)
+
+  (check
+   #b1011100110101001110000111110011010000111011101011101110111011
+   #b1100110101001110000111110011010000111011101011101110110111011 53 5 61)
+  (check
+   #b1001101010011100001111100110100001110111010111011101101110111
+   #b1100110101001110000111110011010000111011101011101110110111011 62 0 61)
+
+  (check
+   #b11011001101010011100001111100110100001110111010111011100111011
+   #b01100110101001110000111110011010000111011101011101110110111011 53 7 62)
+  (check
+   #b11011001101010011100001111100110100001110111010111011100111011
+   #b01100110101001110000111110011010000111011101011101110110111011 -2 7 62)
+  (check
+   #b01100110101001110000111110011010000111011101011101110110111011
+   #b11011001101010011100001111100110100001110111010111011100111011 2 7 62)
+
+  (pass-if-equal "bignum becomes inum"
+      1
+    (rotate-bit-field #x100000000000000000000000000000000 1 0 129)))
 
 ;;
 ;; reverse-bit-field


hooks/post-receive
-- 
GNU Guile



reply via email to

[Prev in Thread] Current Thread [Next in Thread]