In a C program I have a function that writes a message to a log file
LogResult writeLog(const char* format, ...)
That function passes its arguments on to 'vfprintf()' as a 'format' string and a 'va_list'. It just occurred to me that I don't have any control over what would happen if someone were to pass an unterminated string, e.g.
const char unterminatedString[5] = {'h', 'e', 'l', 'l', 'o'};
writeLog("Log message: %s", unterminatedString);
Is there any way to guard against this?
I assume your log function has its own internal buffer and you know the size of that.
You can then use the vsprintf() functions that specify a buffer size. See Possible buffer overflow vulnerability.
There are many other ways (on top of the one that you've mentioned) for passing an illegal string.
A few examples:
char* unterminatedString;
writeLog("Log message: %s", unterminatedString);
char* unterminatedString = (char*)0xA5A5A5A5;
writeLog("Log message: %s", unterminatedString);
char unterminatedString[] = "abc";
unterminatedString[3] = 'd';
writeLog("Log message: %s", unterminatedString);
int x = -1;
char* unterminatedString = (char*)&x;
writeLog("Log message: %s", unterminatedString);
A legal string must start at a valid memory address, and end (with a 0 character) at a valid memory address. There is no definite way to assert that, except for iterating the string itself, until reaching a 0 character or performing a memory access violation (which is exactly what the vfprintf
function does).
const char*
does not know the length of the array, it is just an address. So that is not simply possible.
If you want to stay in pure C, you could pass the length int len
of the string as an extra argument and check if format[len]==0
.
I do not really think this is helpful though, it is even worse in my opinion.
Since you flagged this question with C++, you could (and imo should) use std::string
:
LogResult writeLog(const std::string& format, ...)
An std::string
is always correctly terminated, you can access its underlying C-style string with std::string::c_str()
.
Note that std::string
can store \0
-Characters, so functions using an C-style string would stop at the first \0
, not necessarily at the end of the std::string
.
No, there is no way to portably do it.
What you could do is look for this types of bugs using a tool like valgrind
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With