Exceptions.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. //---------------------------------------------------------------------------
  2. #include <CorePCH.h>
  3. #pragma hdrstop
  4. #include "Exceptions.h"
  5. #include "Configuration.h"
  6. //---------------------------------------------------------------------------
  7. static std::unique_ptr<TCriticalSection> IgnoredExceptionsCriticalSection(TraceInitPtr(new TCriticalSection()));
  8. typedef std::set<UnicodeString> TIgnoredExceptions;
  9. static TIgnoredExceptions IgnoredExceptions;
  10. //---------------------------------------------------------------------------
  11. static UnicodeString __fastcall NormalizeClassName(const UnicodeString & ClassName)
  12. {
  13. return ReplaceStr(ClassName, L".", L"::").LowerCase();
  14. }
  15. //---------------------------------------------------------------------------
  16. void __fastcall IgnoreException(const std::type_info & ExceptionType)
  17. {
  18. TGuard Guard(IgnoredExceptionsCriticalSection.get());
  19. // We should better use type_index as a key, instead of a class name,
  20. // but type_index is not available in 32-bit version of STL in XE6.
  21. IgnoredExceptions.insert(NormalizeClassName(UnicodeString(AnsiString(ExceptionType.name()))));
  22. }
  23. //---------------------------------------------------------------------------
  24. static bool __fastcall WellKnownException(
  25. Exception * E, UnicodeString * AMessage, const wchar_t ** ACounterName, Exception ** AClone, bool Rethrow)
  26. {
  27. UnicodeString Message;
  28. const wchar_t * CounterName = NULL; // shut up
  29. std::unique_ptr<Exception> Clone;
  30. bool Result = true;
  31. bool IgnoreException = false;
  32. if (!IgnoredExceptions.empty())
  33. {
  34. TGuard Guard(IgnoredExceptionsCriticalSection.get());
  35. UnicodeString ClassName = NormalizeClassName(E->QualifiedClassName());
  36. IgnoreException = (IgnoredExceptions.find(ClassName) != IgnoredExceptions.end());
  37. }
  38. if (IgnoreException)
  39. {
  40. Result = false;
  41. }
  42. // EAccessViolation is EExternal
  43. else if (dynamic_cast<EAccessViolation*>(E) != NULL)
  44. {
  45. if (Rethrow)
  46. {
  47. throw EAccessViolation(E->Message);
  48. }
  49. UnicodeString S = E->Message;
  50. UnicodeString Dummy;
  51. if (!ExtractMainInstructions(S, Dummy))
  52. {
  53. S = UnicodeString();
  54. }
  55. Message = MainInstructions(LoadStr(ACCESS_VIOLATION_ERROR3)) + S;
  56. CounterName = L"AccessViolations";
  57. Clone.reset(new EAccessViolation(E->Message));
  58. }
  59. // EIntError and EMathError are EExternal
  60. // EClassNotFound is EFilerError
  61. else if ((dynamic_cast<EListError*>(E) != NULL) ||
  62. (dynamic_cast<EStringListError*>(E) != NULL) ||
  63. (dynamic_cast<EIntError*>(E) != NULL) ||
  64. (dynamic_cast<EMathError*>(E) != NULL) ||
  65. (dynamic_cast<EVariantError*>(E) != NULL) ||
  66. (dynamic_cast<EInvalidOperation*>(E) != NULL) ||
  67. (dynamic_cast<EFilerError*>(E) != NULL))
  68. {
  69. if (Rethrow)
  70. {
  71. throw EIntError(E->Message);
  72. }
  73. Message = MainInstructions(E->Message);
  74. CounterName = L"InternalExceptions";
  75. Clone.reset(new EIntError(E->Message));
  76. }
  77. else if (dynamic_cast<EExternal*>(E) != NULL)
  78. {
  79. if (Rethrow)
  80. {
  81. throw EExternal(E->Message);
  82. }
  83. Message = MainInstructions(E->Message);
  84. CounterName = L"ExternalExceptions";
  85. Clone.reset(new EExternal(E->Message));
  86. }
  87. else if (dynamic_cast<EHeapException*>(E) != NULL)
  88. {
  89. if (Rethrow)
  90. {
  91. throw EHeapException(E->Message);
  92. }
  93. Message = MainInstructions(E->Message);
  94. CounterName = L"HeapExceptions";
  95. Clone.reset(new EHeapException(E->Message));
  96. }
  97. else
  98. {
  99. Result = false;
  100. }
  101. if (Result)
  102. {
  103. if (AMessage != NULL)
  104. {
  105. (*AMessage) = Message;
  106. }
  107. if (ACounterName != NULL)
  108. {
  109. (*ACounterName) = CounterName;
  110. }
  111. if (AClone != NULL)
  112. {
  113. (*AClone) = DebugNotNull(Clone.release());
  114. }
  115. }
  116. return Result;
  117. }
  118. //---------------------------------------------------------------------------
  119. static bool __fastcall ExceptionMessage(Exception * E, bool Count,
  120. bool Formatted, UnicodeString & Message, bool & InternalError)
  121. {
  122. bool Result = true;
  123. const wchar_t * CounterName = NULL;
  124. InternalError = false; // see also IsInternalException
  125. // this list has to be in sync with CloneException
  126. if (dynamic_cast<EAbort *>(E) != NULL)
  127. {
  128. Result = false;
  129. }
  130. else if (WellKnownException(E, &Message, &CounterName, NULL, false))
  131. {
  132. InternalError = true;
  133. }
  134. else if (E->Message.IsEmpty())
  135. {
  136. Result = false;
  137. }
  138. else
  139. {
  140. Message = E->Message;
  141. }
  142. if (!Formatted)
  143. {
  144. Message = UnformatMessage(Message);
  145. }
  146. if (InternalError)
  147. {
  148. Message = FMTLOAD(REPORT_ERROR, (Message));
  149. }
  150. if (Count && (CounterName != NULL) && (Configuration->Usage != NULL))
  151. {
  152. Configuration->Usage->Inc(CounterName);
  153. UnicodeString ExceptionDebugInfo =
  154. E->ClassName() + L":" + GetExceptionDebugInfo();
  155. Configuration->Usage->Set(LastInternalExceptionCounter, ExceptionDebugInfo);
  156. }
  157. return Result;
  158. }
  159. //---------------------------------------------------------------------------
  160. bool __fastcall IsInternalException(Exception * E)
  161. {
  162. // see also InternalError in ExceptionMessage
  163. return WellKnownException(E, NULL, NULL, NULL, false);
  164. }
  165. //---------------------------------------------------------------------------
  166. bool __fastcall ExceptionMessage(Exception * E, UnicodeString & Message)
  167. {
  168. bool InternalError;
  169. return ExceptionMessage(E, true, false, Message, InternalError);
  170. }
  171. //---------------------------------------------------------------------------
  172. bool __fastcall ExceptionMessageFormatted(Exception * E, UnicodeString & Message)
  173. {
  174. bool InternalError;
  175. return ExceptionMessage(E, true, true, Message, InternalError);
  176. }
  177. //---------------------------------------------------------------------------
  178. bool __fastcall ShouldDisplayException(Exception * E)
  179. {
  180. UnicodeString Message;
  181. return ExceptionMessageFormatted(E, Message);
  182. }
  183. //---------------------------------------------------------------------------
  184. TStrings * __fastcall ExceptionToMoreMessages(Exception * E)
  185. {
  186. TStrings * Result = NULL;
  187. UnicodeString Message;
  188. if (ExceptionMessage(E, Message))
  189. {
  190. Result = new TStringList();
  191. Result->Add(Message);
  192. ExtException * ExtE = dynamic_cast<ExtException *>(E);
  193. if ((ExtE != NULL) && (ExtE->MoreMessages != NULL))
  194. {
  195. Result->AddStrings(ExtE->MoreMessages);
  196. }
  197. }
  198. return Result;
  199. }
  200. //---------------------------------------------------------------------------
  201. bool __fastcall ExceptionFullMessage(Exception * E, UnicodeString & Message)
  202. {
  203. bool Result = ExceptionMessage(E, Message);
  204. if (Result)
  205. {
  206. Message += L"\n";
  207. ExtException * EE = dynamic_cast<ExtException *>(E);
  208. if ((EE != NULL) && (EE->MoreMessages != NULL))
  209. {
  210. Message += EE->MoreMessages->Text + L"\n";
  211. }
  212. }
  213. return Result;
  214. }
  215. //---------------------------------------------------------------------------
  216. UnicodeString __fastcall GetExceptionHelpKeyword(Exception * E)
  217. {
  218. UnicodeString HelpKeyword;
  219. ExtException * ExtE = dynamic_cast<ExtException *>(E);
  220. UnicodeString Message; // not used
  221. bool InternalError = false;
  222. if (ExtE != NULL)
  223. {
  224. HelpKeyword = ExtE->HelpKeyword;
  225. }
  226. else if ((E != NULL) && ExceptionMessage(E, false, false, Message, InternalError) &&
  227. InternalError)
  228. {
  229. HelpKeyword = HELP_INTERNAL_ERROR;
  230. }
  231. return HelpKeyword;
  232. }
  233. //---------------------------------------------------------------------------
  234. UnicodeString __fastcall MergeHelpKeyword(const UnicodeString & PrimaryHelpKeyword, const UnicodeString & SecondaryHelpKeyword)
  235. {
  236. if (!PrimaryHelpKeyword.IsEmpty() &&
  237. !IsInternalErrorHelpKeyword(SecondaryHelpKeyword))
  238. {
  239. // we have to yet decide what we have both
  240. // PrimaryHelpKeyword and SecondaryHelpKeyword
  241. return PrimaryHelpKeyword;
  242. }
  243. else
  244. {
  245. return SecondaryHelpKeyword;
  246. }
  247. }
  248. //---------------------------------------------------------------------------
  249. bool __fastcall IsInternalErrorHelpKeyword(const UnicodeString & HelpKeyword)
  250. {
  251. return
  252. (HelpKeyword == HELP_INTERNAL_ERROR);
  253. }
  254. //---------------------------------------------------------------------------
  255. __fastcall ExtException::ExtException(Exception * E) :
  256. Exception("")
  257. {
  258. AddMoreMessages(E);
  259. FHelpKeyword = GetExceptionHelpKeyword(E);
  260. }
  261. //---------------------------------------------------------------------------
  262. __fastcall ExtException::ExtException(Exception* E, UnicodeString Msg, UnicodeString HelpKeyword):
  263. Exception(Msg)
  264. {
  265. AddMoreMessages(E);
  266. FHelpKeyword = MergeHelpKeyword(HelpKeyword, GetExceptionHelpKeyword(E));
  267. }
  268. //---------------------------------------------------------------------------
  269. __fastcall ExtException::ExtException(UnicodeString Msg, Exception* E, UnicodeString HelpKeyword) :
  270. Exception("")
  271. {
  272. // "copy exception"
  273. AddMoreMessages(E);
  274. // and append message to the end to more messages
  275. if (!Msg.IsEmpty())
  276. {
  277. if (Message.IsEmpty())
  278. {
  279. Message = Msg;
  280. }
  281. else
  282. {
  283. if (FMoreMessages == NULL)
  284. {
  285. FMoreMessages = new TStringList();
  286. }
  287. FMoreMessages->Append(UnformatMessage(Msg));
  288. }
  289. }
  290. FHelpKeyword = MergeHelpKeyword(GetExceptionHelpKeyword(E), HelpKeyword);
  291. }
  292. //---------------------------------------------------------------------------
  293. __fastcall ExtException::ExtException(UnicodeString Msg, UnicodeString MoreMessages,
  294. UnicodeString HelpKeyword) :
  295. Exception(Msg),
  296. FHelpKeyword(HelpKeyword)
  297. {
  298. if (!MoreMessages.IsEmpty())
  299. {
  300. FMoreMessages = TextToStringList(MoreMessages);
  301. }
  302. }
  303. //---------------------------------------------------------------------------
  304. __fastcall ExtException::ExtException(UnicodeString Msg, TStrings* MoreMessages,
  305. bool Own, UnicodeString HelpKeyword) :
  306. Exception(Msg),
  307. FHelpKeyword(HelpKeyword)
  308. {
  309. if (Own)
  310. {
  311. FMoreMessages = MoreMessages;
  312. }
  313. else
  314. {
  315. FMoreMessages = new TStringList();
  316. FMoreMessages->Assign(MoreMessages);
  317. }
  318. }
  319. //---------------------------------------------------------------------------
  320. void __fastcall ExtException::AddMoreMessages(Exception* E)
  321. {
  322. if (E != NULL)
  323. {
  324. if (FMoreMessages == NULL)
  325. {
  326. FMoreMessages = new TStringList();
  327. }
  328. ExtException * ExtE = dynamic_cast<ExtException *>(E);
  329. if (ExtE != NULL)
  330. {
  331. if (ExtE->MoreMessages != NULL)
  332. {
  333. FMoreMessages->Assign(ExtE->MoreMessages);
  334. }
  335. }
  336. UnicodeString Msg;
  337. ExceptionMessageFormatted(E, Msg);
  338. // new exception does not have own message, this is in fact duplication of
  339. // the exception data, but the exception class may being changed
  340. if (Message.IsEmpty())
  341. {
  342. Message = Msg;
  343. }
  344. else if (!Msg.IsEmpty())
  345. {
  346. FMoreMessages->Insert(0, UnformatMessage(Msg));
  347. }
  348. if (IsInternalException(E))
  349. {
  350. AppendExceptionStackTraceAndForget(FMoreMessages);
  351. }
  352. if (FMoreMessages->Count == 0)
  353. {
  354. delete FMoreMessages;
  355. FMoreMessages = NULL;
  356. }
  357. }
  358. }
  359. //---------------------------------------------------------------------------
  360. __fastcall ExtException::~ExtException()
  361. {
  362. delete FMoreMessages;
  363. }
  364. //---------------------------------------------------------------------------
  365. ExtException * __fastcall ExtException::CloneFrom(Exception * E)
  366. {
  367. return new ExtException(E, L"");
  368. }
  369. //---------------------------------------------------------------------------
  370. ExtException * __fastcall ExtException::Clone()
  371. {
  372. return CloneFrom(this);
  373. }
  374. //---------------------------------------------------------------------------
  375. void __fastcall ExtException::Rethrow()
  376. {
  377. throw ExtException(this, L"");
  378. }
  379. //---------------------------------------------------------------------------
  380. UnicodeString __fastcall SysErrorMessageForError(int LastError)
  381. {
  382. UnicodeString Result;
  383. if (LastError != 0)
  384. {
  385. Result = FORMAT(System_Sysconst_SOSError, (LastError, SysErrorMessage(LastError), UnicodeString()));
  386. }
  387. return Result;
  388. }
  389. //---------------------------------------------------------------------------
  390. UnicodeString __fastcall LastSysErrorMessage()
  391. {
  392. return SysErrorMessageForError(GetLastError());
  393. }
  394. //---------------------------------------------------------------------------
  395. __fastcall EOSExtException::EOSExtException(UnicodeString Msg) :
  396. ExtException(Msg, LastSysErrorMessage())
  397. {
  398. }
  399. //---------------------------------------------------------------------------
  400. __fastcall EOSExtException::EOSExtException(UnicodeString Msg, int LastError) :
  401. ExtException(Msg, SysErrorMessageForError(LastError))
  402. {
  403. }
  404. //---------------------------------------------------------------------------
  405. __fastcall EFatal::EFatal(Exception* E, UnicodeString Msg, UnicodeString HelpKeyword) :
  406. ExtException(Msg, E, HelpKeyword),
  407. ReopenQueried(false),
  408. InactiveTerminationMessage(false)
  409. {
  410. EFatal * F = dynamic_cast<EFatal *>(E);
  411. if (F != NULL)
  412. {
  413. ReopenQueried = F->ReopenQueried;
  414. InactiveTerminationMessage = F->InactiveTerminationMessage;
  415. }
  416. }
  417. //---------------------------------------------------------------------------
  418. __fastcall ECRTExtException::ECRTExtException(UnicodeString Msg) :
  419. EOSExtException(Msg, errno)
  420. {
  421. }
  422. //---------------------------------------------------------------------------
  423. ExtException * __fastcall EFatal::Clone()
  424. {
  425. return new EFatal(this, L"");
  426. }
  427. //---------------------------------------------------------------------------
  428. void __fastcall EFatal::Rethrow()
  429. {
  430. throw EFatal(this, L"");
  431. }
  432. //---------------------------------------------------------------------------
  433. ExtException * __fastcall ESshTerminate::Clone()
  434. {
  435. return new ESshTerminate(this, L"", Operation, TargetLocalPath, DestLocalFileName);
  436. }
  437. //---------------------------------------------------------------------------
  438. void __fastcall ESshTerminate::Rethrow()
  439. {
  440. throw ESshTerminate(this, L"", Operation, TargetLocalPath, DestLocalFileName);
  441. }
  442. //---------------------------------------------------------------------------
  443. __fastcall ECallbackGuardAbort::ECallbackGuardAbort() : EAbort(L"callback abort")
  444. {
  445. }
  446. //---------------------------------------------------------------------------
  447. Exception * __fastcall CloneException(Exception * E)
  448. {
  449. Exception * Result;
  450. // this list has to be in sync with ExceptionMessage
  451. ExtException * Ext = dynamic_cast<ExtException *>(E);
  452. if (Ext != NULL)
  453. {
  454. Result = Ext->Clone();
  455. }
  456. else if (dynamic_cast<ECallbackGuardAbort *>(E) != NULL)
  457. {
  458. Result = new ECallbackGuardAbort();
  459. }
  460. else if (dynamic_cast<EAbort *>(E) != NULL)
  461. {
  462. Result = new EAbort(E->Message);
  463. }
  464. else if (WellKnownException(E, NULL, NULL, &Result, false))
  465. {
  466. // noop
  467. }
  468. else
  469. {
  470. // we do not expect this to happen
  471. if (DebugAlwaysFalse(IsInternalException(E)))
  472. {
  473. // to save exception stack trace
  474. Result = ExtException::CloneFrom(E);
  475. }
  476. else
  477. {
  478. Result = new Exception(E->Message);
  479. }
  480. }
  481. return Result;
  482. }
  483. //---------------------------------------------------------------------------
  484. void __fastcall RethrowException(Exception * E)
  485. {
  486. // this list has to be in sync with ExceptionMessage
  487. if (dynamic_cast<ExtException *>(E) != NULL)
  488. {
  489. dynamic_cast<ExtException *>(E)->Rethrow();
  490. }
  491. else if (dynamic_cast<ECallbackGuardAbort *>(E) != NULL)
  492. {
  493. throw ECallbackGuardAbort();
  494. }
  495. else if (dynamic_cast<EAbort *>(E) != NULL)
  496. {
  497. throw EAbort(E->Message);
  498. }
  499. else if (WellKnownException(E, NULL, NULL, NULL, true))
  500. {
  501. // noop, should never get here
  502. }
  503. else
  504. {
  505. throw ExtException(E, L"");
  506. }
  507. }
  508. //---------------------------------------------------------------------------
  509. UnicodeString __fastcall AddContextToExceptionMessage(const Exception & E, const UnicodeString & NewContext)
  510. {
  511. UnicodeString MainMessage;
  512. UnicodeString Context = E.Message;
  513. if (!ExtractMainInstructions(Context, MainMessage))
  514. {
  515. MainMessage = E.Message;
  516. Context = NewContext;
  517. }
  518. else
  519. {
  520. Context += L"\n" + NewContext;
  521. }
  522. UnicodeString Result = MainInstructions(MainMessage) + L"\n" + Context;
  523. return Result;
  524. }