Segmentation Fault przy wywoływaniu free()

0
33      /* This function is for enlarging block of allocated memory without
34       * changing the data that is stored in memory already. */
35
36      int resize(void *ptr, size_t size, size_t new_size, ...)
37      {
38              va_list ap;
39              char *temp;
40              int *check;
41              int sockd;
42
43              va_start(ap, new_size);
44
45              if((check=va_arg(ap, int *))!=NULL) {
46                      sockd=(int)check;
47                      va_end(ap);
48                      temp=sec_malloc(size, err_notice, sockd, "Server out of memory", NULL);
49                      memmove(temp, ptr, size);
50                      sec_realloc(ptr, new_size, err_notice, sockd, "Server out of memory", NULL);
51                      memmove(ptr, temp, size);
52                      free(temp);
53              } else {
54                      temp=sec_malloc(size, NULL);
55                      memmove(temp, ptr, size);
56                      sec_realloc(ptr, new_size, NULL);
57                      memmove(ptr, temp, size);
58                      free(temp);
59              }
60              return 0;
61      }

A gdb mi mówi:

(gdb) run
Starting program: /home/I_v0/maitenance/hydra/controller 
Failed to read a valid object file image from memory.

Program received signal SIGSEGV, Segmentation fault.
0xb7e26116 in malloc_set_state () from /lib/libc.so.6
(gdb) backtrace
#0  0xb7e26116 in malloc_set_state () from /lib/libc.so.6
#1  0xb7e2630e in free () from /lib/libc.so.6
#2  0x08049338 in resize (ptr=0x804c180, size=256, new_size=21) at controller.h:52
#3  0x0804977e in find_host (request=0x804c050 "GET / HTTP/1.1\r\nHost: intranet.acision.com\r\n\r\n", sockd=7) at controller.h:140
#4  0x08049da2 in main () at controller.c:57

Na free() dostaje SEGV, o co mu chodzi, jak to poprawić?

Bład Segmentation Fault pojawia się wtedy kiedy program próbuje zmienić coś w adresie pamięci który do niego nie należy - lub bardziej konkretnie, kiedy próbuje zmienić coś w adresie pamięci który należy do innego programu, ale tutaj to nie ma z tym nic wspólnego (tak na mój rozum).

0

prawdopodobnie chcesz zwolnic adres ktory nie byl rezerwowany wczesniej
porownaj wartosc wskaznika z tym co dostajesz po alokacji pamieci

0

imho, przy podobnych wypadkach najpierw szukaj bledu u siebie, a nie zakladaj ze to libc/c++ jest walniete. to ze sigsegv leci z free, to nie znaczy ze zrodlo bledu jest tam.. zarzuc raczej kawalkiem swojego kodu z (controller.c/controller.h) ktory odpala resize'a

0
I_v0 hydra # gdb controller
GNU gdb 6.4
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-pc-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".

(gdb) l
7       #include <string.h>
8
9       #include "err_handle.h"
10      #include "controller.h"
11
12      #define MYPORT 666
13      #define BACKLOG 100
14
15      int main()
16      {
(gdb) 
17              int sockd, new_sockd;           /* listen on sockd, new connection on new_sockd */
18              struct sockaddr_in my_addr;     /* my address information                       */
19              struct sockaddr_in their_addr;  /* client address information                   */
20
21              char *request;                  /* Pointer to the request string as sent by client      */
22              char *temp_req;                 /* Temporary place to store the request template        */
23              char *hostname;                 /* Hostname copeied out from a request                  */
24              int i;
25              socklen_t sin_size;
26              long long content_length;
(gdb) 
27              long long point=0;
28
29              struct part *queue;
30              struct part *starting_point;
31
32              sockd=sec_socket(AF_INET, SOCK_STREAM, 0, err_notice, NULL);
33
34              memset(&my_addr, 0, sizeof(my_addr));
35              my_addr.sin_family = AF_INET;         /* host byte order                */
36              my_addr.sin_port = htons(MYPORT);     /* short, network byte order      */
(gdb) 
37              my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP           */
38
39              if(bind(sockd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))==-1) {
40                      perror("bind");
41                      exit(1);
42              }
43
44              if(listen(sockd, BACKLOG)==-1) {
45                      perror("listen");
46                      exit(1);
(gdb) 
47              }
48
49              sin_size=sizeof(their_addr);
50              while((new_sockd=accept(sockd,(struct sockaddr*)&their_addr, &sin_size))!=-1) {
51
52                      if((request=recv_data(request, new_sockd, new_sockd))==NULL) {
53                              close(new_sockd);
54                              continue;
55                      }
56
(gdb) 
57                      hostname=find_host(request, new_sockd);
58                      content_length=query_length(request, hostname, new_sockd);
59
60                      queue=sec_malloc(sizeof(struct part), err_notice, new_sockd, "Server out of memory", NULL);
61                      starting_point=queue->prev=queue;
62
63                      for(i=0;content_length>0;i++) {
64                              queue->id=i;
65
66                              if(content_length>=1500) {
(gdb) break 57
Breakpoint 1 at 0x8049d90: file controller.c, line 57.
(gdb) run
Starting program: /home/I_v0/maitenance/hydra/controller 
Failed to read a valid object file image from memory.

Breakpoint 1, main () at controller.c:57
57                      hostname=find_host(request, new_sockd);
(gdb) s
find_host (request=0x804c050 "GET / HTTP/1.1\r\nHost: intranet.acision.com\r\n\r\n", sockd=8) at controller.h:131
131             ptr=strstr(request,"Host:")+5;
(gdb) l
126     {
127             char *ptr;
128             char *hostname;
129             int i;
130
131             ptr=strstr(request,"Host:")+5;
132             while(*ptr==' ')
133                     ptr++;
134
135             hostname=sec_malloc(256, err_notice, sockd, "Server out of memory", NULL);
(gdb) 
136
137             for(i=0;isalnum(*ptr)||*ptr=='.';i++,ptr++)
138                     hostname[i]=*ptr;
139             hostname[i]='\0'; 
140             resize(hostname, 256, strlen(hostname)+1, sockd);
141             return hostname;
142     }
143
144
145     /* Function does a DNS query and tries to fill the target server info 
(gdb) 
146      * which it then returns.                                               */
147
148     struct hostent *resolve_host(char *hostname, int sockd)
149     {
150             struct hostent *cli_he;
151
152             if ((cli_he=gethostbyname(hostname))==NULL) {           /* Get the host info */
153                     if((cli_he=gethostbyaddr(hostname,strlen(hostname),AF_INET))==NULL) {
154                             perror("Can't lookup requested hostname");
155                             pure_err_notice(1, err_notice, sockd, "Can't lookup requested hostname", NULL);
(gdb) break 140
Breakpoint 2 at 0x8049745: file controller.h, line 140.
(gdb) cont
Continuing.

Breakpoint 2, find_host (request=0x804c050 "GET / HTTP/1.1\r\nHost: intranet.acision.com\r\n\r\n", sockd=8) at controller.h:140
140             resize(hostname, 256, strlen(hostname)+1, sockd);
(gdb) x/s hostname 
0x804c180:       "intranet.acision.com"
(gdb) p strlen(hostname)+1
$1 = 21
(gdb) p sockd 
$2 = 8
(gdb) s
resize (ptr=0x804c180, size=256, new_size=21) at controller.h:43
43              va_start(ap, new_size);
(gdb) l
38              va_list ap;
39              char *temp;
40              int *check;
41              int sockd;
42
43              va_start(ap, new_size);
44
45              if((check=va_arg(ap, int *))!=NULL) {
46                      sockd=(int)check;
47                      va_end(ap);
(gdb) 
48                      temp=sec_malloc(size, err_notice, sockd, "Server out of memory", NULL);
49                      memmove(temp, ptr, size);
50                      sec_realloc(ptr, new_size, err_notice, sockd, "Server out of memory", NULL);
51                      memmove(ptr, temp, size);
52                      free(temp);
53              } else {
54                      temp=sec_malloc(size, NULL);
55                      memmove(temp, ptr, size);
56                      sec_realloc(ptr, new_size, NULL);
57                      memmove(ptr, temp, size);
(gdb) break 48
Breakpoint 3 at 0x804929d: file controller.h, line 48.
(gdb) cont
Continuing.

Breakpoint 3, resize (ptr=0x804c180, size=256, new_size=21) at controller.h:48
48                      temp=sec_malloc(size, err_notice, sockd, "Server out of memory", NULL);
(gdb) p size
$3 = 256
(gdb) p err_notice
$4 = {void (va_list)} 0x8048ed7 <err_notice>
(gdb) p sockd
$5 = 8
(gdb) s
sec_malloc (size=256) at err_handle.h:123
123             va_start(ap, size);
(gdb) l
118     void *sec_malloc(size_t size, ...) 
119     {
120             va_list ap;
121             void *retval;
122
123             va_start(ap, size);
124             void (*notice_client)(va_list)=va_arg(ap, void *);
125             if((retval=malloc(size))==NULL) {
126                     perror("malloc");
127                     if(notice_client!=NULL)
(gdb) l
128                             notice_client(ap);
129             }
130
131             va_end(ap);
132             return retval;
133     }
134
135     void *sec_realloc(void *ptr, size_t size, ...) 
136     {
137             va_list ap;
(gdb) break 125
Breakpoint 4 at 0x8048bcc: file err_handle.h, line 125.
(gdb) cont
Continuing.

Breakpoint 4, sec_malloc (size=256) at err_handle.h:125
125             if((retval=malloc(size))==NULL) {
(gdb) n
132             return retval;
(gdb) p retval
$6 = (void *) <b>0x804c288</b>
(gdb) n
133     }
(gdb) 
resize (ptr=0x804c180, size=256, new_size=21) at controller.h:49
49                      memmove(temp, ptr, size);
(gdb) l
44
45              if((check=va_arg(ap, int *))!=NULL) {
46                      sockd=(int)check;
47                      va_end(ap);
48                      temp=sec_malloc(size, err_notice, sockd, "Server out of memory", NULL);
49                      memmove(temp, ptr, size);
50                      sec_realloc(ptr, new_size, err_notice, sockd, "Server out of memory", NULL);
51                      memmove(ptr, temp, size);
52                      free(temp);
53              } else {
(gdb) p temp
$7 = <b>0x804c288</b> ""
(gdb) n
50                      sec_realloc(ptr, new_size, err_notice, sockd, "Server out of memory", NULL);
(gdb) 
51                      memmove(ptr, temp, size);
(gdb) 
52                      free(temp);
(gdb) p temp
$8 = <b>0x804c288</b> "intranet.acision.com"
(gdb) n

Program received signal SIGSEGV, Segmentation fault.
0xb7edb116 in malloc_set_state () from /lib/libc.so.6

No nie wiem no chłopaki, poważnie - pomóżcie bo porażka.

0

free(temp) chyba tutaj nic nie ma do rzeczy. program sie wywala w momencie opuszczenia bloku {} zaraz po free, to wskazuje na zniszczenie ramki stosu

I_v0 napisał(a)

resize () at controller.h:43
48 temp=sec_malloc(size, err_notice, sockd, "Server out of memory", NULL);
49 memmove(temp, ptr, size);
50 sec_realloc(ptr, new_size, err_notice, sockd, "Server out of memory", NULL);
51 memmove(ptr, temp, size);
52 free(temp);

53 } else {
54 temp=sec_malloc(size, NULL);
55 memmove(temp, ptr, size);
56 sec_realloc(ptr, new_size, NULL);
57 memmove(ptr, temp, size);

IMHO, @50 i @56, sec_realloc wydaje mi sie ze powinien zwracac void* tak jak kazdy realloc. nie wiem co tam uzywacie, i skad tyle tych varargow przy malloc/realloc, ale wydaje mi sie ze jednak powinno byc:

ptr=sec_realloc(ptr, new_size, err_notice, sockd, "Server out of memory", NULL);
ptr=sec_realloc(ptr, new_size, NULL);

jest pewna mala szansa, ze jesli ptr byl nieprawidlowy to memmove w @51 i @57 niszczyly by jakis kawalek pamieci, i mogly by pechowo trafiac w stos. ale szczerze mowiac wydaje mi sie to jednak malo prawdopodobne..

ktore z owych main() :), find_host, resize(), sec_malloc/realloc sa Twoje, a ktore sa z jakichs bibliotek?

0

Dobra, czas wam podać te funkcje bo nie będę was zmuszał do zgadywania co tam się dzieje, wszystkie są moje (własny kod), rzeczywiście tam powinno być ptr=sec_realloc(... Poprawiłem jednak nadal mam SEGV.

Dobra, no to owy main pierwszy:

int main()
{
        int sockd, new_sockd;           /* listen on sockd, new connection on new_sockd */
        struct sockaddr_in my_addr;     /* my address information                       */
        struct sockaddr_in their_addr;  /* client address information                   */

        char *request;                  /* Pointer to the request string as sent by client      */
        char *temp_req;                 /* Temporary place to store the request template        */
        char *hostname;                 /* Hostname copeied out from a request                  */
        int i;
        socklen_t sin_size;
        long long content_length;
        long long point=0;

        struct part *queue;
        struct part *starting_point;

        sockd=sec_socket(AF_INET, SOCK_STREAM, 0, err_notice, NULL);

        memset(&my_addr, 0, sizeof(my_addr));
        my_addr.sin_family = AF_INET;         /* host byte order                */
        my_addr.sin_port = htons(MYPORT);     /* short, network byte order      */
        my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP           */

        if(bind(sockd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))==-1) {
                perror("bind");
                exit(1);
        }

        if(listen(sockd, BACKLOG)==-1) {
                perror("listen");
                exit(1);
        }

        sin_size=sizeof(their_addr);
        while((new_sockd=accept(sockd,(struct sockaddr*)&their_addr, &sin_size))!=-1) {

                if((request=recv_data(request, new_sockd, new_sockd))==NULL) {
                        close(new_sockd);
                        continue;
                }

                hostname=find_host(request, new_sockd);
                content_length=query_length(request, hostname, new_sockd);

                queue=sec_malloc(sizeof(struct part), err_notice, new_sockd, "Server out of memory", NULL);
                starting_point=queue->prev=queue;

                for(i=0;content_length>0;i++) {
                        queue->id=i;

                        if(content_length>=1500) {
                                queue->size=1500;
                                content_length-=1500;
                                queue->start=point;
                                point+=1500;
                                queue->end=point;
                        } else {
                                queue->size=content_length;
                                queue->start=point;
                                point+=content_length;
                                queue->end=point;
                                content_length=0;
                        }

                        temp_req=forge_template(request, queue->start, queue->end, new_sockd);
                        queue->req_temp=sec_malloc(strlen(temp_req)+1);
                        memmove(queue->req_temp, temp_req, strlen(temp_req)+1);
                        free(temp_req);

                        queue->next=sec_malloc(sizeof(struct part), err_notice, new_sockd, "Server out of memory", NULL);
                        queue->next->prev=queue;
                        queue=queue->next;
                }
                queue->prev->next=starting_point;
                starting_point->prev=queue->prev;
                free(queue);
                queue=starting_point;
                return 0;
        }

Oto i on, mam tam wywołanie funkcji find_host która tak oto się prezentuje:

/* This function copies the hostname from the header and returns it back. */

char *find_host(char *request, int sockd)
{
        char *ptr;
        char *hostname;
        int i;

        ptr=strstr(request,"Host:")+5;
        while(*ptr==' ')
                ptr++;

        hostname=sec_malloc(256, err_notice, sockd, "Server out of memory", NULL);

        for(i=0;isalnum(*ptr)||*ptr=='.';i++,ptr++)
                hostname[i]=*ptr;
        hostname[i]='\0';
        resize(hostname, 256, strlen(hostname)+1, sockd);
        return hostname;
}

I na końcu tejże funkcji w linii XX robię resize() żeby nie tracić za dużo pamięci, tak oto się prezentuje resize():

/* This function is for enlarging block of allocated memory without
 * changing the data that is stored in memory already. */

int resize(void *ptr, size_t size, size_t new_size, ...)
{
        va_list ap;
        char *temp;
        int *check;
        int sockd;

        va_start(ap, new_size);

        if((check=va_arg(ap, int *))!=NULL) {
                sockd=(int)check;
                va_end(ap);
                temp=sec_malloc(size, err_notice, sockd, "Server out of memory", NULL);
                memmove(temp, ptr, size);
                ptr=sec_realloc(ptr, new_size, err_notice, sockd, "Server out of memory", NULL);
                memmove(ptr, temp, size);
                free(temp);
        } else {
                temp=sec_malloc(size, NULL);
                memmove(temp, ptr, size);
                ptr=sec_realloc(ptr, new_size, NULL);
                memmove(ptr, temp, size);
                free(temp);
        }
        return 0;
}

Wszystko przebiega ładnie i składnie dopóki nie dochodzę do free() - kiedy to dostaję SEGV.

Po drodze wykorzystuję dwie funkcje z mojej własnej kuchni, mianowicie sec_malloc i sec_realloc, które w tejże kolejności przytaczam poniżej:

void *sec_malloc(size_t size, ...)
{
        va_list ap;
        void *retval;

        va_start(ap, size);
        void (*notice_client)(va_list)=va_arg(ap, void *);
        if((retval=malloc(size))==NULL) {
                perror("malloc");
                if(notice_client!=NULL)
                        notice_client(ap);
        }

        va_end(ap);
        return retval;
}
void *sec_realloc(void *ptr, size_t size, ...)
{
        va_list ap;
        void *retval;

        va_start(ap, size);
        void (*notice_client)(va_list)=va_arg(ap, void *);
        if((retval=realloc(ptr, size))==NULL) {
                perror("realloc");
                if(notice_client!=NULL)
                        notice_client(ap);
        }

        va_end(ap);
        return retval;
}

Warto zaznaczyć że ani malloc ani realloc w tychże dwóch ostatnich funkcjach nie zwraca wskaźnika NULL więc i nie ma sensu rozpisywać się o tym co się dalej dzieje jeśli jest błąd bo to historia na kolejne kilka godzin.

Dość powiedzieć że dostaję SEGV, rzeczywiście ptr nie był ustawiany w należyty sposób lecz nawet po poprawieniu tegoż błędu nadal pozostaje koszmarny SEGV.

Proszę, pytajcie o co chcecie - sam to wszystko napisałem a program czy tak czy siak kiedy będzie gotowy będzie dostępny na licencji GPL.

Tutaj racja, jest to niewielkie prawdopodobieństwo że ptr kiedyś będzie zły i nadpisze ramke ale to jednak nie tym razem, gdb wyraźnie mówi:

(gdb) n
51                      memmove(ptr, temp, size);
(gdb) 
52                      free(temp);
(gdb) 

Program received signal SIGSEGV, Segmentation fault.
0xb7ef2116 in malloc_set_state () from /lib/libc.so.6
(gdb) backtrace
#0  0xb7ef2116 in malloc_set_state () from /lib/libc.so.6
#1  0xb7ef230e in free () from /lib/libc.so.6
#2  0x0804933b in resize (ptr=0x804c180, size=256, new_size=21) at controller.h:52
#3  0x08049784 in find_host (request=0x804c050 "GET / HTTP/1.1\r\nHost: intranet.acision.com\r\n\r\n", sockd=8) at controller.h:140
#4  0x08049da8 in main () at controller.c:57

Oczywiście prawidelnie poprawiłem błąd zaraz po tym jak go wskazałeś - dziękuję :)

Co myślicie?

0

przepraszam ze nie w temacie SEGV'a, jeszcze nie wymyslilem co moze go powodowac, ale przyuwazylem w kontekscie realloca jeszcze jeden 'myk':

main:
resize(hostname, 256, strlen(hostname)+1, sockd);

resize:
ptr=sec_realloc(ptr, new_size, NULL);
...
return 0;

co oznacza, ze funkcja resize moze z-free-owac (w sec_realloc) oryginalny hostname i mimo iz rzeczywiscie bedzie on realokowany bez strat danych, to main() i tak bedzie mial nadal stary wskaznik.

FIX:

resize: return 0; -> return ptr;
main: resize(hostname, 256, strlen(hostname)+1, sockd); -> hostname = resize(hostname, 256, strlen(hostname)+1, sockd);

a nad SEGV jeszcze mysle..

0

Zgadza się, poprawione:

char *find_host(char *request, int sockd)
{
...
hostname=resize(hostname, 256, strlen(hostname)+1, sockd);
...
}

void *resize(void *ptr, size_t size, size_t new_size, ...)
{
...
return ptr;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1