I have a void *
, call it data
, whose length I know, but is not null terminated. I make a call like this snprintf(line, sizeof(line), "%*s", n, (const char*)data)
where n
is the known length. Almost always this works, but occasionally it results in a segfault.
Whenever the segfault occurs, the back trace says the problem is inside strlen. And when I print data
inside gdb, I see something like this
(gdb) p n
$1 = 88
(gdb) p (const char*) data
$2 = 0x1d752fa8
"JASDF" ... "ADS"<Address 0x1d753000 out of bounds>
(gdb) p 0x1d753000-0x1d752fa8
$3 = 88
data
is indeed 88 characters, but isn't null terminated, in fact, it seems that it lies right up against a segment. My guess is that snprintf is always called strlen on data and I usually get lucky in that even though data
isn't null terminated, there is a \0
before I hit the segment and then occasionally I get unlucky and it is. Is that right? If so, what's the work around?
This is what the stack trace looks like
#0 0x0000003c8927839e in strlen () from /lib64/libc.so.6
#1 0x0000003c89246749 in vfprintf () from /lib64/libc.so.6
#2 0x0000003c8926941a in vsnprintf () from /lib64/libc.so.6
#3 0x0000003c8924d0a3 in snprintf () from /lib64/libc.so.6
EDIT To answer my own question about the work around, strncpy is a more appropriate function to call. I used snprintf by habit.
snprintf(line, sizeof(line), "%*s", n, (const char*)data)
data
isn't zero terminated? Then you are doing it wrong.
snprintf(line, sizeof(line), "%.*s", n, (const char*)data);
Notice the dot.
In case of strings, the first *
in the *.*
if for the desired output (on screen) length - input length is the second *
. man printf
for more.
And obviously in the case of %*s
formatting might call strlen(), since it needs to know whether it needs to pad the output and how to pad it.
Looks like you're right. There's no guarantee that printf
won't call strlen
, even if it doesn't necessarily have to in a given context. You're lying by providing something that isn't a C string as the parameter for an %s
formatting specifier, and so you've broken the contract of printf
. Undefined behavior results.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With