Fix casting from double to uint64_t to avoid UB

This commit is contained in:
Wei Ren 2025-07-27 11:19:07 -07:00
parent db82380cec
commit 7a912c55fb
No known key found for this signature in database
GPG Key ID: 5FE20215B0F1F9A9
2 changed files with 30 additions and 9 deletions

View File

@ -96,6 +96,14 @@ static double vlg_round(double rval)
}
}
static uint64_t vlg_round_to_u64(double rval)
{
// Directly casting a negative double to an unsigned integer types is
// undefined behavior and behaves differently on different architectures.
// Cast to signed integer first to get the behavior we want.
return static_cast<uint64_t>(static_cast<int64_t>(vlg_round(rval)));
}
static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp)
{
__vpiVThrWord*obj = dynamic_cast<__vpiVThrWord*>(ref);
@ -141,17 +149,17 @@ static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp)
break;
case vpiOctStrVal:
snprintf(rbuf, RBUF_USE_SIZE, "%" PRIo64, (uint64_t)vlg_round(val));
snprintf(rbuf, RBUF_USE_SIZE, "%" PRIo64, vlg_round_to_u64(val));
vp->value.str = rbuf;
break;
case vpiHexStrVal:
snprintf(rbuf, RBUF_USE_SIZE, "%" PRIx64, (uint64_t)vlg_round(val));
snprintf(rbuf, RBUF_USE_SIZE, "%" PRIx64, vlg_round_to_u64(val));
vp->value.str = rbuf;
break;
case vpiBinStrVal: {
uint64_t vali = (uint64_t)vlg_round(val);
uint64_t vali = vlg_round_to_u64(val);
unsigned len = 0;
while (vali > 0) {
@ -159,7 +167,7 @@ static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp)
vali /= 2;
}
vali = (uint64_t)vlg_round(val);
vali = vlg_round_to_u64(val);
for (unsigned idx = 0 ; idx < len ; idx += 1) {
rbuf[len-idx-1] = (vali & 1)? '1' : '0';
vali /= 2;

View File

@ -2374,17 +2374,30 @@ bool of_CVT_SR(vthread_t thr, vvp_code_t cp)
return true;
}
static double vlg_round(double rval)
{
if (rval >= 0.0) {
return floor(rval + 0.5);
} else {
return ceil(rval - 0.5);
}
}
static uint64_t vlg_round_to_u64(double rval)
{
// Directly casting a negative double to an unsigned integer types is
// undefined behavior and behaves differently on different architectures.
// Cast to signed integer first to get the behavior we want.
return static_cast<uint64_t>(static_cast<int64_t>(vlg_round(rval)));
}
/*
* %cvt/ur <idx>
*/
bool of_CVT_UR(vthread_t thr, vvp_code_t cp)
{
double r = thr->pop_real();
if (r >= 0.0)
thr->words[cp->bit_idx[0]].w_uint = (uint64_t)floor(r+0.5);
else
thr->words[cp->bit_idx[0]].w_uint = (uint64_t)ceil(r-0.5);
thr->words[cp->bit_idx[0]].w_uint = vlg_round_to_u64(r);
return true;
}