From c3dc9ab31b06c3b35adbac298fefcccdcbf92615 Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Wed, 11 Mar 2026 21:24:05 +0100 Subject: [PATCH 1/4] Replace DATA_PTR and Data_Get_Struct by SWIG_ConvertPtr Mixing ruby functions and SWIG functions to access Ruby/C++ objects is bad practice. It relies on a particular expectation of how SWIG maps C++ objects to Ruby objects. This commit changes the code to use SWIG functions only and to not use raw Ruby functions to access SWIG mapped objects. Also change the flag of ConvertPtr to the SWIG provided constant SWIG_POINTER_DISOWN, to make it more clear, that the object will be deleted by the object it was assigned to. The compiler deprecation warning is re-enabled, since they do no longer appear when built with SWIG with the following patch: https://github.com/swig/swig/pull/3326 Fix type conversions of Array, Array, Array and Array to raise an error on type mismatch. This wasn't checked before and could lead to invalid memory access. --- ext/fox16_c/FXRbApp.cpp | 1 + ext/fox16_c/FXRbDataTarget.cpp | 1 + ext/fox16_c/FXRbGLViewer.cpp | 1 + ext/fox16_c/FXRbObjRegistry.cpp | 13 +++-- ext/fox16_c/FXRuby.cpp | 69 +++++++++++++++++--------- ext/fox16_c/extconf.rb | 2 +- ext/fox16_c/gvl_wrappers.cpp | 1 + ext/fox16_c/impl.cpp | 1 + ext/fox16_c/include/FXRbDCWindow.h | 2 +- ext/fox16_c/include/FXRuby.h | 12 ++--- ext/fox16_c/make_impl.rb | 1 + ext/fox16_c/markfuncs.cpp | 1 + ext/fox16_c/unregisterOwnedObjects.cpp | 1 + swig-interfaces/FXScintilla.i | 2 +- swig-interfaces/FXText.i | 2 +- swig-interfaces/ruby-typemaps.i | 38 +++++++------- test/TC_FXDC.rb | 24 +++++++++ 17 files changed, 117 insertions(+), 55 deletions(-) diff --git a/ext/fox16_c/FXRbApp.cpp b/ext/fox16_c/FXRbApp.cpp index 397aeea6..e9b75f6d 100644 --- a/ext/fox16_c/FXRbApp.cpp +++ b/ext/fox16_c/FXRbApp.cpp @@ -24,6 +24,7 @@ * $Id: FXRbApp.cpp 2902 2008-12-11 14:09:20Z lyle $ ***********************************************************************/ +#include "swigruby.h" #include "FXRbCommon.h" #ifdef HAVE_SYS_TIME_H diff --git a/ext/fox16_c/FXRbDataTarget.cpp b/ext/fox16_c/FXRbDataTarget.cpp index 509a2403..6a0383ba 100644 --- a/ext/fox16_c/FXRbDataTarget.cpp +++ b/ext/fox16_c/FXRbDataTarget.cpp @@ -24,6 +24,7 @@ * $Id: FXRbDataTarget.cpp 2713 2007-11-14 15:27:36Z lyle $ ***********************************************************************/ +#include "swigruby.h" #include "FXRbCommon.h" /** diff --git a/ext/fox16_c/FXRbGLViewer.cpp b/ext/fox16_c/FXRbGLViewer.cpp index 8664af3e..e10b3c97 100644 --- a/ext/fox16_c/FXRbGLViewer.cpp +++ b/ext/fox16_c/FXRbGLViewer.cpp @@ -24,6 +24,7 @@ * $Id: FXRbGLViewer.cpp 2190 2005-08-24 07:58:47Z lyle $ ***********************************************************************/ +#include "swigruby.h" #include "FXRbCommon.h" // Process picks diff --git a/ext/fox16_c/FXRbObjRegistry.cpp b/ext/fox16_c/FXRbObjRegistry.cpp index 953adcb3..2ba28a8e 100644 --- a/ext/fox16_c/FXRbObjRegistry.cpp +++ b/ext/fox16_c/FXRbObjRegistry.cpp @@ -20,9 +20,9 @@ * at "lars@greiz-reinsdorf.de". ***********************************************************************/ +#include "swigruby.h" #include "FXRbCommon.h" #include "FXRbObjRegistry.h" -#include "swigruby.h" FXRbObjRegistry::FXRbObjRegistry(){ FXRuby_Objects=st_init_numtable(); @@ -84,7 +84,7 @@ void FXRbObjRegistry::RegisterRubyObj(VALUE rubyObj,const void* foxObj) { * To avoid double references to the same foxObj from different Ruby objects, * we decouple the foxObj from previoius ruby object and point to the new one. */ - DATA_PTR(desc->obj) = 0; + FXRbConvertPtr(desc->obj, NULL, SWIG_POINTER_RELEASE); desc->obj = rubyObj; desc->type = own; } else { @@ -107,7 +107,14 @@ void FXRbObjRegistry::UnregisterRubyObj(const void* foxObj, bool alsoOwned){ if(st_lookup(FXRuby_Objects,reinterpret_cast(const_cast(foxObj)),reinterpret_cast(&desc))!=0){ if( !alsoOwned && desc->type!=borrowed ) return; FXTRACE((1,"FXRbUnregisterRubyObj(rubyObj=%p (%s),foxObj=%p)\n",(void *)desc->obj,safe_rb_obj_classname(desc->obj),foxObj)); - DATA_PTR(desc->obj)=0; + + if(RB_TYPE_P(desc->obj, RUBY_T_DATA)) { + /* Release unless it's already T_ZOMBIE */ + int res = SWIG_ConvertPtr(desc->obj, NULL, NULL, desc->type==borrowed ? SWIG_POINTER_CLEAR : SWIG_POINTER_RELEASE); + if (res != SWIG_OK){ + rb_bug( "UnregisterRubyObj(rubyObj=%p) error: %d", (void*)desc->obj, res); + } + } FXFREE(&desc); st_delete(FXRuby_Objects,reinterpret_cast(const_cast(&foxObj)),reinterpret_cast(0)); FXASSERT(st_lookup(FXRuby_Objects,reinterpret_cast(const_cast(foxObj)),reinterpret_cast(0))==0); diff --git a/ext/fox16_c/FXRuby.cpp b/ext/fox16_c/FXRuby.cpp index 52b98635..c233addb 100644 --- a/ext/fox16_c/FXRuby.cpp +++ b/ext/fox16_c/FXRuby.cpp @@ -28,13 +28,13 @@ #pragma warning (disable : 4786) #endif +// SWIG runtime functions we need +#include "swigruby.h" + #include "FXRbCommon.h" #include "FXRbObjRegistry.h" #include "impl.h" -// SWIG runtime functions we need -#include "swigruby.h" - #ifdef __CYGWIN__ #include // for get_osf_handle() #endif @@ -842,8 +842,7 @@ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ FXushort id=FXSELID(key); // Extract the FOX object (the receiver) from this Ruby instance - FXObject* obj; - Data_Get_Struct(recv,FXObject,obj); + FXObject *obj = (FXObject*)FXRbConvertPtr(recv, NULL, 0); FXASSERT(type!=SEL_NONE); FXASSERT(type!=SEL_LAST); @@ -896,7 +895,7 @@ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ case SEL_DND_MOTION: case SEL_DND_REQUEST: case SEL_PICKED: - SWIG_ConvertPtr(value,&ptr,FXRbTypeQuery("FXEvent *"),1); + SWIG_ConvertPtr(value,&ptr,FXRbTypeQuery("FXEvent *"),SWIG_POINTER_DISOWN); return ptr; case SEL_IO_READ: case SEL_IO_WRITE: @@ -1072,7 +1071,7 @@ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ if(type==SEL_CHANGED){ if(obj->isMemberOf(FXMETACLASS(FXPicker))){ - SWIG_ConvertPtr(value,&ptr,FXRbTypeQuery("FXPoint *"),1); + SWIG_ConvertPtr(value,&ptr,FXRbTypeQuery("FXPoint *"),SWIG_POINTER_DISOWN); return ptr; } if(obj->isMemberOf(FXMETACLASS(FXWindow))){ @@ -1086,7 +1085,7 @@ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ } if(type==SEL_DRAGGED){ - SWIG_ConvertPtr(value,&ptr,FXRbTypeQuery("FXEvent *"),1); + SWIG_ConvertPtr(value,&ptr,FXRbTypeQuery("FXEvent *"),SWIG_POINTER_DISOWN); return ptr; } @@ -1300,21 +1299,21 @@ FXGLObject* FXRbCallGLObjectMethod_gvlcb(FXGLObject* recv,const char *func){ VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),0); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXGLObject*)FXRbConvertPtr(result, NULL, 0); } FXGLObject* FXRbCallGLObjectMethod_gvlcb(FXGLViewer* recv,const char *func,FXint x,FXint y){ VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),2,INT2NUM(x),INT2NUM(y)); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXGLObject*)FXRbConvertPtr(result, NULL, 0); } FXGLObject* FXRbCallGLObjectMethod_gvlcb(FXGLObject* recv,const char *func,FXuint* path,FXint n){ VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),1,FXRbMakeArray(path,n)); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXGLObject*)FXRbConvertPtr(result, NULL, 0); } //---------------------------------------------------------------------- @@ -1329,7 +1328,8 @@ FXGLObject** FXRbCallGLObjectArrayMethod_gvlcb(FXGLViewer* recv,const char *func Check_Type(result,T_ARRAY); if(FXMALLOC(&objects,FXGLObject*,RARRAY_LEN(result)+1)){ for(long i=0; i(DATA_PTR(rb_ary_entry(result,i))); + VALUE entry = rb_ary_entry(result,i); + objects[i]=(FXGLObject*)FXRbConvertPtr(entry, NULL, 0); } objects[RARRAY_LEN(result)]=0; } @@ -1344,14 +1344,14 @@ FXTableItem* FXRbCallTableItemMethod_gvlcb(FXTable* recv,const char *func,const VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),3,to_ruby(text),to_ruby_cb(icon),itemData); - return NIL_P(result)?0:reinterpret_cast(DATA_PTR(result)); + return (FXTableItem*)FXRbConvertPtr(result, NULL, 0); } FXTableItem* FXRbCallTableItemMethod_gvlcb(FXTable* recv,const char *func,FXint row,FXint col,FXbool notify){ VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),3,to_ruby(row),to_ruby(col),to_ruby(notify)); - return NIL_P(result)?0:reinterpret_cast(DATA_PTR(result)); + return (FXTableItem*)FXRbConvertPtr(result, NULL, 0); } //---------------------------------------------------------------------- @@ -1360,7 +1360,7 @@ FXTreeItem* FXRbCallTreeItemMethod_gvlcb(const FXTreeList* recv,const char *func VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),2,INT2NUM(x),INT2NUM(y)); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXTreeItem*)FXRbConvertPtr(result, NULL, 0); } //---------------------------------------------------------------------- @@ -1369,7 +1369,7 @@ FXFoldingItem* FXRbCallFoldingItemMethod_gvlcb(const FXFoldingList* recv,const c VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),2,INT2NUM(x),INT2NUM(y)); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXFoldingItem*)FXRbConvertPtr(result, NULL, 0); } //---------------------------------------------------------------------- @@ -1378,7 +1378,7 @@ FXFileAssoc* FXRbCallFileAssocMethod_gvlcb(const FXFileDict* recv,const char *fu VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),1,to_ruby(pathname)); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXFileAssoc*)FXRbConvertPtr(result, NULL, 0); } //---------------------------------------------------------------------- @@ -1388,7 +1388,7 @@ FXIcon* FXRbCallIconMethod_gvlcb(const FXTableItem* recv,const char *func){ FXASSERT(!NIL_P(obj)); if(!NIL_P(obj)){ VALUE result=rb_funcall(obj,rb_intern(func),0); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXIcon*)FXRbConvertPtr(result, NULL, 0); } else{ return 0; @@ -1401,7 +1401,7 @@ FXWindow* FXRbCallWindowMethod_gvlcb(const FXTableItem* recv,const char *func,FX VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),1,to_ruby_cb(table)); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXWindow*)FXRbConvertPtr(result, NULL, 0); } //---------------------------------------------------------------------- @@ -1411,7 +1411,7 @@ FXRangef FXRbCallRangeMethod_gvlcb(FXObject* recv,const char *func){ VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),0); - return *reinterpret_cast(DATA_PTR(result)); + return *(FXRangef*)FXRbConvertPtr(result, NULL, 0); } //---------------------------------------------------------------------- @@ -1606,11 +1606,34 @@ FXbool FXRbGLViewer::sortProc(FXfloat*& buffer,FXint& used,FXint& size){ * FXRbConvertPtr() is just a wrapper around SWIG_ConvertPtr(). */ -void* FXRbConvertPtr(VALUE obj,swig_type_info* ty){ +void* FXRbConvertPtr(VALUE obj,swig_type_info* ty, int flags){ void *ptr; - SWIG_ConvertPtr(obj,&ptr,ty,1); - return ptr; + int res = SWIG_ConvertPtr(obj,&ptr,ty,flags); + if( res == SWIG_OK ) return ptr; +#ifdef HAVE_RB_DURING_GC + if( rb_during_gc() ){ + rb_bug( "FXRbConvertPtr got wrong argument type rubyObj=%p", (void*)obj); } +#endif + if( res == SWIG_ERROR_RELEASE_NOT_OWNED ){ + rb_raise( rb_eTypeError, "clean and disown of non-owned object is not allowed: %" PRIsVALUE, obj); + } + if( res == SWIG_NullReferenceError ){ + rb_raise( rb_eTypeError, "object can not be NULL: %" PRIsVALUE, obj); + } + if( res == SWIG_ObjectPreviouslyDeletedError ){ + if(ty){ + rb_raise( rb_eTypeError, "the object has already been deleted: %" PRIsVALUE, ((swig_class *) (ty->clientdata))->klass); + } else { + rb_raise( rb_eTypeError, "the object has already been deleted"); + } + } + if(ty){ + rb_raise( rb_eTypeError, "wrong argument type %" PRIsVALUE ", expected kind of %" PRIsVALUE, rb_obj_class(obj), ((swig_class *) (ty->clientdata))->klass ); + } else { + rb_raise( rb_eTypeError, "wrong argument type %" PRIsVALUE, rb_obj_class(obj) ); + } +} // Returns an FXInputHandle for this Ruby file object diff --git a/ext/fox16_c/extconf.rb b/ext/fox16_c/extconf.rb index a429670d..74740c3c 100755 --- a/ext/fox16_c/extconf.rb +++ b/ext/fox16_c/extconf.rb @@ -366,7 +366,7 @@ def install if RbConfig::MAKEFILE_CONFIG['CC'] =~ /gcc/ $CXXFLAGS += " -Wno-unused-function" $CXXFLAGS += " -Wno-maybe-uninitialized" - $CXXFLAGS += " -Wno-attribute-warning -Wno-deprecated-declarations" + $CXXFLAGS += " -Wno-attribute-warning" end # Last step: build the makefile diff --git a/ext/fox16_c/gvl_wrappers.cpp b/ext/fox16_c/gvl_wrappers.cpp index 66229c71..8f99fe46 100644 --- a/ext/fox16_c/gvl_wrappers.cpp +++ b/ext/fox16_c/gvl_wrappers.cpp @@ -3,6 +3,7 @@ * */ +#include "swigruby.h" #include "FXRbCommon.h" #ifdef HAVE___THREAD diff --git a/ext/fox16_c/impl.cpp b/ext/fox16_c/impl.cpp index ed45a122..904d9e52 100644 --- a/ext/fox16_c/impl.cpp +++ b/ext/fox16_c/impl.cpp @@ -1,3 +1,4 @@ +#include "swigruby.h" #include "FXRbCommon.h" /* Start stub implementations for class FXMemoryBuffer */ diff --git a/ext/fox16_c/include/FXRbDCWindow.h b/ext/fox16_c/include/FXRbDCWindow.h index d2d0245c..0c2fd2db 100644 --- a/ext/fox16_c/include/FXRbDCWindow.h +++ b/ext/fox16_c/include/FXRbDCWindow.h @@ -44,7 +44,7 @@ class FXRbDCWindow : public FXDCWindow { // Helper for FXDCWindow initialization block static VALUE endit(VALUE obj){ - FXDCWindow* dc=reinterpret_cast(DATA_PTR(obj)); + FXDCWindow* dc=(FXDCWindow*)FXRbConvertPtr(obj, NULL, 0); FXASSERT(dc!=0); dc->end(); return Qnil; diff --git a/ext/fox16_c/include/FXRuby.h b/ext/fox16_c/include/FXRuby.h index 00aaf196..ddf641cc 100644 --- a/ext/fox16_c/include/FXRuby.h +++ b/ext/fox16_c/include/FXRuby.h @@ -48,7 +48,7 @@ static int FXSWIG_ConvertPtr(VALUE obj, void **ptr, swig_type_info *ty, int flag template VALUE showHelper(VALUE self, int argc, VALUE *argv, TYPE *p, swig_type_info *typeinfo) { TYPE *win; - FXSWIG_ConvertPtr(self,(void**)&win,typeinfo,1); + FXSWIG_ConvertPtr(self,(void**)&win,typeinfo,SWIG_POINTER_DISOWN); if (argc == 0) { win->_show(); } @@ -73,7 +73,7 @@ bool FXRbIsInGC(const void* ptr); swig_type_info *FXRbTypeQuery(const char *name); // Wrapper around SWIG_ConvertPtr() -void* FXRbConvertPtr(VALUE obj,swig_type_info* typeinfo); +void* FXRbConvertPtr(VALUE obj,swig_type_info* typeinfo, int flags); // Returns an FXInputHandle for this Ruby file object FXInputHandle FXRbGetReadFileHandle(VALUE obj,FXuint mode); @@ -694,7 +694,7 @@ FXIcon* FXRbCallIconMethod_gvlcb(const FXIconSource *recv,const char *func,TYPE1 VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),2,to_ruby(arg1),to_ruby(arg2)); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXIcon*)FXRbConvertPtr(result, NULL, 0); } template @@ -702,7 +702,7 @@ FXIcon* FXRbCallIconMethod_gvlcb(const FXIconSource *recv,const char *func,TYPE1 VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),4,to_ruby(arg1),to_ruby(arg2),to_ruby(arg3),to_ruby(arg4)); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXIcon*)FXRbConvertPtr(result, NULL, 0); } // Call functions with FXImage* return value @@ -711,7 +711,7 @@ FXImage* FXRbCallImageMethod_gvlcb(const FXIconSource *recv,const char *func,TYP VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),2,to_ruby(arg1),to_ruby(arg2)); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXImage*)FXRbConvertPtr(result, NULL, 0); } template @@ -719,7 +719,7 @@ FXImage* FXRbCallImageMethod_gvlcb(const FXIconSource *recv,const char *func,TYP VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,rb_intern(func),4,to_ruby(arg1),to_ruby(arg2),to_ruby(arg3),to_ruby(arg4)); - return NIL_P(result) ? 0 : reinterpret_cast(DATA_PTR(result)); + return (FXImage*)FXRbConvertPtr(result, NULL, 0); } // Call functions with "FXWindow*" return value diff --git a/ext/fox16_c/make_impl.rb b/ext/fox16_c/make_impl.rb index 3cf4377c..08f6acd7 100755 --- a/ext/fox16_c/make_impl.rb +++ b/ext/fox16_c/make_impl.rb @@ -110,6 +110,7 @@ def end_class fcpp = File.new('impl.cpp', 'wb') finc = File.new('./include/inlinestubs.h', 'wb') +fcpp.puts '#include "swigruby.h"' fcpp.puts '#include "FXRbCommon.h"' Dir.glob("./include/FX*.h").sort.each do |file| unless file =~ /BitmapView/ diff --git a/ext/fox16_c/markfuncs.cpp b/ext/fox16_c/markfuncs.cpp index 2b973164..55bbf66b 100644 --- a/ext/fox16_c/markfuncs.cpp +++ b/ext/fox16_c/markfuncs.cpp @@ -2,6 +2,7 @@ * $Id: markfuncs.cpp 2928 2008-12-29 19:16:57Z lyle $ ***********************************************************************/ +#include "swigruby.h" #include "FXRbCommon.h" #ifdef MARK diff --git a/ext/fox16_c/unregisterOwnedObjects.cpp b/ext/fox16_c/unregisterOwnedObjects.cpp index 157025d4..08d629fc 100644 --- a/ext/fox16_c/unregisterOwnedObjects.cpp +++ b/ext/fox16_c/unregisterOwnedObjects.cpp @@ -23,6 +23,7 @@ * but which have somehow been "exposed" to the Ruby layer. */ +#include "swigruby.h" #include "FXRbCommon.h" void FXRbHeader::unregisterOwnedObjects(FXHeader *self) diff --git a/swig-interfaces/FXScintilla.i b/swig-interfaces/FXScintilla.i index fb10d943..dc26af0e 100644 --- a/swig-interfaces/FXScintilla.i +++ b/swig-interfaces/FXScintilla.i @@ -177,7 +177,7 @@ public: lp=(lParam==Qtrue) ? 1 : 0; break; case T_DATA: - lp=reinterpret_cast(DATA_PTR(lParam)); + lp = (sptr_t)FXRbConvertPtr(lParam, NULL, 0); break; default: lp=0; diff --git a/swig-interfaces/FXText.i b/swig-interfaces/FXText.i index f3001908..4ec33b2d 100644 --- a/swig-interfaces/FXText.i +++ b/swig-interfaces/FXText.i @@ -722,7 +722,7 @@ public: text->styles=new FXHiliteStyle[text->numStyles]; for (long i=0; inumStyles; i++){ FXHiliteStyle* ptr; - SWIG_ConvertPtr(rb_ary_entry(styles,i),(void **)&ptr,SWIGTYPE_p_FXHiliteStyle,1); + SWIG_ConvertPtr(rb_ary_entry(styles,i),(void **)&ptr,SWIGTYPE_p_FXHiliteStyle,SWIG_POINTER_DISOWN); text->styles[i]=*ptr; } self->setHiliteStyles(text->styles); diff --git a/swig-interfaces/ruby-typemaps.i b/swig-interfaces/ruby-typemaps.i index 856c5c73..20591b8f 100644 --- a/swig-interfaces/ruby-typemaps.i +++ b/swig-interfaces/ruby-typemaps.i @@ -247,7 +247,7 @@ inline void* to_FXEvent(VALUE obj){ FXEventTypeInfo=SWIG_TypeQuery("FXEvent *"); FXASSERT(FXEventTypeInfo!=0); } - SWIG_ConvertPtr(obj,&ptr,FXEventTypeInfo,1); + SWIG_ConvertPtr(obj,&ptr,FXEventTypeInfo,SWIG_POINTER_DISOWN); return ptr; } %} @@ -278,7 +278,7 @@ inline void* to_FXEvent(VALUE obj){ } /* Convert a Ruby FXDirItem instance into a pointer to a C++ FXDirItem */ -%typemap(in) void* PTR_DIRITEM "SWIG_ConvertPtr($input,&$1,SWIGTYPE_p_FXDirItem,1);"; +%typemap(in) void* PTR_DIRITEM "SWIG_ConvertPtr($input,&$1,SWIGTYPE_p_FXDirItem,SWIG_POINTER_DISOWN);"; %typemap(in) void* PTR_EVENT "$1 = to_FXEvent($input);"; @@ -293,7 +293,7 @@ inline void* to_FXEvent(VALUE obj){ /* Convert a Ruby FXIcon reference to a pointer to an FXIcon */ %typemap(in) void* PTR_ICON(void *tmp) { - tmp = FXRbConvertPtr($input, FXRbTypeQuery("FXIcon *")); + tmp = FXRbConvertPtr($input, FXRbTypeQuery("FXIcon *"), SWIG_POINTER_DISOWN); $1 = (void *) &tmp; } @@ -329,10 +329,10 @@ inline void* to_FXEvent(VALUE obj){ %typemap(in) void* PTR_NULL "$1 = 0;"; /* Convert a Ruby FXObject instance into a pointer to a C++ FXObject */ -%typemap(in) void* PTR_OBJECT "SWIG_ConvertPtr($input,&$1,SWIGTYPE_p_FXObject,1);"; +%typemap(in) void* PTR_OBJECT "SWIG_ConvertPtr($input,&$1,SWIGTYPE_p_FXObject,SWIG_POINTER_DISOWN);"; /* Convert a Ruby FXPoint instance into a pointer to a C++ FXPoint */ -%typemap(in) void* PTR_POINT "$1 = FXRbConvertPtr($input, FXRbTypeQuery(\"FXPoint *\"));"; +%typemap(in) void* PTR_POINT "$1 = FXRbConvertPtr($input, FXRbTypeQuery(\"FXPoint *\"), SWIG_POINTER_DISOWN);"; /* Convert a Ruby number into a pointer to an FXdouble */ %typemap(in) void* PTR_PDOUBLE(FXdouble value) { @@ -353,7 +353,7 @@ inline void* to_FXEvent(VALUE obj){ } /* Convert a Ruby FXTreeItem instance into a pointer to a C++ FXTreeItem */ -%typemap(in) void* PTR_TREEITEM "SWIG_ConvertPtr($input,&$1,SWIGTYPE_p_FXTreeItem,1);"; +%typemap(in) void* PTR_TREEITEM "SWIG_ConvertPtr($input,&$1,SWIGTYPE_p_FXTreeItem,SWIG_POINTER_DISOWN);"; /* Convert a Ruby number into an FXuchar */ %typemap(in) void* PTR_UCHAR "$1 = reinterpret_cast(NUM2UINT($input));"; @@ -371,7 +371,7 @@ inline void* to_FXEvent(VALUE obj){ $1 = new FXVec3f(NUM2DBL(rb_ary_entry($input, 0)), NUM2DBL(rb_ary_entry($input, 1)), NUM2DBL(rb_ary_entry($input, 2))); } else { FXVec3f *p; - SWIG_ConvertPtr($input, (void **)&p, SWIGTYPE_p_FXVec3f, 1); + SWIG_ConvertPtr($input, (void **)&p, SWIGTYPE_p_FXVec3f, SWIG_POINTER_DISOWN); $1 = new FXVec3f(*p); } } @@ -383,7 +383,7 @@ inline void* to_FXEvent(VALUE obj){ tmp = FXVec3f(NUM2DBL(rb_ary_entry($input, 0)), NUM2DBL(rb_ary_entry($input, 1)), NUM2DBL(rb_ary_entry($input, 2))); $1 = &tmp; } else { - SWIG_ConvertPtr($input, (void **) &$1, SWIGTYPE_p_FXVec3f, 1); + SWIG_ConvertPtr($input, (void **) &$1, SWIGTYPE_p_FXVec3f, SWIG_POINTER_DISOWN); } } @@ -397,7 +397,7 @@ inline void* to_FXEvent(VALUE obj){ $1 = new FXVec4f(NUM2DBL(rb_ary_entry($input, 0)), NUM2DBL(rb_ary_entry($input, 1)), NUM2DBL(rb_ary_entry($input, 2)), NUM2DBL(rb_ary_entry($input, 3))); } else { FXVec4f *p; - SWIG_ConvertPtr($input,(void **)&p,SWIGTYPE_p_FXVec4f,1); + SWIG_ConvertPtr($input,(void **)&p,SWIGTYPE_p_FXVec4f,SWIG_POINTER_DISOWN); $1 = new FXVec4f(*p); } } @@ -409,7 +409,7 @@ inline void* to_FXEvent(VALUE obj){ tmp = FXVec4f(NUM2DBL(rb_ary_entry($input, 0)), NUM2DBL(rb_ary_entry($input, 1)), NUM2DBL(rb_ary_entry($input, 2)), NUM2DBL(rb_ary_entry($input, 3))); $1 = &tmp; } else { - SWIG_ConvertPtr($input, (void **) &$1, SWIGTYPE_p_FXVec4f, 1); + SWIG_ConvertPtr($input, (void **) &$1, SWIGTYPE_p_FXVec4f, SWIG_POINTER_DISOWN); } } @@ -651,8 +651,8 @@ inline void* to_FXEvent(VALUE obj){ $1 = new FXPoint[RARRAY_LEN($input)]; $2 = static_cast( RARRAY_LEN($input) ); for (FXuint i = 0; i < $2; i++) { - FXPoint *pPoint; - Data_Get_Struct(rb_ary_entry($input, i), FXPoint, pPoint); + VALUE entry = rb_ary_entry($input, i); + FXPoint *pPoint = (FXPoint*)FXRbConvertPtr(entry, FXRbTypeQuery("FXPoint *"), 0); $1[i] = *pPoint; } } @@ -666,8 +666,8 @@ inline void* to_FXEvent(VALUE obj){ $1 = new FXSegment[RARRAY_LEN($input)]; $2 = static_cast( RARRAY_LEN($input) ); for (FXuint i = 0; i < $2; i++) { - FXSegment *pSeg; - Data_Get_Struct(rb_ary_entry($input, i), FXSegment, pSeg); + VALUE entry = rb_ary_entry($input, i); + FXSegment *pSeg = (FXSegment*)FXRbConvertPtr(entry, SWIGTYPE_p_FXSegment, 0); $1[i] = *pSeg; } } @@ -682,8 +682,8 @@ inline void* to_FXEvent(VALUE obj){ $1 = new FXRectangle[RARRAY_LEN($input)]; $2 = static_cast( RARRAY_LEN($input) ); for (FXuint i = 0; i < $2; i++) { - FXRectangle *pRect; - Data_Get_Struct(rb_ary_entry($input, i), FXRectangle, pRect); + VALUE entry = rb_ary_entry($input, i); + FXRectangle *pRect = (FXRectangle*)FXRbConvertPtr(entry, SWIGTYPE_p_FXRectangle, 0); $1[i] = *pRect; } } @@ -698,8 +698,8 @@ inline void* to_FXEvent(VALUE obj){ $1 = new FXArc[RARRAY_LEN($input)]; $2 = static_cast( RARRAY_LEN($input) ); for (FXuint i = 0; i < $2; i++) { - FXArc *pArc; - Data_Get_Struct(rb_ary_entry($input, i), FXArc, pArc); + VALUE entry = rb_ary_entry($input, i); + FXArc *pArc = (FXArc*)FXRbConvertPtr(entry, SWIGTYPE_p_FXArc, 0); $1[i] = *pArc; } } @@ -766,7 +766,7 @@ inline void* to_FXEvent(VALUE obj){ if (TYPE($input) == T_FIXNUM || TYPE($input) == T_BIGNUM)) { $1 = reinterpret_cast(static_cast(NUM2INT($input))); } else { - SWIG_ConvertPtr($input, (void **) &$1, SWIGTYPE_p_FXWindow, 1); + SWIG_ConvertPtr($input, (void **) &$1, SWIGTYPE_p_FXWindow, SWIG_POINTER_DISOWN); } } diff --git a/test/TC_FXDC.rb b/test/TC_FXDC.rb index 8b1dac74..33a5c427 100755 --- a/test/TC_FXDC.rb +++ b/test/TC_FXDC.rb @@ -59,11 +59,23 @@ def testDrawLinesRel @dc.drawLinesRel(points) end + def testDrawLinesRel_TypeError + points = [ FXPoint.new, FXArc.new ] + msg = assert_raises(TypeError) { @dc.drawLinesRel(points) } + assert_match(/wrong.* Fox::FXArc.*expected.* Fox::FXPoint/i, msg.to_s) + end + def testDrawLineSegments segments = [ FXSegment.new, FXSegment.new ] @dc.drawLineSegments(segments) end + def testDrawLineSegments_TypeError + segments = [ FXSegment.new, FXPoint.new ] + msg = assert_raises(TypeError) { @dc.drawLineSegments(segments) } + assert_match(/wrong.* Fox::FXPoint.*expected.* Fox::FXSegment/i, msg.to_s) + end + def testDrawArc x, y, w, h, ang1, ang2 = 0, 0, 10, 10, 45, 135 @dc.drawArc(x, y, w, h, ang1, ang2) @@ -74,6 +86,12 @@ def testDrawArcs @dc.drawArcs(arcs) end + def testDrawArcs_TypeError + arcs = [ FXPoint.new, FXPoint.new ] + msg = assert_raises(TypeError) { @dc.drawArcs(arcs) } + assert_match(/wrong.* Fox::FXPoint.*expected.* Fox::FXArc/i, msg.to_s) + end + def testFillRectangle x, y, w, h = 0, 0, 20, 20 @dc.fillRectangle(x, y, w, h) @@ -84,6 +102,12 @@ def testFillRectangles @dc.fillRectangles(rectangles) end + def testFillRectangles_TypeError + rectangles = [ FXRectangle.new, FXPoint.new ] + msg = assert_raises(TypeError) { @dc.fillRectangles(rectangles) } + assert_match(/wrong.* Fox::FXPoint.*expected.* Fox::FXRectangle/i, msg.to_s) + end + def testFillArc x, y, w, h, ang1, ang2 = 0, 0, 10, 10, 45, 135 @dc.fillArc(x, y, w, h, ang1, ang2) From 280a54a0ebbb1cb37c8180fbc5d33d3ef7a5824b Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Sat, 21 Mar 2026 16:01:25 +0100 Subject: [PATCH 2/4] Add possibility to enable FXTRACE output by the environment valiable "fxTraceLevel" --- ext/fox16_c/extconf.rb | 1 + test/TS_All.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/ext/fox16_c/extconf.rb b/ext/fox16_c/extconf.rb index 74740c3c..5fc6e533 100755 --- a/ext/fox16_c/extconf.rb +++ b/ext/fox16_c/extconf.rb @@ -356,6 +356,7 @@ def install if enable_config("debug") $CPPFLAGS += " -ggdb" $LDFLAGS += " -ggdb" + $CPPFLAGS += " -DRUBY_DEBUG=1" # define RUBY_DEBUG otherwise ruby/assert.h defines NDEBUG else $CPPFLAGS += " -DNDEBUG" end diff --git a/test/TS_All.rb b/test/TS_All.rb index 0066c24c..ef1a94b9 100755 --- a/test/TS_All.rb +++ b/test/TS_All.rb @@ -1,6 +1,10 @@ require 'fox16' require 'test/unit' +if (l=ENV["fxTraceLevel"].to_i) > 0 + Fox.fxTraceLevel = l +end + if __FILE__ == $0 testdir = File.expand_path("..", __FILE__) $: << testdir From 260eca72a026700f435d6b40e05461506cb42604 Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Sat, 21 Mar 2026 22:11:48 +0100 Subject: [PATCH 3/4] Change the flag of NewPointer to the SWIG provided constant SWIG_POINTER_OWN, to make it clearer. --- ext/fox16_c/FXRbObjRegistry.cpp | 2 +- ext/fox16_c/FXRuby.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/fox16_c/FXRbObjRegistry.cpp b/ext/fox16_c/FXRbObjRegistry.cpp index 2ba28a8e..e8fbcfe0 100644 --- a/ext/fox16_c/FXRbObjRegistry.cpp +++ b/ext/fox16_c/FXRbObjRegistry.cpp @@ -52,7 +52,7 @@ VALUE FXRbObjRegistry::NewBorrowedObj(void *ptr,swig_type_info* ty){ ObjDesc *desc; if(FXMALLOC(&desc,ObjDesc,1)){ - VALUE obj = SWIG_Ruby_NewPointerObj(ptr,ty,1); + VALUE obj = SWIG_Ruby_NewPointerObj(ptr,ty,SWIG_POINTER_OWN); FXTRACE((1,"FXRbNewPointerObj(foxObj=%p) => rubyObj=%p (%s)\n",ptr,(void *)obj,safe_rb_obj_classname(obj))); desc->obj = obj; desc->type = borrowed; diff --git a/ext/fox16_c/FXRuby.cpp b/ext/fox16_c/FXRuby.cpp index c233addb..b2d7ea9b 100644 --- a/ext/fox16_c/FXRuby.cpp +++ b/ext/fox16_c/FXRuby.cpp @@ -74,7 +74,7 @@ VALUE FXRbNewPointerObj(void *ptr,swig_type_info* ty){ } VALUE FXRbNewPointerObjCb(void *ptr,swig_type_info* ty){ - return SWIG_Ruby_NewPointerObj(ptr, ty, 1); + return SWIG_Ruby_NewPointerObj(ptr, ty, SWIG_POINTER_OWN); } From daf94c70e6170e1301081b9fb7403ac52c43aef0 Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Fri, 27 Mar 2026 09:42:40 +0100 Subject: [PATCH 4/4] Clear SWIG object only, without checking ownership Because SWIG-ownership gets dropped when the Fox object is assigned to some other Fox object. --- ext/fox16_c/FXRbObjRegistry.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/fox16_c/FXRbObjRegistry.cpp b/ext/fox16_c/FXRbObjRegistry.cpp index e8fbcfe0..31b69eeb 100644 --- a/ext/fox16_c/FXRbObjRegistry.cpp +++ b/ext/fox16_c/FXRbObjRegistry.cpp @@ -108,9 +108,9 @@ void FXRbObjRegistry::UnregisterRubyObj(const void* foxObj, bool alsoOwned){ if( !alsoOwned && desc->type!=borrowed ) return; FXTRACE((1,"FXRbUnregisterRubyObj(rubyObj=%p (%s),foxObj=%p)\n",(void *)desc->obj,safe_rb_obj_classname(desc->obj),foxObj)); + /* Release unless it's already T_ZOMBIE */ if(RB_TYPE_P(desc->obj, RUBY_T_DATA)) { - /* Release unless it's already T_ZOMBIE */ - int res = SWIG_ConvertPtr(desc->obj, NULL, NULL, desc->type==borrowed ? SWIG_POINTER_CLEAR : SWIG_POINTER_RELEASE); + int res = SWIG_ConvertPtr(desc->obj, NULL, NULL, SWIG_POINTER_CLEAR); if (res != SWIG_OK){ rb_bug( "UnregisterRubyObj(rubyObj=%p) error: %d", (void*)desc->obj, res); }