#1071 [python] Strange behaviour of temporary objects

open
nobody
python (259)
5
2011-02-19
2010-02-15
onko
No

Hi,
maybe this is me misunderstanding some deep memory allocation issues, but I noticed a quite strange behaviour with SWIG and temporary objects. If this is the case, I'd like to have the matching pointer to the documentation or ask you to consider this as a documentation bug :-)
See attached reduced test case. When calling make.sh, I expect to have the same result (1.0) twice, but I get:
./make.sh
A: 1.0
B: 0.0

I am using debian, python version 2.5, and swig 1.3.40, g++ 4.3.4, though this is not the only configuration showing this behaviour (Kubuntu 9.10 with default packages does the same).

Best regards,

Onno

Discussion

  • onko
    onko
    2010-02-15

    Boiled-down test case for access problem/bug

     
    Attachments
  • William Fulton
    William Fulton
    2011-02-15

    Modifying your test.i file to:

    ///////////////////////////////////////////////////////////
    %module test

    %{
    #include "test.hh"
    %}

    %feature("exceptvar") {
    printf("%p In variable wrapper ... $symname\n", arg1);
    $action;
    }
    %exception {
    printf("%p In function... $symname\n", arg1);
    $action;
    }

    %exception v::v {
    $action;
    printf("%p In constructor... $symname\n", result);
    }
    %exception comp::comp {
    $action;
    printf("%p In constructor... $symname\n", result);
    }

    %exception v::~v() {
    printf("%p In destructor... $symname\n", arg1);
    $action;
    }
    %exception comp::~comp() {
    printf("%p In destructor... $symname\n", arg1);
    $action;
    }
    %include "test.hh"
    ///////////////////////////////////////////////////////////

    With just the one line of python code:

    print "B:", comp(v(1,1,1), v(2,2,2)).a.x

    The output is:

    B:0x45ae698 In constructor... new_v
    0x45af200 In constructor... new_v
    0x45af470 In constructor... new_comp
    0x45af200 In destructor... delete_v
    0x45ae698 In destructor... delete_v
    0x45af470 In variable wrapper ... comp_a_get
    0x45af470 In destructor... delete_comp
    0x45af470 In variable wrapper ... v_x_get
    1.0

    So v_x_get uses deleted memory (after delete_comp is called). Note the address of comp is the same as comp::x as x is at the first member variable. Valgrind confirms the problem:

    ==26786== Invalid read of size 8
    ==26786== at 0x4036746: _wrap_v_x_get (in /home/william/swig/trunk/Examples/william/temp_access/_test.so)
    ==26786== by 0x8065B83: PyObject_CallFunction (in /usr/bin/python2.6)
    ==26786== by 0x80940C6: PyObject_GenericGetAttr (in /usr/bin/python2.6)
    ==26786== by 0x80B280E: ??? (in /usr/bin/python2.6)
    ==26786== by 0x80DDD1F: PyEval_EvalFrameEx (in /usr/bin/python2.6)
    ==26786== by 0x80E2806: PyEval_EvalCodeEx (in /usr/bin/python2.6)
    ==26786== by 0x80E2906: PyEval_EvalCode (in /usr/bin/python2.6)
    ==26786== by 0x81005AC: PyRun_FileExFlags (in /usr/bin/python2.6)
    ==26786== by 0x8100811: PyRun_SimpleFileExFlags (in /usr/bin/python2.6)
    ==26786== by 0x805DE5B: Py_Main (in /usr/bin/python2.6)
    ==26786== by 0x805D03A: main (in /usr/bin/python2.6)

    I don't have the solution nor the expertise about the python reference counting, so all I can do is confirm the behaviour will provide undefined results, even though I see the correct result of 1.0. However the equivalent code in Java is known to be problematic and the solution is to enforce a reference in the 'comp' instance to 'a' so that it is not garbage collected early.

     
  • Olly Betts
    Olly Betts
    2011-02-19

    • summary: Strange behaviour of temporary objects --> [python] Strange behaviour of temporary objects