Fix seg fault passing invalid unicode values to std::string

Problem reported as starting with python-3.13.
Due to error not being cleared before calling Python C APIs.

The alternative could have been to ensure SWIG_AsCharPtrAndSize
never returns with a pending error (not that easy).

Closes #3051
This commit is contained in:
William S Fulton 2024-10-20 13:39:11 +01:00
parent 32afafda33
commit d06382ec2a
5 changed files with 56 additions and 31 deletions

View File

@ -7,6 +7,10 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.3.0 (in progress)
===========================
2024-10-20: wsfulton
#3051 Fix seg fault passing invalid unicode values when expecting a
std::string type - fix for python-3.13.
2024-10-19: olly
[ruby] Documentation comments now use `true` and `false` for bool
parameter default values, instead of `True` and `False` (which are

View File

@ -1,9 +1,25 @@
import sys
from li_std_string import *
def check(condition):
if not condition:
raise RuntimeError
# Bad Unicode input check
# This check is run first to check that %error_clear is called the first time SWIG_AsPtr_std_string()
# is called setting the descriptor singleton (by calling SWIG_TypeQuery()).
# Bug https://github.com/swig/swig/issues/3051.
exceptionRaised = False
try:
if sys.version_info[0:2] < (3, 0):
v = u"./\uDCFC.conf"
else:
v = "./\uDCFC.conf"
test_value(v)
except TypeError:
exceptionRaised = True
check(exceptionRaised)
# Checking expected use of %typemap(in) std::string {}
test_value("Fee")
@ -13,9 +29,9 @@ check(test_value("Fi") == "Fi")
# Verify type-checking for %typemap(in) std::string {}
exceptionRaised = False
try:
test_value(0)
test_value(0)
except TypeError:
exceptionRaised = True
exceptionRaised = True
check(exceptionRaised)
# Checking expected use of %typemap(in) const std::string & {}
@ -27,9 +43,9 @@ check(test_const_reference("Fum") == "Fum")
# Verify type-checking for %typemap(in) const std::string & {}
exceptionRaised = False
try:
test_const_reference(0)
test_const_reference(0)
except TypeError:
exceptionRaised = True
exceptionRaised = True
check(exceptionRaised)
#
@ -40,9 +56,9 @@ check(exceptionRaised)
exceptionRaised = False
try:
test_pointer("foo")
test_pointer("foo")
except TypeError:
exceptionRaised = True
exceptionRaised = True
check(exceptionRaised)
result = test_pointer_out()
@ -50,9 +66,9 @@ check(not isinstance(result, str))
exceptionRaised = False
try:
test_const_pointer("bar")
test_const_pointer("bar")
except TypeError:
exceptionRaised = True
exceptionRaised = True
check(exceptionRaised)
result = test_const_pointer_out()
@ -60,9 +76,9 @@ check(not isinstance(result, str))
exceptionRaised = False
try:
test_reference("foo")
test_reference("foo")
except TypeError:
exceptionRaised = True
exceptionRaised = True
check(exceptionRaised)
result = test_reference_out()
@ -72,50 +88,50 @@ check(not isinstance(result, str))
# Member Strings
myStructure = Structure()
if myStructure.MemberString2 != "member string 2":
raise RuntimeError
raise RuntimeError
s = "Hello"
myStructure.MemberString2 = s
if myStructure.MemberString2 != s:
raise RuntimeError
raise RuntimeError
if myStructure.ConstMemberString != "const member string":
raise RuntimeError
raise RuntimeError
if cvar.Structure_StaticMemberString2 != "static member string 2":
raise RuntimeError
raise RuntimeError
cvar.Structure_StaticMemberString2 = s
if cvar.Structure_StaticMemberString2 != s:
raise RuntimeError
raise RuntimeError
if Structure.ConstStaticMemberString != "const static member string":
raise RuntimeError
raise RuntimeError
if test_reference_input("hello") != "hello":
raise RuntimeError
raise RuntimeError
s = test_reference_inout("hello")
if s != "hellohello":
raise RuntimeError
raise RuntimeError
if test_reference_output() != "output":
raise RuntimeError
raise RuntimeError
if stdstring_empty() != "":
raise RuntimeError
raise RuntimeError
if c_empty() != "":
raise RuntimeError
raise RuntimeError
if c_null() != None:
raise RuntimeError
raise RuntimeError
if get_null(c_null()) != None:
raise RuntimeError
raise RuntimeError
if get_null(c_empty()) != "non-null":
raise RuntimeError
raise RuntimeError
if get_null(stdstring_empty()) != "non-null":
raise RuntimeError
raise RuntimeError

View File

@ -57,6 +57,9 @@
/* raise */
#define SWIG_Raise(obj, type, desc) SWIG_Python_Raise(obj, type, desc)
/* clear errors */
#define %error_clear PyErr_Clear()
/* Include the unified typemap library */
%include <typemaps/swigtypemaps.swg>

View File

@ -17,12 +17,8 @@ SWIG_AsPtr_dec(String)(SWIG_Object obj, String **val)
return SWIG_OLDOBJ;
}
} else {
static int init = 0;
static swig_type_info* descriptor = 0;
if (!init) {
descriptor = SWIG_TypeQuery(#String " *");
init = 1;
}
%error_clear;
static swig_type_info *descriptor = SWIG_TypeQuery(#String " *");
if (descriptor) {
String *vptr;
int res = SWIG_ConvertPtr(obj, (void**)&vptr, descriptor, 0);

View File

@ -121,6 +121,12 @@
#endif
#endif
/*==== clear errors ====*/
#ifndef %error_clear
#define %error_clear
#endif
/*==== director output exception ====*/
#if defined(SWIG_DIRECTOR_TYPEMAPS)