I'm making a C++ assignment for school and I've run into a peculiar problem. It's most likely memory corruption or whatever but as I am really mediocre at C++ I don't know how to solve it.
void Inventory::addItem(Item *item, const int stackCount) {
//find the item
Item *fi = findItem(item->id);
if(fi == nullptr)
{
Item *newItem = (Item *)malloc(sizeof(Item));
//std::cout << stackCount << std::endl;
memcpy(&newItem, &item, sizeof(Item));
newItem->stack = stackCount;
current.push_back(newItem);
}
}
I've got this piece of code, where it copies the Item's properties to another item. This works fine, and it carries everything over. Except something weird goes on with the stackCount variable.
There's a commented cout, and with it commented out the stackCount value is wrong. It will be at around 32k or so.
If it's not commented out, the value will be correct! Which is 1! (I am testing this in another function)
When placed behind the memcpy statement, the value is always wrong. Which of course leads me to believe that it's indeed memory corruption.
So I'm really quite confused. What exactly is c++ doing here?
memcpy(&newItem, &item, sizeof(Item));
What you're saying here is to copy from the address of item, aka a pointer to a pointer to an Item, to the address of newItem, aka another pointer to a pointer to an Item.
Since both of these are stack variables, and I'm guessing that sizeof(Item) != sizeof(Item**), you're invoking undefined behaviour here.
The reason the StackSize variable is only working when printing it is pure luck on your part; the compiler is most likeley just moving some variables around on the stack to try to optimize stack/register use, and moving the variable out of the area to be overwritten in the process.
Since you're using C++, you shouldn't be using memcpy in the first place. Write a copy constructor and an operator= instead to copy Item values.
Memcpy should get an address of destination and source.
You are passing "address to address".
Change:
memcpy(&newItem, &item, sizeof(Item));
to
memcpy(newItem, item, sizeof(Item));
Also, as stated by #Bathsheba and #Some-programmer-dude and #yksisarvinen, you shouldn't use malloc. Consider creating a copy constructor and/or assignment operator.
Related
Okay, so i was experimenting with pointers in C++, as i have started to code again after almost an year and a half break(School Stuff). So please spare me if this seems naive to you, i am just rusting off.
Anyways, i was screwing around with pointers in VS 2019, and i noticed something that started to bug me.
This is the code that i wrote:
#include <iostream>
int main() {
int* i = new int[4];
*i = 323;
*(i + 1) = 453;
std::cout << *i << std::endl;
std::cout << *(i + 1) << std::endl;
delete i;
}
Something seems odd right? Dont worry, that delete is intentional, and is kindof the point of this question. Now I expected it to do some memory mishaps, since this is not the way we delete an array on the heap, BUT to my surprise, it did not(I did this in both Debug and Release and had the same observation)
Allocating the array:
First Modification:
Second Modification
Now i was expecting some sort of mishap at delete, since i did not delete it the way it is supposed to be deleted. BUT
Deleting Incorrectly
Now on another run i actually used the delete operator correctly and it did the same thing:
Now i got the same results when i tried to allocate with malloc and use delete to free it.
So my question is - Why does my code not mess up? I mean if this is how it works, I could just use delete (pointer) to wipe the entire array.
The gist of my question is "What does new operator do under the hood?"
What happens on allocating with “new []” and deleting with just “delete”
The behaviour of the program is undefined.
Now I expected it to do some memory mishaps
Your expectation is misguided. Undefined behaviour does not guarantee mishaps in memory or otherwise. Nothing about the behaviour of the program is guaranteed.
I mean if this is how it works
This is how you observed it to "work". It doesn't mean that it will necessarily always work like that. Welcome to undefined behaviour.
I've met a situation that I think it is undefined behavior: there is a structure that has some member and one of them is a void pointer (it is not my code and it is not public, I suppose the void pointer is to make it more generic). At some point to this pointer is allocated some char memory:
void fooTest(ThatStructure * someStrPtr) {
try {
someStrPtr->voidPointer = new char[someStrPtr->someVal + someStrPtr->someOtherVal];
} catch (std::bad_alloc$ ba) {
std::cerr << ba.what << std::endl;
}
// ...
and at some point it crashes at the allocation part (operator new) with Segmentation fault (a few times it works, there are more calls of this function, more cases). I've seen this in debug.
I also know that on Windows (my machine is using Linux) there is also a Segmentation fault at the beginning (I suppose that in the first call of the function that allocates the memory).
More, if I added a print of the values :
std::cout << someStrPtr->someVal << " " << someStrPtr->someOtherVal << std::endl;
before the try block, it runs through the end. This print I've done to see if there is some other problem regarding the structure pointer, but the values are printed and not 0 or negative.
I've seen these topics: topic1, topic2, topic3 and I am thinking that there is some UB linked to the void pointer. Can anyone help me in pointing the issue here so I can solve it, thanks?
No, that in itself is not undefined behavior. In general, when code "crashes at the allocation part", it's because something earlier messed up the heap, typically by writing past one end of an allocated block or releasing the same block more than once. In short: the bug isn't in this code.
A void pointer is a perfectly fine thing to do in C/C++ and you can usually cast from/to other types
When you get a seg-fault while initialization, this means some of the used parameters are themselves invalid or so:
Is someStrPtr valid?
is someStrPtr->someVal and someStrPtr->someotherVal valid?
Are the values printed is what you were expecting?
Also if this is a multuthreaded application, make sure that no other thread is accessing those variables (especially between your print and initialization statement). This is what is really difficult to catch
I have the following method in a template class (a simple FIFO queue) and while GDB debugging, I found that the statement to reassign the pointer 'previous' to 'current' seems to do nothing.
previous starts as NULL and current is not NULL when this statement is executed, yet previous remains as NULL.
Has anyone seen anything like this before?
inline int search(QueueEntry<T> *current,QueueEntry<T> *previous, unsigned long long t)
{
while(current && !(current->getItem()->equals(t)))
{
previous = current; //**this line doesn't seem to work**
current = current->getNext();
}
if(current)
return 1;
return 0;
}
The assignment is optimized away by the compiler because it doesn't have any effect on the function's behavior. You reassign previous every time through the loop, but do nothing else with it.
The bug, if any, is in the rest of the function.
Where are you inspecting the value of previous? If you're doing it within this function, after the assignment, then make sure the build has optimizations turned off, and then try it again.
On the other hand, if you're watching previous outside the scope of this function, then it'll never get modified. When you call search() a copy of pointer previous gets loaded onto the stack and you're modifying this copy. The modification disappears after the function exits. To keep the modification around do something like this:
inline int search(QueueEntry<T> *current,QueueEntry<T> **previous, unsigned long long t)
{
...
*previous = current;
...
}
The call to search() will have to pass the address to the pointer now instead of the value.
Or, you can pass a reference and the rest of your code remains the same.
inline int search(QueueEntry<T> *current,QueueEntry<T> *&previous, unsigned long long t)
You never use your previous variable, therefore, especially if you're compiling with gcc -O2, it's considered a loop invariant, and is optimized away.
Try turning all your optimizations off.
It is likely that the compiler is noticing that that previous=current isn't necessary to do and is simply compiling it out
CARD& STACK::peek()
{
if(cards.size == 0)
{
CARD temp = CARD {-1, -1};
return temp;
}
return cards.back();
}
This is the function I am having trouble with.
CARD is just a struct with two int variables, called rank and suit.
STACK is a class that manages an std::vector<CARD>, that is called cards.
The function is supposed to return a reference to the card on top of the stack, or return the reference to a dummy card if the vector is empty.
First of all, I get a warning that says a reference to a local variable temp is returned. What is wrong with that? How will that effect the function? What do I do about it?
Second, I am trying to use this function with another function I created called cardToString
char* cardToString(CARD& c);
It is supposed to use the rank and suit variables in the passed CARD to look up string values in a table, concatenate the two strings together, and return a pointer to the new string.
So the end result looks like:
cout<<cardToString(deck.peek())<<"\n";
but this line of code will execute up to the cardToString function, then just stop for some reason. It is annoying the hell out of me because it just stops, there is no error message and there does not look like there is anything wrong to me.
Can somebody help me out?
Edit: here is the cardToString function
char *cardToString(const CARD& c)
{
if(c.r >= 13 || c.r < 0 || c.s >= 4 || c.s < 0)
{
std::cout<<"returned null";
return NULL;
}
char *buffer = new char[32];
strcpy(buffer, RANKS[c.r]);
strcat(buffer, " of ");
return strcat(buffer, SUITS[c.s]);
}
I specifically want the function STACK.peek() to return the address of the CARD that already exists on the top of the STACK. It seems to make more sense to do that than to create a copy of the card that I want to return.
First of all, I get a warning that says a reference to a local variable temp is returned. What is wrong with that? How will that effect the function? What do i do about it?
A local variable, as it name implies, is local to the function it belongs to, so it's destroyed as the function returns; if you try to return a reference to it, you'll return a reference to something that will cease to exist at the very moment the function returns.
Although in some cases this may seem to work anyway, you're just being lucky because the stack hasn't been overwritten, just call some other function and you'll notice it will stop working.
You have two choices: first of all, you can return the CARD by value instead of reference; this, however, has the drawback of not allowing the caller to use the reference to modify the CARD as is stored in the vector (this may or may not be desirable).
Another approach is to have a static dummy CARD instance stored in the STACK class, that won't have these lifetime problems, and that can be returned when you don't have elements in the vector; however, you should find a method to "protect" its field, otherwise a "stupid" caller may change the values of your "singleton" dummy element, screwing up the logic of the class. A possibility is to change CARD in a class that will encapsulate its fields, and will deny write access to them if it's the dummy element.
As for the cardToString function, you're probably doing something wrong with the strings (and I'm almost sure you're trying to return a local also in this case), but without seeing the body of the function it's difficult to tell what.
By the way, to avoid many problems with strings I suggest you to use, instead of char *, the std::string class, which takes away most of the ugliness and of the low level memory management of the usual char *.
Also, I'd suggest you to change cardToString to take a const reference, because most probably it doesn't need to change the object passed as reference, and it's good practice to clearly mark this fact (the compiler will warn you if you try to change such reference).
Edit
The cardToString function should be working fine, as long as the RANKS and SUITS arrays are ok. But, if you used that function like you wrote, you're leaking memory, since for each call to cardToString you make an allocation with new that is never freed with delete; thus, you are losing 32 bytes of memory per call.
As stated before, my tip is to just use std::string and forget about these problems; your function becomes as simple as this:
std::string cardToString(const CARD& c)
{
if(c.r >= 13 || c.r < 0 || c.s >= 4 || c.s < 0)
return "(invalid card)";
return std::string(RANKS[c.r]) + " of " + SUITS[c.s];
}
And you don't need to worry about memory leaks and memory allocations anymore.
For the reference/value thing: if the caller do not need to use the reference to modify the object stored in the vector, I strongly suggest passing it by value. The performance hit is negligible: two ints instead of one pointer means 8 vs 4 bytes on most 32 bit architectures, and 8 bytes vs 8 bytes on most 64 bit machines (and also accessing the fields via pointer has a small cost).
This kind of micro-optimization should be the last of your concerns. Your top priority is to write correct and working code, and the last thing you should do is to let micro-optimization get in the way of this aim.
Then, if you experience performance problems, you'll profile your application to find where the bottlenecks are and optimize those critical points.
You cannot return a reference to a local variable, because the local variable no longer exists when the function returns.
You need to return by-value, not by-reference (i.e. CARD STACK::peek() { ... }).
I've written a program that allocates a new object of the class T like this:
T* obj = new T(tid);
where tid is an int
Somewhere else in my code, I'm trying to release the object I've allocated, which is inside a vector, using:
delete(myVec[i]);
and then:
myVec[i] = NULL;
Sometimes it passes without any errors, and in some cases it causes a crash—a segmentation fault.
I've checked before calling delete, and that object is there—I haven't deleted it elsewhere before.
What can cause this crash?
This is my code for inserting objects of the type T to the vector:
_myVec is global
int add() {
int tid = _myVec.size();
T* newT = new T (tid);
if (newT == NULL){
return ERR_CODE;
}
_myVec.push_back(newT);
// _myVec.push_back(new T (tid));
return tid;
}
as it is - the program sometimes crash.
When I replace the push_back line with the commented line, and leave the rest as it is-it works.
but when I replace this code with:
int add() {
int tid = _myVec.size();
if (newT == NULL){
return ERR_CODE;
}
_myVec.push_back(new T (tid));
return tid;
}
it crashes in a different stage...
the newT in the second option is unused, and still - changes the whole process... what is going on here?
Segfaulting mean trying to manipulate a memory location that shouldn't be accessible to the application.
That means that your problem can come from three cases :
Trying to do something with a pointer that points to NULL;
Trying to do something with an uninitialized pointer;
Trying to do something with a pointer that pointed to a now deleted object;
1) is easy to check so I assume you already do it as you nullify the pointers in the vector. If you don't do checks, then do it before the delete call. That will point the case where you are trying to delete an object twice.
3) can't happen if you set NULL to the pointer in the vector.
2) might happen too. In you case, you're using a std::vector, right? Make sure that implicit manipulations of the vector (like reallocation of the internal buffer when not big enough anymore) doesn't corrupt your list.
So, first check that you delete NULL pointers (note that delete(NULL) will not throw! it's the standard and valid behaviour! ) - in your case you shouldn't get to the point to try to delete(NULL).
Then if it never happen, check that you're not having your vector fill with pointers pointing to trash. For example, you should make sure you're familiar with the [Remove-Erase idiom][1].
Now that you added some code I think I can see the problem :
int tid = _myVec.size();
You're using indice as ids.
Now, all depends on the way you delete your objects. (please show it for a more complete answer)
You just set the pointer to NULL.
You remove the pointer from the vector.
If you only do 1), then it should be safe (if you don't bother having a vector that grows and never get released and ids aren't re-used).
If you do 2. then this is all wrong : each time you remove an object from a vector, all the object still contains after the removed object position will be lowered by one. Making any stored id/index invalid.
Make sure you're coherent on this point, it is certainly a source of errors.
that segmentation fault is most probably and memory access violation. Some reasons
1) object already deallocated. be sure you set that array position on NULL after delete
2) you are out of array bounds
3) if you access that array from multiple threads make sure you are synchronizing correctly
If you're completely certain that pointer points to a valid object, and that the act of deleting it causes the crash, then you have heap corruption.
You should try using a ptr_vector, unlike your code, it's guaranteed to be exception-safe.
Hint: if you write delete, you're doing it wrong
You can't be sure that the object is still valid: the memory that was occupied by the object is not necessarily cleaned, and therefore, you can be seeing something that appears to be your object but it is not anymore.
You can use a mark in order to be sure that the object is still alive, and delete that mark in the destructor.
class A {
public:
static const unsigned int Inactive;
static const unsigned int Active;
A();
~A();
/* more things ...*/
private:
unsigned int mark;
};
const unsigned int A::Inactive = 0xDEADBEEF;
const unsigned int A::Active = 0x11BEBEEF;
A::A() : mark( Active )
{}
A::~A()
{
mark = Inactive;
}
This way, checking the first 4 bytes in your object you can easily verify whether your object has finished its live or not.