Good morning.

sum_up_to_nul reads 4 bytes starting from the passed string 'p'.
'p' can have fewer than 4 bytes. Usually there more allocated space
after 'p', which prevents this reading from manifesting itself. This
reading manifests itself visibly when 'p' points to the end of the
allocated block of memory, such that p + 3 points to not allocated
memory.
Please have a look at the patch in the attachment.
Tested on both big and little endian, 32 and 64 bit.

regards, Dmitry
diff --git a/src/hash.c b/src/hash.c
index bd3892e..67f0018 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -16,6 +16,7 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */

 #include "makeint.h"
 #include "hash.h"
+#include <assert.h>

 #define CALLOC(t, n) ((t *) xcalloc (sizeof (t) * (n)))
 #define MALLOC(t, n) ((t *) xmalloc (sizeof (t) * (n)))
@@ -410,10 +411,13 @@ unsigned jhash(unsigned const char *k, int length)

 #ifdef WORDS_BIGENDIAN
 /* The ifs are ordered from the first byte in memory to the last.  */
-#define sum_up_to_nul(r, p, flag)         \
+#define sum_up_to_nul(r, p, plen, flag)   \
   do {                                    \
-    unsigned int val;                     \
-    memcpy(&val, (p), 4);                 \
+    unsigned int val = 0;                 \
+    size_t vsz = sizeof (val);            \
+    size_t pn = (plen);                   \
+    size_t n = pn < vsz ? pn : vsz;       \
+    memcpy(&val, (p), n);                 \
     if ((val & 0xFF000000) == 0)          \
       flag = 1;                           \
     else if ((val & 0xFF0000) == 0)       \
@@ -427,11 +431,14 @@ unsigned jhash(unsigned const char *k, int length)
 /* First detect the presence of zeroes.  If there is none, we can
    sum the 4 bytes directly.  Otherwise, the ifs are ordered as in the
    big endian case, from the first byte in memory to the last.  */
-#define sum_up_to_nul(r, p, flag)                   \
+#define sum_up_to_nul(r, p, plen, flag)             \
   do {                                              \
-    unsigned int val;                               \
+    unsigned int val = 0;                           \
+    size_t vsz = sizeof (val);                      \
+    size_t pn = (plen);                             \
+    size_t n = pn < vsz ? pn : vsz;                 \
     unsigned int zeroes;                            \
-    memcpy(&val, (p), 4);                           \
+    memcpy(&val, (p), n);                           \
     zeroes = ((val - 0x01010101) & ~val);           \
     if (!(zeroes & 0x80808080))                     \
       r += val;                                     \
@@ -454,24 +461,31 @@ unsigned jhash_string(unsigned const char *k)
   unsigned int a, b, c;
   unsigned int have_nul = 0;
   unsigned const char *start = k;
+  size_t klen = strlen(k);

   /* Set up the internal state */
   a = b = c = JHASH_INITVAL;

   /* All but the last block: affect some 32 bits of (a,b,c) */
   for (;;) {
-    sum_up_to_nul(a, k, have_nul);
+    sum_up_to_nul(a, k, klen, have_nul);
     if (have_nul)
       break;
     k += 4;
-    sum_up_to_nul(b, k, have_nul);
+    assert (klen >= 4);
+    klen -= 4;
+    sum_up_to_nul(b, k, klen, have_nul);
     if (have_nul)
       break;
     k += 4;
-    sum_up_to_nul(c, k, have_nul);
+    assert (klen >= 4);
+    klen -= 4;
+    sum_up_to_nul(c, k, klen, have_nul);
     if (have_nul)
       break;
     k += 4;
+    assert (klen >= 4);
+    klen -= 4;
     jhash_mix(a, b, c);
   }


_______________________________________________
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make
  • gmake-4.2.90 ... Dmitry Goncharov via Bug reports and discussion for GNU make

Reply via email to