@@ -235,8 +235,43 @@ void LLVMResetFatalErrorHandler() {
235
235
236
236
#ifdef _WIN32
237
237
238
+ #define WIN32_NO_STATUS
239
+ #include " llvm/Support/Windows/WindowsSupport.h"
240
+ #undef WIN32_NO_STATUS
241
+ #include < ntstatus.h>
238
242
#include < winerror.h>
239
243
244
+ // This is equivalent to NtCurrentTeb()->LastStatusValue, but the public
245
+ // _TEB definition does not expose the LastStatusValue field directly.
246
+ // Avoid offsetting into this structure by calling RtlGetLastNtStatus
247
+ // from ntdll.dll.
248
+ //
249
+ // The return of this function will roughly match that of
250
+ // GetLastError, but this lower level API disambiguates some cases
251
+ // that GetLastError does not.
252
+ //
253
+ // For more information, see:
254
+ // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
255
+ // https://github.com/llvm/llvm-project/issues/89137
256
+ extern " C" NTSYSAPI NTSTATUS NTAPI RtlGetLastNtStatus ();
257
+
258
+ // This function obtains the last error code and maps it. It may call
259
+ // RtlGetLastNtStatus, which is a lower level API that can return a
260
+ // more specific error code than GetLastError.
261
+ std::error_code llvm::mapLastWindowsError () {
262
+ unsigned EV = ::GetLastError ();
263
+ // The mapping of NTSTATUS to Win32 error loses some information; special
264
+ // case the generic ERROR_ACCESS_DENIED code to check the underlying
265
+ // NTSTATUS and potentially return a more accurate error code.
266
+ if (EV == ERROR_ACCESS_DENIED) {
267
+ llvm::errc code = RtlGetLastNtStatus () == STATUS_DELETE_PENDING
268
+ ? errc::delete_pending
269
+ : errc::permission_denied;
270
+ return make_error_code (code);
271
+ }
272
+ return mapWindowsError (EV);
273
+ }
274
+
240
275
// I'd rather not double the line count of the following.
241
276
#define MAP_ERR_TO_COND (x, y ) \
242
277
case x: \
0 commit comments