summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2026-05-21 17:13:42 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2026-05-23 19:18:53 -0700
commit64eb869b68835e15b46a217a6d955605b78044bc (patch)
tree3cb6b850b11fd87ec7167e491218eda030fa2883
parentc72e6cdc464e295d821da24232a2913bbcecf3f8 (diff)
Be more careful about size multiplication
* src/alloc.c (xcalloc): New function. * src/dispnew.c (save_current_matrix): * src/fns.c (Finternal__hash_table_histogram): * src/nsfns.m (Fns_display_monitor_attributes_list): * src/pgtkfns.c (Fpgtk_display_monitor_attributes_list): * src/pgtkselect.c (pgtk_own_selection): * src/profiler.c (make_log): * src/sfnt.c (sfnt_poly_edges_exact): * src/xfns.c (x_get_monitor_attributes_xinerama) (x_get_monitor_attributes_xrandr, Fx_display_monitor_attributes_list): Use it instead of multiplying by hand, conceivably with overflow. * src/profiler.c (make_log): Check for overflow in internal size calculations. Use xnmalloc instead of multiply + xmalloc. * src/sfnt.c (xzalloc) [TEST]: Remove, replacing with ... (xicalloc) [TEST]: ... this new function. All callers changed. (eassert) [TEST]: New macro. * src/treesit.c (treesit_calloc_wrapper): Remove, replacing its use with xcalloc.
-rw-r--r--src/alloc.c20
-rw-r--r--src/dispnew.c2
-rw-r--r--src/fns.c2
-rw-r--r--src/lisp.h2
-rw-r--r--src/nsfns.m2
-rw-r--r--src/pgtkfns.c2
-rw-r--r--src/pgtkselect.c2
-rw-r--r--src/profiler.c15
-rw-r--r--src/sfnt.c14
-rw-r--r--src/treesit.c8
-rw-r--r--src/xfns.c8
-rw-r--r--src/xterm.c4
12 files changed, 48 insertions, 33 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 387b196bbee..6a81fed2d69 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -656,7 +656,10 @@ xmalloc (size_t size)
return val;
}
-/* Like the above, but zeroes out the memory just allocated. */
+/* Like the above, but zero out the memory just allocated.
+ Calling this can be faster than allocating and zeroing,
+ as the calloc implementation can avoid the zeroing overhead
+ when obtaining memory directly from the operating system. */
void *
xzalloc (size_t size)
@@ -668,6 +671,21 @@ xzalloc (size_t size)
return val;
}
+/* Like xzalloc, but for an array of N objects each of size S. */
+
+void *
+xcalloc (size_t n, size_t s)
+{
+ void *val = calloc (n, s);
+ if (!val)
+ {
+ size_t size;
+ memory_full (ckd_mul (&size, n, s) ? SIZE_MAX : size);
+ }
+ MALLOC_PROBE (n * s);
+ return val;
+}
+
/* Like realloc but check for no memory and block interrupt input. */
void *
diff --git a/src/dispnew.c b/src/dispnew.c
index be15a5ab694..7930fa59968 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -1963,7 +1963,7 @@ save_current_matrix (struct frame *f)
int i;
struct glyph_matrix *saved = xzalloc (sizeof *saved);
saved->nrows = f->current_matrix->nrows;
- saved->rows = xzalloc (saved->nrows * sizeof *saved->rows);
+ saved->rows = xcalloc (saved->nrows, sizeof *saved->rows);
for (i = 0; i < saved->nrows; ++i)
{
diff --git a/src/fns.c b/src/fns.c
index 8e7e5f980a1..98671fc1318 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -5996,7 +5996,7 @@ DEFUN ("internal--hash-table-histogram",
{
struct Lisp_Hash_Table *h = check_hash_table (hash_table);
ptrdiff_t size = HASH_TABLE_SIZE (h);
- ptrdiff_t *freq = xzalloc (size * sizeof *freq);
+ ptrdiff_t *freq = xcalloc (size, sizeof *freq);
ptrdiff_t index_size = hash_table_index_size (h);
for (ptrdiff_t i = 0; i < index_size; i++)
{
diff --git a/src/lisp.h b/src/lisp.h
index bf80cfec3ad..d4978460f68 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -5536,6 +5536,8 @@ extern void *xmalloc (size_t)
ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
extern void *xzalloc (size_t)
ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
+extern void *xcalloc (size_t, size_t)
+ ATTRIBUTE_MALLOC_SIZE ((1,2)) ATTRIBUTE_RETURNS_NONNULL;
extern void *xrealloc (void *, size_t)
ATTRIBUTE_ALLOC_SIZE ((2)) ATTRIBUTE_RETURNS_NONNULL;
extern void xfree (void *);
diff --git a/src/nsfns.m b/src/nsfns.m
index efe622782f7..045d167e6b4 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -2768,7 +2768,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */)
if (n_monitors == 0)
return Qnil;
- monitors = xzalloc (n_monitors * sizeof *monitors);
+ monitors = xcalloc (n_monitors, sizeof *monitors);
for (i = 0; i < [screens count]; ++i)
{
diff --git a/src/pgtkfns.c b/src/pgtkfns.c
index 4257dc45f98..e1766d2b1a6 100644
--- a/src/pgtkfns.c
+++ b/src/pgtkfns.c
@@ -2432,7 +2432,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */)
gdpy = dpyinfo->gdpy;
n_monitors = gdk_display_get_n_monitors (gdpy);
monitor_frames = make_nil_vector (n_monitors);
- monitors = xzalloc (n_monitors * sizeof *monitors);
+ monitors = xcalloc (n_monitors, sizeof *monitors);
FOR_EACH_FRAME (rest, frame)
{
diff --git a/src/pgtkselect.c b/src/pgtkselect.c
index 425da3b8fd4..7e32252616b 100644
--- a/src/pgtkselect.c
+++ b/src/pgtkselect.c
@@ -213,7 +213,7 @@ pgtk_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
if (VECTORP (targets))
{
- gtargets = xzalloc (sizeof *gtargets * ASIZE (targets));
+ gtargets = xcalloc (ASIZE (targets), sizeof *gtargets);
ntargets = 0;
for (i = 0; i < ASIZE (targets); ++i)
diff --git a/src/profiler.c b/src/profiler.c
index 67049f487ee..b8339a3c544 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -75,21 +75,24 @@ make_log (int size, int depth)
int index_size = size * 2 + 1;
log->index_size = index_size;
- log->trace = xmalloc (depth * sizeof *log->trace);
+ log->trace = xnmalloc (depth, sizeof *log->trace);
- log->index = xmalloc (index_size * sizeof *log->index);
+ log->index = xnmalloc (index_size, sizeof *log->index);
for (int i = 0; i < index_size; i++)
log->index[i] = -1;
- log->next = xmalloc (size * sizeof *log->next);
+ log->next = xnmalloc (size, sizeof *log->next);
for (int i = 0; i < size - 1; i++)
log->next[i] = i + 1;
log->next[size - 1] = -1;
log->next_free = 0;
- log->hash = xmalloc (size * sizeof *log->hash);
- log->keys = xzalloc (size * depth * sizeof *log->keys);
- log->counts = xzalloc (size * sizeof *log->counts);
+ log->hash = xnmalloc (size, sizeof *log->hash);
+ size_t size_x_depth;
+ if (ckd_mul (&size_x_depth, size, depth))
+ memory_full_up ();
+ log->keys = xcalloc (size_x_depth, sizeof *log->keys);
+ log->counts = xcalloc (size, sizeof *log->counts);
return log;
}
diff --git a/src/sfnt.c b/src/sfnt.c
index ab6a2d5e7bc..e46ebc3a08b 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -70,11 +70,11 @@ xmalloc (size_t size)
}
MAYBE_UNUSED static void *
-xzalloc (size_t size)
+xcalloc (ptrdiff_t n, ptrdiff_t s)
{
void *ptr;
- ptr = calloc (1, size);
+ ptr = calloc (n, s);
if (!ptr)
abort ();
@@ -111,6 +111,8 @@ xfree (void *ptr)
/* Also necessary. */
#define AVOID _Noreturn ATTRIBUTE_COLD void
+#define eassert(expr) assert (expr)
+
#else
#define TEST_STATIC
#include "lisp.h"
@@ -5047,7 +5049,7 @@ sfnt_poly_edges_exact (struct sfnt_fedge *edges, size_t nedges,
sfnt_step_raster_proc proc, void *dcontext)
{
int y;
- size_t size, e, edges_processed;
+ size_t e, edges_processed;
struct sfnt_fedge *active, **prev, *a, sentinel;
struct sfnt_step_raster raster;
struct sfnt_step_chunk *next, *last;
@@ -5065,11 +5067,7 @@ sfnt_poly_edges_exact (struct sfnt_fedge *edges, size_t nedges,
raster.scanlines = height;
raster.chunks = NULL;
-
- if (ckd_mul (&size, height, sizeof *raster.steps))
- abort ();
-
- raster.steps = xzalloc (size);
+ raster.steps = xcalloc (height, sizeof *raster.steps);
for (; y != height; y += 1)
{
diff --git a/src/treesit.c b/src/treesit.c
index 3d342be3dcc..00b97da2c5c 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -559,19 +559,13 @@ load_tree_sitter_if_necessary (bool required)
#endif
}
-static void *
-treesit_calloc_wrapper (size_t n, size_t size)
-{
- return xzalloc (n * size);
-}
-
static void
treesit_initialize (void)
{
if (!treesit_initialized)
{
load_tree_sitter_if_necessary (true);
- ts_set_allocator (xmalloc, treesit_calloc_wrapper, xrealloc, xfree);
+ ts_set_allocator (xmalloc, xcalloc, xrealloc, xfree);
treesit_initialized = true;
}
}
diff --git a/src/xfns.c b/src/xfns.c
index 7ec6025ab66..ba3bf211f55 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -6254,7 +6254,7 @@ x_get_monitor_attributes_xinerama (struct x_display_info *dpyinfo)
/ x_display_pixel_width (dpyinfo));
mm_height_per_pixel = ((double) HeightMMOfScreen (dpyinfo->screen)
/ x_display_pixel_height (dpyinfo));
- monitors = xzalloc (n_monitors * sizeof *monitors);
+ monitors = xcalloc (n_monitors, sizeof *monitors);
for (i = 0; i < n_monitors; ++i)
{
struct MonitorInfo *mi = &monitors[i];
@@ -6328,7 +6328,7 @@ x_get_monitor_attributes_xrandr (struct x_display_info *dpyinfo)
if (!rr_monitors)
goto fallback;
- monitors = xzalloc (n_monitors * sizeof *monitors);
+ monitors = xcalloc (n_monitors, sizeof *monitors);
#ifdef USE_XCB
atom_name_cookies = alloca (n_monitors * sizeof *atom_name_cookies);
#endif
@@ -6427,7 +6427,7 @@ x_get_monitor_attributes_xrandr (struct x_display_info *dpyinfo)
return Qnil;
}
n_monitors = resources->noutput;
- monitors = xzalloc (n_monitors * sizeof *monitors);
+ monitors = xcalloc (n_monitors, sizeof *monitors);
#if RANDR13_LIBRARY
if (randr13_avail)
@@ -6644,7 +6644,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */)
/ x_display_pixel_height (dpyinfo));
#endif
monitor_frames = make_nil_vector (n_monitors);
- monitors = xzalloc (n_monitors * sizeof *monitors);
+ monitors = xcalloc (n_monitors, sizeof *monitors);
FOR_EACH_FRAME (rest, frame)
{
diff --git a/src/xterm.c b/src/xterm.c
index 941297a77ce..06fe480646e 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5730,7 +5730,7 @@ x_cache_xi_devices (struct x_display_info *dpyinfo)
return;
}
- dpyinfo->devices = xzalloc (sizeof *dpyinfo->devices * ndevices);
+ dpyinfo->devices = xcalloc (ndevices, sizeof *dpyinfo->devices);
for (i = 0; i < ndevices; ++i)
{
@@ -13881,7 +13881,7 @@ xi_disable_devices (struct x_display_info *dpyinfo,
return;
ndevices = 0;
- devices = xzalloc (sizeof *devices * dpyinfo->num_devices);
+ devices = xcalloc (dpyinfo->num_devices, sizeof *devices);
/* Loop through every device currently in DPYINFO, and copy it to
DEVICES if it is not in TO_DISABLE. Note that this function