The directorin typemap fixed a couple of commits ago is in the Unified
Typemap Library and so is shared by every language defining SWIG_Object,
but the test for it was written twice, once against PyObject * and once
against VALUE. Replace python_director_pyobject and ruby_director_value
with director_langobj, written against SWIG_Object in the same spirit as
the existing langobj test, and run it from the common test list so that
every language at least compiles it.
Runme files are added for the four languages that define both
SWIG_Object and SWIG_DIRECTOR_TYPEMAPS, that is the four that generate
director code and were affected: Python, Ruby, Perl and Octave. Tcl, R
and Scilab define SWIG_Object but have no directors, so they get compile
only coverage.
python_director_pyobject is kept for the Python specific parts that have
no equivalent in the other languages: the swig::SwigPtr_PyObject and
swig::SwigVar_PyObject smart pointers, by value and by const reference,
and a null PyObject * argument.
Assisted-by: Claude Code (Opus 5)
There is a directorin typemap for SWIG_Object but none for
SWIG_Object const &, so the const reference form fell through to the
generic SWIGTYPE *const& typemap and was wrapped as an opaque proxy
object instead of being passed through unchanged. Affects every
language defining both SWIG_Object and SWIG_DIRECTOR_TYPEMAPS, that is
Python, Ruby, Perl and Octave. For Ruby the generated code did not even
compile, as SWIG_as_voidptr cannot cast a VALUE to void *.
For Python this also covers swig::SwigPtr_PyObject const& and
swig::SwigVar_PyObject const&, which are %applied from PyObject *const&.
Additionally fix a reference count leak for a swig::SwigVar_PyObject
director method argument passed by value. Assigning it into the
SwigVar_PyObject wrapper variable selects the implicitly declared copy
assignment operator, which adds a reference of its own, so the typemap's
SWIG_Py_XINCREF was a second increment against a single decrement on
scope exit. Casting to PyObject * selects
SwigVar_PyObject::operator=(PyObject *), which does not adjust the
count, making the SWIG_Py_XINCREF the one and only increment for every
argument type the typemap handles.
The existing python_director_pyobject test did not catch the leak
because its C++ caller built the SwigVar_PyObject from a borrowed raw
pointer, so the temporary stole a reference and cancelled it out. The
callers are now reference count neutral, the const reference forms are
covered, and the test checks that the object arriving in Python is the
object passed from C++, not just that the count is stable.
Assisted-by: Claude Code (Opus 5)
A bare #define at the start of a line in a brace delimited %fragment body is
consumed by the SWIG preprocessor and never reaches the generated wrapper. The
macro therefore only exists at SWIG level and code that SWIG does not macro
expand, such as a typemap delimited with %{ ... %}, is left referring to an
undefined name. Use %#define so the definition is emitted for the C compiler.
Fixes SWIG_FromCharPtrAndSize for Python, SWIG_FromBinaryCharPtrAndSize for
Octave, Perl, R and Ruby, SWIG_ToUint8Array and SWIG_FromUint8Array for
JavaScript, and the SWIG_AsVal_* and SWIG_From_* macros in the Scilab char,
short, signed char, unsigned char, unsigned long and long long files.
Lib/scilab/scipointer.swg is deliberately left alone. Its fragments are never
requested by any typemap, so they are only emitted as SWIG preprocessor
definitions; switching them to %#define drops SWIG_ConvertPtr and
SWIG_NewPointerObj from the generated code entirely. Fixing those needs the
definitions moving to a runtime insert, as the other target languages do.
Add a common test case charptr_fragment. It uses a %{ ... %} delimited typemap
so the macro name survives into the wrapper, which only compiles when the
library defines the macro for the C compiler. The target languages without
these macros wrap the same functions using their default typemaps. Verified
that the generated Python module fails to load before this change with an
undefined symbol for SWIG_FromCharPtrAndSize.
Follows on from #3522.
Assisted-by: Claude Code (Opus 5)
A character constant containing more than one character, e.g. 'ab', has
type int per both the C standard (6.4.4.4p10) and the C++ standard
([lex.ccon], which describes it as a "multicharacter literal"). SWIG
previously classified every character constant as char regardless of
length, which caused the generated wrapper accessor for a constant such
as #define X 'ab' to be declared char instead of int, silently
truncating the value.
The literal text is left untouched (SWIG does not evaluate constant
expressions), only the internal type tag changes, so the real compiler
that builds the generated wrapper still computes the (implementation
defined) value, exactly as it would for hand written C/C++ code.
Add a new C-only multichar_constant.i test case with per-language runme
files, and keep the new csharp/java char_constant runme files (which
had no coverage before) for the existing, unrelated character constant
checks.
Compiling a real multicharacter constant always triggers GCC's
-Wmultichar warning. #pragma GCC diagnostic ignored "-Wmultichar" does
not suppress it: this is a known, longstanding GCC C++ front-end bug
(gcc.gnu.org PR57241/PR53431, fixed in GCC 13) - verified locally that
it fails identically on GCC 11 and 12 regardless of file- or
function-level pragma scope, while working fine in C or with GCC 13+
or Clang (which also defines __GNUC__ but doesn't have this bug).
The new testcase avoids the warning entirely, with no build system
changes needed:
- The %inline global variable imulti_ab uses the real literal (guarded
by the pragma) wherever that's known to work, and otherwise falls
back to reconstructing the identical value GCC's own packing of
'ab' produces (most significant byte first) without writing a
multicharacter literal at all - the same symbol name and type either
way, so the generated accessor links correctly regardless of which
branch was compiled.
- The #define-driven MULTICHAR_AB constant (whose registration code is
auto-generated per target language, so a similar fallback isn't
portable to hand-write once for every language) is skipped entirely
for octave and javascript's node/napi/v8 engines, the only
configurations that always compile the generated wrapper as C++
regardless of SWIG's own -c/-c++ mode (their runtime APIs require
it) and so would otherwise still hit the GCC bug above.
Verified against both GCC 13 (default) and GCC 11 (matching the actual
CI toolchain that originally failed) across all configured languages.
Assisted-by: Claude Code (Sonnet 5)
Hand written code targeting SWIG 4.4 and earlier invalidates a proxy object
with 'DATA_PTR(obj) = NULL', which used to clear the wrapped C/C++ pointer.
SWIG 4.5 stores that pointer in a swig_ruby_wrapped_object reached through
RTYPEDDATA_GET_DATA, so the assignment now detaches the wrapper itself unless
Ruby embedded it in the object slot, which it only does from Ruby 3.3. The next
conversion of the object then dereferenced a null wrapper and crashed.
Treat a detached object as one whose pointer has been cleared, restoring the
pre 4.5 behaviour, and guard the remaining wrapper dereferences in
SWIG_Ruby_AcquirePtr, SWIG_RubyUnlinkObjects and the mark and free callbacks.
Extend ruby_manual_proxy, which models the Subversion Ruby bindings, with the
legacy close idiom that this fixes.
Closes#3512
Assisted-by: Claude Code (Opus 5)
R::enumvalueDeclaration built the enum item label passed to
defineEnumeration from the C++ name rather than sym:name, so %rename of an
enum item was not honoured in the generated R code. Use sym:name for the
label.
Add test coverage for %rename of an enum class and an enum item to the
cpp11_strongly_typed_enumerations runme of every target language that has
one, locking in the behaviour for the languages that were already correct.
The enum_thorough R runme now checks the renamed enum item too.
Assisted-by: Claude Code (Opus 4.8)
Reported on the swig-devel mailing list during early testing of swig-4.5,
where CrossWire SWORD's Perl bindings (GBFHTMLHREF::MyUserData deriving
from BasicFilterUserData) failed to build: a protected or private nested
class deriving from a class used elsewhere in the wrapped API could produce
a runtime upcast helper function referencing the nested class by its
inaccessible qualified name, a C++ compile error. No target language ever
wraps a non-public nested class, so typepass.cxx now simply skips
registering it for the cast table. Fixes it for Lua too, which hits the
same bug as Perl/Python/Ruby/Tcl despite having full nested class support,
since Java/C# are structurally immune (they don't use SWIG's generic
runtime type table at all). Added regression tests to nested_scope.i and
director_protected.i (covering directors/dirprot), with a runtime check in
every director_protected runme confirming polymorphic dispatch through the
wrapped base still works correctly.
Assisted-by: Claude Code (Sonnet 5)
A 'char *&' (a reference to a char pointer) was only marshalled as a string by
C#, D, Go, Java and PHP; every other language treated it as an opaque char **
pointer. Add char *& string typemaps to the languages that were missing them,
so a char *& function argument, return value or variable is marshalled as a
string in every target language. SWIG's const reference stripping means this
also covers char *const&.
- Lib/typemaps/strings.swg: add Char *& to the %typemaps_string in, freearg,
out, typecheck and director typemaps. This gives char *& to the languages
that use the Unified Typemap Library (Python, Ruby, Perl, Tcl, Octave, Scilab,
R and JavaScript). The shared in typemap now casts &buf to $1_ltype so that a
const char * reference hidden behind a typedef also compiles.
- Lib/lua/luatypemaps.swg, Lib/guile/typemaps.i, Lib/ocaml/ocaml.swg: these
define their own char * string typemaps; give each char *& and const char *&
in/out/freearg typemaps too.
- Lib/r/rtype.swg: the C wrapper returned the char *& string correctly but the R
proxy wrapped it as an undefined _p_p_char S4 class; add char *& to the
scoerceout char list so it is returned as a plain character value.
char_strings.i is now exercised by a runme in every target language, all testing
the same set of functions (get/set/pingpong/global variables and all four char *&
functions), giving complete char *& typemap coverage and testing.
Where a language genuinely cannot support part of the char array portion of the
test (a char[] global has no varin typemap in most scripting languages, a char[16]
parameter is bounds checked, and Guile/OCaml reject char[] parameters), that one
assertion is adapted or skipped with an inline comment; the char *& coverage is
complete everywhere.
Assisted-by: Claude Code (Opus 4.8)
The runme passed the director callback as a temporary argument to Caller.new
without keeping any Ruby reference to it. After the constructor returned, the
only thing referencing the director was the raw, non-owning Callback pointer
stored inside the C++ Caller, which Ruby's garbage collector cannot see. If a
GC ran between constructing the Caller and calling caller.call(), the director
proxy was collected and its C++ director deleted, leaving Caller::_callback
dangling. The subsequent _callback->run() then dispatched through freed memory:
swig_get_self() read the recycled swig_self slot, intermittently observed on CI
as Qfalse, giving "undefined method 'run' for false", and reproducible locally
as a segfault under GC.stress.
Hold the callback in a local variable for the duration of the call, matching the
sibling director_binary_string test and the Python, Java, PHP and Perl runmes
for this same interface. Verified with GC.stress = true: the old code crashed
5/5 runs, the fixed code passed 20/20.
Assisted-by: Claude Code (Opus 4.8)
Embedded data (RUBY_TYPED_EMBEDDABLE) was only enabled on the anonymous
swig_type_data_type descriptor. Wrapped class objects use the per-class
SwigClass*.cext_type descriptor, whose flags were left zero, so they were never
embedded: the swig_ruby_wrapped_object was allocated separately and, since the
free callback no longer calls ruby_xfree once embedding is compiled in, leaked
on every object.
Set cext_type.flags from a shared SWIG_RUBY_TYPED_DATA_FLAGS macro, used by both
the static swig_type_data_type and the generated per-class descriptors so they
can not drift apart. The flags member, and the macro, only exist from Ruby 2.1
(guarded by RUBY_TYPED_FREE_IMMEDIATELY), so the build still works on Ruby 2.0.
Add test ruby_typeddata_embedded which checks that a wrapped object is embedded
on Ruby 3.3 and later via RTYPEDDATA_EMBEDDED_P.
Assisted-by: Claude Opus 4.8
Reverts f029beffe8 - a GC collecting the "hello"
string in the testcase resulting in occasional segfault.
No longer happens with the recently applied fix for #3385 which reworked
SwigGCReferences to retain every tracked object in an st_table and pin them
with rb_gc_mark.
Closes#2115
Ruby objects stored in wrapped STL containers are held by swig::GC_VALUE
as raw VALUEs in C++ - the std::map and std::set keys and the
BinaryPredicate comparator proc. The keep alive registry SwigGCReferences
kept those objects alive but did not pin them, so Ruby 3.x heap
compaction (GC.compact or GC.auto_compact) could relocate them, leaving
the C++ copies dangling and segfaulting the next time the comparator ran.
SwigGCReferences now backs its registry with an st_table instead of a
Ruby Hash, avoiding any C++ STL dependency in the wrapper, and registers
a mark callback that marks every tracked object with the pinning mark
rb_gc_mark. That keeps the objects alive and stops compaction moving
them. Keying the st_table by the VALUE also means register and unregister
no longer dispatch a method on the object.
Add a compaction stress regression to li_std_functors_runme.rb, and drop
the Ruby 3.3 skip that was previously hiding this crash.
Assisted-by: Claude Code (Opus 4.8)
With the one-byte overflow fixed, the li_cdata_bytes tests no longer
corrupt the heap, so the macOS skips - added because free() crashed
"occasionally" - can be removed.
- Remove the Darwin skips from the Perl, Python and Ruby li_cdata_bytes
runme files; the Ruby skip was also pinned to one exact Ruby version.
- Python runme: skip via an early sys.exit() on Python 2 rather than
wrapping the whole body in a conditional, which previously made the
test pass without running anything.
- Few other minor cleanups.
Fix guile cdata.
Add SWIG_BINSTR flag
- Add SWIG_FromBinCharPtrAndSize with the new flag
To add languages that use Lib/cdata.i.
- python use binary string by using the new SWIG_BINSTR
in SWIG_AsCharPtrAndSize and SWIG_FromBinCharPtrAndSize.
Languages that were changed to uses list
- Tcl use list of integers.
- scilab use list of uint8.
And support passing list of numbers to C.
Add support to JavaScript
- use Uint8Array instead of strings.
- Add li_cdata_carrays. tests.
- Add li_cdata_bytes tests.
- Use Debian node-addon-api package location.
- napi folder location to Examples/test-suite/javascript/Makefile.in.
- Update documentation.
Update cdata.i documentation
This new cdata test focus on:
- Ensure we can receive proper data from C and pass proper data back to C.
- Use all possoble byte values , i.e. the full range of 0 to 255
and ensure values 128 to 255 do not pass Unicode transformation (UTF-8/16).
- Ensure zero is a valid value and not a string null termination
nor a modified UTF-8 which transform U+0000 to 0xC0 0x80.
- Check mutability of the cdata object.
Signed-off-by: Erez Geva <ErezGeva2@gmail.com>
* Ruby add number of lines after calling `swig_assert_each_line`.
* Skip buggy ruby
Ruby 2.4 and 2.6 are buggy, that is why they were removed from rvm.
These are 7 years old.
So just remove them from `linux.yml`
Ruby released version 4.0 recently.
And most developers moved to Ruby 3 or newer.
`li_std_functors` break occasionally with Ruby 3.3
Some error inside `GC_VALUE`.
Generate segfault instead of Ruby exception.
This happens occasionally with Ruby.
See the `import_fragments` test.
Signed-off-by: Erez Geva <ErezGeva2@gmail.com>
- Add changes entry for new Lua shared_ptr support.
- Rename director_smartptr test to director_shared_ptr.
- Reimplement cpp11_shared_ptr test cases so that they are run by all
languages (in common.mk instead of being in chosen language's Makefile.in files).
This makes sure missing tests are run by all languages that support
shared_ptr.
* Add a minimal director test
The purpose of this test is to provide
the minimal test the prove a language
support the director feature.
The test does not replace any of the other director tests.
But merely a starting point.
* alphabetical order fix
Signed-off-by: Erez Geva <ErezGeva2@gmail.com>
Co-authored-by: William S Fulton <wsf@fultondesigns.co.uk>
- Enhanced configure.
- Add Windows separator for calling ruby with multiple directories.
- Rename names in test cases which conflict with Windows headers used by Ruby.
- The three Ruby tests are testing Ruby with MinGW-w64 using Universal CRT.
- Also fixes recently disabled ruby test because of ::at_quick_exit compiler problem which was due to incorrect mixing of MINGW64 and UCRT64 runtimes - closes#3237.
Note:
VER=''", ruby 3.4 comes from MSYS2 repository (MINGW-W64).
While VER='3.2', ruby 3.2 and VER='3.3', ruby 3.3 are installed on GitHub Windows runner.
Avoid import_fragments testcase testing for buggy ruby-3.1.x and ruby-3.2.x.
Closes#2800.
I've run ruby-3.3 testing on Github Actions 8 times and flakiness in
cpp11_rvalue_reference_move testcase seems to have gone away using
latest 3.3.x version (3.3.8). Restoring latest 3.3.x testing to see how
it goes.
Closes issue #3030.
We need to strip qualifiers before checking the type is `bool`.
This mainly affects Python. In Ruby there's equivalent code, but
it is only use to generate documentation comments.
Fixes#3052
Most languages now use "NullReferenceError" in the error message
where they previously used "ValueError". Also exception changes:
Guile: "swig-null-reference-error" instead of "swig-value-error"
MzScheme: "swig-null-reference-error" instead of "swig-value-error"
PHP: zend_ce_type_error instead of zend_ce_value_error
Python: Consistently raises TypeError instead of a mix of ValueError
and TypeError.
Ruby: Consistently raises NullReferenceError instead of a mix of
ArgumentError and NullReferenceErrorError.
The consistent raising of a TypeError instead of ValueError for Python
ensures that incorrectly passing 'None' into a C++ reference argument
will correctly convert the error into a NotImplemented error for
the rich comparisons implementations per PEP 207. Fixes#2987
Note that the li_constraints checking implementation for the NONNULL
typemap for pointers also makes the same error change from
SWIG_ValueError to SWIG_NullReferenceError.
The D typemaps use SWIG_DNullReferenceException instead of
SWIG_DIllegalArgumentException, although this ultimately has no change
as the same D Exception is still thrown.
* char_binary_java_fix-tidyup:
Move SWIGStringWithLengthHelper to csharphead.swg
cdata whitespace/cosmetic fixups
cdata doc updates
Rename `typemaps/cdata_struct.swg` to `typemaps/cdata_begin.swg`. And `typemaps/cdata.swg` to `typemaps/cdata.swg`. Move `cdata_apply.swg` content to `typemaps/cdata.swg`.
Group the C# marshalling of STRING-LENGTH typemap into C# class named SWIGStringWithLengthHelper.
Leave Length & string reverse order typemap in typemaps/strings.swg
Support old C# as "LPUTF8Str" was add in 2017.
Improve documentation. Follow @wsfulton reviews.
Use a dummy for MzScheme and untested OCaml cdate. To prevent compilation error.
Further fixing follow reviews.
Reorganise raw data typemap, so typemaps folder contain only common part. Improve document.
Inline SWIG_string_to_utf8_bytes SWIG_utf8_bytes_to_string code
Fixes of STRING/BYTES LENGTH typemaps.
Conflicts:
CHANGES.current
instead of copy constructor when passing movable types. This was
previously implemented only for parameters passed to a global function
or static member function and is now extended to member methods.
Enhancement to e777b054d5.
Fix Java STRING LENGTH typemap.
Use string type in static typed languages (Java, C#, D and Go).
Add BYTES LENGTH typemap and apply it for binary data.
Use byte type in static typed languages.
Add li_cdata_cpp, li_cdata and char_binary
tests for most of languages(apart from R and experimental).
Fix the director_binary_string test and add it to C#, D, Go,
Perl, PHP, Python, Ruby and octave.
Update documents.
Signed-off-by: Erez Geva <ErezGeva2@gmail.com>
Fix setslice(), reinitialise iterator to begin after calling erase().
Fix comparison of integer expressions of different signedness
in getslice() functions.
Fix __setitem__() resize use with new item only if any.
In RubySequence_Cont structure, use standard 'size_t' for size_type.
Add 'li_std_containers_int' test to ruby.
Signed-off-by: Erez Geva <ErezGeva2@gmail.com>
For UTL languages. Previously a copy of the
STL container was made into a target language container when reading the
variable. Changes, such as adjusting an element or adding/erasing
elements, were made to the copy of the container rather the actual
underlying C++ container. Also applies to const reference STL static
members.
Issue #2745
A different approach is taken for supporting casting smart pointers up the
inheritance hierarchy. We no longer try to replace the underlying pointer type,
provided in the 'feature:smartptr', with the base class type. Such as morphing
'std::shared_ptr<(Derived)>' into 'std::shared_ptr<(Base)>'. Instead, we simply
use 'feature:smartptr' from the base class. This is more reliable than trying to
pattern match the pointer type in the feature. The base class must of course
also have the 'feature:smartptr' set, and this is still checked for as before.
The feature is now parsed in one place and stored in the parse tree in the
new 'smart' attribute for handling by the target languages.
Fix also improves the handling of the type parsed in 'feature:smartptr' in that
the type is now normalized and resolved in the scope of the class it is attached
to.
Closes#2768
With Perl the returned string is still being corrupted (the testcase
flags this as "TODO" for Perl's test harness).
Warnings aren't currently emitted for Perl, Ruby or Tcl as I'm not
seeing where in the UTL maze the directorout typemap actually gets
defined.
* ruby-lower-bound-checking:
Ruby: Add check for lower bounds of unsigned long (long) parameters
Ruby: Add test case for checking bounds of integral function parameters
* issue/2625:
Enhanced std::map for non-default constructible types changes entry
Add missing exception.i for std::map wrappers for MzScheme and Guile
std::map wrappers and non-default constructible
Fixed make file ordering
Fixed line endings
Added unit test
Using #ifdef instead of #if to prevent warnings
Fix for #2625 Using c++17 insert_or_assign for std::map when available.
Conflicts:
CHANGES.current