Browse Source

Add a new notification to detect crashes on native scripts

Marcelo Fernandez 7 years ago
parent
commit
deebeb2742

+ 1 - 0
core/os/main_loop.cpp

@@ -58,6 +58,7 @@ void MainLoop::_bind_methods() {
 	BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
 	BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED);
 	BIND_CONSTANT(NOTIFICATION_WM_ABOUT);
+	BIND_CONSTANT(NOTIFICATION_CRASH);
 };
 
 void MainLoop::set_init_script(const Ref<Script> &p_init_script) {

+ 1 - 0
core/os/main_loop.h

@@ -62,6 +62,7 @@ public:
 		// fixes this issue.
 		NOTIFICATION_TRANSLATION_CHANGED = 90,
 		NOTIFICATION_WM_ABOUT = 91,
+		NOTIFICATION_CRASH = 92,
 	};
 
 	virtual void input_event(const Ref<InputEvent> &p_event);

+ 19 - 0
modules/gdnative/nativescript/nativescript.cpp

@@ -697,11 +697,21 @@ Variant NativeScriptInstance::call(const StringName &p_method, const Variant **p
 		Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
 		if (E) {
 			godot_variant result;
+
+#ifdef DEBUG_ENABLED
+			current_method_call = p_method;
+#endif
+
 			result = E->get().method.method((godot_object *)owner,
 					E->get().method.method_data,
 					userdata,
 					p_argcount,
 					(godot_variant **)p_args);
+
+#ifdef DEBUG_ENABLED
+			current_method_call = "";
+#endif
+
 			Variant res = *(Variant *)&result;
 			godot_variant_destroy(&result);
 			r_error.error = Variant::CallError::CALL_OK;
@@ -716,6 +726,15 @@ Variant NativeScriptInstance::call(const StringName &p_method, const Variant **p
 }
 
 void NativeScriptInstance::notification(int p_notification) {
+#ifdef DEBUG_ENABLED
+	if (p_notification == MainLoop::NOTIFICATION_CRASH) {
+		if (current_method_call != StringName("")) {
+			ERR_PRINTS("NativeScriptInstance detected crash on method: " + current_method_call);
+			current_method_call = "";
+		}
+	}
+#endif
+
 	Variant value = p_notification;
 	const Variant *args[1] = { &value };
 	call_multilevel("_notification", args, 1);

+ 3 - 0
modules/gdnative/nativescript/nativescript.h

@@ -181,6 +181,9 @@ class NativeScriptInstance : public ScriptInstance {
 
 	Object *owner;
 	Ref<NativeScript> script;
+#ifdef DEBUG_ENABLED
+	StringName current_method_call;
+#endif
 
 	void _ml_call_reversed(NativeScriptDesc *script_data, const StringName &p_method, const Variant **p_args, int p_argcount);
 

+ 4 - 0
platform/osx/crash_handler_osx.mm

@@ -78,6 +78,10 @@ static void handle_crash(int sig) {
 
 	// Dump the backtrace to stderr with a message to the user
 	fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
+
+	if (OS::get_singleton()->get_main_loop())
+		OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
+
 	fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
 	char **strings = backtrace_symbols(bt_buffer, size);
 	if (strings) {

+ 3 - 0
platform/windows/crash_handler_win.cpp

@@ -124,6 +124,9 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
 
 	fprintf(stderr, "%s: Program crashed\n", __FUNCTION__);
 
+	if (OS::get_singleton()->get_main_loop())
+		OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
+
 	// Load the symbols:
 	if (!SymInitialize(process, NULL, false))
 		return EXCEPTION_CONTINUE_SEARCH;

+ 4 - 0
platform/x11/crash_handler_x11.cpp

@@ -55,6 +55,10 @@ static void handle_crash(int sig) {
 
 	// Dump the backtrace to stderr with a message to the user
 	fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
+
+	if (OS::get_singleton()->get_main_loop())
+		OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
+
 	fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
 	char **strings = backtrace_symbols(bt_buffer, size);
 	if (strings) {

+ 5 - 0
scene/main/scene_tree.cpp

@@ -656,6 +656,11 @@ void SceneTree::_notification(int p_notification) {
 #endif
 		} break;
 
+		case NOTIFICATION_CRASH: {
+
+			get_root()->propagate_notification(p_notification);
+		} break;
+
 		default:
 			break;
 	};