libap: expand xmalloc family to full gnulib-compatible set#149
Conversation
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
There was a problem hiding this comment.
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.
| 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; | ||
| } |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
| if(!n) { | ||
| n = DEFAULT_MXFAST / s; | ||
| n += !n; | ||
| } |
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