On 12/15/2016 02:09 AM, Bruno Haible wrote:
So, the limiting factor is the pointer difference operator
ptr1 - ptr2 where sizeof (*ptr1,*ptr2) > 1.
Yes, it is the pointer difference operator. However, the problem occurs
even with size-1 array elements. For example:
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
ptrdiff_t
diff (char *a, char *b)
{
return a - b;
}
int
main (void)
{
size_t n = PTRDIFF_MAX / 2 + 1;
size_t size = 2 * n;
char *x = malloc (size);
return 0 < diff (x + size, x);
}
'main' returns 0 on Fedora 24 (x86-64 or x86).
* We have no problem with code that only works with indices and never does
pointer differences or pointer comparisons.
I don't see a problem with pointer comparisons, just pointer differences.
* We have no problem with strings, because sizeof (char) == 1.
No, unfortunately large strings do not work, as one cannot reliably
compute differences of pointers to their elements.
One possibility would be to have two flavors of xalloc_oversized. One
flavor would check for both ptrdiff_t overflow and size_t overflow, for
programs that do pointer subtraction, and the other flavor
(yalloc_oversized, say?) would check only for size_t overflow, for
programs that never subtract pointers to the allocated storage. All
current functions like xnmalloc could have two flavors, so that xnmalloc
checks for both kinds of overflow and ynmalloc checks only for size_t
overflow. It's not clear to me whether it's worth going to all that
effort merely to support 3 GiB arrays in 32-bit applications. In the
meantime, I installed the patch I proposed yesterday, along with the
additional patches attached, which merely change the x* functions to
check for both kinds of overflow.
From 7c7c9a8c9fda03b8973fbc866bf6171cab97a8bb Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Thu, 15 Dec 2016 09:53:45 -0800
Subject: [PATCH 1/4] quotearg: pacify GCC better
* modules/quotearg (Depends-on): Add minmax, stdint.
* lib/quotearg.c: Include minmax.h, stdint.h.
(nslots): Now int, as there seems little point to going to extra
work merely to support the INT_MAX slot, which nobody ever uses.
(quotearg_n_options): Redo size-overflow checks to pacify GCC
and to catch (mostly-theoretical) ptrdiff_t problems too.
This can be done via one comparison.
---
ChangeLog | 11 +++++++++++
lib/quotearg.c | 23 +++++++++--------------
modules/quotearg | 2 ++
3 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 767e0c7..612d66c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2016-12-15 Paul Eggert <eggert@cs.ucla.edu>
+
+ quotearg: pacify GCC better
+ * modules/quotearg (Depends-on): Add minmax, stdint.
+ * lib/quotearg.c: Include minmax.h, stdint.h.
+ (nslots): Now int, as there seems little point to going to extra
+ work merely to support the INT_MAX slot, which nobody ever uses.
+ (quotearg_n_options): Redo size-overflow checks to pacify GCC
+ and to catch (mostly-theoretical) ptrdiff_t problems too.
+ This can be done via one comparison.
+
2016-12-14 Paul Eggert <eggert@cs.ucla.edu>
xalloc-oversized: check for PTRDIFF_MAX too
diff --git a/lib/quotearg.c b/lib/quotearg.c
index 730b4b3..07658b2 100644
--- a/lib/quotearg.c
+++ b/lib/quotearg.c
@@ -29,6 +29,7 @@
#include "quotearg.h"
#include "quote.h"
+#include "minmax.h"
#include "xalloc.h"
#include "c-strcaseeq.h"
#include "localcharset.h"
@@ -37,6 +38,7 @@
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
@@ -830,7 +832,7 @@ struct slotvec
/* Preallocate a slot 0 buffer, so that the caller can always quote
one small component of a "memory exhausted" message in slot 0. */
static char slot0[256];
-static unsigned int nslots = 1;
+static int nslots = 1;
static struct slotvec slotvec0 = {sizeof slot0, slot0};
static struct slotvec *slotvec = &slotvec0;
@@ -838,7 +840,7 @@ void
quotearg_free (void)
{
struct slotvec *sv = slotvec;
- unsigned int i;
+ int i;
for (i = 1; i < nslots; i++)
free (sv[i].val);
if (sv[0].val != slot0)
@@ -869,30 +871,23 @@ quotearg_n_options (int n, char const *arg, size_t argsize,
{
int e = errno;
- unsigned int n0 = n;
struct slotvec *sv = slotvec;
if (n < 0)
abort ();
- if (nslots <= n0)
+ if (nslots <= n)
{
- /* FIXME: technically, the type of n1 should be 'unsigned int',
- but that evokes an unsuppressible warning from gcc-4.0.1 and
- older. If gcc ever provides an option to suppress that warning,
- revert to the original type, so that the test in xalloc_oversized
- is once again performed only at compile time. */
- size_t n1 = n0 + 1;
bool preallocated = (sv == &slotvec0);
- if (xalloc_oversized (n1, sizeof *sv))
+ if (MIN (INT_MAX, MIN (PTRDIFF_MAX, SIZE_MAX) / sizeof *sv) <= n)
xalloc_die ();
- slotvec = sv = xrealloc (preallocated ? NULL : sv, n1 * sizeof *sv);
+ slotvec = sv = xrealloc (preallocated ? NULL : sv, (n + 1) * sizeof *sv);
if (preallocated)
*sv = slotvec0;
- memset (sv + nslots, 0, (n1 - nslots) * sizeof *sv);
- nslots = n1;
+ memset (sv + nslots, 0, (n + 1 - nslots) * sizeof *sv);
+ nslots = n + 1;
}
{
diff --git a/modules/quotearg b/modules/quotearg
index bd63761..109a16d 100644
--- a/modules/quotearg
+++ b/modules/quotearg
@@ -16,9 +16,11 @@ gettext-h
mbrtowc
mbsinit
memcmp
+minmax
quotearg-simple
localcharset
stdbool
+stdint
wchar
wctype-h
xalloc
--
2.7.4
From 83c7f0582c5111ce027f74e50fc7f1e813db02e1 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Thu, 15 Dec 2016 09:56:53 -0800
Subject: [PATCH 2/4] malloca: do not exceed PTRDIFF_MAX
* lib/malloca.h: Include xalloc-oversized.
(nmalloca): Use xalloc_oversized instead of rolling our own.
* modules/malloca (Depends-on):
* modules/relocatable-prog-wrapper (Depends-on):
Add xalloc-oversized.
---
ChangeLog | 7 +++++++
lib/malloca.h | 13 ++++---------
modules/malloca | 1 +
modules/relocatable-prog-wrapper | 1 +
4 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 612d66c..07c4d65 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2016-12-15 Paul Eggert <eggert@cs.ucla.edu>
+ malloca: do not exceed PTRDIFF_MAX
+ * lib/malloca.h: Include xalloc-oversized.
+ (nmalloca): Use xalloc_oversized instead of rolling our own.
+ * modules/malloca (Depends-on):
+ * modules/relocatable-prog-wrapper (Depends-on):
+ Add xalloc-oversized.
+
quotearg: pacify GCC better
* modules/quotearg (Depends-on): Add minmax, stdint.
* lib/quotearg.c: Include minmax.h, stdint.h.
diff --git a/lib/malloca.h b/lib/malloca.h
index 46f27f0..c00dbed 100644
--- a/lib/malloca.h
+++ b/lib/malloca.h
@@ -21,6 +21,9 @@
#include <alloca.h>
#include <stddef.h>
#include <stdlib.h>
+#include <stdint.h>
+
+#include "xalloc-oversized.h"
#ifdef __cplusplus
@@ -73,15 +76,7 @@ extern void freea (void *p);
It allocates an array of N objects, each with S bytes of memory,
on the stack. S must be positive and N must be nonnegative.
The array must be freed using freea() before the function returns. */
-#if 1
-/* Cf. the definition of xalloc_oversized. */
-# define nmalloca(n, s) \
- ((n) > (size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) \
- ? NULL \
- : malloca ((n) * (s)))
-#else
-extern void * nmalloca (size_t n, size_t s);
-#endif
+#define nmalloca(n, s) (xalloc_oversized (n, s) ? NULL : malloca ((n) * (s)))
#ifdef __cplusplus
diff --git a/modules/malloca b/modules/malloca
index ca0be89..9d4b40b 100644
--- a/modules/malloca
+++ b/modules/malloca
@@ -12,6 +12,7 @@ m4/longlong.m4
Depends-on:
alloca-opt
stdint
+xalloc-oversized
verify
configure.ac:
diff --git a/modules/relocatable-prog-wrapper b/modules/relocatable-prog-wrapper
index 50444b1..db451ef 100644
--- a/modules/relocatable-prog-wrapper
+++ b/modules/relocatable-prog-wrapper
@@ -47,6 +47,7 @@ unistd
environ
string
verify
+xalloc-oversized
configure.ac:
gl_FUNC_READLINK_SEPARATE
--
2.7.4
From b2d30e9c7649397463aed49f12cc493c93afbd45 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Thu, 15 Dec 2016 09:59:21 -0800
Subject: [PATCH 3/4] xalloc: do not exceed PTRDIFF_MAX
* lib/xmalloc.c (xcalloc) [HAVE_GNU_CALLOC]: Do not omit
xalloc_oversized check, since objects larger than PTRDIFF_MAX
bytes have pointer-subtraction problems.
---
ChangeLog | 5 +++++
lib/xmalloc.c | 10 +++++-----
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 07c4d65..bee9a17 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2016-12-15 Paul Eggert <eggert@cs.ucla.edu>
+ xalloc: do not exceed PTRDIFF_MAX
+ * lib/xmalloc.c (xcalloc) [HAVE_GNU_CALLOC]: Do not omit
+ xalloc_oversized check, since objects larger than PTRDIFF_MAX
+ bytes have pointer-subtraction problems.
+
malloca: do not exceed PTRDIFF_MAX
* lib/malloca.h: Include xalloc-oversized.
(nmalloca): Use xalloc_oversized instead of rolling our own.
diff --git a/lib/xmalloc.c b/lib/xmalloc.c
index 429b50d..7d9c077 100644
--- a/lib/xmalloc.c
+++ b/lib/xmalloc.c
@@ -93,11 +93,11 @@ void *
xcalloc (size_t n, size_t s)
{
void *p;
- /* Test for overflow, since some calloc implementations don't have
- proper overflow checks. But omit overflow and size-zero tests if
- HAVE_GNU_CALLOC, since GNU calloc catches overflow and never
- returns NULL if successful. */
- if ((! HAVE_GNU_CALLOC && xalloc_oversized (n, s))
+ /* Test for overflow, since objects with size greater than
+ PTRDIFF_MAX cause pointer subtraction to go awry. Omit size-zero
+ tests if HAVE_GNU_CALLOC, since GNU calloc never returns NULL if
+ successful. */
+ if (xalloc_oversized (n, s)
|| (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0)))
xalloc_die ();
return p;
--
2.7.4
From bae65427b398824d58ef55bbc14b296ddaf22921 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Thu, 15 Dec 2016 10:00:22 -0800
Subject: [PATCH 4/4] safe-alloc: use xalloc-oversized
* lib/safe-alloc.c: Include xalloc-oversized.h.
(safe_alloc_oversized): Remove. All uses changed to xalloc_oversized.
* modules/safe-alloc (Depends-on): Add xalloc-oversized.
---
ChangeLog | 5 +++++
lib/safe-alloc.c | 25 ++++---------------------
modules/safe-alloc | 3 +++
3 files changed, 12 insertions(+), 21 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index bee9a17..5e9e801 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2016-12-15 Paul Eggert <eggert@cs.ucla.edu>
+ safe-alloc: use xalloc-oversized
+ * lib/safe-alloc.c: Include xalloc-oversized.h.
+ (safe_alloc_oversized): Remove. All uses changed to xalloc_oversized.
+ * modules/safe-alloc (Depends-on): Add xalloc-oversized.
+
xalloc: do not exceed PTRDIFF_MAX
* lib/xmalloc.c (xcalloc) [HAVE_GNU_CALLOC]: Do not omit
xalloc_oversized check, since objects larger than PTRDIFF_MAX
diff --git a/lib/safe-alloc.c b/lib/safe-alloc.c
index 7b2acf2..0f9e5a6 100644
--- a/lib/safe-alloc.c
+++ b/lib/safe-alloc.c
@@ -22,30 +22,13 @@
/* Specification. */
#include "safe-alloc.h"
+#include "xalloc-oversized.h"
+
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
-/* Return 1 if an array of N objects, each of size S, cannot exist due
- to size arithmetic overflow. S must be positive and N must be
- nonnegative. This is a macro, not a function, so that it
- works correctly even when SIZE_MAX < N.
-
- By gnulib convention, SIZE_MAX represents overflow in size
- calculations, so the conservative dividend to use here is
- SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
- However, malloc (SIZE_MAX) fails on all known hosts where
- sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
- exactly-SIZE_MAX allocations on such hosts; this avoids a test and
- branch when S is known to be 1.
-
- This is the same as xalloc_oversized from xalloc.h
-*/
-#define safe_alloc_oversized(n, s) \
- ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
-
-
/**
* safe_alloc_alloc_n:
* @ptrptr: pointer to pointer for address of allocated memory
@@ -68,7 +51,7 @@ safe_alloc_alloc_n (void *ptrptr, size_t size, size_t count, int zeroed)
return 0;
}
- if (safe_alloc_oversized (count, size))
+ if (xalloc_oversized (count, size))
{
errno = ENOMEM;
return -1;
@@ -108,7 +91,7 @@ safe_alloc_realloc_n (void *ptrptr, size_t size, size_t count)
*(void **) ptrptr = NULL;
return 0;
}
- if (safe_alloc_oversized (count, size))
+ if (xalloc_oversized (count, size))
{
errno = ENOMEM;
return -1;
diff --git a/modules/safe-alloc b/modules/safe-alloc
index 94f799f..13e78de 100644
--- a/modules/safe-alloc
+++ b/modules/safe-alloc
@@ -6,6 +6,9 @@ lib/safe-alloc.h
lib/safe-alloc.c
m4/safe-alloc.m4
+Depends-on:
+xalloc-oversized
+
configure.ac:
gl_SAFE_ALLOC
--
2.7.4