python / python/cpython

Musl libc strftime for format strings ending in %

Open
#127,527 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

extension-modules OS-unsupported type-bug
Dominant language
Python
Stars
77.2k
Forks
35.9k
PR merge metrics
PR metrics pending

Description

In glibc if the format string ends in %, strftime and wcsftime will turn it into a %. In musl libc, if the format string ends in %, both wcsftime and strftime return 0 with errno 0 and leave random stuff in the buffer. There's no way for us to distinguish between this and "out of space" without looking at the format string. The following 7 character patch would fix musl to behave the same as glibc:

--- a/src/time/strftime.c
+++ b/src/time/strftime.c
@@ -225,7 +225,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char
*restrict f, const st
 			s[l] = 0;
 			return l;
		}
-		if (*f != '%') {
+		if (*f != '%' || !f[1]) {
 			s[l++] = *f;
 			continue;
 		}

but it sounds like musl may be against applying this patch because it is their position that the behavior is undefined? See this thread:
https://www.openwall.com/lists/musl/2022/12/19/3

So in this case, we repeatedly get format_string returning 0 and end up here:
https://github.com/python/cpython/blob/main/Modules/timemodule.c?plain=1#L844
Then if HAVE_WCSFTIME we call PyUnicode_FromWideChar(*outbuf, 0) which notices we're making an empty string and returns here:
https://github.com/python/cpython/blob/main/Objects/unicodeobject.c?plain=1#L2004-L2005
On the other hand, if !HAVE_WCSFTIME we call PyUnicode_DecodeLocaleAndSize which checks if str[len] != '\0' and raises ValueError("Embedded null byte") here:
https://github.com/python/cpython/blob/main/Objects/unicodeobject.c?plain=1#L4004

So what to do? Well for one thing, it seems to me that we can tell whether format_time is trying to return an empty string by checking if the string ends in a null byte as it should e.g., *outbuf[buflen] == 0. This can allow us to be a bit more conservative in time_strftime1.

Linked PRs
  • gh-127528

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Modules/timemodule.c, especially time_strftime1 and its format_time handling, then compare the behavior described for src/time/strftime.c in musl. Reproduce a trailing-% case through time.strftime and inspect the linked PR gh-127528. Done means the platform-dependent result is handled consistently without treating a non-empty buffer as an empty string.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, python
Domain
operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.