Portal-Zone Gothic-Zone Gothic II-Zone Gothic 3-Zone Gothic 4-Zone Modifikationen-Zone Download-Zone Foren-Zone RPG-Zone Almanach-Zone Spirit of Gothic

 

Seite 3 von 9 « Erste 1234567 ... Letzte »
Ergebnis 41 bis 60 von 174
  1. Beiträge anzeigen #41 Zitieren
    Knight Commander Avatar von Neconspictor
    Registriert seit
    Jan 2009
    Beiträge
    2.749
     
    Neconspictor ist offline
    Code:
    0023:007A634A (0x00000000 0x0FD33A50 0x0CB34348 0x0FD33A50) Gothic2.exe, zCView::BlitText()+170 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zView.cpp, line 627
    0023:007A6706 (0x0CB34348 0x007A6767 0x00000000 0x006C89E8) Gothic2.exe, zCView::Blit()+838 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zView.cpp, line 744
    0023:007A6758 (0x00000000 0x006C89E8 0x0135FCA8 0x00000000) Gothic2.exe, zCView::DrawItems()+8 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zView.cpp, line 753
    0023:007A6767 (0x0135FCA8 0x00000000 0x0135FC98 0x00000000) Gothic2.exe, zCView::DrawItems()+23 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zView.cpp, line 757
    0023:006C89E8 (0x0082F0EC 0x00000000 0x000701A0 0x0FD33A50) Gothic2.exe, oCGame::Render()+840 byte(s), P:\dev\g2addon\release\Gothic\_ulf\oGame.cpp, line 2686
    0023:0078188B (0x0000002C 0x0005BD2F 0x00000004 0x00000000) Gothic2.exe, MainProg()+75 byte(s), P:\dev\g2addon\release\Gothic\_ulf\Phoenix.cpp, line 111
    Blitting: Das ist eine Technik aus der Grafikprogrammierung: https://docs.microsoft.com/en-us/win...xture-blitting

    Im Grunde geht es hier vermutlich darum bereits gerenderten Text auf den Bildschirm zu bringen. Da das ganze in zCView:: DrawItems() passiert, wird wohl irgendein Text von einem Item gerendert (z.B. Fokusname oder die Statistiken im Inventar/Handelsmenü).

    Meine Vermutung ist, dass die Absturzberichte nicht weiterhelfen, da die Abstürze an so grundlegenden Stellen passieren, die eigtl. funktionieren müssten. Ich denke, dass die Ursache ganz wo anders ist. Die Frage ist nur wo

  2. Beiträge anzeigen #42 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Milky-Way Beitrag anzeigen
    Zudem mal ein Absturz in einem Dialog:

    [...]

    Zumindest verweist die Adresse 0x0000C84D von CallFunc auf diese Funktion:

    [...]

    Kann ich aus DoStack irgendwie ablesen, wobei es hier genau gescheitert ist? Die Funktionen sind eigentlich alle sehr simpel, verteilen Gold, Erfahrung, loggen TB-Einträge...

    Zu dieser Access Violation kann ich dir etwas sagen.
    Um das mal etwas transparenter zu gestalten, hier wie ich vorgegangen bin.

    Access Violations in zCParser::DoStack sagen uns auf den ersten Blick erst einmal nicht viel, außer dass etwas bei der Ausführung von Daedaluscode schief gelaufen ist. Du hast ja schon herausgefunden in welcher Funktion der Absturz passiert ist. Von der anderen Seite kann man bei Access Violations in IDA zu den aufgelisteten Adressen springen (IDA öffnen und im Dissassembly View mit G zu einer Adresse springen). Das habe ich gemacht, und zwar direkt mit der Adresse bei der es zum Crash kam.

    Die Umgebung von Adresse 0x7918D4 sieht so aus:
    Code:
    ...
    0x7918CD   mov     ecx, esi
    0x7918CF   call    zCPar_DataStack::Pop(void)
    0x7918D4   mov     eax, [eax]
    0x7918D6   pop     esi
    0x7918D7   retn
    Man kann erahnen, dass dieses Auslesen von EAX gescheitert ist. EAX, welches den Rückgabewert der zuvor aufgerufenen Funktion zCPar_DataStack::Pop(void) enthält, zeigte also auf keine gültige Adresse.
    Um heraus zu finden wie das bitte sein kann, schauen wir in die davor aufgerufene Funktion zCPar_DataStack::Pop(void). Dort wird mit
    Code:
    0x7A5070    mov     eax, [ecx+2000h]  ; Lese von ECX+2000h und schiebe es in EAX
    0x7A5076    test    eax, eax          ; Teste EAX gegen sich selbst
    0x7A5078    jle     short to_0x7A5085 ; Springe, wenn Ergebnis <= 0
    überprüft, ob [ECX+2000h] kleiner gleich null ist. Wenn ja, gibt die Funktion hier 0 zurück (super Fehlerbehandlung!):
    Code:
    0x7A5085    xor     eax, eax  ; EAX auf 0 setzen
    0x7A5087    retn              ; Return
    ECX ist an der Stelle ein Zeiger auf das zCPar_DataStack-Objekt. Der Offset 0x2000 (Dezimal: 8192 = 4 * 2048) ist zCPar_DataStack.sptr, siehe Ikarus Klassendokumentation in zCParser.d:
    Code:
        //zCPar_DataStack           datastack;              //Daten-Stack
            var int datastack_stack[/*zMAX_SYM_DATASTACK*/ 2048];     //0x0058 //sehr klein. Bei korrekter Nutzung aber egal.
            var int datastack_sptr;                                   //0x085C int
    Der Datenstackpointer ist also ungültig! Das passiert, wenn in Daedalus zu viel vom Stack gepoppt wird.

    Wenn ich mich also jetzt nicht verschaut oder einen Denkfehler gemacht habe, heißt das jetzt, dass ihr die Skripte nach Funktionsaufrufen durchsuchen müsst, wo ein Rückgabenwert verarbeitet wird von einer Funktion, die gar keinen gibt; und zwar womöglich alle Skripte, denn es muss ja nicht zwingend in dem Dialog passiert sein, sondern evtl. schon vorher.

    Was mich allerdings wundert ist, dass es nicht vorher zu Problemen kommt, sobald der Datenstack einmal korrumpiert ist, sondern erst, sobald der Stack leer ist.



    EDIT: Ich habe gerade mal über die anderen Access Violations geschaut, die du im LeGo-Thread gepostet hast; aus dem verlinkten Beitrag werden alle durch das gleiche Problem ausgelöst. Es sollte also zumindest eine Erleichterung sein, dass alle die gleiche Ursache haben.
    Geändert von mud-freak (09.09.2018 um 19:08 Uhr)

  3. Beiträge anzeigen #43 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.446
     
    Lehona ist offline
    Gibt die VM nicht einfach 0 zurück, wenn von einem (leeren) Datenstack gepoppt wird? Es gibt auf jedenfall auch in den Originalskripten einige Stellen, wo int-Funktionen nichts auf den Datenstack schieben.

    Edit: Ganz so einfach ist es wohl nicht, ich schau mir das jetzt auch nochmal genauer an.
    Edit2: Ganz so simpel ist der Fehler (leider) nicht. Ein leerer Datenstack führt genau wie beschrieben einfach zu einer 0 als Wert. In diesem Fall lag vorher aber ein Wert auf dem Datenstack, nämlich 0x41 oder in anderen Worten zPAR_TOK_PUSHVAR. Das heißt, Gothic denkt, dass als nächstes die Adresse einer Variablen kommt (bzw. ein Zeiger auf zCPar_Symbol.content). Angenommen der Datenstack ist nicht durch evil data parser stack hacking korrumpiert worden, würde ich sagen, dass der Datenstack eigentlich hätte leer sein "sollen" und da zufälligerweise die Instanz 0x41 lag. Das ist allerdings printdebugch.par0, macht also nicht so viel Sinn. Also vielleicht doch ein Fehler à la Ikarus und Konsorten?
    Edit3: Ich nehme an, die AV tritt bei dem Dialog nur sporadisch auf? Das macht es natürlich schwierig zu debuggen. Das wundert mich allerdings auch, denn ich dachte eigentlich, dass Gothic den Datenstack zwischen Aufrufen in die Scripts aufräumt, d.h. das nur der Dialog und vielleicht noch die Condition darauf Einfluss gehabt haben sollte.
    Geändert von Lehona (09.09.2018 um 19:46 Uhr)

  4. Beiträge anzeigen #44 Zitieren
    Knight Commander Avatar von Neconspictor
    Registriert seit
    Jan 2009
    Beiträge
    2.749
     
    Neconspictor ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Der Datenstackpointer ist also ungültig! Das passiert, wenn in Daedalus zu viel vom Stack gepoppt wird.

    Wenn ich mich also jetzt nicht verschaut oder einen Denkfehler gemacht habe, heißt das jetzt, dass ihr die Skripte nach Funktionsaufrufen durchsuchen müsst, wo ein Rückgabenwert verarbeitet wird von einer Funktion, die gar keinen gibt; und zwar womöglich alle Skripte, denn es muss ja nicht zwingend in dem Dialog passiert sein, sondern evtl. schon vorher.
    Meinst du so etwas?

    Code:
    Func int foo() {
    
    }
    
    
    // Irgendwo im Code
    var int corrupted; corrupted = foo();

  5. Beiträge anzeigen #45 Zitieren
    now also in your universe  Avatar von Milky-Way
    Registriert seit
    Jun 2007
    Beiträge
    15.191
     
    Milky-Way ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Zu dieser Access Violation kann ich dir etwas sagen.
    Um das mal etwas transparenter zu gestalten, hier wie ich vorgegangen bin.

    Access Violations in zCParser:oStack sagen uns auf den ersten Blick erst einmal nicht viel, außer dass etwas bei der Ausführung von Daedaluscode schief gelaufen ist. Du hast ja schon herausgefunden in welcher Funktion der Absturz passiert ist. Von der anderen Seite kann man bei Access Violations in IDA zu den aufgelisteten Adressen springen (IDA öffnen und im Dissassembly View mit G zu einer Adresse springen). Das habe ich gemacht, und zwar direkt mit der Adresse bei der es zum Crash kam.

    Die Umgebung von Adresse 0x7918D4 sieht so aus:
    Code:
    ...
    0x7918CD   mov     ecx, esi
    0x7918CF   call    zCPar_DataStack::Pop(void)
    0x7918D4   mov     eax, [eax]
    0x7918D6   pop     esi
    0x7918D7   retn
    Man kann erahnen, dass dieses Auslesen von EAX gescheitert ist. EAX, welches den Rückgabewert der zuvor aufgerufenen Funktion zCPar_DataStack::Pop(void) enthält, zeigte also auf keine gültige Adresse.
    Um heraus zu finden wie das bitte sein kann, schauen wir in die davor aufgerufene Funktion zCPar_DataStack::Pop(void). Dort wird mit
    Code:
    0x7A5070    mov     eax, [ecx+2000h]  ; Lese von ECX+2000h und schiebe es in EAX
    0x7A5076    test    eax, eax          ; Teste EAX gegen sich selbst
    0x7A5078    jle     short to_0x7A5085 ; Springe, wenn Ergebnis <= 0
    überprüft, ob [ECX+2000h] kleiner gleich null ist. Wenn ja, gibt die Funktion hier 0 zurück (super Fehlerbehandlung!):
    Code:
    0x7A5085    xor     eax, eax  ; EAX auf 0 setzen
    0x7A5087    retn              ; Return
    ECX ist an der Stelle ein Zeiger auf das zCPar_DataStack-Objekt. Der Offset 0x2000 (Dezimal: 8192 = 4 * 2048) ist zCPar_DataStack.sptr, siehe Ikarus Klassendokumentation in zCParser.d:
    Code:
        //zCPar_DataStack           datastack;              //Daten-Stack
            var int datastack_stack[/*zMAX_SYM_DATASTACK*/ 2048];     //0x0058 //sehr klein. Bei korrekter Nutzung aber egal.
            var int datastack_sptr;                                   //0x085C int
    Der Datenstackpointer ist also ungültig! Das passiert, wenn in Daedalus zu viel vom Stack gepoppt wird.

    Wenn ich mich also jetzt nicht verschaut oder einen Denkfehler gemacht habe, heißt das jetzt, dass ihr die Skripte nach Funktionsaufrufen durchsuchen müsst, wo ein Rückgabenwert verarbeitet wird von einer Funktion, die gar keinen gibt; und zwar womöglich alle Skripte, denn es muss ja nicht zwingend in dem Dialog passiert sein, sondern evtl. schon vorher.

    Was mich allerdings wundert ist, dass es nicht vorher zu Problemen kommt, sobald der Datenstack einmal korrumpiert ist, sondern erst, sobald der Stack leer ist.



    EDIT: Ich habe gerade mal über die anderen Access Violations geschaut, die du im LeGo-Thread gepostet hast; aus dem verlinkten Beitrag werden alle durch das gleiche Problem ausgelöst. Es sollte also zumindest eine Erleichterung sein, dass alle die gleiche Ursache haben.
    Vielen Dank für die Nachforschung und auch für die Erklärung, wie du vorgegangen bist! So kann ich mir langsam aber sicher ein paar eigene Schritte zusammenbasteln, um den Fehlern näher zu kommen. (Wie zuvor nach Anleitung Lehonas schon mal CallFunc herauszusuchen)

    Wenn ich mich also jetzt nicht verschaut oder einen Denkfehler gemacht habe, heißt das jetzt, dass ihr die Skripte nach Funktionsaufrufen durchsuchen müsst, wo ein Rückgabenwert verarbeitet wird von einer Funktion, die gar keinen gibt; und zwar womöglich alle Skripte, denn es muss ja nicht zwingend in dem Dialog passiert sein, sondern evtl. schon vorher.
    Das scheint mir ja schon mal ein sehr guter Ansatz zu sein! Mir fallen da 3 Möglichkeiten ein:
    1) Eine func int (oder string, ...) gibt manchmal keinen Wert zurück - diese Fälle kann ich mir alle vom Parser als Warnung ausgeben lassen (oder ging das nur mit GothicSourcer, der kein Ikarus verträgt?)
    2) eine func void abc(){...}; und dann wird eine Variable gesetzt x = abs(); -- das würde aber der Parser schon direkt ablehnen
    3) Hook einer Engine-Funktion hat ein return drin, wodurch die Engine-Funktion keinen Wert zurückgibt. Oder lässt sich aus den Fehlermeldungen ablesen, dass es nicht in einer engine Funktion passieren kann?

  6. Beiträge anzeigen #46 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Lehona Beitrag anzeigen
    Ganz so simpel ist der Fehler (leider) nicht. Ein leerer Datenstack führt genau wie beschrieben einfach zu einer 0 als Wert. In diesem Fall lag vorher aber ein Wert auf dem Datenstack, nämlich 0x41 oder in anderen Worten zPAR_TOK_PUSHVAR. Das heißt, Gothic denkt, dass als nächstes die Adresse einer Variablen kommt (bzw. ein Zeiger auf zCPar_Symbol.content). Angenommen der Datenstack ist nicht durch evil data parser stack hacking korrumpiert worden, würde ich sagen, dass der Datenstack eigentlich hätte leer sein "sollen" und da zufälligerweise die Instanz 0x41 lag. Das ist allerdings printdebugch.par0, macht also nicht so viel Sinn. Also vielleicht doch ein Fehler à la Ikarus und Konsorten?
    Ah, dann könnte ich mir vorstellen, dass es vielleicht mit der neuen Implementierung der Hooks zusammenhängt. Dort habe ich vor Aufruf der Daedalusfunktionen einen Puffer von 10 Integern auf den Datenstack gelegt, mit der Absicht, dass er, falls in einer Hookfunktionen irgendwo etwas fälschlicherweise vom Stack gepoppt wird, anschließend noch intakt ist und setze anschließend den Datenstackpointer wieder an die selbe Position wie zuvor:
    Zitat Zitat von HookEngine.d
    Code:
        // ...
    
        // Remember data stack pointer
        var int sPtr; sPtr = MEM_Parser.datastack_sptr;
    
        // Add a stack buffer for naughty functions that pop off of the data stack illegally
        repeat(j, 10); var int j;
            MEM_PushIntParam(0);
        end;
    
        // Call the function
        MEM_CallByID(MEM_ReadIntArray(a.array, i));
    
        // Reset the data stack pointer (remove buffer and anything left on the stack)
        MEM_Parser.datastack_sptr = sPtr;
    
        // ...
    Geändert von mud-freak (09.09.2018 um 19:53 Uhr)

  7. Beiträge anzeigen #47 Zitieren
    now also in your universe  Avatar von Milky-Way
    Registriert seit
    Jun 2007
    Beiträge
    15.191
     
    Milky-Way ist offline
    Zitat Zitat von Lehona Beitrag anzeigen
    Edit3: Ich nehme an, die AV tritt bei dem Dialog nur sporadisch auf? Das macht es natürlich schwierig zu debuggen. Das wundert mich allerdings auch, denn ich dachte eigentlich, dass Gothic den Datenstack zwischen Aufrufen in die Scripts aufräumt, d.h. das nur der Dialog und vielleicht noch die Condition darauf Einfluss gehabt haben sollte.
    Korrekt, die einzigen reproduzierbaren Abstürze konnte ich darauf zurückführen, dass teils die Talente nicht mitgespeichert wurden. Die neuen Abstürze hier lassen sich nicht verlässlich reproduzieren.

  8. Beiträge anzeigen #48 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.446
     
    Lehona ist offline
    Zitat Zitat von Neconspictor Beitrag anzeigen
    Meinst du so etwas?

    Code:
    Func int foo() {
    
    }
    
    
    // Irgendwo im Code
    var int corrupted; corrupted = foo();
    So ungefähr. Grundsätzlich ist das kein Problem und wird auch im Original so gemacht (auch wenn es nicht schön ist). Solange der Wert aber nicht 0x40 oder 0x41 (PUSHINT und PUSHVAR) ist, d.h. wenn zufälligerweise irgendeine Instanz auf dem Datenstack liegt (die haben nämlich kein Markierungstoken), wird die Instanz einfach "gefressen" und 0 zurückgegeben. Der Datenstack repariert sich also selber (zumindest in etwa).

    Alternative Idee: Vielleicht ist der Datenstack gar nicht leer, sondern da steht wirklich eine 0 auf dem Datenstack. Mit normalen Daedalus sollte man das nicht erreichen können, aber MEM_ReadInt(0) würde zum Beispiel genau dazu führen. Aus Performancegründen haben die entsprechenden Ikarus-Funktionen keine Sanity-Checks mehr, aber zum Debuggen könnte man in MEMINT_ReplaceSlowFunctions() den Aufruf an MEMINT_InitFasterReadWrite() auskommentieren, dann sollten MEM_WriteInt/MEM_ReadInt genau so funktionieren, wie es im Code steht. Solltet ihr die Konstante zERR_StackTraceOnlyForFirst nicht zufällig auf 1 gesetzt haben (0 ist der Default-Wert), wird es dann bei ungültigen Aufrufen, d.h. mit ptr <= 0, einen Stacktrace geben.

    Zitat Zitat von Milky-Way Beitrag anzeigen
    Vielen Dank für die Nachforschung und auch für die Erklärung, wie du vorgegangen bist! So kann ich mir langsam aber sicher ein paar eigene Schritte zusammenbasteln, um den Fehlern näher zu kommen. (Wie zuvor nach Anleitung Lehonas schon mal CallFunc herauszusuchen)


    Das scheint mir ja schon mal ein sehr guter Ansatz zu sein! Mir fallen da 3 Möglichkeiten ein:
    1) Eine func int (oder string, ...) gibt manchmal keinen Wert zurück - diese Fälle kann ich mir alle vom Parser als Warnung ausgeben lassen (oder ging das nur mit GothicSourcer, der kein Ikarus verträgt?)
    2) eine func void abc(){...}; und dann wird eine Variable gesetzt x = abs(); -- das würde aber der Parser schon direkt ablehnen
    3) Hook einer Engine-Funktion hat ein return drin, wodurch die Engine-Funktion keinen Wert zurückgibt. Oder lässt sich aus den Fehlermeldungen ablesen, dass es nicht in einer engine Funktion passieren kann?
    1) Würde mich wundern, wenn der Gothic-Parser da irgendwas meckert. Mit Parsiphae sollte man das recht einfach herausfinden können (wenn wir annehmen, dass einfach nur return; in solchen Funktionen vom Gothic-Parser verboten wird). Wirklich Zeit um sowas zu schreiben habe ich aber nicht. Falls wir uns sicher sind, dass es daran liegt, denk ich nochmal drüber nach
    2) Da würde ich dir zustimmen - meines Wissens erlaubt der Parser nicht die Verwendung von void-Funktionen als Wert (d.h. dein Beispiel würde beim Parsen einen Fehler geben).
    3) Das halte ich, gerade in Verbindung mit mud-freaks Post, nicht für unmöglich. Die Hooks sollte man halbwegs sinnvoll überprüfen können, ob da der Stack korrumpiert wird. Könnte aber natürlich sein, dass das irgendwo in den LeGo-Funktionen passiert und vielleicht nur mit den neuen Hooks auftritt?

  9. Beiträge anzeigen #49 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Ah, dann könnte ich mir vorstellen, dass es vielleicht mit der neuen Implementierung der Hooks zusammenhängt. Dort habe ich vor Aufruf der Daedalusfunktionen einen Puffer von 10 Integern auf den Datenstack gelegt, mit der Absicht, dass er, falls in einer Hookfunktionen irgendwo etwas fälschlicherweise vom Stack gepoppt wird, anschließend noch intakt ist und setze anschließend den Datenstackpointer wieder an die selbe Position wie zuvor:
    Ich weiß nicht mehr genau, wo dieser Gedankengang herkam... Denn zCParser::CallFunc räumt vor Funktionsaufruf einfach den Datenstack auf (siehe 0x792A76) - wieso habe ich das dann nicht genau so gemacht? Oder nicht einfach ganz sein gelassen, denn _Hook wird ja schon mit leerem Datenstack von zCParser::CallFunc aufgerufen?! Ich gehe mal meine alten Forenbeiträge lesen...

    Ob es wirklich damit zutun hat weiß ich nicht.


    EDIT: Ah, es ging darum, alles zwischen den Funktionen zu sichern. Ein zCPar_DataStack::Clear wäre aber trotzdem sinnvoller.
    Geändert von mud-freak (09.09.2018 um 20:16 Uhr)

  10. Beiträge anzeigen #50 Zitieren
    Knight Commander Avatar von Neconspictor
    Registriert seit
    Jan 2009
    Beiträge
    2.749
     
    Neconspictor ist offline
    @Lehona: Danke für die Erklärung!

    Zitat Zitat von mud-freak Beitrag anzeigen
    Ich weiß nicht mehr genau, wo dieser Gedankengang herkam... Denn zCParser::CallFunc räumt vor Funktionsaufruf einfach den Datenstack auf (siehe 0x792A76) - wieso habe ich das dann nicht genau so gemacht? Oder nicht einfach ganz sein gelassen, denn _Hook wird ja schon mit leerem Datenstack von zCParser::CallFunc aufgerufen?! Ich gehe mal meine alten Forenbeiträge lesen...

    Ob es wirklich damit zutun hat weiß ich nicht.


    EDIT: Ah, es ging darum, alles zwischen den Funktionen zu sichern. Ein zCPar_DataStack::Clear wäre aber trotzdem sinnvoller.
    Wenn ich mich nicht täusche, dann dürfte es zumindest ok sein, wenn man das erst einmal auskommentiert und schaut, ob es dann noch immer zu Abstürzen kommt?

    Code:
    // Add a stack buffer for naughty functions that pop off of the data stack illegally
            repeat(j, 10); var int j;
                MEM_PushIntParam(0);
            end;

  11. Beiträge anzeigen #51 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Neconspictor Beitrag anzeigen
    Wenn ich mich nicht täusche, dann dürfte es zumindest ok sein, wenn man das erst einmal auskommentiert und schaut, ob es dann noch immer zu Abstürzen kommt?
    Da es sowie Unsinn ist, habe ich es heraus genommen und durch ein Leeren des Datenstacks ersetzt (wie zCParser::CallFunc es macht). Ich habe es in den Developmentbranch von LeGo gepusht:

    https://app.assembla.com/spaces/lego...v/HookEngine.d

    Bin mir zwar immer noch nicht ganz sicher, ob das dazu beigetragen haben könnte, aber ein Test mit dieser Veränderung kann nicht schaden.

  12. Beiträge anzeigen #52 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.446
     
    Lehona ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    EDIT: Ah, es ging darum, alles zwischen den Funktionen zu sichern. Ein zCPar_DataStack::Clear wäre aber trotzdem sinnvoller.
    Ich verstehe nicht genau, was du damit meinst. In jedem Fall könnte man aber testen, was passiert, wenn eine Hook durch Daedalus-Code ausgelöst wird (via External). Oder wird das so oder so nicht richtig funktionieren, weil CallFunc den Stack cleart und sowieso alles kaputt macht?

  13. Beiträge anzeigen #53 Zitieren
    now also in your universe  Avatar von Milky-Way
    Registriert seit
    Jun 2007
    Beiträge
    15.191
     
    Milky-Way ist offline
    Zitat Zitat von Lehona Beitrag anzeigen
    Alternative Idee: Vielleicht ist der Datenstack gar nicht leer, sondern da steht wirklich eine 0 auf dem Datenstack. Mit normalen Daedalus sollte man das nicht erreichen können, aber MEM_ReadInt(0) würde zum Beispiel genau dazu führen. Aus Performancegründen haben die entsprechenden Ikarus-Funktionen keine Sanity-Checks mehr, aber zum Debuggen könnte man in MEMINT_ReplaceSlowFunctions() den Aufruf an MEMINT_InitFasterReadWrite() auskommentieren, dann sollten MEM_WriteInt/MEM_ReadInt genau so funktionieren, wie es im Code steht. Solltet ihr die Konstante zERR_StackTraceOnlyForFirst nicht zufällig auf 1 gesetzt haben (0 ist der Default-Wert), wird es dann bei ungültigen Aufrufen, d.h. mit ptr <= 0, einen Stacktrace geben.
    Kommt der Stacktrace dann auch irgendwo an für Spieler erreichbarer Stelle, oder muss dafür zSpy laufen?

    Zitat Zitat von Lehona Beitrag anzeigen
    3) Das halte ich, gerade in Verbindung mit mud-freaks Post, nicht für unmöglich. Die Hooks sollte man halbwegs sinnvoll überprüfen können, ob da der Stack korrumpiert wird. Könnte aber natürlich sein, dass das irgendwo in den LeGo-Funktionen passiert und vielleicht nur mit den neuen Hooks auftritt?
    In diesem Beitrag (ganz unten im Spoiler) habe ich alle HookEngine(F) gesammelt:
    https://forum.worldofplayers.de/foru...1#post25801802
    Vielleicht ein Kandidat?
    Code:
    virtual int __thiscall oCNpc::DoDropVob(zCVob *)        0x00744DD0  0   6   public: virtual int __thiscall  oCNpc::DoDropVob(zCVob  *)
    wird gehookt:
    Code:
    HookEngineF ( 7622096, 6, HOOK_AI_Drop); // Hook AIDrop (/*0x00744DD0*/)
    und ruft Funktion auf
    Code:
    func void HOOK_AI_Drop(){
    
      if(ECX == 0) {return;};
      
    	//	----- an den NPC und das item kommen -----
    	var c_npc slf; slf = MEM_PtrToInst(ECX);						// der NPC, der das Item einsammelt
    	
      if (!Hlp_isValidNpc(slf)) {return;};
      
    	var C_ITEM itm; itm = MEM_PtrToInst(MEM_ReadInt(ESP + 4));		// Pointer auf das Item
    	//PrintDebugg(ConcatStrings(slf.name, itm.name));
    
    	if (!Hlp_IsValidItem (itm)) {return;};
    
        /*
    	if (DII_IsDynamic(itm)) {
    
    		var DII_USER_DATA data; data = DII_GetUserData(Hlp_GetInstanceID(itm));
    		if (data.data[MAGICWEAPON_ENCHANTEDWEAPON]) {
    			MagicWeaponSetEffect(itm, data.magicWeaponNewEffect);
    		};
    	};
        */
    
    	// only accept hero as npc
    	if (Hlp_GetInstanceID(slf) != Hlp_GetInstanceID(hero)) {return;};
    
    	if (itm.flags & ITEM_MISSION){
    		PrintDebugg("Missions Item fallen gelassen. Solltest du lieber nicht machen!");
    		return;
    	};
    
    	if Hlp_IsItem (itm, ItMi_Gold){
    		PrintDebugg("it's the Gold item");
    		AMBVAR_DROPWP = Npc_GetNearestWP(hero);
    		AMBVAR_Hero_dropped_Gold = TRUE;
    		TIMEVAR_Drop_pickup = Wld_GetTimePlus(0,0,6);
    	};
    };
    Sind die return hier ein Problem? Sollte eigentlich immer ein Item in der Welt erstellt werden, aber manchmal verhindern wir, dass das passiert?

  14. Beiträge anzeigen #54 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Lehona Beitrag anzeigen
    Ich verstehe nicht genau, was du damit meinst. In jedem Fall könnte man aber testen, was passiert, wenn eine Hook durch Daedalus-Code ausgelöst wird (via External). Oder wird das so oder so nicht richtig funktionieren, weil CallFunc den Stack cleart und sowieso alles kaputt macht?
    Die ursprüngliche Absicht von dem Stackpuffer war es zu vermeiden, dass Funktionen, die die gleiche Adresse hooken sich untereinander den Datenstack kaputt machen (Sachen liegen lassen, zu viel poppen usw.).

    Du hast recht, das sollte schief laufen. Der einzige Weg Daedalus auszuführen geht durch CallFunc, welches den Datenstack leert. Hier ein kleiner Test mit gehookten External, der das bestätigt.

    Code:
    /*
     * Printing function
     */
    func void hooktest1(var int p1, var int p2, var int p3) {
        MEM_Info(IntToString(p1));
        MEM_Info(IntToString(p2));
        MEM_Info(IntToString(p3));
    
        /* Expected output:
    
            Starting hook test
            You just got hijacked
            1
            19333
            3
        */
    
        /* Actual output:
    
            Starting hook test
            You just got hijacked
            0
            19333
            3
        */
    };
    
    /*
     * Function that puts something on the stack, then calls a hooked external
     */
    func void hooktest2() {
        MEM_Info("Starting hook test");
    
        var int arg1; arg1 = 1;
        var int arg3; arg3 = 3;
        hooktest1(arg1, Hlp_GetInstanceID(hero), arg3);
    };
    
    /*
     * Hook external function
     */
    func void hooktest3() {
        MEM_Info("You just got hijacked");
    };
    
    /*
     * Initialization
     */
    func void hooktestinit() {
        const int Hlp_GetInstanceID_0x14 = 7305172; //0x6F77D4
        HookEngineF(Hlp_GetInstanceID_0x14, 8, hooktest3);
        FF_ApplyOnceExt(hooktest2, 5000, 1);
    };

  15. Beiträge anzeigen #55 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Milky-Way Beitrag anzeigen
    In diesem Beitrag (ganz unten im Spoiler) habe ich alle HookEngine(F) gesammelt:
    https://forum.worldofplayers.de/foru...1#post25801802
    Vielleicht ein Kandidat?

    [...]

    Sind die return hier ein Problem? Sollte eigentlich immer ein Item in der Welt erstellt werden, aber manchmal verhindern wir, dass das passiert?
    Das Skript an sich sollte keine Probleme machen, allerdings wird hier tatsächlich eine externe Funktion gehookt, ebenso hier:
    Code:
    	HookEngineF (7654416, 6, Hook_EV_DrawWeapon); //Hook EV_DrawWeapon located at 0x74CC10
    	HookEngineF (7656160, 5, Hook_EV_DrawWeapon); //Hook EV_DrawWeapon1 located at 0x74D2E0
    	HookEngineF (7656832, 6, Hook_EV_DrawWeapon); //Hook EV_DrawWeapon2 located at 0x74D580
    	HookEngineF (7621056, 6, Hook_EV_DoTakeVob); //Hook EV_DrawWeapon2 located at 0x74D580
      HookEngineF ( 7622096, 6, HOOK_AI_Drop); // Hook AIDrop (/*0x00744DD0*/)
    Lehonas Gedanke scheint da ganz richtig zu sein. Sobald in den Skripten irgendwo AI_DrawWeapon, AI_DropItem oder AI_TakeItem aufgerufen wird, ist der Daedalus-Datenstack anschließend leer.

  16. Beiträge anzeigen #56 Zitieren
    Knight Commander Avatar von Neconspictor
    Registriert seit
    Jan 2009
    Beiträge
    2.749
     
    Neconspictor ist offline
    @mud_freak: Ich habe das Beispiel mal versucht zu starten, aber das Spiel stürzt ab nachdem hooktest3() ausgeführt worden ist.
    Das würde also bedeuten, dass man Externals nicht hooken darf.

  17. Beiträge anzeigen #57 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.446
     
    Lehona ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Das Skript an sich sollte keine Probleme machen, allerdings wird hier tatsächlich eine externe Funktion gehookt, ebenso hier:
    ...
    Lehonas Gedanke scheint da ganz richtig zu sein. Sobald in den Skripten irgendwo AI_DrawWeapon, AI_DropItem oder AI_TakeItem aufgerufen wird, ist der Daedalus-Datenstack anschließend leer.
    Nein, alle AI-Funktionen erzeugen bloß eine Nachricht, die in die EventManager-Queue ("AI-Queue") eingereiht wird (und das EV_*-Prefix deutet darauf hin, dass diese Funktionen bei der Verarbeitung dieser Mesages aufgerufen werden). DoDropVob() schon eher (ist 'ne virtuelle Funktion und IDA hat keine xrefs), bezweifle ich aber auch. Zur Sicherheit könnte man den kompletten Datenstack sichern? Müsste man aber wohl in Assembly machen. Solange das nicht der Auslöser ist, also den Aufwand erstmal nicht wert (auch performancetechnisch). Könnte maner aber als zusätzliche Funktion in HookEngine anbieten.

    Zitat Zitat von Milky-Way Beitrag anzeigen
    Kommt der Stacktrace dann auch irgendwo an für Spieler erreichbarer Stelle, oder muss dafür zSpy laufen?
    Das wird nur in den zSpy geprintet, das hatte ich ganz vergessen. Mit den BinaryMachines aus LeGo kann man das aber "einfach" in eine Datei schreiben. Ist aber natürlich mal wieder zusätzlicher Entwicklungsaufwand.

    Zitat Zitat von Milky-Way Beitrag anzeigen
    In diesem Beitrag (ganz unten im Spoiler) habe ich alle HookEngine(F) gesammelt:
    https://forum.worldofplayers.de/foru...1#post25801802
    Vielleicht ein Kandidat?
    Code:
    virtual int __thiscall oCNpc::DoDropVob(zCVob *)        0x00744DD0  0   6   public: virtual int __thiscall  oCNpc::DoDropVob(zCVob  *)
    wird gehookt:
    ...
    Sind die return hier ein Problem? Sollte eigentlich immer ein Item in der Welt erstellt werden, aber manchmal verhindern wir, dass das passiert?
    Nein, das "return" bedeutet doch nur, dass die Funktion verlassen wird - effektiv das selbe, wie ein vollständiges Durchlaufen der Funktion (vgl. zum Beispiel eine leere Funktion anstatt HOOK_AI_Drop, die führt effektiv auch nur ein "return" aus).

  18. Beiträge anzeigen #58 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Neconspictor Beitrag anzeigen
    @mud_freak: Ich habe das Beispiel mal versucht zu starten, aber das Spiel stürzt ab nachdem hooktest3() ausgeführt worden ist.
    Das würde also bedeuten, dass man Externals nicht hooken darf.
    Wirklich? Bei mir funktioniert das. Hast du eine AV und/oder einen Stacktrace im zSpy?

    Zitat Zitat von Lehona Beitrag anzeigen
    Nein, alle AI-Funktionen erzeugen bloß eine Nachricht, die in die EventManager-Queue ("AI-Queue") eingereiht wird (und das EV_*-Prefix deutet darauf hin, dass diese Funktionen bei der Verarbeitung dieser Mesages aufgerufen werden).
    Da habe ich nicht nachgedacht. Sorry, wollte hier nicht noch mehr Verwirrung stiften.

  19. Beiträge anzeigen #59 Zitieren
    now also in your universe  Avatar von Milky-Way
    Registriert seit
    Jun 2007
    Beiträge
    15.191
     
    Milky-Way ist offline
    Zitat Zitat von Lehona Beitrag anzeigen
    Nein, das "return" bedeutet doch nur, dass die Funktion verlassen wird - effektiv das selbe, wie ein vollständiges Durchlaufen der Funktion (vgl. zum Beispiel eine leere Funktion anstatt HOOK_AI_Drop, die führt effektiv auch nur ein "return" aus).
    Ach, natürlich. Da hatte ich kurz fälschlicherweise gedacht, dass return aus der gehookten Funktion springt. Aber es wird ja nicht der Funktionsinhalt eingefügt, sondern die Funktion aufgerufen. Danke für die Erinnerung



    Erscheint es dann aktuell noch wahrscheinlich, dass die Abstürze durch die hook-Version von heute gelöst werden, oder ist weiterhin unbekannt, wie es dadurch zu einem leeren Stack kommen kann? Was ist die empfohlene weitere Vorgehensweise? Ich kann unseren Tester bitten, einige Stunden mit der neuen Version zu spielen, aber man weiß natürlich auch nicht, ab wann genug gespielt wurde, um zu sagen, dass die Abstürze nicht mehr auftreten.
    Ist hier irgendein Zusammenhang zu den nicht gespeicherten Talenten von PermMem denkbar?

  20. Beiträge anzeigen #60 Zitieren
    Knight Commander Avatar von Neconspictor
    Registriert seit
    Jan 2009
    Beiträge
    2.749
     
    Neconspictor ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Wirklich? Bei mir funktioniert das. Hast du eine AV und/oder einen Stacktrace im zSpy?
    Es stürzt nicht bei hooktest2() ab sondern an anderer Stelle. Weiß nicht genau wo, ich habe nur alles auskommentiert, was mit Hooks zu tun hatte.
    Zudem habe ich hooktest3() in der INIT_Global() aufgerufen.
    An sich ist der Absturz aber nicht ganz unlogisch, da ja der Stack geleert wird.

    Spoiler:(zum lesen bitte Text markieren)

    Code:
    [w] 00:23 Warn:  0 Q:     You just got hijacked
    [w] 00:23 Warn:  0 Q:     You just got hijacked
    [w] 00:23 Warn:  0 Q:     You just got hijacked
    [w] 00:23 Warn:  0 Q:     You just got hijacked
    [w] 00:24 Warn:  0 Q:     You just got hijacked
    [w] 00:24 Warn:  0 Q:     You just got hijacked
    [w] 00:24 Warn:  0 Q:     You just got hijacked
    [w] 00:24 Warn:  0 Q:     You just got hijacked
    [w] 00:24 Warn:  0 Q:     You just got hijacked
    [w] 00:24 Warn:  0 Q:     You just got hijacked
    [w] 00:24 Warn:  0 D:     zModel(zCModelAni::ResolveReferences): Could not find nextAni: S_WALK, this:T_WALKL_2_WALK .... <zModelProto.cpp,#3352>
    [w] 00:24 Warn:  0 D:     zModel(zCModelAni::ResolveReferences): Could not find nextAni: S_WALK, this:T_WALKR_2_WALK .... <zModelProto.cpp,#3352>
    [w] 00:24 Warn:  0 Q:     You just got hijacked
    [w] 00:24 Warn:  0 Q:     You just got hijacked
    [w] 00:25 Warn:  0 Q:     You just got hijacked
    [f] 00:25 Fault: 0 Q:     [start of stacktrace]
    [f] 00:25 Fault: 0 Q:             [UNKNOWN]                                                      +169008656 bytes
    [f] 00:25 Fault: 0 Q:     [end of stacktrace]
    [f] 00:25 Fault: 0 Q:     Exception handler was invoked. Ikarus tried to print a Daedalus-Stacktrace to zSpy. Gothic will now crash and probably give you a stacktrace of its own.
    [w] 00:35 Warn:  0 X:     [RND3D-Destructor]: Can't uninitialize D3DX Utility Library ! Error: D3DXERR_D3DXNOTSTARTEDYET .... <zRndD3D.h,#127>
    [w] 00:36 Warn:  0 ==    ===================================== UNHANDLED EXCEPTION OCCURED ====================================================== .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 ==    ============================================ CRASH INFOS: ============================================================== .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 Go    thic II - 2.6 (fix), Parser Version: 50 .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 Us    er:  Necon,  CPUType: 586,  Mem: 1024 MB total, 1024 MB free .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 Ca    mera: Pos(30057.5078/5396.40283/-15494.1572), At(-0.546639383/-0.187057331/-0.816207647) .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 St    artup Options: .... <zWin32.cpp,#2976>
    [w] 00:36 Warn:  0 -g    ame:gothicgame.ini -zreparse -zwindow -znomusic -znosound -zlog:4,s
    
     .... <zWin32.cpp,#2977>
    [w] 00:36 Warn:  0 ==    ============================================= CALLSTACK : ============================================================== .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:006F77E6 (0x1DA6FE60 0x00AB4118 0x00AB40C0 0x0082E6F0) Gothic2.exe, oCMsgState::operator delete()+87862 byte(s), P:\dev\g2addon\release\Gothic\_ulf\oGameExternal.cpp, line 6529+20 byte(s) .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:00792568 (0x006F77C0 0x0088E4AD 0x16911508 0x0082E6F0) Gothic2.exe, zCParser::DoStack()+3080 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zParser.cpp, line 1433 .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:00792CBF (0x00AB40C0 0x00004183 0x16910F80 0x00000000) Gothic2.exe, zCParser::CallFunc()+719 byte(s), P:\dev\g2addon\release\ZenGin\_ulf\zParser.cpp, line 1551 .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:0076CACD (0x00004183 0x00000000 0x00000000 0x00000000) Gothic2.exe, oCNpc_States::StartAIState()+653 byte(s), P:\dev\g2addon\release\Gothic\_ulf\oNpcStates.cpp, line 593 .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:0075A915 (0x198EE264 0x16910F80 0x000000D8 0x00000000) Gothic2.exe, oCNpc::AssessPlayer_S()+469 byte(s), P:\dev\g2addon\release\Gothic\_ulf\oNpc.cpp, line 14733 .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:0069C26A (0xFFFFFFFF 0x0054A7FD 0x00000000 0x00000000) Gothic2.exe, oCAIHuman::DoAI()+1978 byte(s), P:\dev\g2addon\release\Gothic\_ulf\oAiHuman.cpp, line 2678 .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:008103D8 (0xFFFFFFFF 0x00602E59 0x16910F80 0x0135FB28) Gothic2.exe, SetFileAttributesA()+182292 byte(s) .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:008172A0 (0xFFFFFFFF 0x00425E6E 0x00400000 0x01373E3A) Gothic2.exe, SetFileAttributesA()+210652 byte(s) .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:0081A3FE (0x0000000F 0x0078188B 0x0082F0EC 0x0001116E) Gothic2.exe, SetFileAttributesA()+223290 byte(s) .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:007E91F6 (0x00000000 0x00503270 0x0000002C 0x01C4B2FB) Gothic2.exe, SetFileAttributesA()+22066 byte(s) .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:0082933B (0x00831450 0x00000000 0x0135FF80 0x00502DFD) Gothic2.exe, SetFileAttributesA()+284535 byte(s) .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:007D3544 (0x00843D80 0x00000000 0x0135FF94 0x74A18484) Gothic2.exe, _except_handler3 .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:007D3544 (0x5960172C 0x00000000 0x0135FFEC 0x779F2FBA) Gothic2.exe, _except_handler3 .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:77A02510 (0x00000000 0x00000000 0x007D4318 0x00205000) ntdll.dll, wcstombs()+112 byte(s) .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 00    23:77A0EC37 (0x00000000 0x00000000 0x00000000 0x00000000) ntdll.dll, RtlCaptureContext()+247 byte(s) .... <zError.cpp,#474>
    [w] 00:36 Warn:  0 ==    ===================================== UNHANDLED EXCEPTION OCCURED ====================================================== .... <zError.cpp,#474>
    [w] 00:39 Warn:  0 B:     GMAN: gameSession is existing. Call CGameManager::Done() before! .... <oGameManager.cpp,#375>

Seite 3 von 9 « Erste 1234567 ... Letzte »

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
Impressum | Link Us | intern
World of Gothic © by World of Gothic Team
Gothic, Gothic 2 & Gothic 3 are © by Piranha Bytes & Egmont Interactive & JoWooD Productions AG, all rights reserved worldwide