Difference between revisions of "Documentation/Nightly/Developers/Tutorials/Troubleshooting"

From Slicer Wiki
Jump to: navigation, search
(4.1 -> Nightly)
 
(Replaced content with "<noinclude>{{documentation/versioncheck}}</noinclude> {{documentation/banner | text = [https://slicer.readthedocs.io/en/latest/developer_guide/debugging/overview.html Th...")
Tags: 2017 source edit, Replaced
(20 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 +
<noinclude>{{documentation/versioncheck}}</noinclude>
  
Here are some tips to narrow down various issues such as crash, or memory leaks
+
{{documentation/banner
 
+
| text  = [https://slicer.readthedocs.io/en/latest/developer_guide/debugging/overview.html This page has been moved to read-the-docs.]
=Disable features=
+
| background-color = 8FBC8F }}
Try running Slicer with as few features as possible:
 
* Disable Slicer options via the command line
 
*: <pre>$ ./Slicer --no-splash --ignore-slicerrc --disable-cli-module --disable-loadable-module --disable-scriptedmodule</pre>
 
** Look at all the possible options
 
**: <pre>$ ./Slicer --help</pre>
 
* 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=
 
<ol>
 
<li> Turn ON the VTK_DEBUG_LEAKS CMake variable and build Slicer</li>
 
<li> Create a test that reproduces the memory leak systematically </li>
 
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.
 
...
 
<li>Find what specific instance of a class (here vtkProperty2D) leaks.</li>
 
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 [[Documentation/4.0/Developers/Tutorials/Debug_Instructions|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.
 
</li>
 
<li> Analyze the code to see where the leak could be</li>
 
Here is a listing of the most common mistakes
 
* this->MyXXX = vtkXXX::New();
 
** Is there a matching this->MyXXX->Delete() ?
 
** Are you sure <code>this->MyXXX</code> is <code>0</code> 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();
 
</ol>
 
{{ombox
 
|type=content
 
|text=To reduce memory leaks, use the following tools:
 
* <code>vtkNew<vtkXXX> myXXX;</code>
 
* <code>vtkSmartPointer<vtkXXX> myXXX = vtkSmartPointer<vtkXXX>::New()</code>
 
* <code>vtkSmartPointer<vtkXXX> myXXX; myXXX.TakeReference(this->CreateObjAndCallerOwnsReference())</code>.
 
}}
 
 
 
=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 .
 
<ol>
 
<li>Before the crash, print the value of the pointer:</li>
 
Add before the crash (i.e. <code>this->MyObject->update()</code>)
 
std::cout << ">>>>>Object pointer: " << this->MyObject << std::endl;
 
<li>Add a counter in the destructor:</li>
 
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;
 
<li>Run the application and make it crash.</li>
 
<li>In the logs you shall see something like that:</li>
 
#######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
 
<li> Search in the logs when the pointer before crash has been deleted. Set a conditional breakpoint in the debugger:</li>
 
(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);
 
<li> Analyze the backtrace to understand why the pointer has been deleted without letting know the object that tries to access it.</li>
 
</ol>
 

Revision as of 05:40, 19 August 2021

Home < Documentation < Nightly < Developers < Tutorials < Troubleshooting