From f22e3aa996ad11170be928ba27b73694988f6594 Mon Sep 17 00:00:00 2001 From: David Ockey <2897027+ockeydockey@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:56:50 -0500 Subject: [PATCH 1/5] Removed UB in type_def bit-shift operators --- include/etl/type_def.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/etl/type_def.h b/include/etl/type_def.h index 4815b670a..a54255b31 100644 --- a/include/etl/type_def.h +++ b/include/etl/type_def.h @@ -290,14 +290,14 @@ namespace etl } //********************************************************************* - ETL_CONSTEXPR14 type_def& operator <<=(int rhs) ETL_NOEXCEPT + ETL_CONSTEXPR14 type_def& operator <<=(unsigned int rhs) ETL_NOEXCEPT { value <<= rhs; return *this; } //********************************************************************* - ETL_CONSTEXPR14 type_def& operator >>=(int rhs) ETL_NOEXCEPT + ETL_CONSTEXPR14 type_def& operator >>=(unsigned int rhs) ETL_NOEXCEPT { value >>= rhs; return *this; @@ -589,7 +589,7 @@ namespace etl //********************************************************************* // << operator //********************************************************************* - friend ETL_CONSTEXPR type_def operator <<(const type_def& lhs, int rhs) ETL_NOEXCEPT + friend ETL_CONSTEXPR type_def operator <<(const type_def& lhs, unsigned int rhs) ETL_NOEXCEPT { return type_def(lhs.value << rhs); } @@ -597,7 +597,7 @@ namespace etl //********************************************************************* // >> operator //********************************************************************* - friend ETL_CONSTEXPR type_def operator >>(const type_def& lhs, int rhs) ETL_NOEXCEPT + friend ETL_CONSTEXPR type_def operator >>(const type_def& lhs, unsigned int rhs) ETL_NOEXCEPT { return type_def(lhs.value >> rhs); } From 4724d0137868fea6d11697ac7f18ddc9000d097a Mon Sep 17 00:00:00 2001 From: David Ockey <2897027+ockeydockey@users.noreply.github.com> Date: Tue, 9 Sep 2025 17:17:54 -0500 Subject: [PATCH 2/5] Changed shift operators to allow both signed and unsigned operands for shifts This allows the library user to explicitly use unsigned values to avoid UB --- include/etl/type_def.h | 62 +++++++++++++++++++++++++++++++++++++++--- test/test_type_def.cpp | 19 +++++++++++-- 2 files changed, 74 insertions(+), 7 deletions(-) diff --git a/include/etl/type_def.h b/include/etl/type_def.h index a54255b31..d3f3a433a 100644 --- a/include/etl/type_def.h +++ b/include/etl/type_def.h @@ -290,14 +290,28 @@ namespace etl } //********************************************************************* - ETL_CONSTEXPR14 type_def& operator <<=(unsigned int rhs) ETL_NOEXCEPT + template + ETL_CONSTEXPR +#if ETL_USING_CPP11 + typename etl::enable_if::value, type_def&>::type +#else + type_def& +#endif + operator <<=(T rhs) ETL_NOEXCEPT { value <<= rhs; return *this; } //********************************************************************* - ETL_CONSTEXPR14 type_def& operator >>=(unsigned int rhs) ETL_NOEXCEPT + template + ETL_CONSTEXPR +#if ETL_USING_CPP11 + typename etl::enable_if::value, type_def&>::type +#else + type_def& +#endif + operator >>=(T rhs) ETL_NOEXCEPT { value >>= rhs; return *this; @@ -589,19 +603,59 @@ namespace etl //********************************************************************* // << operator //********************************************************************* - friend ETL_CONSTEXPR type_def operator <<(const type_def& lhs, unsigned int rhs) ETL_NOEXCEPT + template + friend ETL_CONSTEXPR +#if ETL_USING_CPP11 + typename etl::enable_if::value, type_def>::type +#else + type_def +#endif + operator <<(const type_def& lhs, T rhs) ETL_NOEXCEPT { return type_def(lhs.value << rhs); } + //********************************************************************* + template + friend ETL_CONSTEXPR +#if ETL_USING_CPP11 + typename etl::enable_if::value, T>::type +#else + T +#endif + operator <<(T lhs, const type_def& rhs) ETL_NOEXCEPT + { + return lhs << rhs.value; + } + //********************************************************************* // >> operator //********************************************************************* - friend ETL_CONSTEXPR type_def operator >>(const type_def& lhs, unsigned int rhs) ETL_NOEXCEPT + template + friend ETL_CONSTEXPR +#if ETL_USING_CPP11 + typename etl::enable_if::value, type_def>::type +#else + type_def +#endif + operator >>(const type_def& lhs, T rhs) ETL_NOEXCEPT { return type_def(lhs.value >> rhs); } + //********************************************************************* + template + friend ETL_CONSTEXPR +#if ETL_USING_CPP11 + typename etl::enable_if::value, T>::type +#else + T +#endif + operator >>(T lhs, const type_def& rhs) ETL_NOEXCEPT + { + return lhs >> rhs.value; + } + //********************************************************************* // < operator //********************************************************************* diff --git a/test/test_type_def.cpp b/test/test_type_def.cpp index 30d277728..8b2554b1b 100644 --- a/test/test_type_def.cpp +++ b/test/test_type_def.cpp @@ -179,7 +179,9 @@ namespace CHECK_EQUAL(i |= 0x003DU, uint32_t(t |= type_t(0x003DU))); CHECK_EQUAL(i ^= 0xAA55U, uint32_t(t ^= 0xAA55U)); CHECK_EQUAL(i ^= 0xAA55U, uint32_t(t ^= type_t(0xAA55U))); + CHECK_EQUAL(i <<= 2, uint32_t(t <<= 2)); CHECK_EQUAL(i <<= 2U, uint32_t(t <<= 2U)); + CHECK_EQUAL(i >>= 2, uint32_t(t >>= 2)); CHECK_EQUAL(i >>= 2U, uint32_t(t >>= 2U)); CHECK_EQUAL(i %= 23, uint32_t(t %= 23)); @@ -195,8 +197,10 @@ namespace uint32_t i1 = 0x5A3DUL; uint32_t i2 = 0xB47AUL; + uint32_t i3 = 3UL; type_t t1(0x5A3DUL); type_t t2(0xB47AUL); + type_t t3(3UL); CHECK_EQUAL(i1 + Two, t1 + Two); CHECK_EQUAL(Two + i1, Two + t1); @@ -205,11 +209,11 @@ namespace CHECK_EQUAL(i1 - Two, t1 - Two); CHECK_EQUAL(i2 - i1, i2 - t1); CHECK_EQUAL(i2 - i1, t2 - t1); - + CHECK_EQUAL(i1 * Two, t1 * Two); CHECK_EQUAL(Two * i1, Two * t1); CHECK_EQUAL(i1 * i2, t1 * t2); - + CHECK_EQUAL(i1 / Two, t1 / Two); CHECK_EQUAL(i2 / i1, i2 / t1); CHECK_EQUAL(i2 / i1, t2 / t1); @@ -227,7 +231,16 @@ namespace CHECK_EQUAL(uint32_t(0xAA55) ^ i1, type_t(0xAA55UL) ^ t1); CHECK_EQUAL(i1 << 2, t1 << 2); + CHECK_EQUAL(i1 << 2U, t1 << 2U); + CHECK_EQUAL(2 << i1, 2 << t1); + CHECK_EQUAL(2U << i1, 2U << t1); + CHECK_EQUAL(2U << i1, 2U << t1); + CHECK_EQUAL(i1 << i3, t1 << t3); CHECK_EQUAL(i1 >> 2, t1 >> 2); + CHECK_EQUAL(i1 >> 2U, t1 >> 2U); + CHECK_EQUAL(2 >> i1, 2 >> t1); + CHECK_EQUAL(2U >> i1, 2U >> t1); + CHECK_EQUAL(i1 >> i3, t1 >> t3); CHECK_EQUAL(i1 % uint32_t(23), t1 % uint32_t(23)); CHECK_EQUAL(uint32_t(23) % i1, uint32_t(23) % t1); @@ -313,7 +326,7 @@ namespace return value; } - + TEST(test_arithmetic_constexpr) { constexpr arithmetic_type_t value_plus = CreatePlus(); From d17dca803ed339f41efa8622d85cd373d287d91f Mon Sep 17 00:00:00 2001 From: David Ockey <2897027+ockeydockey@users.noreply.github.com> Date: Wed, 10 Sep 2025 08:36:43 -0500 Subject: [PATCH 3/5] Fixed constexpr errors for CPP11 --- include/etl/type_def.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/etl/type_def.h b/include/etl/type_def.h index d3f3a433a..41fb6d82c 100644 --- a/include/etl/type_def.h +++ b/include/etl/type_def.h @@ -291,7 +291,7 @@ namespace etl //********************************************************************* template - ETL_CONSTEXPR + ETL_CONSTEXPR14 #if ETL_USING_CPP11 typename etl::enable_if::value, type_def&>::type #else @@ -305,7 +305,7 @@ namespace etl //********************************************************************* template - ETL_CONSTEXPR + ETL_CONSTEXPR14 #if ETL_USING_CPP11 typename etl::enable_if::value, type_def&>::type #else From b380fce5fcb7f7f0e9fba666f457d0108349d62b Mon Sep 17 00:00:00 2001 From: David Ockey <2897027+ockeydockey@users.noreply.github.com> Date: Wed, 10 Sep 2025 10:23:01 -0500 Subject: [PATCH 4/5] Changed is_arithmetic checks to use is_integral since valid shifts require integral operands --- include/etl/type_def.h | 12 ++++++------ test/test_type_def.cpp | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/etl/type_def.h b/include/etl/type_def.h index 41fb6d82c..e3c2a3314 100644 --- a/include/etl/type_def.h +++ b/include/etl/type_def.h @@ -293,7 +293,7 @@ namespace etl template ETL_CONSTEXPR14 #if ETL_USING_CPP11 - typename etl::enable_if::value, type_def&>::type + typename etl::enable_if::value, type_def&>::type #else type_def& #endif @@ -307,7 +307,7 @@ namespace etl template ETL_CONSTEXPR14 #if ETL_USING_CPP11 - typename etl::enable_if::value, type_def&>::type + typename etl::enable_if::value, type_def&>::type #else type_def& #endif @@ -606,7 +606,7 @@ namespace etl template friend ETL_CONSTEXPR #if ETL_USING_CPP11 - typename etl::enable_if::value, type_def>::type + typename etl::enable_if::value, type_def>::type #else type_def #endif @@ -619,7 +619,7 @@ namespace etl template friend ETL_CONSTEXPR #if ETL_USING_CPP11 - typename etl::enable_if::value, T>::type + typename etl::enable_if<(etl::is_integral::value && etl::is_integral::value), T>::type #else T #endif @@ -634,7 +634,7 @@ namespace etl template friend ETL_CONSTEXPR #if ETL_USING_CPP11 - typename etl::enable_if::value, type_def>::type + typename etl::enable_if::value, type_def>::type #else type_def #endif @@ -647,7 +647,7 @@ namespace etl template friend ETL_CONSTEXPR #if ETL_USING_CPP11 - typename etl::enable_if::value, T>::type + typename etl::enable_if<(etl::is_integral::value && etl::is_integral::value), T>::type #else T #endif diff --git a/test/test_type_def.cpp b/test/test_type_def.cpp index 8b2554b1b..facb2ed8f 100644 --- a/test/test_type_def.cpp +++ b/test/test_type_def.cpp @@ -232,14 +232,14 @@ namespace CHECK_EQUAL(i1 << 2, t1 << 2); CHECK_EQUAL(i1 << 2U, t1 << 2U); - CHECK_EQUAL(2 << i1, 2 << t1); - CHECK_EQUAL(2U << i1, 2U << t1); - CHECK_EQUAL(2U << i1, 2U << t1); + CHECK_EQUAL(2 << i3, 2 << t3); + CHECK_EQUAL(2U << i3, 2U << t3); CHECK_EQUAL(i1 << i3, t1 << t3); + CHECK_EQUAL(i1 >> 2, t1 >> 2); CHECK_EQUAL(i1 >> 2U, t1 >> 2U); - CHECK_EQUAL(2 >> i1, 2 >> t1); - CHECK_EQUAL(2U >> i1, 2U >> t1); + CHECK_EQUAL(42 >> i3, 42 >> t3); + CHECK_EQUAL(42U >> i3, 42U >> t3); CHECK_EQUAL(i1 >> i3, t1 >> t3); CHECK_EQUAL(i1 % uint32_t(23), t1 % uint32_t(23)); From f7a828a46f041ef0836798692db96dd203d1d5be Mon Sep 17 00:00:00 2001 From: David Ockey <2897027+ockeydockey@users.noreply.github.com> Date: Thu, 11 Sep 2025 08:42:04 -0500 Subject: [PATCH 5/5] Removed need for CPP11 since changes are CPP03 compatible --- include/etl/type_def.h | 43 +++++++----------------------------------- 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/include/etl/type_def.h b/include/etl/type_def.h index e3c2a3314..30701932e 100644 --- a/include/etl/type_def.h +++ b/include/etl/type_def.h @@ -291,13 +291,8 @@ namespace etl //********************************************************************* template - ETL_CONSTEXPR14 -#if ETL_USING_CPP11 - typename etl::enable_if::value, type_def&>::type -#else - type_def& -#endif - operator <<=(T rhs) ETL_NOEXCEPT + ETL_CONSTEXPR14 typename etl::enable_if::value, type_def&>::type + operator <<=(T rhs) ETL_NOEXCEPT { value <<= rhs; return *this; @@ -305,12 +300,7 @@ namespace etl //********************************************************************* template - ETL_CONSTEXPR14 -#if ETL_USING_CPP11 - typename etl::enable_if::value, type_def&>::type -#else - type_def& -#endif + ETL_CONSTEXPR14 typename etl::enable_if::value, type_def&>::type operator >>=(T rhs) ETL_NOEXCEPT { value >>= rhs; @@ -604,12 +594,7 @@ namespace etl // << operator //********************************************************************* template - friend ETL_CONSTEXPR -#if ETL_USING_CPP11 - typename etl::enable_if::value, type_def>::type -#else - type_def -#endif + friend ETL_CONSTEXPR typename etl::enable_if::value, type_def>::type operator <<(const type_def& lhs, T rhs) ETL_NOEXCEPT { return type_def(lhs.value << rhs); @@ -617,12 +602,7 @@ namespace etl //********************************************************************* template - friend ETL_CONSTEXPR -#if ETL_USING_CPP11 - typename etl::enable_if<(etl::is_integral::value && etl::is_integral::value), T>::type -#else - T -#endif + friend ETL_CONSTEXPR typename etl::enable_if<(etl::is_integral::value && etl::is_integral::value), T>::type operator <<(T lhs, const type_def& rhs) ETL_NOEXCEPT { return lhs << rhs.value; @@ -632,12 +612,7 @@ namespace etl // >> operator //********************************************************************* template - friend ETL_CONSTEXPR -#if ETL_USING_CPP11 - typename etl::enable_if::value, type_def>::type -#else - type_def -#endif + friend ETL_CONSTEXPR typename etl::enable_if::value, type_def>::type operator >>(const type_def& lhs, T rhs) ETL_NOEXCEPT { return type_def(lhs.value >> rhs); @@ -646,11 +621,7 @@ namespace etl //********************************************************************* template friend ETL_CONSTEXPR -#if ETL_USING_CPP11 - typename etl::enable_if<(etl::is_integral::value && etl::is_integral::value), T>::type -#else - T -#endif + typename etl::enable_if<(etl::is_integral::value && etl::is_integral::value), T>::type operator >>(T lhs, const type_def& rhs) ETL_NOEXCEPT { return lhs >> rhs.value;