Stable abi and std::string_view

Using directorout and string_view is dangerous. Add in warning 473.

For the stable abi < Python 3.10, leak instead of undefined behaviour.
See #2727.

Update warning 473 message text to:
  Returning a reference, pointer or pointer wrapper in a director method is not recommended.
This commit is contained in:
William S Fulton 2023-12-19 21:44:26 +00:00
parent f8c2dd67cd
commit 69b2234c41
5 changed files with 13 additions and 9 deletions

View File

@ -492,7 +492,7 @@ example.i(4) : Syntax error in input(1).
<li>470. Thread/reentrant unsafe wrapping, consider returning by value instead.
<li>471. Unable to use return type <em>type</em> in director method
<li>472. Overloaded method <em>method</em> with no explicit typecheck typemap for arg <em>number</em> of type '<em>type</em>'
<li>473. Returning a pointer or reference in a director method is not recommended.
<li>473. Returning a reference, pointer or pointer wrapper in a director method is not recommended.
<li>474. Method <em>method</em> usage of the optimal attribute ignored in the out typemap as the following cannot be used to generate optimal code: <em>code</em>
<li>475. Multiple calls to <em>method</em> might be generated due to optimal attribute usage in the out typemap.
<li>476. Initialization using std::initializer_list.

View File

@ -41,11 +41,11 @@ struct A
{ return (int)s.size(); }
virtual void process_text(const char *text)
virtual void process_text(const char *text) const
{
}
void call_process_func() { process_text("hello"); }
void call_process_func() const { process_text("hello"); }
private:
std::vector<std::string> m_strings;

View File

@ -7,7 +7,10 @@ class B(A):
A.__init__(self, string)
def get_first(self):
return A.get_first(self) + " world!"
# Given std::string_view is just a pointer into a string, the string
# cannot be a temporary in order to avoid undefined behaviour
self.cached_string = A.get_first(self) + " world!"
return self.cached_string
def process_text(self, string):
A.process_text(self, string)
@ -20,6 +23,8 @@ b.get(0)
if b.get_first() != "hello world!":
raise RuntimeError("b.get_first(): {}".format(b.get_first()))
if b.call_get_first() != "hello world!":
raise RuntimeError("b.call_get_first(): {}".format(b.call_get_first()))
b.call_process_func()

View File

@ -77,7 +77,7 @@ namespace std {
Py_XDECREF(bytes$argnum);
%}
%typemap(directorout) string_view {
%typemap(directorout, warning=SWIGWARN_TYPEMAP_DIRECTOROUT_PTR_MSG) string_view {
Py_ssize_t len;
%#ifdef SWIG_PYTHON_STRICT_BYTE_CHAR
const char *p = PyBytes_AsString($input);
@ -86,9 +86,8 @@ namespace std {
const char *p;
PyObject *bytes = NULL;
if (PyUnicode_Check($input)) {
/* Note: The UTF-8 data is cached in the PyObject so remains valid for
* the call to C/C++. */
p = PyUnicode_AsUTF8AndSize($input, &len);
p = SWIG_PyUnicode_AsUTF8AndSize($input, &len, &bytes);
// Py_XDECREF(bytes); // Avoid undefined behaviour ($input will be pointing to a temporary if bytes is not NULL), for now we just leak by not calling Py_XDECREF
} else {
p = PyBytes_AsString($input);
if (p) len = PyBytes_Size($input);

View File

@ -54,7 +54,7 @@
%define SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG "454:Setting a pointer/reference variable may leak memory." %enddef
%define SWIGWARN_TYPEMAP_WCHARLEAK_MSG "455:Setting a const wchar_t * variable may leak memory." %enddef
%define SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG "470:Thread/reentrant unsafe wrapping, consider returning by value instead." %enddef
%define SWIGWARN_TYPEMAP_DIRECTOROUT_PTR_MSG "473:Returning a pointer or reference in a director method is not recommended." %enddef
%define SWIGWARN_TYPEMAP_DIRECTOROUT_PTR_MSG "473:Returning a reference, pointer or pointer wrapper in a director method is not recommended." %enddef
%define SWIGWARN_TYPEMAP_INITIALIZER_LIST_MSG "476:Initialization using std::initializer_list." %enddef
/* -----------------------------------------------------------------------------