Bug 2392416 - glibc: sscanf parsing of %XXXc is not being returned as read
Summary: glibc: sscanf parsing of %XXXc is not being returned as read
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Fedora
Classification: Fedora
Component: glibc
Version: rawhide
Hardware: Unspecified
OS: Linux
unspecified
high
Target Milestone: ---
Assignee: Florian Weimer
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2025-09-01 15:45 UTC by Zdenek Kabelac
Modified: 2025-11-28 15:52 UTC (History)
15 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2025-11-28 15:52:13 UTC
Type: ---
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Sourceware 12701 0 P2 REOPENED scanf accepts non-matching input 2025-09-01 16:15:48 UTC

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.


Note You need to log in before you can comment on or make changes to this bug.