mirror of https://github.com/ecmwf/eccodes.git
ECC-1930: Fix overflow using compile-time code
This commit is contained in:
parent
51c717e75d
commit
39641acf3b
|
@ -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];
|
||||||
|
}
|
||||||
|
};
|
|
@ -10,6 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "grib_accessor_class_signed.h"
|
#include "grib_accessor_class_signed.h"
|
||||||
|
#include "NumericLimits.h"
|
||||||
|
|
||||||
grib_accessor_signed_t _grib_accessor_signed{};
|
grib_accessor_signed_t _grib_accessor_signed{};
|
||||||
grib_accessor* grib_accessor_signed = &_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 {
|
else {
|
||||||
// ECC-1605: Check overflow/underflow
|
// ECC-1605: Check overflow/underflow
|
||||||
const int nbits = nbytes_ * 8;
|
const int nbits = nbytes_ * 8;
|
||||||
const long minval = -(1L << (nbits - 1)) + 1;
|
const long minval = NumericLimits<long>::min(nbits);
|
||||||
const long maxval = (1L << (nbits - 1)) - 1;
|
const long maxval = NumericLimits<long>::max(nbits);
|
||||||
// printf(" key=%s: v=%ld (minval=%ld maxval=%ld)\n", name_ , v, minval, maxval);
|
// printf(" key=%s: v=%ld (minval=%ld maxval=%ld)\n", name_ , v, minval, maxval);
|
||||||
if (v > maxval || v < minval) {
|
if (v > maxval || v < minval) {
|
||||||
grib_context_log(context_, GRIB_LOG_ERROR,
|
grib_context_log(context_, GRIB_LOG_ERROR,
|
||||||
|
|
Loading…
Reference in New Issue