Eigenartiges Verhalten in String-Klasse

Normal werden die Konstanten in einem schreib-geschützten Segment gelagert, dann gibt es einen Fehler und das Programm stürzt ab, wenn versucht wird, darauf zu schreiben.
Wobei man das auch umgehen kann...

Ansonsten (siehe squeaker) einfach mal Breakpoint auf die Zuweisung und lässt dir nebenher den asm-code (Rechtsklick->Gehe zu Disassemblierung) dazu anzeigen, dann kannst du alles genau mitverfolgen.
Dann schaust du erstmal, ob der entsprechende Speicherbereich (der Konstanten "HALLO") schon vor der Zuweisung unbrauchbar ist.
Dann geh es einfach Schritt für Schritt durch und schau an welcher Stelle es unbrauchbar wird (das solltet ihr ja zumindest bei eurer selbstgeschriebenen String-Klasse erkennen, da ihr deren Verhalten genau kennt.)
 
Hmm... dann muss mir mal jemand sagen, wie man in Visual C++ 6.0 / Visual Studio die Stack-Größe einstellt.

Das mit dem Assembler-Code durchsteppen machen wir mal...

Hmm... habe mal strcpy durchgesteppt. Wenn ecx mit 0x12345678 geladen ist und man

Code:
mov eax,dword ptr[ecx]

was sollte dann in eax drinstehen? Bei uns steht dann 0x00000000 drin.

Er läuft dadurch an der Direktive

Code:
test eax, 0x81010100
je main_loop

vorbei.

Hier mal der Code-Abschnitt:
PHP:
copy_start:
10218FC1   mov         ecx,dword ptr [esp+0Ch]
10218FC5   test        ecx,3
10218FCB   je          main_loop_entrance (10218fe6)
src_misaligned:
10218FCD   mov         dl,byte ptr [ecx]
10218FCF   inc         ecx
10218FD0   test        dl,dl
10218FD2   je          byte_0 (10219038)
10218FD4   mov         byte ptr [edi],dl
10218FD6   inc         edi
10218FD7   test        ecx,3
10218FDD   jne         src_misaligned (10218fcd)
10218FDF   jmp         main_loop_entrance (10218fe6)
main_loop:
10218FE1   mov         dword ptr [edi],edx
10218FE3   add         edi,4
main_loop_entrance:
10218FE6   mov         edx,7EFEFEFFh
10218FEB   mov         eax,dword ptr [ecx] // eax ist hiernach 0x00000000
10218FED   add         edx,eax // edx verändert sich darum natürlich nicht
10218FEF   xor         eax,0FFFFFFFFh // eax ist hiernach 0xFFFFFFFF
10218FF2   xor         eax,edx // eax ist hiernach 0x81010100
10218FF4   mov         edx,dword ptr [ecx] // edx ist hiernach 0x00000000
10218FF6   add         ecx,4
10218FF9   test        eax,81010100h // schlägt offenbar fehl
10218FFE   je          main_loop (10218fe1) // läuft er drüberweg
10219000   test        dl,dl
10219002   je          byte_0 (10219038)
10219004   test        dh,dh
10219006   je          byte_1 (1021902f)
10219008   test        edx,0FF0000h
1021900E   je          byte_2 (10219022)
10219010   test        edx,0FF000000h
10219016   je          byte_3 (1021901a)
10219018   jmp         main_loop (10218fe1)
 
Zuletzt bearbeitet:
Also bei dem Befehl
Code:
mov eax, dword ptr[ecx]
wird das nach eax geladen, was an ecx steht.
In C++ ausgedrückt wäre es:
Code:
int* ecx = ... ;
int eax = *ecx;
In ecx steht hier in diesem strcpy immer der Zeiger auf die aktuelle Position. In eax stehen dann also immer 4 Bytes des ausgelesenen zu kopierenden Strings. Wenn in eax irgendwann mindestens ein Byte 0 ist, muss mit Kopieren aufgehört werden.
Wenn das im ersten Durchgang ist, dann stimmt offensichtlich was nicht.



Dieser Code dient dazu, herauszufinden ob irgendein Byte in eax 0 ist. Ist unwahrscheinlich kompliziert und, obwohl es nicht so aussieht, unwahrscheinlich schnell.
Code:
10218FE6   mov         edx,7EFEFEFFh 
10218FEB   mov         eax,dword ptr [ecx]
10218FED   add         edx,eax
10218FEF   xor         eax,0FFFFFFFFh
10218FF2   xor         eax,edx
10218FF4   mov         edx,dword ptr [ecx]
10218FF6   add         ecx,4 
10218FF9   test        eax,81010100h
10218FFE   je          main_loop (10218fe1)
Falls kein Byte 0 ist, wird per je/jz (Jump if Zero) wieder zurück zum Hauptteil der Schleife gesprungen.
Da aber gleich 4 Bytes 0 waren, geht es hier dann weiter, das ist korrekt.

Der Rest hiervon dient nur dazu, herauszufinden welches das erste der 4 Bytes mit dem Wert 0 ist und dann an eine für diesen Fall vorgesehene Stelle zu springen, damit die vorhergehenden Bytes noch kopiert werden können.
Code:
10219000   test        dl,dl 
10219002   je          byte_0 (10219038) 
10219004   test        dh,dh 
10219006   je          byte_1 (1021902f) 
10219008   test        edx,0FF0000h 
1021900E   je          byte_2 (10219022) 
10219010   test        edx,0FF000000h 
10219016   je          byte_3 (1021901a) 
10219018   jmp         main_loop (10218fe1)

Du musst also (falls dword ptr[ecx] schon im ersten Durchgang 0 war) verfolgen, wo der Zeiger auf den String untergegangen ist, bzw ob er schon ungültig war, zu dem Zeitpunkt, an dem er auf den Stack gepushed wurde.
-> Also vor Funktionsbeginn schauen welcher Wert als erstes gepushed wird (denn gepushed werden die Parameter von rechts nach links) und per Speicherfenster schauen, ob dieser Wert auch wirklich auf den Speicherbereich verweisst, an dem dein String liegt.
Oder ob dieser Zeiger stimmt und die strcpy Funktion vielleicht nur den falschen Wert vom Stack holt (also mal ecx mit dem gepushten Wert vergleichen)

Achja: was dir das helfen könnte weiss ich aber eigentlich auch nicht. So hättest du nur dein Problem besser lokalisiert.
 
Zuletzt bearbeitet:
Zurück