lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Unit tests hygiene


From: Greg Chicares
Subject: Re: [lmi] Unit tests hygiene
Date: Mon, 13 Jun 2022 20:33:53 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.8.0

On 6/9/22 23:22, Vadim Zeitlin wrote:
> On Thu, 9 Jun 2022 21:37:00 +0000 Greg Chicares <gchicares@sbcglobal.net> 
> wrote:
> 
> GC> Here's an example that I think is UB, though UBSan doesn't flag it:
> GC> 
> GC>     // UBSAN doesn't complain about this; shouldn't it?
> GC>     auto const b {db.query<oenum_alb_or_anb>(DB_ChildRiderMinAmt)};
> GC>     LMI_TEST_EQUAL(25000, b);
> GC> 
> GC> Am I missing something, or is this truly a false negative?
> 
>  Sorry, I know I'm tired today (because I've already made a couple of bad
> mistakes in the last hour), but what exactly is the problem here, i.e. why
> should it be UB? AFAIK comparing an enum with an int is not UB, due to the
> promotion rules. Am I missing some other reason here?

Consider the throwaway patch below, which I believe demonstrates that
this isn't mere comparison of an int to an enum, but actually entails
the assignment of an out-of-enumerated-range 'int' value into an enum.

In more detail, I manually "inlined" the implementation of
  template<typename T> T product_database::query(e_database_key k) const
from 'database.hpp' as 'c' below. I believe that
  - the assignment into 'c' is just like the assignment into 'a'; and
  - the assignment into 'c' is just like the assignment into 'b';
and so by transitivity all three should be treated the same by UBSan.
But UBSan flags only 'a', not 'b' or 'c', whereas I believe that all
three constitute UB.

At any rate, the outdented last lines in the patch show that a variable
of this type:
  enum oenum_alb_or_anb
    {oe_age_last_birthday
    ,oe_age_nearest_birthday_ties_younger
    ,oe_age_nearest_birthday_ties_older
    };
with lawful values {0,1,2} has acquired the value 25000 . How can that be?
If not by way of undefined behavior, then how else?

--8<----8<----8<----8<----8<----8<----8<----8<--
diff --git a/input_test.cpp b/input_test.cpp
index 9966169b8..fc6a04f5c 100644
--- a/input_test.cpp
+++ b/input_test.cpp
@@ -172,9 +172,24 @@ void input_test::test_product_database()
     db.query_into(DB_ChildRiderMinAmt, a);
     LMI_TEST_EQUAL(25000, a);
 #endif // 0
+// If that "#endif" were moved two lines above, UBsan would complain.
     // UBSAN doesn't complain about this; shouldn't it?
     auto const b {db.query<oenum_alb_or_anb>(DB_ChildRiderMinAmt)};
     LMI_TEST_EQUAL(25000, b);
+    auto const d {db.query<double>(DB_ChildRiderMinAmt)};
+    auto const c
+        {static_cast<oenum_alb_or_anb>
+          (bourn_cast<std::underlying_type_t<oenum_alb_or_anb>>(d))
+        };
+    static_assert(std::is_enum_v<oenum_alb_or_anb>);
+    static_assert(std::is_enum_v<decltype(c)>);
+    static_assert(std::is_same_v<decltype(c),oenum_alb_or_anb const>);
+    LMI_TEST_EQUAL(25000, c);
+
+int status = 0; // next line prints "oenum_alb_or_anb"
+std::cout << abi::__cxa_demangle(typeid(c).name(), nullptr, nullptr, &status) 
<< std::endl;
+// next line prints "25000"
+std::cout << c << std::endl;
 
 #if defined LMI_CLANG
 #   pragma clang diagnostic pop
--8<----8<----8<----8<----8<----8<----8<----8<--


reply via email to

[Prev in Thread] Current Thread [Next in Thread]