factoring out logic to check for overflows during coercions

This commit is contained in:
Vern Paxson 2021-09-02 18:17:29 -07:00
parent 9757d37332
commit a67897135e
8 changed files with 89 additions and 37 deletions

View file

@ -333,6 +333,7 @@ set(MAIN_SRCS
Obj.cc Obj.cc
OpaqueVal.cc OpaqueVal.cc
Options.cc Options.cc
Overflow.cc
PacketFilter.cc PacketFilter.cc
Pipe.cc Pipe.cc
PolicyFile.cc PolicyFile.cc

39
src/Overflow.cc Normal file
View file

@ -0,0 +1,39 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek/Overflow.h"
#include "zeek/Val.h"
namespace zeek::detail {
bool would_overflow(const zeek::Type* from_type, const zeek::Type* to_type,
const Val* val)
{
if ( ! to_type || ! from_type )
return true;
if ( same_type(to_type, from_type) )
return false;
if ( to_type->InternalType() == TYPE_INTERNAL_DOUBLE )
return false;
if ( to_type->InternalType() == TYPE_INTERNAL_UNSIGNED )
{
if ( from_type->InternalType() == TYPE_INTERNAL_DOUBLE )
return double_to_count_would_overflow(val->InternalDouble());
if ( from_type->InternalType() == TYPE_INTERNAL_INT )
return int_to_count_would_overflow(val->InternalInt());
}
if ( to_type->InternalType() == TYPE_INTERNAL_INT )
{
if ( from_type->InternalType() == TYPE_INTERNAL_DOUBLE )
return double_to_int_would_overflow(val->InternalDouble());
if ( from_type->InternalType() == TYPE_INTERNAL_UNSIGNED )
return count_to_int_would_overflow(val->InternalUnsigned());
}
return false;
}
}

33
src/Overflow.h Normal file
View file

@ -0,0 +1,33 @@
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
#include "zeek/Type.h"
namespace zeek::detail {
inline bool double_to_count_would_overflow(double v)
{
return v < 0.0 || v > static_cast<double>(UINT64_MAX);
}
inline bool int_to_count_would_overflow(bro_int_t v)
{
return v < 0.0;
}
inline bool double_to_int_would_overflow(double v)
{
return v < static_cast<double>(INT64_MIN) ||
v > static_cast<double>(INT64_MAX);
}
inline bool count_to_int_would_overflow(bro_uint_t v)
{
return v > INT64_MAX;
}
extern bool would_overflow(const zeek::Type* from_type,
const zeek::Type* to_type, const Val* val);
}

View file

@ -2,6 +2,7 @@
#include "zeek/zeek-config.h" #include "zeek/zeek-config.h"
#include "zeek/Val.h" #include "zeek/Val.h"
#include "zeek/Overflow.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h> #include <sys/param.h>
@ -349,33 +350,6 @@ void Val::SetID(detail::ID* id)
} }
#endif #endif
bool Val::WouldOverflow(const zeek::Type* from_type, const zeek::Type* to_type, const Val* val)
{
if ( !to_type || !from_type )
return true;
else if ( same_type(to_type, from_type) )
return false;
if ( to_type->InternalType() == TYPE_INTERNAL_DOUBLE )
return false;
else if ( to_type->InternalType() == TYPE_INTERNAL_UNSIGNED )
{
if ( from_type->InternalType() == TYPE_INTERNAL_DOUBLE )
return (val->InternalDouble() < 0.0 || val->InternalDouble() > static_cast<double>(UINT64_MAX));
else if ( from_type->InternalType() == TYPE_INTERNAL_INT )
return (val->InternalInt() < 0);
}
else if ( to_type->InternalType() == TYPE_INTERNAL_INT )
{
if ( from_type->InternalType() == TYPE_INTERNAL_DOUBLE )
return (val->InternalDouble() < static_cast<double>(INT64_MIN) ||
val->InternalDouble() > static_cast<double>(INT64_MAX));
else if ( from_type->InternalType() == TYPE_INTERNAL_UNSIGNED )
return (val->InternalUnsigned() > INT64_MAX);
}
return false;
}
TableValPtr Val::GetRecordFields() TableValPtr Val::GetRecordFields()
{ {
@ -3825,7 +3799,7 @@ ValPtr check_and_promote(ValPtr v,
switch ( it ) { switch ( it ) {
case TYPE_INTERNAL_INT: case TYPE_INTERNAL_INT:
if ( ( vit == TYPE_INTERNAL_UNSIGNED || vit == TYPE_INTERNAL_DOUBLE ) && Val::WouldOverflow(vt, t, v.get()) ) if ( ( vit == TYPE_INTERNAL_UNSIGNED || vit == TYPE_INTERNAL_DOUBLE ) && detail::would_overflow(vt, t, v.get()) )
{ {
t->Error("overflow promoting from unsigned/double to signed arithmetic value", v.get(), false, expr_location); t->Error("overflow promoting from unsigned/double to signed arithmetic value", v.get(), false, expr_location);
return nullptr; return nullptr;
@ -3841,7 +3815,7 @@ ValPtr check_and_promote(ValPtr v,
break; break;
case TYPE_INTERNAL_UNSIGNED: case TYPE_INTERNAL_UNSIGNED:
if ( ( vit == TYPE_INTERNAL_DOUBLE || vit == TYPE_INTERNAL_INT) && Val::WouldOverflow(vt, t, v.get()) ) if ( ( vit == TYPE_INTERNAL_DOUBLE || vit == TYPE_INTERNAL_INT) && detail::would_overflow(vt, t, v.get()) )
{ {
t->Error("overflow promoting from signed/double to unsigned arithmetic value", v.get(), false, expr_location); t->Error("overflow promoting from signed/double to unsigned arithmetic value", v.get(), false, expr_location);
return nullptr; return nullptr;

View file

@ -207,8 +207,6 @@ UNDERLYING_ACCESSOR_DECL(TypeVal, zeek::Type*, AsType)
void SetID(detail::ID* id); void SetID(detail::ID* id);
#endif #endif
static bool WouldOverflow(const zeek::Type* from_type, const zeek::Type* to_type, const Val* val);
TableValPtr GetRecordFields(); TableValPtr GetRecordFields();
StringValPtr ToJSON(bool only_loggable=false, RE_Matcher* re=nullptr); StringValPtr ToJSON(bool only_loggable=false, RE_Matcher* re=nullptr);

View file

@ -2134,8 +2134,6 @@ ExprPtr ArithCoerceExpr::Reduce(Reducer* c, StmtPtr& red_stmt)
if ( ! op->IsReduced(c) ) if ( ! op->IsReduced(c) )
op = op->ReduceToSingleton(c, red_stmt); op = op->ReduceToSingleton(c, red_stmt);
auto t = type->InternalType();
if ( op->Tag() == EXPR_CONST ) if ( op->Tag() == EXPR_CONST )
{ {
const auto& t = GetType(); const auto& t = GetType();
@ -2153,9 +2151,18 @@ ExprPtr ArithCoerceExpr::Reduce(Reducer* c, StmtPtr& red_stmt)
if ( c->Optimizing() ) if ( c->Optimizing() )
return ThisPtr(); return ThisPtr();
auto bt = op->GetType()->InternalType(); const auto& ot = op->GetType();
auto bt = ot->InternalType();
auto tt = type->InternalType();
if ( t == bt ) if ( ot->Tag() == TYPE_VECTOR )
{
bt = ot->Yield()->InternalType();
tt = type->Yield()->InternalType();
}
if ( bt == tt )
// Can drop the conversion.
return op; return op;
return AssignToTemporary(c, red_stmt); return AssignToTemporary(c, red_stmt);

View file

@ -1141,8 +1141,9 @@ eval frame[z.v1].double_val = double(frame[z.v2].uint_val);
macro EvalCoerceVec(coercer) macro EvalCoerceVec(coercer)
Unref(frame[z.v1].vector_val); auto old_v1 = frame[z.v1].vector_val;
frame[z.v1].vector_val = coercer(frame[z.v2].vector_val); frame[z.v1].vector_val = coercer(frame[z.v2].vector_val);
Unref(old_v1); // delayed to allow for same value on both sides
internal-op Coerce-UI-Vec internal-op Coerce-UI-Vec
type VV type VV

View file

@ -98,7 +98,6 @@ static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, VectorVal* v2,
auto res_zv = new VectorVal(yt); \ auto res_zv = new VectorVal(yt); \
auto n = v.size(); \ auto n = v.size(); \
res_zv->Resize(n); \ res_zv->Resize(n); \
ASSERT(0); \
auto& res = *res_zv->RawVec(); \ auto& res = *res_zv->RawVec(); \
for ( auto i = 0U; i < n; ++i ) \ for ( auto i = 0U; i < n; ++i ) \
if ( v[i] ) \ if ( v[i] ) \