From 703363feafa60cb567e8863324fb07ed54ba8aaa Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 12 Jun 2018 21:59:58 +0100 Subject: [PATCH] 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++. (cherry picked from commit 7ad5b59a6f7d2e46aefe9dbb85bcc8ea1c7dd9b5) --- verinum.cc | 9 ++++++--- vvp/vthread.cc | 12 +++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/verinum.cc b/verinum.cc index c5f4be65e..7b466053b 100644 --- a/verinum.cc +++ b/verinum.cc @@ -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 # include +# include # include // Needed to get pow for as_double(). # include // Needed to get snprintf for as_string(). # include @@ -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; diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 4696776e0..f2b1760cb 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2015 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 @@ -2517,6 +2517,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]; @@ -3767,6 +3771,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))) @@ -3798,6 +3805,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; } /*