Documentation/4.1/Developers/Tutorials/Troubleshooting

From Slicer Wiki
Revision as of 04:44, 12 April 2012 by JChris.FillionR (talk | contribs) (4.0 -> 4.1)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Home < Documentation < 4.1 < Developers < Tutorials < Troubleshooting


Here are some tips to narrow down various issues such as crash, or memory leaks

Disable features

Try running Slicer with as few features as possible:

  • Disable Slicer options via the command line
    $ ./Slicer --no-splash --ignore-slicerrc --disable-cli-module --disable-loadable-module --disable-scriptedmodule
    • Look at all the possible options
      $ ./Slicer --help
  • Disable ITK plugins
    CLI modules silently load the ITK plugins in lib/Slicer-4.0/ITKFactories. These plugins are used to share the volumes between Slicer and the ITK filter without having to copy them on disk.
    • rename lib/Slicer-4.0/ITKFactories into lib/Slicer-4.0/ITKFactories-disabled
  • Disable Qt plugins
    • rename lib/Slicer-4.0/iconengine into lib/Slicer-4.0/iconengine-disabled

Track memory leaks

  1. Turn ON the VTK_DEBUG_LEAKS CMake variable and build Slicer
  2. Create a test that reproduces the memory leak systematically
  3. After execution, the memory leaks are printed automatically by VTK on the standard output: 224: vtkDebugLeaks has detected LEAKS! 224: Class "vtkProperty2D" has 60 instances still around. ...
  4. Find what specific instance of a class (here vtkProperty2D) leaks.
  5. If the class is instantiated a large amount of time, it is hard to know what instance is leaking. You can edit the constructor and destructor of the class (here vtkProperty2D::vtkProperty2D() and vtkProperty2D::~vtkProperty2D()) vtkProperty2D::vtkProperty2D() { ... static int count = 0; std::cout << "CREATE vtkProperty2D instance #" << count++ << " " << this << std::endl; } vtkProperty2D::~vtkProperty2D() { ... static int count = 0; std::cout << "DELETE vtkProperty2D instance #" << count++ << " " << this << std::endl; } Don't forget to rebuild VTK if the class is from VTK (and not just Slicer inner build) After running the test again, you should see a list of ... CREATE vtkProperty2D instance #0 0x0123456 ... CREATE vtkProperty2D instance #1 0x01234E5 ... DELETE vtkProperty2D instance #0 0x0123456 ... DELETE vtkProperty2D instance #1 0x01234E5 ... CREATE vtkProperty2D instance #2 0x0123A23 ... CREATE vtkProperty2D instance #3 0x0124312 ... Copy/paste the listing in a text editor and ensure that for each CREATE of a pointer (e.g. 0x0123456) it exists a DELETE. If there isn't, you found what instance is leaking. Note the instance # (here instance #2 and #3) Run the test with the debugger, set a breakpoint in the class constructor and ignore the break as many time as the instance number: (gdb) break vtkProperty2D::vtkProperty2D() Breakpoint 1 at 0x5b22d0e55d04296: file vtkProperty2D.cxx, line 22 (gdb) ignore 1 2 When the debugger stops, check the call stack: (gdb) backtrace By analyzing the trace, you should be able to find the faulty instance.
  6. Analyze the code to see where the leak could be
  7. Here is a listing of the most common mistakes
    • this->MyXXX = vtkXXX::New();
      • Is there a matching this->MyXXX->Delete() ?
      • Are you sure this->MyXXX is 0 before being assigned a new pointer ? If not, then you need to add
    if (this->MyXXX != 0) { this->MyXXX->Delete(); this->MyXXX = 0; } this->MyXXX = vtkXXX::New();

Track a crash while accessing already deleted object pointer

If the application crashes by accessing an invalid pointer. The goal here is to find when (and why) the pointer is deleted before it is accessed .

  1. Before the crash, print the value of the pointer:
  2. Add before the crash (i.e. this->MyObject->update()) std::cout << ">>>>>Object pointer: " << this->MyObject << std::endl;
  3. Add a counter in the destructor:
  4. Add in the object destructor (it can be in the base class (vtkObject or vtkMRMLNode) if you don't know the type): static int count = 0; std::cout << "#######Object Destructed: " << this << " " << count++ << std::endl;
  5. Run the application and make it crash.
  6. In the logs you shall see something like that:
  7. #######Object Destructed: 0x12345678 0 #######Object Destructed: 0x12345679 1 #######Object Destructed: 0x12345680 2 >>>>>Object Pointer: 0x12345660 >>>>>Object Pointer: 0x12345661 >>>>>Object Pointer: 0x12345662 #######Object Destructed: 0x12345660 3 #######Object Destructed: 0x12345661 4 #######Object Destructed: 0x12345662 5 #######Object Destructed: 0x12345663 6 >>>>>Object Pointer: 0x12345670 >>>>>Object Pointer: 0x12345671 >>>>>Object Pointer: 0x12345672 #######Object Destructed: 0x12345660 7 #######Object Destructed: 0x12345661 8 #######Object Destructed: 0x12345662 9 >>>>>Object Pointer: 0x12345663 Segfault
  8. Search in the logs when the pointer before crash has been deleted. Set a conditional breakpoint in the debugger:
  9. (gdb) break MyObj.cxx:103 if count == 6 or (gdb) break MyObj.cxx:103 (gdb) ignore 1 5 or if you don't want to use a debugger, you can make it crash the 6th time: assert(count != 6);
  10. Analyze the backtrace to understand why the pointer has been deleted without letting know the object that tries to access it.