Skip to content

Commit eaf0313

Browse files
authored
Merge pull request #126 from swig-fortran/fix-null-sp
Fix inconsistencies with null shared pointers
2 parents d2d347e + 5a22e4a commit eaf0313

File tree

5 files changed

+44
-31
lines changed

5 files changed

+44
-31
lines changed

Examples/test-suite/fortran/fortran_ownership_runme.F90

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ subroutine test_standard
5656
ASSERT(.not. btest(b%swigdata%cmemflags, swig_cmem_rvalue_bit))
5757
ASSERT(foo_counter == 3)
5858

59+
! Return null
60+
call b%release()
61+
b = get_null()
62+
ASSERT(.not. c_associated(b%swigdata%cptr))
63+
5964
! Capture from function
6065
b = make_foo(6)
6166
ASSERT(btest(b%swigdata%cmemflags, swig_cmem_own_bit))

Examples/test-suite/fortran/li_boost_shared_ptr_runme.F90

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ program li_boost_shared_ptr_runme
88
implicit none
99
type(Klass) :: f1, f2
1010
integer(c_int) :: orig_total_count
11-
integer(c_int) :: memory_leak
1211

1312
!call set_debug_shared(.true.)
1413

@@ -40,6 +39,17 @@ program li_boost_shared_ptr_runme
4039
call f1%release() ! Clear the raw pointer (does not deallocate)
4140
ASSERT(use_count(f1) == 0)
4241

42+
! Test null pointers
43+
f1 = sp_pointer_null()
44+
ASSERT(nullsmartpointerpointertest(f1) == "null pointer")
45+
call f1%release()
46+
f1 = null_sp_pointer()
47+
ASSERT(nullsmartpointerpointertest(f1) == "null pointer")
48+
call f1%release()
49+
f1 = sp_value_null()
50+
ASSERT(nullsmartpointerpointertest(f1) == "null pointer")
51+
call f1%release()
52+
4353
! Copy-construct the underlying object
4454
f1 = Klass(f2)
4555
ASSERT(use_count(f1) == 1)
@@ -52,12 +62,7 @@ program li_boost_shared_ptr_runme
5262

5363
call f2%release() ! Further calls to release() are allowable null-ops
5464

55-
! Create a temporary shared pointer that's passed into a function
56-
! THIS LEAKS MEMORY!
57-
ASSERT(use_count(Klass()) == 1)
58-
memory_leak = 1
59-
6065
! The getTotal_count function is static, so 'f2' doesn't have to be allocated
61-
ASSERT(f2%getTotal_count() == orig_total_count + memory_leak)
66+
ASSERT(f2%getTotal_count() == orig_total_count)
6267
end program
6368

Examples/test-suite/fortran_ownership.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Foo& reference(Foo& other) { return other; }
4343
const Foo& const_reference(const Foo& other) { return other; }
4444
Foo make_foo(int val) { return Foo(val); }
4545
Foo make_foo_subroutine(int val) { return Foo(val); }
46+
Foo* get_null() { return NULL; }
4647

4748
int get_value(const Foo& other) { return other.val; }
4849
int get_value_copy(Foo other) { return other.val; }

Examples/test-suite/li_boost_shared_ptr.i

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ std::string nullsmartpointerpointertest(SwigBoost::shared_ptr<Klass>* k) {
242242
else
243243
return "also not null";
244244
}
245+
246+
SwigBoost::shared_ptr<Klass>* sp_pointer_null() { return NULL; }
247+
SwigBoost::shared_ptr<Klass>* null_sp_pointer() { static SwigBoost::shared_ptr<Klass> static_sp; return &static_sp; }
248+
SwigBoost::shared_ptr<Klass> sp_value_null() { return SwigBoost::shared_ptr<Klass>(); }
245249
// $owner
246250
Klass *pointerownertest() {
247251
return new Klass("pointerownertest");

Lib/fortran/boost_shared_ptr.i

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@
6262
* SP-owned copy of the obtained value.
6363
* ------------------------------------------------------------------------- */
6464
%typemap(in, noblock=1, fragment="SWIG_check_sp_nonnull") CONST TYPE ($&1_type argp = 0) {
65-
SWIG_check_sp_nonnull($input, "$1_ltype", "$fclassname", "$decl", return $null)
66-
argp = $input->cptr ? %static_cast($input->cptr, SWIGSP__*)->get() : NULL;
65+
SWIG_check_sp_nonnull($input->cptr, "$1_ltype", "$fclassname", "$decl", return $null)
66+
argp = static_cast<SWIGSP__*>($input->cptr)->get();
6767
$1 = *argp;
6868
}
6969
%typemap(out, noblock=1) CONST TYPE {
@@ -76,10 +76,16 @@
7676
* cmemflags, but the result is always a new self-owned shared pointer.
7777
* ------------------------------------------------------------------------- */
7878
%typemap(in, noblock=1) CONST TYPE * (SWIGSP__* smartarg) {
79-
smartarg = %static_cast($input->cptr, SWIGSP__*);
80-
$1 = smartarg ? %const_cast(smartarg->get(), TYPE*) : NULL;
79+
smartarg = (SWIGSP__*)($input->cptr);
80+
$1 = smartarg ? (TYPE*)(smartarg->get()) : NULL;
8181
}
8282

83+
// Replace call to "delete (Foo*) arg1;" with call to delete the *shared
84+
// pointer*: decrement the reference count instead of forcing the object to
85+
// be destroyed and causing a double-delete.
86+
%feature("unref") TYPE
87+
%{ (void)$self; delete smart$self; %}
88+
8389
// The string "SWIG_NO_NULL_DELETER_$owner" is replaced by the macro
8490
// SWIG_NO_NULL_DELETER_1 if a raw pointer is being emitted via %newobject
8591
// (for a shared pointer this macro is empty);
@@ -93,14 +99,15 @@
9399
}
94100

95101
/* -------------------------------------------------------------------------
96-
* Original class by reference. Same as by pointer, but with null checks.
102+
* Original class by reference. Add null checks.
97103
* ------------------------------------------------------------------------- */
98-
%typemap(in, noblock=1, fragment="SWIG_check_sp_nonnull") CONST TYPE& (SWIGSP__* smartarg) {
99-
SWIG_check_sp_nonnull($input, "$1_ltype", "$fclassname", "$decl", return $null)
100-
smartarg = %static_cast($input->cptr, SWIGSP__*);
101-
$1 = %const_cast(smartarg->get(), TYPE*);
104+
%typemap(in, noblock=1, fragment="SWIG_check_sp_nonnull") CONST TYPE & {
105+
SWIG_check_sp_nonnull($input->cptr, "$1_ltype", "$fclassname", "$decl", return $null)
106+
$1 = (TYPE*)static_cast<SWIGSP__*>($input->cptr)->get();
102107
}
103108

109+
%typemap(in) CONST TYPE &ASSIGNMENT_OTHER = SWIGTYPE *ASSIGNMENT_SELF;
110+
104111
// Output value is never null. Because we're allocating a shared pointer, we set the memory ownership to MOVE so that the *SP*
105112
// will be properly deallocated. But we also must use a null deleter so that when the SP is deleted the corresponding memory
106113
// will not be.
@@ -113,35 +120,35 @@
113120
* SP by value
114121
* ------------------------------------------------------------------------- */
115122
%typemap(in, noblock=1) SWIG_SHARED_PTR_QNAMESPACE::shared_ptr<CONST TYPE > {
116-
if ($input->cptr) $1 = *%static_cast($input->cptr, SWIG_SHARED_PTR_QNAMESPACE::shared_ptr<CONST TYPE >*);
123+
if ($input->cptr) $1 = *static_cast<SWIG_SHARED_PTR_QNAMESPACE::shared_ptr<CONST TYPE >*>($input->cptr);
117124
}
118125

119126
%typemap(out, noblock=1) SWIGSP__ {
120-
$result.cptr = %new_copy($1, SWIGSP__);
127+
$result.cptr = SWIG_SHARED_PTR_NOT_NULL($1) ? %new_copy($1, SWIGSP__) : NULL;
121128
$result.cmemflags = SWIG_MEM_OWN | SWIG_MEM_RVALUE;
122129
}
123130

124131
/* -------------------------------------------------------------------------
125132
* SP by reference
126133
* ------------------------------------------------------------------------- */
127134
%typemap(in, noblock=1) SWIGSP__& ($*1_ltype tempnull) {
128-
$1 = $input->cptr ? %static_cast($input->cptr, $1_ltype) : &tempnull;
135+
$1 = $input->cptr ? static_cast<$1_ltype >($input->cptr) : &tempnull;
129136
}
130137

131138
%typemap(out, noblock=1) SWIGSP__& {
132-
$result.cptr = SWIG_SHARED_PTR_NOT_NULL(*$1) ? %new_copy(*$1, SWIGSP__) : 0;
139+
$result.cptr = SWIG_SHARED_PTR_NOT_NULL(*$1) ? %new_copy(*$1, SWIGSP__) : NULL;
133140
$result.cmemflags = SWIG_MEM_OWN | SWIG_MEM_RVALUE;
134141
}
135142

136143
/* -------------------------------------------------------------------------
137144
* SP by pointer
138145
* ------------------------------------------------------------------------- */
139146
%typemap(in, noblock=1) SWIGSP__ * ($*1_ltype tempnull) {
140-
$1 = $input->cptr ? %static_cast($input->cptr, $1_ltype) : &tempnull;
147+
$1 = $input->cptr ? static_cast<$1_ltype >($input->cptr) : &tempnull;
141148
}
142149

143150
%typemap(out, noblock=1, fragment="SWIG_null_deleter") SWIGSP__ * {
144-
$result.cptr = ($1 && SWIG_SHARED_PTR_NOT_NULL(*$1)) ? %new_copy(*$1, SWIGSP__) : 0;
151+
$result.cptr = ($1 && SWIG_SHARED_PTR_NOT_NULL(*$1)) ? %new_copy(*$1, SWIGSP__) : NULL;
145152
$result.cmemflags = SWIG_MEM_OWN | SWIG_MEM_RVALUE;
146153
}
147154

@@ -158,15 +165,6 @@
158165
#error "typemaps for $1_type not available"
159166
%}
160167

161-
/* -------------------------------------------------------------------------
162-
* Replace call to "delete (Foo*) arg1;" with call to delete the *shared
163-
* pointer* (so decrement the reference count instead of forcing the object to
164-
* be destroyed and causing a double-delete)
165-
*/
166-
167-
%feature("unref") TYPE
168-
%{ (void)$self; delete smart$self; %}
169-
170168
/* -------------------------------------------------------------------------
171169
* Instantiate shared pointer
172170
*/

0 commit comments

Comments
 (0)