Fix format-string use of __FILE__/__func__ and name_for_status lower bound
Two hardening fixes flagged by the earlier review: 1. FAIL passed __FILE__ and __func__ directly as the snprintf format string. __FILE__ expands to a string literal that could contain a '%' (a build path under a directory with a percent sign), and __func__ is not a literal at all; either way snprintf would read nonexistent varargs. Pass them as "%s" arguments instead. 2. akerr_name_for_status guarded the upper bound but not the lower one, so a negative status indexed __AKERR_ERROR_NAMES[negative] -- an out-of-bounds read, or an out-of-bounds write when a name was supplied. Reject status < 0. Regression tests err_format_string (uses #line to put a conversion specifier in __FILE__) and err_name_bounds fail against the old code (verified) and pass now. Full suite: 23/23, no warnings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
34
tests/err_format_string.c
Normal file
34
tests/err_format_string.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "akerror.h"
|
||||
#include "err_capture.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* FAIL records the source file and function names with snprintf. Those names
|
||||
* must be passed as %s ARGUMENTS, not used as the format string -- otherwise a
|
||||
* path containing a printf conversion (say a build directory with a '%') is
|
||||
* interpreted as a format and reads nonexistent varargs (undefined behavior).
|
||||
*
|
||||
* #line lets us make __FILE__ contain a conversion specifier; the stored name
|
||||
* must come back verbatim.
|
||||
*/
|
||||
|
||||
#line 1 "pct%dname.c"
|
||||
akerr_ErrorContext *raise_with_percent_in_filename(void)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_RETURN(e, AKERR_VALUE, "boom");
|
||||
}
|
||||
#line 22 "tests/err_format_string.c"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
akerr_init();
|
||||
|
||||
akerr_ErrorContext *e = raise_with_percent_in_filename();
|
||||
AKERR_CHECK(e != NULL);
|
||||
AKERR_CHECK(strcmp(e->fname, "pct%dname.c") == 0);
|
||||
|
||||
e = akerr_release_error(e);
|
||||
fprintf(stderr, "err_format_string ok\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user