From nobody Wed Apr 15 10:03:28 2026 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fwcD04h6Xz6ZdRV for ; Wed, 15 Apr 2026 10:03:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fwcD03nXXz3D6t for ; Wed, 15 Apr 2026 10:03:28 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1776247408; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Id1ZF1DTcFmzhFtvy0fQu8toe/TV+5ijcVNRWZVmW78=; b=X8xcJ7DW/GV6idQVW20iw+ToMvlofD1fm0RykJ0dWMvszAsaaa72dAGbAsZdQoKoJm+vwj stJg7wDXeeTJk92Qtcuxntuslshd5Kjte4U/w8AS1dYLJEQziWNOP2lW5wNtxepN6xPQIa rkq1ybQDAK9ll0WARLjCVDeqXkOSU0e6KD5h7LJYtbVtYsS7Z/vcQodk6xHvXjzzzcqTGk SiPLJYbnT0qR9FvIgduMI9G3knxxw/AOOXaM8P2qt6KvgOeX5rxzWtFxvtl1A4XH+UfuFz Xqu95s7MJND1c4mvrBZH0IbWCb+wWir9L95DwFCcuGCmZLZEudG7ntEtohOGog== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1776247408; a=rsa-sha256; cv=none; b=dLjY7k280FLkvP4O8DHCbd8HZRoA2m7lX8ta7SihAlnmK0vBol0Ssfww6K9Sy52uMjrHoU PkJTHvwsYlmh/8Q5TW9kGw47tp0ODg253SGkUtGGsIO3bUvFMPa8BbvRXq4dvHy2kwtrfj HvnaXY41+4DNmElrsucQkxhNVdqpZ5Tor2d7kvN4ZQhI1ID+Kma96oL8W2CpKqIHQnFEIu MnVYfRxkM8N/nS6raaWriIWkUWF+plWalojQKjBmc8+lRuuh2gQQBTRpuOBLK9qUh7MDtY +H4B25AA1d58OpRHH9dwimKIQIeOa9NGtJSejTtB5uOV5ibB4EGxk8R86mWRbQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1776247408; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Id1ZF1DTcFmzhFtvy0fQu8toe/TV+5ijcVNRWZVmW78=; b=W2k8ChECw4yrv3QDihXfWDP7gDqOYkA7uFu1TlKpusAWmwrdl3w28YsLyPTnOxyPZuKf2g aiSQbEi9TU9QmlAaOMplH/90cBC6mXjr/On77HqusEYCYIftPhRLtTfpOEmb+jGPyekh5+ LEegiRvqSVL5NgsiFr5oINlsRXClOTsjdCZi1e3sT1WenpdJoOJn93DjS/G6h5eY6zKE4G 5pYDz5+odHDc7NeuQGV2qrbYckWmL/anDjhHV8kcM6//0cy8rvdV+zswKn+aODwcBLQiGT 3+M5h5XVRfLRfM0wD3hPcMVc0XAfhHEBc9PJuh1473yiqDKjRi3m37agx3yiZw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fwcD03KRxz1P2 for ; Wed, 15 Apr 2026 10:03:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 25cac by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 15 Apr 2026 10:03:28 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Robert Clausecker Subject: git: e4f02a72f7f6 - stable/15 - libc/tests/string: add a more comprehensive unit test for strrchr() List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: fuz X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: e4f02a72f7f6ef3a9965427679aec191e2ce34d9 Auto-Submitted: auto-generated Date: Wed, 15 Apr 2026 10:03:28 +0000 Message-Id: <69df6270.25cac.6f20d26c@gitrepo.freebsd.org> The branch stable/15 has been updated by fuz: URL: https://cgit.FreeBSD.org/src/commit/?id=e4f02a72f7f6ef3a9965427679aec191e2ce34d9 commit e4f02a72f7f6ef3a9965427679aec191e2ce34d9 Author: Robert Clausecker AuthorDate: 2026-03-22 21:39:42 +0000 Commit: Robert Clausecker CommitDate: 2026-04-15 10:03:07 +0000 libc/tests/string: add a more comprehensive unit test for strrchr() The unit tests are patterned after those for memrchr(). This catches the issue found in 293915. PR: 293915 Reviewed by: strajabot Reported by: safonov.paul@gmail.com MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D56037 (cherry picked from commit 8b5d77bbcbd98e684226950be1c779e108059d8d) --- lib/libc/tests/string/Makefile | 2 + lib/libc/tests/string/strrchr_test.c | 156 +++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) diff --git a/lib/libc/tests/string/Makefile b/lib/libc/tests/string/Makefile index a019939c30af..a4d23b2dcfe1 100644 --- a/lib/libc/tests/string/Makefile +++ b/lib/libc/tests/string/Makefile @@ -20,6 +20,7 @@ ATF_TESTS_C+= strcmp2_test ATF_TESTS_C+= strcspn_test ATF_TESTS_C+= strerror2_test ATF_TESTS_C+= strlcpy_test +ATF_TESTS_C+= strrchr2_test ATF_TESTS_C+= strspn_test ATF_TESTS_C+= strverscmp_test ATF_TESTS_C+= strxfrm_test @@ -49,6 +50,7 @@ NETBSD_ATF_TESTS_C+= swab_test SRCS.memset2_test= memset_test.c SRCS.strcmp2_test= strcmp_test.c SRCS.strerror2_test= strerror_test.c +SRCS.strrchr2_test= strrchr_test.c .include "../Makefile.netbsd-tests" diff --git a/lib/libc/tests/string/strrchr_test.c b/lib/libc/tests/string/strrchr_test.c new file mode 100644 index 000000000000..1c3d912ec3f8 --- /dev/null +++ b/lib/libc/tests/string/strrchr_test.c @@ -0,0 +1,156 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023, 2026 Robert Clausecker + * + * Adapted from memrchr_test.c. + */ + +#include + +#include +#include +#include +#include + +#include + +static char *(*strrchr_fn)(const char *, int); + +/* + * Check that when looking for the character NUL, we find the + * string terminator, and not some NUL character after it. + */ +ATF_TC_WITHOUT_HEAD(nul); +ATF_TC_BODY(nul, tc) +{ + size_t i, j, k; + char buf[1+15+64]; /* offset [0+15] + 64 buffer bytes + sentinels */ + + buf[0] = '\0'; + memset(buf + 1, '-', sizeof(buf) - 1); + + for (i = 0; i < 16; i++) + for (j = 0; j < 64; j++) + for (k = j; k < 64; k++) { + buf[i + j + 1] = '\0'; + buf[i + k + 1] = '\0'; + ATF_CHECK_EQ(strrchr_fn(buf + i + 1, '\0'), buf + i + j + 1); + buf[i + j + 1] = '-'; + buf[i + k + 1] = '-'; + } +} + +/* + * Check that if the character 'X' does not occur in the string + * (but occurs before and after it), we correctly return NULL. + */ +ATF_TC_WITHOUT_HEAD(not_found); +ATF_TC_BODY(not_found, tc) +{ + size_t i, j; + char buf[1+15+64+2]; /* offset [0..15] + 64 buffer bytes + sentinels */ + + buf[0] = 'X'; + memset(buf + 1, '-', sizeof(buf) - 1); + + for (i = 0; i < 16; i++) + for (j = 0; j < 64; j++) { + buf[i + j + 1] = '\0'; + buf[i + j + 2] = 'X'; + ATF_CHECK_EQ(strrchr_fn(buf + i + 1, 'X'), NULL); + buf[i + j + 1] = '-'; + buf[i + j + 2] = '-'; + } +} + +static void +do_found_test(char buf[], size_t first, size_t second) +{ + /* invariant: first <= second */ + + buf[first] = 'X'; + buf[second] = 'X'; + ATF_CHECK_EQ(strrchr_fn(buf, 'X'), buf + second); + buf[first] = '-'; + buf[second] = '-'; +} + +/* + * Check that if the character 'X' occurs in the string multiple + * times (i. e. twice), its last encounter is returned. + */ +ATF_TC_WITHOUT_HEAD(found); +ATF_TC_BODY(found, tc) +{ + size_t i, j, k, l; + char buf[1+15+64+2]; + + buf[0] = 'X'; + memset(buf + 1, '-', sizeof(buf) - 1); + + for (i = 0; i < 16; i++) + for (j = 0; j < 64; j++) + for (k = 0; k < j; k++) + for (l = 0; l <= k; l++) { + buf[i + j + 1] = '\0'; + buf[i + j + 2] = 'X'; + do_found_test(buf + i + 1, l, k); + buf[i + j + 1] = '-'; + buf[i + j + 2] = '-'; + } +} + +static void +do_values_test(char buf[], size_t len, size_t i, int c) +{ + /* sentinels */ + buf[-1] = c; + buf[len] = '\0'; + buf[len + 1] = 'c'; + + /* fill the string with some other character, but not with NUL */ + memset(buf, c == UCHAR_MAX ? c - 1 : c + 1, len); + + if (i < len) { + buf[i] = c; + ATF_CHECK_EQ(strrchr_fn(buf, c), buf + i); + } else + ATF_CHECK_EQ(strrchr_fn(buf, c), c == 0 ? buf + len : NULL); +} + +/* + * Check that the character is found regardless of its value. + * This catches arithmetic (overflow) errors in incorrect SWAR + * implementations of byte-parallel character matching. + */ +ATF_TC_WITHOUT_HEAD(values); +ATF_TC_BODY(values, tc) +{ + size_t i, j, k; + int c; + char buf[1+15+64+2]; + + for (i = 0; i < 16; i++) + for (j = 0; j < 64; j++) + for (k = 0; k <= j; k++) + for (c = 0; c <= UCHAR_MAX; c++) + do_values_test(buf + i + 1, j, k, c); +} + +ATF_TP_ADD_TCS(tp) +{ + void *dl_handle; + + dl_handle = dlopen(NULL, RTLD_LAZY); + strrchr_fn = dlsym(dl_handle, "test_strrchr"); + if (strrchr_fn == NULL) + strrchr_fn = strrchr; + + ATF_TP_ADD_TC(tp, nul); + ATF_TP_ADD_TC(tp, not_found); + ATF_TP_ADD_TC(tp, found); + ATF_TP_ADD_TC(tp, values); + + return (atf_no_error()); +}