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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
# include "verinum.h"
|
# include "verinum.h"
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
|
# include <climits>
|
||||||
# include <cmath> // Needed to get pow for as_double().
|
# include <cmath> // Needed to get pow for as_double().
|
||||||
# include <cstdio> // Needed to get snprintf for as_string().
|
# include <cstdio> // Needed to get snprintf for as_string().
|
||||||
# include <algorithm>
|
# include <algorithm>
|
||||||
|
|
@ -1444,7 +1445,8 @@ verinum operator / (const verinum&left, const verinum&right)
|
||||||
if (use_len <= (8*sizeof(long) - 1)) {
|
if (use_len <= (8*sizeof(long) - 1)) {
|
||||||
long l = left.as_long();
|
long l = left.as_long();
|
||||||
long r = right.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) {
|
for (unsigned idx = 0 ; idx < use_len ; idx += 1) {
|
||||||
result.set(idx, (v & 1)? verinum::V1 : verinum::V0);
|
result.set(idx, (v & 1)? verinum::V1 : verinum::V0);
|
||||||
v >>= 1;
|
v >>= 1;
|
||||||
|
|
@ -1518,7 +1520,8 @@ verinum operator % (const verinum&left, const verinum&right)
|
||||||
/* Use native signed modulus to do the work. */
|
/* Use native signed modulus to do the work. */
|
||||||
long l = left.as_long();
|
long l = left.as_long();
|
||||||
long r = right.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) {
|
for (unsigned idx = 0 ; idx < use_len ; idx += 1) {
|
||||||
result.set(idx, (v & 1)? verinum::V1 : verinum::V0);
|
result.set(idx, (v & 1)? verinum::V1 : verinum::V0);
|
||||||
v >>= 1;
|
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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) {
|
if (bp[0] == 0) {
|
||||||
vvp_vector4_t tmp(wid, BIT4_X);
|
vvp_vector4_t tmp(wid, BIT4_X);
|
||||||
vala = tmp;
|
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 {
|
} else {
|
||||||
long tmpa = (long) ap[0];
|
long tmpa = (long) ap[0];
|
||||||
long tmpb = (long) bp[0];
|
long tmpb = (long) bp[0];
|
||||||
|
|
@ -3996,6 +4000,9 @@ bool of_MOD_S(vthread_t thr, vvp_code_t)
|
||||||
if (rv == 0)
|
if (rv == 0)
|
||||||
goto x_out;
|
goto x_out;
|
||||||
|
|
||||||
|
if ((lv == LONG_LONG_MIN) && (rv == -1))
|
||||||
|
goto zero_out;
|
||||||
|
|
||||||
/* Sign extend the signed operands when needed. */
|
/* Sign extend the signed operands when needed. */
|
||||||
if (wid < 8*sizeof(long long)) {
|
if (wid < 8*sizeof(long long)) {
|
||||||
if (lv & (1LL << (wid-1)))
|
if (lv & (1LL << (wid-1)))
|
||||||
|
|
@ -4027,6 +4034,9 @@ bool of_MOD_S(vthread_t thr, vvp_code_t)
|
||||||
x_out:
|
x_out:
|
||||||
vala = vvp_vector4_t(wid, BIT4_X);
|
vala = vvp_vector4_t(wid, BIT4_X);
|
||||||
return true;
|
return true;
|
||||||
|
zero_out:
|
||||||
|
vala = vvp_vector4_t(wid, BIT4_0);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue