Repository navigation
Conversation
g_ascii_formatd(buffer, buf_len, format, d) formats exactly one double into buffer, but every call was reported as g_ascii_formatd format string requires 1 parameter but only 0 are given. Uninitialized variable: buffer - The double is a fixed argument: with it configured as arg 4 the format check did not count it. Leave it to the format string check, which now also checks its type. - buffer is written, not read: it need not be initialized or a string. Its size must be at least buf_len.
dmcppcheck
left a comment
There was a problem hiding this comment.
AI review
I found no real problems in this PR. Both false positives from the description go away: wrongPrintfScanfArgNum and uninitvar on the output buffer. Three checks still work: an uninitialized d is still reported, also when the format string is not a literal; a wrong conversion is reported (invalidPrintfArgType_*); and a buffer smaller than buf_len is reported (bufferAccessOutOfBounds).
One small regression: removing <arg nr="4"> also removes not-bool for d. With a literal format string the format check now covers this (invalidPrintfArgType_float). With a non-literal format string, passing a bool is no longer reported, where base reported invalidFunctionArgBool. That case is rare and I don't think it should block the PR.
Testing
Build and tests
make -j8 cppcheck testrunnerinpr/built fine../testrunner TestLibrary TestBufferOverrun: 0 failures.test/cfg/gtk.cwith the options fromtest/cfg/runtests.sh(--check-library --platform=unix64 --enable=style,information --inconclusive --force --check-level=exhaustive --inline-suppr --debug-warnings --library=gtk): no unexpected findings, and all the new inline suppressions are matched.- I could not validate against the RelaxNG schema because
xmllintis not installed here.
How I compared with base
I did not build base. Instead I ran the PR binary once with --library=gtk (new config) and once with --library=std --library=<base gtk.cfg> (old config), on scratch files with these cases:
- the valid call
- uninitialized
d, with a literal format and with a non-literal one "%.2f %f"with one double%dwith a double- a buffer that is too small (stack and
g_malloc, includingchar buf[38]withbuf_len39) - a NULL buffer
%gand%e- a bool argument
Results
- PR: the only findings are the expected ones:
bufferAccessOutOfBoundsforbuf[38]/39,small[4]/39 andg_malloc(4)/39; no finding forbuf[39]/39.wrongPrintfScanfArgNumonly for"%.2f %f", which says it needs 2 parameters and gets 1.invalidPrintfArgType_sintandinvalidPrintfArgType_floatfor the wrong type and the bool.nullPointerfor the NULL buffer.uninitvarond.
- Base config: every call gets
wrongPrintfScanfArgNum ... only 0 are given, and every call getsuninitvaron the buffer.
Small regression
void g8(const char *fmt, int b) { char buf[39]; g_ascii_formatd(buf, 39, fmt, b==1); }The base config reports Invalid g_ascii_formatd() argument nr 4. A non-boolean value is required. [invalidFunctionArgBool]; the PR config reports nothing.
Not detected by either config
buf+1 with a length of 39, and a buf_len held in a variable. These are limits of minsize, not something the PR changed.
Automated review of 395ef5e by Claude. The pull request was built and tested locally.
Review of the previous commit: dropping <arg nr="4"> also dropped its <not-bool/>, so with a format string that is not a literal a bool passed as the value was no longer reported (invalidFunctionArgBool). Describing arg 4 again makes the format check count it as a fixed argument and report "requires 1 parameter but only 0 are given" again, so describe it as the variadic argument instead, as gnu.cfg does.
Thanks for this value feedback. Fixed the not-bool regression in 65c0efe: describing |
dmcppcheck
left a comment
There was a problem hiding this comment.
AI review
No new correctness problems. The not-bool regression is fixed with <arg nr="variadic">: invalidFunctionArgBool is reported again when the format string is not a literal. Both false positives from the description are gone.
One small difference from gnu.cfg: the new variadic entry has no <not-uninit/>. For a struct member that is not initialized, this drops uninitStructMember. The uninitvar warning on the same argument is still reported, so nothing is lost in practice.
As a side effect, the PR now reports an extra argument with a literal format ("%f", d, e), which base did not report.
Testing
Build and tests
- Built
cppcheckandtestrunnerinpr/. ./testrunner TestLibrary: 0 failures.test/cfg/gtk.cwith the options fromruntests.sh(--inline-suppr --check-library --error-exitcode=1 ...): exit code 0, so every new suppression is matched.- Not done:
xmllintis not installed, so I could not validate against the schema.
How I compared with base: I ran the PR binary with --library=gtk and with base's gtk.cfg.
- Valid literal call: base gives
wrongPrintfScanfArgNum ... only 0 are givenanduninitvaron the buffer. The PR gives neither. g_ascii_formatd(buf, 39, "%f")with no value: both reportwrongPrintfScanfArgNum.g_ascii_formatd(buf, 39, "%f", d, e): the PR reportsrequires 1 parameter but 2 are given. Base reported nothing.- Non-literal format with a missing or an extra value: neither reports it. This is unchanged.
- Uninitialized
d,arr[0]ors.xas the value: still reported asuninitvar.
Small difference without not-uninit on the variadic argument
struct S { double x; };
void b(const gchar *fmt) { struct S s; gchar buf[39]; g_ascii_formatd(buf, 39, fmt, s.x); g_print("%s", buf); }Command: cppcheck -q --library=gtk --platform=unix64 u.c
- Base config:
uninitvar s.xanduninitStructMember s.x. - PR config: only
uninitvar s.x. - PR config with
<not-uninit/>added to the variadic arg: both again, with no other change.
Automated review of 65c0efe by Claude. The pull request was built and tested locally.
Review of the previous commit: the variadic argument lacked the <not-uninit/> that gnu.cfg gives its variadic arguments, so an uninitialized struct member passed as the value was only reported as uninitvar, without uninitStructMember.
I don't have a Trac account, so there is no ticket for this; the details are below. Feel free to create one and I'll add it to the title.
g_ascii_formatd(buffer, buf_len, format, d)formats exactly one double intobuffer.%dwith a double is reported).buffer(arg 1, direction out) was markednot-uninitandstrzalthough it is only written. It now hasminsizebuf_leninstead, which also catches a buffer smaller thanbuf_len.Tests:
test/cfg/gtk.ccovers the valid call, a wrong conversion and a too-small buffer. Both false positives show without the change;cfg/gtk.cfgvalidates againstcppcheck-cfg.rng.