<p dir="auto">The <code class="notranslate">pyfragments.swg</code> file which is shipped with numpy contains a memory leak in the redefinition of <code class="notranslate">SWIG_CanCastAsInteger</code> for <code class="notranslate">long</code> and <code class="notranslate">unsigned long</code>. The <code class="notranslate">PyArray_Desc</code> pointer which is created near the top of the function is not <code class="notranslate">DECREF</code>ed when the function returns. Furthermore, the pointer is created very far away from where it is actually used.</p>
<h3 dir="auto">Reproducing code example:</h3>
<p dir="auto">The problem can be reproduced with the following:</p>
<p dir="auto">A cmake file for building this example (CMakeTexts.txt):</p>
<div class="highlight highlight-source-cmake notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="CMAKE_MINIMUM_REQUIRED(VERSION 2.6.2)


# Set up libfoo
add_library(foo
	bar.cpp
)
add_definitions(-fPIC)
target_link_libraries(foo)

# Set up swig
SET(InterfaceFile foo.i)

FIND_PACKAGE(SWIG 3 REQUIRED)
INCLUDE(${SWIG_USE_FILE})

SET(CMAKE_SWIG_FLAGS -c++)

# Get the python site-packages directory
EXECUTE_PROCESS(COMMAND python -c &quot;import site; print(site.getsitepackages()[0])&quot;
	OUTPUT_VARIABLE PYTHON_SITE
	OUTPUT_STRIP_TRAILING_WHITESPACE)

# INCLUDE SOURCE
INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR} )
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} )

# PYTHON DIRECTORIES
INCLUDE_DIRECTORIES( SYSTEM /path/to/include/python2.7 )
LINK_DIRECTORIES( /path/to/lib/python2.7/ )

# NUMPY INCLUDES
INCLUDE_DIRECTORIES( SYSTEM ${PYTHON_SITE}/numpy-1.15.1-py2.7-linux-x86_64.egg/numpy/core/include/ )

SET_SOURCE_FILES_PROPERTIES(${InterfaceFile} PROPERTIES SWIG_MODULE_NAME Foo)
SET_SOURCE_FILES_PROPERTIES(${InterfaceFile} PROPERTIES CPLUSPLUS ON)

SET(SWIG_MODULE_Foo_EXTRA_DEPS
	bar.h
)
SWIG_ADD_MODULE(Foo python ${InterfaceFile})

SWIG_LINK_LIBRARIES(Foo ${PythonFramework} foo)
SET(DLLSuffix so)
"><pre class="notranslate"><span class="pl-c1">CMAKE_MINIMUM_REQUIRED</span>(<span class="pl-k">VERSION</span> 2.6.2)


<span class="pl-c"><span class="pl-c">#</span> Set up libfoo</span>
<span class="pl-c1">add_library</span>(foo
	bar.cpp
)
<span class="pl-c1">add_definitions</span>(-fPIC)
<span class="pl-c1">target_link_libraries</span>(foo)

<span class="pl-c"><span class="pl-c">#</span> Set up swig</span>
<span class="pl-c1">SET</span>(InterfaceFile foo.i)

<span class="pl-c1">FIND_PACKAGE</span>(SWIG 3 <span class="pl-k">REQUIRED</span>)
<span class="pl-c1">INCLUDE</span>(<span class="pl-smi">${SWIG_USE_FILE}</span>)

<span class="pl-c1">SET</span>(CMAKE_SWIG_FLAGS -c++)

<span class="pl-c"><span class="pl-c">#</span> Get the python site-packages directory</span>
<span class="pl-c1">EXECUTE_PROCESS</span>(<span class="pl-k">COMMAND</span> python -c <span class="pl-s">"import site; print(site.getsitepackages()[0])"</span>
	<span class="pl-k">OUTPUT_VARIABLE</span> PYTHON_SITE
	<span class="pl-k">OUTPUT_STRIP_TRAILING_WHITESPACE</span>)

<span class="pl-c"><span class="pl-c">#</span> INCLUDE SOURCE</span>
<span class="pl-c1">INCLUDE_DIRECTORIES</span>( <span class="pl-smi">${CMAKE_SOURCE_DIR}</span> )
<span class="pl-c1">INCLUDE_DIRECTORIES</span>( <span class="pl-smi">${CMAKE_CURRENT_SOURCE_DIR}</span> )

<span class="pl-c"><span class="pl-c">#</span> PYTHON DIRECTORIES</span>
<span class="pl-c1">INCLUDE_DIRECTORIES</span>( <span class="pl-k">SYSTEM</span> /path/to/include/python2.7 )
<span class="pl-c1">LINK_DIRECTORIES</span>( /path/to/lib/python2.7/ )

<span class="pl-c"><span class="pl-c">#</span> NUMPY INCLUDES</span>
<span class="pl-c1">INCLUDE_DIRECTORIES</span>( <span class="pl-k">SYSTEM</span> <span class="pl-smi">${PYTHON_SITE}</span>/numpy-1.15.1-py2.7-linux-x86_64.egg/numpy/core/include/ )

<span class="pl-c1">SET_SOURCE_FILES_PROPERTIES</span>(<span class="pl-smi">${InterfaceFile}</span> <span class="pl-k">PROPERTIES</span> SWIG_MODULE_NAME Foo)
<span class="pl-c1">SET_SOURCE_FILES_PROPERTIES</span>(<span class="pl-smi">${InterfaceFile}</span> <span class="pl-k">PROPERTIES</span> CPLUSPLUS <span class="pl-k">ON</span>)

<span class="pl-c1">SET</span>(SWIG_MODULE_Foo_EXTRA_DEPS
	bar.h
)
SWIG_ADD_MODULE(Foo python <span class="pl-smi">${InterfaceFile}</span>)

SWIG_LINK_LIBRARIES(Foo <span class="pl-smi">${PythonFramework}</span> foo)
<span class="pl-c1">SET</span>(DLLSuffix so)
</pre></div>
<p dir="auto">A c++ header file which will be wrapped by swig (bar.h):</p>
<div class="highlight highlight-source-c++ notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#include &lt;vector&gt;


class Bar
{
public:
	Bar(int length);

	double data(int index);

private:
	std::vector&lt;double&gt; data_;

};"><pre class="notranslate">#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">&lt;</span>vector<span class="pl-pds">&gt;</span></span>


<span class="pl-k">class</span> <span class="pl-en">Bar</span>
{
<span class="pl-k">public:</span>
	<span class="pl-en">Bar</span>(<span class="pl-k">int</span> length);

	<span class="pl-k">double</span> <span class="pl-en">data</span>(<span class="pl-k">int</span> index);

<span class="pl-k">private:</span>
	std::vector&lt;<span class="pl-k">double</span>&gt; data_;

};</pre></div>
<p dir="auto">The respective source file (bar.cpp):</p>
<div class="highlight highlight-source-c++ notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#include &quot;bar.h&quot;


Bar::Bar(int length)
	: data_(length)
{
}


double Bar::data(int index)
{
	return data_[index];
}"><pre class="notranslate">#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">"</span>bar.h<span class="pl-pds">"</span></span>


<span class="pl-en">Bar::Bar</span>(<span class="pl-k">int</span> length)
	: data_(length)
{
}


<span class="pl-k">double</span> <span class="pl-en">Bar::data</span>(<span class="pl-k">int</span> index)
{
	<span class="pl-k">return</span> data_[<span class="pl-c1">index</span>];
}</pre></div>
<p dir="auto">The swig interface file (foo.i):</p>
<div class="highlight highlight-source-c++ notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="%module Foo

%{
#include &quot;numpy/arrayobject.h&quot;
#include &quot;bar.h&quot;
%}

%include &quot;numpy.i&quot;

%init
%{
import_array();
%}

%include &quot;bar.h&quot;"><pre class="notranslate">%module Foo

%{
#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">"</span>numpy/arrayobject.h<span class="pl-pds">"</span></span>
#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">"</span>bar.h<span class="pl-pds">"</span></span>
%}

%include <span class="pl-s"><span class="pl-pds">"</span>numpy.i<span class="pl-pds">"</span></span>

%init
%{
<span class="pl-c1">import_array</span>();
%}

%include <span class="pl-s"><span class="pl-pds">"</span>bar.h<span class="pl-pds">"</span></span></pre></div>
<p dir="auto">Once all of these folders are inside a folder, make sure to copy the <code class="notranslate">numpy.i</code> and <code class="notranslate">pyfragments.swg</code> over from your <code class="notranslate">numpy-1.15.1/tools/swig</code>. Then run <code class="notranslate">mkdir build &amp;&amp; cd build &amp;&amp; cmake .. &amp;&amp; make</code>.</p>
<p dir="auto">Then once the swig wrapper has been created, the following python script can be executed:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import Foo


def main():
    foo = Foo.Bar(1)

    while True:
        foo.data(0)


if __name__ == '__main__':
    main()"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-v">Foo</span>


<span class="pl-k">def</span> <span class="pl-en">main</span>():
    <span class="pl-s1">foo</span> <span class="pl-c1">=</span> <span class="pl-v">Foo</span>.<span class="pl-v">Bar</span>(<span class="pl-c1">1</span>)

    <span class="pl-k">while</span> <span class="pl-c1">True</span>:
        <span class="pl-s1">foo</span>.<span class="pl-en">data</span>(<span class="pl-c1">0</span>)


<span class="pl-k">if</span> <span class="pl-s1">__name__</span> <span class="pl-c1">==</span> <span class="pl-s">'__main__'</span>:
    <span class="pl-en">main</span>()</pre></div>
<p dir="auto">You can run the example python file with <code class="notranslate">PYTHONPATH=${PYTHONPATH}:$(pwd) ../test.py</code>.</p>
<p dir="auto">If the <code class="notranslate">pyfragments.swg</code> file was located in the source tree when the swig module was built, then running the example will show a memory leak. If it was not present, then there will be no memory leak.</p>
<h3 dir="auto">Numpy/Python version information:</h3>
<p dir="auto">Numpy version: 1.15.1<br>
Python version: 2.7.11</p>
<p dir="auto">Output from 'import sys, numpy; print(numpy.<strong>version</strong>, sys.version)':<br>
('1.15.1', '2.7.11 (default, Sep  3 2018, 11:28:21) \n[GCC 5.4.0 20160609]')</p>
<p dir="auto">I think I found a memory leak in pyfragments.swg. In both <code class="notranslate">SWIG_AsVal_dec</code> fragments, <code class="notranslate">PyArray_DescrNewFromType</code> is called but its return value may not get deallocated.</p>
<p dir="auto">I moved the calls to <code class="notranslate">PyArray_DescrNewFromType</code> to right before their value is used (the calls to <code class="notranslate">PyArray_CastScalarToCtype</code>) and added a call to <code class="notranslate">Py_DECREF</code> and that seems to have fixed my memory leak.</p>
<p dir="auto">I discovered this in numpy 1.4.1, but I checked 1.9.0 and I think it's still present there.</p>