Exceptions.cpp 16 KB

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