//--------------------------------------------------------------------------- #include #pragma hdrstop #include "Common.h" #include "Exceptions.h" #include "TextsCore.h" #include "HelpCore.h" #include "Configuration.h" #include "CoreMain.h" #include "Interface.h" #include //--------------------------------------------------------------------------- #pragma package(smart_init) //--------------------------------------------------------------------------- static std::unique_ptr IgnoredExceptionsCriticalSection(TraceInitPtr(new TCriticalSection())); typedef std::set TIgnoredExceptions; static TIgnoredExceptions IgnoredExceptions; //--------------------------------------------------------------------------- static UnicodeString __fastcall NormalizeClassName(const UnicodeString & ClassName) { return ReplaceStr(ClassName, L".", L"::").LowerCase(); } //--------------------------------------------------------------------------- void __fastcall IgnoreException(const std::type_info & ExceptionType) { TGuard Guard(IgnoredExceptionsCriticalSection.get()); // We should better use type_index as a key, instead of a class name, // but type_index is not available in 32-bit version of STL in XE6. IgnoredExceptions.insert(NormalizeClassName(UnicodeString(AnsiString(ExceptionType.name())))); } //--------------------------------------------------------------------------- static bool __fastcall WellKnownException( Exception * E, UnicodeString * AMessage, const wchar_t ** ACounterName, Exception ** AClone, bool Rethrow) { UnicodeString Message; const wchar_t * CounterName; std::unique_ptr Clone; bool Result = true; bool IgnoreException = false; if (!IgnoredExceptions.empty()) { TGuard Guard(IgnoredExceptionsCriticalSection.get()); UnicodeString ClassName = NormalizeClassName(E->QualifiedClassName()); IgnoreException = (IgnoredExceptions.find(ClassName) != IgnoredExceptions.end()); } if (IgnoreException) { Result = false; } // EAccessViolation is EExternal else if (dynamic_cast(E) != NULL) { if (Rethrow) { throw EAccessViolation(E->Message); } UnicodeString S = E->Message; UnicodeString Dummy; if (!ExtractMainInstructions(S, Dummy)) { S = UnicodeString(); } Message = MainInstructions(LoadStr(ACCESS_VIOLATION_ERROR3)) + S; CounterName = L"AccessViolations"; Clone.reset(new EAccessViolation(E->Message)); } // EIntError and EMathError are EExternal // EClassNotFound is EFilerError else if ((dynamic_cast(E) != NULL) || (dynamic_cast(E) != NULL) || (dynamic_cast(E) != NULL) || (dynamic_cast(E) != NULL) || (dynamic_cast(E) != NULL) || (dynamic_cast(E) != NULL) || (dynamic_cast(E) != NULL)) { if (Rethrow) { throw EIntError(E->Message); } Message = MainInstructions(E->Message); CounterName = L"InternalExceptions"; Clone.reset(new EIntError(E->Message)); } else if (dynamic_cast(E) != NULL) { if (Rethrow) { throw EExternal(E->Message); } Message = MainInstructions(E->Message); CounterName = L"ExternalExceptions"; Clone.reset(new EExternal(E->Message)); } else if (dynamic_cast(E) != NULL) { if (Rethrow) { throw EHeapException(E->Message); } Message = MainInstructions(E->Message); CounterName = L"HeapExceptions"; Clone.reset(new EHeapException(E->Message)); } else { Result = false; } if (Result) { if (AMessage != NULL) { (*AMessage) = Message; } if (ACounterName != NULL) { (*ACounterName) = CounterName; } if (AClone != NULL) { (*AClone) = DebugNotNull(Clone.release()); } } return Result; } //--------------------------------------------------------------------------- static bool __fastcall ExceptionMessage(Exception * E, bool Count, bool Formatted, UnicodeString & Message, bool & InternalError) { bool Result = true; const wchar_t * CounterName = NULL; InternalError = false; // see also IsInternalException // this list has to be in sync with CloneException if (dynamic_cast(E) != NULL) { Result = false; } else if (WellKnownException(E, &Message, &CounterName, NULL, false)) { InternalError = true; } else if (E->Message.IsEmpty()) { Result = false; } else { Message = E->Message; } if (!Formatted) { Message = UnformatMessage(Message); } if (InternalError) { Message = FMTLOAD(REPORT_ERROR, (Message)); } if (Count && (CounterName != NULL) && (Configuration->Usage != NULL)) { Configuration->Usage->Inc(CounterName); UnicodeString ExceptionDebugInfo = E->ClassName() + L":" + GetExceptionDebugInfo(); Configuration->Usage->Set(LastInternalExceptionCounter, ExceptionDebugInfo); } return Result; } //--------------------------------------------------------------------------- bool __fastcall IsInternalException(Exception * E) { // see also InternalError in ExceptionMessage return WellKnownException(E, NULL, NULL, NULL, false); } //--------------------------------------------------------------------------- bool __fastcall ExceptionMessage(Exception * E, UnicodeString & Message) { bool InternalError; return ExceptionMessage(E, true, false, Message, InternalError); } //--------------------------------------------------------------------------- bool __fastcall ExceptionMessageFormatted(Exception * E, UnicodeString & Message) { bool InternalError; return ExceptionMessage(E, true, true, Message, InternalError); } //--------------------------------------------------------------------------- bool __fastcall ShouldDisplayException(Exception * E) { UnicodeString Message; return ExceptionMessageFormatted(E, Message); } //--------------------------------------------------------------------------- TStrings * __fastcall ExceptionToMoreMessages(Exception * E) { TStrings * Result = NULL; UnicodeString Message; if (ExceptionMessage(E, Message)) { Result = new TStringList(); Result->Add(Message); ExtException * ExtE = dynamic_cast(E); if ((ExtE != NULL) && (ExtE->MoreMessages != NULL)) { Result->AddStrings(ExtE->MoreMessages); } } return Result; } //--------------------------------------------------------------------------- bool __fastcall ExceptionFullMessage(Exception * E, UnicodeString & Message) { bool Result = ExceptionMessage(E, Message); if (Result) { Message += L"\n"; ExtException * EE = dynamic_cast(E); if ((EE != NULL) && (EE->MoreMessages != NULL)) { Message += EE->MoreMessages->Text + L"\n"; } } return Result; } //--------------------------------------------------------------------------- UnicodeString __fastcall GetExceptionHelpKeyword(Exception * E) { UnicodeString HelpKeyword; ExtException * ExtE = dynamic_cast(E); UnicodeString Message; // not used bool InternalError = false; if (ExtE != NULL) { HelpKeyword = ExtE->HelpKeyword; } else if ((E != NULL) && ExceptionMessage(E, false, false, Message, InternalError) && InternalError) { HelpKeyword = HELP_INTERNAL_ERROR; } return HelpKeyword; } //--------------------------------------------------------------------------- UnicodeString __fastcall MergeHelpKeyword(const UnicodeString & PrimaryHelpKeyword, const UnicodeString & SecondaryHelpKeyword) { if (!PrimaryHelpKeyword.IsEmpty() && !IsInternalErrorHelpKeyword(SecondaryHelpKeyword)) { // we have to yet decide what we have both // PrimaryHelpKeyword and SecondaryHelpKeyword return PrimaryHelpKeyword; } else { return SecondaryHelpKeyword; } } //--------------------------------------------------------------------------- bool __fastcall IsInternalErrorHelpKeyword(const UnicodeString & HelpKeyword) { return (HelpKeyword == HELP_INTERNAL_ERROR); } //--------------------------------------------------------------------------- __fastcall ExtException::ExtException(Exception * E) : Exception("") { AddMoreMessages(E); FHelpKeyword = GetExceptionHelpKeyword(E); } //--------------------------------------------------------------------------- __fastcall ExtException::ExtException(Exception* E, UnicodeString Msg, UnicodeString HelpKeyword): Exception(Msg) { AddMoreMessages(E); FHelpKeyword = MergeHelpKeyword(HelpKeyword, GetExceptionHelpKeyword(E)); } //--------------------------------------------------------------------------- __fastcall ExtException::ExtException(UnicodeString Msg, Exception* E, UnicodeString HelpKeyword) : Exception("") { // "copy exception" AddMoreMessages(E); // and append message to the end to more messages if (!Msg.IsEmpty()) { if (Message.IsEmpty()) { Message = Msg; } else { if (FMoreMessages == NULL) { FMoreMessages = new TStringList(); } FMoreMessages->Append(UnformatMessage(Msg)); } } FHelpKeyword = MergeHelpKeyword(GetExceptionHelpKeyword(E), HelpKeyword); } //--------------------------------------------------------------------------- __fastcall ExtException::ExtException(UnicodeString Msg, UnicodeString MoreMessages, UnicodeString HelpKeyword) : Exception(Msg), FHelpKeyword(HelpKeyword) { if (!MoreMessages.IsEmpty()) { FMoreMessages = TextToStringList(MoreMessages); } } //--------------------------------------------------------------------------- __fastcall ExtException::ExtException(UnicodeString Msg, TStrings* MoreMessages, bool Own, UnicodeString HelpKeyword) : Exception(Msg), FHelpKeyword(HelpKeyword) { if (Own) { FMoreMessages = MoreMessages; } else { FMoreMessages = new TStringList(); FMoreMessages->Assign(MoreMessages); } } //--------------------------------------------------------------------------- void __fastcall ExtException::AddMoreMessages(Exception* E) { if (E != NULL) { if (FMoreMessages == NULL) { FMoreMessages = new TStringList(); } ExtException * ExtE = dynamic_cast(E); if (ExtE != NULL) { if (ExtE->MoreMessages != NULL) { FMoreMessages->Assign(ExtE->MoreMessages); } } UnicodeString Msg; ExceptionMessageFormatted(E, Msg); // new exception does not have own message, this is in fact duplication of // the exception data, but the exception class may being changed if (Message.IsEmpty()) { Message = Msg; } else if (!Msg.IsEmpty()) { FMoreMessages->Insert(0, UnformatMessage(Msg)); } if (IsInternalException(E)) { AppendExceptionStackTraceAndForget(FMoreMessages); } if (FMoreMessages->Count == 0) { delete FMoreMessages; FMoreMessages = NULL; } } } //--------------------------------------------------------------------------- __fastcall ExtException::~ExtException() { delete FMoreMessages; } //--------------------------------------------------------------------------- ExtException * __fastcall ExtException::CloneFrom(Exception * E) { return new ExtException(E, L""); } //--------------------------------------------------------------------------- ExtException * __fastcall ExtException::Clone() { return CloneFrom(this); } //--------------------------------------------------------------------------- void __fastcall ExtException::Rethrow() { throw ExtException(this, L""); } //--------------------------------------------------------------------------- UnicodeString __fastcall SysErrorMessageForError(int LastError) { UnicodeString Result; if (LastError != 0) { Result = FORMAT(System_Sysconst_SOSError, (LastError, SysErrorMessage(LastError), UnicodeString())); } return Result; } //--------------------------------------------------------------------------- UnicodeString __fastcall LastSysErrorMessage() { return SysErrorMessageForError(GetLastError()); } //--------------------------------------------------------------------------- __fastcall EOSExtException::EOSExtException(UnicodeString Msg) : ExtException(Msg, LastSysErrorMessage()) { } //--------------------------------------------------------------------------- __fastcall EOSExtException::EOSExtException(UnicodeString Msg, int LastError) : ExtException(Msg, SysErrorMessageForError(LastError)) { } //--------------------------------------------------------------------------- __fastcall EFatal::EFatal(Exception* E, UnicodeString Msg, UnicodeString HelpKeyword) : ExtException(Msg, E, HelpKeyword), FReopenQueried(false) { EFatal * F = dynamic_cast(E); if (F != NULL) { FReopenQueried = F->ReopenQueried; } } //--------------------------------------------------------------------------- __fastcall ECRTExtException::ECRTExtException(UnicodeString Msg) : EOSExtException(Msg, errno) { } //--------------------------------------------------------------------------- ExtException * __fastcall EFatal::Clone() { return new EFatal(this, L""); } //--------------------------------------------------------------------------- void __fastcall EFatal::Rethrow() { throw EFatal(this, L""); } //--------------------------------------------------------------------------- ExtException * __fastcall ESshTerminate::Clone() { return new ESshTerminate(this, L"", Operation, TargetLocalPath, DestLocalFileName); } //--------------------------------------------------------------------------- void __fastcall ESshTerminate::Rethrow() { throw ESshTerminate(this, L"", Operation, TargetLocalPath, DestLocalFileName); } //--------------------------------------------------------------------------- __fastcall ECallbackGuardAbort::ECallbackGuardAbort() : EAbort(L"callback abort") { } //--------------------------------------------------------------------------- Exception * __fastcall CloneException(Exception * E) { Exception * Result; // this list has to be in sync with ExceptionMessage ExtException * Ext = dynamic_cast(E); if (Ext != NULL) { Result = Ext->Clone(); } else if (dynamic_cast(E) != NULL) { Result = new ECallbackGuardAbort(); } else if (dynamic_cast(E) != NULL) { Result = new EAbort(E->Message); } else if (WellKnownException(E, NULL, NULL, &Result, false)) { // noop } else { // we do not expect this to happen if (DebugAlwaysFalse(IsInternalException(E))) { // to save exception stack trace Result = ExtException::CloneFrom(E); } else { Result = new Exception(E->Message); } } return Result; } //--------------------------------------------------------------------------- void __fastcall RethrowException(Exception * E) { // this list has to be in sync with ExceptionMessage if (dynamic_cast(E) != NULL) { dynamic_cast(E)->Rethrow(); } else if (dynamic_cast(E) != NULL) { throw ECallbackGuardAbort(); } else if (dynamic_cast(E) != NULL) { throw EAbort(E->Message); } else if (WellKnownException(E, NULL, NULL, NULL, true)) { // noop, should never get here } else { throw ExtException(E, L""); } } //--------------------------------------------------------------------------- UnicodeString __fastcall AddContextToExceptionMessage(const Exception & E, const UnicodeString & NewContext) { UnicodeString MainMessage; UnicodeString Context = E.Message; if (!ExtractMainInstructions(Context, MainMessage)) { MainMessage = E.Message; Context = NewContext; } else { Context += L"\n" + NewContext; } UnicodeString Result = MainInstructions(MainMessage) + L"\n" + Context; return Result; }