diff --git a/main/gbx/gb_error.c b/main/gbx/gb_error.c index 38e2753bc..87eb4c8f4 100644 --- a/main/gbx/gb_error.c +++ b/main/gbx/gb_error.c @@ -582,6 +582,11 @@ void THROW_MATH(bool zero) THROW(zero ? E_ZERO : E_MATH); } +void THROW_OVERFLOW(void) +{ + THROW(E_OVERFLOW); +} + void ERROR_fatal(const char *error, ...) { diff --git a/main/gbx/gb_error.h b/main/gbx/gb_error.h index 343f3a4f4..d1a5000c8 100644 --- a/main/gbx/gb_error.h +++ b/main/gbx/gb_error.h @@ -168,6 +168,7 @@ void THROW_STACK(void) NORETURN; void THROW_BOUND(void) NORETURN; void THROW_CLASS(void *class, char *arg1, char *arg2) NORETURN; void THROW_MATH(bool zero) NORETURN; +void THROW_OVERFLOW(void) NORETURN; void ERROR_fatal(const char *error, ...) NORETURN; void ERROR_panic(const char *error, ...) NORETURN; diff --git a/main/gbx/gbx_exec_loop.c b/main/gbx/gbx_exec_loop.c index fa5646b42..6b21d7a1b 100644 --- a/main/gbx/gbx_exec_loop.c +++ b/main/gbx/gbx_exec_loop.c @@ -26,6 +26,8 @@ #include "gb_common.h" #include "gb_common_check.h" #include "gb_error.h" +#include "gb_overflow.h" + #include "gbx_type.h" #include "gbx_debug.h" @@ -1922,9 +1924,11 @@ _ADD_QUICK: THROW(E_NRETURN); +#if DO_NOT_CHECK_OVERFLOW + __AQ_BYTE: - val->_integer.value = (unsigned char)(val->_integer.value + ind); + val->_integer.value = (uchar)(val->_integer.value + ind); goto *jump_end; __AQ_SHORT: @@ -1942,6 +1946,44 @@ _ADD_QUICK: val->_long.value += (int64_t)ind; goto *jump_end; +#else + + __AQ_BYTE: + + { + uchar result; + + if (__builtin_add_overflow((uchar)val->_integer.value, (uchar)ind, &result)) + THROW_OVERFLOW(); + val->_integer.value = result; + goto *jump_end; + } + + __AQ_SHORT: + + { + short result; + + if (__builtin_add_overflow((short)val->_integer.value, (short)ind, &result)) + THROW_OVERFLOW(); + val->_integer.value = result; + goto *jump_end; + } + + __AQ_INTEGER: + + if (__builtin_sadd_overflow(val->_integer.value, ind, &val->_integer.value)) + THROW_OVERFLOW(); + goto *jump_end; + + __AQ_LONG: + + if (__builtin_saddl_overflow(val->_long.value, (int64_t)ind, &val->_long.value)) + THROW_OVERFLOW(); + goto *jump_end; + +#endif + __AQ_SINGLE: val->_single.value += (float)ind; @@ -2145,7 +2187,12 @@ _POP_ARRAY_NATIVE_COLLECTION: _ADD_INTEGER: SP--; +#if DO_NOT_CHECK_OVERFLOW SP[-1]._integer.value += SP->_integer.value; +#else + if (__builtin_sadd_overflow(SP[-1]._integer.value, SP->_integer.value, &SP[-1]._integer.value)) + THROW_OVERFLOW(); +#endif goto _NEXT; _ADD_FLOAT: @@ -2157,7 +2204,12 @@ _ADD_FLOAT: _SUB_INTEGER: SP--; +#if DO_NOT_CHECK_OVERFLOW SP[-1]._integer.value -= SP->_integer.value; +#else + if (__builtin_ssub_overflow(SP[-1]._integer.value, SP->_integer.value, &SP[-1]._integer.value)) + THROW_OVERFLOW(); +#endif goto _NEXT; _SUB_FLOAT: @@ -2169,7 +2221,12 @@ _SUB_FLOAT: _MUL_INTEGER: SP--; +#if DO_NOT_CHECK_OVERFLOW SP[-1]._integer.value *= SP->_integer.value; +#else + if (__builtin_smul_overflow(SP[-1]._integer.value, SP->_integer.value, &SP[-1]._integer.value)) + THROW_OVERFLOW(); +#endif goto _NEXT; _MUL_FLOAT: @@ -3156,6 +3213,8 @@ __BOOLEAN: P1->type = T_BOOLEAN; P1->_integer.value = P1->_integer.value | P2->_integer.value; SP--; return; +#if DO_NOT_CHECK_OVERFLOW + __BYTE: P1->type = T_BYTE; @@ -3180,6 +3239,58 @@ __LONG_NC: P1->_long.value += P2->_long.value; SP--; return; +#else + +__BYTE: + + { + uchar result; + + if (__builtin_add_overflow((uchar)P1->_integer.value, (uchar)P2->_integer.value, &result)) + THROW_OVERFLOW(); + + P1->_integer.value = result; + P1->type = T_BYTE; + SP--; + return; + } + +__SHORT: + + { + short result; + + if (__builtin_add_overflow((short)P1->_integer.value, (short)P2->_integer.value, &result)) + THROW_OVERFLOW(); + + P1->_integer.value = result; + P1->type = T_SHORT; + SP--; + return; + } + +__INTEGER: + + if (__builtin_sadd_overflow(P1->_integer.value, P2->_integer.value, &P1->_integer.value)) + THROW_OVERFLOW(); + P1->type = T_INTEGER; + SP--; + return; + +__LONG: + + VALUE_conv(P1, T_LONG); + VALUE_conv(P2, T_LONG); + +__LONG_NC: + + if (__builtin_saddl_overflow(P1->_long.value, P2->_long.value, &P1->_long.value)) + THROW_OVERFLOW(); + SP--; + return; + +#endif + __SINGLE: VALUE_conv(P1, T_SINGLE); @@ -3262,6 +3373,8 @@ __BOOLEAN: P1->type = T_BOOLEAN; P1->_integer.value = P1->_integer.value ^ P2->_integer.value; SP--; return; +#if DO_NOT_CHECK_OVERFLOW + __BYTE: P1->type = T_BYTE; @@ -3286,6 +3399,58 @@ __LONG_NC: P1->_long.value -= P2->_long.value; SP--; return; +#else + +__BYTE: + + { + uchar result; + + if (__builtin_sub_overflow((uchar)P1->_integer.value, (uchar)P2->_integer.value, &result)) + THROW_OVERFLOW(); + + P1->_integer.value = result; + P1->type = T_BYTE; + SP--; + return; + } + +__SHORT: + + { + short result; + + if (__builtin_sub_overflow((short)P1->_integer.value, (short)P2->_integer.value, &result)) + THROW_OVERFLOW(); + + P1->_integer.value = result; + P1->type = T_SHORT; + SP--; + return; + } + +__INTEGER: + + if (__builtin_ssub_overflow(P1->_integer.value, P2->_integer.value, &P1->_integer.value)) + THROW_OVERFLOW(); + P1->type = T_INTEGER; + SP--; + return; + +__LONG: + + VALUE_conv(P1, T_LONG); + VALUE_conv(P2, T_LONG); + +__LONG_NC: + + if (__builtin_ssubl_overflow(P1->_long.value, P2->_long.value, &P1->_long.value)) + THROW_OVERFLOW(); + SP--; + return; + +#endif + __SINGLE: VALUE_conv(P1, T_SINGLE); @@ -3367,6 +3532,8 @@ __BOOLEAN: P1->type = T_BOOLEAN; P1->_integer.value = P1->_integer.value & P2->_integer.value; SP--; return; +#if DO_NOT_CHECK_OVERFLOW + __BYTE: P1->type = T_BYTE; @@ -3391,6 +3558,58 @@ __LONG_NC: P1->_long.value *= P2->_long.value; SP--; return; +#else + +__BYTE: + + { + uchar result; + + if (__builtin_mul_overflow((uchar)P1->_integer.value, (uchar)P2->_integer.value, &result)) + THROW_OVERFLOW(); + + P1->_integer.value = result; + P1->type = T_BYTE; + SP--; + return; + } + +__SHORT: + + { + short result; + + if (__builtin_mul_overflow((short)P1->_integer.value, (short)P2->_integer.value, &result)) + THROW_OVERFLOW(); + + P1->_integer.value = result; + P1->type = T_SHORT; + SP--; + return; + } + +__INTEGER: + + if (__builtin_smul_overflow(P1->_integer.value, P2->_integer.value, &P1->_integer.value)) + THROW_OVERFLOW(); + P1->type = T_INTEGER; + SP--; + return; + +__LONG: + + VALUE_conv(P1, T_LONG); + VALUE_conv(P2, T_LONG); + +__LONG_NC: + + if (__builtin_smull_overflow(P1->_long.value, P2->_long.value, &P1->_long.value)) + THROW_OVERFLOW(); + SP--; + return; + +#endif + __SINGLE: VALUE_conv(P1, T_SINGLE); diff --git a/main/gbx/gbx_value.c b/main/gbx/gbx_value.c index e090c69dc..2589bc64f 100644 --- a/main/gbx/gbx_value.c +++ b/main/gbx/gbx_value.c @@ -25,6 +25,7 @@ #include "gb_common.h" #include "gb_common_case.h" +#include "gb_overflow.h" #include "gbx_math.h" #include "gbx_type.h" @@ -419,20 +420,52 @@ __p2b: value->type = T_BOOLEAN; return; +#ifdef DO_NOT_CHECK_OVERFLOW + __b2c: __h2c: __i2c: - - value->_integer.value = (unsigned char)value->_integer.value; + value->_integer.value = (uchar)value->_integer.value; value->type = T_BYTE; return; __l2c: - - value->_integer.value = (unsigned char)value->_long.value; + value->_integer.value = (uchar)value->_long.value; value->type = T_BYTE; return; +#else + +__b2c: + value->_integer.value = (uchar)value->_integer.value; + value->type = T_BYTE; + return; + +__h2c: +__i2c: + { + uchar result; + + if (__builtin_add_overflow(value->_integer.value, 0, &result)) + THROW_OVERFLOW(); + value->_integer.value = result; + value->type = T_BYTE; + return; + } + +__l2c: + { + uchar result; + + if (__builtin_add_overflow(value->_long.value, 0, &result)) + THROW_OVERFLOW(); + value->_integer.value = result; + value->type = T_BYTE; + return; + } + +#endif + __g2c: value->_integer.value = (unsigned char)value->_single.value; @@ -445,20 +478,50 @@ __f2c: value->type = T_BYTE; return; +#ifdef DO_NOT_CHECK_OVERFLOW + __b2h: __c2h: __i2h: - - value->_integer.value = (short)value->_integer.value; value->type = T_SHORT; return; __l2h: - value->_integer.value = (short)value->_long.value; value->type = T_SHORT; return; +#else + +__b2h: +__c2h: + value->type = T_SHORT; + return; + +__i2h: + { + short result; + + if (__builtin_add_overflow(value->_integer.value, 0, &result)) + THROW_OVERFLOW(); + value->_integer.value = result; + value->type = T_SHORT; + return; + } + +__l2h: + { + short result; + + if (__builtin_add_overflow(value->_long.value, 0, &result)) + THROW_OVERFLOW(); + value->_integer.value = result; + value->type = T_SHORT; + return; + } + +#endif + __g2h: value->_integer.value = (short)value->_single.value; @@ -471,12 +534,23 @@ __f2h: value->type = T_SHORT; return; -__l2i: +#ifdef DO_NOT_CHECK_OVERFLOW +__l2i: value->_integer.value = (int)value->_long.value; value->type = T_INTEGER; return; +#else + +__l2i: + if (__builtin_add_overflow(value->_long.value, 0, &value->_integer.value)) + THROW_OVERFLOW(); + value->type = T_INTEGER; + return; + +#endif + __g2i: value->_integer.value = (int)value->_single.value; diff --git a/main/share/gb_common.h b/main/share/gb_common.h index a607e374e..6e132472d 100644 --- a/main/share/gb_common.h +++ b/main/share/gb_common.h @@ -206,4 +206,4 @@ typedef break; \ } if (errno) -#endif /* __COMMON_H */ +#endif /* __GB_COMMON_H */ diff --git a/main/share/gb_overflow.h b/main/share/gb_overflow.h new file mode 100644 index 000000000..ae8a7e901 --- /dev/null +++ b/main/share/gb_overflow.h @@ -0,0 +1,65 @@ +/*************************************************************************** + + gb_overflow.h + + (c) BenoƮt Minisini + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + +***************************************************************************/ + +#ifndef __GB_OVERFLOW_H +#define __GB_OVERFLOW_H + +#define DO_NOT_CHECK_OVERFLOW 0 + +#if !__has_builtin(__builtin_add_overflow) +#define __builtin_add_overflow(_a, _b, _c) (*(_c) = (_a) + (_b),0) +#endif + +#if !__has_builtin(__builtin_sadd_overflow) +#define __builtin_sadd_overflow(_a, _b, _c) (*(_c) = (_a) + (_b),0) +#endif + +#if !__has_builtin(__builtin_saddl_overflow) +#define __builtin_saddl_overflow(_a, _b, _c) (*(_c) = (_a) + (_b),0) +#endif + +#if !__has_builtin(__builtin_sub_overflow) +#define __builtin_sub_overflow(_a, _b, _c) (*(_c) = (_a) - (_b),0) +#endif + +#if !__has_builtin(__builtin_ssub_overflow) +#define __builtin_ssub_overflow(_a, _b, _c) (*(_c) = (_a) - (_b),0) +#endif + +#if !__has_builtin(__builtin_ssubl_overflow) +#define __builtin_ssubl_overflow(_a, _b, _c) (*(_c) = (_a) - (_b),0) +#endif + +#if !__has_builtin(__builtin_mul_overflow) +#define __builtin_mul_overflow(_a, _b, _c) (*(_c) = (_a) * (_b),0) +#endif + +#if !__has_builtin(__builtin_smul_overflow) +#define __builtin_smul_overflow(_a, _b, _c) (*(_c) = (_a) * (_b),0) +#endif + +#if !__has_builtin(__builtin_smull_overflow) +#define __builtin_smull_overflow(_a, _b, _c) (*(_c) = (_a) * (_b),0) +#endif + +#endif /* __GB_OVERFLOW_H */