Qprintf Rewrite - #97
Conversation
…branch). Fix a bug in qprintf() that caused % and & characters inside conditional printing areas to always print, regardless of the condition. Improve documentation for qpfPrintf_va_internal() and qpf_grow_fn_t(). Clean up.
Reorder some code to improve clarity. Add various comments. Fix spacing mistakes. Add void to function signatures that do not take parameters.
Clean up some overly cleaver code.
…d more comments. Overhaul qpf_internal_Translate() to improve readability. Improve readability of qpf_internal_SetupTable(). Improve code in multiple functions that ensures the module is initialized. Clean up and improve function doc comments.
Add line numbers to errors. Add qpfLogErrors(). Add qpf_internal_getErrorName(). Add qpf_internal_count_zeros(). Add QPF_ERR_T_NO_ERRORS. Add QPF_ERR_COUNT. Improve formating of QPF_ERR_T defines.
…bility using better code patterns.
Add docs for session functions. Add license. Clarify how to use source and filter format specifiers. Simplify wording for filter specifiers to improve readability.
|
@greptileai Please review this PR. |
Greptile SummaryThe PR substantially rewrites QPrintf and expands its tests, documentation, error reporting, and supporting library utilities.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| centrallix-lib/src/qprintf.c | Rewrites QPrintf parsing and output handling; the previously reported predicate, initialization, no-grow, quote-boundary, syntax, and capacity issues are addressed at current HEAD. |
| centrallix-lib/include/qprintf.h | Expands the public QPrintf API and session error metadata to support the rewritten implementation. |
| centrallix-lib/tests/test_qprintf_69.c | Verifies that quoted overflow in a two-byte destination retains a quote and null terminator. |
| centrallix-lib/tests/test_qprintf_70.c | Covers the one-byte quoted-output boundary without permitting an out-of-bounds quote write. |
| centrallix-sysdoc/QPrintf.md | Documents QPrintf behavior and the expanded formatting interface. |
| centrallix-lib/Makefile.in | Adds new library objects and parallelized test and Valgrind execution infrastructure. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Parse format string] --> B[Resolve source specifier]
B --> C[Apply length and conversion filters]
C --> D{Quoted output?}
D -- Yes --> E[Reserve and write opening quote]
D -- No --> F[Translate or copy content]
E --> F
F --> G[Reserve and write closing quote]
G --> H[Null-terminate destination]
H --> I[Return copied length and session errors]
Reviews (17): Last reviewed commit: "Merge branch 'add-utils' into qprintf-re..." | Re-trigger Greptile
Fix is_only_followed_by_nlen using || instead of &&. Fix closing quote space check didn't handle buffer overflows very well. Fix null_session error line numbers not being initialized. Fix qpfClearErrors() being lazy about clearing error line numbers. Fix qpf_internal_count_zeros(0) edge case.
|
@greptileai I think I resolved your comments. Please rereview. Are there any other concerns you have? |
|
@greptileai I think I resolved your comments. Please rereview. Are there any other concerns you have? |
|
The root cause is that Instead of making the write conditional (which breaks your tests), clamp The clamp is a no-op in the normal case — when |
|
@greptileai I've made the changes you've requested but I haven't tested or pushed my code yet. Could you write a test case, following the same style established in |
|
Here's the test following the exact style of Why this reproduces the bug: A 2-byte buffer for
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include "qprintf.h"
#include <assert.h>
long long
test(char** tname)
{
int i, rval;
int iter;
unsigned char buf[16];
*tname = "qprintf-53 %STR" with buffer too small for content (null termination)";
iter = 200000;
for(i=0;i<iter;i++)
{
buf[9] = '\n';
buf[8] = '\0';
buf[7] = 0xff;
buf[6] = 0xff; /* sentinel: byte immediately after 2-byte buffer -- must not be clobbered */
/* buf+4 is the 2-byte buffer under test: occupies buf[4] and buf[5] */
buf[3] = '\n';
buf[2] = '\0';
buf[1] = 0xff;
buf[0] = '\0';
rval = qpfPrintf(NULL, buf+4, 2, "%STR"", "ab");
/* The 2-byte buffer must be null-terminated within its own bounds.
* Without dest_offset clamped before the closing-quote write,
* buf[5] holds '\'' and no null terminator is ever written. */
assert(buf[5] == '\0');
/* The byte immediately after the buffer must not be overwritten.
* Without the no_grow guard, an out-of-bounds null-terminator write
* could clobber this sentinel. */
assert(buf[6] == 0xff);
/* Bytes before the buffer must be untouched */
assert(buf[3] == '\n');
assert(buf[2] == '\0');
assert(buf[1] == 0xff);
assert(buf[0] == '\0');
/* Return value must indicate overflow: full output 'ab' + NUL = 5 bytes */
assert(rval == 5);
}
return iter;
}Failure summary by variant:
One caveat: I inferred |
Fix a quote buffer overflow comment from Greptile. Add test_qprintf_69.c to validate that the "fixed" code now works properly. Note: Honestly, I'm so in the weeds that I only understand about 80% of what's going on here, but it works, and this probably isn't worth a ton of additional effort.
|
@greptileai I think I resolved your comments, and I also added your test case with some clean up, bug fixing (on the return value), and other improvements. Please rereview. Are there any other concerns you have? |
# Conflicts: # centrallix-lib/tests/test_qprintf_53.c
qprintf.chad some code that confused me a lot. For example, there was a switch statement inside an if statement inside another switch statement inside a loop inside another if statement inside the else block of different if statement inside another if statement inside another loop... causing my brain to throw a stack overflow exception.After understanding the code (which will be useful for the apos_autoscale proejct), I did some refactoring, and now it's much easier to read, in my opinion. Also, I added some tools for improved error handling, as usual.
GitHub Relationships
%BOOLto qprintf() #162qprintf()prints%and&inside skipped conditionals #140centrallix-libTests #170centrallix-libUtilities #130Greptile Summary