Exception in Release mode (Access Violation )



  • Hello everybody!

    I'm working with qt since a few months and wrote a medium-size program (a painting application with layers and several functions and tools).

    I worked in Debug mode and did not compile the program in release mode during the last weeks. Now, if I try to run it in release mode, I get an access violation (reading location 0.ffffffff...). I tried to figure out where the error is triggered by commenting out the code step by step. It turned out that the exception is only thrown, when I add the QListWidget (which I use to show the Layers in the LayersWindow) to the main-layout of this LayersWindow.

    LayersWindow.h
    @ QVBoxLayout* mLayersLayout;
    QListWidget* mLayerList;@

    LayersWindow.cpp (in constructor)
    @ mLayerList = new QListWidget();
    mLayersLayout = new QVBoxLayout(this);
    mLayersLayout->addWidget(mLayerList); <----
    setLayout(mLayersLayout);@

    If I remove the marked line, there is no exception. I wanted to make a small project so that anyone in this forum would be able to reproduce the error. But when I removed everything but this Lines from the whole project, the exception also did not show up. So I tried to remove the rest of the project bit by bit, but there seemed to be several statements that trigger the exception together...

    Does anyone have an idea how I could debug this error? I am programming C++ in Visual Studio 2010 on Windows 8. I make a 64-bit program, but I am pretty sure that the problem pre-existed before I changed to 64-bit.
    The exception is only triggered in Release-Mode, in Debug-Mode everything is working fine... I know that in Release-Mode, the variables are not initialized with default values like in Debug mode, but this did not help me to find the problem.

    I would be very happy if someone could help me with this!
    Greetings!
    eve


  • Moderators

    Looks like you've encountered a "Heisenbug":http://en.wikipedia.org/wiki/Heisenbug

    Most probably, the error isn't caused by that line in LayersWindow.cpp, but somewhere else in your program. A memory corruption might not cause a crash at the moment the corruption begins -- the corruption can slowly spread, and then cause a crash at a completely unrelated part of the code.

    [quote author="eveLine" date="1367195176"]I know that in Release-Mode, the variables are not initialized with default values like in Debug mode, but this did not help me to find the problem.[/quote]What do you mean? Where do the values get set?

    Often, bugs like the one you reported are caused by illegal memory access (e.g. deferencing an object after you've deleted it, or dereferencing an uninitialized pointer). It's a good idea to initialize all variables.


  • Moderators

    [quote author="eveLine" date="1367195176"]I know that in Release-Mode, the variables are not initialized with default values like in Debug mode, but this did not help me to find the problem.[/quote]
    i hope you do not rely on the debug initialization! As JKSH you should initialize all your variables in all cases.



  • Thanks for your replies!

    I am initializing each variable, that's why the information, that in release-mode the vars are not initialized automatically did not help me.
    But I don't know any other important differences between debug and release mode so I could not figure out why the access violation only got triggered in release mode.
    If the problem was that I tried to dereference or unitialize a deleted pointer, the exception would also be caused in debug mode, didn't it?


  • Moderators

    You're welcome :) Ok, I understand what you meant by "not initialized with default values" now.

    [quote author="eveLine" date="1367238225"]But I don't know any other important differences between debug and release mode so I could not figure out why the access violation only got triggered in release mode.
    If the problem was that I tried to dereference or unitialize a deleted pointer, the exception would also be caused in debug mode, didn’t it?
    [/quote]The layout of the compiled code is very different in debug mode and in release mode. For example, your compiler will use strong optimizations in release mode -- it will modify your code to make it more efficient. It will also remove debug code to make your program smaller.

    In your case, this is what could have happened:

    You have a bug that causes memory corruption

    In release mode, the corrupted area happens to be near a place used by mLayersLayout. So, when you call addWidget(), mLayersLayout encounters the corrupted memory and crashes.

    In debug mode, because the compiler produced a different code structure, the corrupted area is far away from the memory used by mLayersLayout. So, when you call addWidget(), mLayersLayout does not encounter the corrupted memory, and you don't get a crash there. (However, if you continue to run your code, something else might eventually encounter the corrupted memory and cause a crash)

    But anyway, the important point is: the bug might not be in LayersWindow at all. Maybe it's in a different class. This type bug is hard to find -- do you have any debugging tools installed? (e.g. CDB? Debugging Tools for Windows?)


  • Moderators

    By the way, pointers are only one example. There are other sources of memory corruption, such as:

    @
    int array[5];

    for (int i = 0; i <= 5; ++i) {
    array[i] = i;
    }
    @
    The program will try to do 'array[5 ] = 5' which will cause memory corruption because you're only allowed to go up to 'array[4 ]'.

    In Qt, calling delete on QObjects can cause memory corruption -- you should use deleteLater().

    There are other possibilities too.



  • Thank you very much for your reply! :)

    I did not think about that! I do not have any debugging tools, only using the Visual Studio Debugger. Is there any tool you can recommend for programming with qt in c++ for the Visual Studio environment?

    Your small example would throw a runtime exception, wouldn't it? So this cannot cause an access violation at a different point in the program or am I mistaken here?

    In my programm I only initialize heap objects in the constructor and destroy them all in the destructor of each class. All the pointers I use are member objects of my classes.



  • [quote author="JKSH" date="1367251356"]By the way, pointers are only one example. There are other sources of memory corruption, such as:
    @
    int array[5];

    for (int i = 0; i <= 5; ++i) {
    array[i] = i;
    }
    @[/quote]
    This is just pointers once again. An array is just a pointer and [] is basically a plus operator for pointers (that's why expressions like [array]4 instead of array[ 4] work, addition is commutative).

    [quote author="JKSH" date="1367251356"]
    In Qt, calling delete on QObjects can cause memory corruption -- you should use deleteLater()..[/quote] Do you have sources for that? As far as I know what you say is not generally true, only for the situation when the deleted object is in a different thread from the place where delete is called.


  • Moderators

    [quote author="DerManu" date="1367306019"]
    [quote author="JKSH" date="1367251356"]
    In Qt, calling delete on QObjects can cause memory corruption -- you should use deleteLater()..[/quote] Do you have sources for that? As far as I know what you say is not generally true, only for the situation when the deleted object is in a different thread from the place where delete is called.
    [/quote]
    i think he meant the case when you may access the pointer in the same event loop iteration again. But basically deleteLater() also calls a simple delete in the next eventloop iteration.


  • Moderators

    [quote author="eveLine" date="1367252626"]I do not have any debugging tools, only using the Visual Studio Debugger. Is there any tool you can recommend for programming with qt in c++ for the Visual Studio environment?[/quote]I'm not experienced with Visual Studio, sorry. The one good memory error detector I know is Valgrind, but that's Linux + Mac only. I think Visual Studio comes with some debugging tools; have a look at http://msdn.microsoft.com/en-us/library/6decc55h(v=vs.100).aspx

    [quote]Your small example would throw a runtime exception, wouldn't it? So this cannot cause an access violation at a different point in the program or am I mistaken here? [/quote]No, exceptions are very expensive and compilers don't add them unless you tell them to. An int array is very low-level -- no checking will be done on it. If you do that with a QVector instead of an int array, you will get an "assertion failure":http://qt-project.org/doc/qt-5.0/qtcore/qtglobal.html#Q_ASSERT in debug mode, but Qt won't check it in release mode (to increase performance).


  • Moderators

    [quote author="DerManu" date="1367306019"]This is just pointers once again. An array is just a pointer and [] is basically a plus operator for pointers (that's why expressions like [array]4 instead of array[ 4] work, addition is commutative).[/quote]Indeed. :) My intention was just to show that access violations can be caused by all kinds of code that look completely different to each other. Technically, the QObject example is related to pointers too -- deleting a QObject too early can cause the event loop to access the deleted object's memory.

    [quote][quote author="JKSH" date="1367251356"]
    In Qt, calling delete on QObjects can cause memory corruption -- you should use deleteLater()..[/quote] Do you have sources for that? As far as I know what you say is not generally true, only for the situation when the deleted object is in a different thread from the place where delete is called.
    [/quote]http://qt-project.org/doc/qt-5.0/qtcore/qobject.html#dtor.QObject says "Warning: Deleting a QObject while pending events are waiting to be delivered can cause a crash." Like raven-worx described, deleteLater() protects objects from deletion before they've processed all pending events.

    It's easy (and common in large applications) for an object to receive multiple signals, or be accessed by multiple slots, within one event loop iteration. Suppose that a slot calls delete on a QObject, when a signal that's connected to that object has already been emitted. The event loop will still try to invoke the deleted object's slot, which will cause bad things to happen.

    However, if the 1st slot used deleteLater() instead, Qt will wait until all signals have been processed, before deleting the object.



  • Hey!

    I read this thread here: https://bugreports.qt-project.org//browse/QTBUG-11445
    and was pretty sure that it would be the solution for my problem, but it did not work.
    The only difference between the problem in this thread and mine is the reading adress.
    Maybe I should have already tell this, but each time the program crashes while starting, the access violation shows up while reading adress 0xffffffffffffffff.

    Does anyone know what the problem could be if it is always this adress?

    Thank you all!



  • Okay, it really was the problem from the thread I posted, I just forgot to recompile Qt... :D


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.