This is the mail archive of the
mailing list for the newlib project.
Re: sscanf() problems
- From: Jeff Johnston <jjohnstn at redhat dot com>
- To: Steffen Wolfer <wolfer at weiss-robotics dot de>
- Cc: newlib at sourceware dot org
- Date: Tue, 2 Dec 2014 15:28:07 -0500 (EST)
- Subject: Re: sscanf() problems
- Authentication-results: sourceware.org; auth=none
- References: <547DA0B0 dot 1070707 at weiss-robotics dot de>
I believe I know what is happening.
The SCNu8 macro expands to be hhu
The vfscanf.c code only supports hh if the flag _WANT_IO_C99_FORMATS is set
to true. By default it is false in newlib/configure.host and for a few select
platforms, it is set to true.
If you did not configure your library with --enable-newlib-io-c99-formats, then
it is false as arm doesn't set it to true.
Now, the second part of the problem. The code in vfscanf.c sees the first 'h' and sets
a flag to indicate a short value and then reads the next format character since h is a modifier
for a format. It reads the second 'h' and processes it the same as it did for the first
(sets the short value flag again to true).
So, the code thinks you are reading a short value and this sets the upper-byte to 0x00. So,
each of a, b, c, d are stepped on in order (ok, since they are being read in that order) and
the final read of d steps on the next byte after it on the stack, which in your case is the str pointer.
-- Jeff J.
----- Original Message -----
> From: "Steffen Wolfer" <email@example.com>
> To: firstname.lastname@example.org
> Sent: Tuesday, December 2, 2014 6:21:20 AM
> Subject: sscanf() problems
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> Dear all,
> I'm having the following, interesting problem using Newlib's sscanf().
> Trying to read an IP address from a string with the following code
> void read_ipaddr()
> char *str;
> uint8_t a, b, c, d;
> int res;
> // This function returns a pointer to the
> // string that represents the IP address
> get_str( &str );
> res = sscanf( str, "%" SCNu8 ".%" SCNu8 ".%" SCNu8 ".%" SCNu8,
> &a, &b, &c, &d );
> The thing is that *str, i.e. the address value that is stored in the
> *str pointer, seems to be corrupted by sscanf().
> Dumping the memory shows that the variables a, b, c and d are located
> first in memory (stack area growing downwards) - let's say at byte
> addresses 10, 11, 12 and 13. After that, the 4-byte pointer *str is
> placed at address 14 to 17.
> Before the call of sscanf(), *str has a value of 0xa14af968. After the
> call to sscanf(), the value is 0xa14af900, meaning that the least
> significant byte of the value, which is located at byte address 14
> (little endian), is overwritten by sscanf(). The bytes at addresses 10
> to 13 represent the correct numbers of the scanned IP address string.
> I'm running a bare metal ARM Cortex-M4 based microcontroller, using
> the compiler toolchain 2014q2 from here:
> This includes GCC 4.8.4 and a Newlib snapshot from 2013-10-16 (at
> least the changelog says so).
> Now do you think this is a problem in Newlib or am I doing something
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1
> -----END PGP SIGNATURE-----