I'm writing a Win32 console application in Visual Studio 2010.
Consider one function that take two char* as parameters.
Following is prototype of function:
void WriteApplicationFile(char *mappname,char* MessageString)
{
//Do some File related stuffs.
}
Now the following calls are working perfectly:
WriteApplicationFile("FirstOne", "Append Me");
WriteApplicationFile("FirstOne", "Append Another");
But if I try the same thing with some character array thing this will give me assertion, and throw me on assembly.
The following code is not working:
char * LocalBuffer = new char[100];
sprintf(LocalBuffer,"Number of jobs in Queue %d",JobsCount);
WriteApplicationFile("SAAZshadowProtect",LocalBuffer);
free(LocalBuffer);
LocalBuffer = NULL;
//Work fine.
//...
LocalBuffer = new char[100];
sprintf(LocalBuffer,"Log file name %s",LogFileCharName);
WriteApplicationFile("SAAZshadowProtect",LocalBuffer);
free(LocalBuffer); // I got assertion here..
LocalBuffer = NULL;
Where am I going wrong?
One more thing is that I want to handle all assertion and bugs with try-catch block. How would I do this?
If use new[] you must use delete[], not free() or delete. Replace:
free(LocalBuffer);
with:
delete[] LocalBuffer;
There appears to be no reason to be dynamically allocating memory. The size of the buffer is a compile time constant, is not large (no stack overflow) and the buffer appears to not be required to live beyond the scope in which it was allocated.
As this is c++ strongly suggest using std::string which will handle dynamic memory management for you and std::ostringstream which is typesafe and avoids specification of fixed sized buffers instead of sprintf():
#include <sstream>
#include <string>
std::ostringstream out;
out << "Number of jobs in Queue " << JobsCount;
const std::string s(out.str());
If access to a c-style string is required use std::string::c_str().
Additionally, the argument types of WriteApplicationFile() are char*, not const char*, so passing a string literal to the function would be causing undefined behaviour if the function modifies the arguments.
First, are you programming in C or in C++. The code you present
looks like C, but you speak of a try/catch block, which can only
be C++.
In C++, use std::ostringstream and std::string. Any other
solution is simply incorrect.
In C, you should use snprintf, instead of sprintf. It is
almost impossible to use sprintf safely. (How many characters
are in LogFileCharName, for example.) And don't use dynamic
allocation when you don't have to. (That holds for C++ as
well; there should be no new or delete (nor malloc nor
free) in the code you show.
As to what is going wrong, there are at least two possible
problems in the code you show: you're allocating memory with
new[], but freeing it with free (undefined behavior), and
you're not checking the length of LogFileCharName before
calling sprintf, so you could be overwriting the end of the
buffer.
Related
I am trying to concatenate two char arrays using the function strcat(). However the program crashes.
#include <cstdio>
#include <cstring>
int main() {
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
const char *file_bk_path = strcat(strdup(file_path), ".bk");
printf("%s\n", file_bk_path);
return 0;
}
The strangest thing to me is that the program indeed produces an output before crashing:
D:/MyFolder/YetAnotherFolder/test.txt.bk
What is the reason for this problem and how it can be fixed?
Error state is reproduced in Windows (MinGW 7.2.0).
strdup is creating new memory for you to hold a duplicate of the string. The memory is only as long as strlen(file_path) + 1. You then try to add an extra 2 characters into memory that you don't own. You will go out of range of the memory created and create some undefined behaviour. It might print because setting the memory and printing the first part could be happening correctly, but it is undefined and anything can happen. Also note, in strdup you need to call free on the memory it creates for you, or you are going to leak some memory.
Here is a much simpler way to do this, use a std::string:
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
std::string file_bk_path = std::string(file_path) + ".bk";
std::cout << file_bk_path << "\n";
Here is a live example.
If it absolutely needs to be in C-style then you are better off controlling the memory yourself:
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
const char *bk_string = ".bk";
char *file_bk_path = malloc((strlen(file_path) + strlen(bk_string) + 1)*sizeof(char));
if (!file_bk_path) { exit(1); }
strcpy(file_bk_path, file_path);
strcat(file_bk_path, bk_string);
printf("%s\n", file_bk_path);
free(file_bk_path);
Here is a live example.
As mentioned in the comments and answers, strdup mallocs the length of your path string, plus an extra cell for the string end character '\0'. When you concatenate to this two characters writing after the allocated area.
Following #Ben's comments, I'd like to elucidate some more:
To be clear strcat adds a delimiter, but this is already after the memory you were allocated.
In general unless you specifically hit no-no addresses, the program will probably run fine - in fact this is a common hard to find bug. If for example you allocate some more memory right after that address, you will be deleting said delimiter (so printing the string will read further into the memory.
So in general, you may be OK crash wise. The crash (probably) occurs when the program ends, and the OS cleans up the memory you forgot to free yourself - That extra cell is a memory leak, and will cause the crash. So you do get a full print, and only after a crash.
Of course all of this is undefined behavior, so may depend on the compiler and OS.
Consider:
CCustomDateTime::CCustomDateTime()
{
LPTSTR result = new TCHAR[1024];
time_t _currentTime_t = time(0);
tm now;
localtime_s(&now, &_currentTime_t);
_tasctime_s(result, _tcslen(result), &now);
_currentTime = result;
delete[] result; // Error occurs here
}
CCustomDateTime::~CCustomDateTime()
{
}
__int64 CCustomDateTime::CurrentTimeAsInt64()
{
return _currentTime_t;
}
LPTSTR CCustomDateTime::CurrentTimeAsString()
{
return _currentTime;
}
I am unable to figure out the safest place to call delete[] on result.
If delete[] is ignored everything is fine, but otherwise an error occurs:
HEAP CORUPTION DETECTED at line delete[]
_tcslen(result) is not doing what you think it is.
change
_tasctime_s(result, _tcslen(result), &now);
to
_tasctime_s(result, 1024, &now);
There are a few problems with your code that I can see:
You don't check any of the function calls for errors. Don't ignore the return value. Use it to check for errors.
The second argument to _tasctime_s is the number of elements in the buffer provided. In other words, 1024. But you pass _tcslen(result) which is the length of the null-terminated string. Not only is that the wrong value, but result is at that point not initialised, so your code has undefined behaviour.
You assign a value to _currentTime, and then immediately delete that memory. So, _currentTime is a stale pointer. Any attempt to read from that memory is yet more undefined behaviour.
I don't want to tell you what your code should be, because you have only given us a tiny window into what you are trying to achieve. Dynamically allocating a fixed length array seems pointless. You may as well use automatically allocated storage. Of course, if you do want to return the memory to the caller, then dynamic allocation makes sense, but in that case then surely the caller would be responsible for calling delete[]. Since this code is clearly C++ I have to wonder why you are using raw memory allocation. Why not use standard library classes like std::string?
Looking at your update to the question, you could deallocate the memory in the destructor of your class. Personally though, I would recommend learning about the standard library classes that will greatly simplify your code.
_tcslen maps to strlen or wcslen depending on whether you are using ANSI or Unicode, respectively.
Both these functions return the length of a string, not the size of the buffer. In other words, they take a pointer to the first character of a string and continuously increment the pointer in search of a null terminator.
Calling these functions on an uninitialized buffer is undefined behavior because there's a very good chance that the pointer will get incremented out of the array bounds and elsewhere into the process' memory.
This is a fairly basic question and I am pretty sure I know the answer, but seeing as the consequence for being wrong is a segfault I figure I should ask. I have been using strlen() and the new char[] operator in the following way for quite some time now and just noticed something that threw up a red flag:
void genericCopy(char *somestring, char *someOtherString) {
someOtherString = new char[strlen(somestring)];
strcpy(someOtherString,somestring);
}
My question is, seeing as a string should be null terminated, should I be doing this as such:
void genericCopy(char *somestring, char *someOtherString) {
someOtherString = new char[strlen(somestring)+1];
strcpy(someOtherString,somestring);
someOtherString[strlen(someOtherString)] = '\0';
}
So far I have never had a problem with the first method, but that doesn't mean I'm doing it right. Since the length being return by strlen()is the number of characters in the string without the null terminator so new isn't reserving space for '/0'... At least I don't think it is.
First of all, you should know that this function of yours is pointless to write, just use strdup (if available on your system).
But yes, you need an additional byte to store the \0, so always do something like new char[strlen(somestring)+1];. However, there is no need to manually add the \0; strcpy already does this.
You should use something like Valgrind to discover this and similar bugs in your code.
There is however an additional problem in your code; your code will always leak someOtherString; it will not be returned to where you called it from. You either need to change your method to something like:
char *genericCopy(char *something) {
char *copy = new char[strlen(somestring)+1];
strcpy(copy,somestring);
return copy;
}
and then get the copy as follows:
copy = genericCopy(something);
Or you need to change your method to something like:
void genericCopy(char *something, char **copy) {
*copy = new char[strlen(somestring)+1];
strcpy(*copy,somestring);
}
and call it as:
genericCopy(something, ©);
If you'll be using C++ you could also just change the method prototype to:
void genericCopy(char* somestring, char*& someOtherString)
and call it as:
genericCopy(something, copy);
Then someOtherString will be passed as a reference, and the new value you allocate to it will propagate outside of your method.
Yes, your suspicion is correct. You should be allocating an additional character, and making sure the copied string is null-terminated. (strcpy() itself will do this, but when someone advises to you that you switch to strncpy(), as they no doubt will (it's safer!) you'll need to be extra careful, because it is NOT guaranteed to copy the '/0'.)
If you're already using C++, though, you may be well-advised to switch to using std::string. It's often an easier, less error-prone method of manipulating character arrays.
However, here's the further problem that you need to address. You are assigning your new character array to a COPY of someOtherString. You need to make some changes:
void genericCopy(char *somestring, char **someOtherString) {
*someOtherString = new char[strlen(somestring)+1];
strcpy(*someOtherString,somestring);
(*someOtherString)[strlen(somestring)] = '\0';
}
This way you will get back the new character buffer outside your function call.
I'm writing a C++ program, that stores strings in a string array, when the array is full I resize the array to make space for more items using the code below. But sometimes (not always) it crashes at the "delete[] temp;" line and I don't know why and how to fix it. Please, help.
I have searched a lot but could not find an answer anywhere. When I debug it says "invalid pointer" but how can it be invalid when I stored data there before and did not free it yet?
This is my code:
if(item_cnt >= (arr_size - 1))
{
int oldsize = arr_size;
string * temp;
arr_size *= 2;
temp = arr;
arr = new string [arr_size];
memcpy(arr, temp, oldsize * sizeof(temp));
delete[] temp;
}
Unless you absolutely have to stick with your current approach, I would recommend using a vector to hold your strings. It will manage all the memory for you.
Here's an example:
#include <vector>
#include <string>
int main()
{
std::vector<std::string> arrayOfStrings;
arrayOfStrings.push_back("Hello World!"); // To Add Items
string value = arrayOfString.at(<some index>); // To Retrieve an Item you can also use the [] operator instead of the at method
return 0;
}
The memcpy is at the root of your problem. everyone's said "don't use it", but let me explain exactly why it's a terminally bad idea.
First off, what is a c++ string, and how does it do its magic? It's basically a variable-length array of characters, and it achieves this feat by holding a pointer within each string object that points to the memory allocated to hold those characters. As the string grows or shrinks, that memory gets reallocated. Copy strings properly involves making a 'deep copy' of the contents.
Now, to your code:
arr = new string [arr_size];
This creates an array of empty string objects. Because they're empty, the internal pointers are typically null.
memcpy(arr, temp, oldsize * sizeof(temp));
Here, bad things happen. This isn't actually creating copies of the original strings, it's just overwriting the internal representation. So both the old and the new strings 'point' to the same character data. Now to really screw things up, this happens:
delete[] temp;
We delete thew old strings, but this also frees up the character memory that they were using. So our 'new' copies of these strings are pointing at memory that's actually been freed. We now have a car-crash waiting to happen : The character data could be re-used for anything, and when we try and delete the strings again, the operating system will hopefully spot that you're trying to free memory that hasn't been allocated.
Your array should be really
vector<string>
This is a recommended way of implementing arrays of dynamic size. By using vector you avoid necessity to reallocate/copy stuff manually and avoid problems like the one you have altogether.
Mixing old style and new style memory operations is always a bad idea... here you use memcpy and new/ delete. be aware that delete[] also calls the dtor for each element of the array...
Edit:
ctor --> dtor
hth
Mario
Is it possible to somehow adapt a c-style string/buffer (char* or wchar_t*) to work with the Boost String Algorithms Library?
That is, for example, it's trimalgorithm has the following declaration:
template<typename SequenceT>
void trim(SequenceT &, const std::locale & = std::locale());
and the implementation (look for trim_left_if) requires that the sequence type has a member function erase.
How could I use that with a raw character pointer / c string buffer?
char* pStr = getSomeCString(); // example, could also be something like wchar_t buf[256];
...
boost::trim(pStr); // HOW?
Ideally, the algorithms would work directly on the supplied buffer. (As far as possible. it obviously can't work if an algorithm needs to allocate additional space in the "string".)
#Vitaly asks: why can't you create a std::string from char buffer and then use it in algorithms?
The reason I have char* at all is that I'd like to use a few algorthims on our existing codebase. Refactoring all the char buffers to string would be more work than it's worth, and when changing or adapting something it would be nice to just be able to apply a given algorithm to any c-style string that happens to live in the current code.
Using a string would mean to (a) copy char* to string, (b) apply algorithm to string and (c) copy string back into char buffer.
For the SequenceT-type operations, you probably have to use std::string. If you wanted to implement that by yourself, you'd have to fulfill many more requirements for creation, destruction, value semantics etc. You'd basically end up with your implementation of std::string.
The RangeT-type operations might be, however, usable on char*s using the iterator_range from Boost.Range library. I didn't try it, though.
There exist some code which implements a std::string like string with a fixed buffer. With some tinkering you can modify this code to create a string type which uses an external buffer:
char buffer[100];
strcpy(buffer, " HELLO ");
xstr::xstring<xstr::fixed_char_buf<char> >
str(buffer, strlen(buffer), sizeof(buffer));
boost::algorithm::trim(str);
buffer[str.size()] = 0;
std::cout << buffer << std::endl; // prints "HELLO"
For this I added an constructor to xstr::xstring and xstr::fixed_char_buf to take the buffer, the size of the buffer which is in use and the maximum size of the buffer. Further I replaced the SIZE template argument with a member variable and changed the internal char array into a char pointer.
The xstr code is a bit old and will not compile without trouble on newer compilers but it needs some minor changes. Further I only added the things needed in this case. If you want to use this for real, you need to make some more changes to make sure it can not use uninitialized memory.
Anyway, it might be a good start for writing you own string adapter.
I don't know what platform you're targeting, but on most modern computers (including mobile ones like ARM) memory copy is so fast you shouldn't even waste your time optimizing memory copies. I say - wrap char* in std::string and check whether the performance suits your needs. Don't waste time on premature optimization.