Bug 2392416

Summary: glibc: sscanf parsing of %XXXc is not being returned as read
Product: [Fedora] Fedora Reporter: Zdenek Kabelac <zkabelac>
Component: glibcAssignee: Florian Weimer <fweimer>
Status: CLOSED NOTABUG QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: high Docs Contact:
Priority: unspecified    
Version: rawhideCC: agk, arjun, codonell, dj, fberat, fweimer, jlaw, josmyers, mcermak, mcoufal, mfabian, pfrankli, sipoyare, skolosov, suraj.ghimire7
Target Milestone: ---   
Target Release: ---   
Hardware: Unspecified   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2025-11-28 15:52:13 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Zdenek Kabelac 2025-09-01 15:45:08 UTC
Our lvm2 project dmstats tool started to fail after upgrade to recent glibc version in rawhide:   glibc 2.42.9000-3.fc44.x86_64


Here is a simple reproducer:

---

include <stdio.h>

int main(void)
{
       int x1, x2, x3, x4, r;
       char parsed[256] = { 0 };
       char to_parse[] = "0: 0+1048576 1048576 dmstats -";
       r = sscanf(to_parse, "%d: %d+%d %d %255c", &x1, &x2, &x3, &x4, parsed);
       printf("result: %d  %s\n", r, parsed);
       return 0;
}

---

It's now after upgrade returning  'just' 4  instead of 5.
However 'parsed' buffer still looks to be properly filled.



Reproducible: Always

Comment 1 Florian Weimer 2025-09-01 16:14:53 UTC
I'm afraid this is the behavior required by the C standard. It says “Matches a sequence of characters of exactly the number specified by the field width”, so if the field width is 255 as in your example, the input must contain 255 or characters for the match to succeed.

Based on a quick Debian Code Search, this change looks rather disruptive. I'll mention this on libc-alpha.

Comment 2 Florian Weimer 2025-09-01 16:25:31 UTC
Ah, my search was wrong. The problem is using "%255c" instead of "%255s".

So the impact should be more limited than I expected. I do not plan to revert this in rawhide immediately.

Comment 3 Zdenek Kabelac 2025-09-01 17:47:21 UTC
There is quite a difference between  %255c     and  %255s.

The 's' stops with the first white space.
The 'c' simply fills the buffer to its capacity with the white spaces included.

This change basically modifies the behavior that's been there for ages.
So IMHO a 'new letter' should be added for new behaviors.

Also man page tells this:

 c      Matches  a  sequence  of characters whose length is specified by the maximum field width (default 1);

'maximum'  !=  'exactly'

Comment 4 Florian Weimer 2025-09-01 18:58:35 UTC
Yes, whitespace treatment is another difference. If you simply want to read a varying number of characters, I think you are expected to use fgets.

And the man page is just misleading. The glibc manual has always documented the current rawhide behavior:

“
   The ‘%c’ conversion is the simplest: it matches a fixed number of
characters, always.  The maximum field width says how many characters to
read; if you don't specify the maximum, the default is 1.  This
conversion doesn't append a null character to the end of the text it
reads.  It also does not skip over initial whitespace characters.  It
reads precisely the next N characters, and fails if it cannot get that
many.  Since there is always a maximum field width with ‘%c’ (whether
specified, or 1 by default), you can always prevent overflow by making
the buffer long enough.
”

It's just that this behavior wasn't implemented before. Other Linux libcs implement the standard behavior, too.

Comment 5 Zdenek Kabelac 2025-09-02 13:38:40 UTC
Well since this now kind of 'randomized' behavior of glibc makes the use of %Xc highly problematic - lvm2 libdm code simply dropped the use of this 'feature' - https://gitlab.com/lvmteam/lvm2/-/commit/be3224b3f535c2019d544e924712eadcfa93784f

However surely old binary running with newer glibc will simply no longer work.

So is there at least  gcc versioning used so the older linked binaries do get old 'logic' - while new builds do get this new fancy one ?

Comment 6 Carlos O'Donell 2025-09-12 13:29:38 UTC
Yes, upstream could at least provide a symbol version, but I'm not sure how easy that will be given the intertwined logic.

Comment 7 Florian Weimer 2025-09-19 13:19:11 UTC
Have there been any other sightings of this issue? Or is lvm2 the only impacted component?

Comment 8 Florian Weimer 2025-11-28 14:42:11 UTC
I need to send the man-pages correction upstream.

Comment 9 Florian Weimer 2025-11-28 15:52:13 UTC
I sent a correction to the man-pages project:

[PATCH] sscanf.3: Document exact matching for %c
<https://lore.kernel.org/linux-man/lhu1pli6tsj.fsf@oldenburg.str.redhat.com/>

On the glibc side, if more software is impacted by this correctness fix, we can consider adding a tunable (upstream) to restore the previous, standards-violating behavior.