Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a strlen call in snprintf causing this segfault?

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.

like image 997
pythonic metaphor Avatar asked Dec 03 '22 12:12

pythonic metaphor


2 Answers

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.

like image 150
Dummy00001 Avatar answered Dec 28 '22 04:12

Dummy00001


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.

like image 22
Tyler McHenry Avatar answered Dec 28 '22 03:12

Tyler McHenry