Reputation: 3031
Replaced vectors of wchar_t pointers with vectors of wstring.
I still get buffer overflow, but now the number of crashing places in the program has drastically reduced.
/****************************************************/
/* */
/* It was the string parser that caused buffer */
/* overflow ! */
/* */
/****************************************************/
It must be some improper use of vectors, but that will be left for another question.
For all those who tried to help, you get +1 from me.
I have tried your answers and they all worked.
I was afraid to use wstring since I am a beginner, but thanks to the help of the community I think I have managed to learn something new.
Thank you all, again.
Thank you all again.
Regards.
NOTE:
This is a simplified description, in order to keep this question as short as possible.
For further information ask additional questions, and I will provide more information.
I have a dialog box with 2 edit controls, 2 buttons and combo box.
On dialog creation, in WM_INIDIALOG, a connection is established with a database, which holds data about monthly salary of employees on a year basis.
Then primary keys of the employees are loaded into combo box.
Tables look like this:
Table_Employee < #primary_key, ...>
Table_Salary < #pk_salary, $primary_key, January, February, ..., Year>
Relationship is one to many, since one employee has data about monthly salary for every year, like this:
| January | ... | Year | #pk_salary| $primary_key| | 1000.51 | ... | 2012 | 100025558 | 48089989891 | | 2000.51 | ... | 2013 | 552025558 | 48089989891 | ...
Once a user selects a primary key from combo box , he is able to change the data about monthly salary by typing it in first edit control, and he must type in the year in the second edit control.
Entered data is held in a vectors declared like this:
INT_PTR CALLBACK dlgProcedure(HWND hwnd, UINT Message,
WPARAM wParam, LPARAM lParam )
{
static vector<wchar_t*> ee; // vector for monthly salaries and a year
// this vector holds data for all thes
tatic vector< vector<wchar_t*> > Pee; years
...
case WM_INITDIALOG:
{
// 12 months + 1 year = vector of 13 to store data
ee.assign( 13, LoadedValue );
...
After user pushes the first button , data for the month is saved in the above vector like this:
case IDC_BUTTON_MONTH:
{
// needed, since we have vector of wchar_t*
wchar_t *temp = new wchar_t[50];
GetDlgItemInt( ... , temp, ... );
UINT i = // ordinal of the month taken from checkbox
ee[ i ] = temp;
Then user must enter year, and after pushing the second button it is stored like this:
case IDC_BUTTON_YEAR:
{
wchar_t *temp = new wchar_t[50]; // needed, since we have vector of wchar_t*
GetDlgItemInt( ... , temp, ... );
ee[12] = temp;
// This means that all the data is collected
// so we can store this year’s data in the vector for years
Pee.push_back(ee);
This way, vector Pee holds data for all the years ( 2012, 2013, ... ), and vector ee holds the specifics ( monthly salary for a certain year ).
After selection in the combo box changes, I must clear all vectors, in order for new data to be stored.
When I do that I get the error, and my program snaps. Crash occurs also when I try to close the window.
If I comment out the section of the code that clears vectors, my program works, but then I can not use it to store new data, since vectors are not cleared properly.
Once I start program and change selection in combo box,a dialog box pops up, with 2 debuggers offered, and this message:
An unhandled exception occurred in SomeProgramName.exe[3300].
In Debug, in MS Visual Studio 2008, I have clicked on Exceptions, and checked everything. After I start the program in Debug mode, I get the dialog box with following message:
This may be due to a corruption of the heap, which indicates a bug in MyProgramName.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while MyProgramName.exe has focus.
The output window may have more diagnostic information.
As I have said above, after I comment out the cleanup code, error no longer occurs.
That is why I am very sure that there lies my problem.
Handler for WM_CLOSE:
case WM_CLOSE:
{
// cleanup
for( vector<wchar_t*>::size_type i = 0; i < ee.size(); i++)
delete[] ee[i];
ee.clear();
for( vector< vector<wchar_t*> >::size_type i = 0; i < pee.size(); i++)
for( vector<wchar_t*>::size_type j = 0; j < pee[i].size(); j++)
delete[] pee[i][j];
pee.clear();
DestroyWindow( hDlg );
}
return TRUE;
Handler for combo box:
case IDC_COMBO12:
{
if(HIWORD(wParam) == CBN_SELCHANGE )
{
// cleanup
for( vector<wchar_t*>::size_type i = 0; i < ee.size(); i++)
delete[] ee[i];
ee.clear();
for( vector< vector<wchar_t*> >::size_type i = 0; i < pee.size(); i++)
for( vector<wchar_t*>::size_type j = 0; j < pee[i].size(); j++)
delete[] pee[i][j];
pee.clear();
// assign neutral values to vectors
ee.assign( 13, L”-1” );
for( int i = 2012; i < currentYear; i++ )
Pee.push_back(ee);
// other commands, like loading data from database and so on...
Since I have a vector of pointers (vector < wchar_t* >
) , I believe that I can’t just use clear()
method to empty the vector since it would cause memory leaks.
That is why, in my opinion, I must delete pointer first, and only then use clear()
method.
This is my first time using vector of wchar_t*
, so I ask the community what am I doing wrong here?
How should I correctly reset those vectors in my handlers ?
Ask for additional information, I will gladly provide them.
Upvotes: 2
Views: 549
Reputation: 3294
The reason for the crash: you define vector<wchar_t*>
, fill your vector with ee.assign( 13, L”-1” );
and with wchar_t *temp = new wchar_t[50];
and delete with delete[]
. All mismatched.
delete[]
operator frees memory allocated on the heap
ee.assign( 13, L”-1” );
passes compiler allocated objects. That is wrong. These are not on the heap and you shouldn't free that memory, but you do that when you call delete[]
.
You may define your vector as vector<std::wstring>
Then use it as
std::vector<std::wstring> v;
v.assign(10,L"xyz");
std::wstring s = L"abc";
v.push_back(s);
... etc.
v.clear(); // call destructor for every std::wstring in the vector
In your button handler:
wchar_t temp[50];
GetDlgItemTxt( ... , temp, ... );
v[i] = temp; // creates a wstring object and copies temp in there
You may define your vector as you did and use new and delete but you'll need a very good reason for that. You are taking responsibility for memory allocated for objects in the vector. You can't mix pointers allocated on the heap, on the stack or allocated statically (e.g. string literals L"-1").
vector<wchar_t*> v;
v.assign(10, 0); // fill in with null pointers
wchar_t *ptr = new wchar_t[10];
... fill in ptr memory with data
v.push_back(ptr);
... etc.
// Now you need to free memory you allocated manually - You do not do that
// in case of std::vector<std::wstring>
for (vector<wchar_t*>::iterator it = v.begin(); it != v.end(); ++it)
delete[] *it;
v.clear(); // clear function calls destructor for every object in the vector.
// There is no destructor for a pointer, hence the difference between
// deallocating vector<wstring> and vector<wchar_t*>
Upvotes: 1
Reputation: 37202
Since I have a vector of pointers ( vector < wchar_t* > )
There's your problem right there. Don't use a vector of pointers. Use a vector of std::wstring
. Then you don't have to worry about any of this.
Edit: To use std::wstring
with GetDlgItemText
you can do:
std::vector<std::wstring> ee;
wchar_t wchScratch[1024]; // should be big enough for any string you've added
GetDlgItemText(hWnd, iID, wchScratch, sizeof(wchScratch) / sizeof(wchScratch[0]));
ee.push_back(wchScratch);
Or, if you want something more complicated, you can do:
int iLength = GetWindowTextLength(GetDlgItem(hWnd, iID));
std::wstring strTemp;
strTemp.resize(iLength + 1);
strTemp.resize(GetDlgItemText(hWnd, iID, &strTemp[0], strTemp.size()));
ee.push_back(strTemp);
Basically, nothing changes about how you get the string from the control, you are just changing how you store it.
Upvotes: 5