diff mbox series

xen: let ASSERT_UNREACHABLE() WARN() in non-debug builds

Message ID 20220824102225.11431-1-jgross@suse.com (mailing list archive)
State New, archived
Headers show
Series xen: let ASSERT_UNREACHABLE() WARN() in non-debug builds | expand

Commit Message

Jürgen Groß Aug. 24, 2022, 10:22 a.m. UTC
Hitting an ASSERT_UNREACHABLE() is always wrong, so even in production
builds a warning seems to be appropriate when hitting one.

In order not to flood the console in reproducible cases, introduce
WARN_ONCE() to be used in this case.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
Notice for the release manager: this patch isn't really urgent for the
4.17 release, OTOH it is adding probably useful debug information for
the unlikely case of hitting an ASSERT_UNREACHABLE(). The risk for
taking the patch should be rather low, but you have the last saying,
of course.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 xen/include/xen/lib.h | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

Comments

Julien Grall Aug. 24, 2022, 10:29 a.m. UTC | #1
Hi Juergen,

Thanks for sending the patch quickly :).

On 24/08/2022 11:22, Juergen Gross wrote:
> Hitting an ASSERT_UNREACHABLE() is always wrong, so even in production
> builds a warning seems to be appropriate when hitting one.
> 
> In order not to flood the console in reproducible cases, introduce
> WARN_ONCE() to be used in this case.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>

Acked-by: Julien Grall <jgrall@amazon.com>

Cheers,
Jan Beulich Aug. 24, 2022, 10:35 a.m. UTC | #2
On 24.08.2022 12:22, Juergen Gross wrote:
> Hitting an ASSERT_UNREACHABLE() is always wrong, so even in production
> builds a warning seems to be appropriate when hitting one.

I disagree, for two reasons: This violates the implication of NDEBUG
meaning ASSERT() and friends expand to no actual code. Plus if doing so
for ASSERT_UNREACHABLE(), why would we not do the same for ASSERT()?
There's a reason we have ASSERT() and friends and, independently,
WARN_ON() / BUG_ON() et al.

Jan
Bertrand Marquis Aug. 24, 2022, 10:40 a.m. UTC | #3
Hi,

> On 24 Aug 2022, at 11:35, Jan Beulich <jbeulich@suse.com> wrote:
> 
> On 24.08.2022 12:22, Juergen Gross wrote:
>> Hitting an ASSERT_UNREACHABLE() is always wrong, so even in production
>> builds a warning seems to be appropriate when hitting one.
> 
> I disagree, for two reasons: This violates the implication of NDEBUG
> meaning ASSERT() and friends expand to no actual code. Plus if doing so
> for ASSERT_UNREACHABLE(), why would we not do the same for ASSERT()?
> There's a reason we have ASSERT() and friends and, independently,
> WARN_ON() / BUG_ON() et al.

I agree with Jan here, this is introducing code in ASSERT which is not the intention
and will end up with dead code in production mode.

In NDEBUG those should appear.

If something is needed or we think there could be a situation where this is reachable,
then the code should be modified to use something else then ASSERT[_UNREACHABLE]().

Bertrand

> 
> Jan
>
Jürgen Groß Aug. 24, 2022, 10:45 a.m. UTC | #4
On 24.08.22 12:35, Jan Beulich wrote:
> On 24.08.2022 12:22, Juergen Gross wrote:
>> Hitting an ASSERT_UNREACHABLE() is always wrong, so even in production
>> builds a warning seems to be appropriate when hitting one.
> 
> I disagree, for two reasons: This violates the implication of NDEBUG
> meaning ASSERT() and friends expand to no actual code. Plus if doing so

This is something we can change IMHO.

> for ASSERT_UNREACHABLE(), why would we not do the same for ASSERT()?

There are multiple reasons to have ASSERT()s. Some serve as a kind of
documentation (e.g. to document that the programmer thought of a special
case not being possible), or they are meant to catch hard to diagnose
bugs rather early instead of letting them hit later in a situation where
it wouldn't be clear what caused them. Adding a WARN() for all of these
cases isn't really appropriate, especially as this might impact
performance due to added tests, which isn't the case for theoretically
unreachable code.

> There's a reason we have ASSERT() and friends and, independently,
> WARN_ON() / BUG_ON() et al.

We might want to introduce something like ASSERT_OR_WARN(). I'm sure
this could be useful in some cases.


Juergen
Jan Beulich Aug. 24, 2022, 11:12 a.m. UTC | #5
On 24.08.2022 12:45, Juergen Gross wrote:
> On 24.08.22 12:35, Jan Beulich wrote:
>> On 24.08.2022 12:22, Juergen Gross wrote:
>>> Hitting an ASSERT_UNREACHABLE() is always wrong, so even in production
>>> builds a warning seems to be appropriate when hitting one.
>>
>> I disagree, for two reasons: This violates the implication of NDEBUG
>> meaning ASSERT() and friends expand to no actual code. Plus if doing so
> 
> This is something we can change IMHO.
> 
>> for ASSERT_UNREACHABLE(), why would we not do the same for ASSERT()?
> 
> There are multiple reasons to have ASSERT()s. Some serve as a kind of
> documentation (e.g. to document that the programmer thought of a special
> case not being possible), or they are meant to catch hard to diagnose
> bugs rather early instead of letting them hit later in a situation where
> it wouldn't be clear what caused them. Adding a WARN() for all of these
> cases isn't really appropriate, especially as this might impact
> performance due to added tests, which isn't the case for theoretically
> unreachable code.
> 
>> There's a reason we have ASSERT() and friends and, independently,
>> WARN_ON() / BUG_ON() et al.
> 
> We might want to introduce something like ASSERT_OR_WARN(). I'm sure
> this could be useful in some cases.

I'm curious why in such cases it can't just be WARN_ON().

Jan
Andrew Cooper Aug. 24, 2022, 11:19 a.m. UTC | #6
On 24/08/2022 11:35, Jan Beulich wrote:
> On 24.08.2022 12:22, Juergen Gross wrote:
>> Hitting an ASSERT_UNREACHABLE() is always wrong, so even in production
>> builds a warning seems to be appropriate when hitting one.
> I disagree, for two reasons: This violates the implication of NDEBUG
> meaning ASSERT() and friends expand to no actual code.

I agree.  ASSERT() and friends should no code in !DEBUG builds.

Furthermore, if an ASSERT_UNREACHALBE() is proving to be problematic
even at runtime, then it's not the correct construct in the first place.

~Andrew
Jürgen Groß Aug. 24, 2022, 11:28 a.m. UTC | #7
On 24.08.22 13:12, Jan Beulich wrote:
> On 24.08.2022 12:45, Juergen Gross wrote:
>> On 24.08.22 12:35, Jan Beulich wrote:
>>> On 24.08.2022 12:22, Juergen Gross wrote:
>>>> Hitting an ASSERT_UNREACHABLE() is always wrong, so even in production
>>>> builds a warning seems to be appropriate when hitting one.
>>>
>>> I disagree, for two reasons: This violates the implication of NDEBUG
>>> meaning ASSERT() and friends expand to no actual code. Plus if doing so
>>
>> This is something we can change IMHO.
>>
>>> for ASSERT_UNREACHABLE(), why would we not do the same for ASSERT()?
>>
>> There are multiple reasons to have ASSERT()s. Some serve as a kind of
>> documentation (e.g. to document that the programmer thought of a special
>> case not being possible), or they are meant to catch hard to diagnose
>> bugs rather early instead of letting them hit later in a situation where
>> it wouldn't be clear what caused them. Adding a WARN() for all of these
>> cases isn't really appropriate, especially as this might impact
>> performance due to added tests, which isn't the case for theoretically
>> unreachable code.
>>
>>> There's a reason we have ASSERT() and friends and, independently,
>>> WARN_ON() / BUG_ON() et al.
>>
>> We might want to introduce something like ASSERT_OR_WARN(). I'm sure
>> this could be useful in some cases.
> 
> I'm curious why in such cases it can't just be WARN_ON().

It won't result in test failure of debug builds.

In the end I'm not feeling really strong here, so I'm fine to drop this
patch.


Juergen
diff mbox series

Patch

diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h
index 05ee1e18af..b8472d753c 100644
--- a/xen/include/xen/lib.h
+++ b/xen/include/xen/lib.h
@@ -40,6 +40,16 @@ 
     unlikely(ret_warn_on_);             \
 })
 
+#define WARN_ONCE() do {                \
+    static bool warned = false;         \
+                                        \
+    if ( !warned )                      \
+    {                                   \
+        warned = true;                  \
+        WARN();                         \
+    }                                   \
+} while (0)
+
 /* All clang versions supported by Xen have _Static_assert. */
 #if defined(__clang__) || \
     (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
@@ -63,7 +73,7 @@ 
 #define ASSERT_UNREACHABLE() assert_failed("unreachable")
 #else
 #define ASSERT(p) do { if ( 0 && (p) ) {} } while (0)
-#define ASSERT_UNREACHABLE() do { } while (0)
+#define ASSERT_UNREACHABLE() WARN_ONCE()
 #endif
 
 #define ABS(_x) ({                              \