I came across a formatting problem in my code. Here is the issue:
#include <iostream>
#include <cstdio>
#include <cstdarg>
void PP_p_VSPF_vsprintf(char *buf, size_t max_size, const char *fmt, va_list args )
{
const int stat = vsnprintf(buf, max_size, fmt, args);
if(stat >= static_cast<int>(max_size)) // not enough room in buffer
{
buf[max_size - 1] = '\0';
}
else if (stat < 0)
{
buf[max_size - 1] = '\0';
}
}
void PP_p_SPF_sprintf(char *buf, size_t max_size, const char *fmt, ...)
{
va_list argptr;
va_start(argptr, fmt);
PP_p_VSPF_vsprintf( buf, max_size, fmt, argptr );
va_end( argptr );
}
int main() {
char ExpCrcData[100] = "";
unsigned int crc32Values[] = {0xe870cde0u, 0x1ec5adaeu, 0xcb43101bu};
for (int i = 0; i < 3; ++i) {
PP_p_SPF_sprintf(ExpCrcData, 100, "%s0x%08x ", ExpCrcData, crc32Values[i]);
std::cout << "Download admin string is now: " << ExpCrcData << std::endl;
}
return 0;
}
Using GNU compiler,
In Windows, I get the output:
Download admin string is now: 0xe870cde0
Download admin string is now: 0xe870cde0 0x1ec5adae
Download admin string is now: 0xe870cde0 0x1ec5adae 0xcb43101b
In Linux, I get the output:
Download admin string is now: 0xe870cde0
Download admin string is now: 0x1ec5adae
Download admin string is now: 0xcb43101b
Can someone explain the reason behind this difference?
https://linux.die.net/man/3/sprintf says:
C99 and POSIX.1-2001 specify that the results are undefined if a call to sprintf(), snprintf(), vsprintf(), or vsnprintf() would cause copying to take place between objects that overlap (e.g., if the target string array and one of the supplied input arguments refer to the same buffer).
Because the question is tagged C and C++, here the C++ quote:
https://en.cppreference.com/w/cpp/io/c/fprintf says:
If a call to sprintf or snprintf causes copying to take place between objects that overlap, the behavior is undefined (e.g.
sprintf(buf, "%s text", buf);
).
buf
and the buffer pointed to by the variable argument corresponding to the %s
specifier are overlapping, which is undefined behavior.
Therefore
PP_p_SPF_sprintf(ExpCrcData, 100, "%s0x%08x ", ExpCrcData, crc32Values[i]);
should be
PP_p_SPF_sprintf(ExpCrcData+strlen(ExpCrcData), 100-strlen(ExpCrcData), "0x%08x ", crc32Values[i]);
Another possibility is to keep track of where you are in the buffer and what's left.