Subject: more POSIX 2008 cleanup: strnlen(), rindex()

From: Peter Eisentraut <[email-masked]>
Date: Sat, 3 Jan 2026 10:51:53 +0100

It has previously been established that POSIX 2008 is the baseline for 
PostgreSQL code (modulo Windows).  Looking through the POSIX 2008 
changes, I found a few more things we can clean up with respect to that.

The first patch removes the configure checks for strnlen(), since that 
is now required, and I see that all buildfarm members support.  There 
was some discussion in the commit messages that added these checks 
(e.g., commit 8a241792f96) that suggests it was once required, but I did 
not find any information about which platforms were affected then.  But 
that's 8 years ago now, so I think it might be obsolete.

The second patch replaces the single remaining use of rindex() with the 
equivalent strrchr().  rindex() has been removed from POSIX.

From 9f6fd1349ef9e726f6baf16777ca1658da8567b2 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email-masked]>
Date: Sat, 3 Jan 2026 10:11:19 +0100
Subject: [PATCH 1/2] strnlen() is now required

Remove all configure checks and workarounds for strnlen() missing.  It
is required by POSIX 2008.
---
 configure                  | 23 -----------------------
 configure.ac               |  3 +--
 meson.build                |  2 --
 src/include/pg_config.h.in |  7 -------
 src/include/port.h         |  4 ----
 src/port/meson.build       |  1 -
 src/port/strnlen.c         | 33 ---------------------------------
 7 files changed, 1 insertion(+), 72 deletions(-)
 delete mode 100644 src/port/strnlen.c

diff --git a/configure b/configure
index 78597c6229a..d34529b1de0 100755
--- a/configure
+++ b/configure
@@ -16079,16 +16079,6 @@ fi
 cat >>confdefs.h <<_ACEOF
 #define HAVE_DECL_STRLCPY $ac_have_decl
 _ACEOF
-ac_fn_c_check_decl "$LINENO" "strnlen" "ac_cv_have_decl_strnlen" "$ac_includes_default"
-if test "x$ac_cv_have_decl_strnlen" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_STRNLEN $ac_have_decl
-_ACEOF
 ac_fn_c_check_decl "$LINENO" "strsep" "ac_cv_have_decl_strsep" "$ac_includes_default"
 if test "x$ac_cv_have_decl_strsep" = xyes; then :
   ac_have_decl=1
@@ -16268,19 +16258,6 @@ esac
 
 fi
 
-ac_fn_c_check_func "$LINENO" "strnlen" "ac_cv_func_strnlen"
-if test "x$ac_cv_func_strnlen" = xyes; then :
-  $as_echo "#define HAVE_STRNLEN 1" >>confdefs.h
-
-else
-  case " $LIBOBJS " in
-  *" strnlen.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS strnlen.$ac_objext"
- ;;
-esac
-
-fi
-
 ac_fn_c_check_func "$LINENO" "strsep" "ac_cv_func_strsep"
 if test "x$ac_cv_func_strsep" = xyes; then :
   $as_echo "#define HAVE_STRSEP 1" >>confdefs.h
diff --git a/configure.ac b/configure.ac
index 2ccf410f94c..284a2a4c498 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1825,7 +1825,7 @@ AC_CHECK_DECLS(posix_fadvise, [], [], [#include <fcntl.h>])
 ]) # fi
 
 AC_CHECK_DECLS(fdatasync, [], [], [#include <unistd.h>])
-AC_CHECK_DECLS([strlcat, strlcpy, strnlen, strsep, timingsafe_bcmp])
+AC_CHECK_DECLS([strlcat, strlcpy, strsep, timingsafe_bcmp])
 
 # We can't use AC_CHECK_FUNCS to detect these functions, because it
 # won't handle deployment target restrictions on macOS
@@ -1846,7 +1846,6 @@ AC_REPLACE_FUNCS(m4_normalize([
 	mkdtemp
 	strlcat
 	strlcpy
-	strnlen
 	strsep
 	timingsafe_bcmp
 ]))
diff --git a/meson.build b/meson.build
index 467f7f005a6..8289187c182 100644
--- a/meson.build
+++ b/meson.build
@@ -2664,7 +2664,6 @@ decl_checks = [
   ['posix_fadvise', 'fcntl.h'],
   ['strlcat', 'string.h'],
   ['strlcpy', 'string.h'],
-  ['strnlen', 'string.h'],
   ['strsep',  'string.h'],
   ['timingsafe_bcmp',  'string.h'],
 ]
@@ -2912,7 +2911,6 @@ func_checks = [
   ['strerror_r', {'dependencies': [thread_dep]}],
   ['strlcat'],
   ['strlcpy'],
-  ['strnlen'],
   ['strsep'],
   ['strsignal'],
   ['sync_file_range'],
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index f0091b09cbe..54ee5ccabbe 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -111,10 +111,6 @@
    don't. */
 #undef HAVE_DECL_STRLCPY
 
-/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
-   don't. */
-#undef HAVE_DECL_STRNLEN
-
 /* Define to 1 if you have the declaration of `strsep', and to 0 if you don't.
    */
 #undef HAVE_DECL_STRSEP
@@ -401,9 +397,6 @@
 /* Define to 1 if you have the `strlcpy' function. */
 #undef HAVE_STRLCPY
 
-/* Define to 1 if you have the `strnlen' function. */
-#undef HAVE_STRNLEN
-
 /* Define to 1 if you have the `strsep' function. */
 #undef HAVE_STRSEP
 
diff --git a/src/include/port.h b/src/include/port.h
index 11b21098a39..e9e81cefef7 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -476,10 +476,6 @@ extern size_t strlcat(char *dst, const char *src, size_t siz);
 extern size_t strlcpy(char *dst, const char *src, size_t siz);
 #endif
 
-#if !HAVE_DECL_STRNLEN
-extern size_t strnlen(const char *str, size_t maxlen);
-#endif
-
 #if !HAVE_DECL_STRSEP
 extern char *strsep(char **stringp, const char *delim);
 #endif
diff --git a/src/port/meson.build b/src/port/meson.build
index c1ef6fd4821..28655142ebe 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -72,7 +72,6 @@ replace_funcs_neg = [
   ['mkdtemp'],
   ['strlcat'],
   ['strlcpy'],
-  ['strnlen'],
   ['strsep'],
   ['timingsafe_bcmp'],
 ]
diff --git a/src/port/strnlen.c b/src/port/strnlen.c
deleted file mode 100644
index 13f87377d21..00000000000
--- a/src/port/strnlen.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * strnlen.c
- *		Fallback implementation of strnlen().
- *
- *
- * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * IDENTIFICATION
- *	  src/port/strnlen.c
- *
- *-------------------------------------------------------------------------
- */
-
-#include "c.h"
-
-/*
- * Implementation of posix' strnlen for systems where it's not available.
- *
- * Returns the number of characters before a null-byte in the string pointed
- * to by str, unless there's no null-byte before maxlen. In the latter case
- * maxlen is returned.
- */
-size_t
-strnlen(const char *str, size_t maxlen)
-{
-	const char *p = str;
-
-	while (maxlen-- > 0 && *p)
-		p++;
-	return p - str;
-}

base-commit: 094b61ce3ebbb1258675cb9b4eca9198628e2177
-- 
2.52.0

From 936cc7cbb5981ea8be1a4c0c2c3c5bf37e69a8ad Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email-masked]>
Date: Sat, 3 Jan 2026 10:16:50 +0100
Subject: [PATCH 2/2] Remove use of rindex() function

rindex() has been removed from POSIX 2008.  Replace the one remaining
use with the equivalent and more standard strrchr().
---
 src/backend/jit/llvm/llvmjit.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index 49e76153f9a..8d009dd5cf7 100644
--- a/src/backend/jit/llvm/llvmjit.c
+++ b/src/backend/jit/llvm/llvmjit.c
@@ -1058,7 +1058,7 @@ llvm_split_symbol_name(const char *name, char **modname, char **funcname)
 		 * Symbol names cannot contain a ., therefore we can split based on
 		 * first and last occurrence of one.
 		 */
-		*funcname = rindex(name, '.');
+		*funcname = strrchr(name, '.');
 		(*funcname)++;			/* jump over . */
 
 		*modname = pnstrdup(name + strlen("pgextern."),
-- 
2.52.0

---

From: Jelte Fennema-Nio <[email-masked]>
Date: Sat, 3 Jan 2026 10:58:14 +0100

> changes, I found a few more things we can clean up with respect to that.

Both changes look sensible to me