porting ist im git
Posts by horchi
-
-
Noch ein Gedanke zu diesem Thema.
Warum tritt der Fehler nur auf, wenn ich einen Timer manuell anlege oder ändere?
Suchtimer sind nicht betroffen und können den Namen mit Hilfe der recording.py ermitteln.
Wo ist hier der Unterschied.
weil er nur bei manueller Anlage via WEBIF vom epghttpd angelegt wird und nur dort in einem Thread.
-
was lange währt ....
Nachdem ich meinen Server auf Ubuntu 24.04 aktualisiert habe ich ich nun auch in den 'Genuss' von libpython 3.12 gekommen.
So konnte ich es reproduzieren und nach langer Suche beheben. Der Ansatz meines letzten Versuchs via PyGILState_Ensure() / PyGILState_Release war richtig.
Gefehlt hatte nur noch das Freigeben des Locks welche die Lib automatisch beim Initialisieren für dem Main-Thread anlegt - genau das ist Bescheiden bis nicht dokumentiert (sofern ich nicht ganz blind bin).
Lange Rede ... mit der neusten epgs/epghttpd Version (1.3.25) im Git sollte das Problem nicht mehr auftreten.
LG Jörg -
versuche es bitte nochmal hiermit.
Ich bekomme damit mit Python 3.8 einen Deadlock und vermute es ist der hier beschriebene. Menie Hoffnung ist das es damit mit der 3.12 läuftDiff
Display Morediff --git a/lib/python.c b/lib/python.c index faf769f..854d0d9 100644 --- a/lib/python.c +++ b/lib/python.c @@ -233,6 +233,11 @@ int Python::init(const char* modulePath) pName = PyString_FromString(file); #endif + PyGILState_STATE gstate; + printf("Ensure()\n"); + gstate = PyGILState_Ensure(); + printf("Ensure() got\n"); + usages++; // add search path for Python modules @@ -255,7 +260,8 @@ int Python::init(const char* modulePath) { showError(); tell("Failed to load '%s.py'", file); - + PyGILState_Release(gstate); + printf("Release()\n"); return fail; } @@ -269,10 +275,14 @@ int Python::init(const char* modulePath) showError(); tell("Cannot find function '%s'", function); - + PyGILState_Release(gstate); + printf("Release()\n"); return fail; } + PyGILState_Release(gstate); + printf("Release()\n"); + return success; } @@ -300,6 +310,11 @@ int Python::execute(cDbTable* eventsDb, int namingmode, const char* tmplExpressi { PyObject* pValue; + PyGILState_STATE gstate; + printf("Ensure()\n"); + gstate = PyGILState_Ensure(); + printf("Ensure() got\n"); + free(result); result = 0; @@ -311,6 +326,8 @@ int Python::execute(cDbTable* eventsDb, int namingmode, const char* tmplExpressi if (!pValue) { + PyGILState_Release(gstate); + printf("Release()\n"); showError(); tell("Python: Call of function '%s()' failed", function); @@ -332,10 +349,12 @@ int Python::execute(cDbTable* eventsDb, int namingmode, const char* tmplExpressi Py_DECREF(pValue); + PyGILState_Release(gstate); + printf("Release()\n"); + return success; } - //*************************************************************************** // Dup Py String //*************************************************************************** -
ich hab mir mal die Hinweise zum Thread handing für die Python Lib angesehen und mal Test weise etwas eingebaut (untested!)
Diff
Display Morediff --git a/lib/python.c b/lib/python.c index faf769f..1e78734 100644 --- a/lib/python.c +++ b/lib/python.c @@ -215,6 +215,8 @@ Python::~Python() int Python::init(const char* modulePath) { PyObject* pName {}; + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); tell(eloInfo, "Initialize python script '%s/%s.py'", modulePath, file); @@ -255,7 +257,7 @@ int Python::init(const char* modulePath) { showError(); tell("Failed to load '%s.py'", file); - + PyGILState_Release(gstate); return fail; } @@ -269,15 +271,20 @@ int Python::init(const char* modulePath) showError(); tell("Cannot find function '%s'", function); - + PyGILState_Release(gstate); return fail; } + PyGILState_Release(gstate); + return success; } int Python::exit() { + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); + usages--; if (pFunc) @@ -289,6 +296,8 @@ int Python::exit() if (!usages) Py_Finalize(); + PyGILState_Release(gstate); + return success; } @@ -300,6 +309,9 @@ int Python::execute(cDbTable* eventsDb, int namingmode, const char* tmplExpressi { PyObject* pValue; + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); + free(result); result = 0; @@ -311,6 +323,7 @@ int Python::execute(cDbTable* eventsDb, int namingmode, const char* tmplExpressi if (!pValue) { + PyGILState_Release(gstate); showError(); tell("Python: Call of function '%s()' failed", function); @@ -332,6 +345,7 @@ int Python::execute(cDbTable* eventsDb, int namingmode, const char* tmplExpressi Py_DECREF(pValue); + PyGILState_Release(gstate); return success; }es compiliert, weiter konnte ich noch nicht testen.
/EDIT: könnt ja mal berichten wenn ihr es damit testen konntet -
ja bin auch schon auf MULTIPLE_INTERPRETERS gestoßen ich schaue mal was ich da einbauen muss -
Prima, danke für den Test!
Dann gilt es herauszufinden was sich zwischen 3.11 und 3.12 geändert hat. -
und nun ist es die 3.12, wäre interessant ab welcher es nicht mehr geht
-
nein mit den Curl Meldungen hat es zu 99,9% nichts zu tun.
Interessant wäre ob es auf diesem System mit einer älteren libpython z.B. der 3.8 auch passiert, ich weiß nicht wann ich dazu kommen eine entsprechende Testumgebung aufzubauen.
-
habe es mir angesehen, der Umbau ist nicht ganz klein.
Das Plugin ist so aufgebaut das es eine Event Quelle ist, die DVB Events werden abgegriffen und in einer Datenbank abgelegt, sie gelangen nicht ins EPG. In der Datenbank werden sie mit EPG Daten aus bis zu zwei weiteren EPG Quellen gemerged und damit neue Events erstellt welche auf diesem Weg aktuell gehalten werden. Diese Events werden in das EPG übernommen.
Das hätte man auch anderes aufbauen können, damals erschien es als best mögliche Lösung, auch zu dem Damaligen Stand des EPG Handler Interfaces.Um es nun umzubauen muss das Handling der IDs umgebaut werden, also die Stelle an welcher alles zusammen läuft.
Ich werde das mal mit CKone durchsprechen ggf. fällt uns eine pragmatische Lösung ein, für einen großen Umbau habe ich im Moment keine Zeit.
-
Jup (muss ich eigentlich -fno-stack-protector -O0 aus dem ifdef DEBUG Block auch noch entfernen, weil sich sonst das -O2 und -O0 bzw. die unterschiedlichen stack-protection Optionen beißen?):
ja, sorry hatte ich übersehen:
aber wie kommt man nun dem Problem besser auf die Spur?
Sieht immer noch gleich aus für meine Augen:
in den Fall hat es wie es aussieht nicht geholfen. Diese Einstellungen bewirken das (in bestimmten Situationen) Stack Fehler, Buffer-Overflows etc. erkannt und direkt mir SEGFAULT abgebrochen wird wodurch man die auslösende Stelle besser eingrenzen kann. Hier hat es wohl nicht zugeschlagen. Das ganze war ausgehend von der Vermutung das der Crash in der Python Lib nur ein Folgefehler ist (wovon ich immer noch ausgehe). Hab gerade auch keine Idee mehr wie man dem auf die Schliche kommen könnte.
Generell läuft meine Implementierung rund um die Python C++ lib ja, zum einen im epgd und zum anderen auch im Test Programm. -
ja genau. Definiere dir am besten dieses Macro im Make.config
CodeCFLAGS_MEM = -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS \ -fstack-clash-protection -fstack-protector-strong \ -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now CFLAGS_MEM += -fcf-protection=full -Wtrampolinesund hänge es an die CFLAGS dran:
dann alles neu bauen
beim make solltest du dann sehen das die Optionen verwendet werden
Als Patch:Diff
Display Morediff --git a/Make.config b/Make.config index 840a61c..b00abc6 100644 --- a/Make.config +++ b/Make.config @@ -73,6 +73,13 @@ USEWOL = 1 USES = -DUSEUUID -DUSEMD5 -DUSELIBXML -DUSELIBARCHIVE -DUSEJSON -DUSEGUNZIP DEFINES += -D_GNU_SOURCE -DBINDEST='"$(BINDEST)"' -DTARGET='"$(TARGET)"' -DLOG_PREFIX='""' -DPLGDIR='"$(PLGDEST)"' $(USES) +CFLAGS_MEM = -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS \ + -fstack-clash-protection -fstack-protector-strong \ + -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now +CFLAGS_MEM += -fcf-protection=full -Wtrampolines + +# CFLAGS += $(CFLAGS_MEM) -O2 + ifeq "$(INIT_SYSTEM)" "systemd" SYSD_NOTIFY = 1 endifdas ist kein Fix hilft aber ggf. um dem Problem auf die Spur zu kommen.
-
Okay selbes Resultat also an den beiden Instanzen des Python Wrapper liegt es schon mal nicht.
m.E. wird (sofern es am epghttpd liegt, wovon ich ausgehe) etwas im Speicher überschrieben.
Komisch ist nur das Valgrind dazu nichts anzeigt.
Hast du mal versucht es mit FORTIFY oder Stack Protection übersetz? Ggf bringt das Licht ins Dunkel
-
Versuchs mal hiermit:
Diff
Display Moreroot@gate {master u=} ~/source/epgd> git diff lib/searchtimer.c lib/searchtimer.h diff --git a/lib/searchtimer.c b/lib/searchtimer.c index 4a958a4..902f41a 100644 --- a/lib/searchtimer.c +++ b/lib/searchtimer.c @@ -80,21 +80,21 @@ cSearchTimer::cSearchTimer(cFrame* aParent) lastSearchTimerUpdate = 0; - ptyRecName = new Python("recording", "name"); + // ptyRecName = new Python("recording", "name"); } cSearchTimer::~cSearchTimer() { - delete ptyRecName; + // delete ptyRecName; } int cSearchTimer::init(const char* confDir) { - if (ptyRecName->init(confDir) != success) - { - tell("Error: Init of python script recording.py failed, aborting"); - return fail; - } + // if (ptyRecName->init(confDir) != success) + // { + // tell("Error: Init of python script recording.py failed, aborting"); + // return fail; + // } return done; } @@ -784,19 +784,19 @@ int cSearchTimer::checkTimers() { // execute python - calc recording name - if (ptyRecName->execute(useeventsDb, namingmode, tmplExpression) == success) - { - if (!timerDb->hasValue("FILE", ptyRecName->getResult())) - { - parent->message(0, 'I', "EPGD: Timer action", "Calculated name of event (%ld) changed from '%s' to '%s', updating timer (%ld)!", - timerDb->getIntValue("EVENTID"), timerDb->getStrValue("FILE"), - ptyRecName->getResult(), timerDb->getIntValue("ID")); - - timerDb->setValue("FILE", ptyRecName->getResult()); - modifyTimer(timerDb, timerDb->hasCharValue("ACTION", taCreate) ? taCreate : taModify); - count++; - } - } + // if (ptyRecName->execute(useeventsDb, namingmode, tmplExpression) == success) + // { + // if (!timerDb->hasValue("FILE", ptyRecName->getResult())) + // { + // parent->message(0, 'I', "EPGD: Timer action", "Calculated name of event (%ld) changed from '%s' to '%s', updating timer (%ld)!", + // timerDb->getIntValue("EVENTID"), timerDb->getStrValue("FILE"), + // ptyRecName->getResult(), timerDb->getIntValue("ID")); + + // timerDb->setValue("FILE", ptyRecName->getResult()); + // modifyTimer(timerDb, timerDb->hasCharValue("ACTION", taCreate) ? taCreate : taModify); + // count++; + // } + // } } selectEvent->freeResult(); @@ -1352,14 +1352,14 @@ int cSearchTimer::createTimer(int id) { // execupe python - calc recording name - if (ptyRecName->execute(useeventsDb, namingmode, tmplExpression) == success) - { - tell(eloSearch, "Info: The recording name calculated by 'recording.py' is '%s'", - ptyRecName->getResult()); + // if (ptyRecName->execute(useeventsDb, namingmode, tmplExpression) == success) + // { + // tell(eloSearch, "Info: The recording name calculated by 'recording.py' is '%s'", + // ptyRecName->getResult()); - if (!isEmpty(ptyRecName->getResult())) - timerRow.setValue("FILE", ptyRecName->getResult()); - } + // if (!isEmpty(ptyRecName->getResult())) + // timerRow.setValue("FILE", ptyRecName->getResult()); + // } } // for 'event' based timers, check on failed attemps for this eventid diff --git a/lib/searchtimer.h b/lib/searchtimer.h index 66efd57..58b3eca 100644 --- a/lib/searchtimer.h +++ b/lib/searchtimer.h @@ -69,7 +69,7 @@ class cSearchTimer // data - Python* ptyRecName {}; + // Python* ptyRecName {}; cDbConnection* connection {};Ist nur ein Test um es einzugrenzen, keine Lösung. Dden epgd würde ich damit nicht tauschen nur den ephghttpd sonst hebelst du auch dort das generieren der Namen aus.
-
zumindest wissen wir nun das der Python Aufruf aus C++ funktioniert. Der Code dazu welchen der epghttpd verwendet ist der selbe.
Entweder etwas rundrum, zum Beispiel das der epghttpd zwei Instanzen davon verwendet oder ein ganz anderer Fehler welchen den Speicher vorher schreddert.
Vielleicht als nächstes die andere Stelle mal auskommentieren und schauen was dann passiert. -
pull mal die neuste Version aus dem git, wechsle in den lib Ordner und baue das pytst:
dann aufrufen (./pytst) und entsprechend der Usage Ausgabe verwenden.
Damit kannst du des Python Skript Aufruf aus dem c++ Code heraus testen. Wenn das geht liegt das Problem an anderer Stelle. Wenn es nicht geht müssen wir viel weniger Code debuggen. -
Bzw. welche Meldungen kommen bei Start nach Initialize python script?
-
ganz blöde Frage, die Meldung Cannot find function ... hast du nicht im Log des epghttpd ?
oder Failed to load ... ? -
Habs mir angesehen, leider bis jetzt noch nichts gefunden. Wenn ich mir einen Timer Namen über das Skript erstellen lasse bekomme ich:
CodeJun 4 15:20:12 gate epghttpd: Info: The recording name (mode=4) calculated by 'recording.py' is 'Spielfilm~Nachtschicht: Es lebe der Tod'Auch valgrind zeigt mir nichts auffälliges.
Kannst du es bei dir auch mal mit valgrind laufen lassen?
Welche python Version verwendet du, also von welcher Version ist das 'dev' Paket installiert? -
Am Plugin nichts das habe ich wie man bei github sehen kann 8 Monate nicht angefasst