Skip to content

Commit 3cba3cf

Browse files
committed
Fix reference to out-of-scope data for reflexive string reference
The contrived test case here is the only possible time this would happen so in practice this is unlikely to be neceessary, but this way is the safest and the only penalty is an extra allocation/string copy/free.
1 parent 90c93a9 commit 3cba3cf

File tree

2 files changed

+54
-34
lines changed

2 files changed

+54
-34
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
! File : li_std_string_runme.f90
2+
3+
#include "fassert.h"
4+
5+
program li_std_string_runme
6+
use li_std_string
7+
use ISO_C_BINDING
8+
implicit none
9+
character(kind=C_CHAR, len=*), parameter :: mystring = "howdy!"
10+
character(kind=C_CHAR, len=:), allocatable :: actual
11+
type(swigtype_p_std__string) :: anonymous_string
12+
13+
allocate(actual, source=test_value(mystring))
14+
ASSERT(actual == mystring)
15+
deallocate(actual)
16+
17+
actual = test_const_reference(mystring)
18+
ASSERT(actual == mystring)
19+
deallocate(actual)
20+
21+
call test_pointer(anonymous_string)
22+
23+
anonymous_string = test_pointer_out()
24+
end program
25+

Lib/fortran/std_string.i

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -30,45 +30,12 @@ namespace std {
3030
class string;
3131
}
3232

33-
/* ---- CONST REFERENCE: NATIVE STRING ---- */
34-
35-
%clear const std::string &;
36-
%typemap(ctype) const std::string & = char*;
37-
%typemap(imtype) const std::string & = char*;
38-
%typemap(ftype) const std::string & = char*;
39-
40-
// C input translation typemaps: $1 is std::string*, $input is SwigArrayWrapper
41-
%typemap(in, noblock=1) const std::string & (std::string tempstr) {
42-
tempstr = std::string(static_cast<char *>($input->data), $input->size);
43-
$1 = &tempstr;
44-
}
45-
46-
// C output translation typemaps: $1 is string*, $input is SwigArrayWrapper
47-
%typemap(out, noblock=1) const std::string & {
48-
$result.data = ($1->empty() ? NULL : &(*$1->begin()));
49-
$result.size = $1->size();
50-
}
51-
52-
// Fortran proxy translation code: convert from char array to Fortran string
53-
%typemap(fin) const std::string & = char*;
54-
// Unlike char* code, we never delete the return value!
55-
%typemap(fout, noblock=1, fragment="SWIG_fout"{char*}) const std::string & {
56-
call %fortrantm(fout, char*)($1, $result)
57-
}
58-
5933
/* ---- VALUE: NATIVE STRING ---- */
6034

6135
%clear std::string;
62-
%apply const std::string & { std::string };
6336

64-
%typemap(globalin) std::string {
65-
$1 = *$input;
66-
}
67-
%typemap(memberin) std::string {
68-
$1 = *$input;
69-
}
37+
%typemap(ctype) std::string = char*;
7038

71-
// Copy input data to local string
7239
%typemap(in, noblock=1) std::string {
7340
$1.assign(static_cast<char *>($input->data), $input->size);
7441
}
@@ -84,9 +51,37 @@ class string;
8451
}
8552
}
8653

54+
%typemap(imtype) std::string = char*;
55+
%typemap(ftype) std::string = char*;
56+
57+
// Fortran proxy translation code: convert from char array to Fortran string
58+
%typemap(fin) std::string = char*;
59+
8760
// Fortran proxy translation code: convert from char array to Fortran string
8861
%typemap(fout, noblock=1,
8962
fragment="SWIG_free_f", fragment="SWIG_fout"{char*}) std::string {
9063
call %fortrantm(fout, char*)($1, $result)
9164
call SWIG_free($1%data)
9265
}
66+
67+
/* ---- CONST REFERENCE: NATIVE STRING ---- */
68+
69+
// Use the same
70+
%clear const std::string &;
71+
%apply std::string { const std::string & };
72+
73+
// Construct a temporary string from the Fortran character array
74+
%typemap(in, noblock=1) const std::string & (std::string tempstr) {
75+
tempstr = std::string(static_cast<char *>($input->data), $input->size);
76+
$1 = &tempstr;
77+
}
78+
79+
%typemap(out, noblock=1, fragment="<stdlib.h>", fragment="<string.h>") const std::string & {
80+
$result.size = $1->size();
81+
if ($result.size > 0) {
82+
$result.data = malloc($result.size);
83+
memcpy($result.data, $1->c_str(), $result.size);
84+
} else {
85+
$result.data = NULL;
86+
}
87+
}

0 commit comments

Comments
 (0)