From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailtransmit04.runbox.com (mailtransmit04.runbox.com [185.226.149.37]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A448634D4DE for ; Mon, 23 Feb 2026 11:10:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.226.149.37 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771845043; cv=none; b=ihfBk06hfGsWPOpB1wmCT0VJooVt08hYEPNc4eZSCEFH8N/wvvBWUA/l9fxUHkbn02xEbD75+EKsbB+2OVFt1QsDUlYvD3it4RBh71PijtHm0dKf0H5HbAH0lqbsKLIY8kWElr6XDWN5C6Ru9Z+DcKbp6Mx/V26xL3RE8LcRX84= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771845043; c=relaxed/simple; bh=u+6JTbvh2s4QJvC1bDHd0x+KO/CfIj8Uvl/clpJ2aLk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=b7X+5J67ortUWOK22DhbEex3m9K3+GGpQl2FPfZJJw2m4QDRMilXhkTWTnCmpQT2fMiMFuq89KRFmavNTqZzC5aA5s0p3/vK97PB2u2h+l9/FL9JTRNMeMiFsfvmAWyWhcbjS0NkkmPvm1q7VCT44coGmbpkWIlojNmlWkwXZzc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=runbox.com; dkim=pass (2048-bit key) header.d=runbox.com header.i=@runbox.com header.b=HmCyku0b; arc=none smtp.client-ip=185.226.149.37 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=runbox.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=runbox.com header.i=@runbox.com header.b="HmCyku0b" Received: from mailtransmit03.runbox ([10.9.9.163] helo=aibo.runbox.com) by mailtransmit04.runbox.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.93) (envelope-from ) id 1vuT1C-00GgpC-Uz; Mon, 23 Feb 2026 11:18:22 +0100 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=runbox.com; s=selector2; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To :Message-Id:Date:Subject:Cc:To:From; bh=fIcCZ7m9f/bsnL6B1y6KWqhrBG/OU5qL3DBfDr8Qszo=; b=HmCyku0bTGFz/deJejW8nFFLse DIsbTXXuE+O3JPFbNg2fDEElwFry4/OA8aWLA68TnNWLlpTrZ+CAOcPfvh+6pAxrl2G1X8480kfmg f7Iqyltiocag9bzpOdKnn8odsQZhEEidDl0alu1CdbxT4db1QMfDJAR0+BBhpnF0HOoAYd97yYuo/ 39AbMcddikMo4kNM/5Ez5YENZfir4KcXB6WAbxT7h81yhS2ivIsia3DckDMHDsq44xE/xH1+drHjV 89nqn+8H7nIoCieSBk1kPk3EIwBqxoCBiBsCvhPXpJfyr3cXJqrvAa5pdkTlezdiOvIFYRqB8ks/1 qqDSNHEQ==; Received: from [10.9.9.73] (helo=submission02.runbox) by mailtransmit03.runbox with esmtp (Exim 4.86_2) (envelope-from ) id 1vuT1C-0001Su-KY; Mon, 23 Feb 2026 11:18:22 +0100 Received: by submission02.runbox with esmtpsa [Authenticated ID (1493616)] (TLS1.2:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.93) id 1vuT11-006AjD-PZ; Mon, 23 Feb 2026 11:18:11 +0100 From: david.laight.linux@gmail.com To: Willy Tarreau , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , linux-kernel@vger.kernel.org, Cheng Li Cc: David Laight Subject: [PATCH v3 next 04/17] selftests/nolibc: Improve reporting of vfprintf() errors Date: Mon, 23 Feb 2026 10:17:22 +0000 Message-Id: <20260223101735.2922-5-david.laight.linux@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260223101735.2922-1-david.laight.linux@gmail.com> References: <20260223101735.2922-1-david.laight.linux@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: David Laight Check the string matches before checking the returned length. Only print the string once when it matches. Allow for skipping tests that check non-standard behaviour. Since the 'return value' from snprintf() is really the output buffer there is no reason for the test cases to specify the numeric return value (the length of the extected output) as well as the expected output. The expected output needs to be the 'untruncated' output for tests that generate output that gets truncatedb because expect_vfprintf() uses a short buffer. This puts all the knowledge of any truncation to expect_vfprintf(). It also easier to change the maximum size, and saves counting the length of the expected string by hand when adding tests. Increase the size limit from 20 to 25 characters, changing the tests to match. This is needed to test octal conversions later on. Append a '+' to the printed output (after the final ") when the output is truncated. Additionally check that nothing beyond the end is written. The "width_trunc" test (#14) now fails because e90ce42e81381 ("tools/nolibc: implement width padding in printf()") doesn't correctly update the space in the buffer when adding pad characters. This will be addressed in a later patch. Also correctly return 1 (the number of errors) when strcmp() fails rather than the return value from strncmp() which is the signed difference between the mismatching characters. Signed-off-by: David Laight --- For v3: - Patch 9 in v2, patch 5 in v1.. - Increase the size limit to 25 in preparation for testing octal. - Change the way truncated fprintf() are handled. - Allow for tests being skipped. - Use a fixed value (0xa5) for the canary when detecting overwrites. tools/testing/selftests/nolibc/nolibc-test.c | 91 ++++++++++++++------ 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 0e8b3b9a86ef..029ed63e1ae4 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1660,33 +1660,70 @@ int run_stdlib(int min, int max) return ret; } -#define EXPECT_VFPRINTF(c, expected, fmt, ...) \ - ret += expect_vfprintf(llen, c, expected, fmt, ##__VA_ARGS__) +#define EXPECT_VFPRINTF(cond, expected, fmt, ...) \ + ret += expect_vfprintf(llen, cond, expected, fmt, ##__VA_ARGS__) -static int expect_vfprintf(int llen, int c, const char *expected, const char *fmt, ...) +#define VFPRINTF_LEN 25 + +static int expect_vfprintf(int llen, int cond, const char *expected, const char *fmt, ...) { - char buf[100]; + ssize_t written, expected_len; + char buf[VFPRINTF_LEN + 80]; + unsigned int cmp_len; va_list args; - ssize_t w; - int ret; + if (!cond) { + result(llen, SKIPPED); + return 0; + } + + /* Fill and terminate buffer to check for overlong/absent writes */ + memset(buf, 0xa5, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = 0; va_start(args, fmt); - /* Only allow writing 21 bytes, to test truncation */ - w = vsnprintf(buf, 21, fmt, args); + /* Limit the buffer length to test truncation */ + written = vsnprintf(buf, VFPRINTF_LEN + 1, fmt, args); va_end(args); - if (w != c) { - llen += printf(" written(%d) != %d", (int)w, c); + llen += printf(" \"%s\"", buf); + + /* If the expected output is long it will have been truncated. */ + expected_len = strlen(expected); + if (expected_len > VFPRINTF_LEN) { + /* Indicate truncated in test output */ + llen += printf("+"); + cmp_len = VFPRINTF_LEN; + } else { + cmp_len = expected_len; + } + + if (memcmp(expected, buf, cmp_len) || buf[cmp_len]) { + /* Copy and truncate until "%.*s" supported */ + memcpy(buf, expected, cmp_len); + buf[cmp_len] = 0; + llen += printf(" should be \"%s\"", buf); result(llen, FAIL); return 1; } - llen += printf(" \"%s\" = \"%s\"", expected, buf); - ret = strncmp(expected, buf, c); + if (written != expected_len) { + llen += printf(" written(%d) != %d", (int)written, (int)expected_len); + result(llen, FAIL); + return 1; + } - result(llen, ret ? FAIL : OK); - return ret; + /* Check for any overwrites after the actual data. */ + while (++cmp_len < sizeof(buf) - 1) { + if ((unsigned char)buf[cmp_len] != 0xa5) { + llen += printf(" overwrote buf[%d] with 0x%x", cmp_len, buf[cmp_len]); + result(llen, FAIL); + return 1; + } + } + + result(llen, OK); + return 0; } static int test_scanf(void) @@ -1807,21 +1844,21 @@ static int run_printf(int min, int max) * test numbers. */ switch (test + __LINE__ + 1) { - CASE_TEST(empty); EXPECT_VFPRINTF(0, "", ""); break; - CASE_TEST(simple); EXPECT_VFPRINTF(3, "foo", "foo"); break; - CASE_TEST(string); EXPECT_VFPRINTF(3, "foo", "%s", "foo"); break; - CASE_TEST(number); EXPECT_VFPRINTF(4, "1234", "%d", 1234); break; - CASE_TEST(negnumber); EXPECT_VFPRINTF(5, "-1234", "%d", -1234); break; - CASE_TEST(unsigned); EXPECT_VFPRINTF(5, "12345", "%u", 12345); break; + CASE_TEST(empty); EXPECT_VFPRINTF(1, "", ""); break; + CASE_TEST(simple); EXPECT_VFPRINTF(1, "foo", "foo"); break; + CASE_TEST(string); EXPECT_VFPRINTF(1, "foo", "%s", "foo"); break; + CASE_TEST(number); EXPECT_VFPRINTF(1, "1234", "%d", 1234); break; + CASE_TEST(negnumber); EXPECT_VFPRINTF(1, "-1234", "%d", -1234); break; + CASE_TEST(unsigned); EXPECT_VFPRINTF(1, "12345", "%u", 12345); break; CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break; CASE_TEST(hex); EXPECT_VFPRINTF(1, "f", "%x", 0xf); break; - CASE_TEST(pointer); EXPECT_VFPRINTF(3, "0x1", "%p", (void *) 0x1); break; - CASE_TEST(uintmax_t); EXPECT_VFPRINTF(20, "18446744073709551615", "%ju", 0xffffffffffffffffULL); break; - CASE_TEST(intmax_t); EXPECT_VFPRINTF(20, "-9223372036854775807", "%jd", 0x8000000000000001LL); break; - CASE_TEST(truncation); EXPECT_VFPRINTF(25, "01234567890123456789", "%s", "0123456789012345678901234"); break; - CASE_TEST(string_width); EXPECT_VFPRINTF(10, " 1", "%10s", "1"); break; - CASE_TEST(number_width); EXPECT_VFPRINTF(10, " 1", "%10d", 1); break; - CASE_TEST(width_trunc); EXPECT_VFPRINTF(25, " ", "%25d", 1); break; + CASE_TEST(pointer); EXPECT_VFPRINTF(1, "0x1", "%p", (void *) 0x1); break; + CASE_TEST(uintmax_t); EXPECT_VFPRINTF(1, "18446744073709551615", "%ju", 0xffffffffffffffffULL); break; + CASE_TEST(intmax_t); EXPECT_VFPRINTF(1, "-9223372036854775807", "%jd", 0x8000000000000001LL); break; + CASE_TEST(truncation); EXPECT_VFPRINTF(1, "012345678901234567890123456789", "%s", "012345678901234567890123456789"); break; + CASE_TEST(string_width); EXPECT_VFPRINTF(1, " 1", "%10s", "1"); break; + CASE_TEST(number_width); EXPECT_VFPRINTF(1, " 1", "%10d", 1); break; + CASE_TEST(width_trunc); EXPECT_VFPRINTF(1, " 1", "%30d", 1); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; CASE_TEST(strerror); EXPECT_ZR(1, test_strerror()); break; CASE_TEST(printf_error); EXPECT_ZR(1, test_printf_error()); break; -- 2.39.5