Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is snprintf() ALWAYS null terminating?

Tags:

c

posix

libc

Is snprintf always null terminating the destination buffer?

In other words, is this sufficient:

char dst[10];

snprintf(dst, sizeof (dst), "blah %s", somestr);

or do you have to do like this, if somestr is long enough?

char dst[10];

somestr[sizeof (dst) - 1] = '\0';
snprintf(dst, sizeof (dst) - 1, "blah %s", somestr);

I am interested both in what the standard says and what some popular libc might do which is not standard behavior.

like image 411
Prof. Falken Avatar asked Oct 09 '11 22:10

Prof. Falken


People also ask

Does sprintf append null?

In other words, sprintf and snprintf always append the null byte, but printf does not, so your example isn't applicable.

What does Snprintf return?

The snprintf() function returns the number of bytes that are written in the array, not counting the ending null character.

Does Strncpy null terminate?

Problem with strncpy(): If there is no null character among the first n character of src, the string placed in dest will not be null-terminated. So strncpy() does not guarantee that the destination string will be NULL terminated.

Are strings automatically null-terminated?

The things that are called "C strings" will be null-terminated on any platform. That's how the standard C library functions determine the end of a string. Within the C language, there's nothing stopping you from having an array of characters that doesn't end in a null.


3 Answers

As the other answers establish: It should:

snprintf ... Writes the results to a character string buffer. (...) will be terminated with a null character, unless buf_size is zero.

So all you have to take care is that you don't pass an zero-size buffer to it, because (obviously) it cannot write a zero to "nowhere".


However, beware that Microsoft's library does not have a function called snprintf but instead historically only had a function called _snprintf (note leading underscore) which does not append a terminating null. Here's the docs (VS 2012, ~~ VS 2013):

http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx

Return Value

Let len be the length of the formatted data string (not including the terminating null). len and count are in bytes for _snprintf, wide characters for _snwprintf.

  • If len < count, then len characters are stored in buffer, a null-terminator is appended, and len is returned.

  • If len = count, then len characters are stored in buffer, no null-terminator is appended, and len is returned.

  • If len > count, then count characters are stored in buffer, no null-terminator is appended, and a negative value is returned.

(...)

Visual Studio 2015 (VC14) apparently introduced the conforming snprintf function, but the legacy one with the leading underscore and the non null-terminating behavior is still there:

The snprintf function truncates the output when len is greater than or equal to count, by placing a null-terminator at buffer[count-1]. (...)

For all functions other than snprintf, if len = count, len characters are stored in buffer, no null-terminator is appended, (...)

like image 104
Martin Ba Avatar answered Oct 13 '22 22:10

Martin Ba


According to snprintf(3) manpage.

The functions snprintf() and vsnprintf() write at most size bytes (including the trailing null byte ('\0')) to str.

So, yes, no need to terminate if size >= 1.

like image 37
piotr Avatar answered Oct 13 '22 21:10

piotr


According to the C standard, unless the buffer size is 0, vsnprintf() and snprintf() null terminates its output.

The snprintf() function shall be equivalent to sprintf(), with the addition of the n argument which states the size of the buffer referred to by s. If n is zero, nothing shall be written and s may be a null pointer. Otherwise, output bytes beyond the n-1st shall be discarded instead of being written to the array, and a null byte is written at the end of the bytes actually written into the array.

So, if you need to know how big a buffer to allocate, use a size of zero, and you can then use a null pointer as the destination. Note that I linked to the POSIX pages, but these explicitly say that there is not intended to be any divergence between Standard C and POSIX where they cover the same ground:

The functionality described on this reference page is aligned with the ISO C standard. Any conflict between the requirements described here and the ISO C standard is unintentional. This volume of POSIX.1-2008 defers to the ISO C standard.

Be wary of the Microsoft version of vsnprintf(). It definitely behaves differently from the standard C version when there is not enough space in the buffer (it returns -1 where the standard function returns the required length). It is not entirely clear that the Microsoft version null terminates its output under error conditions, whereas the standard C version does.

Note also the answers to Do you use the TR 24731 safe functions? (see MSDN for the Microsoft version of the vsprintf_s()) and Mac solution for the safe alternatives to unsafe C standard library functions?

like image 12
Jonathan Leffler Avatar answered Oct 13 '22 21:10

Jonathan Leffler