ECC-1930: Fix overflow using compile-time code

This commit is contained in:
Eugen Betke 2024-10-08 17:09:44 +00:00 committed by shahramn
parent 51c717e75d
commit 39641acf3b
2 changed files with 73 additions and 2 deletions

70
src/NumericLimits.h Normal file
View File

@ -0,0 +1,70 @@
/*
* (C) Copyright 2005- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*
* In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
* virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
*/
#pragma once
#include <array>
template <typename ValueType>
struct NumericLimits
{
static_assert(std::is_integral<ValueType>::value, "ValueType must be an integral type");
private:
using S = std::make_signed_t<ValueType>;
using U = std::make_unsigned_t<ValueType>;
static constexpr int MaxN = 8 * sizeof(ValueType);
static constexpr std::array<ValueType, MaxN> max_ = []() {
if constexpr (std::is_signed<ValueType>::value) {
std::array<S, MaxN> max{};
for (int i = 1; i < MaxN; ++i) {
auto ones = ~(static_cast<U>(0));
max[i] = static_cast<S>(ones >> (MaxN - i));
}
return max;
}
else {
std::array<U, MaxN> max{};
for (int i = 1; i < MaxN; ++i) {
auto ones = ~(static_cast<U>(0));
max[i] = ones >> (MaxN - i - 1);
}
return max;
}
}();
static constexpr std::array<ValueType, MaxN> min_ = []() {
if constexpr (std::is_signed<ValueType>::value) {
std::array<S, MaxN> min{};
for (int i = 1; i < MaxN; ++i) {
min[i] = ~max_[i];
}
return min;
}
else {
return std::array<U, MaxN>{};
}
}();
public:
static constexpr ValueType min(int nbits)
{
if constexpr (std::is_signed<ValueType>::value)
return min_[nbits - 1];
else
return 0;
}
static constexpr ValueType max(int nbits)
{
return max_[nbits - 1];
}
};

View File

@ -10,6 +10,7 @@
*/
#include "grib_accessor_class_signed.h"
#include "NumericLimits.h"
grib_accessor_signed_t _grib_accessor_signed{};
grib_accessor* grib_accessor_signed = &_grib_accessor_signed;
@ -118,8 +119,8 @@ int grib_accessor_signed_t::pack_long(const long* val, size_t* len)
else {
// ECC-1605: Check overflow/underflow
const int nbits = nbytes_ * 8;
const long minval = -(1L << (nbits - 1)) + 1;
const long maxval = (1L << (nbits - 1)) - 1;
const long minval = NumericLimits<long>::min(nbits);
const long maxval = NumericLimits<long>::max(nbits);
// printf(" key=%s: v=%ld (minval=%ld maxval=%ld)\n", name_ , v, minval, maxval);
if (v > maxval || v < minval) {
grib_context_log(context_, GRIB_LOG_ERROR,