Posts by SHF

    Crash 2 ist wieder mal der alte Bekannte cChannel::Name.


    Crash 1 müsste wieder in der Zeile mir caids = cString::sprintf("%s%d;", (const char*)caids, caid); sein. Nur da passt für mich die Aufruf-Reihenfolge.


    Interessant ist hier aber, dass es direkt nach einer Fehlermeldung geknallt hat (Zeile 1180):

    C++: tools.c
      if (!fmt || vasprintf(&buffer, fmt, ap) < 0) {
        esyslog("error in vasprintf('%s', ...)", fmt);
        buffer = strdup("???");
      }

    RHS Das wäre eventuell hilfreich, wenn Du die noch finden könntest.

    Da man an den Punkt eigentlich nie gelangen sollte, könnten die Informationen Aufschluss geben, was da schief läuft.



    Da die Crashs anscheinend recht schnell auftreten, wäre es möglich das mal nur mit einem KODI-Client zu versuchen?

    Das wäre mal interessant, ob die Crashs da auch auftreten.



    Irgendwie ist schon merkwürdig, dass die Fehler immer nur in dieser einen Funktion und im Zusammenhang mit den Channels auftreten.

    Das EPG wird durch ein sehr ähnliches Konstrukt eingelesen und da gibt es nie Ärger.


    Verwendet jemand zufällig das SAT>IP-Plugin in Verbindung mit ShowChannelNamesWithSource == 2 (Das ist mit Anzeige der SAT-Position.)?

    Nur um sicher zu stellen, dass es nicht daran liegt.

    Zum Testen sollte es reichen das zu aktivieren und die ein- zwei-mal die Kanalliste durch zu scrollen.

    Mit einer DVB-Karte werde ich es die Tage mal testen, aber mit SAT>IP kann ich es leider nicht.

    Vielleicht wäre es hier sinnvoller, std::swap zu verwenden, dann ist der Pointer in der queue definitiv leer und kann ohne Nebenwirkungen weg.

    Das klingt, als ob es ein brauchbarer Lösungs- oder Verbesserungsansatz wäre.

    (Das Konstrukt mit dem std::move aus einer Queue wird mehrfach verwendet.)

    Man müsste aber mal schauen, was das std::swap genau macht. Nachher sind es nur 3 moves und ein temporärer Pointer, dann hätte man nichts gewonnen.


    Die Objekte in der m_Queue sind auch intern ziemlich unterschiedlich. Es erben lediglich alle von ICommandSharedPtr. Das kann tückisch sein, was mit dem einen Objekt-Typ geht, kann beim Anderen zu Fehlern führen


    Ich hatte, ehrlich gesagt, aber noch gar nicht soweit gedacht, sondern erstmal nur versucht das vermutete, alte Verhalten zu emulieren.

    Und das mit möglichst wenig Aufwand und nachdenken, meine Freizeit ist halt leider auch begrenzt...

    Wenn es was gebracht hätte, hätte man ja weiter darüber nachdenken können, was da los ist.




    Der Fehler ist auch nach wie vor an etwa der gleichen Stelle, diesmal trifft es aber ein free().

    Interessant ist, dass es diesmal im Moveoperator von cString auftritt:

    Code
    #8  0x0000000000553c96 in cString::operator= (this=this@entry=0x23ddfe8, String=...) at tools.c:1111

    Wenn ich das this=this richtig interpretiere, ist es diesmal auch eine nicht abgefangene Selbstzuweisung gewesen.


    Wenn das stimmt, sollte man den Test nochmal wiederholen. Zusätzlich mit dem Patch aus #48 im VDR.

    Auch nach entfernen von responsepacket_realloc_3.diff.txt gibt es keine Warnungen mehr.

    Dann passt es ja.




    Auf der Suche, ob weiter "vorne" im Thread was falsch gelaufen ist, bin ich vielleicht auf was gestoßen:


    Gleich nach StartThread kommt immer dieses:

    Code
     #15 0x00007fe729ec4950 in cVNSIClient::Action (this=0x7fe700000ef0) at vnsiclient.c:103

    Der Code dazu:

    Man beachte besonders Zeile 99: Das ganze Objekt, mit dem wir es hier zu tun haben, wurde wurde mittels std::move "verschoben".

    Genauer gesagt, wird das Objekt aus der Liste heraus "kopiert" und das in der Liste dann gelöscht. Das std::move erlaubt es dem Compiler aber auch move operator/constructor dazu zu verwenden.


    Prinzipiell ist daran nichts auszusetzen, aber könnte das nicht die Verbindung zum neu eingeführten move constructor beim cString sein?

    Eventuell wurde bislang immer implizit eine Kopie von "Irgendwas" erzeugt und jetzt nicht mehr, was dann zu den Abstürzen führt?


    Wie genau da jetzt das cString vom VDR rein spielt, bin ich nicht sicher. Die Objekte vom Typ

    ICommandSharedPtr&, hier konkret cRequestPacket, enthalten aber einen String der Form uint8_t* userData. Instanziiert werden die fraglichen Objekte hier:

    C++: vnsiclient.c
    m_Queue.push_back( command );

    An beiden Stellen ist aber vdr/tools.h via #include <vdr/channels.h> verfügbar, es könnte also.


    Ausserdem gibt es im requestpacket noch so eine verdächtige, auskommentierte Funktion:

    C++: requestpacket.h
      // If you call this, the memory becomes yours. Free with free()
      //uint8_t* getData();

    Das sieht mir so aus, als ob da mal was angedacht war.


    Ich nehme jetzt einfach testweise mal das std::move raus, um die Kopie zu erzwingen. (Bitte auf den neueste GIT-Stand anwenden.)

    Mal sehen was passiert, der Compiler winkt das bei mir zwar ohne Beanstandungen durch, aber ob es wirklich geht bin ich echt nicht sicher.

    Das ist erstmal auch nur ein Versuch, eine echte Lösung wäre das sowieso noch nicht.

    #83 vnsiserver-gcc12.diff.txt

    Der sollte auf jeden Fall rein. (War aber in Beitrag #81 ;) .)

    Der Patch behebt nachvollziehbare Fehler auf nachvollziehbare Weise.


    Wobei letzterer Patch noch etwas wie "Testen ob es hilft" wirkt. Aber ich habe das im Post auch so verstanden das es genau darum erstmal geht. Um das Problem auf diese Stelle einzugrenzen.

    So ist es.

    Der Patch hätte die Ursache wenn nur durch Zufall behoben, hätte aber die Symptome (=Abstürze) beseitigen oder verringern können.


    Ich habe einfach einen großzügigen 80Byte-Puffer am Ende des Speicher-Blocks für das "responsepacket" eingefügt, so dass etwas Raum für Fehler bleibt.

    Des weiteren vergrößere ich den jetzt in Schritten zu 512Byte(+x), nicht wie bisher in mini Schritten (zB. 4Byte für einen hinzugefügten uint32_t). Das spart eine Menge realloc() Aufrufe in der for-Schleife.

    Zumindest eine dieser Maßnahmen hätte was gegen die Abstürze bringen können.


    Der Hintergedanke war:

    Die Speicherverwaltung versucht die Threads in getrennte Speicherbereiche zu legen, um globale mutex zu sparen und damit die Leistung zu steigern. Der "tcache" ist auch thredbezogen.

    Garantiert ist das zwar nicht, die Chance, dass ein Thread seine Speicherbereiche selbst zerstört sollte statistisch normalerweise aber höher sein, als dass es ein anderer Thread macht.

    Zumal es hier ja auch immer im gleichen Thread an fast der gleiche Stelle zu schlägt.


    Da das aber nicht geklappt hat, ist das "responsepacket" wohl erstmal raus.


    Also mit dem neuen Patch responsepacket_realloc_3.diff.txt und dem Patch aus #81 erhalte ich auch mit der Compiler Option -O3 keine Warnung mehr.

    Bitte nochmal nur mit dem Patch aus #81 probieren (nur ob die Warnung kommt reicht).


    An meinem kann das mit der Warnung nämlich eigentlich nicht liegen.

    (Ich wüsste zumindest nicht, wie ich das angestellt haben könnte :schiel .)

    Laut VLC Ausgabe komme ich damit auf minimal 520ms Verzögerung mit 50ms als Parameter.

    Bei 25Hz braucht man schon 1000 / 25 = 40ms pro Bild und ein halbes Bild zu puffern bringt nichts ;) .

    Du wirst mindestens 5-10 im Puffer brauchen, damit der einen Sinn macht.

    Die Patche lassen sich anwenden, ich erhalte aber dann folgenden compile ERROR:

    Beim responsepacket-Patch ist was durcheinander geraten, irgendwie hatte es die neueste Version nicht bis zum diff.txt geschafft.

    Wenn man alles umbenennen muss, um es anzuhängen, muss das wohl mal passieren, sorry.

    Ist jetzt oben aber korrigiert.


    der VDR crasht jetzt sofort beim start:

    Das ist eine Folge hier von:

    Code
    videoinput.c: In constructor ‘cDummyReceiver::cDummyReceiver()’:
    videoinput.c:439:21: warning: ‘cDummyReceiver::m_BeenDetached’ will be initialized after [-Wreorder]
      439 |   std::atomic<bool> m_BeenDetached;
          |                     ^~~~~~~~~~~~~~
    videoinput.c:440:72: warning:   base ‘cReceiver’ [-Wreorder]
      440 |   cDummyReceiver() : m_BeenDetached(false), cReceiver(NULL, MINPRIORITY) {}
          |                                                                        ^
    videoinput.c:440:3: warning:   when initialized here [-Wreorder]
      440 |   cDummyReceiver() : m_BeenDetached(false), cReceiver(NULL, MINPRIORITY) {}
          |   ^~~~~~~~~~~~~~

    Und das ist eine Folge des "videoinput-Patches", den also bitte nicht mehr anwenden!


    Ich hatte schon vermutet, dass man die Reihenfolge nicht einfach ungestraft ändern kann, bekam aber keine Warnung.

    Irgendwie war bei mir das "-Wall" Flag verschwunden und ich habe es nicht gemerkt. Jetzt habe ich die Warnung aber auch.


    Der Rest sind die bekannten Kandidaten, der Patch aus #81 fehlt vermutlich.


    Den nächsten Versuch bitte mit dem Patch aus #81 und dem (neuen!) responsepacked-realloc3 aus #115.

    Der aus #81 behebt die Warnungen und der aus #115 ist zum testen.


    Der Rest der Patches hat ja nichts gebracht, belastet IMHO also nur.


    Kann also gut sein, dass man das inzwischen gemacht hat und Warnung ab GCC Version 12.5 oder 12.6 verschwunden ist.

    Kann doch nicht sein, Version 12.4 ist noch nicht draußen. Fix ist aber dafür vorgesehen.

    Bei Version 13.2 kann es aber sein, da kann es zeitlich hin kommen.

    Leider konnte ich aber nichts genaueres finden. Die Suche nach der Bug-Nummer im GIT brachte auch nichts.

    Bin kein Programmierer, aber versucht doch einfach mal statt readlock zum Ursache finden die Channels zu duplizieren so dass jeder Thread seine eigene Kopie hat. Dann kann es ja keine doppelten Zugriffe mehr geben. Ist nur zum Fehler ausschließen, nicht für später.

    Die Kanalliste "gehört" dem VDR, um die lesen zu dürfen muss man sich einen readlock holen, sonst ist Chaos vorprogrammiert.

    Da sowohl die originale Variante, als auch die wirbel, als auch meine, das exakt gleich Verhalten zeigen, wird es am readlock selber wohl eher nicht liegen.


    Man könnte testweise den VDR so modifizieren, dass nur ein Thread readlock auf die Channels gewährt bekommt, das müsste vergleichbar einfach machbar sein.

    So würde dann nur noch einer der VNSI-Plugin-Threads gleichzeitig laufen.

    Die Änderung würde einiges durcheinander werfen, was das gesamte Timing im VDR betrifft. Unter Umständen geht damit dann gar nichts mehr.


    [...] (war doppelt)

    writing 1 byte into .... und cc1plus : dest... is likely at address zero.


    geben diese compiler Warnungen nicht Hinweise auf das Fehlverhalten?

    Leider nicht.

    Das ist auch an einer völlig anderen Stelle, der Code wird hier gar nicht verwendet.


    ich hab jetzt mal mit -O0 übersetzt, dann gibt es bei mir auch keine warnings ebenso keine mit

    -Wno-stringop-overflow
    . Es crasht dennoch:

    Dass es mit der Optimierung zu tun hat, habe ich schon öfters gelesen.

    Vermutlich liegt es am am inlinen, das dürfte -O0 nicht machen.


    Die Warnung ist aber generell wohl fehlerhaft, wenn man den GCC-Entwicklern trauen kann.

    (Siehe Link in #69.) Die sind sich da auch einig, dass man die Warnung entfernen will.

    Kann also gut sein, dass man das inzwischen gemacht hat und Warnung ab GCC Version 12.5 oder 12.6 verschwunden ist.


    Generell ist dieses Konstrukt aber eher speziell (leerer Constructor dafür eine Initialisierungsliste), einen auffälligen Fehler sehe ich aber nicht.

    Man könnte mal versuchen die Reihenfolge in der Initialisierungsliste zu tauschen, vielleicht bringt das was. Patch im Anhang.(Entfernt, da es nicht funktioniert hat!)


    #1 0x00007f9fe0041176 __GI_raise (libc.so.6 + 0x41176)

    #2 0x00007f9fe0028917 __GI_abort (libc.so.6 + 0x28917)


    heißt aber AFAIK, dass das geplant aborted wurde, also dass ggf. das kaputt ist, was in den vasprintf gesteckt wurde.

    Prinzipiell richtig, nur kommen die Meldung vom *alloc() nicht vasprintf(), wie wirbel auch schon geschrieben hat.


    Der Beitrag hat mich veranlasst mir endlich mal malloc() näher anzusehen, das hätte ich früher tun sollen...


    Die Fehlermeldung malloc(): unaligned tcache chunk detected kommt von hier: malloc.c:3183

    Wie man unschwer sieht, kommt die, wenn mit dem Zeiger auf den Speicherbereich etwas nicht stimmt.

    Nach dem "Durchklicken" einiger der Links, sieht es mir so aus, als ob das beim anfordern eines neuen Speicherblocks passiert und die Safe-Linking Pointer Protection anschlägt.

    100% sicher bin ich da zwar nicht, die Ursache müsste aber immer sein, dass jemand ausserhalb seines angeforderten Speichers etwas geschrieben hat.


    Der Tcache enthält kürzlich freigegebene Blöcke und ist Thread bezogen, jeder hat seinen eigenen.

    Ob man daraus aber schlussfolgern kann, dass der Übeltäter im gleichen Thread sitzt, bin ich nicht sicher.


    Wenn man nach "tcache" sucht findet man, dass es auch Attacken darauf gibt.

    Ich denke, unser Fehler besteht schon lange, fällt aber erst jetzt durch eine neu eingeführte Abwehrmaßnahme auf.


    Primär verdächtig ist alles was mit dynamischer Speicherverwaltung (malloc() und Co.) zu tun hat.

    Die Funktionen von cResponsePacket machen das dauernd.

    Ich habe da mal etwas Puffer eingebaut und hole den Speicher in größeren Blöcken. Das löst das Problem zwar nicht, sollte die Wahrscheinlichkeit für einen Crash aber senken.

    Wenn es mit den Patch besser wird, weiß man also wenigstens, wo man suchen muss.

    Ihr könnt ja mal mit grep nach setlocale im vnsiserver suchen.

    Weder setlocale noch locale gibt es.


    Vielleicht sind es cString::sprintf() und cString::vsprintf(), die nicht threadsafe sind.

    Nach einigem nachdenken habe ich aber keinen kritischen Fall gesehen (was aber nicht heissen muss).

    Auf der Kanalliste ist der Readlock, die sollte sich nicht ändern, solange diese for-Schleife läuft.

    Und sonst wird nichts mit anderen Threads ausgetauscht - zumindest nicht offensichtlich.


    Ich habe aber mal grob überschlagen, dass bei einem Durchlauf der for-Schleife cString::sprintf() oder ein Äquivalent zwischen 10 und 20 Mal aufgerufen werden. Praktisch jeder ausgeführte Befehl mach mindestens einen Aufruf, manche gleich mehrere.

    Es könnte auch gut eine Frage der Statistik sein, dass es meist cString::sprintf() trifft.


    Dann verwenden noch die Funktionen von cResponsePacket dynamische Speicherverwaltung. Eine üble Rechnerei mit Puffergrösse, verbrauchtem Puffer usw.

    Gesehen hab ich zwar nichts auffälliges, aber würde mich nicht wundern, wenn man sich da irgendwo +-1 verrechnet hat.

    Da muss ich morgen noch mal ausgeschlafen genauer schauen :gaehn .




    Einiges, was in der Schleife gemacht wird ist IMHO für den Betrieb nicht lebensnotwendig.

    Wenn man Lust hat, könnte man mal versuchen möglichst viel zu deaktivieren, um die Suche einzugrenzen:

    Wahrscheinlich wird es bei einem oder mehreren der 4 makierten Blöcke irgendwelche Probleme geben.

    Da muss man Probieren, was unbedingt gebraucht wird und was nicht.

    Genau die gleiche Idee. Die macros machen auch nicht viel anderes.

    Inzwischen habe ich da etwas mehr Überblick und im Endeffekt sollten alle 3 Varianten in diesem Fall aufs selbe hinaus laufen.


    Wollen wir mit deinem oder meinem Patch weitermachen?

    Mir egal, Hauptsache gleicher Code und es ist absolut sicher, dass der Lock aus dem Spiel ist.

    Mir auch völlig egal.

    Ich hatte es eigentlich nur angehängt, da ich es eh rum fliegen hatte.

    Soll doch der Maintainer entscheiden, was er für besser zu pflegen hält.



    Inzwischen bin ich aber relativ sicher, dass der Lock nicht die Ursache für den Crash ist, sonder den ganzen Prozess nur in Gang setzt.

    Bislang hatte ich vermutet, dass der Neustart das Einlesen der Kanalliste auslöst, das scheint aber nicht so zu sein.


    Das zwei Prozesse gleichzeitig einen Readlock auf die Kanalliste bekommen, müsste prinzipiell auch funktionieren. Und die Formulierungen deuten für mich auch darauf hin, dass mehrere Prozesse gleichzeitig einen Readlock auf eine Liste haben können.



    Der Ablauf müsste folgender sein:

    Der VDR ändert die PID eines Kanals und gibt die Kanalliste wieder frei. Dabei wird der Statekey auch korrekt inkrementiert.

    Das merkt jetzt das vnsiplugin und gibt das an die KODIClients weiter. Der Code dazu steckt in status.c, die ganze Datei dient nur dazu die Listen des VDR auf Änderungen zu überwachen.

    Die Clients holen sich dann jeweils die neue Kanalliste vom Plugin. Und das startet dann processCHANNELS_GetChannels, ehe die Daten an die Clients geschickt werden.


    Einen Einfluss des Neustarts kann ich momentan zwar nicht 100% ausschließen, aber da das Problem auch zur Laufzeit auftritt, lasse ich das hier mal gut sein.


    Zum Zeitpunkt der Crashs laufen eigentlich auch nur die beiden for-Schleifen in processCHANNELS_GetChannels. Praktisch alle anderen Prozesse stehen bei einem "wait" oder "poll" das heisst, die tun eigentlich nichts und warten nur.

    Der Fehler müsste IMHO also in irgend einem Code-Schnipsel liegen, der in der for-Schleife ausgeführt wird.


    crash um 23:19:27

    Da hat es mal nicht den Prozess, der in channel->Name() steckt erwischt. (Womit sich meine Frage nach der Zeilennummer erübrigt.)


    Vielleicht sind es cString::sprintf() und cString::vsprintf(), die nicht threadsafe sind.

    Das will ich mal nicht hoffen, das würde eine Katastrophe nahe kommen :angst .

    Aber evtl. ein Bug in der GLIBC?


    @Zeilennummern

    Danke für den Tipp, das schaue ich mir mal an.

    An Anfang hatte ich auch mal überlegt, das StateKey-Geschichte komplett durch die "convenience macros" zu ersetzen. (Primär um sich das nicht näher ansehen zu müssen ;) )

    In vnsiclient.c ging es zwar, in status.c bin ich mit den Konzept aber gescheitert und habe es deshalb nicht weiter verfolgt. Im Anhang trotzdem mal die Änderungen in vnsiclient.c.

    Am Problem ändern wird das aber ziemlich sicher nichts.


    Vielleicht versteht man dann besser was da passiert.

    In dem zweiten Coredump sieht man doch mehr als bisher, man muss nur mal genau lesen...


    Beide Threads von cVNSIClient::processCHANNELS_GetChannels haben den Readlock bekommen, oder sie verhalten sich zumindest so.


    Der Eine hängt Zeile 1185 in VNSIChannelFilter.PassFilter(*channel). (Da gibt es nur die eine Zeile, die in Frage kommen könnte.)


    Der Zweite "böse" hat mal wieder mit channel->Name() einen Chrash ausgelöst.

    Beim Suchen der Zeile ist mir Aufgefallen, dass zwei in Frage kommen könnten: 1181 und 1190.

    Jetzt wäre mal interessant, ob es wieder in 1181 war.

    Die Zeilennummern konnte ich in lesbarer Form nicht erkennen, bekommt man die irgendwie auch noch raus?

    Auffällig ist auch, dass zwei threads in der gleichen Funktion cVNSIClient::processCHANNELS_GetChannels sind.

    Endlich sieht man das mal, vermutet hatte ich das schon die ganze Zeit.

    Grundsätzlich ist daran aber, bei zwei Clients, nichts auszusetzen.


    Daher auch der Vorschlag sich das Locking mal anzusehen. Vielleicht versteht man dann besser was da passiert.

    Zu: warning: loop variable ‘i’ creates a copy from type...


    Dazu, mir das wirklich mal anzusehen, war ich bislang nicht gekommen, aber ich hatte mal nach so ähnlichen Stellen gesucht.

    Da kamen dann noch 2 weitere, die keine Warnung verursacht hatten:

    channelfilter.c Zeile 222

    vnsiclient.c Zeile 1410

    Eigentlich müsste da das "&" auch Sinn machen, meine ich, es sei denn std::set mal wieder irgend ein Sonderfall.

    Ohne das wirklich verstanden zu haben, wollte ich da aber besser nichts ändern

    Damit kann das Problem weiter eingeengt werden

    gcc > 11.1.0 && gcc <= 12.3.0

    Wenn man nach diesen Warnungen sucht, findet man auch immer, dass die mit dem 12er Zweig, also 12.0.0 anfingen. Von daher deckt sich das.

    Im Changelog steht auch zu einigen der Warnungen, dass die "optimiert" wurden. Aber das sind ja letztendlich lediglich Hinweise, dass da was seien könnte und bislang hat es ja so funktioniert.

    Einen echten Grund, warum es aber diese Probleme gibt, habe ich beim überfliegen nicht gesehen.

    Vielleicht sieht ja jemand anderes mehr.


    responsepacket.c, status.c,vnsisocket.c


    und dann;


    hash.c vnsitimer.c, vnsisocket.c

    Letztendlich sind es aber immer die 3 gleichen Stellen, die die Warnung auslösen.

    Das deutet stark darauf hin, dass die dem GCC nicht gefallen.


    Warum das von unterschiedlichen Dateien getriggert wird, weiß der Geier.

    Eventuell liegt es einfach an der Reihenfolge der Bearbeitung?


    Interessant ist auch, dass die Änderung aus #70 anscheinend keinen Einfluss hatte.


    Code
    streamer.c: In constructor ‘cLiveStreamer::cLiveStreamer(int, bool, int, uint8_t, uint32_t)’:
    streamer.c:57:17: warning: member ‘cLiveStreamer::m_Event’ is used uninitialized [-Wuninitialized]
       57 |  , m_VideoInput(m_Event)
          |                 ^~~~~~~

    Zu -Wuninitialized steht was im Changelog (s.o.).

    An der Warnung könnte prinzipiell was dran sein, uninitialisierte Variablen/Objekte können derartige Abstürze auslösen.

    Die Warnung warnt auch vor allen möglichen potenziellen Problemen, die aber nicht auftreten müssen, wenn man es richtig macht.

    Und da es bislang ja funktioniert hat ...


    Neu ist in GCC 12 übrigens dieses Stück in der Dokumentation dazu:

    Quote

    In C++, this warning also warns about using uninitialized objects in member-initializer-lists. For example, GCC warns about b being uninitialized in the following snippet:

    Code
    struct A {
      int a;
      int b;
      A() : a(b) { }
    };


    Code
    channelfilter.c: In member function ‘void cVNSIChannelFilter::StoreWhitelist(bool)’:
    channelfilter.c:188:23: warning: loop variable ‘i’ creates a copy from type ‘const cVNSIProvider’ [-Wrange-loop-construct]
      188 |       for (const auto i : *whitelist)
          |                       ^
    channelfilter.c:188:23: note: use reference type to prevent copying
      188 |       for (const auto i : *whitelist)
          |                       ^
          |                       &

    Irgendwie sieht es mir so aus, als ob das ein beliebter Anfänger/Flüchtigkeitsfehler ist.

    Die neue (ich habe noch C++2003 gelernt) Syntax mit dem "auto" ist zwar schön kompakt, was IMHO aber zu so Fehlern einlädt. Das fehlende "&" übersieht man einfach gerne mal.

    Daher wohl die Warnung.


    Die Kopie ist, von der Performance, Spericherverbrauch, ... zwar nicht ideal, ein wirkliches Problem dürfte das in den meisten Fällen aber wohl nicht auslösen, denke ich.


    Und in unserem Fall bin ich momentan nicht mal sicher, ob das nicht Absicht so war.



    Den letzten von den Fehlern hatten wir ja schon und da wird da wird behauptet, dass es ein "false positive" ist.

    Könnte mir jemand bei der Menge der Testvorschläge die Varianten etwas strukturieren, ich blicke derzeit nicht genau wie was mit einander wechselwirkt.

    So wirklich blickt hier wohl keiner durch was wie wechselwirkt, daher auch die vielen unterschiedlichen Testvorschläge um das Problem einzugrenzen.

    Ich werde es aber mal versuchen mit dem Stukturieren.


    Ausgangslage ist:

    VDR 2.6.6, GCC 7.5.0: keine Fehlermeldungen und keine Abstürze.

    VDR 2.6.6, GCC 13.2.1: Fehlermeldung und praktisch sofortiger Absturz.

    VDR 2.6.6, GCC 13.2.1 ohne Move-Operator/Constructor: Fehlermeldung und Abstürze, aber seltener.

    Richtig?


    Der Move-Operator/Constructor hat großen Einfluss auf die Speicherbelegung.

    Ohne entstehen durch die temporären Objekte, die gleich wieder gelöscht werden, viel mehr "Lücken".

    Das dürfte erklären, warum es ohne besser wird. Wenn man so eine "Lücke" nach dem problematischen Bereich liegt, fällt der Fehler nicht unbedingt auf.


    Zum weiteren Testen macht eigentlich nur die Version VDR 2.6.6, GCC 13.2.1 (mit Move-Operator/Constructor) Sinn, man will ja was sehen ;) .

    Es macht auch erstmal keinen Sinn die Tests zu kombinieren, das verwirrt einen nur, daher immer schön einzeln.


    Man könnte auch mal probieren das Aktualisieren der Kanäle in VDR ganz ab zu stellen (setup.conf UpdateChannels = 0).

    Der Test ist einfach, Änderungen am Code sind nicht nötig:

    Sicherstellen, dass ein Crash eintritt.

    VDR stoppen (wichtig!).

    setup.conf ändern.

    VDR starten und schauen, ob es erneut zum Crash kommt.


    Habe deinen Vorschlag #70 mal eingebaut in videoinput.c insgesamt erhalte ich folgende Warnings in vnsiserver:

    [...]

    diese sehen, glaub ich, leicht anders aus als vorher

    Der Test ist also erstmal schon erledigt.


    Die ersten zwei Warnungen sind neu, ich verstehe die aber noch nicht so ganz.

    Besonders die Zweite. Warum ist das erst jetzt ein Problem???


    Die Dritte sieht leicht anders aus, scheint aber der Ursprünglichen weitgehend zu entsprechen.

    Die Unterscheide können in den Compilereinstellungen liegen, die sind leicht unterschiedlich.




    Apropos Compilereinstellungen, da könnte man mal -O1 und -march=x86-64 (ist doch eine x86 64Bit CPU?) anstelle von -O3[tt] und -march=native[/tt] versuchen.

    Es könnte sein, dass der neue GCC es bei der Optimierung generell (-O_) etwas "übertreibt".

    -march=native erlaubt spezifischere Optimierungen für die verwendete CPU, da besteht die Chance, dass da Bugs drin stecken. Distributionen verwenden "x86-64" oder was vergleichbares, damit die Pakete allgemein kompatibel sind, native für exakt Deine CPU ist also wenig getestet.

    Auch wieder als frischer Test, ohne weitere Änderungen. Einfach schauen, ob es auch so auch crasht.


    Ich habe das DEBUG_LOCKING versuchsweise aktiviert, leider schreibt vdr mir dann den syslog mit lock/unlock Meldungen voll. Der crash ist so nicht weiter einzugrenzen.

    Dass da etwas mehr zusammen kommt, hatte ich schon erwartet. Das sind die Meldungen von allen Locks, Channels, Timers, EPG...

    Ich hatte nur die Hoffnung, dass es noch im Rahmen bleibt und der Syslog das bewältigt, das wäre übersichtlicher gewesen.

    Eine getrennte Logfile geht aber auch, wie Du das bei SUSE umleitest, musst Du aber selber mal schauen.


    Die (un)lock Meldungen sollten die pid/tid des verursachendem Prozesses enthalten.

    Diese sind auch in den Syslog-Meldungen enthalten:

    [...] vdr[1987]: [11772] VNSI Client[...] thread started (pid=1987, tid=11772, prio=high)

    [...] vdr[1987]: [1995] changing pids of channel 4[...]

    (Die 1987 ist die pid des VDR Hauptprozess.)

    So sollte man die Meldungen den Prozessen zuordnen können.

    (Die pids der channels haben damit übrigens gar nichts zu tun, heissen nur zufällig gleich.)


    Relevant sind wahrscheinlich auch nur die letzten 10-20 (un)locks vor dem Crash.

    Also etwa ab dem changing pids evtl noch ein paar davor.

    Und wenn das "writing 1 byte into a region of size 0 overflows the destination" ein Compilerfehler ist?

    Da ist wohl wirklich ein Bug im GCC, aber im Sinne eines false positives:

    108374 – [12/13/14 Regression] unexpected -Wstringop-overflow when using std::atomic and std::shared_ptr

    In dem Fall geht es auch um weakPointer, sieht nahezu identisch aus.

    Ich hoffe die haben mit ihrer Einschätzung recht :schiel .


    Wobei das schon komisch wäre wenn Plugins, die da bisher keine Probleme hatten, jetzt Locking Fehler werfen.

    Wirkliche Fehler müssten jetzt schon im Log landen. Entsprechende Ausgaben sind jetzt schon aktiv und davon gibt es auch reichlich.


    Wenn muss es da was subtileres sein. Deshalb auch die Frage mit dem StateKey.Remove.

    Könnte es Probleme verursachen, wenn man was ändert und den state nicht inkrementiert?

    Ich bin da momentan nicht sicher, ob das was macht, oder nicht. So weit habe ich mich noch nicht "durch gebuddelt".


    Durch das DEBUG_LOCKING sollte man zumindest sehen, wann auf was Locks gesetzt werden, vielleicht sieht man dadurch irgendwelche Zusammenhänge.

    Momentan sieht man aus dem Log eigentlich nur, dass sich zwei VNSI-Clinets verbinden und dann kommt schon die Crash-Sequenz.

    Durch die Locks müsste man besser nachvollziehen können, worauf das Plugin zugreift.


    Man könnte auch mal probieren das Aktualisieren der Kanäle in VDR ganz ab zu stellen (setup.conf UpdateChannels = 0).

    Das wäre durchaus interessant, ob und wann es dann zum Absturz kommt.

    Wenn das Aktualisieren der PIDs die Ursache für den Absturz ist, sollte der dann nicht mehr auftreten.

    Wenn es an was anderem liegt, dann wo anders.

    So wie es aussieht scheint der Move-Operator/Constructor nicht die Ursache zu sein.

    Dazu wird er IMHO einfach zu oft aufgerufen, da müsste es auch anderswo krachen.

    Uns auch die Selbstzuweisung ist inzwischen ausgeschlossen.


    Auffällig ist, dass es vor dem Crash eine Änderung an der Kanalliste gab, auf die das Plugin gerade zugreift.

    Ist das Immer der Fall?


    Eigentlich sollte doch allein das korrekte setzen der Locks auf die Liste, die Zugriffe darauf threadsave machen?

    Und damit da eigentlich auch jegliche Timing-Effekte ausschließen.


    Auffällig ist aber halt, dass die Änderung der PIDs ziemlich direkt vor dem Crash kam.

    Fehler sehe ich da auch weder im Plugin, noch im VDR.

    Allenfalls diese Zeile in pat.c:

    847 StateKey.Remove(ChannelsModified);

    Was würde denn passieren, wenn ChannelsModified versehentlich false wäre, obwohl was geändert wurde?

    Das müsste man doch eigentlich testweise einfach mal auf true setzen können, ohne dass es eine Katastrophe gibt?


    Könnte es in diesem Fall was bringen die debug_locking zu aktivieren?

    (Zeile 29 thread.c)

    29 //#define DEBUG_LOCKING // uncomment this line to activate debug output for locking

    Na, das ist ja mal Schwarzmalerei ... klar kannst aus dem Haus gehen und von einem Meteoriten getroffen werden ... :rolleyes:

    Die Ausfallwahrscheinlichkeit ist bei einem neuen Produkt am höchsten.

    Das ist keine Schwarzmalerei, sondern anerkannte Statistik!

    Siehe: Badewannenkurve

    Die Zeitachse ist typischer weise logarithmisch, der Anstieg am Ende ist in Wirklichkeit also sehr viel flacher als er erscheint!


    Genau aus diesem Grund existiert auch die gesetzliche Gewährleistung. Der Gedanke dahinter:

    Einzelne Kunden soll nicht auf den bekannten, aber unvermeidlichen Frühausfällen sitzen bleiben.


    Dieses Verhalten ist auch logisch, wenn man sich überlegt wie technische Produkte hergestellt werden.

    Bei einem Netzteil werden die Platinen zuerst bestückt, fahren dann durch ein Lötbad und werden danach ins Gehäuse geschraubt. Das passiert alles am Fließband und der Arbeiter hält jedes einzelne Teil allenfalls ein paar Sekunden in der Hand, sonst würde das Produkt unbezahlbar.

    Abschließend folgt dann noch ein Funktionstest: Stecker rein, einschalten und wenn es geht, kommt es in die Verpackung, fertig. Anderenfalls muss nach gearbeitet werden.

    Bei hochwertigeren Netzteilen gibt es zwischen drin vielleicht noch eine Kontrolle der Lötstellen und Platine mittels Kamera und der Funktionstest belastet das Netzteil einige Minuten mit der Nennlast. Auch wird die Produktion stichprobenartig überprüft werden.

    Im Grunde genommen macht der Kunde aber immer die eigentliche Endkontrolle, das wäre anders auch nicht zu bezahlen.

    Das gilt so für eigentlich alle technische Produkte, die industriell hergestellt werden. Ausnahmen sind vielleicht Produkte für erhöhte Anforderungen wie industrieller Einsatz, medizinische Geräte und dergleichen.



    Wenn ich jetzt ein bekanntes, einwandfrei funktionierendes, Netzteil grundlos gegen ein neues austausche, steigt die Ausfallwahrscheinlichkeit des Gesamtsystems Computer also erstmal für eine Weile an.

    (Für mich als Techniker ist es immer faszinierend, wie die Maketingabteilungen es geschafft haben, die Kunden vom Gegenteil zu überzeugen ;) .)


    Gibt Leute, die stehen nicht auf Datenverluste und unerklärliche Abstürze. ;)

    Das ist mir letztens auch passiert, der Computer schaltete einfach sporadisch ab. Anfangs nur sehr kurz, so dass es etwas gedauert hat, die Ursache zu finden.

    Am Ende war das Netzeil, mein insgesamt neuestes wohlgemerkt! An sich ein hochwertiges Marken-Gerät, 80+ Platinum, knapp ein Jahr alt und nicht billig.

    Manchmal erwischt es einen halt, da kann man nichts machen. Wurde zum Glück anstandslos getauscht.


    Meine anderen PC-Netzteile sind, mit einer Ausnahme, übrigens inzwischen zwischen 9 und 12 Jahren alt und noch immer täglich problemlos im Einsatz.



    Bislang waren Wir am linken Rand der Badewanne, jetzt der Blick nach rechts und der Frage, wann das Gerät alt ist.

    Dazu muss man das Alterungsverhalten kennen und was es beeinflusst, einfach eine Jahreszahl zu sagen ist schlicht unseriös. Da kann man je nach Einsatzbedingung weit daneben liegen, in beide Richtungen!


    Bei Netzteilen und den meisten anderen Elektronik-Geräten sind die Elektrolytkondensatoren (Elkos) die Lebensdauer bestimmenden Bauteile. Deren Lebensdauer ist leider extrem temperaturabhängig.

    Grob abschätzen kann man das mit der 10-Grad-Regel, die besagt, dass eine um 10°C verringerte Temperatur die Lebensdauer verdoppelt.

    Je nach Kühlung (+-20°C) kann sich die Lebensdauer also locker um den Faktor 4 oder mehr unterscheiden.

    Dann spielt natürlich die Qualität der Elkos und wie knapp sie ausgelegt wurden eine Rolle.


    Wenn man ein hochwertige Netzteil verbaut hat und es immer schön Luft bekommt, würde ich mir jedenfalls keine Sorgen machen.

    Wenn der Hersteller mehrere Jahre Garantie gibt, wird man selbst unter ungünstigen Bedingungen (grenzwertig warm und hohe Last), da immer noch unten auf dem "Boden" der "Wanne" sein, weit vom Anstieg entfernt (alles andere könnte für den Hersteller teuer werden). Das dann mal 4 ....

    Klar, das Netzteil kann in den nächsten zB. 5 Jahre ausfallen, das kann das neue aber auch. Und ich würde mich nicht wundern, wenn die Wahrscheinlichkeit, inklusive Einlaufphase, beim Neuen sogar höher ist.


    Passieren wird bei einem Netzteildefekt ziemlich sicher nichts weiter.

    PC-Netzteile haben seit Jahren entsprechende Schutzeinrichtungen verbaut. Zumindest die Besseren.

    Details wurden hier ja schon geschrieben.


    PC-Netzteildefekte hatte ich, bis auf diesen einen, auch noch keine.

    Ausgetauscht habe ich funktionsfähige PC-Netzteildefekte bislang nur wegen unzeitgemäßem Verbrauch bei geringer Last. (Wenn von den 45W die der Computer im Leerlauf braucht nur 15W auf die eigentlichen Komponenten entfallen und der Rest aufs Netzteil, kann man schon mal darüber nachdenken.)




    Konkret empfehlen möchte ich kein Netzteil, da ändert sich einfach zu häufig was und die Anforderungen sind zu verschieden.

    Generell würde ich aber nur Netzteile von namhaften Herstellern kaufen, die auf den Gebiet schon länger tätig sind. Und dann auch nicht die billigste Serie.

    Bei einem Rechner der viel läuft, würde ich die Auswahl auf "Gold" oder besser beschränken. Da gibt es mit 450W mehrere, die in Frage kämen, auch beQuiet!, wenn man das will.


    Vorsichtig wäre ich bei Billigen-Angeboten und Netzteilen, die bei Gehäusen dabei sind.

    Da wird gerne an allem gespart, das rächt sich irgendwann.

    Ich habe da schon schlechte Erfahrungen gemacht.



    Wieviele USB-Wandwarzen aus der MicroUSB-Ära >2018 sind denn noch im Einsatz?

    Bei den Netzteilen selber hatte ich auch noch keine Defekte. Und dabei habe ich mehr von den Dingern, als mir lieb ist ;) .

    Bei den MicroUSB-Kabeln dagegen schon einige.


    Bei diesen Klein-Netzteile gibt es ziemliche Qualitätsunterschiede.

    Es gibt welche mit anständigen Ein- und Ausgangsfiltern und einem Controller-IC mit allem Pipapo wie Überspannungs und Temperaturschutz.

    Dann so gruselige Konstruktionen, die mit nur einem Transistor und ein paar passiven Bauteilen auskommen, wo man sich wundert, wie die es geschafft haben, dass da eine definierte Ausgangsspannung raus kommt.

    Und oft korrespondiert der Qualitätsunterschied nicht mal mit dem Verkaufspreis.

    Hier ist diese Absicherung auch drin: https://www.geeksforgeeks.org/…nment-operator-in-cpp-11/

    Danke, das ist der eine Artikel, in dem ich es gesehen hatte.

    Ich dachte, es war bei cppreference.com gewesen, da es dann natürlich nicht wieder finden...


    Ich bin beim Suchen dann immer nur auf den Folgenden gestoßen :versteck :

    learn.microsoft.com: Bewegungskonstruktoren und Bewegungszuweisungsoperatoren (C++)

    Da wird sogar zwei mal explizit davor gewarnt.



    Wann diese Selbstzuweisungen auftreten, würde mich auch mal interessieren.

    Unter Umständen ist es aber gar nicht so selten.

    Selbst was triviales wie a = a+x; könnte bei x == 0 ja theoretisch irgendwie dazu werden.

    Kann es sein, dass da ein

    Code
    if (this == &String)
        return *this;

    oder vergleichbares fehlt?


    Nicht, dass ich das wirklich beurteilen könnte, ich bin nur beim rekapitulieren zufällig über den Hinweis gestolpert.

    Und die anderen Operatoren haben das auch drin.