2015-11-26 2 views
1

C - addrinfo - ошибка сегментации указателейC - addrinfo - ошибка сегментации указателей

У меня возникает ошибка сегментации; Я сделал странное решение, но я все еще беспокоюсь, потому что не могу понять, в чем проблема. Любое понимание было бы потрясающе! Рабочее «исправление» в последнем блоке кода!

ошибки сегментации при попытке связать с помощью target_addrinfo:

struct addrinfo *my_server_res; 
struct addrinfo *their_server_res; 

int main(int argc, char **argv) { 
//........ 
    set_addrinfo(); 
    handle_binding(); 
} 

void set_addrinfo() { 
    int status; 
    struct addrinfo hints; 
    struct addrinfo *target_addrinfo; // fix (1/3): **target_addrinfo 
    char ipstr[INET6_ADDRSTRLEN]; 

    // THIS IS TRUE, takes my_server_res 
    // fix(2/3): (l ? &my_server_res : &their_server_res) 
    target_addrinfo = (l ? my_server_res : their_server_res); 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; 
    char *node; 
    node = (l ? "localhost" : host_name); 

    // fix (3/3) 3rd argument: target_addrinfo 
    if ((status = getaddrinfo(node, port, &hints, &target_addrinfo)) != 0) { 
     fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status)); 
     exit(1); 
    } 

} 

void handle_binding() { 
    struct addrinfo *target_addrinfo; 
    // THIS IS TRUE, takes my_server_res 
    target_addrinfo = (l ? my_server_res : their_server_res); 
    int b_res = bind(sockfd, target_addrinfo->ai_addr, target_addrinfo->ai_addrlen); 
    if (b_res == -1) { 
     perror("__Bind"); 
     exit(1); 
    } 
} 

трассировки стека: проблемы при попытке использовать my_server_res снова ?:

Program received signal SIGSEGV, Segmentation fault. 
0x0000000000401e16 in handle_binding() at ncTh.c:385 
385  int b_res = bind(sockfd, target_addrinfo->ai_addr, target_addrinfo->ai_addrlen); 
(gdb) backtrace 
#0 0x0000000000401e16 in handle_binding() at ncTh.c:385 
#1 0x0000000000401cad in setup_socket() at ncTh.c:330 
#2 0x0000000000401ad0 in main (argc=6, argv=0x7fffffffdea8) at ncTh.c:266 
(gdb) frame 0 
#0 0x0000000000401e16 in handle_binding() at ncTh.c:385 
385  int b_res = bind(sockfd, target_addrinfo->ai_addr, target_addrinfo->ai_addrlen); 
(gdb) 

работает "исправить", изменения в set_addrinfo():

struct addrinfo **target_addrinfo; // was *target_addrinfo 
char ipstr[INET6_ADDRSTRLEN]; 

target_addrinfo = (l ? &my_server_res : &their_server_res); // was my_server_res : their_server_res 

memset(&hints, 0, sizeof hints); 
hints.ai_family = AF_INET; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_flags = AI_PASSIVE; 

char *node; 
node = (l ? "localhost" : host_name); 
           // 3rd argument was &target_addrinfo : 
if ((status = getaddrinfo(node, port, &hints, target_addrinfo)) != 0) { 
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status)); 
    exit(1); 
} 
+1

Похоже, что 'target_addrinfo' не указывает на действительное место в памяти. Где и как объявляется 'their_server_res'? –

+0

О, извините, обновлено; 'their_server_res' объявлен тем же местом, что и' my_server_res', но я запустил программу с помощью 'l = 1', чтобы я мог сначала проверить my_server_res'о – Appleboy

ответ

2

В исходном коде:

struct addrinfo *target_addrinfo; 
target_addrinfo = (l ? my_server_res : their_server_res); 

Это копирует значение указателя my_server_res в target_addrinfo.

getaddrinfo(node, port, &hints, &target_addrinfo) 

Это передает указатель на target_addrinfo (указатель на указатель) в функции getaddrinfo который затем присваивает новое значение к нему, делая эквивалент *&target_addrinfo = new_ptr. Это новое значение является указателем на информацию, которую получает getaddrinfo.

Все это не влияет на my_server_res, который остается с его первоначальным значением, вероятно, NULL.

В новом коде:

struct addrinfo **target_addrinfo; 
target_addrinfo = (l ? &my_server_res : &their_server_res); 

Это копирует указатель на my_server_res в target_addrinfo (который теперь является указателем на указатель).

getaddrinfo(node, port, &hints, target_addrinfo) 

Это передает значение target_addrinfo (который в настоящее время является указателем на my_server_res) в функцию getaddrinfo который затем присваивает новое значение к нему, делая эквивалент *target_addrinfo = new_ptr. my_server_res теперь содержит указатель на информацию getaddrinfo извлекает для вас.

+1

, drop this 'target_addrinfo = (l? my_server_res: their_server_res);' from ' handle_binding() ', поскольку он уже установлен в' set_addrinfo() ' – milevyo

+0

Ahhhhhh спасибо, спасибо, я могу спать спокойно, теперь ха-ха! – Appleboy

+0

@milevyo 'target_addrinfo' является локальным, а не глобальным. – ymett

1

вы, вероятно, попадете в разыменование проблемы target_addrinfo, я разместил этот код. (лучше поздно, потом никогда :))

struct addrinfo *my_server_res; 
struct addrinfo *their_server_res; 

struct addrinfo **target_addrinfo; //this should be global 

int main(int argc, char **argv) { 
//........ 
    set_addrinfo(); 
    handle_binding(); 
} 

void set_addrinfo() { 
    int status; 
    struct addrinfo hints; 

    char ipstr[INET6_ADDRSTRLEN]; 

    // THIS IS TRUE, takes my_server_res 
    target_addrinfo = (l ? &my_server_res : &their_server_res); //set it once here 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; 
    char *node; 
    node = (l ? "localhost" : host_name); 
    if ((status = getaddrinfo(node, port, &hints, &target_addrinfo)) != 0) { 
     fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status)); 
     exit(1); 
    } 

} 

void handle_binding() { 
    //target_addrinfo should be initialized in set_addrinfo() 
    int b_res = bind(sockfd, 
     (*target_addrinfo)->ai_addr, // don't forget to dereference target_addrinfo, here 
     (*target_addrinfo)->ai_addrlen); // and here 

    if (b_res == -1) { 
     perror("__Bind"); 
     exit(1); 
    } 
} 
+0

Спасибо!Я рад, что, по крайней мере, часть себя увидела исправление, но мне нужно больше практиковать, что мне нужно было сделать это, чтобы на самом деле подтвердить эту мысль. – Appleboy

Смежные вопросы