]> granicus.if.org Git - graphviz/commitdiff
avoid use of '__builtin_unreachable' in 'UNREACHABLE' macro
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Thu, 10 Mar 2022 02:57:17 +0000 (18:57 -0800)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Sat, 12 Mar 2022 23:48:46 +0000 (15:48 -0800)
There was some discussion on !2503¹ around the effect of `__builtin_unreachable`
and whether we are really confident applying such a strong compiler hint to
complex control flow logic that is, in some cases, only partially understood.
This change softens the effect of the `UNREACHABLE` macro to a reliable program
abort rather than undefined behavior if mistakenly tagged unreachable code is
reached. The result is slightly less efficient but safer code.

¹ https://gitlab.com/graphviz/graphviz/-/merge_requests/2503#note_866261546

lib/cgraph/unreachable.h

index f3d69b730281739cf8a2c99f81ba48e9c80f41eb..919d71534cfa946ebc185d941965fa12c82b7786 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <assert.h>
+#include <stdio.h>
 #include <stdlib.h>
 
 /** Marker for a point in code which execution can never reach.
@@ -9,9 +10,7 @@
  *
  *   _Noreturn void UNREACHABLE(void);
  *
- * Calling this teaches the compiler that the call site can never be executed,
- * and it can optimize with this assumption in mind. This can be used to explain
- * that a switch is exhaustive:
+ * This can be used to explain that a switch is exhaustive:
  *
  *   switch (…) {
  *   default: UNREACHABLE();
  *     UNREACHABLE();
  *   }
  */
-#ifdef __GNUC__
 #define UNREACHABLE()                                                          \
   do {                                                                         \
-    assert(0 && "unreachable");                                                \
-    __builtin_unreachable();                                                   \
-  } while (0)
-#elif defined(_MSC_VER)
-#define UNREACHABLE()                                                          \
-  do {                                                                         \
-    assert(0 && "unreachable");                                                \
-    __assume(0);                                                               \
-  } while (0)
-#else
-#define UNREACHABLE()                                                          \
-  do {                                                                         \
-    assert(0 && "unreachable");                                                \
+    fprintf(stderr, "%s:%d: claimed unreachable code was reached", __FILE__,   \
+            __LINE__);                                                         \
     abort();                                                                   \
   } while (0)
-#endif