Bläddra i källkod

Add dxc exception handler (#3604)

The most common cause of internal compiler errors are access violations
or stack overflows. This registers an exception handler in dxc.exe for
these cases that are otherwise unhandled. It prints a simple message
for these errors and passes the exception along.

In case this is unwanted for some reason, a hidden disabling flag is
added as well.

Adds LLVM builtin exceptions for assert, fatal, and unreachable. Adds a
default message for exceptions not explicitly addressed.

Alters behavior of llvm_unreachable so it always raises an exception
regardless of compiler support for unreachable hints.

Reports errors using fputs instead of std::cerr to ensure that no
allocation is necessary. Custom output is performed in a static array
that is output with fputs.
Greg Roth 4 år sedan
förälder
incheckning
9b475a7fa3

+ 1 - 0
include/dxc/Support/HLSLOptions.h

@@ -202,6 +202,7 @@ public:
 
 
   bool PrintAfterAll; // OPT_print_after_all
   bool PrintAfterAll; // OPT_print_after_all
   bool EnablePayloadQualifiers = false; // OPT_enable_payload_qualifiers
   bool EnablePayloadQualifiers = false; // OPT_enable_payload_qualifiers
+  bool HandleExceptions = false; // OPT_disable_exception_handling
 
 
   // Rewriter Options
   // Rewriter Options
   RewriterOpts RWOpt;
   RewriterOpts RWOpt;

+ 2 - 0
include/dxc/Support/HLSLOptions.td

@@ -281,6 +281,8 @@ def enable_payload_qualifiers : Flag<["-", "/"], "enable-payload-qualifiers">, G
   HelpText<"Enables support for payload access qualifiers for raytracing payloads in SM 6.6.">;
   HelpText<"Enables support for payload access qualifiers for raytracing payloads in SM 6.6.">;
 def disable_payload_qualifiers : Flag<["-", "/"], "disable-payload-qualifiers">, Group<hlslcomp_Group>, Flags<[CoreOption, RewriteOption, DriverOption]>,
 def disable_payload_qualifiers : Flag<["-", "/"], "disable-payload-qualifiers">, Group<hlslcomp_Group>, Flags<[CoreOption, RewriteOption, DriverOption]>,
   HelpText<"Disables support for payload access qualifiers for raytracing payloads in SM 6.7.">;
   HelpText<"Disables support for payload access qualifiers for raytracing payloads in SM 6.7.">;
+def disable_exception_handling : Flag<["-", "/"], "disable-exception-handling">, Group<hlslcomp_Group>, Flags<[DriverOption, HelpHidden]>,
+  HelpText<"Disable dxc handling of exceptions">;
 
 
 // Used with API only
 // Used with API only
 def skip_serialization : Flag<["-", "/"], "skip-serialization">, Group<hlslcore_Group>, Flags<[CoreOption, HelpHidden]>,
 def skip_serialization : Flag<["-", "/"], "skip-serialization">, Group<hlslcore_Group>, Flags<[CoreOption, HelpHidden]>,

+ 2 - 2
include/llvm/Support/ErrorHandling.h

@@ -97,8 +97,8 @@ namespace llvm {
 #ifndef NDEBUG
 #ifndef NDEBUG
 #define llvm_unreachable(msg) \
 #define llvm_unreachable(msg) \
   ::llvm::llvm_unreachable_internal(msg, __FILE__, __LINE__)
   ::llvm::llvm_unreachable_internal(msg, __FILE__, __LINE__)
-#elif defined(LLVM_BUILTIN_UNREACHABLE)
-#define llvm_unreachable(msg) LLVM_BUILTIN_UNREACHABLE
+//#elif defined(LLVM_BUILTIN_UNREACHABLE) // HLSL Change - always throw exception for unreachable
+//#define llvm_unreachable(msg) LLVM_BUILTIN_UNREACHABLE
 #else
 #else
 #define llvm_unreachable(msg) ::llvm::llvm_unreachable_internal()
 #define llvm_unreachable(msg) ::llvm::llvm_unreachable_internal()
 #endif
 #endif

+ 2 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -664,6 +664,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
     return 1;
     return 1;
   }
   }
 
 
+  opts.HandleExceptions = !Args.hasFlag(OPT_disable_exception_handling, OPT_INVALID, false);
+
   if (opts.DefaultColMajor && opts.DefaultRowMajor) {
   if (opts.DefaultColMajor && opts.DefaultRowMajor) {
     errors << "Cannot specify /Zpr and /Zpc together, use /? to get usage information";
     errors << "Cannot specify /Zpr and /Zpc together, use /? to get usage information";
     return 1;
     return 1;

+ 59 - 0
tools/clang/tools/dxclib/dxc.cpp

@@ -1216,6 +1216,59 @@ void DxcContext::GetCompilerVersionInfo(llvm::raw_string_ostream &OS) {
 #define VERSION_STRING_SUFFIX ""
 #define VERSION_STRING_SUFFIX ""
 #endif
 #endif
 
 
+#ifdef _WIN32
+// Unhandled exception filter called when an unhandled exception occurs
+// to at least print an generic error message instead of crashing silently.
+// passes exception along to allow crash dumps to be generated
+static LONG CALLBACK ExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
+{
+  static char scratch[32];
+
+  fputs("Internal compiler error: " , stderr);
+
+  if (!pExceptionInfo || !pExceptionInfo->ExceptionRecord) {
+    // No information at all, it's not much, but it's the best we can do
+    fputs("Unknown", stderr);
+    return EXCEPTION_CONTINUE_SEARCH;
+  }
+
+  switch(pExceptionInfo->ExceptionRecord->ExceptionCode) {
+    // native exceptions
+  case EXCEPTION_ACCESS_VIOLATION: {
+    fputs("access violation. Attempted to ", stderr);
+    if (pExceptionInfo->ExceptionRecord->ExceptionInformation[0])
+      fputs("write", stderr);
+    else
+      fputs("read", stderr);
+    fputs(" from address ", stderr);
+    sprintf_s(scratch, _countof(scratch), "0x%016llx\n", pExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
+    fputs(scratch, stderr);
+  } break;
+  case EXCEPTION_STACK_OVERFLOW:
+    fputs("stack overflow\n", stderr);
+    break;
+    // LLVM exceptions
+  case STATUS_LLVM_ASSERT:
+    fputs("LLVM Assert\n", stderr);
+    break;
+  case STATUS_LLVM_UNREACHABLE:
+    fputs("LLVM Unreachable\n", stderr);
+    break;
+  case STATUS_LLVM_FATAL:
+    fputs("LLVM Fatal Error\n", stderr);
+    break;
+  default:
+    fputs("Error ", stderr);
+    sprintf_s(scratch, _countof(scratch), "0x%08x\n", pExceptionInfo->ExceptionRecord->ExceptionCode);
+    fputs(scratch, stderr);
+  }
+
+  // Continue search to pass along the exception
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+#endif
+
+
 #ifdef _WIN32
 #ifdef _WIN32
 int dxc::main(int argc, const wchar_t **argv_) {
 int dxc::main(int argc, const wchar_t **argv_) {
 #else
 #else
@@ -1255,6 +1308,12 @@ int dxc::main(int argc, const char **argv_) {
       dxcOpts.EntryPoint = "main";
       dxcOpts.EntryPoint = "main";
     }
     }
 
 
+#ifdef _WIN32
+    // Set exception handler if enabled
+    if (dxcOpts.HandleExceptions)
+      SetUnhandledExceptionFilter(ExceptionFilter);
+#endif
+
     // Setup a helper DLL.
     // Setup a helper DLL.
     {
     {
       std::string dllErrorString;
       std::string dllErrorString;