stdio/printf: add error propagation#483
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the formatting library to propagate errors by changing the 'feedfunc' signature to return an 'int' instead of 'void', and introduces a 'CHECK_FAIL' macro for early returns on failure. However, several critical issues were identified in the review: returning directly on '__bignum_shiftl' failure leaks allocated bignums, using 'CHECK_FAIL' on 'format_sprintfDecimalForm' bypasses necessary cleanup causing memory leaks, and 'format_feed' should return 'ctx->error' instead of '0' when an error is present to allow early aborts.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
650b0ab to
6cc5fcb
Compare
6cc5fcb to
00d2740
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request updates the stdio formatting library to support error propagation by changing the signature of the feedfunc callback to return an int and introducing a CHECK_FAIL macro to handle failures. The review feedback suggests ensuring that vfprintf and vprintf set errno to ENOMEM when memory allocation fails, in compliance with POSIX. Additionally, it is recommended that format_printBuffer explicitly returns 0 on success to prevent positive return values from feed (such as from putchar) from propagating as unexpected non-zero success codes.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| putchar(c); | ||
|
|
||
| ret = putchar(c); | ||
| if (ret >= 0) { |
There was a problem hiding this comment.
Better to compare to EOF explicitly.
| *n = *n + 1; | ||
| } | ||
|
|
||
| return ret; |
There was a problem hiding this comment.
This will return positive values returned from putchar() or -1 (EOF). Better to return 0 here and some error code on EOF.
| @@ -102,7 +104,7 @@ int vfprintf(FILE *stream, const char *format, va_list arg) | |||
There was a problem hiding this comment.
-1 is not an error code.
| prec = precision ? precision : 1; | ||
| exp = format_sprintfScientificForm(&buff, &bd_backup, flags, prec - 1, &startOffset); | ||
| if (exp <= DOUBLE_EXP_INVALID) { | ||
| ret = exp - DOUBLE_EXP_INVALID; |
There was a problem hiding this comment.
ret value is later used in function's logic. Cutting it to 0/-1 caused CI errors. Decoding what format_sprintfScientificForm returns w/o any comments is too time consuming, so left it as it is
There was a problem hiding this comment.
I don't see it. At which line is it used? format_sprintfDouble is supposed to return negative error code not some unrelated negative value like exp - DOUBLE_EXP_INVALID.
There was a problem hiding this comment.
ret is used in line 840 to decide if we should call format_printBuffer or not.
Regarding format_sprintfDouble returning error code, we don't utilize it in format_parse which calls that function. We only check if it returned negative value or not. errno should be already set if error occured. format_parse only returns -1/0.
| else if (format == 'e') { | ||
| ret = format_sprintfScientificForm(&buff, &bd, flags, precision, &startOffset); | ||
| if (ret <= DOUBLE_EXP_INVALID) { | ||
| ret -= DOUBLE_EXP_INVALID; |
There was a problem hiding this comment.
ret used later in function
required by POSIX - return negative value and set errno on `printf` error. JIRA: RTOS-1354
00d2740 to
cb07ba8
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors the formatting library to propagate errors by changing the feedfunc signature to return an int and introducing a CHECK_FAIL macro to handle failures. However, the review feedback highlights that the printf family functions (vfprintf, vdprintf, vsprintf, and vsnprintf) return EOF on failure without setting errno as required by POSIX. It is recommended to set errno to the negative error code returned by format_parse. Additionally, the documentation comment for format_parse should be updated to correctly reflect that it propagates negative error codes rather than returning -1 on error.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if (ret != 0) { | ||
| return EOF; | ||
| } |
There was a problem hiding this comment.
POSIX requires printf and related functions to set errno on failure. Currently, if formatting fails due to an out-of-memory error (e.g., in bignum operations or buffer allocations), format_parse returns -ENOMEM, but vfprintf returns EOF without setting errno. We should set errno = -ret when ret is a negative error code other than -1 (which indicates the error was already handled and errno was set by the underlying I/O function).
if (ret != 0) {
if (ret != -1) {
errno = -ret;
}
return EOF;
}| if (ret != 0) { | ||
| return EOF; | ||
| } |
There was a problem hiding this comment.
POSIX requires printf and related functions to set errno on failure. Currently, if formatting fails due to an out-of-memory error (e.g., in bignum operations or buffer allocations), format_parse returns -ENOMEM, but vdprintf returns EOF without setting errno. We should set errno = -ret when ret is a negative error code other than -1 (which indicates the error was already handled and errno was set by the underlying I/O function).
if (ret != 0) {
if (ret != -1) {
errno = -ret;
}
return EOF;
}| ret = format_parse(&ctx, vsprintf_feed, format, arg); | ||
| vsprintf_feed(&ctx, '\0'); | ||
|
|
||
| if (ret == 0) { | ||
| return ctx.n - 1; | ||
| } | ||
| else { | ||
| return SET_ERRNO(ret); | ||
| } | ||
| return (ret == 0) ? ctx.n - 1 : EOF; |
There was a problem hiding this comment.
POSIX requires printf and related functions to set errno on failure. Currently, if formatting fails due to an out-of-memory error (e.g., in bignum operations or buffer allocations), format_parse returns -ENOMEM, but vsprintf returns EOF without setting errno. We should set errno = -ret when ret is a negative error code.
| ret = format_parse(&ctx, vsprintf_feed, format, arg); | |
| vsprintf_feed(&ctx, '\0'); | |
| if (ret == 0) { | |
| return ctx.n - 1; | |
| } | |
| else { | |
| return SET_ERRNO(ret); | |
| } | |
| return (ret == 0) ? ctx.n - 1 : EOF; | |
| ret = format_parse(&ctx, vsprintf_feed, format, arg); | |
| vsprintf_feed(&ctx, '\0'); | |
| if (ret != 0) { | |
| errno = -ret; | |
| return EOF; | |
| } | |
| return ctx.n - 1; |
| ret = format_parse(&ctx, vsnprintf_feed, format, arg); | ||
| vsnprintf_feed(&ctx, '\0'); | ||
|
|
||
| if (ret == 0) { | ||
| return ctx.n - 1; | ||
| } | ||
| else { | ||
| return SET_ERRNO(ret); | ||
| } | ||
| return (ret == 0) ? ctx.n - 1 : EOF; |
There was a problem hiding this comment.
POSIX requires printf and related functions to set errno on failure. Currently, if formatting fails due to an out-of-memory error (e.g., in bignum operations or buffer allocations), format_parse returns -ENOMEM, but vsnprintf returns EOF without setting errno. We should set errno = -ret when ret is a negative error code.
ret = format_parse(&ctx, vsnprintf_feed, format, arg);
vsnprintf_feed(&ctx, '\0');
if (ret != 0) {
errno = -ret;
return EOF;
}
return ctx.n - 1;| /* | ||
| * @return: 0 on success, -1 on any error. | ||
| * | ||
| * Functions called by format_parse() shall set `errno` when error occurs. | ||
| */ |
There was a problem hiding this comment.
The comment states that format_parse returns -1 on any error, but it actually propagates negative error codes (such as -ENOMEM or -errno) returned by the underlying formatting and bignum functions. Updating the comment to reflect this will improve code clarity and maintainability.
/*
* @return: 0 on success, negative error code on error.
*
* Functions called by format_parse() shall set `errno` when error occurs.
*/|
What's the idea with returning EOF in |
|
|
||
| if (fmt != '%') { | ||
| feed(ctx, fmt); | ||
| CHECK_FAIL(ret, feed(ctx, fmt)); |
There was a problem hiding this comment.
Function returns -ret instead of -1 as stated by the comment and errno is not set. This applies to all CHECK_FAIL() invocations in this function.
| @@ -94,12 +98,7 @@ int vsprintf(char *str, const char *format, va_list arg) | |||
| ret = format_parse(&ctx, vsprintf_feed, format, arg); | |||
| vsprintf_feed(&ctx, '\0'); | |||
There was a problem hiding this comment.
Consider casting the return value to (void) and adding a comment that vsprintf_feed() always succeeds.
| @@ -115,10 +114,5 @@ int vsnprintf(char *str, size_t n, const char *format, va_list arg) | |||
| ret = format_parse(&ctx, vsnprintf_feed, format, arg); | |||
| vsnprintf_feed(&ctx, '\0'); | |||
There was a problem hiding this comment.
Consider casting the return value to (void) and adding a comment that vsnprintf_feed() always succeeds.
required by POSIX - return negative value and set errno on
printferror.JIRA: RTOS-1354
Fixes phoenix-rtos/phoenix-rtos-project#1416
Description
Motivation and Context
Types of changes
How Has This Been Tested?
Checklist:
Special treatment