Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong return value from snprintf if the buffer is too small #2

Open
jonathangjertsen opened this issue Aug 18, 2022 · 3 comments
Open

Comments

@jonathangjertsen
Copy link

https://cplusplus.com/reference/cstdio/snprintf/ says:

Return value
The number of characters that would have been written if n had been sufficiently large, not counting the terminating null character.

The snprintf implementation in this repo instead returns the size of the buffer.

char buffer[4];
size_t result = snprintf(buffer, sizeof(buffer), "13 characters");
assert(result == 13); // fails; result is 4

It seems that printf-stdarg.c has been ported from somewhere else, where is it originally from?

@htibosch
Copy link
Owner

About sprintf(): you may call me stubborn, but already 30 years I am struggling with this set of functions.

Personally, I only use sprintf() for logging, and then it is not fatal if a string is truncated. It is more important that each string gets null-terminated.

I don't like to add the following checks to each call of snprintf():

char buffer[4];
int result = snprintf(buffer, sizeof( buffer ), "13 characters" );
if( result >= sizeof( buffer ) )
{
    buffer[ sizeof( buffer ) - 1 ] = 0;
    result = sizeof( buffer ) - 1;
}

I have also seen code in which snprintf() is called twice: first to assess the number of bytes needed, after that a buffer is allocated, and then snprintf() is called again to actually write the string.

It makes the code look so ugly :-(

And wasn't there also an implementation that returned - <size>, in case the buffer is too short? It would not print anything, unless the buffer was big enough to hold the entire string, including the null.

In Microsoft Visual C, snprintf() was allowed. Then it got banned, and we had to use _snprintf(). And nowadays it is allowed again. The FreeRTOS libraries had to make many extra defines to "stay compatible" with the MSC compiler:

#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) )
	/* Map to Windows names. */
	#define snprintf	_snprintf
	#define vsnprintf	_vsnprintf
#endif

( and also close() was once renamed to closesocket() )

Indeed I created my own version of printf-stdarg.c, because it is safer, and it uses a small determined amount of stack.

It never uses the heap ans it is "interrupt proof". I made it available in my "plus testing projects". This source code is not part of the official FreeRTOS kernel or +TCP libraries.

But if you find it convenient, I don't mind to add a configuration macro like configSNPRINTF_STANDARD_BEHAVIOUR, and have it behave like the modern c++ version of snprintf().

Thanks

@htibosch
Copy link
Owner

@jonathangjertsen : would you like the change that I proposed? Add a config macro like: configSNPRINTF_STANDARD_BEHAVIOUR to get the official behaviour?

@jonathangjertsen
Copy link
Author

jonathangjertsen commented Aug 31, 2022

Hi @htibosch sorry for not getting back to you, I changed my usage to not rely on the return value of snprintf so this is not very important for me anymore. Adding a configuration macro sounds like a good solution though, in case someone else needs it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants