poke-devel
[Top][All Lists]
Advanced

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

Re: GNU poke 2.90.0 on Linux/x86_64 with UBsan


From: Jose E. Marchesi
Subject: Re: GNU poke 2.90.0 on Linux/x86_64 with UBsan
Date: Mon, 23 Jan 2023 15:57:38 +0100
User-agent: Gnus/5.13 (Gnus v5.13)

Hi Bruno.
Thanks for the testing and reporting.

> "gcc -ftrapv" checks only for one single case of undefined behaviour,
> namely specific cases of integer overflow.
>
> More generically, one can use clang's UB sanitizer. I installed clang 14.0.0
> then set
>
> CC="clang 
> -fsanitize=undefined,signed-integer-overflow,shift,integer-divide-by-zero 
> -fno-sanitize=pointer-overflow"
> CFLAGS="-O1 -fno-omit-frame-pointer -ggdb"
> (per recommendations from
> https://blogs.oracle.com/linux/post/improving-application-security-with-undefinedbehaviorsanitizer-ubsan-and-gcc)
>
> then built poke and did "make check". Find attached the poke.log. It has
> several occurrences of
>
>   runtime error: left shift of negative value
>
> but also several occurrences of
>
>   runtime error: left shift of <X> by <Y> places cannot be represented in 
> type 'int32_t'
>   runtime error: left shift of <X> by <Y> places cannot be represented in 
> type 'int64_t'
> where <X> and <Y> are positive integers.

I installed the two patches below and that made all the UBsan runtime
errors to go away.

There were no regressions, but still I would appreciate if somebody
would take a look at the changes.  These are easy to get wrong.

>From f18d5418e89defdb6666bd0ea0f8bdc180ce1ff4 Mon Sep 17 00:00:00 2001
From: "Jose E. Marchesi" <jose.marchesi@oracle.com>
Date: Mon, 23 Jan 2023 15:37:06 +0100
Subject: [PATCH 1/3] ios,pvm: remove UB related to left-shifting

2023-01-23  Jose E. Marchesi  <jemarch@gnu.org>

        * libpoke/ios.c (ios_read_int): Avoid UB in signed left shifts,
        and overflows in unsigned left shifts.
        * libpoke/pvm-val.h (PVM_VAL_INT): Likewise.
        (PVM_MAKE_INT): Likewise.
        (PVM_MAKE_UINT): Likewise.
        (PVM_VAL_LONG): Likewise.
        * libpoke/pvm.jitter (PVM_ADD_SIGNED): Likewise.
        (PVM_SUB_SIGNED): Likewise.
        (PVM_MUL_SIGNED): Likewise.
---
 ChangeLog          | 12 ++++++++++++
 libpoke/ios.c      | 27 +++++++++++++++------------
 libpoke/pvm-val.h  | 12 ++++++------
 libpoke/pvm.jitter | 10 +++++-----
 4 files changed, 38 insertions(+), 23 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 51739797..49270e37 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2023-01-23  Jose E. Marchesi  <jemarch@gnu.org>
+
+       * libpoke/ios.c (ios_read_int): Avoid UB in signed left shifts,
+       and overflows in unsigned left shifts.
+       * libpoke/pvm-val.h (PVM_VAL_INT): Likewise.
+       (PVM_MAKE_INT): Likewise.
+       (PVM_MAKE_UINT): Likewise.
+       (PVM_VAL_LONG): Likewise.
+       * libpoke/pvm.jitter (PVM_ADD_SIGNED): Likewise.
+       (PVM_SUB_SIGNED): Likewise.
+       (PVM_MUL_SIGNED): Likewise.
+
 2023-01-23  Arsen Arsenović  <arsen@aarsen.me>
 
        * doc/poke.texi (Exceptions): Fix typo in the E_no_return
diff --git a/libpoke/ios.c b/libpoke/ios.c
index 8e10d3f8..151096d4 100644
--- a/libpoke/ios.c
+++ b/libpoke/ios.c
@@ -760,19 +760,21 @@ ios_read_int (ios io, ios_off offset, int flags,
       case 16:
         {
           if (endian == IOS_ENDIAN_LSB)
-            *value = (int16_t) (c[1] << 8) | c[0];
+            *value = ((uint64_t) c[1] << 8) | c[0];
           else
-            *value = (int16_t) (c[0] << 8) | c[1];
+            *value = ((uint64_t) c[0] << 8) | c[1];
+          *value = (uint64_t) *value << 48;
+          *value >>= 48;
           return IOS_OK;
         }
 
       case 24:
         {
           if (endian == IOS_ENDIAN_LSB)
-            *value = (c[2] << 16) | (c[1] << 8) | c[0];
+            *value = ((uint64_t) c[2] << 16) | ((uint64_t) c[1] << 8) | c[0];
           else
-            *value = (c[0] << 16) | (c[1] << 8) | c[2];
-          *value <<= 40;
+            *value = ((uint64_t) c[0] << 16) | ((uint64_t) c[1] << 8) | c[2];
+          *value = (uint64_t) *value << 40;
           *value >>= 40;
           return IOS_OK;
         }
@@ -780,9 +782,11 @@ ios_read_int (ios io, ios_off offset, int flags,
       case 32:
         {
           if (endian == IOS_ENDIAN_LSB)
-            *value = (int32_t) (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | 
c[0];
+            *value = ((uint64_t) c[3] << 24) | ((uint64_t) c[2] << 16) | 
((uint64_t) c[1] << 8) | c[0];
           else
-            *value = (int32_t) (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | 
c[3];
+            *value = ((uint64_t) c[0] << 24) | ((uint64_t) c[1] << 16) | 
((uint64_t) c[2] << 8) | c[3];
+          *value = (uint64_t) *value << 32;
+          *value >>= 32;
           return IOS_OK;
         }
 
@@ -794,7 +798,7 @@ ios_read_int (ios io, ios_off offset, int flags,
           else
             *value = ((uint64_t) c[0] << 32) | ((uint64_t) c[1] << 24)
                      | (c[2] << 16) | (c[3] << 8) | c[4];
-          *value <<= 24;
+          *value = (uint64_t) *value << 24;
           *value >>= 24;
           return IOS_OK;
         }
@@ -809,7 +813,7 @@ ios_read_int (ios io, ios_off offset, int flags,
             *value = ((uint64_t) c[0] << 40) | ((uint64_t) c[1] << 32)
                      | ((uint64_t) c[2] << 24) | (c[3] << 16)
                      | (c[4] << 8) | c[5];
-          *value <<= 16;
+          *value = (uint64_t) *value << 16;
           *value >>= 16;
           return IOS_OK;
         }
@@ -824,7 +828,7 @@ ios_read_int (ios io, ios_off offset, int flags,
             *value = ((uint64_t) c[0] << 48) | ((uint64_t) c[1] << 40)
                      | ((uint64_t) c[2] << 32) | ((uint64_t) c[3] << 24)
                      | (c[4] << 16) | (c[5] << 8) | c[6];
-          *value <<= 8;
+          *value = (uint64_t) *value << 8;
           *value >>= 8;
           return IOS_OK;
         }
@@ -851,8 +855,7 @@ ios_read_int (ios io, ios_off offset, int flags,
                                      (uint64_t *) value);
   if (ret_val == IOS_OK)
     {
-      *value <<= 64 - bits;
-      *value >>= 64 - bits;
+      *value = ((int64_t) (((uint64_t) *value) << (64 - bits))) >> (64 - bits);
       return IOS_OK;
     }
   return ret_val;
diff --git a/libpoke/pvm-val.h b/libpoke/pvm-val.h
index 4be0213f..a98bc5d3 100644
--- a/libpoke/pvm-val.h
+++ b/libpoke/pvm-val.h
@@ -60,12 +60,12 @@
    Bits marked with `x' are unused and should be always 0.  */
 
 #define PVM_VAL_INT_SIZE(V) (((int) (((V) >> 3) & 0x1f)) + 1)
-#define PVM_VAL_INT(V) (((int32_t) ((V) >> 32))                \
-                        << (32 - PVM_VAL_INT_SIZE ((V)))       \
+#define PVM_VAL_INT(V) (((int32_t) (((uint32_t) ((V) >> 32))            \
+                                    << (32 - PVM_VAL_INT_SIZE ((V)))))  \
                         >> (32 - PVM_VAL_INT_SIZE ((V))))
 #define PVM_MAKE_INT(V,S)                            \
   (((((uint64_t) (int64_t) (V)) & 0xffffffff) << 32) \
-   | ((((S) - 1) & 0x1f) << 3)                       \
+   | ((uint32_t)(((S) - 1) & 0x1f) << 3)             \
    | PVM_VAL_TAG_INT)
 
 #define PVM_VAL_UINT_SIZE(V) (((int) (((V) >> 3) & 0x1f)) + 1)
@@ -73,7 +73,7 @@
                          & ((uint32_t) (~( ((~0ul) << ((PVM_VAL_UINT_SIZE 
((V)))-1)) << 1 ))))
 #define PVM_MAKE_UINT(V,S)                      \
   (((((uint64_t) (V)) & 0xffffffff) << 32)      \
-   | ((((S) - 1) & 0x1f) << 3)                  \
+   | ((uint32_t) (((S) - 1) & 0x1f) << 3)       \
    | PVM_VAL_TAG_UINT)
 
 #define PVM_MAX_UINT(size) ((1U << (size)) - 1)
@@ -108,8 +108,8 @@
     ((uint64_t) (uintptr_t) ll) | (T); })
 
 #define PVM_VAL_LONG_SIZE(V) (_PVM_VAL_LONG_ULONG_SIZE (V))
-#define PVM_VAL_LONG(V) (_PVM_VAL_LONG_ULONG_VAL ((V))           \
-                         << (64 - PVM_VAL_LONG_SIZE ((V)))      \
+#define PVM_VAL_LONG(V) (((int64_t) ((uint64_t) _PVM_VAL_LONG_ULONG_VAL ((V)) \
+                                     << (64 - PVM_VAL_LONG_SIZE ((V))))) \
                          >> (64 - PVM_VAL_LONG_SIZE ((V))))
 #define PVM_MAKE_LONG(V,S)                              \
   (PVM_MAKE_LONG_ULONG ((V),(S),PVM_VAL_TAG_LONG))
diff --git a/libpoke/pvm.jitter b/libpoke/pvm.jitter
index 8f7f33aa..9e9e6f2c 100644
--- a/libpoke/pvm.jitter
+++ b/libpoke/pvm.jitter
@@ -344,8 +344,8 @@ late-header-c
     CTYPE a = PVM_VAL_##TYPE (JITTER_UNDER_TOP_STACK ());                    \
     CTYPE b = PVM_VAL_##TYPE (JITTER_TOP_STACK ());                          \
     int size = PVM_VAL_##TYPE##_SIZE (JITTER_TOP_STACK ());                  \
-    int64_t a64 = ((int64_t) a << (64 - size));                              \
-    int64_t b64 = ((int64_t) b << (64 - size));                              \
+    int64_t a64 = ((uint64_t)(int64_t) a) << (64 - size);                    \
+    int64_t b64 = ((uint64_t)(int64_t) b) << (64 - size);                    \
                                                                              \
     if (INT_ADD_OVERFLOW (a64, b64))                                         \
       PVM_RAISE_DFL (PVM_E_OVERFLOW);                                        \
@@ -364,8 +364,8 @@ late-header-c
     CTYPE a = PVM_VAL_##TYPE (JITTER_UNDER_TOP_STACK ());                    \
     CTYPE b = PVM_VAL_##TYPE (JITTER_TOP_STACK ());                          \
     int size = PVM_VAL_##TYPE##_SIZE (JITTER_TOP_STACK ());                  \
-    int64_t a64 = ((int64_t) a << (64 - size));                              \
-    int64_t b64 = ((int64_t) b << (64 - size));                              \
+    int64_t a64 = ((uint64_t)(int64_t) a) << (64 - size);                    \
+    int64_t b64 = ((uint64_t)(int64_t) b) << (64 - size);                    \
                                                                              \
     if (INT_SUBTRACT_OVERFLOW (a64, b64))                                    \
       PVM_RAISE_DFL (PVM_E_OVERFLOW);                                        \
@@ -384,7 +384,7 @@ late-header-c
     CTYPE a = PVM_VAL_##TYPE (JITTER_UNDER_TOP_STACK ());                    \
     CTYPE b = PVM_VAL_##TYPE (JITTER_TOP_STACK ());                          \
     int size = PVM_VAL_##TYPE##_SIZE (JITTER_TOP_STACK ());                  \
-    int64_t a64 = ((int64_t) a << (64 - size));                              \
+    int64_t a64 = ((uint64_t)(int64_t) a) << (64 - size);                    \
                                                                              \
     if (INT_MULTIPLY_OVERFLOW (a64, b))                                      \
       PVM_RAISE_DFL (PVM_E_OVERFLOW);                                        \
-- 
2.30.2


>From afe93eb61e436faebd7232d5212e19683faba5ee Mon Sep 17 00:00:00 2001
From: "Jose E. Marchesi" <jose.marchesi@oracle.com>
Date: Mon, 23 Jan 2023 15:54:21 +0100
Subject: [PATCH 2/2] pvm.jitter: avoid left-shit UB in PVM_BINOP_SL

2023-01-23  Jose E. Marchesi  <jemarch@gnu.org>

        * libpoke/pvm.jitter (PVM_BINOP_SL): Do not trigger left-shit UB.
---
 ChangeLog          | 4 ++++
 libpoke/pvm.jitter | 5 ++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index d471c624..71785fcd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2023-01-23  Jose E. Marchesi  <jemarch@gnu.org>
+
+       * libpoke/pvm.jitter (PVM_BINOP_SL): Do not trigger left-shit UB.
+
 2023-01-23  Jose E. Marchesi  <jemarch@gnu.org>
 
        * libpoke/pkl-fold.c (pkl_phase_fold): Remove duplicated handler
diff --git a/libpoke/pvm.jitter b/libpoke/pvm.jitter
index 9e9e6f2c..96caa3f6 100644
--- a/libpoke/pvm.jitter
+++ b/libpoke/pvm.jitter
@@ -466,7 +466,10 @@ late-header-c
      }                                                                       \
      else                                                                    \
      {                                                                       \
-        PVM_BINOP (TYPEA, TYPEB, TYPER, OP);                                 \
+        int size = PVM_VAL_##TYPER##_SIZE (JITTER_UNDER_TOP_STACK ());       \
+        pvm_val res = PVM_MAKE_##TYPER ((uint64_t) PVM_VAL_##TYPEA 
(JITTER_UNDER_TOP_STACK ()) \
+                                        << PVM_VAL_##TYPEB (JITTER_TOP_STACK 
()), size); \
+        JITTER_PUSH_STACK (res);                                             \
      }                                                                       \
    }
 
-- 
2.30.2




reply via email to

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