mirror of
https://github.com/zeek/zeek.git
synced 2025-10-05 16:18:19 +00:00
run-time checking of vector operations for overflows and division-by-zero
This commit is contained in:
parent
abd75932a2
commit
5c6801131f
1 changed files with 48 additions and 26 deletions
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "zeek/script_opt/CPP/RuntimeVec.h"
|
#include "zeek/script_opt/CPP/RuntimeVec.h"
|
||||||
|
|
||||||
|
#include "zeek/Overflow.h"
|
||||||
#include "zeek/ZeekString.h"
|
#include "zeek/ZeekString.h"
|
||||||
|
|
||||||
namespace zeek::detail
|
namespace zeek::detail
|
||||||
|
@ -103,20 +104,25 @@ VEC_OP1(comp, ~, )
|
||||||
|
|
||||||
// A kernel for applying a binary operation element-by-element to two
|
// A kernel for applying a binary operation element-by-element to two
|
||||||
// vectors of a given low-level type.
|
// vectors of a given low-level type.
|
||||||
#define VEC_OP2_KERNEL(accessor, type, op) \
|
#define VEC_OP2_KERNEL(accessor, type, op, zero_check) \
|
||||||
for ( unsigned int i = 0; i < v1->Size(); ++i ) \
|
for ( unsigned int i = 0; i < v1->Size(); ++i ) \
|
||||||
{ \
|
{ \
|
||||||
auto v1_i = v1->ValAt(i); \
|
auto v1_i = v1->ValAt(i); \
|
||||||
auto v2_i = v2->ValAt(i); \
|
auto v2_i = v2->ValAt(i); \
|
||||||
if ( v1_i && v2_i ) \
|
if ( v1_i && v2_i ) \
|
||||||
|
{ \
|
||||||
|
if ( zero_check && v2_i->IsZero() ) \
|
||||||
|
reporter->CPPRuntimeError("division/modulo by zero"); \
|
||||||
|
else \
|
||||||
v_result->Assign(i, make_intrusive<type>(v1_i->accessor() op v2_i->accessor())); \
|
v_result->Assign(i, make_intrusive<type>(v1_i->accessor() op v2_i->accessor())); \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analogous to VEC_OP1, instantiates a function for a given binary operation,
|
// Analogous to VEC_OP1, instantiates a function for a given binary operation,
|
||||||
// which might-or-might-not be supported for low-level "double" types.
|
// which might-or-might-not be supported for low-level "double" types.
|
||||||
// This version is for operations whose result type is the same as the
|
// This version is for operations whose result type is the same as the
|
||||||
// operand type.
|
// operand type.
|
||||||
#define VEC_OP2(name, op, double_kernel) \
|
#define VEC_OP2(name, op, double_kernel, zero_check) \
|
||||||
VectorValPtr vec_op_##name##__CPP(const VectorValPtr& v1, const VectorValPtr& v2) \
|
VectorValPtr vec_op_##name##__CPP(const VectorValPtr& v1, const VectorValPtr& v2) \
|
||||||
{ \
|
{ \
|
||||||
if ( ! check_vec_sizes__CPP(v1, v2) ) \
|
if ( ! check_vec_sizes__CPP(v1, v2) ) \
|
||||||
|
@ -130,15 +136,15 @@ VEC_OP1(comp, ~, )
|
||||||
case TYPE_INTERNAL_INT: \
|
case TYPE_INTERNAL_INT: \
|
||||||
{ \
|
{ \
|
||||||
if ( vt->Yield()->Tag() == TYPE_BOOL ) \
|
if ( vt->Yield()->Tag() == TYPE_BOOL ) \
|
||||||
VEC_OP2_KERNEL(AsBool, BoolVal, op) \
|
VEC_OP2_KERNEL(AsBool, BoolVal, op, zero_check) \
|
||||||
else \
|
else \
|
||||||
VEC_OP2_KERNEL(AsInt, IntVal, op) \
|
VEC_OP2_KERNEL(AsInt, IntVal, op, zero_check) \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
case TYPE_INTERNAL_UNSIGNED: \
|
case TYPE_INTERNAL_UNSIGNED: \
|
||||||
{ \
|
{ \
|
||||||
VEC_OP2_KERNEL(AsCount, CountVal, op) \
|
VEC_OP2_KERNEL(AsCount, CountVal, op, zero_check) \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
|
@ -151,27 +157,28 @@ VEC_OP1(comp, ~, )
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiates a double_kernel for a binary operation.
|
// Instantiates a double_kernel for a binary operation.
|
||||||
#define VEC_OP2_WITH_DOUBLE(name, op) \
|
#define VEC_OP2_WITH_DOUBLE(name, op, zero_check) \
|
||||||
VEC_OP2( \
|
VEC_OP2( \
|
||||||
name, op, case TYPE_INTERNAL_DOUBLE \
|
name, op, case TYPE_INTERNAL_DOUBLE \
|
||||||
: { \
|
: { \
|
||||||
VEC_OP2_KERNEL(AsDouble, DoubleVal, op) \
|
VEC_OP2_KERNEL(AsDouble, DoubleVal, op, zero_check) \
|
||||||
break; \
|
break; \
|
||||||
})
|
}, \
|
||||||
|
zero_check)
|
||||||
|
|
||||||
// The binary operations supported for vectors.
|
// The binary operations supported for vectors.
|
||||||
VEC_OP2_WITH_DOUBLE(add, +)
|
VEC_OP2_WITH_DOUBLE(add, +, 0)
|
||||||
VEC_OP2_WITH_DOUBLE(sub, -)
|
VEC_OP2_WITH_DOUBLE(sub, -, 0)
|
||||||
VEC_OP2_WITH_DOUBLE(mul, *)
|
VEC_OP2_WITH_DOUBLE(mul, *, 0)
|
||||||
VEC_OP2_WITH_DOUBLE(div, /)
|
VEC_OP2_WITH_DOUBLE(div, /, 1)
|
||||||
VEC_OP2(mod, %, )
|
VEC_OP2(mod, %, , 1)
|
||||||
VEC_OP2(and, &, )
|
VEC_OP2(and, &, , 0)
|
||||||
VEC_OP2(or, |, )
|
VEC_OP2(or, |, , 0)
|
||||||
VEC_OP2(xor, ^, )
|
VEC_OP2(xor, ^, , 0)
|
||||||
VEC_OP2(andand, &&, )
|
VEC_OP2(andand, &&, , 0)
|
||||||
VEC_OP2(oror, ||, )
|
VEC_OP2(oror, ||, , 0)
|
||||||
VEC_OP2(lshift, <<, )
|
VEC_OP2(lshift, <<, , 0)
|
||||||
VEC_OP2(rshift, >>, )
|
VEC_OP2(rshift, >>, , 0)
|
||||||
|
|
||||||
// A version of VEC_OP2 that instead supports relational operations, so
|
// A version of VEC_OP2 that instead supports relational operations, so
|
||||||
// the result type is always vector-of-bool.
|
// the result type is always vector-of-bool.
|
||||||
|
@ -189,19 +196,19 @@ VEC_OP2(rshift, >>, )
|
||||||
{ \
|
{ \
|
||||||
case TYPE_INTERNAL_INT: \
|
case TYPE_INTERNAL_INT: \
|
||||||
{ \
|
{ \
|
||||||
VEC_OP2_KERNEL(AsInt, BoolVal, op) \
|
VEC_OP2_KERNEL(AsInt, BoolVal, op, 0) \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
case TYPE_INTERNAL_UNSIGNED: \
|
case TYPE_INTERNAL_UNSIGNED: \
|
||||||
{ \
|
{ \
|
||||||
VEC_OP2_KERNEL(AsCount, BoolVal, op) \
|
VEC_OP2_KERNEL(AsCount, BoolVal, op, 0) \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
case TYPE_INTERNAL_DOUBLE: \
|
case TYPE_INTERNAL_DOUBLE: \
|
||||||
{ \
|
{ \
|
||||||
VEC_OP2_KERNEL(AsDouble, BoolVal, op) \
|
VEC_OP2_KERNEL(AsDouble, BoolVal, op, 0) \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
|
@ -394,6 +401,11 @@ VectorValPtr vector_coerce_to__CPP(const VectorValPtr& v, const TypePtr& targ)
|
||||||
if ( ! v_i )
|
if ( ! v_i )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// We compute these for each element to cover the case where
|
||||||
|
// the coerced vector is of type "any".
|
||||||
|
auto& t_i = v_i->GetType();
|
||||||
|
auto it = t_i->InternalType();
|
||||||
|
|
||||||
ValPtr r_i;
|
ValPtr r_i;
|
||||||
switch ( ytag )
|
switch ( ytag )
|
||||||
{
|
{
|
||||||
|
@ -402,10 +414,20 @@ VectorValPtr vector_coerce_to__CPP(const VectorValPtr& v, const TypePtr& targ)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
|
if ( (it == TYPE_INTERNAL_UNSIGNED || it == TYPE_INTERNAL_DOUBLE) &&
|
||||||
|
would_overflow(t_i.get(), yt.get(), v_i.get()) )
|
||||||
|
reporter->CPPRuntimeError(
|
||||||
|
"overflow promoting from unsigned/double to signed arithmetic value");
|
||||||
|
else
|
||||||
r_i = val_mgr->Int(v_i->CoerceToInt());
|
r_i = val_mgr->Int(v_i->CoerceToInt());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_COUNT:
|
case TYPE_COUNT:
|
||||||
|
if ( (it == TYPE_INTERNAL_INT || it == TYPE_INTERNAL_DOUBLE) &&
|
||||||
|
would_overflow(t_i.get(), yt.get(), v_i.get()) )
|
||||||
|
reporter->CPPRuntimeError(
|
||||||
|
"overflow promoting from signed/double to signed arithmetic value");
|
||||||
|
else
|
||||||
r_i = val_mgr->Count(v_i->CoerceToUnsigned());
|
r_i = val_mgr->Count(v_i->CoerceToUnsigned());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue