From a73f9ccc1f2c8862094872f46f773f7ee39f6c33 Mon Sep 17 00:00:00 2001 From: Wayward Heart <91356680+WaywardHeart@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:44:02 -0500 Subject: [PATCH] Prevent memory leaks from rb_raise rb_raise calls longjmp, which bypasses C++ destructors, and also keeps the error for catch blocks from being unallocated if passed by reference, which we do for exceptions. Some of the calls I left can still jump out of try blocks, which you're not supposed to do, but there shouldn't be any objects with destructors initialized at those points so it's probably fine. --- binding/audio-binding.cpp | 27 ++- binding/binding-mri.cpp | 59 ++--- binding/binding-util.cpp | 380 ++++++++++++++++-------------- binding/binding-util.h | 128 ++++++---- binding/bitmap-binding.cpp | 145 +++++++----- binding/cusl-binding.cpp | 5 +- binding/filesystem-binding.cpp | 16 +- binding/graphics-binding.cpp | 6 +- binding/http-binding.cpp | 16 +- binding/input-binding.cpp | 61 ++--- binding/miniffi-binding.cpp | 12 +- binding/sceneelement-binding.h | 18 +- binding/serializable-binding.h | 13 +- binding/sprite-binding.cpp | 10 +- binding/table-binding.cpp | 10 +- binding/viewportelement-binding.h | 3 +- binding/window-binding.cpp | 3 +- src/util/exception.h | 7 +- 18 files changed, 529 insertions(+), 390 deletions(-) diff --git a/binding/audio-binding.cpp b/binding/audio-binding.cpp index aaa56bb..1e6d177 100644 --- a/binding/audio-binding.cpp +++ b/binding/audio-binding.cpp @@ -25,17 +25,18 @@ #include "exception.h" #define DEF_PLAY_STOP_POS(entity) \ - RB_METHOD(audio_##entity##Play) \ + RB_METHOD_GUARD(audio_##entity##Play) \ { \ RB_UNUSED_PARAM; \ const char *filename; \ int volume = 100; \ int pitch = 100; \ double pos = 0.0; \ - rb_get_args(argc, argv, "z|iif", &filename, &volume, &pitch, &pos RB_ARG_END); \ - GUARD_EXC( shState->audio().entity##Play(filename, volume, pitch, pos); ) \ + rb_get_args(argc, argv, "z|iif", &filename, &volume, &pitch, &pos RB_ARG_END); \ + shState->audio().entity##Play(filename, volume, pitch, pos); \ return Qnil; \ } \ + RB_METHOD_GUARD_END \ RB_METHOD(audio_##entity##Stop) \ { \ RB_UNUSED_PARAM; \ @@ -49,16 +50,17 @@ } #define DEF_PLAY_STOP(entity) \ - RB_METHOD(audio_##entity##Play) \ + RB_METHOD_GUARD(audio_##entity##Play) \ { \ RB_UNUSED_PARAM; \ const char *filename; \ int volume = 100; \ int pitch = 100; \ rb_get_args(argc, argv, "z|ii", &filename, &volume, &pitch RB_ARG_END); \ - GUARD_EXC( shState->audio().entity##Play(filename, volume, pitch); ) \ + shState->audio().entity##Play(filename, volume, pitch); \ return Qnil; \ } \ + RB_METHOD_GUARD_END \ RB_METHOD(audio_##entity##Stop) \ { \ RB_UNUSED_PARAM; \ @@ -87,7 +89,7 @@ RB_METHOD(audio_##entity##Fade) \ #define MAYBE_NIL_TRACK(t) t == Qnil ? -127 : NUM2INT(t) -RB_METHOD(audio_bgmPlay) +RB_METHOD_GUARD(audio_bgmPlay) { RB_UNUSED_PARAM; const char *filename; @@ -96,9 +98,10 @@ RB_METHOD(audio_bgmPlay) double pos = 0.0; VALUE track = Qnil; rb_get_args(argc, argv, "z|iifo", &filename, &volume, &pitch, &pos, &track RB_ARG_END); - GUARD_EXC( shState->audio().bgmPlay(filename, volume, pitch, pos, MAYBE_NIL_TRACK(track)); ) + shState->audio().bgmPlay(filename, volume, pitch, pos, MAYBE_NIL_TRACK(track)); return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(audio_bgmStop) { @@ -117,25 +120,27 @@ RB_METHOD(audio_bgmPos) return rb_float_new(shState->audio().bgmPos(MAYBE_NIL_TRACK(track))); } -RB_METHOD(audio_bgmGetVolume) +RB_METHOD_GUARD(audio_bgmGetVolume) { RB_UNUSED_PARAM; VALUE track = Qnil; rb_get_args(argc, argv, "|o", &track RB_ARG_END); int ret = 0; - GUARD_EXC( ret = shState->audio().bgmGetVolume(MAYBE_NIL_TRACK(track)); ) + ret = shState->audio().bgmGetVolume(MAYBE_NIL_TRACK(track)); return rb_fix_new(ret); } +RB_METHOD_GUARD_END -RB_METHOD(audio_bgmSetVolume) +RB_METHOD_GUARD(audio_bgmSetVolume) { RB_UNUSED_PARAM; int volume; VALUE track = Qnil; rb_get_args(argc, argv, "i|o", &volume, &track RB_ARG_END); - GUARD_EXC( shState->audio().bgmSetVolume(volume, MAYBE_NIL_TRACK(track)); ) + shState->audio().bgmSetVolume(volume, MAYBE_NIL_TRACK(track)); return Qnil; } +RB_METHOD_GUARD_END DEF_PLAY_STOP_POS( bgs ) diff --git a/binding/binding-mri.cpp b/binding/binding-mri.cpp index 35289bc..f6da12c 100644 --- a/binding/binding-mri.cpp +++ b/binding/binding-mri.cpp @@ -528,14 +528,15 @@ RB_METHOD(mkxpSystemMemory) { return INT2NUM(SDL_GetSystemRAM()); } -RB_METHOD(mkxpReloadPathCache) { +RB_METHOD_GUARD(mkxpReloadPathCache) { RB_UNUSED_PARAM; - GUARD_EXC(shState->fileSystem().reloadPathCache();); + shState->fileSystem().reloadPathCache(); return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(mkxpAddPath) { +RB_METHOD_GUARD(mkxpAddPath) { RB_UNUSED_PARAM; VALUE path, mountpoint, reload; @@ -545,36 +546,32 @@ RB_METHOD(mkxpAddPath) { const char *mp = (mountpoint == Qnil) ? 0 : RSTRING_PTR(mountpoint); - try { - bool rl = true; - if (reload != Qnil) - rb_bool_arg(reload, &rl); - - shState->fileSystem().addPath(RSTRING_PTR(path), mp, rl); - } catch (Exception &e) { - raiseRbExc(e); - } + bool rl = true; + if (reload != Qnil) + rb_bool_arg(reload, &rl); + + shState->fileSystem().addPath(RSTRING_PTR(path), mp, rl); + return path; } +RB_METHOD_GUARD_END -RB_METHOD(mkxpRemovePath) { +RB_METHOD_GUARD(mkxpRemovePath) { RB_UNUSED_PARAM; VALUE path, reload; rb_scan_args(argc, argv, "11", &path, &reload); SafeStringValue(path); - try { - bool rl = true; - if (reload != Qnil) - rb_bool_arg(reload, &rl); - - shState->fileSystem().removePath(RSTRING_PTR(path), rl); - } catch (Exception &e) { - raiseRbExc(e); - } + bool rl = true; + if (reload != Qnil) + rb_bool_arg(reload, &rl); + + shState->fileSystem().removePath(RSTRING_PTR(path), rl); + return path; } +RB_METHOD_GUARD_END RB_METHOD(mkxpFileExists) { RB_UNUSED_PARAM; @@ -601,24 +598,25 @@ RB_METHOD(mkxpSetDefaultFontFamily) { return Qnil; } -RB_METHOD(mkxpStringToUTF8) { +RB_METHOD_GUARD(mkxpStringToUTF8) { RB_UNUSED_PARAM; rb_check_argc(argc, 0); std::string ret(RSTRING_PTR(self), RSTRING_LEN(self)); - GUARD_EXC(ret = Encoding::convertString(ret); ); + ret = Encoding::convertString(ret); return rb_utf8_str_new(ret.c_str(), ret.length()); } +RB_METHOD_GUARD_END -RB_METHOD(mkxpStringToUTF8Bang) { +RB_METHOD_GUARD(mkxpStringToUTF8Bang) { RB_UNUSED_PARAM; rb_check_argc(argc, 0); std::string ret(RSTRING_PTR(self), RSTRING_LEN(self)); - GUARD_EXC(ret = Encoding::convertString(ret); ); + ret = Encoding::convertString(ret); rb_str_resize(self, ret.length()); memcpy(RSTRING_PTR(self), ret.c_str(), RSTRING_LEN(self)); @@ -629,6 +627,7 @@ RB_METHOD(mkxpStringToUTF8Bang) { return self; } +RB_METHOD_GUARD_END #ifdef __APPLE__ #define OPENCMD "open " @@ -641,7 +640,7 @@ RB_METHOD(mkxpStringToUTF8Bang) { #define OPENARGS "" #endif -RB_METHOD(mkxpLaunch) { +RB_METHOD_GUARD(mkxpLaunch) { RB_UNUSED_PARAM; VALUE cmdname, args; @@ -674,11 +673,12 @@ RB_METHOD(mkxpLaunch) { } if (std::system(command.c_str()) != 0) { - raiseRbExc(Exception(Exception::MKXPError, "Failed to launch \"%s\"", RSTRING_PTR(cmdname))); + throw Exception(Exception::MKXPError, "Failed to launch \"%s\"", RSTRING_PTR(cmdname)); } return RUBY_Qnil; } +RB_METHOD_GUARD_END json5pp::value loadUserSettings() { json5pp::value ret; @@ -722,7 +722,7 @@ RB_METHOD(mkxpGetJSONSetting) { } -RB_METHOD(mkxpSetJSONSetting) { +RB_METHOD_GUARD(mkxpSetJSONSetting) { RB_UNUSED_PARAM; VALUE sname, svalue; @@ -736,6 +736,7 @@ RB_METHOD(mkxpSetJSONSetting) { return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(mkxpGetAllJSONSettings) { RB_UNUSED_PARAM; diff --git a/binding/binding-util.cpp b/binding/binding-util.cpp index 5a09723..bd8cea8 100644 --- a/binding/binding-util.cpp +++ b/binding/binding-util.cpp @@ -50,28 +50,35 @@ RbData::RbData() { exc[IOError] = rb_eIOError; exc[TypeError] = rb_eTypeError; exc[ArgumentError] = rb_eArgError; + exc[SystemExit] = rb_eSystemExit; + exc[RuntimeError] = rb_eRuntimeError; } RbData::~RbData() {} /* Indexed with Exception::Type */ -static const RbException excToRbExc[] = { +const RbException excToRbExc[] = { RGSS, /* RGSSError */ ErrnoENOENT, /* NoFileError */ IOError, - TypeError, ArgumentError, + TypeError, ArgumentError, SystemExit, RuntimeError, PHYSFS, /* PHYSFSError */ SDL, /* SDLError */ MKXP /* MKXPError */ }; -void raiseRbExc(const Exception &exc) { +VALUE excToRbClass(const Exception &exc) { + RbData *data = getRbData(); + return data->exc[excToRbExc[exc.type]]; +} + +void raiseRbExc(Exception exc) { RbData *data = getRbData(); VALUE excClass = data->exc[excToRbExc[exc.type]]; - rb_raise(excClass, "%s", exc.msg.c_str()); + rb_raise(excClass, "%s", exc.msg); } void raiseDisposedAccess(VALUE self) { @@ -89,207 +96,224 @@ void raiseDisposedAccess(VALUE self) { } int rb_get_args(int argc, VALUE *argv, const char *format, ...) { - char c; - VALUE *arg = argv; - va_list ap; - bool opt = false; - int argI = 0; + Exception *exc = 0; + try{ + char c; + VALUE *arg = argv; + va_list ap; + bool opt = false; + int argI = 0; - va_start(ap, format); + va_start(ap, format); - while ((c = *format++)) { - switch (c) { - case '|': - break; - default: - // FIXME print num of needed args vs provided - if (argc <= argI && !opt) - rb_raise(rb_eArgError, "wrong number of arguments"); + while ((c = *format++)) { + switch (c) { + case '|': + break; + default: + // FIXME print num of needed args vs provided + if (argc <= argI && !opt) + rb_raise(rb_eArgError, "wrong number of arguments"); - break; - } + break; + } - if (argI >= argc) - break; - - switch (c) { - case 'o': { if (argI >= argc) break; - VALUE *obj = va_arg(ap, VALUE *); + switch (c) { + case 'o': { + if (argI >= argc) + break; - *obj = *arg++; - ++argI; + VALUE *obj = va_arg(ap, VALUE *); - break; - } + *obj = *arg++; + ++argI; - case 'S': { - if (argI >= argc) + break; + } + + case 'S': { + if (argI >= argc) + break; + + VALUE *str = va_arg(ap, VALUE *); + VALUE tmp = *arg; + + if (!RB_TYPE_P(tmp, RUBY_T_STRING)) + rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); + + *str = tmp; + ++argI; + + break; + } + + case 's': { + if (argI >= argc) + break; + + const char **s = va_arg(ap, const char **); + int *len = va_arg(ap, int *); + + VALUE tmp = *arg; + + if (!RB_TYPE_P(tmp, RUBY_T_STRING)) + rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); + + *s = RSTRING_PTR(tmp); + *len = RSTRING_LEN(tmp); + ++argI; + + break; + } + + case 'z': { + if (argI >= argc) + break; + + const char **s = va_arg(ap, const char **); + + VALUE tmp = *arg++; + + if (!RB_TYPE_P(tmp, RUBY_T_STRING)) + rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); + + *s = RSTRING_PTR(tmp); + ++argI; + + break; + } + + case 'f': { + if (argI >= argc) + break; + + double *f = va_arg(ap, double *); + VALUE fVal = *arg++; + + rb_float_arg(fVal, f, argI); + + ++argI; + break; + } + + case 'i': { + if (argI >= argc) + break; + + int *i = va_arg(ap, int *); + VALUE iVal = *arg++; + + rb_int_arg(iVal, i, argI); + + ++argI; + break; + } + + case 'b': { + if (argI >= argc) + break; + + bool *b = va_arg(ap, bool *); + VALUE bVal = *arg++; + + rb_bool_arg(bVal, b, argI); + + ++argI; + break; + } + + case 'n': { + if (argI >= argc) + break; + + ID *sym = va_arg(ap, ID *); + + VALUE symVal = *arg++; + + if (!SYMBOL_P(symVal)) + rb_raise(rb_eTypeError, "Argument %d: Expected symbol", argI); + + *sym = SYM2ID(symVal); + ++argI; + + break; + } + + case '|': + opt = true; break; - VALUE *str = va_arg(ap, VALUE *); - VALUE tmp = *arg; - - if (!RB_TYPE_P(tmp, RUBY_T_STRING)) - rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); - - *str = tmp; - ++argI; - - break; + default: + rb_raise(rb_eFatal, "invalid argument specifier %c", c); + } } - case 's': { - if (argI >= argc) - break; - - const char **s = va_arg(ap, const char **); - int *len = va_arg(ap, int *); - - VALUE tmp = *arg; - - if (!RB_TYPE_P(tmp, RUBY_T_STRING)) - rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); - - *s = RSTRING_PTR(tmp); - *len = RSTRING_LEN(tmp); - ++argI; - - break; - } - - case 'z': { - if (argI >= argc) - break; - - const char **s = va_arg(ap, const char **); - - VALUE tmp = *arg++; - - if (!RB_TYPE_P(tmp, RUBY_T_STRING)) - rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); - - *s = RSTRING_PTR(tmp); - ++argI; - - break; - } - - case 'f': { - if (argI >= argc) - break; - - double *f = va_arg(ap, double *); - VALUE fVal = *arg++; - - rb_float_arg(fVal, f, argI); - - ++argI; - break; - } - - case 'i': { - if (argI >= argc) - break; - - int *i = va_arg(ap, int *); - VALUE iVal = *arg++; - - rb_int_arg(iVal, i, argI); - - ++argI; - break; - } - - case 'b': { - if (argI >= argc) - break; - - bool *b = va_arg(ap, bool *); - VALUE bVal = *arg++; - - rb_bool_arg(bVal, b, argI); - - ++argI; - break; - } - - case 'n': { - if (argI >= argc) - break; - - ID *sym = va_arg(ap, ID *); - - VALUE symVal = *arg++; - - if (!SYMBOL_P(symVal)) - rb_raise(rb_eTypeError, "Argument %d: Expected symbol", argI); - - *sym = SYM2ID(symVal); - ++argI; - - break; - } - - case '|': - opt = true; - break; - - default: - rb_raise(rb_eFatal, "invalid argument specifier %c", c); - } - } - #ifndef NDEBUG - /* Pop remaining arg pointers off - * the stack to check for RB_ARG_END */ - format--; + /* Pop remaining arg pointers off + * the stack to check for RB_ARG_END */ + format--; - while ((c = *format++)) { - switch (c) { - case 'o': - case 'S': - va_arg(ap, VALUE *); - break; + while ((c = *format++)) { + switch (c) { + case 'o': + case 'S': + va_arg(ap, VALUE *); + break; - case 's': - va_arg(ap, const char **); - va_arg(ap, int *); - break; + case 's': + va_arg(ap, const char **); + va_arg(ap, int *); + break; - case 'z': - va_arg(ap, const char **); - break; + case 'z': + va_arg(ap, const char **); + break; - case 'f': - va_arg(ap, double *); - break; + case 'f': + va_arg(ap, double *); + break; - case 'i': - va_arg(ap, int *); - break; + case 'i': + va_arg(ap, int *); + break; - case 'b': - va_arg(ap, bool *); - break; + case 'b': + va_arg(ap, bool *); + break; + } } - } - // FIXME print num of needed args vs provided - if (!c && argc > argI) - rb_raise(rb_eArgError, "wrong number of arguments"); + // FIXME print num of needed args vs provided + if (!c && argc > argI) + rb_raise(rb_eArgError, "wrong number of arguments"); - /* Verify correct termination */ - void *argEnd = va_arg(ap, void *); - (void)argEnd; - assert(argEnd == RB_ARG_END_VAL); + /* Verify correct termination */ + void *argEnd = va_arg(ap, void *); + (void)argEnd; + assert(argEnd == RB_ARG_END_VAL); #endif - va_end(ap); + va_end(ap); - return argI; + return argI; + } catch (const Exception &e) { + exc = new Exception(e); + } + + /* This should always be true if we reach here */ + if (exc) { + /* Raising here is probably fine, right? + * If any methods allocate something with a destructor before + * calling this then they can probably be fixed to not do that. */ + Exception e(*exc); + delete exc; + rb_raise(excToRbClass(e), "%s", e.msg); + } + + return 0; } diff --git a/binding/binding-util.h b/binding/binding-util.h index da6e59a..8fdacfb 100644 --- a/binding/binding-util.h +++ b/binding/binding-util.h @@ -55,6 +55,8 @@ enum RbException { TypeError, ArgumentError, + SystemExit, + RuntimeError, RbExceptionsMax }; @@ -73,7 +75,8 @@ RbData *getRbData(); struct Exception; -void raiseRbExc(const Exception &exc); +VALUE excToRbClass(const Exception &exc); +void raiseRbExc(Exception exc); #if RAPI_FULL > 187 #define DECL_TYPE(Klass) extern rb_data_type_t Klass##Type @@ -315,16 +318,16 @@ raiseRbExc(exc); \ } \ } -#define GFX_GUARD_EXC(exp) \ -{\ -GFX_LOCK; \ -try {\ +#define GFX_GUARD_EXC(exp) \ +{ \ +GFX_LOCK; \ +try { \ exp \ -} catch (const Exception &exc) {\ -GFX_UNLOCK; \ -raiseRbExc(exc); \ -}\ -GFX_UNLOCK;\ +} catch (const Exception &exc) { \ +GFX_UNLOCK; \ +throw exc; \ +} \ +GFX_UNLOCK; \ } @@ -338,7 +341,7 @@ static inline VALUE objectLoad(int argc, VALUE *argv, VALUE self) { C *c = 0; - GUARD_EXC(c = C::deserialize(data, dataLen);); + c = C::deserialize(data, dataLen); setPrivateData(obj, c); @@ -358,7 +361,7 @@ inline void rb_float_arg(VALUE arg, double *out, int argPos = 0) { break; default: - rb_raise(rb_eTypeError, "Argument %d: Expected float", argPos); + throw Exception(Exception::TypeError, "Argument %d: Expected float", argPos); } } @@ -374,7 +377,7 @@ inline void rb_int_arg(VALUE arg, int *out, int argPos = 0) { break; default: - rb_raise(rb_eTypeError, "Argument %d: Expected fixnum", argPos); + throw Exception(Exception::TypeError, "Argument %d: Expected fixnum", argPos); } } @@ -390,10 +393,13 @@ inline void rb_bool_arg(VALUE arg, bool *out, int argPos = 0) { break; default: - rb_raise(rb_eTypeError, "Argument %d: Expected bool", argPos); + throw Exception(Exception::TypeError, "Argument %d: Expected bool", argPos); } } +/* rb_check_argc and rb_error_arity are both + * consistently called before any C++ objects are allocated, + * so we can just call rb_raise directly in them */ inline void rb_check_argc(int actual, int expected) { if (actual != expected) rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", actual, @@ -431,21 +437,41 @@ static inline VALUE rb_file_open_str(VALUE filename, const char *mode) { (void)self; \ } +/* Calling rb_raise inside the catch block + * leaks memory even if we catch by value */ +#define RB_METHOD_GUARD(name) RB_METHOD(name) \ +{ \ + Exception *exc = 0; \ + try{ \ + +#define RB_METHOD_GUARD_END \ + } catch (const Exception &e) { \ + exc = new Exception(e); \ + } \ + if (exc) { \ + Exception e(*exc); \ + delete exc; \ + rb_raise(excToRbClass(e), "%s", e.msg); \ + } \ + return Qnil; \ +} + #define MARSH_LOAD_FUN(Typ) \ -RB_METHOD(Typ##Load) { return objectLoad(argc, argv, self); } +RB_METHOD_GUARD(Typ##Load) { return objectLoad(argc, argv, self); } RB_METHOD_GUARD_END #define INITCOPY_FUN(Klass) \ -RB_METHOD(Klass##InitializeCopy) { \ +RB_METHOD_GUARD(Klass##InitializeCopy) { \ VALUE origObj; \ rb_get_args(argc, argv, "o", &origObj RB_ARG_END); \ if (!OBJ_INIT_COPY(self, origObj)) /* When would this fail??*/ \ return self; \ Klass *orig = getPrivateData(origObj); \ Klass *k = 0; \ -GUARD_EXC(k = new Klass(*orig);) \ +k = new Klass(*orig); \ setPrivateData(self, k); \ return self; \ -} +} \ +RB_METHOD_GUARD_END /* Object property which is copied by reference, with allowed NIL * FIXME: Getter assumes prop is disposable, @@ -461,7 +487,7 @@ RB_METHOD(Klass##Get##PropName) { \ RB_UNUSED_PARAM; \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ RB_UNUSED_PARAM; \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ @@ -471,17 +497,18 @@ if (NIL_P(propObj)) \ prop = 0; \ else \ prop = getPrivateDataCheck(propObj, PropKlass##Type); \ -GUARD_EXC(k->set##PropName(prop);) \ +k->set##PropName(prop) \ rb_iv_set(self, prop_iv, propObj); \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #else #define DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \ RB_METHOD(Klass##Get##PropName) { \ RB_UNUSED_PARAM; \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ RB_UNUSED_PARAM; \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ @@ -491,10 +518,11 @@ if (NIL_P(propObj)) \ prop = 0; \ else \ prop = getPrivateDataCheck(propObj, #PropKlass); \ -GUARD_EXC(k->set##PropName(prop);) \ +k->set##PropName(prop) \ rb_iv_set(self, prop_iv, propObj); \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #endif /* Object property which is copied by value, not reference */ @@ -505,15 +533,16 @@ RB_UNUSED_PARAM; \ checkDisposed(self); \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ VALUE propObj = *argv; \ PropKlass *prop; \ prop = getPrivateDataCheck(propObj, PropKlass##Type); \ -GUARD_EXC(k->set##PropName(*prop);) \ +k->set##PropName(*prop); \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #else #define DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ RB_METHOD(Klass##Get##PropName) { \ @@ -521,33 +550,36 @@ RB_UNUSED_PARAM; \ checkDisposed(self); \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ VALUE propObj = *argv; \ PropKlass *prop; \ prop = getPrivateDataCheck(propObj, #PropKlass); \ -GUARD_EXC(k->set##PropName(*prop);) \ +k->set##PropName(*prop); \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #endif -#define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \ -RB_METHOD(Klass##Get##PropName) { \ +#define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \ +RB_METHOD_GUARD(Klass##Get##PropName) { \ RB_UNUSED_PARAM; \ Klass *k = getPrivateData(self); \ type value = 0; \ -GUARD_EXC(value = k->get##PropName();) \ +value = k->get##PropName(); \ return value_fun(value); \ -} \ -RB_METHOD(Klass##Set##PropName) { \ +} \ +RB_METHOD_GUARD_END \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ type value; \ rb_##arg_fun##_arg(*argv, &value); \ -GUARD_EXC(k->set##PropName(value);) \ +k->set##PropName(value); \ return *argv; \ -} +} \ +RB_METHOD_GUARD_END #define DEF_PROP_I(Klass, PropName) \ DEF_PROP(Klass, int, PropName, int, rb_fix_new) @@ -573,7 +605,7 @@ RB_METHOD(Klass##Get##PropName) { \ RB_UNUSED_PARAM; \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ RB_UNUSED_PARAM; \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ @@ -586,7 +618,8 @@ prop = getPrivateDataCheck(propObj, PropKlass##Type); \ GFX_GUARD_EXC(k->set##PropName(prop);) \ rb_iv_set(self, prop_iv, propObj); \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #else #define DEF_GFX_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \ DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) @@ -600,7 +633,7 @@ RB_UNUSED_PARAM; \ checkDisposed(self); \ return rb_iv_get(self, prop_iv); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ VALUE propObj = *argv; \ @@ -608,28 +641,31 @@ PropKlass *prop; \ prop = getPrivateDataCheck(propObj, PropKlass##Type); \ GFX_GUARD_EXC(k->set##PropName(*prop);) \ return propObj; \ -} +} \ +RB_METHOD_GUARD_END #else #define DEF_GFX_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) #endif -#define DEF_GFX_PROP(Klass, type, PropName, arg_fun, value_fun) \ -RB_METHOD(Klass##Get##PropName) { \ +#define DEF_GFX_PROP(Klass, type, PropName, arg_fun, value_fun) \ +RB_METHOD_GUARD(Klass##Get##PropName) { \ RB_UNUSED_PARAM; \ Klass *k = getPrivateData(self); \ type value = 0; \ -GUARD_EXC(value = k->get##PropName();) \ +value = k->get##PropName(); \ return value_fun(value); \ } \ -RB_METHOD(Klass##Set##PropName) { \ +RB_METHOD_GUARD_END \ +RB_METHOD_GUARD(Klass##Set##PropName) { \ rb_check_argc(argc, 1); \ Klass *k = getPrivateData(self); \ type value; \ rb_##arg_fun##_arg(*argv, &value); \ GFX_GUARD_EXC(k->set##PropName(value);) \ return *argv; \ -} +} \ +RB_METHOD_GUARD_END #define DEF_GFX_PROP_I(Klass, PropName) \ DEF_GFX_PROP(Klass, int, PropName, int, rb_fix_new) diff --git a/binding/bitmap-binding.cpp b/binding/bitmap-binding.cpp index 442b285..0b1b51a 100644 --- a/binding/bitmap-binding.cpp +++ b/binding/bitmap-binding.cpp @@ -64,7 +64,7 @@ void bitmapInitProps(Bitmap *b, VALUE self) { b->setInitFont(font); } -RB_METHOD(bitmapInitialize) { +RB_METHOD_GUARD(bitmapInitialize) { Bitmap *b = 0; if (argc == 1) { @@ -84,45 +84,49 @@ RB_METHOD(bitmapInitialize) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapWidth) { +RB_METHOD_GUARD(bitmapWidth) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); int value = 0; - GUARD_EXC(value = b->width();); + value = b->width(); return INT2FIX(value); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapHeight) { +RB_METHOD_GUARD(bitmapHeight) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); int value = 0; - GUARD_EXC(value = b->height();); + value = b->height(); return INT2FIX(value); } +RB_METHOD_GUARD_END DEF_GFX_PROP_OBJ_REF(Bitmap, Bitmap, Hires, "hires") -RB_METHOD(bitmapRect) { +RB_METHOD_GUARD(bitmapRect) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); IntRect rect; - GUARD_EXC(rect = b->rect();); + rect = b->rect(); Rect *r = new Rect(rect); return wrapObject(r, RectType); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapBlt) { +RB_METHOD_GUARD(bitmapBlt) { Bitmap *b = getPrivateData(self); int x, y; @@ -143,8 +147,9 @@ RB_METHOD(bitmapBlt) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapStretchBlt) { +RB_METHOD_GUARD(bitmapStretchBlt) { Bitmap *b = getPrivateData(self); VALUE destRectObj; @@ -167,8 +172,9 @@ RB_METHOD(bitmapStretchBlt) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapFillRect) { +RB_METHOD_GUARD(bitmapFillRect) { Bitmap *b = getPrivateData(self); VALUE colorObj; @@ -197,8 +203,9 @@ RB_METHOD(bitmapFillRect) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapClear) { +RB_METHOD_GUARD(bitmapClear) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); @@ -207,8 +214,9 @@ RB_METHOD(bitmapClear) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetPixel) { +RB_METHOD_GUARD(bitmapGetPixel) { Bitmap *b = getPrivateData(self); int x, y; @@ -216,14 +224,18 @@ RB_METHOD(bitmapGetPixel) { rb_get_args(argc, argv, "ii", &x, &y RB_ARG_END); Color value; - GUARD_EXC(value = b->getPixel(x, y);); + if (b->surface() || b->megaSurface()) + value = b->getPixel(x, y); + else + GFX_GUARD_EXC(value = b->getPixel(x, y);); Color *color = new Color(value); return wrapObject(color, ColorType); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSetPixel) { +RB_METHOD_GUARD(bitmapSetPixel) { Bitmap *b = getPrivateData(self); int x, y; @@ -239,8 +251,9 @@ RB_METHOD(bitmapSetPixel) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapHueChange) { +RB_METHOD_GUARD(bitmapHueChange) { Bitmap *b = getPrivateData(self); int hue; @@ -251,8 +264,9 @@ RB_METHOD(bitmapHueChange) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapDrawText) { +RB_METHOD_GUARD(bitmapDrawText) { Bitmap *b = getPrivateData(self); const char *str; @@ -293,8 +307,9 @@ RB_METHOD(bitmapDrawText) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapTextSize) { +RB_METHOD_GUARD(bitmapTextSize) { Bitmap *b = getPrivateData(self); const char *str; @@ -309,16 +324,17 @@ RB_METHOD(bitmapTextSize) { } IntRect value; - GUARD_EXC(value = b->textSize(str);); + value = b->textSize(str); Rect *rect = new Rect(value); return wrapObject(rect, RectType); } +RB_METHOD_GUARD_END DEF_GFX_PROP_OBJ_VAL(Bitmap, Font, Font, "font") -RB_METHOD(bitmapGradientFillRect) { +RB_METHOD_GUARD(bitmapGradientFillRect) { Bitmap *b = getPrivateData(self); VALUE color1Obj, color2Obj; @@ -353,8 +369,9 @@ RB_METHOD(bitmapGradientFillRect) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapClearRect) { +RB_METHOD_GUARD(bitmapClearRect) { Bitmap *b = getPrivateData(self); if (argc == 1) { @@ -376,33 +393,32 @@ RB_METHOD(bitmapClearRect) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapBlur) { +RB_METHOD_GUARD(bitmapBlur) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); - GFX_LOCK; - b->blur(); - GFX_UNLOCK; + GFX_GUARD_EXC( b->blur(); ); return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapRadialBlur) { +RB_METHOD_GUARD(bitmapRadialBlur) { Bitmap *b = getPrivateData(self); int angle, divisions; rb_get_args(argc, argv, "ii", &angle, &divisions RB_ARG_END); - GFX_LOCK; - b->radialBlur(angle, divisions); - GFX_UNLOCK; + GFX_GUARD_EXC( b->radialBlur(angle, divisions); ); return Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetRawData) { +RB_METHOD_GUARD(bitmapGetRawData) { RB_UNUSED_PARAM; Bitmap *b = getPrivateData(self); @@ -413,8 +429,9 @@ RB_METHOD(bitmapGetRawData) { return ret; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSetRawData) { +RB_METHOD_GUARD(bitmapSetRawData) { RB_UNUSED_PARAM; VALUE str; @@ -427,8 +444,9 @@ RB_METHOD(bitmapSetRawData) { return self; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSaveToFile) { +RB_METHOD_GUARD(bitmapSaveToFile) { RB_UNUSED_PARAM; VALUE str; @@ -441,8 +459,9 @@ RB_METHOD(bitmapSaveToFile) { return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetMega){ +RB_METHOD_GUARD(bitmapGetMega){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -455,8 +474,9 @@ RB_METHOD(bitmapGetMega){ return ret; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetAnimated){ +RB_METHOD_GUARD(bitmapGetAnimated){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -469,8 +489,9 @@ RB_METHOD(bitmapGetAnimated){ return ret; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetPlaying){ +RB_METHOD_GUARD(bitmapGetPlaying){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -479,8 +500,9 @@ RB_METHOD(bitmapGetPlaying){ return rb_bool_new(b->isPlaying()); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSetPlaying){ +RB_METHOD_GUARD(bitmapSetPlaying){ RB_UNUSED_PARAM; bool play; @@ -493,8 +515,9 @@ RB_METHOD(bitmapSetPlaying){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapPlay){ +RB_METHOD_GUARD(bitmapPlay){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -504,8 +527,9 @@ RB_METHOD(bitmapPlay){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapStop){ +RB_METHOD_GUARD(bitmapStop){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -515,8 +539,9 @@ RB_METHOD(bitmapStop){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGotoStop){ +RB_METHOD_GUARD(bitmapGotoStop){ RB_UNUSED_PARAM; int frame; @@ -529,8 +554,9 @@ RB_METHOD(bitmapGotoStop){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGotoPlay){ +RB_METHOD_GUARD(bitmapGotoPlay){ RB_UNUSED_PARAM; int frame; @@ -543,8 +569,9 @@ RB_METHOD(bitmapGotoPlay){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapFrames){ +RB_METHOD_GUARD(bitmapFrames){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -553,8 +580,9 @@ RB_METHOD(bitmapFrames){ return INT2NUM(b->numFrames()); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapCurrentFrame){ +RB_METHOD_GUARD(bitmapCurrentFrame){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -563,8 +591,9 @@ RB_METHOD(bitmapCurrentFrame){ return INT2NUM(b->currentFrameI()); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapAddFrame){ +RB_METHOD_GUARD(bitmapAddFrame){ RB_UNUSED_PARAM; VALUE srcBitmap; @@ -588,8 +617,9 @@ RB_METHOD(bitmapAddFrame){ return INT2NUM(ret); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapRemoveFrame){ +RB_METHOD_GUARD(bitmapRemoveFrame){ RB_UNUSED_PARAM; VALUE position; @@ -608,8 +638,9 @@ RB_METHOD(bitmapRemoveFrame){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapNextFrame){ +RB_METHOD_GUARD(bitmapNextFrame){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -620,8 +651,9 @@ RB_METHOD(bitmapNextFrame){ return INT2NUM(b->currentFrameI()); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapPreviousFrame){ +RB_METHOD_GUARD(bitmapPreviousFrame){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -632,8 +664,9 @@ RB_METHOD(bitmapPreviousFrame){ return INT2NUM(b->currentFrameI()); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSetFPS){ +RB_METHOD_GUARD(bitmapSetFPS){ RB_UNUSED_PARAM; VALUE fps; @@ -652,8 +685,9 @@ RB_METHOD(bitmapSetFPS){ return RUBY_Qnil; } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetFPS){ +RB_METHOD_GUARD(bitmapGetFPS){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -662,12 +696,13 @@ RB_METHOD(bitmapGetFPS){ float ret; - GUARD_EXC(ret = b->getAnimationFPS();); + ret = b->getAnimationFPS(); return rb_float_new(ret); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapSetLooping){ +RB_METHOD_GUARD(bitmapSetLooping){ RB_UNUSED_PARAM; bool loop; @@ -679,8 +714,9 @@ RB_METHOD(bitmapSetLooping){ return rb_bool_new(loop); } +RB_METHOD_GUARD_END -RB_METHOD(bitmapGetLooping){ +RB_METHOD_GUARD(bitmapGetLooping){ RB_UNUSED_PARAM; rb_check_argc(argc, 0); @@ -688,12 +724,13 @@ RB_METHOD(bitmapGetLooping){ Bitmap *b = getPrivateData(self); bool ret; - GUARD_EXC(ret = b->getLooping();); + ret = b->getLooping(); return rb_bool_new(ret); } +RB_METHOD_GUARD_END // Captures the Bitmap's current frame data to a new Bitmap -RB_METHOD(bitmapSnapToBitmap) { +RB_METHOD_GUARD(bitmapSnapToBitmap) { RB_UNUSED_PARAM; VALUE position; @@ -713,6 +750,7 @@ RB_METHOD(bitmapSnapToBitmap) { return ret; } +RB_METHOD_GUARD_END RB_METHOD(bitmapGetMaxSize){ RB_UNUSED_PARAM; @@ -722,7 +760,7 @@ RB_METHOD(bitmapGetMaxSize){ return INT2NUM(Bitmap::maxSize()); } -RB_METHOD(bitmapInitializeCopy) { +RB_METHOD_GUARD(bitmapInitializeCopy) { rb_check_argc(argc, 1); VALUE origObj = argv[0]; @@ -740,6 +778,7 @@ RB_METHOD(bitmapInitializeCopy) { return self; } +RB_METHOD_GUARD_END void bitmapBindingInit() { VALUE klass = rb_define_class("Bitmap", rb_cObject); diff --git a/binding/cusl-binding.cpp b/binding/cusl-binding.cpp index f280032..8fe795e 100644 --- a/binding/cusl-binding.cpp +++ b/binding/cusl-binding.cpp @@ -32,7 +32,7 @@ } \ } -RB_METHOD(CUSLSetStat) { +RB_METHOD_GUARD(CUSLSetStat) { RB_UNUSED_PARAM; VALUE name, stat; @@ -47,11 +47,12 @@ RB_METHOD(CUSLSetStat) { STEAMSHIM_setStatI(RSTRING_PTR(name), (int)NUM2INT(stat)); STEAMSHIM_GET_OK(SHIMEVENT_SETSTATI, ret); } else { - rb_raise(rb_eTypeError, + throw Exception(Exception::TypeError, "Statistic value must be either an integer or float."); } return rb_bool_new(ret); } +RB_METHOD_GUARD_END RB_METHOD(CUSLGetStatI) { RB_UNUSED_PARAM; diff --git a/binding/filesystem-binding.cpp b/binding/filesystem-binding.cpp index b0c41a7..9c479a0 100644 --- a/binding/filesystem-binding.cpp +++ b/binding/filesystem-binding.cpp @@ -52,6 +52,10 @@ DEF_ALLOCFUNC_CUSTOMFREE(FileInt, fileIntFreeInstance); #endif static VALUE fileIntForPath(const char *path, bool rubyExc) { + VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt")); + + VALUE obj = rb_obj_alloc(klass); + SDL_RWops *ops = SDL_AllocRW(); try { @@ -59,16 +63,9 @@ static VALUE fileIntForPath(const char *path, bool rubyExc) { } catch (const Exception &e) { SDL_FreeRW(ops); - if (rubyExc) - raiseRbExc(e); - else - throw e; + throw e; } - VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt")); - - VALUE obj = rb_obj_alloc(klass); - setPrivateData(obj, ops); return obj; @@ -183,7 +180,7 @@ kernelLoadDataInt(const char *filename, bool rubyExc, bool raw) { return result; } -RB_METHOD(kernelLoadData) { +RB_METHOD_GUARD(kernelLoadData) { RB_UNUSED_PARAM; VALUE filename; @@ -195,6 +192,7 @@ RB_METHOD(kernelLoadData) { rb_bool_arg(raw, &rawv); return kernelLoadDataInt(RSTRING_PTR(filename), true, rawv); } +RB_METHOD_GUARD_END RB_METHOD(kernelSaveData) { RB_UNUSED_PARAM; diff --git a/binding/graphics-binding.cpp b/binding/graphics-binding.cpp index d28521f..fb0aa08 100644 --- a/binding/graphics-binding.cpp +++ b/binding/graphics-binding.cpp @@ -74,7 +74,7 @@ RB_METHOD(graphicsFreeze) return Qnil; } -RB_METHOD(graphicsTransition) +RB_METHOD_GUARD(graphicsTransition) { RB_UNUSED_PARAM; @@ -88,6 +88,7 @@ RB_METHOD(graphicsTransition) return Qnil; } +RB_METHOD_GUARD_END RB_METHOD(graphicsFrameReset) { @@ -228,7 +229,7 @@ RB_METHOD(graphicsFadein) void bitmapInitProps(Bitmap *b, VALUE self); -RB_METHOD(graphicsSnapToBitmap) +RB_METHOD_GUARD(graphicsSnapToBitmap) { RB_UNUSED_PARAM; @@ -241,6 +242,7 @@ RB_METHOD(graphicsSnapToBitmap) return obj; } +RB_METHOD_GUARD_END RB_METHOD(graphicsResizeScreen) { diff --git a/binding/http-binding.cpp b/binding/http-binding.cpp index f6debeb..40adfcf 100644 --- a/binding/http-binding.cpp +++ b/binding/http-binding.cpp @@ -87,7 +87,7 @@ void* httpGetInternal(void *req) { } #endif -RB_METHOD(httpGet) { +RB_METHOD_GUARD(httpGet) { RB_UNUSED_PARAM; VALUE path, rheaders, redirect; @@ -107,6 +107,7 @@ RB_METHOD(httpGet) { return (VALUE)httpGetInternal(&req); #endif } +RB_METHOD_GUARD_END #if RAPI_MAJOR >= 2 @@ -130,7 +131,7 @@ void* httpPostInternal(void *args) { } #endif -RB_METHOD(httpPost) { +RB_METHOD_GUARD(httpPost) { RB_UNUSED_PARAM; VALUE path, postDataHash, rheaders, redirect; @@ -153,6 +154,7 @@ RB_METHOD(httpPost) { return httpPostInternal(&args); #endif } +RB_METHOD_GUARD_END #if RAPI_MAJOR >= 2 typedef struct { @@ -280,13 +282,13 @@ json5pp::value rb2json(VALUE v) { return ret_value; } - raiseRbExc(Exception(Exception::MKXPError, "Invalid value for JSON: %s", RSTRING_PTR(rb_inspect(v)))); + throw Exception(Exception::MKXPError, "Invalid value for JSON: %s", RSTRING_PTR(rb_inspect(v))); // This should be unreachable return json5pp::value(0); } -RB_METHOD(httpJsonParse) { +RB_METHOD_GUARD(httpJsonParse) { RB_UNUSED_PARAM; VALUE jsonv; @@ -298,13 +300,14 @@ RB_METHOD(httpJsonParse) { v = json5pp::parse5(RSTRING_PTR(jsonv)); } catch (const std::exception &e) { - raiseRbExc(Exception(Exception::MKXPError, "Failed to parse JSON: %s", e.what())); + throw Exception(Exception::MKXPError, "Failed to parse JSON: %s", e.what()); } return json2rb(v); } +RB_METHOD_GUARD_END -RB_METHOD(httpJsonStringify) { +RB_METHOD_GUARD(httpJsonStringify) { RB_UNUSED_PARAM; VALUE obj; @@ -313,6 +316,7 @@ RB_METHOD(httpJsonStringify) { json5pp::value v = rb2json(obj); return rb_utf8_str_new_cstr(v.stringify5(json5pp::rule::space_indent<>()).c_str()); } +RB_METHOD_GUARD_END void httpBindingInit() { VALUE mNet = rb_define_module("HTTPLite"); diff --git a/binding/input-binding.cpp b/binding/input-binding.cpp index bbe5550..0b89bab 100644 --- a/binding/input-binding.cpp +++ b/binding/input-binding.cpp @@ -76,7 +76,7 @@ static int getScancodeArg(VALUE *argv) { try { code = strToScancode[scancode]; } catch (...) { - rb_raise(rb_eRuntimeError, "%s is not a valid name of an SDL scancode.", scancode); + throw Exception(Exception::RuntimeError, "%s is not a valid name of an SDL scancode.", scancode); } return code; @@ -88,7 +88,7 @@ static int getControllerButtonArg(VALUE *argv) { try { btn = strToGCButton[button]; } catch (...) { - rb_raise(rb_eRuntimeError, "%s is not a valid name of an SDL Controller button.", button); + throw Exception(Exception::RuntimeError, "%s is not a valid name of an SDL Controller button.", button); } return btn; @@ -172,7 +172,7 @@ RB_METHOD(inputRepeatTime) { return rb_float_new(shState->input().repeatTime(num)); } -RB_METHOD(inputPressEx) { +RB_METHOD_GUARD(inputPressEx) { RB_UNUSED_PARAM; VALUE button; @@ -185,8 +185,9 @@ RB_METHOD(inputPressEx) { return rb_bool_new(shState->input().isPressedEx(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END -RB_METHOD(inputTriggerEx) { +RB_METHOD_GUARD(inputTriggerEx) { RB_UNUSED_PARAM; VALUE button; @@ -199,8 +200,9 @@ RB_METHOD(inputTriggerEx) { return rb_bool_new(shState->input().isTriggeredEx(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END -RB_METHOD(inputRepeatEx) { +RB_METHOD_GUARD(inputRepeatEx) { RB_UNUSED_PARAM; VALUE button; @@ -213,8 +215,9 @@ RB_METHOD(inputRepeatEx) { return rb_bool_new(shState->input().isRepeatedEx(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END -RB_METHOD(inputReleaseEx) { +RB_METHOD_GUARD(inputReleaseEx) { RB_UNUSED_PARAM; VALUE button; @@ -227,8 +230,9 @@ RB_METHOD(inputReleaseEx) { return rb_bool_new(shState->input().isReleasedEx(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END -RB_METHOD(inputCountEx) { +RB_METHOD_GUARD(inputCountEx) { RB_UNUSED_PARAM; VALUE button; @@ -241,8 +245,9 @@ RB_METHOD(inputCountEx) { return UINT2NUM(shState->input().repeatcount(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END -RB_METHOD(inputRepeatTimeEx) { +RB_METHOD_GUARD(inputRepeatTimeEx) { RB_UNUSED_PARAM; VALUE button; @@ -255,6 +260,7 @@ RB_METHOD(inputRepeatTimeEx) { return rb_float_new(shState->input().repeatTimeEx(NUM2INT(button), 1)); } +RB_METHOD_GUARD_END RB_METHOD(inputDir4) { RB_UNUSED_PARAM; @@ -370,7 +376,7 @@ AXISFUNC(Trigger, TRIGGERLEFT, TRIGGERRIGHT); #undef POWERCASE #undef M_SYMBOL -RB_METHOD(inputControllerPressEx) { +RB_METHOD_GUARD(inputControllerPressEx) { RB_UNUSED_PARAM; VALUE button; @@ -383,8 +389,9 @@ RB_METHOD(inputControllerPressEx) { return rb_bool_new(shState->input().controllerIsPressedEx(NUM2INT(button))); } +RB_METHOD_GUARD_END -RB_METHOD(inputControllerTriggerEx) { +RB_METHOD_GUARD(inputControllerTriggerEx) { RB_UNUSED_PARAM; VALUE button; @@ -397,8 +404,9 @@ RB_METHOD(inputControllerTriggerEx) { return rb_bool_new(shState->input().controllerIsTriggeredEx(NUM2INT(button))); } +RB_METHOD_GUARD_END -RB_METHOD(inputControllerRepeatEx) { +RB_METHOD_GUARD(inputControllerRepeatEx) { RB_UNUSED_PARAM; VALUE button; @@ -411,8 +419,9 @@ RB_METHOD(inputControllerRepeatEx) { return rb_bool_new(shState->input().controllerIsRepeatedEx(NUM2INT(button))); } +RB_METHOD_GUARD_END -RB_METHOD(inputControllerReleaseEx) { +RB_METHOD_GUARD(inputControllerReleaseEx) { RB_UNUSED_PARAM; VALUE button; @@ -425,8 +434,9 @@ RB_METHOD(inputControllerReleaseEx) { return rb_bool_new(shState->input().controllerIsReleasedEx(NUM2INT(button))); } +RB_METHOD_GUARD_END -RB_METHOD(inputControllerCountEx) { +RB_METHOD_GUARD(inputControllerCountEx) { RB_UNUSED_PARAM; VALUE button; @@ -439,8 +449,9 @@ RB_METHOD(inputControllerCountEx) { return rb_bool_new(shState->input().controllerRepeatcount(NUM2INT(button))); } +RB_METHOD_GUARD_END -RB_METHOD(inputControllerRepeatTimeEx) { +RB_METHOD_GUARD(inputControllerRepeatTimeEx) { RB_UNUSED_PARAM; VALUE button; @@ -453,6 +464,7 @@ RB_METHOD(inputControllerRepeatTimeEx) { return rb_float_new(shState->input().controllerRepeatTimeEx(NUM2INT(button))); } +RB_METHOD_GUARD_END RB_METHOD(inputControllerRawButtonStates) { RB_UNUSED_PARAM; @@ -504,18 +516,13 @@ RB_METHOD(inputGets) { return ret; } -RB_METHOD(inputGetClipboard) { +RB_METHOD_GUARD(inputGetClipboard) { RB_UNUSED_PARAM; - VALUE ret; - try { - ret = rb_utf8_str_new_cstr(shState->input().getClipboardText()); - } catch (const Exception &e) { - raiseRbExc(e); - } - return ret; + return rb_utf8_str_new_cstr(shState->input().getClipboardText()); } +RB_METHOD_GUARD_END -RB_METHOD(inputSetClipboard) { +RB_METHOD_GUARD(inputSetClipboard) { RB_UNUSED_PARAM; VALUE str; @@ -523,13 +530,11 @@ RB_METHOD(inputSetClipboard) { SafeStringValue(str); - try { - shState->input().setClipboardText(RSTRING_PTR(str)); - } catch (const Exception &e) { - raiseRbExc(e); - } + shState->input().setClipboardText(RSTRING_PTR(str)); + return str; } +RB_METHOD_GUARD_END struct { const char *str; diff --git a/binding/miniffi-binding.cpp b/binding/miniffi-binding.cpp index 3c24c3f..8a53955 100644 --- a/binding/miniffi-binding.cpp +++ b/binding/miniffi-binding.cpp @@ -46,7 +46,7 @@ static void *MiniFFI_GetFunctionHandle(void *libhandle, const char *func) { // MiniFFI.new(library, function[, imports[, exports]]) // Yields itself in blocks -RB_METHOD(MiniFFI_initialize) { +RB_METHOD_GUARD(MiniFFI_initialize) { VALUE libname, func, imports, exports; rb_scan_args(argc, argv, "22", &libname, &func, &imports, &exports); SafeStringValue(libname); @@ -66,7 +66,7 @@ RB_METHOD(MiniFFI_initialize) { } #endif if (!hfunc) - rb_raise(rb_eRuntimeError, "%s", SDL_GetError()); + throw Exception(Exception::RuntimeError, "%s", SDL_GetError()); rb_iv_set(self, "_func", MVAL2RB((mffi_value)hfunc)); rb_iv_set(self, "_funcname", func); @@ -138,7 +138,7 @@ RB_METHOD(MiniFFI_initialize) { } if (MINIFFI_MAX_ARGS < RARRAY_LEN(ary_imports)) - rb_raise(rb_eRuntimeError, "too many parameters: %ld/%ld\n", + throw Exception(Exception::RuntimeError, "too many parameters: %ld/%ld\n", RARRAY_LEN(ary_imports), MINIFFI_MAX_ARGS); rb_iv_set(self, "_imports", ary_imports); @@ -181,6 +181,7 @@ RB_METHOD(MiniFFI_initialize) { rb_yield(self); return Qnil; } +RB_METHOD_GUARD_END #if RAPI_MAJOR >= 2 typedef struct { @@ -195,7 +196,7 @@ void* miniffi_call_cb(void *args) { } #endif -RB_METHOD(MiniFFI_call) { +RB_METHOD_GUARD(MiniFFI_call) { MiniFFIFuncArgs param; #define params param.params VALUE func = rb_iv_get(self, "_func"); @@ -206,7 +207,7 @@ RB_METHOD(MiniFFI_call) { int items = rb_scan_args(argc, argv, "0*", &args); int nimport = RARRAY_LEN(own_imports); if (items != nimport) - rb_raise(rb_eRuntimeError, + throw Exception(Exception::RuntimeError, "wrong number of parameters: expected %d, got %d", nimport, items); for (int i = 0; i < nimport; i++) { @@ -264,6 +265,7 @@ RB_METHOD(MiniFFI_call) { return MVAL2RB(0); } } +RB_METHOD_GUARD_END void MiniFFIBindingInit() { VALUE cMiniFFI = rb_define_class("MiniFFI", rb_cObject); diff --git a/binding/sceneelement-binding.h b/binding/sceneelement-binding.h index 270cdb0..b49abf7 100644 --- a/binding/sceneelement-binding.h +++ b/binding/sceneelement-binding.h @@ -27,20 +27,21 @@ #include "graphics.h" template -RB_METHOD(sceneElementGetZ) +RB_METHOD_GUARD(sceneElementGetZ) { RB_UNUSED_PARAM; SceneElement *se = getPrivateData(self); int value = 0; - GUARD_EXC( value = se->getZ(); ); + value = se->getZ(); return rb_fix_new(value); } +RB_METHOD_GUARD_END template -RB_METHOD(sceneElementSetZ) +RB_METHOD_GUARD(sceneElementSetZ) { SceneElement *se = getPrivateData(self); @@ -51,22 +52,24 @@ RB_METHOD(sceneElementSetZ) return rb_fix_new(z); } +RB_METHOD_GUARD_END template -RB_METHOD(sceneElementGetVisible) +RB_METHOD_GUARD(sceneElementGetVisible) { RB_UNUSED_PARAM; SceneElement *se = getPrivateData(self); bool value = false; - GUARD_EXC( value = se->getVisible(); ); + value = se->getVisible(); return rb_bool_new(value); } +RB_METHOD_GUARD_END template -RB_METHOD(sceneElementSetVisible) +RB_METHOD_GUARD(sceneElementSetVisible) { SceneElement *se = getPrivateData(self); @@ -75,8 +78,9 @@ RB_METHOD(sceneElementSetVisible) GFX_GUARD_EXC( se->setVisible(visible); ); - return rb_bool_new(visible); + return rb_bool_new(visible); } +RB_METHOD_GUARD_END template void diff --git a/binding/serializable-binding.h b/binding/serializable-binding.h index 12e897b..4536503 100644 --- a/binding/serializable-binding.h +++ b/binding/serializable-binding.h @@ -36,7 +36,18 @@ serializableDump(int, VALUE *, VALUE self) VALUE data = rb_str_new(0, dataSize); - GUARD_EXC( s->serialize(RSTRING_PTR(data)); ); + Exception *exc = 0; + try{ + s->serialize(RSTRING_PTR(data)); + } catch (const Exception &e) { + exc = new Exception(e); + } + + if (exc) { + Exception e(exc->type, exc->msg); + delete exc; + rb_raise(excToRbClass(e), "%s", e.msg); + } return data; } diff --git a/binding/sprite-binding.cpp b/binding/sprite-binding.cpp index 77da2ee..096464e 100644 --- a/binding/sprite-binding.cpp +++ b/binding/sprite-binding.cpp @@ -84,27 +84,29 @@ DEF_GFX_PROP_B(Sprite, Mirror) DEF_GFX_PROP_B(Sprite, PatternTile) DEF_GFX_PROP_B(Sprite, Invert) -RB_METHOD(spriteWidth) { +RB_METHOD_GUARD(spriteWidth) { RB_UNUSED_PARAM; Sprite *s = getPrivateData(self); int value = 0; - GUARD_EXC(value = s->getWidth();) + value = s->getWidth(); return rb_fix_new(value); } +RB_METHOD_GUARD_END -RB_METHOD(spriteHeight) { +RB_METHOD_GUARD(spriteHeight) { RB_UNUSED_PARAM; Sprite *s = getPrivateData(self); int value = 0; - GUARD_EXC(value = s->getHeight();) + value = s->getHeight(); return rb_fix_new(value); } +RB_METHOD_GUARD_END void spriteBindingInit() { VALUE klass = rb_define_class("Sprite", rb_cObject); diff --git a/binding/table-binding.cpp b/binding/table-binding.cpp index 65452d6..2ef5143 100644 --- a/binding/table-binding.cpp +++ b/binding/table-binding.cpp @@ -86,7 +86,7 @@ TABLE_SIZE(x, X) TABLE_SIZE(y, Y) TABLE_SIZE(z, Z) -RB_METHOD(tableGetAt) { +RB_METHOD_GUARD(tableGetAt) { Table *t = getPrivateData(self); int x, y, z; @@ -99,7 +99,7 @@ RB_METHOD(tableGetAt) { z = NUM2INT(argv[2]); if (argc > 3) - rb_raise(rb_eArgError, "wrong number of arguments"); + throw Exception(Exception::ArgumentError, "wrong number of arguments"); if (x < 0 || x >= t->xSize() || y < 0 || y >= t->ySize() || z < 0 || z >= t->zSize()) { @@ -110,15 +110,16 @@ RB_METHOD(tableGetAt) { return INT2FIX(result); /* short always fits in a Fixnum */ } +RB_METHOD_GUARD_END -RB_METHOD(tableSetAt) { +RB_METHOD_GUARD(tableSetAt) { Table *t = getPrivateData
(self); int x, y, z, value; x = y = z = 0; if (argc < 2) - rb_raise(rb_eArgError, "wrong number of arguments"); + throw Exception(Exception::ArgumentError, "wrong number of arguments"); switch (argc) { default: @@ -146,6 +147,7 @@ RB_METHOD(tableSetAt) { return argv[argc - 1]; } +RB_METHOD_GUARD_END MARSH_LOAD_FUN(Table) INITCOPY_FUN(Table) diff --git a/binding/viewportelement-binding.h b/binding/viewportelement-binding.h index 209bc7d..fb9e916 100644 --- a/binding/viewportelement-binding.h +++ b/binding/viewportelement-binding.h @@ -42,7 +42,7 @@ RB_METHOD(viewportElementGetViewport) } template -RB_METHOD(viewportElementSetViewport) +RB_METHOD_GUARD(viewportElementSetViewport) { RB_UNUSED_PARAM; @@ -62,6 +62,7 @@ RB_METHOD(viewportElementSetViewport) return viewportObj; } +RB_METHOD_GUARD_END template static C * diff --git a/binding/window-binding.cpp b/binding/window-binding.cpp index 2ba5520..601fef3 100644 --- a/binding/window-binding.cpp +++ b/binding/window-binding.cpp @@ -44,7 +44,7 @@ RB_METHOD(windowInitialize) { return self; } -RB_METHOD(windowUpdate) { +RB_METHOD_GUARD(windowUpdate) { RB_UNUSED_PARAM; Window *w = getPrivateData(self); @@ -53,6 +53,7 @@ RB_METHOD(windowUpdate) { return Qnil; } +RB_METHOD_GUARD_END DEF_GFX_PROP_OBJ_REF(Window, Bitmap, Windowskin, "windowskin") DEF_GFX_PROP_OBJ_REF(Window, Bitmap, Contents, "contents") diff --git a/src/util/exception.h b/src/util/exception.h index 6f95b60..45c28f8 100644 --- a/src/util/exception.h +++ b/src/util/exception.h @@ -37,6 +37,8 @@ struct Exception /* Already defined by ruby */ TypeError, ArgumentError, + SystemExit, + RuntimeError, /* New types introduced in mkxp */ PHYSFSError, @@ -45,7 +47,7 @@ struct Exception }; Type type; - std::string msg; + char msg[512]; Exception(Type type, const char *format, ...) : type(type) @@ -53,8 +55,7 @@ struct Exception va_list ap; va_start(ap, format); - msg.resize(512); - vsnprintf(&msg[0], msg.size(), format, ap); + vsnprintf(msg, sizeof(msg), format, ap); va_end(ap); }