g_try_malloc
g_try_malloc0
g_try_realloc
+g_malloc_n
+g_malloc0_n
+g_realloc_n
+g_try_malloc_n
+g_try_malloc0_n
+g_try_realloc_n
<SUBSECTION>
g_free
Allocates @n_structs elements of type @struct_type.
The returned pointer is cast to a pointer to the given type.
If @n_structs is 0 it returns %NULL.
+Care is taken to avoid overflow when calculating the size of the allocated block.
</para>
<para>
Since the returned pointer is already casted to the right type,
Allocates @n_structs elements of type @struct_type, initialized to 0's.
The returned pointer is cast to a pointer to the given type.
If @n_structs is 0 it returns %NULL.
+Care is taken to avoid overflow when calculating the size of the allocated block.
</para>
<para>
Since the returned pointer is already casted to the right type,
Reallocates the memory pointed to by @mem, so that it now has space for
@n_structs elements of type @struct_type. It returns the new address of
the memory, which may have been moved.
+Care is taken to avoid overflow when calculating the size of the allocated block.
</para>
@struct_type: the type of the elements to allocate
Attempts to allocate @n_structs elements of type @struct_type, and returns
%NULL on failure. Contrast with g_new(), which aborts the program on failure.
The returned pointer is cast to a pointer to the given type.
-If @n_structs is 0 it returns %NULL.
+The function returns %NULL when @n_structs is 0 of if an overflow occurs.
</para>
@struct_type: the type of the elements to allocate
to 0's, and returns %NULL on failure. Contrast with g_new0(), which aborts
the program on failure.
The returned pointer is cast to a pointer to the given type.
-The function returns %NULL when @n_structs is 0.
+The function returns %NULL when @n_structs is 0 of if an overflow occurs.
</para>
@struct_type: the type of the elements to allocate
space for @n_structs elements of type @struct_type, and returns %NULL on
failure. Contrast with g_renew(), which aborts the program on failure.
It returns the new address of the memory, which may have been moved.
+The function returns %NULL if an overflow occurs.
</para>
@struct_type: the type of the elements to allocate
@Returns: the allocated memory, or %NULL.
+<!-- ##### FUNCTION g_malloc_n ##### -->
+<para>
+This function is similar to g_malloc(), allocating (@n_blocks * @n_block_bytes) bytes,
+but care is taken to detect possible overflow during multiplication.
+</para>
+
+@n_blocks: the number of blocks to allocate
+@n_block_bytes: the size of each block in bytes
+@Returns: a pointer to the allocated memory
+@Since: 2.24
+
+
+<!-- ##### FUNCTION g_malloc0_n ##### -->
+<para>
+This function is similar to g_malloc0(), allocating (@n_blocks * @n_block_bytes) bytes,
+but care is taken to detect possible overflow during multiplication.
+</para>
+
+@n_blocks: the number of blocks to allocate
+@n_block_bytes: the size of each block in bytes
+@Returns: a pointer to the allocated memory
+@Since: 2.24
+
+
+<!-- ##### FUNCTION g_realloc_n ##### -->
+<para>
+This function is similar to g_realloc(), allocating (@n_blocks * @n_block_bytes) bytes,
+but care is taken to detect possible overflow during multiplication.
+</para>
+
+@mem: the memory to reallocate
+@n_blocks: the number of blocks to allocate
+@n_block_bytes: the size of each block in bytes
+@Returns: the new address of the allocated memory
+@Since: 2.24
+
+
+<!-- ##### FUNCTION g_try_malloc_n ##### -->
+<para>
+This function is similar to g_try_malloc(), allocating (@n_blocks * @n_block_bytes) bytes,
+but care is taken to detect possible overflow during multiplication.
+</para>
+
+@n_blocks: the number of blocks to allocate
+@n_block_bytes: the size of each block in bytes
+@Returns: the allocated memory, or %NULL.
+@Since: 2.24
+
+
+<!-- ##### FUNCTION g_try_malloc0_n ##### -->
+<para>
+This function is similar to g_try_malloc0(), allocating (@n_blocks * @n_block_bytes) bytes,
+but care is taken to detect possible overflow during multiplication.
+</para>
+
+@n_blocks: the number of blocks to allocate
+@n_block_bytes: the size of each block in bytes
+@Returns: the allocated memory, or %NULL
+@Since: 2.24
+
+
+<!-- ##### FUNCTION g_try_realloc_n ##### -->
+<para>
+This function is similar to g_try_realloc(), allocating (@n_blocks * @n_block_bytes) bytes,
+but care is taken to detect possible overflow during multiplication.
+</para>
+
+@mem: previously-allocated memory, or %NULL.
+@n_blocks: the number of blocks to allocate
+@n_block_bytes: the size of each block in bytes
+@Returns: the allocated memory, or %NULL.
+@Since: 2.24
+
+
<!-- ##### FUNCTION g_free ##### -->
<para>
Frees the memory pointed to by @mem.
g_free
g_malloc G_GNUC_MALLOC
g_malloc0 G_GNUC_MALLOC
+g_malloc_n G_GNUC_MALLOC
+g_malloc0_n G_GNUC_MALLOC
g_mem_is_system_malloc
g_mem_profile
g_mem_set_vtable
g_realloc
+g_realloc_n
g_try_malloc G_GNUC_MALLOC
g_try_malloc0 G_GNUC_MALLOC
+g_try_malloc_n G_GNUC_MALLOC
+g_try_malloc0_n G_GNUC_MALLOC
g_try_realloc
+g_try_realloc_n
#ifndef G_DISABLE_DEPRECATED
g_allocator_free
g_allocator_new
gpointer
g_try_malloc0 (gsize n_bytes)
-{
+{
gpointer mem;
mem = g_try_malloc (n_bytes);
-
+
if (mem)
memset (mem, 0, n_bytes);
return NULL;
}
+
+#define SIZE_OVERFLOWS(a,b) (G_UNLIKELY ((a) > G_MAXSIZE / (b)))
+
+#undef g_malloc_n
+gpointer
+g_malloc_n (gsize n_blocks,
+ gsize n_block_bytes)
+{
+ if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+ {
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+
+ g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes",
+ G_STRLOC, n_blocks, n_block_bytes);
+ }
+
+ return g_malloc (n_blocks * n_block_bytes);
+}
+
+#undef g_malloc0_n
+gpointer
+g_malloc0_n (gsize n_blocks,
+ gsize n_block_bytes)
+{
+ if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+ {
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+
+ g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes",
+ G_STRLOC, n_blocks, n_block_bytes);
+ }
+
+ return g_malloc0 (n_blocks * n_block_bytes);
+}
+
+#undef g_realloc_n
+gpointer
+g_realloc_n (gpointer mem,
+ gsize n_blocks,
+ gsize n_block_bytes)
+{
+ if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+ {
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+
+ g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes",
+ G_STRLOC, n_blocks, n_block_bytes);
+ }
+
+ return g_realloc (mem, n_blocks * n_block_bytes);
+}
+
+#undef g_try_malloc_n
+gpointer
+g_try_malloc_n (gsize n_blocks,
+ gsize n_block_bytes)
+{
+ if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+ return NULL;
+
+ return g_try_malloc (n_blocks * n_block_bytes);
+}
+
+#undef g_try_malloc0_n
+gpointer
+g_try_malloc0_n (gsize n_blocks,
+ gsize n_block_bytes)
+{
+ if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+ return NULL;
+
+ return g_try_malloc0 (n_blocks * n_block_bytes);
+}
+
+#undef g_try_realloc_n
+gpointer
+g_try_realloc_n (gpointer mem,
+ gsize n_blocks,
+ gsize n_block_bytes)
+{
+ if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+ return NULL;
+
+ return g_try_realloc (mem, n_blocks * n_block_bytes);
+}
+
+
+
static gpointer
fallback_calloc (gsize n_blocks,
gsize n_block_bytes)
/* Memory allocation functions
*/
+
+void g_free (gpointer mem);
+
gpointer g_malloc (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
gpointer g_malloc0 (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
gpointer g_realloc (gpointer mem,
gsize n_bytes) G_GNUC_WARN_UNUSED_RESULT;
-void g_free (gpointer mem);
gpointer g_try_malloc (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
gpointer g_try_malloc0 (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
gpointer g_try_realloc (gpointer mem,
gsize n_bytes) G_GNUC_WARN_UNUSED_RESULT;
+gpointer g_malloc_n (gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_malloc0_n (gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_realloc_n (gpointer mem,
+ gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_WARN_UNUSED_RESULT;
+gpointer g_try_malloc_n (gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_try_malloc0_n (gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_try_realloc_n (gpointer mem,
+ gsize n_blocks,
+ gsize n_block_bytes) G_GNUC_WARN_UNUSED_RESULT;
+
+
+/* avoid the overflow check if we can determine at compile-time that no
+ * overflow happens. */
+#if defined (__GNUC__) && (__GNUC__ >= 2) && defined (__OPTIMIZE__)
+# define _G_MALLOC_N(n_blocks, n_block_bytes, func_1, func_n) \
+ (__extension__ ({ \
+ gsize __a = (gsize) (n_blocks); \
+ gsize __b = (gsize) (n_block_bytes); \
+ gpointer __p; \
+ if (__builtin_constant_p (__a) && __a == 1) \
+ __p = func_1 (__b); \
+ else if (__builtin_constant_p (__b) && __b == 1) \
+ __p = func_1 (__a); \
+ else if (__builtin_constant_p (__a) && \
+ __builtin_constant_p (__b) && \
+ __a <= G_MAXSIZE / __b) \
+ __p = func_1 (__a * __b); \
+ else \
+ __p = func_n (__a, __b); \
+ __p; \
+ }))
+# define _G_REALLOC_N(mem, n_blocks, n_block_bytes, func_1, func_n) \
+ (__extension__ ({ \
+ gsize __a = (gsize) (n_blocks); \
+ gsize __b = (gsize) (n_block_bytes); \
+ gpointer __p = (gpointer) (mem); \
+ if (__builtin_constant_p (__a) && __a == 1) \
+ __p = func_1 (__p, __b); \
+ else if (__builtin_constant_p (__b) && __b == 1) \
+ __p = func_1 (__p, __a); \
+ else if (__builtin_constant_p (__a) && \
+ __builtin_constant_p (__b) && \
+ __a <= G_MAXSIZE / __b) \
+ __p = func_1 (__p, __a * __b); \
+ else \
+ __p = func_n (__p, __a, __b); \
+ __p; \
+ }))
+
+# define g_malloc_n(n_blocks,n_block_bytes) _G_MALLOC_N (n_blocks, n_block_bytes, g_malloc, g_malloc_n)
+# define g_malloc0_n(n_blocks,n_block_bytes) _G_MALLOC_N (n_blocks, n_block_bytes, g_malloc0, g_malloc0_n)
+# define g_realloc_n(mem,n_blocks,n_block_bytes) _G_REALLOC_N (mem, n_blocks, n_block_bytes, g_realloc, g_realloc_n)
+# define g_try_malloc_n(n_blocks,n_block_bytes) _G_MALLOC_N (n_blocks, n_block_bytes, g_try_malloc, g_try_malloc_n)
+# define g_try_malloc0_n(n_blocks,n_block_bytes) _G_MALLOC_N (n_blocks, n_block_bytes, g_try_malloc0, g_try_malloc0_n)
+# define g_try_realloc_n(mem,n_blocks,n_block_bytes) _G_REALLOC_N (mem, n_blocks, n_block_bytes, g_try_realloc, g_try_realloc_n)
+#endif
+
/* Convenience memory allocators
*/
-#define g_new(struct_type, n_structs) \
- ((struct_type *) g_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
-#define g_new0(struct_type, n_structs) \
- ((struct_type *) g_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
-#define g_renew(struct_type, mem, n_structs) \
- ((struct_type *) g_realloc ((mem), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
-#define g_try_new(struct_type, n_structs) \
- ((struct_type *) g_try_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
-#define g_try_new0(struct_type, n_structs) \
- ((struct_type *) g_try_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
-#define g_try_renew(struct_type, mem, n_structs) \
- ((struct_type *) g_try_realloc ((mem), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define _G_NEW(struct_type, n_structs, _g_malloc_n) \
+ ((struct_type *) _g_malloc_n ((n_structs), sizeof (struct_type)))
+#define _G_RENEW(struct_type, mem, n_structs, _g_realloc_n) \
+ ((struct_type *) _g_realloc_n ((mem), (n_structs), sizeof (struct_type)))
+
+#define g_new(struct_type, n_structs) _G_NEW (struct_type, n_structs, g_malloc_n)
+#define g_new0(struct_type, n_structs) _G_NEW (struct_type, n_structs, g_malloc0_n)
+#define g_renew(struct_type, mem, n_structs) _G_RENEW (struct_type, mem, n_structs, g_realloc_n)
+#define g_try_new(struct_type, n_structs) _G_NEW (struct_type, n_structs, g_try_malloc_n)
+#define g_try_new0(struct_type, n_structs) _G_NEW (struct_type, n_structs, g_try_malloc0_n)
+#define g_try_renew(struct_type, mem, n_structs) _G_RENEW (struct_type, mem, n_structs, g_try_realloc_n)
/* Memory allocation virtualization for debugging purposes
* g_mem_set_vtable() has to be the very first GLib function called
* if being used
*/
-struct _GMemVTable
-{
+struct _GMemVTable {
gpointer (*malloc) (gsize n_bytes);
gpointer (*realloc) (gpointer mem,
gsize n_bytes);
TEST_PROGS += gvariant
gvariant_LDADD = $(progs_ldadd)
+TEST_PROGS += mem-overflow
+mem_overflow_LDADD = $(progs_ldadd)
+
if OS_UNIX
# some testing of gtester funcitonality
--- /dev/null
+/* Unit tests for g
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This work is provided "as is"; redistribution and modification
+ * in whole or in part, in any medium, physical or electronic is
+ * permitted without restriction.
+ *
+ * This work is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * In no event shall the authors or contributors be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential
+ * damages (including, but not limited to, procurement of substitute
+ * goods or services; loss of use, data, or profits; or business
+ * interruption) however caused and on any theory of liability, whether
+ * in contract, strict liability, or tort (including negligence or
+ * otherwise) arising in any way out of the use of this software, even
+ * if advised of the possibility of such damage.
+ */
+
+#include "glib.h"
+#include <stdlib.h>
+
+static void
+mem_overflow (void)
+{
+ gsize a = G_MAXSIZE / 10 + 10;
+ gsize b = 10;
+ gpointer p, q;
+ typedef char X[10];
+
+#define CHECK_PASS(P) p = (P); g_assert (p == NULL);
+#define CHECK_FAIL(P) p = (P); g_assert (p != NULL);
+
+ CHECK_PASS (g_try_malloc_n (a, a));
+ CHECK_PASS (g_try_malloc_n (a, b));
+ CHECK_PASS (g_try_malloc_n (b, a));
+ CHECK_FAIL (g_try_malloc_n (b, b));
+
+ CHECK_PASS (g_try_malloc0_n (a, a));
+ CHECK_PASS (g_try_malloc0_n (a, b));
+ CHECK_PASS (g_try_malloc0_n (b, a));
+ CHECK_FAIL (g_try_malloc0_n (b, b));
+
+ q = g_malloc (1);
+ CHECK_PASS (g_try_realloc_n (q, a, a));
+ CHECK_PASS (g_try_realloc_n (q, a, b));
+ CHECK_PASS (g_try_realloc_n (q, b, a));
+ CHECK_FAIL (g_try_realloc_n (q, b, b));
+ free (p);
+
+ CHECK_PASS (g_try_new (X, a));
+ CHECK_FAIL (g_try_new (X, b));
+
+ CHECK_PASS (g_try_new0 (X, a));
+ CHECK_FAIL (g_try_new0 (X, b));
+
+ q = g_try_malloc (1);
+ CHECK_PASS (g_try_renew (X, q, a));
+ CHECK_FAIL (g_try_renew (X, q, b));
+ free (p);
+
+#undef CHECK_EQ
+#undef CHECK_NEQ
+
+#define CHECK_FAIL(P) if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) { p = (P); exit (0); } g_test_trap_assert_failed();
+#define CHECK_PASS(P) if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) { p = (P); exit (0); } g_test_trap_assert_passed();
+
+ CHECK_FAIL (g_malloc_n (a, a));
+ CHECK_FAIL (g_malloc_n (a, b));
+ CHECK_FAIL (g_malloc_n (b, a));
+ CHECK_PASS (g_malloc_n (b, b));
+
+ CHECK_FAIL (g_malloc0_n (a, a));
+ CHECK_FAIL (g_malloc0_n (a, b));
+ CHECK_FAIL (g_malloc0_n (b, a));
+ CHECK_PASS (g_malloc0_n (b, b));
+
+ q = g_malloc (1);
+ CHECK_FAIL (g_realloc_n (q, a, a));
+ CHECK_FAIL (g_realloc_n (q, a, b));
+ CHECK_FAIL (g_realloc_n (q, b, a));
+ CHECK_PASS (g_realloc_n (q, b, b));
+ free (q);
+
+ CHECK_FAIL (g_new (X, a));
+ CHECK_PASS (g_new (X, b));
+
+ CHECK_FAIL (g_new0 (X, a));
+ CHECK_PASS (g_new0 (X, b));
+
+ q = g_malloc (1);
+ CHECK_FAIL (g_renew (X, q, a));
+ CHECK_PASS (g_renew (X, q, b));
+ free (q);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/mem/overflow", mem_overflow);
+
+ return g_test_run();
+}
-/* Unit tests for gstring
+/* Unit tests for gprintf
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This work is provided "as is"; redistribution and modification
-/* Unit tests for gstring
+/* Unit tests for grand
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This work is provided "as is"; redistribution and modification