Why Do I Get _Crtisvalidheappointer(Block) And/Or Is_Block_Type_Valid(Header->_Block_Use) Assertions

Why do I get _CrtIsValidHeapPointer(block) and/or is_block_type_valid(header-_block_use) assertions?

These assertions show that either the pointer, which should be freed is not (or no longer) valid (_CrtIsValidHeapPointer-assertion) or that the heap was corrupted at some point during the run of the program (is_block_type_valid(header->_block_use)-assertion aka _Block_Type_Is_Valid (pHead->nBlockUse)-assertion in earlier versions).

When acquiring memory from the heap, functions malloc/free don't communicate directly with the OS, but with a memory manager, which is usually provided by the corresponding C-runtime. VisualStudio/Windows SDK provide a special heap-memory manager for debug-builds, which performs additional sanity checks during the run time.

_CrtIsValidHeapPointer is just a heuristic, but there are enough cases of invalid pointers, for which this function can report a problem.

1. When does _CrtIsValidHeapPointer-assertion fire?

There are some of the most usual scenarios:

A. Pointer doesn't point to a memory from the heap to begin with:

char *mem = "not on the heap!";
free(mem);

here the literal isn't stored on the heap and thus can/should not be freed.

B. The value of the pointer isn't the original address returned by malloc/calloc:

unsigned char *mem = (unsigned char*)malloc(100);
mem++;
free(mem); // mem has wrong address!

As value of mem is no longer 64byte aligned after the increment, the sanity check can easily see that it cannot be a heap-pointer!

A slightly more complex, but not unusual C++-example (mismatch new[] and delete):

struct A {
int a = 0;
~A() {// destructor is not trivial!
std::cout << a << "\n";
}
};
A *mem = new A[10];
delete mem;

When new A[n] is called, actually sizeof(size_t)+n*sizeof(A)bytes memory are allocated via malloc (when the destructor of the class A is not trivial), the number of elements in array is saved at the beginning of the allocated memory and the returned pointer mem points not to the original address returned by malloc, but to address+offset (sizeof(size_t)). However, delete knows nothing about this offset and tries to delete the pointer with wrong address (delete [] would do the right thing).

C. double-free:

unsigned char *mem = (unsigned char*)malloc(10);
free(mem);
free(mem); # the pointer is already freed

A very common reason in C++ that rule of three/five isn't adhered to, e.g:

struct A {// bad: doesn't adhere to rule of three
int* ptr;
A(int i): ptr(new int(i)){}
~A() { delete ptr; }
};

{
A a(0);
A b = a; // a and b share pointer: a.ptr == b.ptr
} // here destructors of b and a called => problem
// at first b.ptr gets deleted
// deleting (already deleted) a.ptr leads now to UB/error.

D. pointer from another runtime/memory manager

Windows programs have the ability to use multiple runtimes at once: every used dll could potentially have its own runtime/memory manager/heap, because it was linked statically or because they have different versions. Thus, a memory allocated in one dll, could fail when freed in another dll, which uses a different heap (see for example this SO-question or this SO-question).

2. When does is_block_type_valid(header->_block_use)-assertion fire?

In the above cases A. and B., in addition also is_block_type_valid(header->_block_use) will fire. After _CrtIsValidHeapPointer-assertion, the free-function (more precise free_dbg_nolock) looks for info in the block-header (a special data structure used by debug-heap, more information about it later on) and checks that the block type is valid. However, because the pointer is completely bogus, the place in the memory, where nBlockUse is expected to be, is some random value.

However, there are some scenarios, when is_block_type_valid(header->_block_use) fires without previous _CrtIsValidHeapPointer-assertion.

A. _CrtIsValidHeapPointer doesn't detect invalid pointer

Here is an example:

unsigned char *mem = (unsigned char*)malloc(100);
mem+=64;
free(mem);

Because debug-heap fills the allocated memory with 0xCD, we can be sure that accessing nBlockUse will yield a wrong type, thus leading to the above assertion.

B. Corruption of the heap

Most of the time, when is_block_type_valid(header->_block_use) fires without _CrtIsValidHeapPointer it means, that the heap was corrupted due to some out-of-range writes.

So if we "delicate" (and don't overwrite "no man's land"-more on that later):

unsigned char *mem = (unsigned char*)malloc(100);
*(mem-17)=64; // thrashes _block_use.
free(mem);

leads only to is_block_type_valid(header->_block_use).


In all above cases, it is possible to find the underlying issue by following memory allocations, but knowing more about the structure of debug-heap helps a lot.

An overview about debug-heap can be found e.g. in documentation, alternatively all details of the implementation can be found in the corresponding Windows Kit,(e.g. C:\Program Files (x86)\Windows Kits\10\Source\10.0.16299.0\ucrt\heap\debug_heap.cpp).

In a nutshell: When a memory is allocated on a debug heap, more memory than needed is allocated, so additional structures such as "no man's land" and additional info, such as _block_use, can be stored next to the "real" memory. The actual memory layout is:

------------------------------------------------------------------------
| header of the block + no man's land | "real" memory | no man's land |
----------------------------------------------------------------------
| 32 bytes + 4bytes | ? bytes | 4 bytes |
------------------------------------------------------------------------

Every byte in "no man's land" at the end and at the beginning are set to a special value (0xFD), so once it is overwritten we can register out-of-bounds write access (as long as they are at most 4 bytes off).

For example in the case of new[]-delete-mismatch we can analyze memory before the pointer, to see whether this is no man's land or not (here as code, but normally done in debugger):


A *mem = new A[10];
...
// instead of
//delete mem;
// investigate memory:
unsigned char* ch = reinterpret_cast<unsigned char*>(mem);
for (int i = 0; i < 16; i++) {
std::cout << (int)(*(ch - i)) << " ";
}

we get:

0 0 0 0 0 0 0 0 10 253 253 253 253 0 0 52

i.e. the first 8 bytes are used for the number of elements (10), than we see "no man's land" (0xFD=253) and then other information. It is easy to see, what is going wrong - if the pointer where correct, the first 4 values where 253.

When Debug-heap frees memory it overwrites it with a special byte value: 0xDD, i.e. 221. One also can restrict the reuse of once used and freed memory by setting flag _CRTDBG_DELAY_FREE_MEM_DF, thus the memory stays marked not only directly after the free-call, but during the whole run of the program. So when we try to free the same pointer a second time, debug-heap can see, taht the memory was already freed once and fire the assertion.

Thus, it is also easy to see, that the problem is a double-free, by analyzing the values around pointer:

unsigned char *mem = (unsigned char*)malloc(10);
free(mem);
for (int i = 0; i < 16; i++) {
printf("%d ", (int)(*(mem - i)));
}
free(mem); //second free

prints

221 221 221 221 221 221 221 221 221 221 221 221 221 221 221 221

the memory, i.e. the memory was already freed once.

On the detection of heap-corruption:

The purpose of no-man's land is to detect out-of-range writes, this however works only for being off for 4 bytes in either direction, e.g.:

unsigned char *mem = (unsigned char*)malloc(100);
*(mem-1)=64; // thrashes no-man's land
free(mem);

leads to

HEAP CORRUPTION DETECTED: before Normal block (#13266) at 0x0000025C6CC21050.
CRT detected that the application wrote to memory before start of heap buffer.

A good way to find heap corruption is to use _CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF) or ASSERT(_CrtCheckMemory());(see this SO-post). However, this is somewhat indirect - a more direct way it to use gflags as explained in this SO-post (it is not unusual that gflags needs about 30 times more memory and is about 10 times slower).


Btw, the definition of _CrtMemBlockHeader changed over the time and no longer the one shown in online-help, but:

struct _CrtMemBlockHeader
{
_CrtMemBlockHeader* _block_header_next;
_CrtMemBlockHeader* _block_header_prev;
char const* _file_name;
int _line_number;

int _block_use;
size_t _data_size;

long _request_number;
unsigned char _gap[no_mans_land_size];

// Followed by:
// unsigned char _data[_data_size];
// unsigned char _another_gap[no_mans_land_size];
};

Debug Assertion Failed OpenCv is_block_type_valid(header-_block_use)

Are you absolutely sure that the image has been loaded correctly?

I would think that it hasn't been loaded correctly and because of that the vector rgb is empty and, in turn, the element rgb[0] doesn't exist which triggers the exception ...

A couple of things I noted:

  1. Use slashes (/) for include-statements not backslashes (\), i.e.

    #include <opencv2\core.hpp> // Bad!
    #include <opencv2/core.hpp> // Good!
  2. In your check

    if (!image.data) { ... } 

    do not assume that image.data is set to NULL or nullptr for empty images. Instead check

    if (!image.empty()) { ... }
  3. Make sure that calls to cv::imshow(...) are followed by a call to cv::waitKey( /* delay in ms or 0 to wait for user input */ ), cf. the note in the OpenCV reference.

  4. while (1); -- is that intentional? What you want is probably cv::waitKey( 0 ) (see 3.).

UPDATE:


  1. Make sure the vector rgb has been initialized to the number of channels, i.e.

    vector<Mat> rgb(image.channels());
    split(image, rgb);
    // ...

UPDATE 2:

Can you tell me what exactly the error meant ?

Three things:

  1. The default constructor of std::vector<T> creates an empty vector.
  2. Apparently, cv::split() expects the caller, i.e. you, to allocate data for the output. If you fail to do so, it's likely provoke a segmentation fault.
  3. For debug builds some compilers add padding or safety memory around objects in memory which is never to be touched. If this padding memory is altered at runtime, the program "knows" that something bad happened and throws an exception like the one you saw.

_Block_Type_Is_Valid (pHead-nBlockUse) Error

Just use a std::string. That error means that you double deleted something, or something like that, a problem that you wouldn't have if you didn't manage your own memory. Your code is littered with memory leaks and other bugs that you won't have with std::string.

Debug Assertion Failed! Expression: __acrt_first_block == header

As this is a DLL, the problem might lie in different heaps used for allocation and deallocation (try to build the library statically and check if that will work).

The problem is, that DLLs and templates do not agree together very well. In general, depending on the linkage of the MSVC runtime, it might be problem if the memory is allocated in the executable and deallocated in the DLL and vice versa (because they might have different heaps). And that can happen with templates very easily, for example: you push_back() to the vector inside the removeWhiteSpaces() in the DLL, so the vector memory is allocated inside the DLL. Then you use the output vector in the executable and once it gets out of scope, it is deallocated, but inside the executable whose heap doesn't know anything about the heap it has been allocated from. Bang, you're dead.

This can be worked-around if both DLL and the executable use the same heap. To ensure this, both the DLL and the executable must use the dynamic MSVC runtime - so make sure, that both link to the runtime dynamically, not statically. In particular, the exe should be compiled and linked with /MD[d] and the library with /LD[d] or /MD[d] as well, neither one with /MT[d]. Note that afterwards the computer which will be running the app will need the MSVC runtime library to run (for example, by installing "Visual C++ Redistributable" for the particular MSVC version).

You could get that work even with /MT, but that is more difficult - you would need to provide some interface which will allow the objects allocated in the DLL to be deallocated there as well. For example something like:

__declspec(dllexport) void deallocVector(std::vector<std::string> &x);

void deallocVector(std::vector<std::string> &x) {
std::vector<std::string> tmp;
v.swap(tmp);
}

(however this does not work very well in all cases, as this needs to be called explicitly so it will not be called e.g. in case of exception - to solve this properly, you would need to provide some interface from the DLL, which will cover the vector under the hood and will take care about the proper RAII)


EDIT: the final solution was actually was to have all of the projects (the exe, dll and the entire googleTest project) built in Multi-threaded Debug DLL (/MDd)
(the GoogleTest projects are built in Multi-threaded debug(/MTd) by default)

Expression: _BLOCK_TYPE_IS_VALID(pHead-nBlockUse) Error

Issue

void Event::set(Room r, const std::string& name) 
{
d_room = &r;
// ^
d_name = name;
}

You are referencing to the temporary object: Room r passed by value, which is destroyed at the end of the scope: }.

Instead you must reallocate the member pointer:

d_room = new Room(r);

Why it went wrong

Because you are writing C-style code in C++ classes.

In C++ we tend to:

  1. Avoid naked pointers, prefer smart pointers:

    class Event 
    {
    std::shared_ptr<Room> d_room;
    ...

    Event::~Event() { /* no need to delete */ }
  2. Use constructor overloading (instead of using set-like functions after construction):

    Event(Room& r, const std::string& name):
    d_room(new Room(r)),
    d_name(name)
    {}
  3. Pass by reference:

    void set(Room& r, const std::string& name);
  4. Avoid raw arrays, use STL facilities instead:

    std::vector<Event> lectures;
    // or
    std::array<Event, 5> lectures;

Another issue

r.d_hasProjector != r.d_hasProjector; // checks if r.d_hasProject is not itself

You probably want

r.d_hasProjector = !r.d_hasProjector;

Complete code: link

Also, here is a must-read link about advanced C++ stuff which, I believe, will be very useful to you: http://www.parashift.com/c++-faq/

Edit: I forgot about your question:

In addition to this, the printed text displays numbers that are very large and often negative. What is causing this?

Those numbers are garbage. Variables that are not explicitly initialized are not initialized at all. Memory is allocated but holds old information from previous program. It could contain anything. When you read from uninitialized variables, you'll get this garbage. You had a pointer which was pointing to a destroyed object. So the pointer was effectively uninitialized.



Related Topics



Leave a reply



Submit