segmentation fault cause by delete[] while writing to a file - c++

I'm trying to write to a file and i get a segmentation fault when i delete the allocated memory. I don't understant what is the problem, please help:
void writeToLog(string msg) {
int len = msg.size()+1;
char *text = new char(len);
strcpy(text,msg.c_str());
char* p = text;
for(int i=0; i<len; i++){
fputc(*p, _log) ;
p++;
}
delete[] text; //THIS IS WHERE IT CRASHES
}
I also tried without the [ ] but then i get
*** glibc detected *** ./s: free(): invalid next size (fast): 0x09ef7308 ***
So what is the problem?
Thanks!

This:
char *text = new char(len);
should be:
char *text = new char[len + 1];
And this is all unnecessary anyway. why are you doing it?

Well, delete[] doesn't balance new char(N), it balances new char[N]. The former creates a pointer to a single char and gives it the value N; the latter creates a pointer to an array of char with length N, and leaves the values indefined.
Of course, to write a std::string to a FILE *, why not just do:
fwrite(msg.c_str(), sizeof(char), msg.size() + 1, _log);
Note that preserves the trailing null character; so does your original code.

char *text = new char(len);
allocates just one char. Try with:
char *text = new char[len];

Try this:
char *text = new char[len];
Then:
delete[] text;

Although the technical issue has been answer (mismatched new/delete pair), I still think you could benefit from some help here. And I thus propose to help you trim your code.
First: there would not be any issue if you simply did not perform a copy.
void writeToLog(string msg) {
typedef std::string::const_iterator iterator;
for(iterator it = msg.begin(), end = msg.end(); it != end; ++it) {
fputc(*it, _log) ;
}
}
Note how I reworked the code to use C++ iterators instead of a mix of pointers and indices.
Second: what is this fputc call ?
You should not need to use a FILE* in your code. If you do, you are likely to get it wrong too and forget to close it, or close it twice etc...
The Standard Library provides the Streams collection to handle input and output, and for a log file the ofstream class seems particularly adapted.
std::ofstream _log("myLogFile");
void writeToLog(std::string const& msg) { // by reference (no copy)
_log << msg;
}
Note how it is much simpler ? And you cannot forget to close the file either, because if you do forget, then it'll be closed when _log is destructed anyway.
Of course at this point one might decide that it is superflous to have a function. However such a function allows you to prefix the message, typically with timestamps / PID / Thread ID or other decorations, so it's still nice.

Related

Convert from vector<unsigned char> to char* includes garbage data

I'm trying to base64 decode a string, then convert that value to a char array for later use. The decode works fine, but then I get garbage data when converting.
Here's the code I have so far:
std::string encodedData = "VGVzdFN0cmluZw=="; //"TestString"
std::vector<BYTE> decodedData = base64_decode(encodedData);
char* decodedChar;
decodedChar = new char[decodedData.size() +1]; // +1 for the final 0
decodedChar[decodedData.size() + 1] = 0; // terminate the string
for (size_t i = 0; i < decodedData.size(); ++i) {
decodedChar[i] = decodedData[i];
}
vector<BYTE> is a typedef of unsigned char BYTE, as taken from this SO answer. The base64 code is also from this answer (the most upvoted answer, not the accepted answer).
When I run this code, I get the following value in the VisualStudio Text Visualiser:
TestStringÍ
I've also tried other conversion methods, such as:
char* decodedChar = reinterpret_cast< char *>(&decodedData[0]);
Which gives the following:
TestStringÍÍÍýýýýÝÝÝÝÝÝÝ*b4d“
Why am I getting the garbage data at the end of the string? What am i doing wrong?
EDIT: clarified which answer in the linked question I'm using
char* decodedChar;
decodedChar = new char[decodedData.size() +1]; // +1 for the final 0
Why would you manually allocate a buffer and then copy to it when you have std::string available that does this for you?
Just do:
std::string encodedData = "VGVzdFN0cmluZw=="; //"TestString"
std::vector<BYTE> decodedData = base64_decode(encodedData);
std::string decodedString { decodedData.begin(), decodedData.end() };
std::cout << decodedString << '\n';
If you need a char * out of this, just use .c_str()
const char* cstr = decodedString.c_str();
If you need to pass this on to a function that takes char* as input, for example:
void someFunc(char* data);
//...
//call site
someFunc( &decodedString[0] );
We have a TON of functions and abstractions and containers in C++ that were made to improve upon the C language, and so that programmers wouldn't have to write things by hand and make same mistakes every time they code. It would be best if we use those functionalities wherever we can to avoid raw loops or to do simple modifications like this.
You are writing beyond the last element of your allocated array, which can cause literally anything to happen (according to the C++ standard). You need decodedChar[decodedData.size()] = 0;

strcat error "Unhandled exception.."

My goal with my constructor is to:
open a file
read into everything that exists between a particular string ("%%%%%")
put together each read row to a variable (history)
add the final variable to a double pointer of type char (_stories)
close the file.
However, the program crashes when I'm using strcat. But I can't understand why, I have tried for many hours without result. :/
Here is the constructor code:
Texthandler::Texthandler(string fileName, int number)
: _fileName(fileName), _number(number)
{
char* history = new char[50];
_stories = new char*[_number + 1]; // rows
for (int j = 0; j < _number + 1; j++)
{
_stories[j] = new char [50];
}
_readBuf = new char[10000];
ifstream file;
int controlIndex = 0, whileIndex = 0, charCounter = 0;
_storieIndex = 0;
file.open("Historier.txt"); // filename
while (file.getline(_readBuf, 10000))
{
// The "%%%%%" shouldnt be added to my variables
if (strcmp(_readBuf, "%%%%%") == 0)
{
controlIndex++;
if (controlIndex < 2)
{
continue;
}
}
if (controlIndex == 1)
{
// Concatenate every line (_readBuf) to a complete history
strcat(history, _readBuf);
whileIndex++;
}
if (controlIndex == 2)
{
strcpy(_stories[_storieIndex], history);
_storieIndex++;
controlIndex = 1;
whileIndex = 0;
// Reset history variable
history = new char[50];
}
}
file.close();
}
I have also tried with stringstream without results..
Edit: Forgot to post the error message:
"Unhandled exception at 0x6b6dd2e9 (msvcr100d.dll) in Step3_1.exe: 0xC00000005: Access violation writing location 0c20202d20."
Then a file named "strcat.asm" opens..
Best regards
Robert
You've had a buffer overflow somewhere on the stack, as evidenced by the fact one of your pointers is 0c20202d20 (a few spaces and a - sign).
It's probably because:
char* history = new char[50];
is not big enough for what you're trying to put in there (or it's otherwise not set up correctly as a C string, terminated with a \0 character).
I'm not entirely certain why you think multiple buffers of up to 10K each can be concatenated into a 50-byte string :-)
strcat operates on null terminated char arrays. In the line
strcat(history, _readBuf);
history is uninitialised so isn't guaranteed to have a null terminator. Your program may read beyond the memory allocated looking for a '\0' byte and will try to copy _readBuf at this point. Writing beyond the memory allocated for history invokes undefined behaviour and a crash is very possible.
Even if you added a null terminator, the history buffer is much shorter than _readBuf. This makes memory over-writes very likely - you need to make history at least as big as _readBuf.
Alternatively, since this is C++, why don't you use std::string instead of C-style char arrays?

memory allocation error while converting string to char*

I need some help figuring out a memory allocation error. I keep getting this error:
Error: Memory could not be allocated.
...when fList is large in the following code:
for (unsigned int ii=0; ii<fList.size(); ii++) {
char *fName = new char[fList[ii].length() + 1];
strcpy(fName, fList[ii].c_str());
err = xInitFile(fName, ii+1);
if(err != 0) {
cout << "FOOBAR" << endl;
}
delete[] fName;
}
fList is a std::vector<std::string>.
The function xInitFile is a C shared library function with the following prototype:
int xInitFile(char *fName, int fHandle)
If fList is small, then everything runs fine. I'm pretty sure the problem lies in how I'm converting the string to a char *, but I can't figure out how to fix it. As far as I can tell, fName is always deleted, so it doesn't appear to be a memory leak. My memory usage doesn't spike while running the code either.
EDIT:
Commenting out err = xInitFile(fName, ii+1); eliminates the error. That means the allocation error is occurring in the xInitFile, right? I didn't think to try this earlier, because I thought the problem was in my code (b/c I'm new to C++).
It's probably frowned upon for one reason or another, but I'd be inclined to instead try strdup.
char *fName = strdup( fList[ii].c_str() );
paired with
free(fName);

Simple C++ char array encryption function - Segment fault

As always, problems with the pointers. I am trying to create a very simple "encryption/decryption" function for char arrays. Yes, I know I can use strings, but I want to improve my knowledge about pointers and make use of simple bytes to achieve a simple task.
So, I created a simple struct like this:
struct text {
char* value;
int size;
}
And I created this simple function:
text encrypt(text decrypted) {
char key = 'X';
for (int i=0; i<decrypted.size; i++) {
decrypted.value[i] = decrypted.value[i] ^ (key + i) % 255);
}
return decrypted;
}
At this point, an experienced C++ programmer should have spot the problem, I think. Anyway, I call this function like this:
...
text mytext;
mytext.value = new char[5];
mytext.value = "Hello";
mytext.size = 5;
mytext = encrypt(mytext);
...
I get, like always, a 'Segmentation fault(core dumped)' error. This is Linux, and, of course, g++. What have I done, again? Thanks!
mytext.value = new char[5];
mytext.value = "Hello";
on the second line, you throw away the (handle to the) allocated memory, leaking it, and let mytext.value point to a string literal. Modifying a string literal is undefined behaviour, and usually crashes, since string literals are often stored in a read-only memory segment.
If you insist on using a char*, you should strncpy the string into the allocated memory (but be aware that it won't be 0-terminated then, you should better allocate a new char[6] and copy also the 0-terminator).
Or let decrypt create a new text that it returns:
text encrypt(text decrypted) {
char key = 'X';
text encrypted;
encrypted.size = decrypted.size;
encrypted.value = new char[encrypted.size];
for (int i=0; i<decrypted.size; i++) {
encrypted.value[i] = decrypted.value[i] ^ (key + i) % 255;
}
// What about 0-terminators?
return encrypted;
}
But, as you're using C++, std::string would be a better choice here.
You're modifying string literals:
mytext.value = "Hello";
after this, you can no longer legally mutate what mytext.value points to, you can only re-assign the pointer.
The fix: use std::string

Why does this code leak?

Well, here again, this time the compiler is showing me a memory error (leak):
otest(18015,0xacae32c0) malloc: * error for object 0x194e734:
incorrect checksum for freed object - object was probably modified
after being freed.
* set a breakpoint in malloc_error_break to debug
I'm using clang with ARC activated and STL, this is a C++ file (.cpp).
What I found: If I comment the "delete" line it runs without problems. It makes me wonder who is freeing my allocated memory (cStr).
Btw. This code takes a query string (arg=abc&arg2=asdb) and returns a map whit those values.
static map<string, string> getDecodedQueryString( string qs ) {
map<string, string> r;
qs = qs+"&";
char key[100], value[100], * cStr, *ptr;
cStr = new char[ qs.length() ];
memcpy( cStr, qs.c_str(), url.length()-1);
cStr[qs.length()]=0;
ptr = strtok(cStr, "&");
while ( ptr != NULL && sscanf( ptr, "%[^=]=%[^&]", &key, &value ) == 2) {
r[key]=value;
ptr = strtok(NULL, "&");
}
delete [] cStr; //leaking?
return r;
}
Thanks
The problem is likely in these lines:
cStr = new char[ qs.length() ];
memcpy( cStr, qs.c_str(), url.length()-1);
cStr[qs.length()]=0;
Even without the memcpy() (which may have its own problems due to the length of url, as I mentioned above in a comment), the cStr[qs.length()] = 0 writes one byte past the end of the buffer.
If your compiler has strdup() available (it's nonstandard, but most do), you can replace this with:
cStr = strdup(qs.c_str());
// ...
free(cStr);
This saves you from having to mess around with manually allocating bytes, copying them, null terminating in the right place, etc.
Str = new char[ qs.length() ];
...
cStr[qs.length()]=0;
That write is invalid, it's one past the end of cStr. If the allocator stored a checksum right after the allocation, and checks it at delete time, you've just stomped on it.
Something along the lines of below will do the same thing.
std::stringstream ss(qs);
std::string temp;
std::string key;
std::string value;
while(std::getline(ss, temp, '&')) {
std::stringstream equal(temp);
std::getline(equal, key, '=');
std::getline(equal, value, '=');
r[key] = value;
}