[libc-commits] [libc] [libc] Add Annex K strnlen_s function (PR #186112)

Victor Campos via libc-commits libc-commits at lists.llvm.org
Tue Mar 17 09:25:31 PDT 2026


https://github.com/vhscampos updated https://github.com/llvm/llvm-project/pull/186112

>From 91882b2faaf236585df8d24eb67580ad27c22d0c Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Fri, 6 Mar 2026 13:44:38 +0000
Subject: [PATCH 1/2] [libc] Add Annex K strnlen_s function

This patch adds the `strnlen_s` function from Annex K.

In order to reduce duplication between `strnlen` and `strnlen_s`, the
common logic has been extracted to a new internal function which both
now call.

In addition to the function definition, the patch adds a unit test and a
fuzzing test.
---
 libc/config/baremetal/aarch64/entrypoints.txt |  1 +
 libc/config/baremetal/arm/entrypoints.txt     |  1 +
 libc/config/darwin/aarch64/entrypoints.txt    |  1 +
 libc/config/linux/aarch64/entrypoints.txt     |  1 +
 libc/config/linux/arm/entrypoints.txt         |  1 +
 libc/config/windows/entrypoints.txt           |  1 +
 libc/fuzzing/string/CMakeLists.txt            |  8 +++
 libc/fuzzing/string/strnlen_s_fuzz.cpp        | 58 +++++++++++++++++++
 libc/include/CMakeLists.txt                   |  1 +
 libc/include/string.yaml                      | 10 ++++
 libc/src/string/CMakeLists.txt                | 11 ++++
 libc/src/string/string_utils.h                |  6 ++
 libc/src/string/strnlen.cpp                   |  4 +-
 libc/src/string/strnlen_s.cpp                 | 16 +++++
 libc/src/string/strnlen_s.h                   | 19 ++++++
 libc/test/src/string/CMakeLists.txt           | 10 ++++
 libc/test/src/string/strnlen_s_test.cpp       | 57 ++++++++++++++++++
 libc/utils/docgen/string.yaml                 |  3 +
 18 files changed, 206 insertions(+), 3 deletions(-)
 create mode 100644 libc/fuzzing/string/strnlen_s_fuzz.cpp
 create mode 100644 libc/src/string/strnlen_s.cpp
 create mode 100644 libc/src/string/strnlen_s.h
 create mode 100644 libc/test/src/string/strnlen_s_test.cpp

diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index c4e040e537cd0..da4b99b53d8d2 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -87,6 +87,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncpy
     libc.src.string.strndup
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strsep
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 7acaca15d39ae..7480560407db1 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -87,6 +87,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncpy
     libc.src.string.strndup
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strsep
diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt
index 2d26763e29d03..a7e3f9d4a5af8 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -46,6 +46,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncmp
     libc.src.string.strncpy
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strspn
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 380c91e1ac396..0272fb80ccd0c 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -79,6 +79,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncpy
     libc.src.string.strndup
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strsep
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 8611082f87003..dd1f48bf2bb5d 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -49,6 +49,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncmp
     libc.src.string.strncpy
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strsep
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 02b56ab01081b..7739773cafec1 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -43,6 +43,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncmp
     libc.src.string.strncpy
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strspn
diff --git a/libc/fuzzing/string/CMakeLists.txt b/libc/fuzzing/string/CMakeLists.txt
index 0918e92552ea7..92880d7e37407 100644
--- a/libc/fuzzing/string/CMakeLists.txt
+++ b/libc/fuzzing/string/CMakeLists.txt
@@ -48,3 +48,11 @@ add_libc_fuzzer(
   DEPENDS
     libc.src.string.strlen
 )
+
+add_libc_fuzzer(
+  strnlen_s_fuzz
+  SRCS
+    strnlen_s_fuzz.cpp
+  DEPENDS
+    libc.src.string.strnlen_s
+)
diff --git a/libc/fuzzing/string/strnlen_s_fuzz.cpp b/libc/fuzzing/string/strnlen_s_fuzz.cpp
new file mode 100644
index 0000000000000..93176ae871a65
--- /dev/null
+++ b/libc/fuzzing/string/strnlen_s_fuzz.cpp
@@ -0,0 +1,58 @@
+//===-- strnlen_s_fuzz.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// Fuzzing test for llvm-libc strnlen_s implementation.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strnlen_s.h"
+#define __STDC_WANT_LIB_EXT1__ 1
+#include <stdint.h>
+#include <string.h>
+
+extern "C" size_t LLVMFuzzerMutate(uint8_t *data, size_t size, size_t max_size);
+extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size,
+                                          size_t max_size,
+                                          unsigned int /*seed*/) {
+  // The buffer is constructed as follows:
+  // data = max_len (size_t) + null-terminated string
+  if (max_size < sizeof(size_t) + 1)
+    return size;
+
+  do {
+    size = LLVMFuzzerMutate(data, size, max_size);
+  } while (size < sizeof(size_t) + 1);
+
+  data[size - 1] = '\0';
+  return size;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  if (size < sizeof(size_t) + 1)
+    return 0;
+
+  size_t max_len;
+  ::memcpy(&max_len, data, sizeof(size_t));
+  data += sizeof(size_t);
+
+  // If Annex K is not available in the system's C library, we compare against
+  // strnlen instead. We can assume this is valid because in the case where the
+  // input string is not null, the two functions must have identical semantics.
+#ifdef __STDC_LIB_EXT1__
+  size_t ref = ::strnlen_s(reinterpret_cast<const char *>(data), max_len);
+#else
+  size_t ref = ::strnlen(reinterpret_cast<const char *>(data), max_len);
+#endif
+  size_t impl =
+      LIBC_NAMESPACE::strnlen_s(reinterpret_cast<const char *>(data), max_len);
+
+  if (ref != impl)
+    __builtin_trap();
+
+  return 0;
+}
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index b2ebd035872aa..b1c437059d6be 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -252,6 +252,7 @@ add_header_macro(
   string.h
   DEPENDS
     .llvm_libc_common_h
+    .llvm-libc-macros.annex_k_macros
     .llvm-libc-macros.null_macro
     .llvm-libc-types.size_t
 )
diff --git a/libc/include/string.yaml b/libc/include/string.yaml
index 22010f4afa812..b52f2bb1a5933 100644
--- a/libc/include/string.yaml
+++ b/libc/include/string.yaml
@@ -4,6 +4,8 @@ standards:
 macros:
   - macro_name: "NULL"
     macro_header: null-macro.h
+  - macro_name: LIBC_HAS_ANNEX_K
+    macro_header: annex-k-macros.h
 types:
   - type_name: locale_t
   - type_name: size_t
@@ -249,6 +251,14 @@ functions:
     arguments:
       - type: const char *
       - type: size_t
+  - name: strnlen_s
+    standards:
+      - stdc
+    return_type: size_t
+    arguments:
+      - type: const char *
+      - type: size_t
+    guard: LIBC_HAS_ANNEX_K
   - name: strpbrk
     standards:
       - stdc
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index a640e1d2cc774..2a38c6509605e 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -302,6 +302,17 @@ add_entrypoint_object(
     .string_utils
 )
 
+add_entrypoint_object(
+  strnlen_s
+  SRCS
+    strnlen_s.cpp
+  HDRS
+    strnlen_s.h
+  DEPENDS
+    libc.hdr.types.size_t
+    .string_utils
+)
+
 add_entrypoint_object(
   strpbrk
   SRCS
diff --git a/libc/src/string/string_utils.h b/libc/src/string/string_utils.h
index b0144e01a9006..8c8879b4886e8 100644
--- a/libc/src/string/string_utils.h
+++ b/libc/src/string/string_utils.h
@@ -124,6 +124,12 @@ LIBC_INLINE void *find_first_character(const unsigned char *src,
   return find_first_character_impl(src, ch, max_strlen);
 }
 
+LIBC_INLINE size_t strnlen(const char *s, size_t max_len) {
+  const void *temp = internal::find_first_character(
+      reinterpret_cast<const unsigned char *>(s), '\0', max_len);
+  return temp ? reinterpret_cast<const char *>(temp) - s : max_len;
+}
+
 } // namespace internal
 } // namespace LIBC_NAMESPACE_DECL
 
diff --git a/libc/src/string/strnlen.cpp b/libc/src/string/strnlen.cpp
index 26fcd5a04c0d7..6bfbb86a5014e 100644
--- a/libc/src/string/strnlen.cpp
+++ b/libc/src/string/strnlen.cpp
@@ -16,9 +16,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(size_t, strnlen, (const char *src, size_t n)) {
-  const void *temp = internal::find_first_character(
-      reinterpret_cast<const unsigned char *>(src), '\0', n);
-  return temp ? reinterpret_cast<const char *>(temp) - src : n;
+  return internal::strnlen(src, n);
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/string/strnlen_s.cpp b/libc/src/string/strnlen_s.cpp
new file mode 100644
index 0000000000000..c76591d30d70b
--- /dev/null
+++ b/libc/src/string/strnlen_s.cpp
@@ -0,0 +1,16 @@
+//===-- Implementation header for strnlen_s ----------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strnlen_s.h"
+#include "src/string/string_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+LLVM_LIBC_FUNCTION(size_t, strnlen_s, (const char *s, size_t n)) {
+  return (s != 0) ? internal::strnlen(s, n) : 0;
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/string/strnlen_s.h b/libc/src/string/strnlen_s.h
new file mode 100644
index 0000000000000..89bbbd53b0494
--- /dev/null
+++ b/libc/src/string/strnlen_s.h
@@ -0,0 +1,19 @@
+//===-- Implementation header for strnlen_s ----------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STRING_STRNLEN_S_H
+#define LLVM_LIBC_SRC_STRING_STRNLEN_S_H
+
+#include "hdr/types/size_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+size_t strnlen_s(const char *src, size_t n);
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STRING_STRNLEN_S_H
diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt
index ced60750a45c7..17927ea93ed1e 100644
--- a/libc/test/src/string/CMakeLists.txt
+++ b/libc/test/src/string/CMakeLists.txt
@@ -274,6 +274,16 @@ add_libc_test(
     libc.src.string.strnlen
 )
 
+add_libc_test(
+  strnlen_s_test
+  SUITE
+    libc-string-tests
+  SRCS
+    strnlen_s_test.cpp
+  DEPENDS
+    libc.src.string.strnlen_s
+)
+
 add_libc_test(
   strpbrk_test
   SUITE
diff --git a/libc/test/src/string/strnlen_s_test.cpp b/libc/test/src/string/strnlen_s_test.cpp
new file mode 100644
index 0000000000000..4749a544c8fb5
--- /dev/null
+++ b/libc/test/src/string/strnlen_s_test.cpp
@@ -0,0 +1,57 @@
+//===-- Unittests for strnlen_s -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strnlen_s.h"
+#include "test/UnitTest/Test.h"
+#include <stddef.h>
+
+TEST(LlvmLibcStrNLenSTest, NullPointerInput) {
+  const char *str = nullptr;
+  // If the string input is a null pointer, it should return 0 regardless of
+  // the max len arg value.
+  ASSERT_EQ(static_cast<size_t>(0), LIBC_NAMESPACE::strnlen_s(str, 0));
+  ASSERT_EQ(static_cast<size_t>(0), LIBC_NAMESPACE::strnlen_s(str, 1));
+}
+
+// The semantics when the string input is not null are the same as strnlen. The
+// following tests are copied from the latter's tests.
+
+TEST(LlvmLibcStrNLenSTest, EmptyString) {
+  const char *empty = "";
+  ASSERT_EQ(static_cast<size_t>(0), LIBC_NAMESPACE::strnlen_s(empty, 0));
+  // If N is greater than string length, this should still return 0.
+  ASSERT_EQ(static_cast<size_t>(0), LIBC_NAMESPACE::strnlen_s(empty, 1));
+}
+
+TEST(LlvmLibcStrNLenSTest, OneCharacterString) {
+  const char *single = "X";
+  ASSERT_EQ(static_cast<size_t>(1), LIBC_NAMESPACE::strnlen_s(single, 1));
+  // If N is zero, this should return 0.
+  ASSERT_EQ(static_cast<size_t>(0), LIBC_NAMESPACE::strnlen_s(single, 0));
+  // If N is greater than string length, this should still return 1.
+  ASSERT_EQ(static_cast<size_t>(1), LIBC_NAMESPACE::strnlen_s(single, 2));
+}
+
+TEST(LlvmLibcStrNLenSTest, ManyCharacterString) {
+  const char *many = "123456789";
+  ASSERT_EQ(static_cast<size_t>(9), LIBC_NAMESPACE::strnlen_s(many, 9));
+  // If N is smaller than the string length, it should return N.
+  ASSERT_EQ(static_cast<size_t>(3), LIBC_NAMESPACE::strnlen_s(many, 3));
+  // If N is zero, this should return 0.
+  ASSERT_EQ(static_cast<size_t>(0), LIBC_NAMESPACE::strnlen_s(many, 0));
+  // If N is greater than the string length, this should still return 9.
+  ASSERT_EQ(static_cast<size_t>(9), LIBC_NAMESPACE::strnlen_s(many, 42));
+}
+
+TEST(LlvmLibcStrNLenSTest, CharactersAfterNullTerminatorShouldNotBeIncluded) {
+  const char str[5] = {'a', 'b', 'c', '\0', 'd'};
+  ASSERT_EQ(static_cast<size_t>(3), LIBC_NAMESPACE::strnlen_s(str, 3));
+  // This should only read up to the null terminator.
+  ASSERT_EQ(static_cast<size_t>(3), LIBC_NAMESPACE::strnlen_s(str, 4));
+  ASSERT_EQ(static_cast<size_t>(3), LIBC_NAMESPACE::strnlen_s(str, 5));
+}
diff --git a/libc/utils/docgen/string.yaml b/libc/utils/docgen/string.yaml
index d703a8e3593e1..94a6756bed8c0 100644
--- a/libc/utils/docgen/string.yaml
+++ b/libc/utils/docgen/string.yaml
@@ -66,6 +66,9 @@ functions:
   strndup:
     c-definition: 7.26.2.7
     in-latest-posix: ''
+  strnlen_s:
+    c-definition: K.3.7.4.4
+    in-latest-posix: ''
   strpbrk:
     c-definition: 7.26.5.5
     in-latest-posix: ''

>From 5e8726e7ea819d01c42b179b6b93d8b308a9e44a Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Tue, 17 Mar 2026 14:14:48 +0000
Subject: [PATCH 2/2] Fix issues

---
 libc/config/baremetal/riscv/entrypoints.txt | 1 +
 libc/config/darwin/x86_64/entrypoints.txt   | 1 +
 libc/config/gpu/amdgpu/entrypoints.txt      | 1 +
 libc/config/gpu/nvptx/entrypoints.txt       | 1 +
 libc/config/gpu/spirv/entrypoints.txt       | 1 +
 libc/config/linux/riscv/entrypoints.txt     | 1 +
 libc/config/linux/x86_64/entrypoints.txt    | 1 +
 libc/fuzzing/string/strnlen_s_fuzz.cpp      | 3 ++-
 libc/src/string/CMakeLists.txt              | 2 ++
 libc/src/string/strnlen_s.cpp               | 5 +++++
 libc/src/string/strnlen_s.h                 | 2 ++
 11 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index fc6201b44149f..89d0fdbbae1e1 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -87,6 +87,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncpy
     libc.src.string.strndup
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strsep
diff --git a/libc/config/darwin/x86_64/entrypoints.txt b/libc/config/darwin/x86_64/entrypoints.txt
index b0c247464c850..75f10fa49cae4 100644
--- a/libc/config/darwin/x86_64/entrypoints.txt
+++ b/libc/config/darwin/x86_64/entrypoints.txt
@@ -45,6 +45,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncmp
     libc.src.string.strncpy
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strspn
diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt
index 98c27d300ad9d..aa18658236066 100644
--- a/libc/config/gpu/amdgpu/entrypoints.txt
+++ b/libc/config/gpu/amdgpu/entrypoints.txt
@@ -65,6 +65,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncpy
     libc.src.string.strndup
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strsep
diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt
index 532fcda9ab3be..66a3eeb13c9b9 100644
--- a/libc/config/gpu/nvptx/entrypoints.txt
+++ b/libc/config/gpu/nvptx/entrypoints.txt
@@ -65,6 +65,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncpy
     libc.src.string.strndup
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strsep
diff --git a/libc/config/gpu/spirv/entrypoints.txt b/libc/config/gpu/spirv/entrypoints.txt
index 5c3c2c7e4303a..11edc358339b7 100644
--- a/libc/config/gpu/spirv/entrypoints.txt
+++ b/libc/config/gpu/spirv/entrypoints.txt
@@ -62,6 +62,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncpy
     libc.src.string.strndup
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strsep
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index ddb24c3eea178..01f5a21409a06 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -79,6 +79,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncpy
     libc.src.string.strndup
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strsep
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 9102de9bf0417..c4a9875fdc05b 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -81,6 +81,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strncpy
     libc.src.string.strndup
     libc.src.string.strnlen
+    libc.src.string.strnlen_s
     libc.src.string.strpbrk
     libc.src.string.strrchr
     libc.src.string.strsep
diff --git a/libc/fuzzing/string/strnlen_s_fuzz.cpp b/libc/fuzzing/string/strnlen_s_fuzz.cpp
index 93176ae871a65..741011cf44f6a 100644
--- a/libc/fuzzing/string/strnlen_s_fuzz.cpp
+++ b/libc/fuzzing/string/strnlen_s_fuzz.cpp
@@ -10,8 +10,9 @@
 ///
 //===----------------------------------------------------------------------===//
 
-#include "src/string/strnlen_s.h"
 #define __STDC_WANT_LIB_EXT1__ 1
+
+#include "src/string/strnlen_s.h"
 #include <stdint.h>
 #include <string.h>
 
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index 2a38c6509605e..e28fe7af8cf25 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -311,6 +311,8 @@ add_entrypoint_object(
   DEPENDS
     libc.hdr.types.size_t
     .string_utils
+    libc.src.__support.common
+    libc.src.__support.macros.config
 )
 
 add_entrypoint_object(
diff --git a/libc/src/string/strnlen_s.cpp b/libc/src/string/strnlen_s.cpp
index c76591d30d70b..862b1ca4d0fc0 100644
--- a/libc/src/string/strnlen_s.cpp
+++ b/libc/src/string/strnlen_s.cpp
@@ -7,10 +7,15 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/string/strnlen_s.h"
+#include "hdr/types/size_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
 #include "src/string/string_utils.h"
 
 namespace LIBC_NAMESPACE_DECL {
+
 LLVM_LIBC_FUNCTION(size_t, strnlen_s, (const char *s, size_t n)) {
   return (s != 0) ? internal::strnlen(s, n) : 0;
 }
+
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/string/strnlen_s.h b/libc/src/string/strnlen_s.h
index 89bbbd53b0494..2e42d37f49415 100644
--- a/libc/src/string/strnlen_s.h
+++ b/libc/src/string/strnlen_s.h
@@ -13,7 +13,9 @@
 #include "src/__support/macros/config.h"
 
 namespace LIBC_NAMESPACE_DECL {
+
 size_t strnlen_s(const char *src, size_t n);
+
 } // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC_STRING_STRNLEN_S_H



More information about the libc-commits mailing list