I have a char array defined like this
char buffer[100];
When I run Flawfinder scan for hits I get the one says:
(buffer) char:
Statically-sized arrays can be improperly restricted, leading to potential
overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
functions that limit length, or ensure that the size is larger than the
maximum possible length.
I know I have to do the checks when needed to make sure my code will be exceptions free but do we have any way to solve this (define a char array in other ways) and make the Flawfindr output without any hit?
UPDATE
Here's the full code of the function in case it would help
std::string MyClass::randomGenerator(odb::nullable<int> maxLength) {
struct timeval tmnow;
struct tm *tm;
char buf[100];
gettimeofday(&tmnow, NULL);
tm = localtime(&tmnow.tv_sec);
strftime(buf, 100, "%m%d%H%M%S", tm);
string micro = std::to_string(((int)tmnow.tv_usec / 10000));
strlcat(buf, micro.c_str(), sizeof(buf));
std::stringstream stream;
stream << std::hex << stoll(buf);
std::string result(stream.str());
Utilities::find_and_replace(result, "0", "h");
Utilities::find_and_replace(result, "1", "k");
std::transform(result.begin(), result.end(),result.begin(), ::toupper);
if (maxLength) {
return result.substr(result.size() - maxLength.get(), result.size() - 1);
} else {
return result ;
}
}
Flawfinder is really a slightly glorified grep - it's not a true static-analysis tool that does data flow analysis, so I have always taken its output with a healthy dose of salt!
The way you should really write this code is to write true C++ code rather than glorified-C using C runtime functions, which are absolutely subject to memory corruption issues.
Related
I'm having a string is not null terminated error, though I'm not entirely sure why. The usage of std::string in the second part of the code is one of my attempt to fix this problem, although it still doesn't work.
My initial codes was just using the buffer and copy everything into client_id[]. The error than occurred. If the error is correct, that means I've got either client_ id OR theBuffer does not have a null terminator. I'm pretty sure client_id is fine, since I can see it in debug mode. Strange thing is buffer also has a null terminator. No idea what is wrong.
char * next_token1 = NULL;
char * theWholeMessage = &(inStream[3]);
theTarget = strtok_s(theWholeMessage, " ",&next_token1);
sendTalkPackets(next_token1, sizeof(next_token1) + 1, id_clientUse, (unsigned int)std::stoi(theTarget));
Inside sendTalkPackets is. I'm getting a string is not null terminated at the last line.
void ServerGame::sendTalkPackets(char * buffer, unsigned int buffersize, unsigned int theSender, unsigned int theReceiver)
{
std::string theMessage(buffer);
theMessage += "0";
const unsigned int packet_size = sizeof(Packet);
char packet_data[packet_size];
Packet packet;
packet.packet_type = TALK;
char client_id[MAX_MESSAGE_SIZE];
char theBuffer[MAX_MESSAGE_SIZE];
strcpy_s(theBuffer, theMessage.c_str());
//Quick hot fix for error "string not null terminated"
const char * test = theMessage.c_str();
sprintf_s(client_id, "User %s whispered: ", Usernames.find(theSender)->second.c_str());
printf("This is it %s ", buffer);
strcat_s(client_id, buffersize , theBuffer);
Methinks that problem lies in this line:
sendTalkPackets(next_token1, sizeof(next_token1) + 1, id_clientUse, (unsigned int)std::stoi(theTarget));
sizeof(next_token1)+1 will always gives 5 (on 32 bit platform) because it return size of pointer not size of char array.
One thing which could be causing this (or other problems): As
buffersize, you pass sizeof(next_token1) + 1. next_token1 is
a pointer, which will have a constant size of (typically) 4 or 8. You
almost certainly want strlen(next_token1) + 1. (Or maybe without the
+ 1; conventions for passing sizes like this generally only include
the '\0' if it is an output buffer. There are a couple of other
places where you're using sizeof, which may have similar problems.
But it would probably be better to redo the whole logic to use
std::string everywhere, rather than all of these C routines. No
worries about buffer sizes and '\0' terminators. (For protocol
buffers, I've also found std::vector<char> or std::vector<unsigned char>
quite useful. This was before the memory in std::string was
guaranteed to be contiguous, but even today, it seems to correspond more
closely to the abstraction I'm dealing with.)
You can't just do
std::string theMessage(buffer);
theMessage += "0";
This fails on two fronts:
The std::string constructor doesn't know where buffer ends, if buffer is not 0-terminated. So theMessage will potentially be garbage and include random stuff until some zero byte was found in the memory beyond the buffer.
Appending string "0" to theMessage doesn't help. What you want is to put a zero byte somewhere, not value 0x30 (which is the ascii code for displaying a zero).
The right way to approach this, is to poke a literal zero byte buffersize slots beyond the start of the buffer. You can't do that in buffer itself, because buffer may not be large enough to accomodate that extra zero byte. A possibility is:
char *newbuffer = malloc(buffersize + 1);
strncpy(newbuffer, buffer, buffersize);
newbuffer[buffersize] = 0; // literal zero value
Or you can construct a std::string, whichever you prefer.
Cppcheck 1.67 raised a portability issue in my source code at this line:
sscanf(s, "%d%*[,;.]%d", &f, &a);
This is the message I got from it:
scanf without field width limits can crash with huge input data on some versions of libc.
The original intention of the format string was to accept one of three possible limiter chars between two integers, and today - thanks to Cppcheck[1] - I see that %*[,;.] accepts even strings of limiter chars. However I doubt that my format string may cause a crash, because the unlimited part is ignored.
Is there possibly an issue with a buffer overrun? ...maybe behind the scenes?
[1]
How to get lost between farsightedness and blindness:
I tried to fix it by %1*[,;.] (after some API doc), but Cppcheck insisted in the issue, so I also tried %*1[,;.] with the same "success". Seems that I have to suppress it for now...
Congratulations on finding a bug in Cppcheck 1.67 (the current version).
You have basically three workarounds:
Just ignore the false positive.
Rework your format (assign that field, possible as you only want to match one character).
char tmp;
if(3 != sscanf(s, "%d %c%d", &f, &tmp, &a) || tmp!=',' && tmp!=';' && tmp!= '.')
goto error;
Suppress the warning directly (preferably inline-suppressions):
//cppcheck-suppress invalidscanf_libc
if(2 != sscanf(s, "%d%1*[,;.]%d", &f, &a))
goto error;
Don't forget to report the error, as "defect / false positive", so you can retire and forget that workaround as fast as possible.
When to quantify ignored pattern match in the C sscanf function?
Probably it's a good idea to always quantify (see below), but over-quantification may also distract from your intentions. In the above case, where a single separator char has to be skipped, the quantification would definitely be useful.
Is there possibly an issue with a buffer overrun? ...maybe behind the scenes?
There will be no crashes caused by your code. As to deal with the "behind the scenes" question, I experimented with large input strings. In the C library I tested, there was no internal buffer overflow. I tried the C lib that's shipped with Borland C++ 5.6.4 and found that I could not trigger a buffer overrun with large inputs (more than 400 million chars).
Surprisingly, Cppcheck was not totally wrong - there is a portability issue, but a different one:
#include <stdio.h>
#include <assert.h>
#include <sstream>
int traced_sscanf_set(const int count, const bool limited)
{
const char sep = '.';
printf("\n");
std::stringstream ss;
ss << "123" << std::string(count, sep) << "456";
std::string s = ss.str();
printf("string of size %d with %d '%c's in it\n", s.size(), count, sep);
std::stringstream fs;
fs << "%d%";
if (limited) {
fs << count;
}
fs << "*["<< sep << "]%d";
std::string fmt = fs.str();
printf("fmt: \"%s\"\n", fmt.c_str());
int a = 0;
int b = 0;
const sscanfResult = sscanf(s.c_str(), fmt.c_str(), &a, &b);
printf("sscanfResult=%d, a=%d, b=%d\n", sscanfResult, a, b);
return sscanfResult;
}
void test_sscanf()
{
assert(traced_sscanf_set(0x7fff, true)==2);
assert(traced_sscanf_set(0x7fff, false)==2);
assert(traced_sscanf_set(0x8000, true)==2);
assert(traced_sscanf_set(0x8000, false)==1);
}
The library I checked, internally limits the input consumed (and skipped) to 32767 (215-1) chars, if there is no explicitly specified limit in the format parameter.
For those who are interested, here is the trace output:
string of size 32773 with 32767 '.'s in it
fmt: "%d%32767*[.]%d"
sscanfResult=2, a=123, b=456
string of size 32773 with 32767 '.'s in it
fmt: "%d%*[.]%d"
sscanfResult=2, a=123, b=456
string of size 32774 with 32768 '.'s in it
fmt: "%d%32768*[.]%d"
sscanfResult=2, a=123, b=456
string of size 32774 with 32768 '.'s in it
fmt: "%d%*[.]%d"
sscanfResult=1, a=123, b=0
I am currently writing a program in C++. I want to save a number of files continuously throughout the run of my program. The format of the filename is as such:
char fnameC[sizeof "C:\..._SitTurn_104_c2_00_00_000.bmp"];
- SitTurn is an experiment name
- 104 is an experiment number
These two will be changing after each different run of the program. Currently, my program works like this:
char fnameCVS[sizeof"C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_SitTurn_104_c2_02.csv"];
LARGE_INTEGER frequency;
LARGE_INTEGER t1, t2;
double elapsedTime;
SYSTEMTIME comptime;
int main(int argc, char *argv[])
{
GetSystemTime(&comptime);
sprintf_s(fnameCVS, "C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_SitTurn_104_c2_%02d.csv", comptime.wDay);
However, I tried this and I can't seem to get it to work. Can anyone help me?
...//rest of code set up
string expName = "SitStand";
string subjNumber = "101";
char fnameCVS[sizeof "C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_" + expName + "_" + subjNumber + "_c2_02.csv"];
LARGE_INTEGER frequency;
LARGE_INTEGER t1, t2;
double elapsedTime;
SYSTEMTIME comptime;
int main(int argc, char *argv[])
{
GetSystemTime(&comptime);
sprintf_s(fnameCVS, "C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_" + expName + "_" + subjNumber + "_c2_%02d.csv", comptime.wDay);
Since I am using this filename later in the program also, I would like to be able to just rename all files by changing the two strings: expName and subjNumber. Can someone help me explain how I can name my files using a string inputs (e.g. expName and subjNumber), so I only have to rename those corresponding string each time I change the experiment name, or subject number. Thanks!
Try this:
char fnameCVS[MAX_PATH+1];
SYSTEMTIME comptime;
GetSystemTime(&comptime);
sprintf_s(fnameCVS, _countof(fnameCVS), "C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_SitTurn_104_c2_%02d.csv", comptime.wDay);
Or this:
#include <string>
#include <sstream>
std::string expName = "SitStand";
std::string subjNumber = "101";
std::string fnameCVS;
SYSTEMTIME comptime;
GetSystemTime(&comptime);
std::ostringstream oss;
oss << "C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_" << expName << "_" << subjNumber << "_c2_" << std::setw(2) << std::setfill('0') << comptime.wDay << ".csv";
fnameCVS = oss.str();
You are mixing sprintf and std::string, which is never a good plan. You should either pick to use C's sprintf with char *, or C++'s std::string with std::stringstream.
Your fnameCVS array isn't going to be big enough: you'll take the sizeof of a std::string, which almost certainly will not be what you want.
Option 1: Use only sprintf. Allocate a big-enough string (e.g. char fnameCVS[256]) and use snprintf(fnameCVS, 256, "...Skeleton_%s_%d_c2_%02.csv", ...).
Option 2: Use only string and use a std::stringstream to build your filename.
This is a really bad idea:
char fnameCVS[sizeof"C:\\Users\\Adam\\Desktop\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_RGBDepth_DataAcquisition2013\\Skeleton_SitTurn_104_c2_02.csv"];
The main reason is that it is very difficult to visually inspect whether you have allocated the right number of bytes. Perhaps you make a slight change to the filename later in the sprintf line but then you forget to update this line or you make a typo. Boom, buffer overflow (which may go undetected until it is time to give a presentation).
A secondary bug is that when you use %02d in printf, the 2 is a minimum field width; if the number would require more than 2 digits then it outputs more than 2 digits, causing a buffer overflow. To be safe here you'd need to check that the number is between 0 and 99 before printing it.
Finally, sprintf_s is a non-standard function, there's really no reason to use it instead of sprintf or snprintf.
In C++ the equivalent formatting is a bit more wordy, but leaves no possibility of buffer overflows:
std::string fnameCVS;
// ...
std::ostringstream oss;
oss << "C:\\Users\\whatever...." << std::setw(2) << std::setfill('0')
<< comptime.wDay;
fnameCVS = oss.str();
If you really want to stick with the printf family plus a static char array (note: you can use printf and a dynamically-sized char container) then to make your code safe:
char const my_format[] = "C:\\Users\\whatever.....\\%02d.csv";
char fnameCVS[ sizeof my_format - 2 ]; // "NN" is two chars shorter than "%02d"
// ...
if ( comptime.wDay < 0 || comptime.wDay > 99 )
throw std::runtime_error("wDay out of range");
snprintf(fnameCVS, sizeof fnameCVS, my_format, comptime.wDay);
Your update indicates that you want to compute various other parts of the filename at runtime too; the C++ version that I suggest is easier to extend than the C-with-static-array version where you have to calculate the amount of memory you need by hand.
I have an error in my class.
I'm suspect it's something simple, maybe me failing to understand how strings works in C++.
My function tries to returns local std::string to another std::string, but instead of getting the string, I'm getting segmentation fault after the function returns.
This is my code:
TestClass::TestClass(std::string a, std::string b)
{
m_a = a;
m_b = b;
}
std::string TestClass::stringHandler()
{
const char myTemplate[] = "a=%s,b=%s";
char formattedString[strlen(myTemplate) + m_a.length() + m_b.length()];
sprintf( formattedString, myTemplate, m_a.c_str(), m_b.c_str());
std::cout << "formattedString= " << formattedString << "\n";
std::string returnStr(formattedString);
std::cout << "returnStr=" << returnStr << "\n";
return returnStr;
}
int main(...)
{
/* getting a and b from argv */
TestClass MyClassObj(a, b);
std::string strRet = MyClassObj.stringHandler();
std::cout << "Back after stringHandler\n";
return 0
}
In stringHandler, when I'm printing returnStr, it displayes properly.
But right after that, I'm getting Segmentation fault, and "Back after stringHandler" is not being printed.
Do any of you masters, have any idea what am I doing wrong?
Several issues:
%b is not a valid format specifier.
You have 3 format specifiers (if %b is fixed!) but you only passed 2 arguments.
You didn't allocate enough memory for formattedString.
Arrays with runtime size are illegal in C++
(update:) after the edits to OP, the first three of these were fixed, so if your compiler also has an extension for runtime array size then this code would not cause a segfault.
The simplest fix is just to write:
std::string returnStr = "a=" + m_a + ",b=" + m_b;
But supposing you want to stick with printf formatting, here is one way to do it.
Although it is possible to calculate and work out the exact amount of space, that is fragile. It'd be easy to cause a buffer overflow if you made a change to myTemplate.
One plan would be to allocate a large amount of space. A more robust way is to use snprintf to determine the buffer size first:
char const myTemplate[] = "a=%s,b=%s";
size_t expect_len = std::snprintf(NULL, 0, myTemplate, m_a.c_str(), m_b.c_str());
if ( expect_len == -1 )
throw std::runtime_error("snprintf failed");
std::vector<char> buffer(expect_len + 1);
std::snprintf(&buffer[0], buffer.size(), myTemplate, m_a.c_str(), m_b.c_str());
std::string returnStr(buffer);
In C++11 you could actually snprintf directly into returnStr.
To be clear, the whole printf idea is not very safe as you can cause undefined behaviour if myTemplate contains something you didn't expect. (I presume you did it this way to allow yourself to specify a different format string at runtime). So use it with caution.
I want a function that will take a time_t parameter and an arbitrary format string and format it. I want something like this:
std::string GetTimeAsString(std::string formatString, time_t theTime)
{
struct tm *timeinfo;
timeinfo = localtime( &theTime);
char buffer[100];
strftime(buffer, 100, formatString.c_str(), timeinfo);
std::string result(buffer);
return result;
}
However one problem I'm running into is the buffer length. I was thinking of doing something like formatString * 4 as the buffer length. But I guess you can't dynamically set the buffer length? Maybe I could pick an arbitrarily large buffer? I'm a little stuck as to how to make it generic.
How can I write a function to achieve this?
If you have C++11:
std::string GetTimeAsString(std::string formatString, time_t theTime)
{
struct tm *timeinfo;
timeinfo = localtime( &theTime);
formatString += '\a'; //force at least one character in the result
std::string buffer;
buffer.resize(formatstring.size());
int len = strftime(&buffer[0], buffer.size(), formatString.c_str(), timeinfo);
while (len == 0) {
buffer.resize(buffer.size()*2);
len = strftime(&buffer[0], buffer.size(), formatString.c_str(), timeinfo);
}
buffer.resize(len-1); //remove that trailing '\a'
return buffer;
}
Note I take formatString as a const reference, (for speed and safety), and use the result string as the buffer, which is faster than doing an extra copy later. I also start at the same size as the formatstring, and double the size with each attempt, but that's easily changable to something more appropriate for the results of strftime.
C++11 solution with std::put_time():
std::string GetTimeAsString(std::string formatString, time_t theTime)
{
const struct tm* timeinfo = localtime(&theTime);
std::ostringstream os;
os << std::put_time(timeinfo, formatString.c_str());
return os.str();
}
Use a vector<char> for the buffer instead of an array. Repeatedly increase the size until strftime returns non-zero.
I would think your best bet would be to provide a fixed buffer that is likely to handle the vast majority of cases, and then do special handling for the rest. Something like (untested, except in the wetware inside my skull):
std::string GetTimeAsString (std::string formatString, time_t theTime) {
struct tm *timeinfo;
char buffer[100], *pBuff = buffer;
int rc, buffSize = 100;
timeinfo = localtime (&theTime);
rc = strftime(pBuff, 100, formatString.c_str(), timeinfo);
// Most times, we shouldn't enter this loop.
while (rc == 0) {
// Free previous in it was allocated.
if (pBuff != buffer)
delete[] pBuff;
// Try with larger buffer.
buffSize += 100;
pBuff = new char [buffSize];
rc = strftime(pBuff, buffSize, formatString.c_str(), timeinfo);
}
// Make string then free buffer if it was allocated.
std::string result(pBuff);
if (pBuff != buffer)
delete[] pBuff;
return result;
}
strftime will return zero if the provided buffer wasn't big enough. In that case, you start allocating bigger buffers until it fits.
Your non-allocated buffer size and the increment you use for allocation size can be tuned to your needs. This method has the advantage that you won't notice an efficiency hit (however small it may be) except for the rare cases - no allocation is done for that vast majority.
In addition, you could choose some other method (e.g., +10%, doubling, etc) for increasing the buffer size.
The strftime() function returns 0 if the buffer's size is too small to hold the expected result. Using this property, you could allocate the buffer on the heap and try the consecutive powers of 2 as its size: 1, 2, 4, 8, 16 etc. until the buffer is big enough. The advantage of using the powers of 2 is that the solution's complexity is logarithmically proportional to the result's length.
There's also a special case that needs to be thought of: the format might be such that the result's size will always be 0 (e.g. an empty format). Not sure how to handle that.