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:
Benoît Minisini 2022-12-06 20:30:39 +01:00
parent 3a35562603
commit 0a7f10ad52
6 changed files with 374 additions and 10 deletions

View File

@ -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, ...)
{

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -206,4 +206,4 @@ typedef
break; \
} if (errno)
#endif /* __COMMON_H */
#endif /* __GB_COMMON_H */

65
main/share/gb_overflow.h Normal file
View 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 */