From: Alan T. DeKok Date: Thu, 22 Sep 2022 18:46:00 +0000 (-0400) Subject: clean up integer calculations X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8cf89b524dfa95ef238403b5b0ad39e53eb0a419;p=thirdparty%2Ffreeradius-server.git clean up integer calculations simplify the process of hinting, and always upcast intermediate integers to int64_t or uint64_t. That way the result is much more likely to be representable --- diff --git a/src/lib/util/calc.c b/src/lib/util/calc.c index 4ae4521b675..96f0a722573 100644 --- a/src/lib/util/calc.c +++ b/src/lib/util/calc.c @@ -66,6 +66,11 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { * string / octets -> octets */ [FR_TYPE_STRING] = { + [FR_TYPE_STRING] = FR_TYPE_STRING, + [FR_TYPE_OCTETS] = FR_TYPE_OCTETS, + }, + + [FR_TYPE_OCTETS] = { [FR_TYPE_OCTETS] = FR_TYPE_OCTETS, }, @@ -81,10 +86,19 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_IPV4_ADDR] = FR_TYPE_INT64, }, + /* + * IPv6 mod IPv6 -> ???? + */ + [FR_TYPE_IPV6_ADDR] = { + [FR_TYPE_IPV6_ADDR] = FR_TYPE_OCTETS, + }, + /* * Prefix + int --> ipaddr */ [FR_TYPE_IPV4_PREFIX] = { + [FR_TYPE_IPV4_PREFIX] = FR_TYPE_IPV4_PREFIX, + [FR_TYPE_BOOL] = FR_TYPE_IPV4_ADDR, [FR_TYPE_UINT8] = FR_TYPE_IPV4_ADDR, @@ -104,6 +118,8 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { }, [FR_TYPE_IPV6_PREFIX] = { + [FR_TYPE_IPV6_PREFIX] = FR_TYPE_IPV6_PREFIX, + [FR_TYPE_BOOL] = FR_TYPE_IPV6_ADDR, [FR_TYPE_UINT8] = FR_TYPE_IPV6_ADDR, @@ -127,6 +143,8 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { * the other integer. */ [FR_TYPE_BOOL] = { + [FR_TYPE_BOOL] = FR_TYPE_BOOL, + [FR_TYPE_STRING] = FR_TYPE_BOOL, [FR_TYPE_OCTETS] = FR_TYPE_BOOL, @@ -158,17 +176,18 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_STRING] = FR_TYPE_UINT8, [FR_TYPE_OCTETS] = FR_TYPE_UINT8, - [FR_TYPE_UINT16] = FR_TYPE_UINT16, - [FR_TYPE_UINT32] = FR_TYPE_UINT32, + [FR_TYPE_UINT8] = FR_TYPE_UINT64, + [FR_TYPE_UINT16] = FR_TYPE_UINT64, + [FR_TYPE_UINT32] = FR_TYPE_UINT64, [FR_TYPE_UINT64] = FR_TYPE_UINT64, - [FR_TYPE_SIZE] = FR_TYPE_SIZE, + [FR_TYPE_SIZE] = FR_TYPE_UINT64, [FR_TYPE_DATE] = FR_TYPE_DATE, - [FR_TYPE_INT8] = FR_TYPE_INT16, - [FR_TYPE_INT16] = FR_TYPE_INT16, - [FR_TYPE_INT32] = FR_TYPE_INT32, + [FR_TYPE_INT8] = FR_TYPE_INT64, + [FR_TYPE_INT16] = FR_TYPE_INT64, + [FR_TYPE_INT32] = FR_TYPE_INT64, [FR_TYPE_INT64] = FR_TYPE_INT64, [FR_TYPE_TIME_DELTA] = FR_TYPE_TIME_DELTA, @@ -181,16 +200,17 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_STRING] = FR_TYPE_UINT16, [FR_TYPE_OCTETS] = FR_TYPE_UINT16, - [FR_TYPE_UINT32] = FR_TYPE_UINT32, + [FR_TYPE_UINT16] = FR_TYPE_UINT64, + [FR_TYPE_UINT32] = FR_TYPE_UINT64, [FR_TYPE_UINT64] = FR_TYPE_UINT64, - [FR_TYPE_SIZE] = FR_TYPE_SIZE, + [FR_TYPE_SIZE] = FR_TYPE_UINT64, [FR_TYPE_DATE] = FR_TYPE_DATE, - [FR_TYPE_INT8] = FR_TYPE_INT32, - [FR_TYPE_INT16] = FR_TYPE_INT32, - [FR_TYPE_INT32] = FR_TYPE_INT32, + [FR_TYPE_INT8] = FR_TYPE_INT64, + [FR_TYPE_INT16] = FR_TYPE_INT64, + [FR_TYPE_INT32] = FR_TYPE_INT64, [FR_TYPE_INT64] = FR_TYPE_INT64, [FR_TYPE_TIME_DELTA] = FR_TYPE_TIME_DELTA, @@ -203,9 +223,10 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_STRING] = FR_TYPE_UINT32, [FR_TYPE_OCTETS] = FR_TYPE_UINT32, + [FR_TYPE_UINT32] = FR_TYPE_UINT64, [FR_TYPE_UINT64] = FR_TYPE_UINT64, - [FR_TYPE_SIZE] = FR_TYPE_SIZE, + [FR_TYPE_SIZE] = FR_TYPE_UINT64, [FR_TYPE_DATE] = FR_TYPE_DATE, @@ -224,7 +245,10 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_STRING] = FR_TYPE_UINT64, [FR_TYPE_OCTETS] = FR_TYPE_UINT64, - [FR_TYPE_SIZE] = FR_TYPE_SIZE, + [FR_TYPE_UINT64] = FR_TYPE_UINT64, + [FR_TYPE_INT64] = FR_TYPE_INT64, + + [FR_TYPE_SIZE] = FR_TYPE_UINT64, [FR_TYPE_DATE] = FR_TYPE_DATE, @@ -242,6 +266,8 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_INT32] = FR_TYPE_INT64, [FR_TYPE_INT64] = FR_TYPE_INT64, + [FR_TYPE_SIZE] = FR_TYPE_INT64, + [FR_TYPE_FLOAT32] = FR_TYPE_FLOAT32, [FR_TYPE_FLOAT64] = FR_TYPE_FLOAT64, }, @@ -254,6 +280,7 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_INT32] = FR_TYPE_DATE, [FR_TYPE_INT64] = FR_TYPE_DATE, + [FR_TYPE_DATE] = FR_TYPE_DATE, [FR_TYPE_TIME_DELTA] = FR_TYPE_DATE, [FR_TYPE_FLOAT32] = FR_TYPE_DATE, @@ -267,8 +294,9 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_STRING] = FR_TYPE_INT8, [FR_TYPE_OCTETS] = FR_TYPE_INT8, - [FR_TYPE_INT16] = FR_TYPE_INT32, - [FR_TYPE_INT32] = FR_TYPE_INT32, + [FR_TYPE_INT8] = FR_TYPE_INT64, + [FR_TYPE_INT16] = FR_TYPE_INT64, + [FR_TYPE_INT32] = FR_TYPE_INT64, [FR_TYPE_INT64] = FR_TYPE_INT64, [FR_TYPE_TIME_DELTA] = FR_TYPE_TIME_DELTA, @@ -281,6 +309,7 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_STRING] = FR_TYPE_INT16, [FR_TYPE_OCTETS] = FR_TYPE_INT16, + [FR_TYPE_INT16] = FR_TYPE_INT64, [FR_TYPE_INT32] = FR_TYPE_INT64, [FR_TYPE_INT64] = FR_TYPE_INT64, @@ -302,6 +331,8 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_STRING] = FR_TYPE_INT64, [FR_TYPE_OCTETS] = FR_TYPE_INT64, + [FR_TYPE_INT64] = FR_TYPE_INT64, + [FR_TYPE_TIME_DELTA] = FR_TYPE_TIME_DELTA, [FR_TYPE_FLOAT32] = FR_TYPE_FLOAT32, [FR_TYPE_FLOAT64] = FR_TYPE_FLOAT64, @@ -310,6 +341,8 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_TIME_DELTA] = { [FR_TYPE_STRING] = FR_TYPE_TIME_DELTA, + [FR_TYPE_TIME_DELTA] = FR_TYPE_TIME_DELTA, + [FR_TYPE_FLOAT32] = FR_TYPE_TIME_DELTA, [FR_TYPE_FLOAT64] = FR_TYPE_TIME_DELTA, }, @@ -317,15 +350,16 @@ static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = { [FR_TYPE_FLOAT32] = { [FR_TYPE_STRING] = FR_TYPE_FLOAT32, + [FR_TYPE_FLOAT32] = FR_TYPE_FLOAT32, [FR_TYPE_FLOAT64] = FR_TYPE_FLOAT64, }, [FR_TYPE_FLOAT64] = { + [FR_TYPE_FLOAT64] = FR_TYPE_FLOAT64, [FR_TYPE_STRING] = FR_TYPE_FLOAT64, }, }; - /** Updates type (a,b) -> c * * Note that we MUST have a less than b here. Otherwise there will @@ -775,7 +809,7 @@ static int calc_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value case T_LSHIFT: if (b->vb_uint32 >= 64) return ERR_OVERFLOW; - when = fr_time_delta_unwrap(a->vb_time_delta) << b->vb_uint8; + when = fr_time_delta_unwrap(a->vb_time_delta) << b->vb_uint32; dst->vb_time_delta = fr_time_delta_wrap(when); break; @@ -1506,188 +1540,176 @@ static int calc_float64(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_bo } -#define CALC(_t) static int calc_ ## _t(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2) \ -{ \ - switch (op) { \ - case T_ADD: \ - if (!fr_add(&dst->vb_ ## _t, in1->vb_ ## _t, in2->vb_ ## _t)) return ERR_OVERFLOW; \ - break; \ - \ - case T_SUB: \ - if (!fr_sub(&dst->vb_ ## _t, in1->vb_ ## _t, in2->vb_ ## _t)) return ERR_UNDERFLOW; \ - break; \ - \ - case T_MUL: \ - if (!fr_multiply(&dst->vb_ ## _t, in1->vb_ ## _t, in2->vb_ ## _t)) return ERR_OVERFLOW; \ - break; \ - \ - case T_DIV: \ - if (in2->vb_ ## _t == 0) return ERR_ZERO; \ - \ - dst->vb_ ## _t = in1->vb_ ## _t / in2->vb_ ## _t; \ - break; \ - \ - case T_MOD: \ - if (in2->vb_ ## _t == 0) return ERR_ZERO; \ - \ - dst->vb_ ## _t = in1->vb_ ## _t % in2->vb_ ## _t; \ - break; \ - \ - case T_AND: \ - dst->vb_ ## _t = in1->vb_ ## _t & in2->vb_ ## _t; \ - break; \ - \ - case T_OR: \ - dst->vb_ ## _t = in1->vb_ ## _t | in2->vb_ ## _t; \ - break; \ - \ - case T_XOR: \ - dst->vb_ ## _t = in1->vb_ ## _t ^ in2->vb_ ## _t; \ - break; \ - \ - case T_RSHIFT: \ - if (in2->vb_uint32 > (8 * sizeof(in1->vb_ ## _t))) return ERR_UNDERFLOW; \ - \ - dst->vb_ ## _t = in1->vb_ ## _t >> in2->vb_uint8; \ - break; \ - \ - case T_LSHIFT: \ - if (in2->vb_uint32 >= (8 * sizeof(in1->vb_ ## _t))) return ERR_OVERFLOW; \ - \ - dst->vb_ ## _t = in1->vb_ ## _t << in2->vb_uint8; \ - break; \ - \ - default: \ - return ERR_INVALID; \ - } \ - \ - return 0; \ -} +/* + * Do all intermediate operations on 64-bit numbers. + */ +static int calc_uint64(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2) +{ + fr_value_box_t one, two, result; + fr_value_box_t const *a = in1; + fr_value_box_t const *b = in2; -CALC(uint8) -CALC(uint16) -CALC(uint32) -CALC(uint64) + fr_value_box_init(&result, FR_TYPE_UINT64, NULL, a->tainted | b->tainted); -CALC(size) + COERCE_A(FR_TYPE_UINT64, NULL); -CALC(int8) -CALC(int16) -CALC(int32) -CALC(int64) + if ((op == T_RSHIFT) || (op == T_LSHIFT)) { + /* + * Don't touch the RHS. + */ + fr_assert(b->type == FR_TYPE_UINT32); -typedef int (*fr_binary_op_t)(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b); + } else { + COERCE_B(FR_TYPE_UINT64, dst->enumv); + } + + switch (op) { + case T_ADD: + if (!fr_add(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_OVERFLOW; + break; + + case T_SUB: + if (!fr_sub(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_UNDERFLOW; + break; -static const fr_binary_op_t calc_integer_type[FR_TYPE_MAX + 1] = { - [FR_TYPE_UINT8] = calc_uint8, - [FR_TYPE_UINT16] = calc_uint16, - [FR_TYPE_UINT32] = calc_uint32, - [FR_TYPE_UINT64] = calc_uint64, + case T_MUL: + if (!fr_multiply(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_OVERFLOW; + break; - [FR_TYPE_SIZE] = calc_size, + case T_DIV: + if (b->vb_uint64 == 0) return ERR_ZERO; - [FR_TYPE_INT8] = calc_int8, - [FR_TYPE_INT16] = calc_int16, - [FR_TYPE_INT32] = calc_int32, - [FR_TYPE_INT64] = calc_int64, -}; + result.vb_uint64 = a->vb_uint64 / b->vb_uint64; + break; + + case T_MOD: + if (b->vb_uint64 == 0) return ERR_ZERO; + + result.vb_uint64 = a->vb_uint64 % in2->vb_uint64; + break; + + case T_AND: + result.vb_uint64 = a->vb_uint64 & b->vb_uint64; + break; + + case T_OR: + result.vb_uint64 = a->vb_uint64 | b->vb_uint64; + break; + + case T_XOR: + result.vb_uint64 = a->vb_uint64 ^ b->vb_uint64; + break; + + case T_RSHIFT: + if (b->vb_uint32 > (8 * sizeof(a->vb_uint64))) return ERR_UNDERFLOW; + + result.vb_uint64 = a->vb_uint64 >> b->vb_uint32; + break; + + case T_LSHIFT: + if (b->vb_uint32 >= (8 * sizeof(a->vb_uint64))) return ERR_OVERFLOW; + + result.vb_uint64 = a->vb_uint64 << b->vb_uint32; + break; + + default: + return ERR_INVALID; + } -static int calc_integer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2) + /* + * Once we're done, cast the result to the final data type. + */ + if (fr_value_box_cast(ctx, dst, dst->type, dst->enumv, &result) < 0) return -1; + + return 0; +} + +/* + * Same as above, except uint64 -> int64. These functions should be kept in sync! + */ +static int calc_int64(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2) { - int rcode; - fr_type_t type; + fr_value_box_t one, two, result; fr_value_box_t const *a = in1; fr_value_box_t const *b = in2; - fr_value_box_t one, two, out; - fr_binary_op_t calc = NULL; - /* - * We don't do upcasts on shifting. - * - * @todo - on left shift, if the RHS shift value is - * larger than the LHS data type, then promote the result - * data type to the next thing which will fit. - */ + fr_value_box_init(&result, FR_TYPE_INT64, NULL, a->tainted | b->tainted); + + COERCE_A(FR_TYPE_INT64, NULL); + if ((op == T_RSHIFT) || (op == T_LSHIFT)) { - type = a->type; + /* + * Don't touch the RHS. + */ fr_assert(b->type == FR_TYPE_UINT32); - goto calc_it; + + } else { + COERCE_B(FR_TYPE_INT64, dst->enumv); } - /* - * All of the types are the same. Just do the work. - */ - if ((dst->type == in1->type) && - (dst->type == in2->type)) { - if (!calc_integer_type[dst->type]) return invalid_type(dst->type); + switch (op) { + case T_ADD: + if (!fr_add(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_OVERFLOW; + break; - return calc_integer_type[dst->type](ctx, dst, in1, op, in2); - } + case T_SUB: + if (!fr_sub(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_UNDERFLOW; + break; - /* - * Upcast to the largest type which will handle the - * calculations. - * - * Note that this still won't catch all of the overflow - * cases, just the majority. - * - * This will still fail if we do things like - * - * uint64 foo - int64 INT64_MIN -> uint64 - * - * the RHS should arguably be converted to uint64. - * Perhaps we'll do that as a later step. - */ - type = dst->type; - if (upcast_op[type][a->type] != FR_TYPE_NULL) { - type = upcast_op[type][a->type]; + case T_MUL: + if (!fr_multiply(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_OVERFLOW; + break; - } else if (upcast_op[a->type][type] != FR_TYPE_NULL) { - type = upcast_op[a->type][type]; - } + case T_DIV: + if (b->vb_int64 == 0) return ERR_ZERO; - if (upcast_op[type][b->type] != FR_TYPE_NULL) { - type = upcast_op[type][b->type]; + result.vb_int64 = a->vb_int64 / b->vb_int64; + break; - } else if (upcast_op[b->type][type] != FR_TYPE_NULL) { - type = upcast_op[b->type][type]; - } + case T_MOD: + if (b->vb_int64 == 0) return ERR_ZERO; - if (a->type != type) { - if (fr_value_box_cast(NULL, &one, type, NULL, a) < 0) return -1; - a = &one; - } + result.vb_int64 = a->vb_int64 % in2->vb_int64; + break; - if (b->type != type) { - if (fr_value_box_cast(NULL, &two, type, NULL, b) < 0) return -1; - b = &two; - } + case T_AND: + result.vb_int64 = a->vb_int64 & b->vb_int64; + break; - /* - * Clang scan is too stupid to notice that - * calc_integer_type[] is "const", so if we check - * calc_integer_type[type] for being !NULL, and then call - * a function from calc_integer_type[type], then the - * array entry can't be NULL. - * - * Apparently putting the function pointer into an - * intermediate variable shuts it up. - */ -calc_it: - calc = calc_integer_type[type]; - if (!calc) return invalid_type(type); + case T_OR: + result.vb_int64 = a->vb_int64 | b->vb_int64; + break; + + case T_XOR: + result.vb_int64 = a->vb_int64 ^ b->vb_int64; + break; - fr_value_box_init(&out, type, dst->enumv, false); - rcode = calc(NULL, &out, a, op, b); - if (rcode < 0) return rcode; + case T_RSHIFT: + if (b->vb_uint32 > (8 * sizeof(a->vb_int64))) return ERR_UNDERFLOW; + + result.vb_int64 = a->vb_int64 >> b->vb_uint32; + break; + + case T_LSHIFT: + if (b->vb_uint32 >= (8 * sizeof(a->vb_int64))) return ERR_OVERFLOW; + + result.vb_int64 = a->vb_int64 << b->vb_uint32; + break; + + default: + return ERR_INVALID; + } /* - * Then once we're done, cast the result to the final - * output type. + * Once we're done, cast the result to the final data type. */ - return fr_value_box_cast(NULL, dst, dst->type, dst->enumv, &out); + if (fr_value_box_cast(ctx, dst, dst->type, dst->enumv, &result) < 0) return -1; + + return 0; } +typedef int (*fr_binary_op_t)(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b); + static const fr_binary_op_t calc_type[FR_TYPE_MAX + 1] = { [FR_TYPE_BOOL] = calc_bool, @@ -1699,17 +1721,17 @@ static const fr_binary_op_t calc_type[FR_TYPE_MAX + 1] = { [FR_TYPE_IPV6_ADDR] = calc_ipv6_addr, [FR_TYPE_IPV6_PREFIX] = calc_ipv6_prefix, - [FR_TYPE_UINT8] = calc_integer, - [FR_TYPE_UINT16] = calc_integer, - [FR_TYPE_UINT32] = calc_integer, - [FR_TYPE_UINT64] = calc_integer, + [FR_TYPE_UINT8] = calc_uint64, + [FR_TYPE_UINT16] = calc_uint64, + [FR_TYPE_UINT32] = calc_uint64, + [FR_TYPE_UINT64] = calc_uint64, - [FR_TYPE_SIZE] = calc_integer, + [FR_TYPE_SIZE] = calc_uint64, - [FR_TYPE_INT8] = calc_integer, - [FR_TYPE_INT16] = calc_integer, - [FR_TYPE_INT32] = calc_integer, - [FR_TYPE_INT64] = calc_integer, + [FR_TYPE_INT8] = calc_int64, + [FR_TYPE_INT16] = calc_int64, + [FR_TYPE_INT32] = calc_int64, + [FR_TYPE_INT64] = calc_int64, [FR_TYPE_DATE] = calc_date, [FR_TYPE_TIME_DELTA] = calc_time_delta, @@ -1795,15 +1817,6 @@ int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint case T_DIV: case T_MOD: case T_XOR: - /* - * Nothing else set it. If the input types are - * the same, then that must be the output type. - */ - if (a->type == b->type) { - hint = a->type; - break; - } - /* * Try to "up-cast" the types. This is * so that we can take (for example) @@ -1816,7 +1829,7 @@ int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint hint = upcast_op[a->type][b->type]; if (hint == FR_TYPE_NULL) { hint = upcast_op[b->type][a->type]; - } else { + } else if (a->type != b->type) { fr_assert(upcast_op[b->type][a->type] == FR_TYPE_NULL); } @@ -1824,7 +1837,8 @@ int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint * No idea what to do. :( */ if (hint == FR_TYPE_NULL) { - fr_strerror_const("Unable to automatically determine output data type"); + fr_strerror_printf("Unable to automatically determine output data type for inputs %s and %s", + fr_type_to_str(a->type), fr_type_to_str(b->type)); goto done; } @@ -1866,7 +1880,7 @@ int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint * Try to "up-cast" the types. This is * so that we can take (for example) * uint8 < uint16, and have it make - * sense. uint16. + * sense. * * There must be only one entry per [a,b] * pairing. That way we're sure that [a,b]==[b,a] diff --git a/src/tests/unit/calc.txt b/src/tests/unit/calc.txt index d0f2e60b82f..a63f254dcff 100644 --- a/src/tests/unit/calc.txt +++ b/src/tests/unit/calc.txt @@ -7,7 +7,7 @@ # integers # calc uint8 255 + uint8 255 -> uint8 -match Value overflows 'uint8' when calculating result. +match Invalid cast from uint64 to uint8. 510 outside value range 0-255 calc uint8 127 + uint8 127 -> uint8 match 254