diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ea41271c16..b9b1263812 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -333,6 +333,7 @@ set(MAIN_SRCS Obj.cc OpaqueVal.cc Options.cc + Overflow.cc PacketFilter.cc Pipe.cc PolicyFile.cc diff --git a/src/Overflow.cc b/src/Overflow.cc new file mode 100644 index 0000000000..4cdc8d14e2 --- /dev/null +++ b/src/Overflow.cc @@ -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; + } + +} diff --git a/src/Overflow.h b/src/Overflow.h new file mode 100644 index 0000000000..0119085eae --- /dev/null +++ b/src/Overflow.h @@ -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(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(INT64_MIN) || + v > static_cast(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); + +} diff --git a/src/Val.cc b/src/Val.cc index 35df899c6c..0741b4a6eb 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -2,6 +2,7 @@ #include "zeek/zeek-config.h" #include "zeek/Val.h" +#include "zeek/Overflow.h" #include #include @@ -349,33 +350,6 @@ void Val::SetID(detail::ID* id) } #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(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(INT64_MIN) || - val->InternalDouble() > static_cast(INT64_MAX)); - else if ( from_type->InternalType() == TYPE_INTERNAL_UNSIGNED ) - return (val->InternalUnsigned() > INT64_MAX); - } - - return false; - } TableValPtr Val::GetRecordFields() { @@ -3825,7 +3799,7 @@ ValPtr check_and_promote(ValPtr v, switch ( it ) { 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); return nullptr; @@ -3841,7 +3815,7 @@ ValPtr check_and_promote(ValPtr v, break; 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); return nullptr; diff --git a/src/Val.h b/src/Val.h index 9205eee98b..73c2e541be 100644 --- a/src/Val.h +++ b/src/Val.h @@ -207,8 +207,6 @@ UNDERLYING_ACCESSOR_DECL(TypeVal, zeek::Type*, AsType) void SetID(detail::ID* id); #endif - static bool WouldOverflow(const zeek::Type* from_type, const zeek::Type* to_type, const Val* val); - TableValPtr GetRecordFields(); StringValPtr ToJSON(bool only_loggable=false, RE_Matcher* re=nullptr); diff --git a/src/script_opt/Expr.cc b/src/script_opt/Expr.cc index 62f9395f57..07f61c5537 100644 --- a/src/script_opt/Expr.cc +++ b/src/script_opt/Expr.cc @@ -2134,8 +2134,6 @@ ExprPtr ArithCoerceExpr::Reduce(Reducer* c, StmtPtr& red_stmt) if ( ! op->IsReduced(c) ) op = op->ReduceToSingleton(c, red_stmt); - auto t = type->InternalType(); - if ( op->Tag() == EXPR_CONST ) { const auto& t = GetType(); @@ -2153,9 +2151,18 @@ ExprPtr ArithCoerceExpr::Reduce(Reducer* c, StmtPtr& red_stmt) if ( c->Optimizing() ) 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 AssignToTemporary(c, red_stmt); diff --git a/src/script_opt/ZAM/Ops.in b/src/script_opt/ZAM/Ops.in index e6d6a07332..c84ee49dfc 100644 --- a/src/script_opt/ZAM/Ops.in +++ b/src/script_opt/ZAM/Ops.in @@ -1141,8 +1141,9 @@ eval frame[z.v1].double_val = double(frame[z.v2].uint_val); 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); + Unref(old_v1); // delayed to allow for same value on both sides internal-op Coerce-UI-Vec type VV diff --git a/src/script_opt/ZAM/ZBody.cc b/src/script_opt/ZAM/ZBody.cc index 9f6c9059d5..62968fec27 100644 --- a/src/script_opt/ZAM/ZBody.cc +++ b/src/script_opt/ZAM/ZBody.cc @@ -98,7 +98,6 @@ static void vec_exec(ZOp op, TypePtr t, VectorVal*& v1, VectorVal* v2, auto res_zv = new VectorVal(yt); \ auto n = v.size(); \ res_zv->Resize(n); \ - ASSERT(0); \ auto& res = *res_zv->RawVec(); \ for ( auto i = 0U; i < n; ++i ) \ if ( v[i] ) \