LLVM: lib/Support/CrashRecoveryContext.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

10#include "llvm/Config/llvm-config.h"

15#include

16#include

17#include <setjmp.h>

18

19using namespace llvm;

20

21namespace {

22

23struct CrashRecoveryContextImpl;

24static LLVM_THREAD_LOCAL const CrashRecoveryContextImpl *CurrentContext;

25

26struct CrashRecoveryContextImpl {

27

28

29

30

31 const CrashRecoveryContextImpl *Next;

32

33 CrashRecoveryContext *CRC;

34 ::jmp_buf JumpBuffer;

35 volatile unsigned Failed : 1;

36 unsigned SwitchedThread : 1;

37 unsigned ValidJumpBuffer : 1;

38

39public:

40 CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept

41 : CRC(CRC), Failed(false), SwitchedThread(false), ValidJumpBuffer(false) {

42 Next = CurrentContext;

43 CurrentContext = this;

44 }

45 ~CrashRecoveryContextImpl() {

46 if (!SwitchedThread)

47 CurrentContext = Next;

48 }

49

50

51

52 void setSwitchedThread() {

53#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0

54 SwitchedThread = true;

55#endif

56 }

57

58

59

60

61

62 void HandleCrash(int RetCode, uintptr_t Context) {

63

64

65 CurrentContext = Next;

66

67 assert(!Failed && "Crash recovery context already failed!");

68 Failed = true;

69

70 if (CRC->DumpStackAndCleanupOnFailure)

72

73 CRC->RetCode = RetCode;

74

75

76 if (ValidJumpBuffer)

77 longjmp(JumpBuffer, 1);

78

79

80

81 }

82};

83

84std::mutex &getCrashRecoveryContextMutex() {

85 static std::mutex CrashRecoveryContextMutex;

86 return CrashRecoveryContextMutex;

87}

88

89static bool gCrashRecoveryEnabled = false;

90

92

93}

94

97

99

106

108

111 IsRecoveringFromCrash = this;

112 while (i) {

114 i = tmp->next;

117 delete tmp;

118 }

119 IsRecoveringFromCrash = PC;

120

121 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;

122 delete CRCI;

123}

124

126 return IsRecoveringFromCrash != nullptr;

127}

128

130 if (!gCrashRecoveryEnabled)

131 return nullptr;

132

133 const CrashRecoveryContextImpl *CRCI = CurrentContext;

134 if (!CRCI)

135 return nullptr;

136

137 return CRCI->CRC;

138}

139

141 std::lock_guardstd::mutex L(getCrashRecoveryContextMutex());

142

143 if (gCrashRecoveryEnabled)

144 return;

145 gCrashRecoveryEnabled = true;

147}

148

150 std::lock_guardstd::mutex L(getCrashRecoveryContextMutex());

151 if (!gCrashRecoveryEnabled)

152 return;

153 gCrashRecoveryEnabled = false;

155}

156

158{

160 return;

161 if (head)

165}

166

167void

170 return;

173 if (head)

174 head->prev = nullptr;

175 }

176 else {

180 }

182}

183

184#if defined(_MSC_VER)

185

186#include <windows.h>

187

188

189

190

191

192

193

194

195

198

199

200

201static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {

202

203 const CrashRecoveryContextImpl *CRCI = CurrentContext;

204

205 if (!CRCI) {

206

207

209 return EXCEPTION_CONTINUE_SEARCH;

210 }

211

212 int RetCode = (int)Except->ExceptionRecord->ExceptionCode;

213 if ((RetCode & 0xF0000000) == 0xE0000000)

214 RetCode &= ~0xF0000000;

215

216

217 const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(

218 RetCode, reinterpret_cast<uintptr_t>(Except));

219

220 return EXCEPTION_EXECUTE_HANDLER;

221}

222

223#if defined(__clang__) && defined(_M_IX86)

224

225__attribute__((optnone))

226#endif

228 if (!gCrashRecoveryEnabled) {

229 Fn();

230 return true;

231 }

232 assert(!Impl && "Crash recovery context already initialized!");

233 Impl = new CrashRecoveryContextImpl(this);

234 __try {

235 Fn();

236 } __except (ExceptionFilter(GetExceptionInformation())) {

237 return false;

238 }

239 return true;

240}

241

242#else

243

244#if defined(_WIN32)

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

265

266static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)

267{

268

269

270 constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL;

271 switch (ExceptionInfo->ExceptionRecord->ExceptionCode)

272 {

273 case DBG_PRINTEXCEPTION_C:

274 case DbgPrintExceptionWideC:

275 case 0x406D1388:

276 return EXCEPTION_CONTINUE_EXECUTION;

277 }

278

279

280 const CrashRecoveryContextImpl *CRCI = CurrentContext;

281

282 if (!CRCI) {

283

284

286 return EXCEPTION_CONTINUE_SEARCH;

287 }

288

289

290

291

292 int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode;

293 if ((RetCode & 0xF0000000) == 0xE0000000)

294 RetCode &= ~0xF0000000;

295

296

297 const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(

298 RetCode, reinterpret_cast<uintptr_t>(ExceptionInfo));

299

300

301

302 llvm_unreachable("Handled the crash, should have longjmp'ed out of here");

303}

304

305

306

307

308

309

311

313

314

315

316

317 PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler);

318 sCurrentExceptionHandle = handle;

319}

320

322 PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle);

323 if (currentHandle) {

324

325 ::RemoveVectoredExceptionHandler(currentHandle);

326

327

328 sCurrentExceptionHandle = NULL;

329 }

330}

331

332#else

333

334

335

336

337

338

339

340

341

342

343

344

345#include <signal.h>

346

348 { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP };

351

353

354 const CrashRecoveryContextImpl *CRCI = CurrentContext;

355

356 if (!CRCI) {

357

358

359

360

361

362

363

364

365

366

368 raise(Signal);

369

370

371 return;

372 }

373

374

375 sigset_t SigMask;

376 sigemptyset(&SigMask);

377 sigaddset(&SigMask, Signal);

378 sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);

379

380

381

382

383 int RetCode = 128 + Signal;

384

385

386 if (Signal == SIGPIPE)

387 RetCode = EX_IOERR;

388

389 if (CRCI)

390 const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(RetCode, Signal);

391}

392

394

395 struct sigaction Handler;

397 Handler.sa_flags = 0;

398 sigemptyset(&Handler.sa_mask);

399

400 for (unsigned i = 0; i != NumSignals; ++i) {

402 }

403}

404

406

407 for (unsigned i = 0; i != NumSignals; ++i)

409}

410

411#endif

412

414

415 if (gCrashRecoveryEnabled) {

416 assert(!Impl && "Crash recovery context already initialized!");

417 CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this);

418 Impl = CRCI;

419

420 CRCI->ValidJumpBuffer = true;

421 if (setjmp(CRCI->JumpBuffer) != 0) {

422 return false;

423 }

424 }

425

426 Fn();

427 return true;

428}

429

430#endif

431

433#if defined(_WIN32)

434

435

436

437

438 ::RaiseException(0xE0000000 | RetCode, 0, 0, NULL);

439#else

440

441

442 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl;

443 assert(CRCI && "Crash recovery context never initialized!");

444 CRCI->HandleCrash(RetCode, 0 );

445#endif

447}

448

450#if defined(_WIN32)

451

452

453

454

456 if (Code != 0xC && Code != 8)

457 return false;

458#else

459

460

462 return false;

463#endif

464 return true;

465}

466

469 return false;

470#if defined(_WIN32)

471 ::RaiseException(RetCode, 0, 0, NULL);

472#else

475#endif

476 return true;

477}

478

479

481#ifdef __APPLE__

482 setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);

483#endif

484}

485

487#ifdef __APPLE__

488 return getpriority(PRIO_DARWIN_THREAD, 0) == 1;

489#else

490 return false;

491#endif

492}

493

494namespace {

495struct RunSafelyOnThreadInfo {

496 function_ref<void()> Fn;

497 CrashRecoveryContext *CRC;

498 bool UseBackgroundPriority;

500};

501}

502

504 RunSafelyOnThreadInfo *Info =

505 reinterpret_cast<RunSafelyOnThreadInfo*>(UserData);

506

507 if (Info->UseBackgroundPriority)

509

510 Info->Result = Info->CRC->RunSafely(Info->Fn);

511}

513 unsigned RequestedStackSize) {

515 RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false };

517 ? std::nullopt

518 : std::optional(RequestedStackSize),

520 Thread.join();

521

522 if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)

523 CRC->setSwitchedThread();

524 return Info.Result;

525}

526

528 unsigned RequestedStackSize) {

529#ifdef LLVM_HAS_SPLIT_STACKS

532#else

534#endif

535}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

static void cleanup(BlockFrequencyInfoImplBase &BFI)

Clear all memory not needed downstream.

Analysis containing CSE Info

#define LLVM_THREAD_LOCAL

\macro LLVM_THREAD_LOCAL A thread-local storage specifier which can be used with globals,...

static bool hasThreadBackgroundPriority()

Definition CrashRecoveryContext.cpp:486

static const unsigned NumSignals

Definition CrashRecoveryContext.cpp:349

static const int Signals[]

Definition CrashRecoveryContext.cpp:347

static void CrashRecoverySignalHandler(int Signal)

Definition CrashRecoveryContext.cpp:352

static void RunSafelyOnThread_Dispatch(void *UserData)

Definition CrashRecoveryContext.cpp:503

static void setThreadBackgroundPriority()

Definition CrashRecoveryContext.cpp:480

static void uninstallExceptionOrSignalHandlers()

Definition CrashRecoveryContext.cpp:405

static struct sigaction PrevActions[NumSignals]

Definition CrashRecoveryContext.cpp:350

static void installExceptionOrSignalHandlers()

Definition CrashRecoveryContext.cpp:393

This file contains definitions of exit codes for exit() function.

Abstract base class of cleanup handlers.

virtual ~CrashRecoveryContextCleanup()

virtual void recoverResources()=0

Crash recovery helper object.

static LLVM_ABI bool isCrash(int RetCode)

Return true if RetCode indicates that a signal or an exception occurred.

Definition CrashRecoveryContext.cpp:449

static LLVM_ABI CrashRecoveryContext * GetCurrent()

Return the active context, if the code is currently executing in a thread which is in a protected con...

Definition CrashRecoveryContext.cpp:129

LLVM_ABI void HandleExit(int RetCode)

Explicitly trigger a crash recovery in the current process, and return failure from RunSafely().

Definition CrashRecoveryContext.cpp:432

LLVM_ABI ~CrashRecoveryContext()

Definition CrashRecoveryContext.cpp:107

static LLVM_ABI void Enable()

Enable crash recovery.

Definition CrashRecoveryContext.cpp:140

LLVM_ABI bool RunSafelyOnNewStack(function_ref< void()>, unsigned RequestedStackSize=0)

Definition CrashRecoveryContext.cpp:527

LLVM_ABI void unregisterCleanup(CrashRecoveryContextCleanup *cleanup)

Definition CrashRecoveryContext.cpp:168

LLVM_ABI bool RunSafely(function_ref< void()> Fn)

Execute the provided callback function (with the given arguments) in a protected context.

Definition CrashRecoveryContext.cpp:413

static LLVM_ABI void Disable()

Disable crash recovery.

Definition CrashRecoveryContext.cpp:149

int RetCode

In case of a crash, this is the crash identifier.

static LLVM_ABI bool isRecoveringFromCrash()

Return true if the current thread is recovering from a crash.

Definition CrashRecoveryContext.cpp:125

static LLVM_ABI bool throwIfCrash(int RetCode)

Throw again a signal or an exception, after it was catched once by a CrashRecoveryContext.

Definition CrashRecoveryContext.cpp:467

LLVM_ABI void registerCleanup(CrashRecoveryContextCleanup *cleanup)

Register cleanup handler, which is used when the recovery context is finished.

Definition CrashRecoveryContext.cpp:157

LLVM_ABI CrashRecoveryContext()

Definition CrashRecoveryContext.cpp:100

LLVM_ABI bool RunSafelyOnThread(function_ref< void()>, unsigned RequestedStackSize=0)

Execute the provide callback function (with the given arguments) in a protected context which is run ...

Definition CrashRecoveryContext.cpp:512

An efficient, type-erasing, non-owning reference to a callable.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

IRHandle handle(const Type *Ty)

LLVM_ABI void DisableSystemDialogsOnCrash()

Disable all system dialog boxes that appear when the process crashes.

LLVM_ABI void unregisterHandlers()

LLVM_ABI void CleanupOnSignal(uintptr_t Context)

This function does the following:

This is an optimization pass for GlobalISel generic memory operations.

LLVM_ABI void runOnNewStack(unsigned StackSize, function_ref< void()> Fn)

Runs Fn on a new stack of at least the given size.

testing::Matcher< const detail::ErrorHolder & > Failed()