Sign in to follow this  

unknown cause of exception

This topic is 4223 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm having a problem with one of my functions causing an exception but I can't figure out why. I've narrowed it down to one line in the function that calls another function so I'm not sure if the error is in the calling function or the function called.. this only happens when I run it straight from the folder and not within visual C 8. It also has different behavior when I run it straight from the folder but I don't know why.
void SerialGen()
{ 
	char alpha[80] ="ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
	char* ppasswrd = NULL;
	wchar_t* wppasswrd = new wchar_t[11];
	char passwrd[80]="";
		
	int numChars = 20;
	
	for (int n=0; n<numChars; n++)
	{
		int x;
		x = 0 + int(35.0 * rand()/(RAND_MAX+1.0));
		passwrd[n]= alpha[x];
	}
	
	ppasswrd = passwrd;

	memset(wppasswrd,0,sizeof(wppasswrd));

	MultiByteToWideChar(  CP_ACP, NULL,ppasswrd, -1, wppasswrd,numChars );

	AddString(wppasswrd); // this is the line that causes an exception

	getchar();
	wppasswrd = NULL;
	delete[] wppasswrd;

}



here's the funtion called which works fine with passing TEXT("blah") to it but I don't know if it's causing the above problem when passing the wchar_t pointer.
STRINGSTRUCT* AddString(LPCWSTR StringToAdd)
{
	if(FirstString == NULL)
	{
		FirstString = new STRINGSTRUCT;
		LastString = FirstString;

		LastString->Next = NULL;
	}
	else
	{
		LastString->Next = new STRINGSTRUCT;

		LastString = LastString->Next;
		LastString->Next = NULL;
	}

	size_t len;

	LastString->DisplayString = StringToAdd;
	StringCchLength(StringToAdd, 512, &len);

	LastString->StringLength = len;

	return LastString;
}



can anyone help me out?

Share this post


Link to post
Share on other sites
Looks like your wchar_t string is overwriting the boundary... one line BEFORE you say.

Your wchar_t array should at least be the same size as the password... and you're only allocating 11 for it.

Share this post


Link to post
Share on other sites
well I was only allocating 11 for it cause it's 2 bytes and the password is only 20 chars long of 1 byte. for some reason if I make the wppasswrd anything other than 11 or 12 I get extra blank characters printed on screen with my password generated.

Share this post


Link to post
Share on other sites
Quote:
Original post by etsuja
well I was only allocating 11 for it cause it's 2 bytes and the password is only 20 chars long of 1 byte. for some reason if I make the wppasswrd anything other than 11 or 12 I get extra blank characters printed on screen with my password generated.


you need wchar_t[20] or larger... because MultiByteToWideChar() will write 20 wchar_t's into the array, which is 40 bytes.

You should probably make the array 21 wide chars long, and use ZeroMemory or memset to clear it first, too.


void SerialGen()
{
char alpha[80] ="ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
char* ppasswrd = NULL;
wchar_t* wppasswrd = new wchar_t[21];

char passwrd[80]="";

int numChars = 20;

for (int n=0; n<numChars; n++)
{
int x;
x = 0 + int(35.0 * rand()/(RAND_MAX+1.0));
passwrd[n]= alpha[x];
}

ppasswrd = passwrd;

memset(wppasswrd,0,sizeof(wppasswrd));

MultiByteToWideChar( CP_ACP, NULL,ppasswrd, -1, wppasswrd,numChars );

AddString(wppasswrd); // this is the line that causes an exception

getchar();

// whoa! and the following will leak memory
// wppasswrd = NULL;
// delete[] wppasswrd;

// do this instead

delete[] wppasswrd;
wppasswrd = NULL;

}

Share this post


Link to post
Share on other sites
I set the length to 21 and I tried using zeromemory and memset but it prints the password with this after it when running from VC8 |||||||| and ||| when running from the folder. And I don't think I can use delete[] on it cause it clears the password. I don't know where I can deallocate it unless I make it global. maybe I could return it and then delete it outside the function? When it's 21 I don't get that exception though.

EDIT: nevermind I just figured out why it was doint it I changed
MultiByteToWideChar( CP_ACP, NULL,ppasswrd, -1, wppasswrd,numChars )
to
MultiByteToWideChar( CP_ACP, NULL,ppasswrd, -1, wppasswrd,(numChars + 1) )

Share this post


Link to post
Share on other sites
Quote:
Original post by etsuja
I set the length to 21 and I tried using zeromemory and memset but it prints the password with this after it when running from VC8 |||||||| and ||| when running from the folder. And I don't think I can use delete[] on it cause it clears the password. I don't know where I can deallocate it unless I make it global. maybe I could return it and then delete it outside the function? When it's 21 I don't get that exception though.


memset(wppasswrd,0,sizeof(wchar_t) * 21);

And if you don't want to clear the password... then don't delete wppassword
[smile]

Just remember to delete the array somewhere... keep a pointer to the wchar_t array in your struct, or something, and then delete it when your STRINGSTRUCT is deleted... perhaps in the destructor.

Share this post


Link to post
Share on other sites
wait if DisplayString in my struct = StringToAdd and wppasswrd is getting passed to AddString isn't it already getting deleted when I delete my struct?

Share this post


Link to post
Share on other sites
Quote:
Original post by etsuja
wait if DisplayString in my struct = StringToAdd and wppasswrd is getting passed to AddString isn't it already getting deleted when I delete my struct?


Not unless you have explicit code in your struct's destructor to take care of those. You'll have memory leaks unless you call "delete" for everything you've called "new" for, and "delete[]" for everything you've called "new[]" for.



// delete FirstString calls...

STRINGSTRUCT::~STRINGSTRUCT()
{
// you have to iterate through your linked list, and delete
// all "DisplayString" like this

// delete[] Next->DisplayString;

// THEN You have to iterate through, deleting all "Next"... which might
// blow the stack, if your linked list is very long (delete Next; would
// recursively call the destructor STRINGSTRUCT::~STRINGSTRUCT())
}


This is where smart pointers can really help you... with the "Next" pointers. If you declared "Next" a smart pointer in your struct, instead of just "STRINGSTRUCT *Next", it would mean you'd only have to explicitly go through and delete[] Next->DisplayString.

You'd no longer have to call "delete Next" in the destructor, and potentially blow the stack with a long linked list.

boost::shared_ptr and Loki::SmartPtr are good places to start.

Share this post


Link to post
Share on other sites
Well I tried this and got an assertion failure:


void DeleteAllStrings()
{
STRINGSTRUCT* ThisString = FirstString;
STRINGSTRUCT* DeadString = NULL;

while(ThisString != NULL)
{
DeadString = ThisString;
delete[] DeadString->DisplayString;
ThisString = ThisString->Next;
delete DeadString;
}
FirstString = NULL;
LastString = NULL;
}




I also tried regular delete too

Share this post


Link to post
Share on other sites
That code looks fine (to me)

When does it assert? Have you single-stepped through?

Does it assert on the first delete[], the first delete, or after everything is deleted?

Are there any other deletes or delete[]s in your code?

Share this post


Link to post
Share on other sites
Stop using manually allocated blocks of memory.

Use std::wstring, std::string, std::vector<char> and std::vector<wchar_t>.

As you may have noticed, keeping track of who owns what block of memory is hell. So don't do it. Make copies of your strings willy nilly. Only in the extremely rare cases where you need every ounce of performace does it make sense to carry around pointers to manually allocated blocks of memory.

Share this post


Link to post
Share on other sites
Quote:
Original post by NotAYakk
Stop using manually allocated blocks of memory.

Use std::wstring, std::string, std::vector<char> and std::vector<wchar_t>.

As you may have noticed, keeping track of who owns what block of memory is hell. So don't do it. Make copies of your strings willy nilly. Only in the extremely rare cases where you need every ounce of performace does it make sense to carry around pointers to manually allocated blocks of memory.


Quoted for extreme emphasis. (Also, don't make your own linked list; use std::list.)

You are doing a *lot* of *very* error-prone things. Stop it. Now.


template <typename number>
struct random() {
int limit;
random(int limit) : limit(limit) {}
number operator()() {
return static_cast<number>(static_cast<double>(limit) * rand() / (RAND_MAX + 1));
}
};

std::list<std::wstring> mystrings; // replaces wtf-ever you were doing with STRINGSTRUCT

void SerialGen() {
const std::string alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
const int password_length = 20;
// I am using this array as an array of characters and NOT as a string!
char tmp_password[password_length];
std::generate(tmp_password, tmp_password + password_length, random<int>(alpha.length()));
// Calculate the size of the buffer that is needed, and then create it.
size_t needed_space = MultiByteToWideChar(CP_ACP, 0, tmp_password, password_length, 0, 0);
vector<wchar_t> wide_password(needed_space);
// Do the actual conversion.
MultiByteToWideChar(CP_ACP, 0, tmp_password, password_length, &wide_password[0], needed_space);
// Create a string from the buffer and append it to the list.
mystrings.push_back(std::string(wide_password.begin(), wide_password.end()));
}

Share this post


Link to post
Share on other sites

This topic is 4223 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this