Toon posts:

[c++] Linked list probleempje

Pagina: 1
Acties:
  • 140 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Er zijn geen errors als telkens het laatste item uit de lijst wordt verwijderd, vanaf dat er één van de middenste wordt verwijderd(dus alles behalve de eerste en de laatste) zal bij het verwijderen van eender welk ander lijst item een fout worden gegeven.
Qua uitvoering geeft het programma geen problemen, want de items worden wel degelijk uit de lijst verwijderd. Ik vermoed dat het opkuisen van de linked list items (bij het verwijderen van een item) niet wordt gedaan zoals het moet... (ja, weeral die kl*** delete ws).

De foutmelding is:
De leesbewerking "read" op het geheugen is mislukt

Nota: Nieuwe items worden vooraan in de lijst geplaatst.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
struct LL_SOCKETS {
   SOCKET sock;         // client socket
   int id;              // player server ID
   int score;           // current player score
   int ping;            // current ping
   float pingStartTime; // start time of last ping poll
   char* nick;          // player nickname
   LL_SOCKETS *next;    // pointer to next list item
};

extern LL_SOCKETS *ll_tex_start;    // start pointer of list
LL_SOCKETS *ll_sock_start = NULL;
int connectedUsers = 0;             // counts amount of connected users


//add an item in the list (WERKT PERFECT!)
int LL_Sockets_Add(SOCKET insocket)
{
    static int idCounter;
    idCounter++;
    LL_SOCKETS *new_item = new LL_SOCKETS;       // make a new list item
    new_item->sock = insocket;
    new_item->id = idCounter;                    // define the new item
    new_item->nick = "undefined";
    new_item->pingStartTime = 0.0f;
    new_item->ping = 0;
    new_item->next  = ll_sock_start;             // push the list a bit further to the right
    ll_sock_start = new_item;                    // set the start pointer to the this item
    Cns_Addline("[socket added to list]");
    connectedUsers++;
    return idCounter;
}


// IN DEZE FUNCTIE ZIT DE FOUT:
// remove a socket from the linked list
void LL_Sockets_Remove(SOCKET insock)
{
    LL_SOCKETS *ll_sock_current = NULL;            // current read pointer
    LL_SOCKETS *ll_sock_previous = NULL;           // previous read pointer
    ll_sock_previous = ll_sock_start;              // set previous read pointer to start item
    ll_sock_current = ll_sock_start->next;         // set current read pointer to the second item
    LL_Sockets_Viewlist();                         // view the socket list (details of all clients)
    if (ll_sock_start->sock == insock)             // socket to delete is first socket in list
    {
        if (ll_sock_start->next)                   // there is a list item after this list
        {
            Cns_Addline("FIRST CLIENT DISCONNECTS, THERE IS A SECOND CLIENT AFTER 1ST");
            delete(ll_sock_start);
            ll_sock_start = new LL_SOCKETS;
            ll_sock_start = ll_sock_start->next;
        } else {                                   // first (and only) list item
            Cns_Addline("FIRST CLIENT DISCONNECTS, ONLY CLIENT IN LIST");
            delete(ll_sock_start);
            ll_sock_start = new LL_SOCKETS;
            ll_sock_start = NULL;
        }
        connectedUsers--;
        return;
    } else {                                       // look further in list
        Cns_Addline("CLIENT DISCONNECTS, NOT FIRST CLIENT IN LIST");
        while (ll_sock_current)
        {
            if (ll_sock_current->sock == insock)
            {
                if (ll_sock_current->next != NULL) // item to be removed is NOT the last list item in the list
                {
                    Cns_Addline("TYPE 1");
                    ll_sock_previous->next = ll_sock_current->next;
                    delete(ll_sock_current);
                } else {                           // item to be removed is last list item
                    Cns_Addline("TYPE 2");
                    ll_sock_previous->next = NULL;
                    delete(ll_sock_current);
                }
                connectedUsers--;
                return;
            }
            ll_sock_previous = ll_sock_current;      // store current socket in 'previous socket' pointer
            ll_sock_current = ll_sock_current->next; // read next socket
        }
     }
}

Verwijderd

aangezien je c++ gebruikt wel eens overwogen gewoon std::vector te gebruiken?

Verwijderd

Topicstarter
Verwijderd schreef op 21 March 2003 @ 14:06:
aangezien je c++ gebruikt wel eens overwogen gewoon std::vector te gebruiken?
heb ik ooit eens gebruikt voor chars
thanks vr de hint
*zoekt meer info over vectors en of het ook voor structs werkt*

[ Voor 6% gewijzigd door Verwijderd op 21-03-2003 14:10 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

allereerst vind ik dit een wazige constructie:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    if (ll_sock_start->sock == insock)             // socket to delete is first socket in list 
    { 
        if (ll_sock_start->next)                   // there is a list item after this list 
        { 
            Cns_Addline("FIRST CLIENT DISCONNECTS, THERE IS A SECOND CLIENT AFTER 1ST"); 
            delete(ll_sock_start); 
            ll_sock_start = new LL_SOCKETS; 
            ll_sock_start = ll_sock_start->next; 
        } else {                                   // first (and only) list item 
            Cns_Addline("FIRST CLIENT DISCONNECTS, ONLY CLIENT IN LIST"); 
            delete(ll_sock_start); 
            ll_sock_start = new LL_SOCKETS; 
            ll_sock_start = NULL; 
        } 
           connectedUsers--; 
        return; 
    }


Je kijkt of ie aan het begin van de lijst staat. Dat is goed. Als dat zo is, zijn er 2 mogelijkheden: er komt een entry na, of er komt geen entry na. Als er geen na komt is ll_sock_start->next natuurlijk NULL.
als je dat weet dan hoef je dus ook geen special case code ervoor te schrijven: als ll_sock_start->next gelijk is aan NULL, dan kun je ll_sock_start ook wel laten wijzen naar ll_sock_start->next (net als bij het geval dat er wel een entry na komt), aangezien dat toch null is.

Maar er is nog iets: bij het geval dat er wel een entry na komt, delete je eerst de entry, en daarna ga je nog data ervan opvragen (je wilt tenslotte de next weten). Dat geheugen is al vrijgegeven, en kun je dus ook niet meer opvragen (dit gaat soms wel goed en soms niet goed, maar technisch gezien is het gewoon fout)

Verder maak je ook nog een new LL_SOCKET aan. Waarom je dat doet is me geheel onduidelijk :?

maar goed, ik zou je code herschrijven naar dit:
C++:
1
2
3
4
5
6
    if (ll_sock_start->sock == insock)             // socket to delete is first socket in list 
    {
            LL_SOCKETS * next = ll_sock_start->next;
            delete ll_sock_start;
            ll_sock_start = next;
    }





goed, kom je in het 2e gedeelte, namelijk dat ie niet aan het begin van de lijst staat. Je zoekt de entry op in een while lus, en houdt steeds de vorige entry bij zodat je de next pointer aan kan passen. Dat is goed. Ook hier heb je weer een onnodige special case voor het geval er geen entry achter staat. Ook hier is dat niet nodig. De rest klopt ongeveer wel

Maar goed, waarom uberhaupt een apart geval voor het begin van de lijst? Dat kun je net zo goed combineren met het andere stuk code:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void LL_Sockets_Remove(SOCKET insock) 
{
    for (LL_SOCKETS * prev = NULL, * cur = ll_socket_start; cur; prev = cur, cur = cur->next)
    {
        if (cur->sock == insock)
        {
            if (prev)
                 prev->next = cur->next;
            if (cur == ll_sock_start)
                 ll_sock_start = cur->next;
            delete cur;
            connectedUsers--; 
            break;
        }
    }
}


stukkie korter, niet? ;)

Verder kun je in dit geval beter std::set gebruiken :)

[ Voor 4% gewijzigd door .oisyn op 21-03-2003 14:18 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
.oisyn:

Verder maak je ook nog een new LL_SOCKET aan. Waarom je dat doet is me geheel onduidelijk
-> stupidity seems to rule my mind the last week :(

Die grote if-tak structuur was om het geheel op te splitsen in deel-problemen. Ik wou zien of de foutmelding in sommige gevallen er niet was. Bedankt voor de uitleg!
*zoekt std::set op*

[edit] Mag ik jou ook aan de credits toevoegen?

[ Voor 36% gewijzigd door Verwijderd op 21-03-2003 14:33 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

dat was niet het enige waar ik het over had
Maar er is nog iets: bij het geval dat er wel een entry na komt, delete je eerst de entry, en daarna ga je nog data ervan opvragen (je wilt tenslotte de next weten). Dat geheugen is al vrijgegeven, en kun je dus ook niet meer opvragen (dit gaat soms wel goed en soms niet goed, maar technisch gezien is het gewoon fout)

[ Voor 80% gewijzigd door .oisyn op 21-03-2003 14:29 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
.oisyn schreef op 21 March 2003 @ 14:29:
dat was niet het enige waar ik het over had

[...]
inderdaad, die fout zag ik ook zopas maar :$ net voordat ik ging eten had ik zitten prutsen met die code en toen ik ging eten heb ik snel ff nog die lijntjes code aangepast, waardoor de volgorde van die code dus niet meer klopte (deleten van dat item vóór de data van dat item werd gebruikt)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 21 maart 2003 @ 14:23:
[edit] Mag ik jou ook aan de credits toevoegen?


maar natuurlijk ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
De thread - waarin de remove functie van deze linked list wordt toegepast - crasht nog steeds ;(
En het gebeurt enkel als een van de middelste clients uit de linked list disconnect.

De algemene pseudocode structuur is:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
DWORD WINAPI ThreadHandler(void* insocket_)
{
    int returnwaarde = 0;

    do
    {
        invoer = LeesCharVanSocket(socket);
        if (invoer != NETWERK_ERROR)
        {
            VerhandelData(invoer); // break bij \n
        } else {
            break;
        }
    } while (invoer != NETWERK_ERROR)

    int spelerID = ZoekSpelerIDInLijst(socket);
    char* spelerNaam = ZoekSpelerNaamInLijst(socket);

    LL_Socket_Remove(socket); // code van daarnet

    if (SluitConnectie(socket))
    {
        cout >> "OK";
    } else {
        cout >> "ERROR";
        returnwaarde = 3;
    }

    return returnwaarde;
}


[edit] onder welke naam mag ik je plaatsen .oisyn?

[ Voor 16% gewijzigd door Verwijderd op 21-03-2003 14:55 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

wanneer crasht ie? weer bij het returnstatement?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
.oisyn schreef op 21 maart 2003 @ 15:29:
wanneer crasht ie? weer bij het returnstatement?
nog steeds daar, ja ;( hij geeft nog steeds de "read" foutmelding.
Als ik een eindeloze loop plaats zoals deze, nét vóór de return statement dan loopt hij niet vast:
C++:
1
2
while (1)
    sleep(10000);


[edit xal de code maar effe toevoegen]
Nota:
- Cns_Addline(char*) voegt een char* toe aan de console-uitvoer
- Cns_AddToLastline(char*) voegt een char* toe aan de laatste console-uitvoerlijn

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// a client thread to start when a new client has succesfully connected
DWORD WINAPI ThreadHandler(void* insocket_)
{
    int retval = 0;
    int readBytes;
    char readBuffer;
    SOCKET insocket = (SOCKET)insocket_;
    ostringstream sstream;
    do // main loop
    {
        readBytes = recv(insocket, &readBuffer, 1, 0); // read 1 character
        if (readBytes > 0) { // handle valid data only
            switch (readBuffer)
            {
                case '\n': // received end of line character
                    Cns_Addline("Received %d bytes from client [%s]", 0, sstream.str().c_str());
                    //LL_Sockets_SendAll(resultString);
                    if (!strcmp(sstream.str().c_str(), "P")) // ping command
                        PingReply(insocket);                 // execute ping
                    LL_Sockets_SendAllButSelf(sstream.str().c_str(), insocket);
                    sstream.str("");
                    break;
                default: // adding character buffer to databuffer vector
                    sstream << readBuffer;
                    break;
            }
        } else if (readBytes == SOCKET_ERROR) {
            Cns_Addline(WSAGetLastErrorMessage("Handling of packages failed"));
            LookupSocketData(insocket); // print out socket info from linked list (eg nickname)
            retval = 3;
        }
        // check for buffer overflows (security)
        if (strlen(sstream.str().c_str()) > RECEIVEBUFFERMAX)
        {
            Cns_Addline("Buffer overflow");
            retval = 3;
            break;
        }
    } while (readBytes != 0);

    int playerID = LL_Sockets_GetID(insocket);       // get player ID from linked list
    char* playerNick = LL_Sockets_GetNick(insocket); // get player nick from linked list

    Cns_Addline("Connection closed by peer [ID %d] [Nick %s]", playerID, playerNick);

    // clean up
    LL_Sockets_Remove(insocket);
    Cns_Addline("Socket removed from list [ID %d] [Nick %s]", playerID, playerNick);//REMOVE THIS IN THE FUTURE
    Cns_Addline("Shutting connection down [ID %d] [Nick %s] ... ", playerID, playerNick);//REMOVE THIS IN THE FUTURE
    if (ShutdownConnection(insocket))
        Cns_Addtolastline("[ok]");
    else
    {
        Cns_Addtolastline(WSAGetLastErrorMessage("[error: Connection shutdown failed"));
        retval = 3;
    }

    return retval;
}

[ Voor 112% gewijzigd door Verwijderd op 21-03-2003 21:21 ]


  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Aangezien je het in je vorige post over een multithreaded server had, heb je wel een vorm van synchronisatie ingebouwd (mutex, critical section o.i.d.) voor het gebruik van de linked list die zo te zien globaal is? Anders gaan 2 threads tegelijk met dezelfde structures klooien en volgens Murphy's law gaat dat gegarandeerd fout :).
Weet je trouwens zeker dat ie precies op het return statement crasht? Wat is de volledige foutmelding (inclusief geheugenadres waar ie dus niet kan lezen)? Een crash bij een return kan eigenlijk alleen maar als een of andere destructor van een lokaal object aangeroepen wordt die op 1 of andere manier crasht (maar dan zou je daar in crashen en bovendien zie ik geen lokale objecten bij je), of als de stack corrupt is.
Hoe ziet je Cns_Addline eruit? Gebruik je daar een (w)(s)printf? Zoja, is je buffer groot genoeg? Buffer overflow kan zeker een crash bij het returnen veroorzaken.
Misschien is dit allemaal niet het geval maar kan het in ieder geval maar vragen voor de zekerheid.

www.madwizard.org


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

staat er in je debugger een groene driehoek-vormige pijl op de regel van de returnstatement? Dan is het dus niet de return, maar de statement die daar direct voor komt.

.edit: oh, ik ging er trouwens misschien ten onrechte vanuit dat je MSVC gebruikte :)

[ Voor 21% gewijzigd door .oisyn op 21-03-2003 21:41 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
madwizard schreef op 21 maart 2003 @ 21:34:
Aangezien je het in je vorige post over een multithreaded server had, heb je wel een vorm van

synchronisatie ingebouwd (mutex, critical section o.i.d.) voor het gebruik van de linked list die

zo te zien globaal is? Anders gaan 2 threads tegelijk met dezelfde structures klooien en volgens

Murphy's law gaat dat gegarandeerd fout :).
De thread gebruiken idd dezelfde structures, maar niet tegelijk, want ik disconnect de clients één voor één. Of mag dat niet?
Weet je trouwens zeker dat ie precies op het return statement crasht? Wat is de volledige

foutmelding (inclusief geheugenadres waar ie dus niet kan lezen)? Een crash bij een return kan

eigenlijk alleen maar als een of andere destructor van een lokaal object aangeroepen wordt die op

1 of andere manier crasht (maar dan zou je daar in crashen en bovendien zie ik geen lokale

objecten bij je), of als de stack corrupt is.
Ik weet heel zeker dat het enkel op de return statement crasht, maar de foutmelding van de debugger luidt anders dan die van windows:
"An acces violation (segmentation fault) raised in your program"
Als ik voor die returnwaarde een eindeloze loop zet, dan krijg ik die foutmelding niet en werkt het programma perfect.
Hoe ziet je Cns_Addline eruit? Gebruik je daar een (w)(s)printf? Zoja, is je buffer groot genoeg?

Buffer overflow kan zeker een crash bij het returnen veroorzaken.
Misschien is dit allemaal niet het geval maar kan het in ieder geval maar vragen voor de

zekerheid.
Geen printf varianten hierzo. De code geeft niet áltijd een foutmelding, want als de clients op een bepaalde volgorde disconnecten, dan lukt het wél.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
char* consoleBuffer[CNS_LINES]; // console buffer
char inputBuffer[CNS_CHARWIDTH];// input buffer

void Cns_Addline(const char *format, ...)
{
    char buffer[CNS_CHARWIDTH];
    int i;
    va_list errmsg;
    va_start (errmsg, format);
    vsprintf (buffer, format, errmsg);
    va_end (errmsg);

    if(consoleBuffer[0] != NULL)                            // free up the memory for the line to be discarded
        free(consoleBuffer[0]);

    for(i=0; i<CNS_LINES-1 && consoleBuffer[i]!=NULL; i++)  // move existing pointers up one line
        consoleBuffer[i] = consoleBuffer[i+1];

    consoleBuffer[i] = (char*)malloc( strlen(buffer) + 1);    // allocate memory for new line
    strcpy(consoleBuffer[i], buffer);                         // copy new line to allocated memory 
    Cns_Render();
}

Verwijderd

Topicstarter
.oisyn schreef op 21 maart 2003 @ 21:40:
staat er in je debugger een groene driehoek-vormige pijl op de regel van de returnstatement? Dan is het dus niet de return, maar de statement die daar direct voor komt.

.edit: oh, ik ging er trouwens misschien ten onrechte vanuit dat je MSVC gebruikte :)
Nee, de debugger van Dev-C++ is niet echt duidelijk, er staat ook nergens duidelijke info over die debugger ;(

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Verwijderd schreef op 21 March 2003 @ 21:50:
De thread gebruiken idd dezelfde structures, maar niet tegelijk, want ik disconnect de clients één voor één. Of mag dat niet?
Dat mag wel, als je er maar zeker van bent dat ze nooit dezelfde structures tegelijk gebruiken gaat het goed :).
Ik weet heel zeker dat het enkel op de return statement crasht, maar de foutmelding van de debugger luidt anders dan die van windows:
"An acces violation (segmentation fault) raised in your program"
Als ik voor die returnwaarde een eindeloze loop zet, dan krijg ik die foutmelding niet en werkt het programma perfect.
En gewoon het programma los draaien zonder debugger? Dan krijg je wel uitgebreide foutinfo als het goed is.
Geen printf varianten hierzo. De code geeft niet áltijd een foutmelding, want als de clients op een bepaalde volgorde disconnecten, dan lukt het wél.
vsprintf lijkt me toch wel een printf variant.. Als je die console dingen allemaal weghaalt, crasht je programma dan nog steeds? Wel vreemd dat de volgorde uit maakt idd.

[ Voor 4% gewijzigd door madwizard op 21-03-2003 21:58 ]

www.madwizard.org


Verwijderd

Topicstarter
madwizard schreef op 21 maart 2003 @ 21:56:
[...]

Dat mag wel, als je er maar zeker van bent dat ze nooit dezelfde structures tegelijk gebruiken gaat het goed :).
dan is er geen probleem denk ik
En gewoon het programma los draaien zonder debugger? Dan krijg je wel uitgebreide foutinfo als het goed is.
Windows xp geeft dan een reusachtig hexadecimaal getint foutenrapport. Xal even de msvc debugger laten starten en de assembly code posten, dat lijkt me duidelijker.
De msvc debugger (VC6.0) geeft de volgende foutmelding:
"Unhandled exception in Server.exe: 0xC0000005: Acces violation"

GAS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
00403204   mov         ecx,dword ptr [edx]
00403206   mov         dword ptr [eax],ecx
00403208   add         esp,0F8h
0040320B   push        2
0040320D   lea         eax,[ebp-90h]
00403213   push        eax
00403214   call        00413780
00403219   add         esp,10h
0040321C   mov         eax,esi
0040321E   jmp         00403224
00403220   jmp         00403224
00403222   jmp         00403224
00403224   lea         esp,[ebp-118h]
0040322A   pop         ebx
0040322B   pop         esi
0040322C   leave
0040322D   ret         4
00403230   inc         ecx
00403231   arpl        word ptr [ebx+65h],sp
00403234   jo          004032AA
00403236   ???
00403237   and         byte ptr fs:[ebx+6Fh],ah
0040323B   outs        dx,byte ptr [esi]
0040323C   outs        dx,byte ptr [esi]
0040323D   arpl        word ptr gs:[ecx+ebp*2+6Fh],si
00403242   outs        dx,byte ptr [esi]
00403243   and         byte ptr [esi+72h],ah
00403246   outs        dx,dword ptr [esi]
00403247   ins         dword ptr [edi],dx
00403248   and         byte ptr ds:[64253A73h],ah
0040324E   add         byte ptr [ecx+63h],ah
00403251   arpl        word ptr [ebp+70h],sp
00403254   je          0040327E
00403256   sub         dword ptr [eax],esp
00403258   popa
vsprintf lijkt me toch wel een printf variant.. Als je die console dingen allemaal weghaalt, crasht je programma dan nog steeds? Wel vreemd dat de volgorde uit maakt idd.
hij crasht nog steeds...

Verwijderd

Topicstarter
Nota: Er komt een blauwe pijl aan de return lijn van de functie, dus daar crasht hij.

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

My Computer > Advanced > Error reporting > Disable error reporting aan en 'but notify me when critical error occurs' uit. Dan krijg je een duidelijkere foutmelding in win2k stijl.
De assembler code die je postte, is dat waar je code op dat moment zit? Aan het begin?
Probeer je code eens gewoon met MSVC te compilen in debug mode, dan staat de source ook tussen de disassembly. Het eerste deel ziet er uit als gewone code, het tweede meer als data. Lijkt dus niet op buffer overflow (krijg je meldingen als access violation op 0x48414C42 enzo, addressen die eigenlijk een deel van een string zijn), zeker niet omdat ie nog steeds crasht als je de console prints weghaald. Hoe ziet je stack trace eruit als ie crasht?

[ Voor 3% gewijzigd door madwizard op 21-03-2003 22:18 ]

www.madwizard.org


Verwijderd

Topicstarter
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[Switching to thread 3372.0xf3c]
breakpoint 1
Breakpoint 1,
frame-begin 0 0x4031f7
frame-function-name
ThreadHandler
frame-args
 (
   ... [alle argumenten]
 )
frame-source-begin
 at
frame-source-file-end
:
frame-source-end
source E:\C++\AlterNova\Server\Bin\serverlib.cpp:165:5579:beg:0x4031f7
frame-end
stopped
pre-prompt
(gdb)
prompt

post-prompt
error
pre-prompt
(gdb)
prompt
error-begin
The program is not being run.

pre-prompt
pre-prompt
post-prompt
error
pre-prompt
...


dit is alvast de dev-c++ debugger code (hij laat geen c/p toe van het debugvenster :() ik probeer zometeen alles in msvc++ te importeren.

Verwijderd

Topicstarter
De foutmelding - na je instellingstip - is nu:
De instructie op 0x00403204 verwijst naar geheugen op 0x009bff14. De lees- of schrijfbewerking ("read") op het geheugen is mislukt.
Volgens mij betekent dit dat er een stuk geheugen wordt gelezen dat niet meer is voorbehouden?

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Het kan zijn dat het een totaal ongeldig adres is (1 of andere niet geinitialiseerde variabele bijvoorbeeld), of een stuk geheugen dat gedealloceerd is.. Kun je de source bij 403204 krijgen (in msvc met een debug build rechtermuisknop en goto source). edit: Is bij een VC build dan waarschijnlijk een ander adres, maar igg gewoon het punt waar hij crasht ff source aanzetten en een stukje kopieren, zoiets:
code:
1
2
3
4
5
6
7
8
9
10
11
87:       int i = 4;
00401D08   mov         dword ptr [ebp-4],4
88:       cout << "test" << i;
00401D0F   mov         eax,dword ptr [ebp-4]
00401D12   push        eax
00401D13   push        offset string "test" (0047008c)
00401D18   push        offset std::cout (0047bdf0)
00401D1D   call        @ILT+680(std::operator<<) (004012ad)
00401D22   add         esp,8
00401D25   mov         ecx,eax
00401D27   call        @ILT+265(std::basic_ostream<char,std::char_traits<char> >::operator<<) (0040110e)

[ Voor 58% gewijzigd door madwizard op 21-03-2003 22:34 ]

www.madwizard.org


Verwijderd

Topicstarter
Nota bij deze debug code: de '165'staat voor regel 165, dit is de return regel van de thread functie.

Dit heb ik manueel overgetypt van de debugger:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
[begin van de thread]

frame-source-line
165
frame-source-end
frame-end
frame-begin 0x77e5d33b
#1
frame-address
0x77e5d33b
frame-address-end
 in
frame-function-name
_libwsock32_a_iname
frame-args
 ()
frame-end
pre-prompt
(gdb)
prompt


-----------ERROR HIERNA -----------------

post-prompt
frame-begin 0 0x40348f
 #0
 frame-function-name
 ThreadHandler
 frame-args
  (
  arg-begin
  insocket_
  arg-name-end
  =
  arg-value-
  0x764
  arg-end
  )
 frame-source-begin
  at
 frame-source-file
 source/serverlib.cpp
 frame-source-file-end
 :
 frame-source-line
 165
 frame-source-end
frame-end

frame-begin 1 0x77e5d33b
 #1
 frame-address
 0x77e5d33b
 frame-address-end
  in
 _libwsock32_a_iname
 frame-args
  ()
frame-end

pre-prompt
(gdb)
prompt

post-prompt
starting
frames-invalid
frames-invalid
frames-invalid
frames-invalid
frames-invalid
frames-invalid
signal
Program received signal

signal-name
 SIGSEGV
signal-name-end

signal-string
Segmentation fault
signal-string-end
.

frame-begin 0 0x40349c
 frame-address
 0x0040349c
 frame-address-end
  in
 frame-function-name
 ThreadHandler
 frame-args
  (
    ...
  )
 ...
 source E:\C++\AlterNova\Server\serverlib.cpp:165:5563:beg:0x40349c
frame-end
stopped
pre-prompt
(gdb)
prompt

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Van die dev-c++ output word ik niet veel wijzer, is de VC versie al gelukt?
Aan de eerdere assembler code die je liet zien blijkt wel dat ie vlak voor de return crasht. De return is hoogstwaarschijnlijk de ret 4 (de thread proc is de enige stdcall functie, C functies gebruiken gewoon ret), maar de crash zelf zit dus niet in de return maar in een ander stuk code dat daar vlak voor zit. Het lijkt ook niet duidelijk overeen te komen met een van de laatste regels van je thread functie, misschien dat gcc andere functies heeft zitten inlinen..
Als je de bijbehorende source op 1 of andere manier erbij kunt vinden (bij die mov ecx, [edx] dus) zou het een hoop schelen.

[ Voor 80% gewijzigd door madwizard op 21-03-2003 23:57 ]

www.madwizard.org


Verwijderd

Topicstarter
madwizard schreef op 21 March 2003 @ 23:51:
Van die dev-c++ output word ik niet veel wijzer, is de VC versie al gelukt?
neej, die geeft een fout bij het compilen:
E:\C++\AlterNova\Server\msvc\serverlib.cpp(114) : error C2065: 'ostringstream' : undeclared identifier
Daarna ook de volgende fouten, maar das ws omdat de ostringstream niet wordt herkend:
E:\C++\AlterNova\Server\msvc\serverlib.cpp(114) : error C2146: syntax error : missing ';' before identifier 'sstream'
E:\C++\AlterNova\Server\msvc\serverlib.cpp(114) : error C2065: 'sstream' : undeclared identifier
E:\C++\AlterNova\Server\msvc\serverlib.cpp(124) : error C2228: left of '.str' must have class/struct/union type
E:\C++\AlterNova\Server\msvc\serverlib.cpp(124) : error C2228: left of '.c_str' must have class/struct/union type
E:\C++\AlterNova\Server\msvc\serverlib.cpp(126) : error C2228: left of '.str' must have class/struct/union type
E:\C++\AlterNova\Server\msvc\serverlib.cpp(126) : error C2228: left of '.c_str' must have class/struct/union type
E:\C++\AlterNova\Server\msvc\serverlib.cpp(127) : error C2228: left of '.str' must have class/struct/union type
E:\C++\AlterNova\Server\msvc\serverlib.cpp(130) : warning C4552: '<<' : operator has no effect; expected operator with side-effect
E:\C++\AlterNova\Server\msvc\serverlib.cpp(139) : error C2228: left of '.str' must have class/struct/union type
E:\C++\AlterNova\Server\msvc\serverlib.cpp(139) : error C2228: left of '.c_str' must have class/struct/union type
Dit terwijl de nodige heades zijn geinclude (denk ik):
C++:
1
2
3
4
5
#include <iostream>
#include <istream>
#include <ostream>
#include <strstream>
#include <sstream>


Source erbij krijgen kan niet in Dev-C++ denk ik ;(

[ Voor 8% gewijzigd door Verwijderd op 21-03-2003 23:59 ]


  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

using namespace std erbij helpt ook niet?
Wat ik nog wel kan bedenken:
C++:
1
char* playerNick = LL_Sockets_GetNick(insocket); // get player nick from linked list

Aangenomen dat LL_Socket_GetNick(insock) gewoon een insock mapt naar een LL_SOCKETS en daar de nick member uit kopieert (de pointer dus)...
C++:
1
LL_Sockets_Remove(insocket); 

... en aangenomen dat deze remove functie ook de nick member dealloceert...
C++:
1
Cns_Addline("Socket removed from list [ID %d] [Nick %s]", playerID, playerNick);

... zou dit dus de mist in moeten gaan omdat de nick pointer niet meer bestaat...

Volgens mij klopt dat niet helemaal maar ik weet niet of je die nick überhaupt wel weer vrij maakt in je code, stond namelijk niet in 1 van je posts. In ieder geval zou ik daar ook gewoon een std::string van maken.
Ook zou dit niet uit moeten maken omdat dit wel goed zou moeten gaan als je die console dingen eruit haalt en dat had je al geprobeerd..
Gebruikt ShutdownConnection ook nog die LL_SOCKETS?
Als het niet te veel omschrijfwerk is zou ik gewoon alles overzetten in C++ stijl, dus met std::map of set en strings ipv char*.

www.madwizard.org


Verwijderd

Topicstarter
madwizard schreef op 22 March 2003 @ 00:59:
using namespace std erbij helpt ook niet?
Wat ik nog wel kan bedenken:
C++:
1
char* playerNick = LL_Sockets_GetNick(insocket); // get player nick from linked list

Aangenomen dat LL_Socket_GetNick(insock) gewoon een insock mapt naar een LL_SOCKETS en daar de nick member uit kopieert (de pointer dus)...
C++:
1
LL_Sockets_Remove(insocket); 

... en aangenomen dat deze remove functie ook de nick member dealloceert...
C++:
1
Cns_Addline("Socket removed from list [ID %d] [Nick %s]", playerID, playerNick);

... zou dit dus de mist in moeten gaan omdat de nick pointer niet meer bestaat...
Als ik die code in comment zet, dan geeft hij de fout nog steeds.
Volgens mij klopt dat niet helemaal maar ik weet niet of je die nick überhaupt wel weer vrij maakt in je code, stond namelijk niet in 1 van je posts. In ieder geval zou ik daar ook gewoon een std::string van maken.
Moét je elke char* terug vrijmaken?
Ook zou dit niet uit moeten maken omdat dit wel goed zou moeten gaan als je die console dingen eruit haalt en dat had je al geprobeerd..
Gebruikt ShutdownConnection ook nog die LL_SOCKETS?
Als het niet te veel omschrijfwerk is zou ik gewoon alles overzetten in C++ stijl, dus met std::map of set en strings ipv char*.
ShutdownConnection gebruikt geen LL_SOCKETS, enkel de socket zélf. (wordt de socket mss gewist als deze uit de linked list stucture wordt verwijderd, waardoor de shutdown niet werkt?).

Het probleem is dat ik de console functie heb gemaakt zodat hij argumenten aanneemt en deze argumenten mogen geen strings zijn :(

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Cns_Addline(const char *format, ...)
{
    char buffer[CNS_CHARWIDTH];
    int i;
    va_list errmsg;
    va_start (errmsg, format);
    vsprintf (buffer, format, errmsg);
    va_end (errmsg);

    if(consoleBuffer[0] != NULL)                            // free up the memory for the line to be discarded
        free(consoleBuffer[0]);

    for(i=0; i<CNS_LINES-1 && consoleBuffer[i]!=NULL; i++)  // move existing pointers up one line
        consoleBuffer[i] = consoleBuffer[i+1];

    consoleBuffer[i] = (char*)malloc( strlen(buffer) + 1);    // allocate memory for new line
    strcpy(consoleBuffer[i], buffer);                         // copy new line to allocated memory 
    Cns_Render();
}

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Verwijderd schreef op 22 maart 2003 @ 21:05:
Als ik die code in comment zet, dan geeft hij de fout nog steeds.
Ja het ligt blijkbaar niet aan die console functies. Maar het is wel een fout volgens mij, tenminste als je die char* had vrijgemaakt wat dus wel hoort.
Moét je elke char* terug vrijmaken?
Alles wat je alloceert moet je zelf ook weer dealloceren. Daarom is std::string zo handig omdat die dat automatisch voor je doet.
ShutdownConnection gebruikt geen LL_SOCKETS, enkel de socket zélf. (wordt de socket mss gewist als deze uit de linked list stucture wordt verwijderd, waardoor de shutdown niet werkt?).
Als je de socket niet closet hoort ie gewoon nog te werken. Bovendien zou de shutdown naar niet op moeten crashen, hoogstens gewoon een foutmelding.
Het probleem is dat ik de console functie heb gemaakt zodat hij argumenten aanneemt en deze argumenten mogen geen strings zijn :(
Je kan toch de c_str() method aanroepen op de strings?
Cns_Addline("Socket removed from list [ID %d] [Nick %s]", playerID, playerNick.c_str());

Maar het blijft een beetje een combinatie van C++ en C... Kan je niet beter die console functies ook omschrijven, in bijvoorbeeld zoiets:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Console : public ostringstream
{
public:
    Console() {}
    ~Console()
    {
        *this << endl;
        MessageBox(NULL, this->str().c_str(), "Console line", MB_OK|MB_ICONINFORMATION);
    }
};


Console() << "Socket removed from list [ID " << playerID << "] [Nick " << playerName << "]";
Console() << "Shutting connection down [ID " << playerID << "] [Nick " << playerName << "]";

(MessageBox is even als voorbeeld)

Wat betreft de crash, probeer eens wat delen code in commentaar te zetten en kijken of ie dan nog steeds crasht, dan kan je vinden waar het zit. Wat gebeurt er bijvoorbeeld als je de code in de LL_Sockets_Remove functie in commentaar zet (zodat ze niet uit de lijst verwijderd worden)?

www.madwizard.org


Verwijderd

Topicstarter
Zelfs na alles om te zetten naar strings geeft het programma nog steeds die fout. Ik heb wat zitten nadenken:

Het programma geeft énkel een fout als een 'oudere' client disconnect en dan een nieuwere. Dit wil zeggen: een client die eerder is geconnect dan een andere gaat eerst disconnecten en dan pas die andere.

Volgens mij wordt er bij het stoppen van de thread een of andere variabele op NULL gezet, terwijl een van de andere threads/clients die wél nog nodig heeft.
Misschien heeft het iets met de sockets te maken?

De volgorde van het disconnecten is heel belangrijk, dus moet het iets te maken hebben met een variabele die wordt gewist, terwijl deze variabele nog nodig is in de andere threads?

Zo ziet mijn ThreadHandler er nu uit:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// a client thread to start when a new client has succesfully connected
DWORD WINAPI ThreadHandler(void* insocket_)
{
    int retval = 0;               // function return value
    int readBytes;                // to store the amount of received bytes
    char readBuffer;              // read buffer for 1 char
    SOCKET insocket = (SOCKET)insocket_;
    ostringstream sstream;        // string streaming buffer (for socket input)
    do                            // main loop
    {
        readBytes = recv(insocket, &readBuffer, 1, 0); // read 1 character
        if (readBytes > 0) {      // handle valid data only
            switch (readBuffer)
            {
                case '\n':        // received end of line character
                    Cns_Addline("Received %d bytes from client [%s]", sstream.str().size(), sstream.str().c_str());
                    //LL_Sockets_SendAll(resultString);
                    if (!strcmp(sstream.str().c_str(), "P")) // ping command
                        PingReply(insocket);                 // execute ping
                    LL_Sockets_SendAllButSelf(sstream.str().c_str(), insocket);
                    sstream.str("");
                    break;
                default:          // add the buffer character to the string buffer
                    sstream << readBuffer;
                    break;
            }
        } else if (readBytes == SOCKET_ERROR) {
            Cns_Addline(WSAGetLastErrorMessage("Handling of packages failed"));
            LookupSocketData(insocket); // print out socket info from linked list (e.g. nickname)
            retval = 3;
        }
        // check for buffer overflows (security)
        if (strlen(sstream.str().c_str()) > RECEIVEBUFFERMAX)
        {
            Cns_Addline("Buffer overflow");
            LookupSocketData(insocket); // print out socket info from linked list (e.g. nickname)
            retval = 3;
            break;
        }
    } while (readBytes != 0);

    int playerID = LL_Sockets_GetID(insocket);       // get player ID from linked list
    string playerNick = LL_Sockets_GetNick(insocket);

    Cns_Addline("Connection closed by peer [ID %d] [Nick %s]", playerID, playerNick.c_str());

    // clean up
    if (!LL_Sockets_Remove(insocket))
        retval = 3;

    //////////////////////////////
    // thread crashes on return //
    //////////////////////////////
 /*   while (1) // endless loop to avoid crash
        Sleep(1000000);*/
    
    return retval;
}


[edit] als ik alle onbelangrijke code wis, dan komt er nog steeds die foutmelding

[ Voor 4% gewijzigd door Verwijderd op 23-03-2003 21:06 ]


  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Verwijderd schreef op 23 maart 2003 @ 21:05:
Zelfs na alles om te zetten naar strings geeft het programma nog steeds die fout. Ik heb wat zitten nadenken:

Het programma geeft énkel een fout als een 'oudere' client disconnect en dan een nieuwere. Dit wil zeggen: een client die eerder is geconnect dan een andere gaat eerst disconnecten en dan pas die andere.
Lijkt dan toch dat je iets verkeerds weghaald, heb je geprobeerd die hele LL_Sockets_Remove weg te halen?
Volgens mij wordt er bij het stoppen van de thread een of andere variabele op NULL gezet, terwijl een van de andere threads/clients die wél nog nodig heeft.
Misschien heeft het iets met de sockets te maken?
Misschien gaat er toch iets niet goed met die linked list. Hoe ziet je LL_Sockets_Remove er op dit moment uit?

Het is heel erg vreemd dat de crash op de return komt, aan de assembler code te zien lijkt dat eigenlijk niet zo maar vanwege de oneindige loop die wel werkt kan het bijna niet anders.

Ik wil best wel even naar je volledige source kijken om de bug te vinden maar ik weet niet of je die wel kwijt wilt.. Anders misschien een binaire versie al kan ik daar natuurlijk wel een stuk minder mee. Zo van een afstand is het wat lastig debuggen :|.

www.madwizard.org


Verwijderd

Topicstarter
madwizard schreef op 23 March 2003 @ 21:25:
[...]

Lijkt dan toch dat je iets verkeerds weghaald, heb je geprobeerd die hele LL_Sockets_Remove weg te halen?


[...]

Misschien gaat er toch iets niet goed met die linked list. Hoe ziet je LL_Sockets_Remove er op dit moment uit?
Ja
Het is heel erg vreemd dat de crash op de return komt, aan de assembler code te zien lijkt dat eigenlijk niet zo maar vanwege de oneindige loop die wel werkt kan het bijna niet anders.

Ik wil best wel even naar je volledige source kijken om de bug te vinden maar ik weet niet of je die wel kwijt wilt.. Anders misschien een binaire versie al kan ik daar natuurlijk wel een stuk minder mee. Zo van een afstand is het wat lastig debuggen :|.
Thanks, ik heb het al proberen compilen met MS Visual C++, maar die bleef de fout geven dat ostringstream niet herkent werd (alhoewel de juiste headers werden ingevoegd). Heel erg bedankt dat je de source ff wil inkijken! Ik mail het je zo door!

[edit] hoe&waarom namespace::std?

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Alle STL classes zitten in een namespace genaamd 'std'. Using namespace std geeft aan dat namen die je gebruikt mogelijk in de std namespace zitten, ook als je dit niet expliciet vermeld door er std:: voor te zetten.

Dat hoeft overigens alleen als je de nieuwe stijl headers gebruikt <string>, <sstream>, <vector> etc. Als je de .h versies gebruikt (<string.h>, <sstream.h>) wordt dit al voor je gedaan (heb je source gezien, dit stond er dus al in). Eigenlijk zijn de .h versies verouderd (in de zin van dat je beter de niet .h versies kunt gebruiken en zelf een using namespace std toevoegd), al werken ze wel nog gewoon.
Bovendien zijn de namen van de stringstream classes en headers een keer veranderd, ik dacht dat de laatste en juiste versie <sstream> + *stringstream was (ipv <stringstream> of <strstream> en *strstream etc.).

[ Voor 15% gewijzigd door madwizard op 24-03-2003 00:05 ]

www.madwizard.org


  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Ik ben op zoek geweest naar de bug in kenvh's code, gecompileert in VC, een simpel foutje eruitgehaald en het werkte perfect. Ook in dev-c++ (mingw met gcc 3.2) werkte het prima maar bij kenvh niet. Die werkte met gcc 2.95.3 en daar crashte ie wel.
Ik een oude versie opgezocht en kwam uiteindelijk na lang zoeken tot de conclusie dat de crash plaatsvond in de destructor van ostringstream 8)7. Zelfs met een heel erg gereduceerde ThreadHandler was de crash nog steeds niet verholpen, ook dit crashte:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
DWORD WINAPI ThreadHandler(void* insocket_)
{
    int retval = 0;               // function return value
    int readBytes;                // to store the amount of received bytes
    char readBuffer;              // read buffer for 1 char
    SOCKET insocket = (SOCKET)insocket_;
    ostringstream sstream;        // string streaming buffer (for socket input)
   
    do                            // main loop
    {
        readBytes = recv(insocket, &readBuffer, 1, 0); // wait for 1 byte
    } while (readBytes != 0);
   
    Cns_Addline("Connection closed by peer");
   
    return retval;
}

En dat lag niet aan Cns_AddLine, ook zonder die regel crasht ie. De recv is wel van belang maar niet in de meest logische zin.. De crash treedt op als 2 clients na elkaar disconnecten, oftewel 2 threads gaan achter elkaar uit de do-loop en termineren. Als meerdere threads een ostringstream (of elke ostream in principe) destructen na elkaar (niet per se tegelijk) dus, maar ook belangrijk is de volgorde.
De crash kwam alleen als een oudere client eerder disconnect dan een nieuwere. Zolang de threads termineren in omgekeerde volgorde is er niks aan de hand.

Een simpel voorbeeldje kon het probleem reproduceren:
(kenvh: dit is een iets anders voorbeeldje dan ik je mailde, deze laat zien dat de volgorde ook echt uitmaakt)

Dit werkt perfect:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <windows.h>
using namespace std;

DWORD CALLBACK ThreadProc(void *param)
{
    ostream s;
    Sleep((int)param);
    return 0;
}

int main(int argc, char *argv[])
{
  DWORD dwThreadID;
  CreateThread(NULL, 0, ThreadProc, (void*)2500, 0, &dwThreadID);
  CreateThread(NULL, 0, ThreadProc, (void*)2000, 0, &dwThreadID);
  CreateThread(NULL, 0, ThreadProc, (void*)1500, 0, &dwThreadID);
  CreateThread(NULL, 0, ThreadProc, (void*)1000, 0, &dwThreadID);
  Sleep(5000);
  return 0;
}

In deze code termineren de threads in omgekeerde volgorde. Als je de sleep waardes omgooit, bijvoorbeeld de eerste geen 2500 maar 1800 gaat het de mist in.. Ook andere combinaties waarbij de volgorde van termineren niet nieuwste-eerst is resulteren in een crash op return 0 (meer precies in de ostream destructor).

De mingw versie met gcc 3.2 heeft dit probleem niet, is dit een bug of zie ik iets stoms over het hoofd :?

Dit zijn echt van die dingen waar je net op zit te wachten bij het debuggen :).

www.madwizard.org


Verwijderd

Topicstarter
@ MadWizard:

Eerst en vooral: _/-\o_ _/-\o_ _/-\o_

Kvind het echt zwaar k*t dat de fout door zóiets werd veroorzaakt! Ik ga verder zoeken naar een oplossing (mss kan ik beide compilers installen, want m'n engine is niet compileerbaar met gcc 3.2 ... dat heb ik reeds uitgeprobeerd, maar het gaf véél te veel compileerfouten dan me lief is).
Kan ik die ostringstream niet vervangen door iets anders? Wat is het beste alternatief? Misschien gewoon een array van chars? (want de inputbuffer heeft een maximum grootte als de beveiliging).

[edit] ik kan er gelukkig nog om lachen :) ben blij dat ik geen agressieve reactie ofzo kreeg toen ik dit las :P

[ Voor 12% gewijzigd door Verwijderd op 24-03-2003 22:48 ]


  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Verwijderd schreef op 24 maart 2003 @ 22:44:
Kvind het echt zwaar k*t dat de fout door zóiets werd veroorzaakt! Ik ga verder zoeken naar een oplossing (mss kan ik beide compilers installen, want m'n engine is niet compileerbaar met gcc 3.2 ... dat heb ik reeds uitgeprobeerd, maar het gaf véél te veel compileerfouten dan me lief is).
Ik weet niet of je later objects van verschillende versies samen kunt linken. In principe natuurlijk wel maar dan moeten alle gebruikte structuren ook hetzelfde zijn (inclusief de hele STL). Wat die compileerfouten betreft, zoveel verschillen kunnen er toch niet zijn? Weet je zeker dat je niet een header ofzo vergeten bent die in de oudere versie op 1 of andere manier automatisch meegenomen werd? Wat zijn het voor soort errors?
Kan ik die ostringstream niet vervangen door iets anders? Wat is het beste alternatief? Misschien gewoon een array van chars? (want de inputbuffer heeft een maximum grootte als de beveiliging).
Als je toch een maximum hebt kun je best een lokale char array gebruiken (char buffer[MAX_SIZE]).. Zowieso kun je misschien beter gewoon input lezen zo groot als de buffer is in plaats van steeds 1 karakter (is best wel inefficient maar scheelt natuurlijk parse werk). Zodra er een hele regel in de buffer staat haal je die eruit, verwerk je em en schuif je eventuele overige data in de buffer (van de volgende regel) terug naar het begin zodat de volgende regel weer aan het begin van de buffer staat. Als de buffer helemaal vol zit maar er zit geen enter in dan heb je een te lange regel = buffer overflow.

Maar het gebruik van ostringstreams zou geen enkel probleem moeten zijn, het is gewoon de STL standaard dus zou met elke compiler moeten werken. De enige problemen zijn meestal verkeerde headers of compiler specifieke uitbreidingen maar die gebruik je niet zo gauw.

www.madwizard.org


Verwijderd

Topicstarter
madwizard schreef op 24 maart 2003 @ 22:53:

Ik weet niet of je later objects van verschillende versies samen kunt linken. In principe natuurlijk wel maar dan moeten alle gebruikte structuren ook hetzelfde zijn (inclusief de hele STL). Wat die compileerfouten betreft, zoveel verschillen kunnen er toch niet zijn? Weet je zeker dat je niet een header ofzo vergeten bent die in de oudere versie op 1 of andere manier automatisch meegenomen werd? Wat zijn het voor soort errors?
Ik bedoelde de dat ik de ene compilerversie voor m'n engine dan zou gebruiken en de andere voor de server. Die compiler errors ken ik niet meer vanbuiten, maar het was vooral omdat bepaalde headers niet meer werden gevonden en áls ik ze vond (in een andere map), dan werkte het evengoed niet.
Als je toch een maximum hebt kun je best een lokale char array gebruiken (char buffer[MAX_SIZE]).. Zowieso kun je misschien beter gewoon input lezen zo groot als de buffer is in plaats van steeds 1 karakter (is best wel inefficient maar scheelt natuurlijk parse werk). Zodra er een hele regel in de buffer staat haal je die eruit, verwerk je em en schuif je eventuele overige data in de buffer (van de volgende regel) terug naar het begin zodat de volgende regel weer aan het begin van de buffer staat. Als de buffer helemaal vol zit maar er zit geen enter in dan heb je een te lange regel = buffer overflow.
Dit zou niet werken, want de grootte van de ontvangen data is variabel. (dus een network package heeft geen vaste grootte. Elke package wordt afgesloten met een terminator character, maar dat wist je ws al.
[edit] in principe zou ik een package een vast waarde kunnen geven, maar dan wordt de netwerktraffic te groot.
Maar het gebruik van ostringstreams zou geen enkel probleem moeten zijn, het is gewoon de STL standaard dus zou met elke compiler moeten werken. De enige problemen zijn meestal verkeerde headers of compiler specifieke uitbreidingen maar die gebruik je niet zo gauw.

[ Voor 3% gewijzigd door Verwijderd op 24-03-2003 23:01 ]


  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Verwijderd schreef op 24 March 2003 @ 22:59:
Ik bedoelde de dat ik de ene compilerversie voor m'n engine dan zou gebruiken en de andere voor de server. Die compiler errors ken ik niet meer vanbuiten, maar het was vooral omdat bepaalde headers niet meer werden gevonden en áls ik ze vond (in een andere map), dan werkte het evengoed niet.
Dat bedoelde ik ook, de vraag is dus of je de output van de aparte compilers (de object files dus) wel zomaar aan elkaar kunt linken.. Niet gevonden headers is meestal gewoon een kwestie van include paths goed instellen bij je project..
Dit zou niet werken, want de grootte van de ontvangen data is variabel. (dus een network package heeft geen vaste grootte. Elke package wordt afgesloten met een terminator character, maar dat wist je ws al.
[edit] in principe zou ik een package een vast waarde kunnen geven, maar dan wordt de netwerktraffic te groot.
Daar ga ik ook niet van uit, je buffer is gewoon de maximum grootte, de eigenlijke 'pakketten' of regels kunnen kleiner zijn. Zie het als een soort wachtrij: je voert continu data aan aan de achterkant (mogelijk met bijvoorbeeld 10 tegelijk) en continu kijk je of er in de wachtrij een hele regel gevormd is aan de voorkant (komt minimaal 1 enter in voor). Zoja, haal je de hele rij bytes die de eerste regel vormen uit de wachtrij en verwerk je ze. De rest van de wachtrij (mogelijk een deel van een regel, mogelijk meerdere regels) schuiven weer naar voren over de plaatsen die vrij zijn gekomen door de eerste regel weg te halen.
Pseudo code:
code:
1
2
3
4
5
6
7
8
9
10
11
while(connected)
{
   recv(socket, buffer + used, max - used, 0);
   while(*minimaal* hele regel in buffer (mag dus meer zijn))
   {
       verwijder 1 regel van de buffer;
       schuif de data achter de regel naar het begin van de buffer;
       verwerk de regel;
   }
   if (buffer_vol) buffer_overflow;
}

www.madwizard.org


Verwijderd

Topicstarter
[b][message=17356814,noline]madwizard schreef op 24 maart 2003 @
Dat bedoelde ik ook, de vraag is dus of je de output van de aparte compilers (de object files dus) wel zomaar aan elkaar kunt linken.. Niet gevonden headers is meestal gewoon een kwestie van include paths goed instellen bij je project..
De object files van de engine zijn staan appart dus dat gaat geen probs geven :)
Daar ga ik ook niet van uit, je buffer is gewoon de maximum grootte, de eigenlijke 'pakketten' of regels kunnen kleiner zijn. Zie het als een soort wachtrij: je voert continu data aan aan de achterkant (mogelijk met bijvoorbeeld 10 tegelijk) en continu kijk je of er in de wachtrij een hele regel gevormd is aan de voorkant (komt minimaal 1 enter in voor). Zoja, haal je de hele rij bytes die de eerste regel vormen uit de wachtrij en verwerk je ze. De rest van de wachtrij (mogelijk een deel van een regel, mogelijk meerdere regels) schuiven weer naar voren over de plaatsen die vrij zijn gekomen door de eerste regel weg te halen.
Pseudo code:
code:
1
2
3
4
5
6
7
8
9
10
11
while(connected)
{
   recv(socket, buffer + used, max - used, 0);
   while(*minimaal* hele regel in buffer (mag dus meer zijn))
   {
       verwijder 1 regel van de buffer;
       schuif de data achter de regel naar het begin van de buffer;
       verwerk de regel;
   }
   if (buffer_vol) buffer_overflow;
}
Aha, zo kan het natuurlijk ook. Kga er eens een nachtje over slapen en dan zie ik wel wat ik ga doen :)

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
madwizard schreef op 23 March 2003 @ 13:11:
Kan je niet beter die console functies ook omschrijven, in bijvoorbeeld zoiets:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Console : public ostringstream
{
public:
    Console() {}
    ~Console()
    {
        *this << endl;
        MessageBox(NULL, this->str().c_str(), "Console line", MB_OK|MB_ICONINFORMATION);
    }
};


Console() << "Socket removed from list [ID " << playerID << "] [Nick " << playerName << "]";
Console() << "Shutting connection down [ID " << playerID << "] [Nick " << playerName << "]";

(MessageBox is even als voorbeeld)
Nee. Als je een stream wil redirecten doe je dat via ostream::rdbuf(), en stop je daar een gepaste streambuffer in.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein

Pagina: 1