diff options
author | Thomas Habets <thomas@habets.se> | 2020-05-18 22:02:30 +0100 |
---|---|---|
committer | Martin Braun <martin@gnuradio.org> | 2020-05-21 10:46:58 -0700 |
commit | de5c0123e81329e1a8f6611edeac14062114af0c (patch) | |
tree | 80d7e6891675ac0d398e3e0453645023882af00b | |
parent | 4aa2ff61959a0005f50d9f591a76e69c2d3cbc34 (diff) |
gr-blocks/peak_detector: Remove UB on infinities
This code fixes two issues:
1. The code used `::min()` in one place, and "minus infinity" in
another, for the same purpose.
2. It used minus infinity on integer types, which is undefined
behavior.
(1) seems to have been accidentally left out of
9d9ea63c45b5f314eb344a69340ef49e8edafdfa.
(2)
Section 4.9:
> The behavior is undefined if the truncated value cannot be
> represented in the destination type.
And trunc() on infinity is still infinity, which can't be represented
in integer types.
-rw-r--r-- | cmake/msvc/config.h | 8 | ||||
-rw-r--r-- | gr-blocks/lib/peak_detector_impl.cc | 27 |
2 files changed, 25 insertions, 10 deletions
diff --git a/cmake/msvc/config.h b/cmake/msvc/config.h index 68f716e8a6..a055f59fe8 100644 --- a/cmake/msvc/config.h +++ b/cmake/msvc/config.h @@ -41,14 +41,6 @@ static inline float rintf(float x) #endif //////////////////////////////////////////////////////////////////////// -// math constants -//////////////////////////////////////////////////////////////////////// -#if _MSC_VER < 1800 -#include <math.h> -#define INFINITY HUGE_VAL -#endif - -//////////////////////////////////////////////////////////////////////// // random and srandom //////////////////////////////////////////////////////////////////////// #include <stdlib.h> diff --git a/gr-blocks/lib/peak_detector_impl.cc b/gr-blocks/lib/peak_detector_impl.cc index c10a977b1a..1967e4416e 100644 --- a/gr-blocks/lib/peak_detector_impl.cc +++ b/gr-blocks/lib/peak_detector_impl.cc @@ -15,11 +15,34 @@ #include "peak_detector_impl.h" #include <gnuradio/io_signature.h> #include <string.h> +#include <type_traits> #include <limits> namespace gr { namespace blocks { +namespace { + +// lowest_value() returns -infinity if the type has a concept of +// infinity. Otherwise it returns the lowest possible value. +// +// Positive infinity is guaranteed by std::numeric_limits<T>::has_infinity, but +// since we want negative infinity let's use IEEE754. +template <typename T, + typename std::enable_if<std::numeric_limits<T>::is_iec559, int>::type = 0> +constexpr T lowest_value() noexcept +{ + return -std::numeric_limits<T>::infinity(); +} + +template <typename T, + typename std::enable_if<!std::numeric_limits<T>::is_iec559, int>::type = 0> +constexpr T lowest_value() noexcept +{ + return std::numeric_limits<T>::lowest(); +} +} // namespace + template <class T> typename peak_detector<T>::sptr peak_detector<T>::make(float threshold_factor_rise, float threshold_factor_fall, @@ -61,7 +84,7 @@ int peak_detector_impl<T>::work(int noutput_items, memset(optr, 0, noutput_items * sizeof(char)); - T peak_val = std::numeric_limits<T>::min(); + T peak_val = lowest_value<T>(); int peak_ind = 0; unsigned char state = 0; int i = 0; @@ -89,7 +112,7 @@ int peak_detector_impl<T>::work(int noutput_items, } else { optr[peak_ind] = 1; state = 0; - peak_val = -(T)INFINITY; + peak_val = lowest_value<T>(); // printf("Leaving State 1: Peak: %f Peak Ind: %d i: %d noutput_items: // %d\n", peak_val, peak_ind, i, noutput_items); } |