2

I have a code snippet like below. I have created some Dynamic memory allocation for my Something class and then deleted them. The code print wrong data which I expect but why ->show does not crash? In what case/how ->show will cause crash? Is it possible to overwrite the same memory location of i, ii, iii with some other object?

I am trying to understand why after delete which frees up the memory location to be written with something else still have information about ->show!

#include <iostream>
#include <vector>

class Something
{
public:

  Something(int i) : i(i)
  {
    std::cout << "+" << i << std::endl;
  }

  ~Something()
  {
    std::cout << "~" << i << std::endl;
  }

  void show()
  {
    std::cout << i << std::endl;
  }
private:
  int i;

};

int main()
{
  std::vector<Something *> somethings;

  Something *i = new Something(1);
  Something *ii = new Something(2);
  Something *iii = new Something(3);

  somethings.push_back(i);
  somethings.push_back(ii);
  somethings.push_back(iii);

  delete i;
  delete ii;
  delete iii;

  std::vector<Something *>::iterator n;
  for(n = somethings.begin(); n != somethings.end(); ++n)
  {
    (*n)->show(); // In what case this line would crash? 
  }

  return 0;
}
pmoubed
  • 3,842
  • 10
  • 37
  • 60
  • 8
    Undefined behavior does not necessarily cause a crash. Its behavior is... well, undefined. – Fred Larson May 06 '19 at 16:05
  • is there a way to make it crash definitely maybe by writing in same memory location another type of object? – pmoubed May 06 '19 at 16:06
  • 2
    [ASan](https://clang.llvm.org/docs/AddressSanitizer.html) makes it [crash](https://coliru.stacked-crooked.com/a/332345fbe9c44d5d). – nwp May 06 '19 at 16:08
  • 1
    @PMoubed -- I'll have to ask -- why are you seemingly trying to get the program to crash? Is it because you wrote some other code using pointers where you are not confident of the soundness of the code, and hoping that the "crash" helps you in finding the error? If this is the case, I'm sorry to say that C++ doesn't work this way. – PaulMcKenzie May 06 '19 at 16:23
  • related: https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope – default May 06 '19 at 16:30
  • Possible duplicate of [What happens to the pointer itself after delete?](https://stackoverflow.com/questions/23621677/what-happens-to-the-pointer-itself-after-delete) or [Pointers in c++ after delete](https://stackoverflow.com/questions/44182049/pointers-in-c-after-delete) or maybe [Reusing a pointer to array after deletion](https://stackoverflow.com/questions/30493389/reusing-a-pointer-to-array-after-deletion) – crashmstr May 06 '19 at 16:39
  • I guess I was trying to learn by example here. – pmoubed May 06 '19 at 16:40
  • 1
    Learning by example/experimenting does not work well when undefined behavior is involved. Experimenting requires consistent results to learn from. Undefined behavior is not consistent. – nwp May 06 '19 at 16:42
  • 1
    I think part of your question was why the information about `->show()` is not lost. Your method is resolved at compile time. Declaring it as `virtual` would make it resolve at runtime from the object itself. But unless you actually overwrite the object with something you have no guarantee of even that crashing immediately. –  May 06 '19 at 16:53
  • @jakub_d - Adding `virtual` to `show` method caused Segmentation fault. Thanks. – pmoubed May 06 '19 at 16:58
  • `free` does not return the memory to the system back.. It simply marks that the allocation is free.. vaguely speaking When adjacent blocks are freed then the memory is reclaimed by the system and heap is shrinked. Configure malloc to use anonymous memory mappings to get a crash always... Since free on these anonymous mappings will always be returned to system.. Use the below code in main() before rest of the code. mallopt (M_MMAP_THRESHOLD, 0) – Sam Daniel May 06 '19 at 17:04
  • @PMoubed -- And if you used a different compiler, or used different compiler options to build your program, what if `virtual` no longer crashes? You would be back to square one again. So you have a choice -- either accept that the behavior is undefined and move onto something worthy (like learning legitimate aspects of the C++ language), or go on wild chases trying to make ill-formed programs crash. – PaulMcKenzie May 06 '19 at 17:22

2 Answers2

2

Remember, a pointer stores an integer memory address. On a call to delete, the dynamic memory will be deallocated but the pointer will still store the memory address. If we nulled the pointer, then program would crash.

See this question: What happens to the pointer itself after delete?

Dylan Fouche
  • 91
  • 2
  • 8
  • 3
    There is no guarantee that the program would crash, even if the pointer is nulled. It's still UB. – super May 06 '19 at 16:13
  • I have tried to null out the pointers after each delete but result was the same - no crash! – pmoubed May 06 '19 at 16:16
  • @super is right here. We can't say for sure it will crash, because this is undefined behaviour. We can say that it might crash, because accessing a deleted pointer is a bad idea. – Dylan Fouche May 06 '19 at 17:42
2

The code print wrong data which I expect but why ->show does not crash?

Why do you simultaneously expect the data to be wrong, but also that it would crash?

The behaviour of indirecting through an invalid pointer is undefined. It is not reasonable to expect the data to be correct, nor to expect the data to be wrong, nor to expect that it should crash, nor to expect that it shouldn't crash - in particular.

In what case/how ->show will cause crash?

There is no situation where the C++ language specifies the program to crash. Crashing is a detail of the particular implementation of C++.

For example, a Linux system will typically force the process to crash due to "segmentation fault" if you attempt to write into a memory area that is marked read-only, or attempt to access an unmapped area of memory.

There is no direct way in standard C++ to create memory mappings: The language implementation takes care of mapping the memory for objects that you create.

Here is an example of a program that demonstrably crashes on a particular system:

int main() {
    int* i = nullptr;
    *i = 42;
}

But C++ does not guarantee that it crashes.

Is it possible to overwrite the same memory location of i, ii, iii with some other object?

The behaviour is undefined. Anything is possible as far as the language is concerned.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • So I added `virtual` keyword to `show` and it caused Segmentation fault. – pmoubed May 06 '19 at 17:04
  • 1
    @PMoubed Ok. Just remember that it is not guaranteed to cause a segmentation fault. Just like it is not guaranteed to not cause a segmentation fault without virtual. – eerorika May 06 '19 at 17:22
  • I missed the point of "undefined behavior", "not guaranteed" in all the comments and answers. now I know! – pmoubed May 06 '19 at 20:13