How to resolve this C6385 code analysis warning: Reading invalid data - c++

I am trying to address a code analysis warning that appears in the following method:
CStringArray* CCreateReportDlg::BuildCustomAssignArray(ROW_DATA_S &rsRowData)
{
INT_PTR iAssign, iNumAssigns, iUsedAssign;
CStringArray *pAryStrCustom = nullptr;
CUSTOM_ASSIGN_S *psAssign = nullptr;
if (rsRowData.uNumCustomToFill > 0)
{
pAryStrCustom = new CStringArray[rsRowData.uNumCustomToFill];
iNumAssigns = m_aryPtrAssign.GetSize();
for (iAssign = 0, iUsedAssign = 0; iAssign < iNumAssigns; iAssign++)
{
psAssign = (CUSTOM_ASSIGN_S*)m_aryPtrAssign.GetAt(iAssign);
if (psAssign != nullptr)
{
if (!psAssign->bExcluded)
{
pAryStrCustom[iUsedAssign].Copy(psAssign->aryStrBrothersAll);
iUsedAssign++;
}
}
}
}
return pAryStrCustom;
}
The offending line of code is:
pAryStrCustom[iUsedAssign].Copy(psAssign->aryStrBrothersAll);
I compile this code for both 32 bit and 64 bit. The warning being raised is:
Warning (C6385) Reading invalid data from pAryStrCustom: the readable size is (size_t)*40+8 bytes, but 80 bytes may be read.
I don't know if it is relevant, but the CUSTOM_ASSIGN_S structure is defined as:
typedef struct tagCustomAssignment
{
int iIndex;
CString strDescription;
CString strHeading;
BOOL bExcluded;
CStringArray aryStrBrothersAll;
CStringArray aryStrBrothersWT;
CStringArray aryStrBrothersSM;
BOOL bIncludeWT;
BOOL bIncludeTMS;
BOOL bFixed;
int iFixedType;
} CUSTOM_ASSIGN_S;
My code is functional (for years) but is there a coding improvement I can make to address this issue? I have read the linked article and it is not clear to me. I have also seen this question (Reading Invalid Data c6385) along similar lines. But in my code I can't see how that applies.

Warning... the readable size is (size_t)*40+8 bytes, but 80 bytes may be read.
The wording for this warning is not accurate, because size_t is not a number, it's a data type. (size_t)*40+8 doesn't make sense. It's probably meant to be:
Warning... the readable size is '40+8 bytes', but '80 bytes' may be read.
This warning can be roughly reproduced with the following example:
//don't run this code, it's just for viewing the warning
size_t my_size = 1;
char* buf = new char[my_size];
buf[1];
//warning C6385: Reading invalid data from 'buf':
//the readable size is 'my_size*1' bytes, but '2' bytes may be read
The warning is correct and obvious. buf[1] is out of bound. The compiler sees allocation size for buf is my_size*1, and index 1 is accessing byte '2'. I think in other place the compiler prints it incorrectly, but the actual warning is valid.
In any case, just make sure iUsedAssign is within range
if (!psAssign->bExcluded && iUsedAssign < rsRowData.uNumCustomToFill)
{
...
}

Related

Warning C6386 - Buffer overrun while writing to 'LINES_DATA.Lines'

I know this question has been asked before, but I couldn't quite fix my code, even reading other topics.
Does anyone know why is it throwing this warning?
Warning C6386 Buffer overrun while writing to 'LINES_DATA.Lines': the writable size is 'LINES_DATA.NumLines4' bytes, but '8' bytes might be written.*
"
LINES_DATA.NumLines = line_i; //line_i = 100
LINES_DATA.Lines = new int* [LINES_DATA.NumLines];
line_i = 0;
for (rapidxml::xml_node<>* pNode = pRoot->first_node(); pNode; pNode = pNode->next_sibling())
{
LINES_DATA.Lines[line_i] = new int[COLUMNSIZE]; //COLUMNSIZE = 5
for (int pos_i = 0; pos_i < COLUMNSIZE; pos_i++)
{
LINES_DATA.Lines[line_i][pos_i] = pNode->value()[pos_i] - '0';
}
line_i++;
}
I get the warning in this line:
LINES_DATA.Lines[line_i] = new int[COLUMNSIZE];
Thank you so much
If the array (LINES_DATA.Lines) hasline_i elements then LINES_DATA.Lines[line_i] is not valid.
Arrays are zero based so LINES_DATA.Lines has elements 0 to line_i-1
It's just a Code Analysis warning. The compiler isn't smart enough to work out your program's entire runtime behaviour.
Your code does have major risks of buffer over-runs, particularly if the XML contains more than 100 elements. You should be using smart pointers and/or STL containers here.

Wrong output when printing a string from inside a struct pointer (VC++ 2010)

I've found a very strange issue with both printf (and printf_s), and also std::cout. I'm not sure if it's some short of "glitch" or error in these functions, or if I'm doing something wrong. Since both functions do the same, I'm assuming I'm not doing it the right way.
I have the following structures in my program (By the way, this is a Visual C++ 2010 project):
#pragma pack(push, 1)
typedef struct nameentry
{
char NAME[17];
char EXT[4];
}NAMEENTRY;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct fileentry
{
unsigned int ID;
NAMEENTRY FILENAME;
unsigned int GPFID;
unsigned long long int FPOINTER;
size_t FILESIZE;
}FILEENTRY;
#pragma pack(pop)
Now I have the following portion of code:
NAMEENTRY fname = MCreateNameEntry("LONGFILE.JPG");
FILEENTRY* myfile_ = SearchFileByPkgID(0, fname);
printf("%s", myfile_->FILENAME.NAME);
So what this code is supposed to do is, create an instance of NAMEENTRY with NAME=LONGFILE, and EXT=JPG. Both character arrays are null terminated (last byte is a 0). Then create an instance of FILEENTRY with it's corresponding data from a database I'm developing, then print the name of the file from the FILEENTRY's NAMEENTRY structure.
After running the code, what I get instead of the name of the file, is... garbage. The classic garbage you get when trying to print text from a bad pointer. If I try to print any of the other fields, I also get wrong values.
So obviously, my first thought was that one of my functions were not returning the right value. So I started inspecting the code and, to my surprise, they are actually returning the right values and the structure is filled with the right data. I get the proper values in each field, every character array ends with a 0, etc.
So then I said... "What if I copy the entire block into another instance of FILEENTRY?", and I tried this:
NAMEENTRY fname = MCreateNameEntry("LONGFILE.JPG");
FILEENTRY* myfile_ = SearchFileByPkgID(0, fname);
FILEENTRY dMem;
memcpy(&dMem, myfile_, sizeof(FILEENTRY));
printf("%s", dMem.FILENAME.NAME);
And guess what? It works perfectly fine. I get the name of the file, no garbage. So I'm assuming, either the problem is inside of printf (I also tried std::cout with the same results), or I am doing something wrong when using these functions.
Well, that helps. Seems like the problem was trying to return a pointer to a local variable, as Igor Tandetnik suggested.
So as a workaround, I'm not sure if this is a proper way of handling this, instead of define a local variable, I'm using calloc to allocate a memory block for a FILEENTRY pointer, then fill it and return it. And yes, it seems to work this way.
This is the actual code of the function:
FILEENTRY* SearchFileByPkgID(int ID, NAMEENTRY fname)
{
FILEENTRY* myFile = (FILEENTRY*)calloc(sizeof(FILEENTRY),1);
std::vector<int> results;
unsigned int* dptable = GetDPTableByPkgId(ID);
bool found = false;
for(int x = 0; x < 1024; x++)
{
if(dptable[x] > 0)
{
fseek(PDBFILE, dptable[x], SEEK_SET);
fread(myFile, sizeof(FILEENTRY), 1, PDBFILE);
if(strcmp(myFile->FILENAME.EXT, fname.EXT) == 0)
if(myFile->FILENAME.NAME[0] == fname.NAME[0])
results.push_back(dptable[x]);
}
}
for(int y = 0; y < results.size(); y++)
{
fseek(PDBFILE, results[y], SEEK_SET);
fread(myFile, sizeof(FILEENTRY), 1, PDBFILE);
if(strcmp(myFile->FILENAME.NAME, fname.NAME) == 0)
{
found = true;
break;
}
}
results.clear();
if(found)
return myFile;
else
return 0L;
}
Any more suggestions are wellcome.

C Code Acting Differently to C++ on Lookup

I have the following code block (NOT written by me), which performs mapping and recodes ASCII characters to EBCDIC.
// Variables.
CodeHeader* tchpLoc = {};
...
memset(tchpLoc->m_ucpEBCDCMap, 0xff, 256);
for (i = 0; i < 256; i++) {
if (tchpLoc->m_ucpASCIIMap[i] != 0xff) {
ucTmp2 = i;
asc2ebn(&ucTmp1, &ucTmp2, 1);
tchpLoc->m_ucpEBCDCMap[ucTmp1] = tchpLoc->m_ucpASCIIMap[i];
}
}
The CodeHeader definition is
typedef struct {
...
UCHAR* m_ucpASCIIMap;
UCHAR* m_ucpEBCDCMap;
} CodeHeader;
and the method that seems to be giving me problems is
void asc2ebn(char* szTo, char* szFrom, int nChrs)
{
while (nChrs--)
*szTo++ = ucpAtoe[(*szFrom++) & 0xff];
}
[Note, the unsigned char array ucpAtoe[256] is copied at the end of the question for reference].
Now, I have an old C application and my C++11 conversion running side-by-side, the two codes write a massive .bin file and there is a tiny discrepancy which I have traced to the above code. What is happening for both codes is that the block
...
if (tchpLoc->m_ucpASCIIMap[i] != 0xff) {
ucTmp2 = i;
asc2ebn(&ucTmp1, &ucTmp2, 1);
tchpLoc->m_ucpEBCDCMap[ucTmp1] = tchpLoc->m_ucpASCIIMap[i];
}
gets entered into for i = 32 and the asc2ebn method returns ucTmp1 as 64 or '#' for both C and C++ variants great. The next entry is for i = 48, for this value the asc2ebn method returns ucTmp1 as 240 or 'ð' and the C++ code returns ucTmp1 as -16 or 'ð'. My question is why is this lookup/conversion producing different results for exactly the same input and look up array (copied below)?
In this case the old C code is taken as correct, so I want the C++ to produce the same result for this lookup/conversion. Thanks for your time.
static UCHAR ucpAtoe[256] = {
'\x00','\x01','\x02','\x03','\x37','\x2d','\x2e','\x2f',/*00-07*/
'\x16','\x05','\x25','\x0b','\x0c','\x0d','\x0e','\x0f',/*08-0f*/
'\x10','\x11','\x12','\xff','\x3c','\x3d','\x32','\xff',/*10-17*/
'\x18','\x19','\x3f','\x27','\x22','\x1d','\x35','\x1f',/*18-1f*/
'\x40','\x5a','\x7f','\x7b','\x5b','\x6c','\x50','\xca',/*20-27*/
'\x4d','\x5d','\x5c','\x4e','\x6b','\x60','\x4b','\x61',/*28-2f*/
'\xf0','\xf1','\xf2','\xf3','\xf4','\xf5','\xf6','\xf7',/*30-37*/
'\xf8','\xf9','\x7a','\x5e','\x4c','\x7e','\x6e','\x6f',/*38-3f*/
'\x7c','\xc1','\xc2','\xc3','\xc4','\xc5','\xc6','\xc7',/*40-47*/
'\xc8','\xc9','\xd1','\xd2','\xd3','\xd4','\xd5','\xd6',/*48-4f*/
'\xd7','\xd8','\xd9','\xe2','\xe3','\xe4','\xe5','\xe6',/*50-57*/
'\xe7','\xe8','\xe9','\xad','\xe0','\xbd','\xff','\x6d',/*58-5f*/
'\x79','\x81','\x82','\x83','\x84','\x85','\x86','\x87',/*60-67*/
'\x88','\x89','\x91','\x92','\x93','\x94','\x95','\x96',/*68-6f*/
'\x97','\x98','\x99','\xa2','\xa3','\xa4','\xa5','\xa6',/*70-77*/
'\xa7','\xa8','\xa9','\xc0','\x6a','\xd0','\xa1','\xff',/*78-7f*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*80-87*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*88-8f*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*90-97*/
'\xff','\xff','\xff','\x4a','\xff','\xff','\xff','\xff',/*98-9f*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*a0-a7*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*a8-af*/
'\xff','\xff','\xff','\x4f','\xff','\xff','\xff','\xff',/*b0-b7*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*b8-bf*/
'\xff','\xff','\xff','\xff','\xff','\x8f','\xff','\xff',/*c0-c7*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*c8-cf*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*d0-d7*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*d8-df*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*e0-e7*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*e8-ef*/
'\xff','\xff','\xff','\x8c','\xff','\xff','\xff','\xff',/*f0-f7*/
'\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff' };
In both C and C++, the standard doesn't require char to be a signed or unsigned type. It's implementation defined, and apparently, your C compiler decided char to be unsigned char, while your C++ compiler decided it to be signed char.
For GCC, the flag to make char to be unsigned char is -funsigned-char. For MSVC, it's /J.

Segmentation fault : Address out of bounds for a pointer in C

I am trying to build and run some complicated code that was written by someone else, I don't know who they are and can't ask them to help. The code reads a bpf (brain potential file) and converts it to a readable ascii format. It has 3 C files, and 2 corresponding header files. I got it to build successfully with minor changes, however now it crashes
with a segmentation fault.
I narrowed the problem down to FindSectionEnd() (in ReadBPFHeader.c) and find that the error occurs when sscanfLine() (in the file sscanfLine.c) is called (code for both is below).
ui1 is defined as unsigned char.
si1 is defined as char.
Just before returning from sscanfLine(), the address pointed to by dp is 0x7e5191, or something similar ending with 191. However, on returning to FindSectionEnd(), dp points to 0x20303035 and it says 'Address 0x20303035 is out of bounds', which then causes a fault at strstr(). The loop in FindSectionEnd() runs without problem for 14 iterations before the fault occurs. I have no idea what is going wrong. I really hope the information I have given here is adequate.
ui1 *FindSectionEnd(ui1 *dp)
{
si1 Line[256], String[256];
int cnt=0;
while (sscanfLine(dp, Line) != EOF){
dp = (ui1 *)strstr(dp, Line);
dp+= strlen(Line);
sscanf(Line,"%s",String);
if(SectionEnd(String))
return(dp);
}
return(NULL);
}
si1 *sscanfLine(ui1 *dp, si1 *s)
{
int i = 0;
*s = NULL;
int cnt = 0;
while (sscanf(dp, "%c", s + i) != EOF){
cnt++;
dp++;
if(*(s + i) == '\n') {
*(s + i + 1) = '\0';
return s;
}
++i;
}
*(s + i) = '\0';
return s;
}
The sscanfLine function doesn't respect the size of the buffer passed in, and if it doesn't find '\n' within the first 256 bytes, happily trashes the stack next to the Line array.
You may be able to work around this by making Line bigger.
If you're going to improve the code, you should pass the buffer size to sscanfLine and make it stop when the count is reached even if a newline wasn't found. While you're at it, instead of returning s, which the caller already has, make sscanfLine return the new value of dp, which will save the caller from needing to use strstr and strlen.
My first guess would be that your string is not null terminated and strstr() segfaults because it reads past the boundaries of the array

"Buffer too small" error on resized array (C++ / Win32)

I'm resizing an array. The resize (doubling the size) appears to work correctly, but when I send more text into the resized array, when it reaches what would have been the limit of the array before it was resized, I get a "Debug Assertion Failed! Expression: (L"Buffer is too small" && 0)" error. I've tried it a few different ways, always with the same result.
static int ReadBufferSize, totalChars;
static char *ReadBuffer = NULL;
ReadBuffer = (char *)malloc(ReadBufferSize);
...
//Double buffer size.
if((float)totalChars > (0.75f) * (float)ReadBufferSize)
{
char *tempBuffer = NULL;
tempBuffer = (char *)malloc(2 * ReadBufferSize);
if(tempBuffer == NULL)
free(tempBuffer);
else
{
memcpy(tempBuffer,ReadBuffer,strlen(ReadBuffer)+1);
free(ReadBuffer);
ReadBuffer = tempBuffer;
tempBuffer = NULL;
ReadBufferSize *= 2;
}
}
For my testing, ReadBufferSize has been set initially to 85 characters. After the code resizing the array is executed, the text in ReadBuffer is still displayed on the screen. I type more characters and they are sent into the array, and from there, displayed on the screen. But when the number of characters reaches 85 characters, I get the "Debug Assertion Failed! Expression: (L"Buffer is too small" && 0)" error, when there should now be space for 170 characters. I've also tried the following.
//Double buffer size.
if((float)totalChars > (0.75f) * (float)ReadBufferSize)
{
char* temp = 0;
temp = new char[2 * ReadBufferSize];
for(unsigned int i = 0; i < strlen(ReadBuffer); i++)
temp[i] = ReadBuffer[i];
temp[strlen(ReadBuffer)] = '\0';
delete[] ReadBuffer;
ReadBuffer = temp;
temp = 0;
ReadBufferSize *= 2;
}
I've also tried:
malloc(2 * ReadBufferSize * sizeof(char));
and:
strcpy_s(tempBuffer, strlen(ReadBuffer)+1, ReadBuffer);
Many thanks.
Since you didn't provided the full minimal program it's difficult to say what is wrong.
You should normally start your program in the debugger, put breakpoint inside your function and reproduce the problem. Take a look at all variables and functions like strlen(). They might return values that you don't expect.
Offtopic, but for real applications you should better use std::string which does all the tricks with memory management automatically.
I figured it out. I was about to post some more of my code to give you more information when I noticed the problem. I had a "pageSize" variable that I had been using for the size of the array. Then when I wanted to start dynamically changing the size, I separated the array size from the page size by creating the "ReadBufferSize" variable. Unfortunately, I still had "pageSize" in the segment of code where I was putting characters into the array:
strcat_s(ReadBuffer, pageSize, keystroke);
I've now changed it to
strcat_s(ReadBuffer, ReadBufferSize, keystroke);
and everything seems to be working. Thanks to everyone for taking the time to look at this. I was fixated on the idea that the problem must be in the section of code for resizing the array, not elsewhere.