]> granicus.if.org Git - libatomic_ops/commitdiff
Fix size value wrap around in AO_malloc_large
authorIvan Maidanski <ivmai@mail.ru>
Mon, 22 Aug 2016 17:12:19 +0000 (20:12 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Wed, 2 Nov 2016 22:10:20 +0000 (01:10 +0300)
(Cherry-pick commits 1033478 and b1365bd from 'master' branch.)

AO_malloc(SIZE_MAX) should return NULL now.

* src/atomic_ops_malloc.c: Include limits.h (unless SIZE_MAX already
defined).
* src/atomic_ops_malloc.c (AO_SIZE_MAX): New macro.
* src/atomic_ops_malloc.c (SIZET_SAT_ADD): New macro.
* src/atomic_ops_malloc.c (AO_malloc_large): Use SIZET_SAT_ADD to
avoid integer overflow when computing the memory size to map (i.e.,
malloc should handle arguments close to SIZE_MAX correctly).

src/atomic_ops_malloc.c

index 124c87c414261b7416126efba723af051a4fc19e..327c4ae4191471a054fb4cf66bbd0894abf643d0 100644 (file)
@@ -135,6 +135,20 @@ static char *get_mmaped(size_t sz)
   return result;
 }
 
+#ifndef SIZE_MAX
+# include <limits.h>
+#endif
+#ifdef SIZE_MAX
+# define AO_SIZE_MAX SIZE_MAX
+#else
+# define AO_SIZE_MAX (~(size_t)0)
+#endif
+
+/* Saturated addition of size_t values.  Used to avoid value wrap       */
+/* around on overflow.  The arguments should have no side effects.      */
+#define SIZET_SAT_ADD(a, b) \
+                ((a) < AO_SIZE_MAX - (b) ? (a) + (b) : AO_SIZE_MAX)
+
 /* Allocate an object of size (incl. header) of size > CHUNK_SIZE.      */
 /* sz includes space for an AO_t-sized header.                          */
 static char *
@@ -142,9 +156,8 @@ AO_malloc_large(size_t sz)
 {
  char * result;
  /* The header will force us to waste ALIGNMENT bytes, incl. header.    */
-   sz += ALIGNMENT;
- /* Round to multiple of CHUNK_SIZE.    */
-   sz = (sz + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
+ /* Round to multiple of CHUNK_SIZE.                                    */
+ sz = SIZET_SAT_ADD(sz, ALIGNMENT + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
  result = get_mmaped(sz);
  if (result == 0) return 0;
  result += ALIGNMENT;