From 88a0e228a9c80bedc414164f17b26be0147da333 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 18 Dec 2013 01:28:32 +0100 Subject: [PATCH] Change the length of strings created from fixed-size buffers. Use the usual C rule for NUL-terminated strings instead of discarding all the trailing NUL characters. This was unexpected (as buffers in C code are not necessarily always padded with NULs to their full length) and also inconsistent among languages as this was only done for those of them using typemaps/strings.swg but not for C# or Java, for example, which terminated the string at the first NUL even before this change. Notice that this patch couldn't use strlen() or wcslen() with possibly not NUL-terminated strings, so we had to add [our own equivalents of] strnlen() and wcsnlen() and use them instead. This required adding yet another parameter to string typemap macros, so update the example using them accordingly too. --- CHANGES.current | 8 ++++ Examples/perl5/xmlstring/xmlstring.i | 12 ++++++ .../test-suite/perl5/primitive_types_runme.pl | 2 +- Examples/test-suite/primitive_types.i | 2 +- .../python/primitive_types_runme.py | 2 +- Lib/typemaps/string.swg | 13 +++++- Lib/typemaps/strings.swg | 42 ++++++++++++------- Lib/typemaps/wstring.swg | 14 ++++++- 8 files changed, 75 insertions(+), 20 deletions(-) diff --git a/CHANGES.current b/CHANGES.current index 59ebeebcd..680765d40 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -5,6 +5,14 @@ See the RELEASENOTES file for a summary of changes in each release. Version 3.0.0 (in progress) ============================ +2013-12-23: vadz + [Octave, Perl, Python, R, Ruby, Tcl] Change the length of strings created from fixed-size char + buffers in C code. + + This is a potential backwards compatibility break: a "char buf[5]" containing "ho\0la" was + returned as a string of length 5 before, but is returned as a string of length 2 now. Apply + "char FIXSIZE[ANY]" typemaps to explicitly choose the old behaviour. + 2013-12-23: talby [Perl] Add support for directors. diff --git a/Examples/perl5/xmlstring/xmlstring.i b/Examples/perl5/xmlstring/xmlstring.i index 3ef53169d..861e1b84d 100644 --- a/Examples/perl5/xmlstring/xmlstring.i +++ b/Examples/perl5/xmlstring/xmlstring.i @@ -93,6 +93,17 @@ SWIG_FromXMLChPtrAndSize(const XMLCh* input, size_t size) } } +%fragment("SWIG_XMLStringNLen","header") { +size_t +SWIG_XMLStringNLen(const XMLCh* s, size_t maxlen) +{ + const XMLCh *p; + for (p = s; maxlen-- && *p; p++) + ; + return p - s; +} +} + %init { if (!SWIG_UTF8Transcoder()) { croak("ERROR: XML::Xerces: INIT: Could not create UTF-8 transcoder"); @@ -106,6 +117,7 @@ SWIG_FromXMLChPtrAndSize(const XMLCh* input, size_t size) SWIG_AsXMLChPtrAndSize, SWIG_FromXMLChPtrAndSize, XERCES_CPP_NAMESPACE::XMLString::stringLen, + SWIG_XMLStringNLen, "", INT_MIN, INT_MAX); diff --git a/Examples/test-suite/perl5/primitive_types_runme.pl b/Examples/test-suite/perl5/primitive_types_runme.pl index 31604ad06..688b241c2 100755 --- a/Examples/test-suite/perl5/primitive_types_runme.pl +++ b/Examples/test-suite/perl5/primitive_types_runme.pl @@ -166,7 +166,7 @@ $t->{var_paramd} = $primitive_types::sct_paramd; $t->{var_paramc} = $primitive_types::sct_paramc; ok($t->v_check(), 'v_check'); -is($primitive_types::def_namet, "ho\0la", "namet"); +is($primitive_types::def_namet, "hola", "namet"); $t->{var_namet} = $primitive_types::def_namet; is($t->{var_namet}, $primitive_types::def_namet, "namet"); diff --git a/Examples/test-suite/primitive_types.i b/Examples/test-suite/primitive_types.i index 9425cc1a0..5e3ce3eed 100644 --- a/Examples/test-suite/primitive_types.i +++ b/Examples/test-suite/primitive_types.i @@ -185,7 +185,7 @@ char* const def_pchar = (char *const)"hello"; const char* const def_pcharc = "hija"; - const namet def_namet = {'h','o',0, 'l','a'}; + const namet def_namet = {'h','o','l','a', 0}; extern namet gbl_namet; diff --git a/Examples/test-suite/python/primitive_types_runme.py b/Examples/test-suite/python/primitive_types_runme.py index be8d38bad..0986da5ad 100644 --- a/Examples/test-suite/python/primitive_types_runme.py +++ b/Examples/test-suite/python/primitive_types_runme.py @@ -165,7 +165,7 @@ t.var_paramc = sct_paramc t.v_check() # this value contains a '0' char! -if def_namet != 'ho\0la': +if def_namet != 'hola': print "bad namet", def_namet raise RuntimeError diff --git a/Lib/typemaps/string.swg b/Lib/typemaps/string.swg index 279ee2a41..1bf0bd15a 100644 --- a/Lib/typemaps/string.swg +++ b/Lib/typemaps/string.swg @@ -17,8 +17,19 @@ SWIG_pchar_descriptor(void) } } +%fragment("SWIG_strnlen","header",fragment="SWIG_FromCharPtrAndSize") { +size_t +SWIG_strnlen(const char* s, size_t maxlen) +{ + const char *p; + for (p = s; maxlen-- && *p; p++) + ; + return p - s; +} +} %include %typemaps_string(%checkcode(STRING), %checkcode(CHAR), - char, Char, SWIG_AsCharPtrAndSize, SWIG_FromCharPtrAndSize, strlen, + char, Char, SWIG_AsCharPtrAndSize, SWIG_FromCharPtrAndSize, + strlen, SWIG_strnlen, "", CHAR_MIN, CHAR_MAX) diff --git a/Lib/typemaps/strings.swg b/Lib/typemaps/strings.swg index 55e9d2bb5..79ad85cd6 100644 --- a/Lib/typemaps/strings.swg +++ b/Lib/typemaps/strings.swg @@ -22,6 +22,7 @@ SWIG_AsCharPtrAndSize, SWIG_FromCharPtrAndSize, SWIG_CharPtrLen, + SWIG_CharBufLen, SWIG_AsCharPtr, SWIG_FromCharPtr, SWIG_AsCharArray, @@ -276,12 +277,13 @@ } %typemap(freearg) const Char (&)[ANY] ""; -%typemap(out,fragment=#SWIG_FromCharPtrAndSize) +%typemap(out,fragment=#SWIG_FromCharPtrAndSize,fragment=#SWIG_CharBufLen) Char [ANY], const Char[ANY] { - size_t size = $1_dim0; %#ifndef SWIG_PRESERVE_CARRAY_SIZE - while (size && ($1[size - 1] == '\0')) --size; + size_t size = SWIG_CharBufLen($1, $1_dim0); +%#else + size_t size = $1_dim0; %#endif %set_output(SWIG_FromCharPtrAndSize($1, size)); } @@ -298,23 +300,25 @@ /* varout */ -%typemap(varout,noblock=1,fragment=#SWIG_FromCharPtrAndSize) +%typemap(varout,noblock=1,fragment=#SWIG_CharBufLen) Char [ANY], const Char [ANY] { - size_t size = $1_dim0; %#ifndef SWIG_PRESERVE_CARRAY_SIZE - while (size && ($1[size - 1] == '\0')) --size; + size_t size = SWIG_CharBufLen($1, $1_dim0); +%#else + size_t size = $1_dim0; %#endif %set_varoutput(SWIG_FromCharPtrAndSize($1, size)); } /* constant */ -%typemap(constcode,fragment=#SWIG_FromCharPtrAndSize) +%typemap(constcode,fragment=#SWIG_CharBufLen) Char [ANY], const Char [ANY] { - size_t size = $value_dim0; %#ifndef SWIG_PRESERVE_CARRAY_SIZE - while (size && ($value[size - 1] == '\0')) --size; + size_t size = SWIG_CharBufLen($1, $1_dim0); +%#else + size_t size = $value_dim0; %#endif %set_constant("$symname", SWIG_FromCharPtrAndSize($value,size)); } @@ -323,12 +327,13 @@ #if defined(SWIG_DIRECTOR_TYPEMAPS) /* directorin */ -%typemap(directorin,fragment=#SWIG_FromCharPtrAndSize) +%typemap(directorin,fragment=#SWIG_CharBufLen) Char [ANY], const Char [ANY] { - size_t size = $1_dim0; %#ifndef SWIG_PRESERVE_CARRAY_SIZE - while (size && ($1[size - 1] == '\0')) --size; + size_t size = SWIG_CharBufLen($1, $1_dim0); +%#else + size_t size = $1_dim0; %#endif $input = SWIG_FromCharPtrAndSize($1, size); } @@ -360,12 +365,13 @@ /* throws */ -%typemap(throws,fragment=#SWIG_FromCharPtrAndSize) +%typemap(throws,fragment=#SWIG_CharBufLen) Char [ANY], const Char[ANY] { - size_t size = $1_dim0; %#ifndef SWIG_PRESERVE_CARRAY_SIZE - while (size && ($1[size - 1] == '\0')) --size; + size_t size = SWIG_CharBufLen($1, $1_dim0); +%#else + size_t size = $1_dim0; %#endif %raise(SWIG_FromCharPtrAndSize($1, size), "$type", 0); } @@ -499,6 +505,7 @@ SWIG_AsCharPtrAndSize, SWIG_FromCharPtrAndSize, SWIG_CharPtrLen, + SWIG_CharBufLen, SWIG_NewCopyCharArray, SWIG_DeleteCharArray, FragLimits, CHAR_MIN, CHAR_MAX) @@ -586,6 +593,7 @@ SWIG_AsVal_dec(Char)(SWIG_Object obj, Char *val) SWIG_AsCharPtrAndSize, SWIG_FromCharPtrAndSize, SWIG_CharPtrLen, + SWIG_CharBufLen, SWIG_As##CharName##Ptr, SWIG_From##CharName##Ptr, SWIG_As##CharName##Array, @@ -604,12 +612,14 @@ SWIG_AsVal_dec(Char)(SWIG_Object obj, Char *val) SWIG_AsCharPtrAndSize, SWIG_FromCharPtrAndSize, SWIG_CharPtrLen, + SWIG_CharBufLen, FragLimits, CHAR_MIN, CHAR_MAX) %_typemap2_string(StringCode, CharCode, Char, CharName, SWIG_AsCharPtrAndSize, SWIG_FromCharPtrAndSize, SWIG_CharPtrLen, + SWIG_CharBufLen, %new_copy_array, %delete_array, FragLimits, CHAR_MIN, CHAR_MAX) @@ -624,6 +634,7 @@ SWIG_AsVal_dec(Char)(SWIG_Object obj, Char *val) SWIG_AsCharPtrAndSize, SWIG_FromCharPtrAndSize, SWIG_CharPtrLen, + SWIG_CharBufLen, SWIG_NewCopyCharArray, SWIG_DeleteCharArray, FragLimits, CHAR_MIN, CHAR_MAX) @@ -632,6 +643,7 @@ SWIG_AsVal_dec(Char)(SWIG_Object obj, Char *val) SWIG_AsCharPtrAndSize, SWIG_FromCharPtrAndSize, SWIG_CharPtrLen, + SWIG_CharBufLen, SWIG_NewCopyCharArray, SWIG_DeleteCharArray, FragLimits, CHAR_MIN, CHAR_MAX) diff --git a/Lib/typemaps/wstring.swg b/Lib/typemaps/wstring.swg index 2567dc782..1f2de8221 100644 --- a/Lib/typemaps/wstring.swg +++ b/Lib/typemaps/wstring.swg @@ -18,8 +18,20 @@ SWIG_pwchar_descriptor() } } +%fragment("SWIG_wcsnlen","header",fragment="SWIG_FromWCharPtrAndSize") { +size_t +SWIG_wcsnlen(const wchar_t* s, size_t maxlen) +{ + const wchar_t *p; + for (p = s; maxlen-- && *p; p++) + ; + return p - s; +} +} + %include %typemaps_string(%checkcode(UNISTRING), %checkcode(UNICHAR), - wchar_t, WChar, SWIG_AsWCharPtrAndSize, SWIG_FromWCharPtrAndSize, wcslen, + wchar_t, WChar, SWIG_AsWCharPtrAndSize, SWIG_FromWCharPtrAndSize, + wcslen, SWIG_wcsnlen, "", WCHAR_MIN, WCHAR_MAX)