PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Könnte dies bitte mal jemand kompilieren (gcc 3.2)


Rudi
2003-04-30, 16:05:12
Ich hätte hier mal ein Code-Snippet, was bei mir eine Access-Violation bringt, ich bin mir ziemlich sicher, zu wissen warum, allerdings wären ein paar Resultate von anderen zur Vergewisserung ganz gut.

Am liebsten wären mir folgende Testbedingungen:

Win98 (SE) als OS

Der gcc is' als Kompiler Vorraussetzung:
gcc 3.2 (mingw special 20020817-1)

mit folgender Kommandozeile:

"Compiler: Default compiler
Building Makefile: "C:\Eigene Dateien\MyProjects\SegFaultTest\Makefile.win"
Führt make clean aus
rm -f winmain.o SegFaultTest2.exe

g++.exe -D__DEBUG__ -c winmain.cpp -o winmain.o -I"C:/PROGRAMME/DEV-CPP/include/c++" -I"C:/PROGRAMME/DEV-CPP/include/c++/mingw32" -I"C:/PROGRAMME/DEV-CPP/include/c++/backward" -I"C:/PROGRAMME/DEV-CPP/include" -g3

g++.exe -D__DEBUG__ winmain.o -o "SegFaultTest2.exe" -L"C:/PROGRAMME/DEV-CPP/lib" -L"C:/Programme/Dev-Cpp/lib/DxLibs" -mwindows

Ausführung beendet
Kompilierung erfolgreich
"

Die Verzeichnisse sind egal ;), aber es kommt mir halt auf die Compiler-Schalter an.

Nun der Code:

#include <windows.h>
#include <stdio.h>

/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
void CallMe(HWND, UINT, HINSTANCE, HINSTANCE);
void DoSomething(void);

/* Make the class name into a global variable */
char szClassName[ ] = "WindowsApp";
FILE * stream = NULL;
unsigned char ksarray[256];
unsigned char ToAsciiTable[256][256];

int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)

{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */

/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);

/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;

/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Windows App", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);

/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);

CallMe(hwnd, 12345, hThisInstance, hPrevInstance);

/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}

/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}


/* This function is called by the Windows function DispatchMessage() */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}

return 0;
}

void CallMe(HWND hwnd, UINT number, HINSTANCE hInstance, HINSTANCE prevInstance)
{
DoSomething();

if(prevInstance != 0)
{
stream = fopen("bla.txt", "wb");
fprintf(stream, "prevInstance branch reached !\n");
fclose(stream);
}
else
{
stream = fopen("bla.txt", "wb");
fprintf(stream, "prevInstance branch reached !\n");
fclose(stream);
}

if(hInstance != 0)
{
stream = fopen("bla.txt", "wb");
fprintf(stream, "hInstance branch reached !\n");
fclose(stream);
}
else
{
stream = fopen("bla.txt", "wb");
fprintf(stream, "hInstance branch reached !\n");
fclose(stream);
}

if(number != 0)
{
stream = fopen("bla.txt", "wb");
fprintf(stream, "number branch reached !\n");
fclose(stream);
}
else
{
stream = fopen("bla.txt", "wb");
fprintf(stream, "number branch reached !\n");
fclose(stream);
}

if(hwnd != 0)
{
stream = fopen("bla.txt", "wb");
fprintf(stream, "hwnd branch reached !\n");
fclose(stream);
}
else
{
stream = fopen("bla.txt", "wb");
fprintf(stream, "hwnd branch reached !\n");
fclose(stream);
}
}

void DoSomething()
{
WORD output;
int k=0,i=0,s=0;

for (k=0; k<=255; k++)
{
ksarray[k]=0;
}

for (i=0; i<=255; i++)
{
for (s=0; s<=255; s++)
{
if(ToAscii(i,s,&ksarray[0],&output,0))
{
ToAsciiTable[i][s] = (unsigned char)output;
}
else
{
ToAsciiTable[i][s] = 0;
}
}
}
}


Danke im Vorraus für die Mühe,falls die sich jemand macht. :D

Rudi
2003-05-05, 21:47:48
Nun gut, vielleicht als 'Auflösung', falls man nicht dahinter gekommen ist bzw. es jemanden interessiert. :D
Die Funktion CallMe() bekommt einfach ein paar Parameter mit, weil der Zugriff auf diese, die Access Violation auslösen wird.
CallMe() selbst ruft die Funktion DoSomething() auf.
Und jetzt kommt das Wichtigste.
DoSomething() deklariert sofort eine lokale Variable mit WORD-Grösse (2 Byte), dafür reserviert der gcc tatsächlich genau 2 Byte auf dem Stack.
Zu dem Zeitpunkt liegt sozusagen als 'Nachbar' der gesicherte Basepointer von CallMe() 'daneben'.
Die ganzen Schleifen kann man ignorieren, die habe ich nur mit reingenommen, da so der Originalcode aus 'ALiens versus Predator' aussieht, bei dem ich auf dieses Problem gestossen bin.
Aber zurück zu dieser engen Nachbarschaft, diese wird nämlich dann zum Problem, wenn die Win-API Funktion ToAscii() aufgerufen wird.
Diese Funktion bekommt nämlich unter anderem einen Zeiger auf einen WORD-Wert mit (und ich habe eben nochmal auf der MSDN Seite nachgeschauen -> LPWORD), nur leider beschränkt sich ToAscii scheinabr nicht auf eben diese 2 Byte und manipuliert 4 Byte --> riesen Kacke, da der gcc nur 2 Byte für WORD auf dem Stack gedacht hatte --> damit überschreibt ToAscii() indirekt die zwei niederwertigsten Bytes des gespeicherten Basepointers.
Wenn dann DoSomething() verlassen wird, wird natürlich auch ein inkorrekter Basepointer vom Stack geholt und das ganze endet dann in einer Access Violation, wenn CallMe() auf irgendwelche Variablen zurückgreifen will, da der BasePointer ausserhalb des Stackframes ist.

Ich hab's net weiter untersucht, aber je nach dem wird in dem Fall der Basepointer von ToAscii() zerrammelt, im schlechtesten Fall gibt's ne Access Violation (Stackpointer grösser als Basepointer) und im nich' ganz so schlechten Fall werden vollkommen falsche Werte über den Basepointer angesprochen.

Unregistered
2003-05-05, 23:18:01
Nochmal kurz "ich", die Schleifen kann man net weglassen, da ohne die Schleifen ein Aufrufen von ToAscii() scheinbar korrekt funktioniert, aber trotzdem ist was faul, die Schleifen alleine wiederum laufen korrekt durch, wenn man ToAscii() weglässt, zumindest bei mir ... von wegen _deterministischer_ endlich Automat ... pah :D
Egal, die Ursache ist aber definitiv ein teilweise überschriebener Basepointer auf dem Stack und man kann das halt dadurch verhindern hier, dass man output min als 4 Byte Variable deklariert, wer aber warum, wie wo, wann was überschreibt ---> ich kann's net wirklich sagen, der Assembler Output von dem Programm hier überschreibt nix, da bin ich mir eigentlich fast 100%-ig sicher.
Falls jemand andere Ideen dazu hat, immer her damit...

Rudi