Segfault (возможно, из-за кастинга) - PullRequest
1 голос
/ 12 июня 2010

Обычно я не обращаюсь к stackoverflow для ошибок sigsegv, но я сделал все, что мог, с моим отладчиком на данный момент.

Ошибка сбоя сегментации выдается после завершения функции.Есть идеи, что я пропускаю?Я подозреваю, что это происходит из-за приведения sockaddr к sockaddr_in, но я не могу найти там никаких ошибок.(Удаление этой строки избавляет от ошибки seg - но я знаю, что это может быть не основной причиной).

// basic setup
int sockfd;
char str[INET_ADDRSTRLEN];
sockaddr* sa;
socklen_t* sl;
struct addrinfo hints, *servinfo, *p;
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;

// return string
string foundIP;

// setup the struct for a connection with selected IP
if ((rv = getaddrinfo("4.2.2.1", NULL, &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return "1";
}

// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype,
            p->ai_protocol)) == -1) {
        perror("talker: socket");
        continue;
    }

    break;
}

if (p == NULL) {
    fprintf(stderr, "talker: failed to bind socket\n");
    return "2";
}

// connect the UDP socket to something
connect(sockfd, p->ai_addr, p->ai_addrlen); // we need to connect to get the systems local IP

// get information on the local IP from the socket we created
getsockname(sockfd, sa, sl);

// convert the sockaddr to a sockaddr_in via casting
struct sockaddr_in *sa_ipv4 = (struct sockaddr_in *)sa;

// get the IP from the sockaddr_in and print it
inet_ntop(AF_INET, &(sa_ipv4->sin_addr), str, INET_ADDRSTRLEN);
printf("%s\n", str);

// return the IP
return foundIP;

}

Ответы [ 4 ]

5 голосов
/ 12 июня 2010

Не похоже, что вы когда-либо инициализировали указатель sa, чтобы указывать на действительный sockaddr (или sockaddr_in) объект.

Если вы замените

sockaddr* sa;

с

sockaddr addr;

и замените все варианты использования sa на &addr, вы должны быть в лучшей форме.

То же самое относится и к sl. По крайней мере, согласно документации для моего getsockname, параметр socklen_t* должен указывать на действительный объект socklen_t, инициализированный размером в байтах адресного буфера.

1021 * Е.Г. *

socklen_t slen = sizeof addr;

и используйте &slen вместо sl.

2 голосов
/ 12 июня 2010

Мне кажется, что вы никогда не устанавливали указатель sa, чтобы на самом деле указывать на что-либо.Закомментируем строку "struct sockaddr_in * sa_ipv4 = (struct sockaddr_in *) sa;"должен вызвать ошибку компиляции, поэтому я думаю, что я вижу, что неспособность скомпилировать вашу программу также может привести к тому, что она не станет segfault - трудно для несуществующего двоичного файла, приводящего к краху:)

1 голос
/ 12 июня 2010

Чтобы добавить, valgrind весьма полезен при обнаружении неинициализированных указателей или любых других ошибок, связанных с указателем.

1 голос
/ 12 июня 2010

Вы не выделили sa перед передачей его в getsockname, поэтому вы фактически передали туда некоторое значение указателя мусора. Это должно быть:

struct sockaddr_in sa;
socklen_t sl;
...
getsockname(sockfd, (struct sockaddr*)&sa, &sl);
...
...