warning: dereferencing 'void *' pointer

1. warning: dereferencing 'void *' pointer

97-3048-567-XS32
97-3048-567-XS32

(usa Outra)

Enviado em 03/07/2021 - 12:11h

TL;DR

Por que o programa abaixo está gerando um warning "dereferencing 'void *' pointer"? É possível corrigir sem mexer muito na lógica do programa?


#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>

#include <netdb.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define SNDTIMEO 5
#define MAXCONN 10

static bool set_sock_opts(int sockfd, bool only_ipv6) {

bool ok = false;
const int optval = 1;
struct timeval timeout = {SNDTIMEO, 0};

do {

if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) != 0 ) {

break;
}

if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != 0 ) {

break;
}

if (only_ipv6 == true) {

if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)) != 0 ) {

break;
}
}

ok = true;

} while (false);

return ok;
}

static int make_server_socket(int af, const char *service, bool only_ipv6, size_t somaxconn) {

int sockfd, ecode;
struct addrinfo hints, *result = NULL, *rp = NULL;

memset(&hints, 0, sizeof(hints));

hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;

if ((ecode = getaddrinfo(NULL, service, &hints, &result)) != 0 ) {

fprintf(stderr, "make_server_socket() -> getaddrinfo() -> ERROR: %s\n", gai_strerror(ecode));

exit(EXIT_FAILURE);
}

for (rp = result; rp != NULL; rp = rp->ai_next) {

if ((sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0 ) {

continue;
}

if (set_sock_opts(sockfd, only_ipv6) != true ) {

close(sockfd);

continue;
}

if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) != -1 ) {

break;
}

close(sockfd);
}

if (rp == NULL) {

fprintf(stderr, "make_server_socket() -> socket()/bind() -> ERROR: %s\n", strerror(errno));

freeaddrinfo(rp);

exit(EXIT_FAILURE);
}

freeaddrinfo(rp);

if (listen(sockfd, somaxconn) < 0 ) {

fprintf(stderr, "make_server_socket() -> listen() -> ERROR: %s\n", strerror(errno));

close(sockfd);

exit(EXIT_FAILURE);
}

return sockfd;
}

static bool check_addr(int af, void *addr, void *adresses, size_t count) {

bool found = false;

if (af == AF_UNIX) {

struct sockaddr_un *un = addr;

for (size_t i = 0; i < count; i++) {

struct sockaddr_un *tmp = &adresses[i];

if (memcmp(un->sun_path, tmp->sun_path, sizeof(un->sun_path)) == 0 ) {

found = true;

break;
}
}

} else if (af == AF_INET) {

struct sockaddr_in *in = addr;

for (size_t i = 0; i < count; i++) {

struct sockaddr_in *tmp = &adresses[i];

if (memcmp(&in->sin_addr.s_addr, &tmp->sin_addr.s_addr, sizeof(in->sin_addr.s_addr)) == 0 ) {

found = true;

break;
}
}

} else {

struct sockaddr_in6 *in6 = addr;

for(size_t i = 0; i < count; i++) {

struct sockaddr_in6 *tmp = &adresses[i];

if (memcmp(&in6->sin6_addr.s6_addr, &tmp->sin6_addr.s6_addr, sizeof(in6->sin6_addr.s6_addr)) == 0 ) {

found = true;

break;
}
}
}

return found;
}

static void show_addr(int af, void *addr) {

char buff[INET6_ADDRSTRLEN];

if (af == AF_UNIX) {

struct sockaddr_un *un = addr;

printf("%s\n", un->sun_path);

} else if (af == AF_INET) {

struct sockaddr_in *in = addr;

if (inet_ntop(af, &in->sin_addr.s_addr, buff, INET_ADDRSTRLEN) < 0 ) {

fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno));

} else {

printf("%s\n", buff);
}

} else {

struct sockaddr_in6 *in6 = addr;

if (inet_ntop(af, &in6->sin6_addr.s6_addr, buff, INET6_ADDRSTRLEN) < 0 ) {

fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno));

} else {

printf("%s\n", buff);
}
}
}

static void search(char **argv, size_t somaxconn, size_t maxconn) {

int af;
bool only_ipv6 = false;
socklen_t addrlen;

if (strcmp(argv[1], "-u") == 0 ) {

af = AF_UNIX;

addrlen = sizeof(struct sockaddr_un);

} else if (strcmp(argv[1], "-4") == 0 ) {

af = AF_INET;

addrlen = sizeof(struct sockaddr_in);

} else if (strcmp(argv[1], "-6") == 0 ) {

af = AF_INET6;

only_ipv6 = true;

addrlen = sizeof(struct sockaddr_in6);

} else {

af = AF_INET6;

addrlen = sizeof(struct sockaddr_in6);
}

size_t i = 0;
int sockfd = make_server_socket(af, argv[2], only_ipv6, somaxconn);
void *addr = malloc(addrlen);
void *adresses = NULL;

const char msg_1[] = "Welcome!\n", err_msg[] = "Internal server error!", msg_2[] = "Get out!\n";

while (i < maxconn) {

int cli_sockfd;

if ((cli_sockfd = accept(sockfd, addr, &addrlen)) < 0 ) {

fprintf(stderr, "search() -> accept() -> ERROR: %s\n", strerror(errno));

} else {

if (check_addr(af, addr, adresses, i) == false ) {

void *tmp = realloc(adresses, addrlen * (i + 1));

if (!tmp) {

fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\nsearch() -> realloc() -> ERROR: %s\n",
addrlen * (i + 1), strerror(errno));

send(cli_sockfd, err_msg, sizeof(err_msg), 0);

} else {

i++;

adresses = tmp;

memcpy(&adresses[i-1], addr, addrlen);

show_addr(af, addr);

send(cli_sockfd, msg_1, sizeof(msg_1), 0);
}

}else{

send(cli_sockfd, msg_2, sizeof(msg_2), 0);
}

close(cli_sockfd);
}
}

free(addr);

free(adresses);

close(sockfd);
}

int main(int argc, char **argv) {

if (argc == 1) {

printf(" *** ERROR: No arguments! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");

exit(EXIT_FAILURE);
}

int opt = getopt(argc, argv, "u46Mh");

if (strlen(argv[1]) > 2 ) {

printf("*** Invalid value for [OPTION]! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");

} else if (opt == 'h' || opt == '?') {

printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");

} else if ((argc < 5) || (argc > 5)) {

printf("*** Invalid values! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");

}else{

size_t somaxconn = strtoull(argv[3], NULL, 10);
size_t maxconn = strtoull(argv[4], NULL, 10);

if (somaxconn > SOMAXCONN) {

printf("*** Invalid value for [SOMAXCONN]. The value is too long! ***\n");
printf("The maximum allowed value is %u\n", SOMAXCONN);

} else if ( maxconn > MAXCONN ) {

printf("*** Invalid value for [MAXCONN]. The value is too long! ***\n");
printf("The maximum allowed value is %u\n", MAXCONN);

} else {

search(argv, somaxconn, maxconn);
}
}

return EXIT_SUCCESS;
}


Compilação e tempo de execução:

//Terminal do servidor
$ gcc -Wall server_2.c -o server
server_2.c: In function 'check_addr':
server_2.c:135:60: warning: dereferencing 'void *' pointer
135 | struct sockaddr_un *tmp = &adresses[i];
| ^
server_2.c:149:60: warning: dereferencing 'void *' pointer
149 | struct sockaddr_in *tmp = &adresses[i];
| ^
server_2.c:163:61: warning: dereferencing 'void *' pointer
163 | struct sockaddr_in6 *tmp = &adresses[i];
| ^
server_2.c: In function 'search':
server_2.c:280:57: warning: dereferencing 'void *' pointer
280 | memcpy(&adresses[i-1], addr, addrlen);
| ^
$ ./server -M 9009 4096 3
::ffff:127.0.0.1
::1
::ffff:192.168.50.2



//Terminal do cliente
$ nc 127.0.0.1 9009
Welcome!
^C
$ nc ::1 9009
Welcome!
^C
$ nc 192.168.50.2 9009
Welcome!
^C


Afinal, o que esse programa faz?

É basicamente uma aplicação servidora escrita usando a API de sockets do Linux que tem como objetivo enviar uma simples mensagem para o cliente informando se ele se conectou pela primeira vez ("Welcome!") ou se ele está realizando uma reconexão ("Get out!").

Na verdade não é a primeira vez que escrevo algo do tipo. Algumas semanas atrás eu fiz exatamente o mesmo, porém utilizei uma matriz alocada dinâmicamente no lugar de um vetor alocado dinâmicamente. Segue o código para uma melhor análise:


#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>

#include <netdb.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define SNDTIMEO 5
#define MAXCONN 10

static bool set_sock_opts(int sockfd, bool only_ipv6) {

bool ok = false;
const int optval = 1;
struct timeval timeout = {SNDTIMEO, 0};

do {

if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) != 0 ) {

break;
}

if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != 0 ) {

break;
}

if (only_ipv6 == true) {

if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)) != 0 ) {

break;
}
}

ok = true;

} while (false);

return ok;
}

static int make_server_socket(int af, const char *service, bool only_ipv6, size_t somaxconn) {

int sockfd, ecode;
struct addrinfo hints, *result = NULL, *rp = NULL;

memset(&hints, 0, sizeof(hints));

hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;

if ((ecode = getaddrinfo(NULL, service, &hints, &result)) != 0 ) {

fprintf(stderr, "make_server_socket() -> getaddrinfo() -> ERROR: %s\n", gai_strerror(ecode));

exit(EXIT_FAILURE);
}

for (rp = result; rp != NULL; rp = rp->ai_next) {

if ((sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0 ) {

continue;
}

if (set_sock_opts(sockfd, only_ipv6) != true ) {

close(sockfd);

continue;
}

if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) != -1 ) {

break;
}

close(sockfd);
}

if (rp == NULL) {

fprintf(stderr, "make_server_socket() -> socket()/bind() -> ERROR: %s\n", strerror(errno));

freeaddrinfo(rp);

exit(EXIT_FAILURE);
}

freeaddrinfo(rp);

if (listen(sockfd, somaxconn) < 0 ) {

fprintf(stderr, "make_server_socket() -> listen() -> ERROR: %s\n", strerror(errno));

close(sockfd);

exit(EXIT_FAILURE);
}

return sockfd;
}

static bool check_addr(int af, void *addr, void **addr_table, size_t count) {

bool found = false;

if (af == AF_UNIX) {

struct sockaddr_un *un = addr;

for (size_t i = 0; i < count; i++) {

struct sockaddr_un *tmp = addr_table[i];

if (memcmp(un->sun_path, tmp->sun_path, sizeof(un->sun_path)) == 0 ) {

found = true;

break;
}
}

} else if (af == AF_INET) {

struct sockaddr_in *in = addr;

for (size_t i = 0; i < count; i++) {

struct sockaddr_in *tmp = addr_table[i];

if (memcmp(&in->sin_addr.s_addr, &tmp->sin_addr.s_addr, sizeof(in->sin_addr.s_addr)) == 0 ) {

found = true;

break;
}
}

} else {

struct sockaddr_in6 *in6 = addr;

for(size_t i = 0; i < count; i++) {

struct sockaddr_in6 *tmp = addr_table[i];

if (memcmp(&in6->sin6_addr.s6_addr, &tmp->sin6_addr.s6_addr, sizeof(in6->sin6_addr.s6_addr)) == 0 ) {

found = true;

break;
}
}
}

return found;
}

static void show_addr(int af, void *addr) {

char buff[INET6_ADDRSTRLEN];

if (af == AF_UNIX) {

struct sockaddr_un *un = addr;

printf("%s\n", un->sun_path);

} else if (af == AF_INET) {

struct sockaddr_in *in = addr;

if (inet_ntop(af, &in->sin_addr.s_addr, buff, INET_ADDRSTRLEN) < 0 ) {

fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno));

} else {

printf("%s\n", buff);
}

} else {

struct sockaddr_in6 *in6 = addr;

if (inet_ntop(af, &in6->sin6_addr.s6_addr, buff, INET6_ADDRSTRLEN) < 0 ) {

fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno));

} else {

printf("%s\n", buff);
}
}
}

static void **realloc_addr_table(void **addr_table, size_t count, socklen_t addrlen) {

void **tmp = realloc(addr_table, count * sizeof(*addr_table));

if (tmp == NULL) {

fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\nrealloc_addr_table() -> realloc() -> ERROR: %s\n",
count * sizeof(*addr_table), strerror(errno));

} else {

tmp[count-1] = malloc(addrlen);

if (tmp == NULL) {

fprintf(stderr, "ERROR: Memory allocation for %u bytes failed\nrealloc_addr_table -> realloc() -> ERROR: %s\n",
addrlen, strerror(errno));
}
}

return tmp;
}

static void free_addr_table(void **addr_table, size_t count) {

for (size_t i = 0; i < count; i++) {

free(addr_table[i]);
}

free(addr_table);
}

static void search(char **argv, size_t somaxconn, size_t maxconn) {

int af;
bool only_ipv6 = false;
socklen_t addrlen;

if (strcmp(argv[1], "-u") == 0 ) {

af = AF_UNIX;

addrlen = sizeof(struct sockaddr_un);

} else if (strcmp(argv[1], "-4") == 0 ) {

af = AF_INET;

addrlen = sizeof(struct sockaddr_in);

} else if (strcmp(argv[1], "-6") == 0 ) {

af = AF_INET6;

only_ipv6 = true;

addrlen = sizeof(struct sockaddr_in6);

} else {

af = AF_INET6;

addrlen = sizeof(struct sockaddr_in6);
}

size_t i = 0;
int sockfd = make_server_socket(af, argv[2], only_ipv6, somaxconn);
void *addr = malloc(addrlen);
void **addr_table = NULL;

const char msg_1[] = "Welcome!\n", err_msg[] = "Internal server error!", msg_2[] = "Get out!\n";

while (i < maxconn) {

int cli_sockfd;

if ((cli_sockfd = accept(sockfd, addr, &addrlen)) < 0 ) {

fprintf(stderr, "search() -> accept() -> ERROR: %s\n", strerror(errno));

} else {

if (check_addr(af, addr, addr_table, i) == false ) {

void **tmp = realloc_addr_table(addr_table, i+1, addrlen);

if (!tmp) {

send(cli_sockfd, err_msg, sizeof(err_msg), 0);

} else {

i++;

addr_table = tmp;

memcpy(addr_table[i-1], addr, addrlen);

show_addr(af, addr);

send(cli_sockfd, msg_1, sizeof(msg_1), 0);
}

}else{

send(cli_sockfd, msg_2, sizeof(msg_2), 0);
}

close(cli_sockfd);
}
}

free(addr);

free_addr_table(addr_table, i);

close(sockfd);
}

int main(int argc, char **argv) {

if (argc == 1) {

printf(" *** ERROR: No arguments! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");

exit(EXIT_FAILURE);
}

int opt = getopt(argc, argv, "u46Mh");

if (strlen(argv[1]) > 2 ) {

printf("*** Invalid value for [OPTION]! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");

} else if (opt == 'h' || opt == '?') {

printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");

} else if ((argc < 5) || (argc > 5)) {

printf("*** Invalid arguments! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");

} else {

size_t somaxconn = strtoull(argv[3], NULL, 10);
size_t maxconn = strtoull(argv[4], NULL, 10);

if (somaxconn > SOMAXCONN) {

printf("*** ERROR: The value passed for [SOMAXCONN] is too long! ***\n");
printf("The maximum allowed value is %d\n", SOMAXCONN);

} else if (maxconn > MAXCONN) {

printf("*** ERROR: The value passed for [MAXCONN] is too long! ***\n");
printf("The maximum allowed value is %d\n", MAXCONN);

} else {

search(argv, somaxconn, maxconn);
}
}

return EXIT_SUCCESS;
}


O código do programa acima tem um funcionamento em tempo de execução semelhante ao anterior. A única coisa que muda é fato dele utilizar uma matriz alocada dinâmicamente no lugar de um vetor alocado dinâmicamente.


  


2. Re: warning: dereferencing 'void *' pointer

berghetti
berghetti

(usa Debian)

Enviado em 06/07/2021 - 17:04h

considere esse programa

#include <stdio.h>

int main(void)
{
int ar[5];

void *p = ar;

printf("%p\n%p\n%p\n%p\n",
&ar[1],
&(*(ar + 1)),
ar + 1,
p + 1);
}


quando faço
ar + 1 

estou fazendo aritmética de ponteiros,
que significa que ao adicionar 1 ao endereço que representa o array ar,
o compilador vai adicionar 1 * sizeof(int) bytes a esse endereço.

porem quando faço
p + 1 

sendo p um ponteiro para qualquer tipo de dado (void),
o compilador não sabe quantos bytes adicionar a esse endereço e acaba adicionando 1 ao endereço como comportamento padrão,
que provavelmente não é o lugar que você espera apontar.

mas o aviso do compilador não é sobre isso,
e sim sobre dereferenciar um ponteiro do tipo void,
não faz sentido ler um dado que você ( o compilador ) não sabe como interpreta-lo.

isso
 struct sockaddr_un *tmp = &adresses[i];  

é sinônimo disso
 struct sockaddr_un *tmp = &(*(adresses + i));  


que é onde ocorre a dereferencia

você poderia escrever assim

struct sockaddr_un *tmp = (struct sockaddr_un *) adress + i;



off:
você poderia postar somente a parte que interessa do código, facilitando a leitura.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts