From 6012ec9e56a8b3c41193652c58285699733cbf59 Mon Sep 17 00:00:00 2001 From: aquanight Date: Sun, 5 Jul 2020 15:31:07 -0600 Subject: [PATCH] Prevent double calls of perl_script_unload --- src/perl/perl-core.c | 28 ++++++++++++++++++++++++---- src/perl/perl-core.h | 7 +++++++ src/perl/perl-fe.c | 2 +- src/perl/perl-signals.c | 4 ++++ src/perl/perl-sources.c | 5 +++++ 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/perl/perl-core.c b/src/perl/perl-core.c index 866b86e8..295715d3 100644 --- a/src/perl/perl-core.c +++ b/src/perl/perl-core.c @@ -67,9 +67,6 @@ static void perl_script_destroy(PERL_SCRIPT_REC *script) { perl_scripts = g_slist_remove(perl_scripts, script); - perl_signal_remove_script(script); - perl_source_remove_script(script); - signal_emit("script destroyed", 1, script); g_free(script->name); @@ -314,7 +311,30 @@ void perl_script_unload(PERL_SCRIPT_REC *script) g_return_if_fail(script != NULL); perl_script_destroy_package(script); - perl_script_destroy(script); + + perl_signal_remove_script(script); + perl_source_remove_script(script); + + script->unloaded = 1; + if (!script->active_signals) + perl_script_destroy(script); +} + +/* Enter a perl script (signal or input source) */ +void perl_script_enter(PERL_SCRIPT_REC *script) +{ + g_return_if_fail(script != NULL); + + script->active_signals++; +} + +void perl_script_exit(PERL_SCRIPT_REC *script) +{ + g_return_if_fail(script != NULL); + + script->active_signals--; + if (script->unloaded) + perl_script_destroy(script); } /* Find loaded script by name */ diff --git a/src/perl/perl-core.h b/src/perl/perl-core.h index 0d3a1a2f..5b2de9ac 100644 --- a/src/perl/perl-core.h +++ b/src/perl/perl-core.h @@ -8,6 +8,8 @@ typedef struct { /* Script can be loaded from a file, or from some data in memory */ char *path; /* FILE: full path for file */ char *data; /* DATA: data used for the script */ + int unloaded; /* Indicates unloading has been done, so it should be destroyed once all signals exit */ + int active_signals; /* active signal calls into this script - prevents full teardown when nonzero */ } PERL_SCRIPT_REC; extern GSList *perl_scripts; @@ -26,6 +28,11 @@ PERL_SCRIPT_REC *perl_script_load_data(const char *data); /* Unload perl script */ void perl_script_unload(PERL_SCRIPT_REC *script); +/* Mark a script as entered */ +void perl_script_enter(PERL_SCRIPT_REC *script); +/* Mark a script as exited */ +void perl_script_exit(PERL_SCRIPT_REC *script); + /* Find loaded script by name */ PERL_SCRIPT_REC *perl_script_find(const char *name); /* Find loaded script by package */ diff --git a/src/perl/perl-fe.c b/src/perl/perl-fe.c index ac84d67a..ba6dccce 100644 --- a/src/perl/perl-fe.c +++ b/src/perl/perl-fe.c @@ -106,7 +106,7 @@ static void cmd_script_unload(const char *data) script_fix_name(name); script = perl_script_find(name); - if (script == NULL) { + if (script == NULL || script->unloaded) { printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_SCRIPT_NOT_LOADED, name); } else { diff --git a/src/perl/perl-signals.c b/src/perl/perl-signals.c index 27522f5e..5ea40d73 100644 --- a/src/perl/perl-signals.c +++ b/src/perl/perl-signals.c @@ -420,7 +420,10 @@ static void sig_func(const void *p1, const void *p2, args[3] = p4; args[4] = p5; args[5] = p6; rec = signal_get_user_data(); + if (rec->script->unloaded) return; /* Drop signal calls into unloaded scripts. */ + perl_script_enter(rec->script); perl_call_signal(rec->script, rec->func, signal_get_emitted_id(), args); + perl_script_exit(rec->script); } static void perl_signal_add_full_int(const char *signal, SV *func, @@ -437,6 +440,7 @@ static void perl_signal_add_full_int(const char *signal, SV *func, script = perl_script_find_package(perl_get_package()); g_return_if_fail(script != NULL); + g_return_if_fail(script->unloaded); rec = g_new(PERL_SIGNAL_REC, 1); rec->script = script; diff --git a/src/perl/perl-sources.c b/src/perl/perl-sources.c index 3c72be22..57fb579d 100644 --- a/src/perl/perl-sources.c +++ b/src/perl/perl-sources.c @@ -78,6 +78,7 @@ static int perl_source_event(PERL_SOURCE_REC *rec) PUTBACK; perl_source_ref(rec); + perl_script_enter(rec->script); perl_call_sv(rec->func, G_EVAL|G_DISCARD); if (SvTRUE(ERRSV)) { @@ -86,6 +87,8 @@ static int perl_source_event(PERL_SOURCE_REC *rec) g_free(error); } + perl_script_exit(rec->script); + if (perl_source_unref(rec) && rec->once) perl_source_destroy(rec); @@ -104,6 +107,7 @@ int perl_timeout_add(int msecs, SV *func, SV *data, int once) pkg = perl_get_package(); script = perl_script_find_package(pkg); g_return_val_if_fail(script != NULL, -1); + g_return_val_if_fail(script->unloaded, -1); rec = g_new0(PERL_SOURCE_REC, 1); perl_source_ref(rec); @@ -127,6 +131,7 @@ int perl_input_add(int source, int condition, SV *func, SV *data, int once) pkg = perl_get_package(); script = perl_script_find_package(pkg); g_return_val_if_fail(script != NULL, -1); + g_return_val_if_fail(script->unloaded, -1); rec = g_new0(PERL_SOURCE_REC, 1); perl_source_ref(rec);