Fix for GitHub issue #199: handle signed division overflow.
When performing a signed division or modulus operation using native arithmetic, trap the special case that the numerator is the minimum integer value and the denominator is -1, as this gives an undefined result in C++.
This commit is contained in:
parent
6e49ab10ec
commit
7ad5b59a6f
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2018 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
# include "verinum.h"
|
||||
# include <iostream>
|
||||
# include <cassert>
|
||||
# include <climits>
|
||||
# include <cmath> // Needed to get pow for as_double().
|
||||
# include <cstdio> // Needed to get snprintf for as_string().
|
||||
# include <algorithm>
|
||||
|
|
@ -1444,7 +1445,8 @@ verinum operator / (const verinum&left, const verinum&right)
|
|||
if (use_len <= (8*sizeof(long) - 1)) {
|
||||
long l = left.as_long();
|
||||
long r = right.as_long();
|
||||
long v = l / r;
|
||||
bool overflow = (l == LONG_MIN) && (r == -1);
|
||||
long v = overflow ? LONG_MIN : l / r;
|
||||
for (unsigned idx = 0 ; idx < use_len ; idx += 1) {
|
||||
result.set(idx, (v & 1)? verinum::V1 : verinum::V0);
|
||||
v >>= 1;
|
||||
|
|
@ -1518,7 +1520,8 @@ verinum operator % (const verinum&left, const verinum&right)
|
|||
/* Use native signed modulus to do the work. */
|
||||
long l = left.as_long();
|
||||
long r = right.as_long();
|
||||
long v = l % r;
|
||||
bool overflow = (l == LONG_MIN) && (r == -1);
|
||||
long v = overflow ? 0 : l % r;
|
||||
for (unsigned idx = 0 ; idx < use_len ; idx += 1) {
|
||||
result.set(idx, (v & 1)? verinum::V1 : verinum::V0);
|
||||
v >>= 1;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2018 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -2707,6 +2707,10 @@ bool of_DIV_S(vthread_t thr, vvp_code_t)
|
|||
if (bp[0] == 0) {
|
||||
vvp_vector4_t tmp(wid, BIT4_X);
|
||||
vala = tmp;
|
||||
} else if (((long)ap[0] == LONG_MIN) && ((long)bp[0] == -1)) {
|
||||
vvp_vector4_t tmp(wid, BIT4_0);
|
||||
tmp.set_bit(wid-1, BIT4_1);
|
||||
vala = tmp;
|
||||
} else {
|
||||
long tmpa = (long) ap[0];
|
||||
long tmpb = (long) bp[0];
|
||||
|
|
@ -3996,6 +4000,9 @@ bool of_MOD_S(vthread_t thr, vvp_code_t)
|
|||
if (rv == 0)
|
||||
goto x_out;
|
||||
|
||||
if ((lv == LONG_LONG_MIN) && (rv == -1))
|
||||
goto zero_out;
|
||||
|
||||
/* Sign extend the signed operands when needed. */
|
||||
if (wid < 8*sizeof(long long)) {
|
||||
if (lv & (1LL << (wid-1)))
|
||||
|
|
@ -4027,6 +4034,9 @@ bool of_MOD_S(vthread_t thr, vvp_code_t)
|
|||
x_out:
|
||||
vala = vvp_vector4_t(wid, BIT4_X);
|
||||
return true;
|
||||
zero_out:
|
||||
vala = vvp_vector4_t(wid, BIT4_0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue