Externe Bibliothek buggy?



  • Wenn es was internes ist, dann hast du ja die Moeglichkeit in die Implementation zu schauen.



  • Nein. Es ist nichts internes unserer Firma hier. Aber es ist nichts öffentliches.
    Ich habe einige *.so's, einige *.dll's und ein paar Header-Dateien.

    Und glaub mir, wenn wir da an die Interna drankämen, wäre das ganze Ding schon neugeschrieben, damit es nicht nur mal läuft sondern auch Fehler überhaupt mal meldet (aber das ist 'ne andere Geschichte).

    Aber um es mal beim Namen zu nennen, es geht um den Elster Rich Client (ERiC 18.1.4.65766) und die Handles sind RueckgabepufferHandle's (ja, es ist eine deutsche Bibliothek)



  • Mir fällt auf, dass HandleContentLength 0 zurückgibt, vielleicht darfst du in dem Fall HandleContent gar nicht aufrufen? Sagt die Doku irgendwas dazu? Oder tritt der Fehler immer auf, auch wenn HandleContentLength einen Wert >0 zurückgibt?

    Edit:
    Ist das der gleiche Verein, der auch den Bundestrojaner programmiert hat? 😃
    *Duck und weg*



  • Gibt die Länge des Inhalts eines Rückgabepuffers zurück.
    Die zurückgegebene Zahl entspricht der Anzahl von Bytes, die von einer zuvor aufgerufenen ERiC
    API-Funktion in den Rückgabepuffer geschrieben wurden. Die Null-Terminierung, die bei Aufruf von
    EricRueckgabepufferInhalt() an das zurückgegebene Character-Array angefügt wird, wird bei dieser
    Längenangabe nicht berücksichtigt.

    Parameter:
    in : Handle auf einen mit EricRueckgabepufferErzeugen() angelegten
    Rückgabepuffer. Dieser Rückgabepuffer darf nicht bereits
    freigegeben worden sein.

    Rückgabe:
    - Bei Übergabe eines gültigen Handles: Anzahl der in den Rückgabepuffer geschriebenen Bytes
    - Bei Übergabe des ungültigen Wertes NULL: 0



  • Skym0sh0 schrieb:

    Gibt die Länge des Inhalts eines Rückgabepuffers zurück.
    Die zurückgegebene Zahl entspricht der Anzahl von Bytes, die von einer zuvor aufgerufenen ERiC
    API-Funktion in den Rückgabepuffer geschrieben wurden. Die Null-Terminierung, die bei Aufruf von
    EricRueckgabepufferInhalt() an das zurückgegebene Character-Array angefügt wird, wird bei dieser
    Längenangabe nicht berücksichtigt.

    Parameter:
    in : Handle auf einen mit EricRueckgabepufferErzeugen() angelegten
    Rückgabepuffer. Dieser Rückgabepuffer darf nicht bereits
    freigegeben worden sein.

    Rückgabe:
    - Bei Übergabe eines gültigen Handles: Anzahl der in den Rückgabepuffer geschriebenen Bytes
    - Bei Übergabe des ungültigen Wertes NULL: 0

    Und hast du getestet, ob das stimmt? Insbesondere wenn size 0 liefert?



  • Also wenn ich die Länge des nullptr abfrage kommt wie dokumentiert auch 0 raus.

    Greife ich auf irgendeine Speicheradresse zu crasht es (wie eigentlich erwartet), irgendwelche Checks macht ERiC also nicht.

    Also ich denke, ich habe die Spezifikationen dieser Doku schon getestet. o_O

    Was meinst du genau?

    DocShoe schrieb:

    Ist das der gleiche Verein, der auch den Bundestrojaner programmiert hat? 😃
    *Duck und weg*

    Offensichtlich nicht, denn der Bundestrojaner hat doch halbwegs funktioniert, wenn ich mich recht erinnere 😃
    Aber laut Wikipedia kommt der Bundestrojaner von der Digi Task GmbH im Auftrag der Bayerischen Staatsregierung. Und ERiC kommt auch aus Bayern (Steueramt oder Finanzamt oder sowas). Mh, ich frag mal grad die Illuminanten.....



  • Skym0sh0 schrieb:

    Also wenn ich die Länge des nullptr abfrage kommt wie dokumentiert auch 0 raus.

    Spannend wird es ja erst bei der Umkehrung. Evtl. ist der zugriff auf HandleContent() ungültig, wenn HandleContentLength()==0 - auf jeden Fall ist er überflüssig.

    Allerdings verstehe ich das hier:

    Skym0sh0 schrieb:

    Das Problem, auch bei meinem großen Programm, wo diese Dinger drin eingearbeitet waren, und auch wirklich nachprüfbar was in den Puffern stand und extrahiert wurde nach string, crashte es bei Rücksprung aus der Funktion zum Aufruf.

    (so unverständlich es auch geschrieben sein mag)
    dahingehend, dass auch bei HandleContentLength()!=0 der Wrapper crasht.
    Richtig?



  • Ja



  • Also wenn ich die Länge des nullptr abfrage kommt wie dokumentiert auch 0 raus.

    Und was bedeutet Laenge? Groesse des Buffers? Warum dann nicht eins? Hast du die Bibliothek korrekt initialisiert?

    Ansonsten zusammenfassend: Es crasht also recht haeufig. Aber bei anderen funktioniert die Bibliothek ...



  • Wie bei anderen funktioniert sie?

    Ich würde mal behaupten, dass es nur eine Handvoll ernste Anwender davon in Deutschland gibt. Zumal das die neue Version ist.

    Zweitens läuft sie bei auch ohne Probleme. Unter Windows per MSVC. Nur Linux mit dem GCC spackt rum.

    Ausserdem bin ich eigentlich nicht an einer Q&D Lösung interessiert, dass es so gerade klappt, sondern an einer ordentlichen Lösung, die mir nicht sämtlichen RAM stiehlt falls mal eine Exception fliegen sollte.

    Initialisieren ist nicht nötig, wenn ichd as richtig im Kopf habe. Ich werde da morgen nochmal nach suchen, ob weitere Initialisierungsschritte notwendig sind.

    Um dir mal einen Eindruck zu geben von dem Ding und der letzten Version:
    Bei manchen Fehlern wurde keine Fehlercode returnt oder eine Exception geworfen. Auch ein kontrollierter Absturz war nicht programmiert.
    Das Problem war: Es ging etwas nicht, obwohl alle Returncodes sagten "Alles ok".
    Wo ist der Knackpunkt? Tja, in einer Logging-Datei die bei einem Run schon mehrere Tausend Zeilen umfasst stand irgendwo dann eine Zahl, eine ganz normale Zahl. Das war der Fehlercode.

    Ist das etwa kein Luxus??



  • @Skym0sh0
    Also hast du die "size erst prüfen" Variante jetzt schon probiert oder nicht?
    Also sowas da

    std::string str() const 
    { 
    	if (std::size_t const s = this->size())
    		return std::string(HandleContent(this->m_handle), s);
    	else
    		return std::string();
    }
    

    Wäre ja irgendwie naheliegend das zu versuchen.
    Und wenn es funktioniert würde ich es auch nicht als "Q&D" bezeichnen.



  • Ja, die Idee kam mir mittlerweile auch. Das probiere ich jetzt.

    Aber andererseits, wieso stürzt das Programm dann ab, wenn die size > 0 ist und der Puffer gefüllt ist?

    Edit: Also hustbaers Idee ist probiert. Die Längenabfrage rettet mich in Fällen, wo die Größe tatsächlich 0 ist.
    Das Problem bleibt jedoch: sind sinnvolle Dinge in den Rückgabepuffer geschrieben und die Länge damit > 0 (in meinem Fall knapp 115000 Zeichen), dann crasht es nach dem Pufferzugriff.



  • int main()
    {
    	EricRueckgabepufferHandle x = 0;
    
    	assert(x == nullptr); // passt
    	x = EricRueckgabepufferErzeugen();
    	assert(x != nullptr); // passt
    
    	EricRueckgabepufferHandle address = x;
    	assert(x == address); // geht
    	uint32_t s = EricRueckgabepufferLaenge(x);
    	assert(x == address); // assertion nicht erfuellt
    
        return 0;
    }
    

    o_O

    Muss ich mehr zu der Bibliothek sagen?



  • Hast du mal geprüft, ob die calling-conventions stimmen? Crash bei return hört sich schwer danach an.



  • mh, laut Header Dateien STDCALL, was beim GCC als nichts definiert ist.
    Ich habe auch nichts andere definiert, oder liege ich da falsch?

    Ich setzte sogar noch ein Progrämmchen drauf:

    #include <cassert>
    #include <iostream>
    //-----------------------------------------------
    #include <ericapi.h>
    #include <tm98ericapi.h>
    #include <ericdef.h>
    #include <eric_types.h>
    #include <eric_fehlercodes.h>
    //-----------------------------------------------
    void test(const char* file, int line, long first, long second)
    {
    	std::cout << "File: \"" << file << "\", Zeile: \"" << line << "\" -> " << first << " = " << second << std::endl;
    	assert(first == second);
    }
    #define TEST(a, b) { test(__FILE__, __LINE__, (long)(a), (long)(b)); }
    //-----------------------------------------------
    int main()
    {
    	EricRueckgabepufferHandle x = 0;
    
    	assert(x == nullptr);
    	x = EricRueckgabepufferErzeugen();
    	assert(x != nullptr);
    
    	const EricRueckgabepufferHandle address = x;
    
    	TEST(x, address);
    
    	int r = EricVersion(x);
    	assert(r == ERIC_OK);
    
    	TEST(x, address);
    
    	const char* ptr = EricRueckgabepufferInhalt(x);
    
    	TEST(x, address);
    
    	uint32_t s = EricRueckgabepufferLaenge(x);
    
    	TEST(x, address);
    
    	return 0;
    }
    

    Ausgabe:

    File: "../src/bugtest.cpp", Zeile: "26" -> 152551504 = 152551504
    File: "../src/bugtest.cpp", Zeile: "31" -> 152551504 = 0
    File: "../src/bugtest.cpp", Zeile: "35" -> 0 = 0
    File: "../src/bugtest.cpp", Zeile: "39" -> 0 = -146141184
    

    😃



  • Probier mal

    #define STDCALL __attribute__((stdcall))
    


  • Nein, hilft auch nicht. Zumal bei meinen aktuellen Miniprogrammen nichtmals ein Funktionsaufruf vonstatten geht, ausser zu der Lib hin.



  • int main()
    {
        EricRueckgabepufferHandle x = 0;
    
        assert(x == nullptr); // passt
        x = EricRueckgabepufferErzeugen();
        assert(x != nullptr); // passt
    
        EricRueckgabepufferHandle address = x;
        assert(x == address); // geht
        uint32_t s = EricRueckgabepufferLaenge(x);
        assert(x == address); // assertion nicht erfuellt
    
        return 0;
    }
    

    Ist dieses Verhalten für Windows und Linux ähnlich?

    Hast du mal Debug Tools ala Application Verifier bei Windows drübergejagt? Nach meinem Gefühl ist Windows manchmal etwas verschwiegen und undefiniert wenn es um Fehler geht.

    Vielleicht kommst du ja auch an die Speicherbereiche ran und kannst den Unterschied zwischen den Speicherbereichen und den Handles anschauen.

    Oder kann es sein dass die Funktion EricRueckgabepufferLaenge() einen unerwünschten Seiteneffekt hat? So nach dem Motto, dass die Funktion automatisch das Handle auf den nächsten Speicherbereich legt.

    EricRueckgabepufferHandle Handle = x;
    uint32_t s;
    
    while ((s = EricRueckgabepufferLaenge(x)) != INVALID_LENGTH)
    {
      // Ausgabe der Größe 
    }
    

    Notfalls pack die große Keule raus und wirf man einen kurzen Blick in das Disassembly von EricRueckgabepufferLaenge().



  • Mh, ich dachte auch erst, dass Windows mir den Fehler nur verschweigt, intern aber auch Probleme hat (oder sie einfach nicht bemerkt).

    Aber das Programm läuft unter Windows 1a. Die Speicheradressen bleiben gleich und nichts stürzt ab. Es wird sogar alles fein säuberlich aufgeräumt wie gewünscht. (Ich beziehe mich da auf mein letztes gepostetes Programm mit dem TEST-Makro)

    Mein Tipp ist eher, dass die Bibliothek keine Seiteneffekte* hat, sondern einfach nur ein groben Fehler vllt beid er Portierung nach linux hat, die den gesamten Stack korrumpiert, da mir sämtliche Stackvariablen zerschossen und mehr doer weniger willkürlich verändert werden.

    *: Ich dachte auch erst an einen undokumentierten Seiteneffekt, der meinen Zeiger um z.B. die Puffergröße weiter schiebt (also quasi an das Ende hinter den Puffer wie einen EndIterator), aber da müsste ich durch Pointerarithmetik ja etwa sehen können wie die Zeiger stehen, aber die Werte sind teilweise mehrere hunderttausende Speicherzellen distanziert.

    Idee: Am Montag teste ich das mal mit Globalen statt Stackvariablen.



  • Skym0sh0 schrieb:

    Mein Tipp ist eher, dass die Bibliothek keine Seiteneffekte* hat, sondern einfach nur ein groben Fehler vllt beid er Portierung nach linux hat, die den gesamten Stack korrumpiert, da mir sämtliche Stackvariablen zerschossen und mehr doer weniger willkürlich verändert werden.

    Ich gehe eher davon aus dass es hier ein Problem mit der ABI gibt.
    Also dass die Linux-LIB mit nem anderen Compiler bebaut wurde, andere Calling-Conventions verwendet oder sowas in der Art.
    Und dass dadurch der Stack zerschossen wird.


Anmelden zum Antworten