Using snprintf to avoid buffer overruns
I am using snprintf
like this to avoid a buffer overrun:
char err_msg[32] = {0};
snprintf(err_msg, sizeof(err_msg) - 1, "[ ST_ENGINE_FAILED ]");
I added the -1
to reserve space for the null terminator in case the string is more than 32 bytes long.
Am I correct in my thinking?
Platform:
- G开发者_如何转开发CC 4.4.1
- C99
As others have said, you do not need the -1 in this case. If the array is fixed size, I would use strncpy
instead. It was made for copying strings - sprintf
was made for doing difficult formatting. However, if the size of the array is unknown or you are trying to determine how much storage is necessary for a formatted string. This is what I really like about the Standard specified version of snprintf
:
char* get_error_message(char const *msg) {
size_t needed = snprintf(NULL, 0, "%s: %s (%d)", msg, strerror(errno), errno);
char *buffer = malloc(needed+1);
sprintf(buffer, "%s: %s (%d)", msg, strerror(errno), errno);
return buffer;
}
Combine this feature with va_copy
and you can create very safe formatted string operations.
You don't need the -1, as the reference states:
The functions snprintf() and vsnprintf() do not write more than size bytes (including the trailing '\0').
Note the "including the trailing '\0'" part
No need for -1. C99 snprintf
always zero-terminates. Size argument specifies the size of output buffer including zero terminator. The code, thus, becomes
char err_msg[32];
int ret = snprintf(err_msg, sizeof err_msg, "[ ST_ENGINE_FAILED ]");
ret
contains actual number of characters printed (excluding zero terminator).
However, do not confuse with Microsoft's _snprintf
(pre-C99), which does not null-terminate, and, for that matter, has completely different behaviour (e.g. returning -1
instead of would-be printed length in case if buffer is not big enough). If using _snprintf
, you should be using the same code as in your question.
According to snprintf(3)
:
The functions
snprintf()
andvsnprintf()
do not write more thansize
bytes (including the trailing'\0'
).
For the example given, you should be doing this instead:
char err_msg[32];
strncpy(err_msg, "[ ST_ENGINE_FAILED ]", sizeof(err_msg));
err_msg[sizeof(err_msg) - 1] = '\0';
or even better:
char err_msg[32] = "[ ST_ENGINE_FAILED ]";
sizeof will return the number of bytes the datatype will use in memory, not the length of the string. E.g. sizeof(int) returns '4' bytes on a 32-bit system (well, depending on the implementation I guess). Since you use a constant in your array, you can happily pass that to the printf.
精彩评论