Skip to content

Conversation

@mleleszi
Copy link
Contributor

This patch fixes a bug in strftime's return value when the formatted output exactly fills the buffer, not including the null terminator. The previous check failed to account for the null terminator in this case, incorrectly returning the written count instead of 0.

@mleleszi mleleszi marked this pull request as ready for review October 30, 2025 12:27
@llvmbot llvmbot added the libc label Oct 30, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 30, 2025

@llvm/pr-subscribers-libc

Author: Marcell Leleszi (mleleszi)

Changes

This patch fixes a bug in strftime's return value when the formatted output exactly fills the buffer, not including the null terminator. The previous check failed to account for the null terminator in this case, incorrectly returning the written count instead of 0.


Full diff: https://github.com/llvm/llvm-project/pull/165711.diff

3 Files Affected:

  • (modified) libc/src/time/strftime.cpp (+1-1)
  • (modified) libc/src/time/strftime_l.cpp (+1-1)
  • (modified) libc/test/src/time/strftime_test.cpp (+20)
diff --git a/libc/src/time/strftime.cpp b/libc/src/time/strftime.cpp
index f36091bc9736e..89b7d9bb7c1b9 100644
--- a/libc/src/time/strftime.cpp
+++ b/libc/src/time/strftime.cpp
@@ -26,7 +26,7 @@ LLVM_LIBC_FUNCTION(size_t, strftime,
   int ret = strftime_core::strftime_main(&writer, format, timeptr);
   if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
     wb.buff[wb.buff_cur] = '\0';
-  return (ret < 0 || static_cast<size_t>(ret) > buffsz) ? 0 : ret;
+  return (ret < 0 || static_cast<size_t>(ret) >= buffsz) ? 0 : ret;
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/strftime_l.cpp b/libc/src/time/strftime_l.cpp
index 201b85da39ee2..409f8683b7289 100644
--- a/libc/src/time/strftime_l.cpp
+++ b/libc/src/time/strftime_l.cpp
@@ -29,7 +29,7 @@ LLVM_LIBC_FUNCTION(size_t, strftime_l,
   int ret = strftime_core::strftime_main(&writer, format, timeptr);
   if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
     wb.buff[wb.buff_cur] = '\0';
-  return (ret < 0 || static_cast<size_t>(ret) > buffsz) ? 0 : ret;
+  return (ret < 0 || static_cast<size_t>(ret) >= buffsz) ? 0 : ret;
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/time/strftime_test.cpp b/libc/test/src/time/strftime_test.cpp
index cac7560b2b945..38176f77804d5 100644
--- a/libc/test/src/time/strftime_test.cpp
+++ b/libc/test/src/time/strftime_test.cpp
@@ -2326,3 +2326,23 @@ TEST(LlvmLibcStrftimeTest, TimeFormatFullDateTime) {
 //    size_t written = 0;
 //    SimplePaddedNum spn;
 //  }
+
+TEST(LlvmLibcStrftimeTest, BufferTooSmall) {
+  struct tm time;
+  char buffer[1];
+
+  time.tm_year = get_adjusted_year(2025);
+  time.tm_mon = 10;
+  time.tm_mday = 24;
+
+  size_t written =
+      LIBC_NAMESPACE::strftime(buffer, sizeof(buffer), "%F", &time);
+  EXPECT_EQ(written, size_t{0});
+
+  char buffer2[10];
+
+  // The string "2025-11-24" is 10 chars,
+  // so strftime needs 10 + 1 bytes to write the string and the null terminator.
+  written = LIBC_NAMESPACE::strftime(buffer, sizeof(buffer2), "%F", &time);
+  EXPECT_EQ(written, size_t{0});
+}

@mleleszi
Copy link
Contributor Author

@michaelrj-google Can you please take a look?

Copy link
Contributor

@michaelrj-google michaelrj-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the cleanup!

@mleleszi
Copy link
Contributor Author

Can you merge please? I don't have access yet

@michaelrj-google michaelrj-google merged commit 784b74c into llvm:main Oct 30, 2025
24 checks passed
michaelrj-google added a commit to michaelrj-google/llvm-project that referenced this pull request Oct 30, 2025
A typo in llvm#165711 caused sanitizer failures (the small buffer was used
for the larger test). Renamed the variables to avoid the mistake in
future.
michaelrj-google added a commit that referenced this pull request Oct 30, 2025
A typo in #165711 caused sanitizer failures (the small buffer was used
for the larger test). Renamed the variables to avoid the mistake in
future.
luciechoi pushed a commit to luciechoi/llvm-project that referenced this pull request Nov 1, 2025
This patch fixes a bug in strftime's return value when the formatted
output exactly fills the buffer, not including the null terminator. The
previous check failed to account for the null terminator in this case,
incorrectly returning the written count instead of 0.
luciechoi pushed a commit to luciechoi/llvm-project that referenced this pull request Nov 1, 2025
A typo in llvm#165711 caused sanitizer failures (the small buffer was used
for the larger test). Renamed the variables to avoid the mistake in
future.
DEBADRIBASAK pushed a commit to DEBADRIBASAK/llvm-project that referenced this pull request Nov 3, 2025
This patch fixes a bug in strftime's return value when the formatted
output exactly fills the buffer, not including the null terminator. The
previous check failed to account for the null terminator in this case,
incorrectly returning the written count instead of 0.
DEBADRIBASAK pushed a commit to DEBADRIBASAK/llvm-project that referenced this pull request Nov 3, 2025
A typo in llvm#165711 caused sanitizer failures (the small buffer was used
for the larger test). Renamed the variables to avoid the mistake in
future.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants