Skip to content

libap: expand xmalloc family to full gnulib-compatible set#149

Merged
staalmannen merged 1 commit into
mainfrom
claude/upgrade-ape-c-library-mmZGd
May 23, 2026
Merged

libap: expand xmalloc family to full gnulib-compatible set#149
staalmannen merged 1 commit into
mainfrom
claude/upgrade-ape-c-library-mmZGd

Conversation

@staalmannen

Copy link
Copy Markdown
Owner

Add xreallocarray, xnmalloc, xcharalloc, xzalloc, x2nrealloc, x2realloc, xpalloc to libap's xmalloc.c.

Fix xnrealloc signature: gnulib's xnrealloc(p, n, s) is a fixed resize (calls xreallocarray), NOT the growing variant. The growing behavior is x2nrealloc. The old libap xnrealloc had x2nrealloc's signature, which would have caused ABI mismatches.

xpalloc uses ptrdiff_t for idx_t parameters (gnulib defines idx_t as ptrdiff_t); ckd_add/ckd_mul replaced with manual overflow guards.

Update xalloc.h with all new declarations and XNMALLOC/XNREALLOC macros.

https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs

Add xreallocarray, xnmalloc, xcharalloc, xzalloc, x2nrealloc,
x2realloc, xpalloc to libap's xmalloc.c.

Fix xnrealloc signature: gnulib's xnrealloc(p, n, s) is a fixed resize
(calls xreallocarray), NOT the growing variant. The growing behavior is
x2nrealloc. The old libap xnrealloc had x2nrealloc's signature, which
would have caused ABI mismatches.

xpalloc uses ptrdiff_t for idx_t parameters (gnulib defines idx_t as
ptrdiff_t); ckd_add/ckd_mul replaced with manual overflow guards.

Update xalloc.h with all new declarations and XNMALLOC/XNREALLOC macros.

https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
@staalmannen staalmannen merged commit 64ed89d into main May 23, 2026
1 check passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request expands the xalloc utility library in APE by introducing several new allocation and reallocation functions, such as xreallocarray, xnmalloc, xzalloc, and growth-oriented helpers like x2nrealloc and xpalloc. The review identified several critical issues that need to be addressed: the use of the non-standard reallocarray function which will lead to link errors in the APE environment, multiple potential integer overflows during buffer size calculations that could result in heap overflows, and a possible division-by-zero exception in the initial allocation logic.

Comment on lines +44 to +50
xreallocarray(void *p, size_t n, size_t s)
{
void *r = reallocarray(p, n, s);
if(!r && n != 0 && s != 0)
xalloc_die();
return r;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The function reallocarray is an OpenBSD extension and is not part of the standard Plan 9 APE library. Using it here will result in a link error. Since this is libap, you should provide a manual implementation that checks for overflow before calling realloc.

void *
xreallocarray(void *p, size_t n, size_t s)
{
	if(n != 0 && s != 0 && n > (size_t)-1 / s)
		xalloc_die();
	void *r = realloc(p, n * s);
	if(!r && n != 0 && s != 0)
		xalloc_die();
	return r;
}

if(0 <= n_max && n_max < n)
n = n_max;

nbytes = (size_t)n * (size_t)s;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The multiplication (size_t)n * (size_t)s can overflow size_t before the result is passed to xrealloc. This is a critical security risk as it could lead to a heap buffer overflow if a smaller-than-requested buffer is allocated. An explicit overflow check is required.

	if(s > 0 && (size_t)n > (size_t)-1 / (size_t)s)
		xalloc_die();
	nbytes = (size_t)n * (size_t)s;

n = n0 + n_incr_min;
if(n < 0 || (0 <= n_max && n_max < n))
xalloc_die();
nbytes = (size_t)n * (size_t)s;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Similar to the previous calculation, this multiplication must be guarded against overflow to ensure the integrity of the heap allocation.

		if(s > 0 && (size_t)n > (size_t)-1 / (size_t)s)
			xalloc_die();
		nbytes = (size_t)n * (size_t)s;

Comment on lines +114 to +117
if(!n) {
n = DEFAULT_MXFAST / s;
n += !n;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If s is 0, the division DEFAULT_MXFAST / s will cause a division-by-zero exception (SIGFPE). While s is typically a sizeof expression, a robust library implementation should guard against this.

		if(!n) {
			n = s ? DEFAULT_MXFAST / s : 0;
			n += !n;
		}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants