| 13186 | |
| 13187 | |
| 13188 | ResultType Script::UnhandledException(Line* aLine, ResultType aErrorType) |
| 13189 | { |
| 13190 | LPCTSTR message = _T(""), extra = _T(""); |
| 13191 | TCHAR extra_buf[MAX_NUMBER_SIZE], message_buf[MAX_NUMBER_SIZE]; |
| 13192 | |
| 13193 | global_struct &g = *::g; |
| 13194 | |
| 13195 | // OnError: Allow the script to handle it via a global callback. |
| 13196 | static bool sOnErrorRunning = false; |
| 13197 | if (mOnError.Count() && !sOnErrorRunning) |
| 13198 | { |
| 13199 | __int64 retval; |
| 13200 | ResultToken *token = g.ThrownToken; |
| 13201 | g.ThrownToken = NULL; // Allow the callback to execute correctly. |
| 13202 | sOnErrorRunning = true; |
| 13203 | ExprTokenType param[2]; |
| 13204 | param[0].CopyValueFrom(*token); |
| 13205 | param[1].SetValue(aErrorType == CRITICAL_ERROR ? _T("ExitApp") |
| 13206 | : aErrorType == FAIL_OR_OK ? _T("Return") : _T("Exit")); |
| 13207 | mOnError.Call(param, 2, INT_MAX, &retval); |
| 13208 | sOnErrorRunning = false; |
| 13209 | if (g.ThrownToken) // An exception was thrown by the callback. |
| 13210 | { |
| 13211 | // UnhandledException() has already been called recursively for g.ThrownToken, |
| 13212 | // so don't show a second error message. This allows `throw param1` to mean |
| 13213 | // "abort all OnError callbacks and show default message now". |
| 13214 | FreeExceptionToken(token); |
| 13215 | return FAIL; |
| 13216 | } |
| 13217 | if (retval < 0 && aErrorType == FAIL_OR_OK) |
| 13218 | { |
| 13219 | FreeExceptionToken(token); |
| 13220 | return OK; // Ignore error and continue. |
| 13221 | } |
| 13222 | // Some callers rely on g.ThrownToken!=NULL to unwind the stack, so it is restored |
| 13223 | // rather than freeing it immediately. If the exception object has __Delete, it |
| 13224 | // will be called after the stack unwinds. |
| 13225 | g.ThrownToken = token; |
| 13226 | if (retval) |
| 13227 | return FAIL; // Exit thread. |
| 13228 | } |
| 13229 | |
| 13230 | if (Object *ex = dynamic_cast<Object *>(TokenToObject(*g.ThrownToken))) |
| 13231 | { |
| 13232 | // For simplicity and safety, we call into the Object directly rather than via Invoke(). |
| 13233 | ExprTokenType t; |
| 13234 | if (ex->GetOwnProp(t, _T("Message"))) |
| 13235 | message = TokenToString(t, message_buf); |
| 13236 | if (ex->GetOwnProp(t, _T("Extra"))) |
| 13237 | extra = TokenToString(t, extra_buf); |
| 13238 | if (ex->GetOwnProp(t, _T("Line"))) |
| 13239 | { |
| 13240 | LineNumberType line_no = (LineNumberType)TokenToInt64(t); |
| 13241 | if (ex->GetOwnProp(t, _T("File"))) |
| 13242 | { |
| 13243 | LPCTSTR file = TokenToString(t); |
| 13244 | // Locate the line by number and file index, then display that line instead |
| 13245 | // of the caller supplied one since it's probably more relevant. |
no test coverage detected