Integer arithmetic and conversion now raise an error if overflow is detected.
[INTERPRETER] * NEW: Integer arithmetic and conversion now raise an error if overflow is detected.
This commit is contained in:
parent
3a35562603
commit
0a7f10ad52
@ -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, ...)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -206,4 +206,4 @@ typedef
|
||||
break; \
|
||||
} if (errno)
|
||||
|
||||
#endif /* __COMMON_H */
|
||||
#endif /* __GB_COMMON_H */
|
||||
|
65
main/share/gb_overflow.h
Normal file
65
main/share/gb_overflow.h
Normal file
@ -0,0 +1,65 @@
|
||||
/***************************************************************************
|
||||
|
||||
gb_overflow.h
|
||||
|
||||
(c) Benoît Minisini <benoit.minisini@gambas-basic.org>
|
||||
|
||||
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 */
|
Loading…
x
Reference in New Issue
Block a user