Atribuição errônea de ponteiro a um inteiro

20 views
Skip to first unread message

Fernando Mercês

unread,
Feb 8, 2012, 3:31:25 PM2/8/12
to ccppb...@googlegroups.com
Boa noite, grupo!

Eu uso um adaptador D-Link DWA-125 no Linux, que tem driver para o
kernel 2.6 [1], no enanto, desde o kernel 3.0 a compilação deste
driver falha e venho fazendo ajustes no código para compilar [2].
Coloquei o kernel 3.2 e novamente foram necessários ajustes. Agora
estou removendo os warnings mas um ainda persiste:

/home/fernando/drivers/dwa-125/2009_1204_RT3070_Linux_STA_v2.1.2.0/os/linux/../../common/ba_action.c:
In function ‘convert_reordering_packet_to_preAMSDU_or_802_3_packet’:
/home/fernando/drivers/dwa-125/2009_1204_RT3070_Linux_STA_v2.1.2.0/os/linux/../../common/ba_action.c:1524:2:
warning: assignment makes integer from pointer without a cast [enabled
by default]

A linha em questão é essa:

SET_OS_PKT_DATATAIL(pRxPkt, pRxBlk->pData, pRxBlk->DataSize);

Caçando os defines e typedefs:

typedef unsigned char UCHAR;
typedef UCHAR* PUCHAR;
#define RTPKT_TO_OSPKT(_p) ((struct sk_buff *)(_p))
#define SET_OS_PKT_DATATAIL(_pkt, _start, _len) \
((RTPKT_TO_OSPKT(_pkt))->tail) = (PUCHAR)((_start) + (_len))

Então expandindo a linha original:

1ª expansão: ((RTPKT_TO_OSPKT(pRxPkt))->tail) =
(PUCHAR)(pRxBlk->pData) + (pRxBlk->DataSize));
2ª expansão: ((((struct sk_buff *)(pRxPkt)))->tail) =
(PUCHAR)((pRxBlk->pData) + (pRxBlk->DataSize));

Estou certo? Bem, usando a linha como na segunda expansão, recebo
exatamente o mesmo warning, o que é de se esperar.

Seguindo, vi que o struct sk_buff pode ter este campo 'tail' com o
interio ou como ponteiro, dependendo de um define:

Em /usr/src/linux-headers-3.2.0-1-common/include/linux/skbuff.h:

#if BITS_PER_LONG > 32
#define NET_SKBUFF_DATA_USES_OFFSET 1
#endif

#ifdef NET_SKBUFF_DATA_USES_OFFSET
typedef unsigned int sk_buff_data_t;
#else
typedef unsigned char *sk_buff_data_t;
#endif

struct sk_buff {
sk_buff_data_t tail;
}

Meu chute é que nos kernels anterioes este campo seja inteiro. No
entanto, o driver está funcionando. Alguém vê alguma chance de
funcionar assim ou será que dei "sorte"? Acho que vai dar muito
trabalho remover este warning. O que acham?

Grato!

[1] ftp://ftp.dlinkla.com/pub/drivers/DWA-125/DRIVER_LINUX_DWA-125_STA_v2.1.2.0.tar.gz
[2] http://www.mentebinaria.com.br/blog#6

Att,

Fernando Mercês
Linux Registered User #432779
www.mentebinaria.com.br
softwarelivre-rj.org
@MenteBinaria
------------------------------------
II Hack'n Rio - 23 e 24/11
                 hacknrio.org
------------------------------------

Fernando Mercês

unread,
Feb 8, 2012, 3:55:41 PM2/8/12
to ccppb...@googlegroups.com
Fiz um teste mudando a definição do campo 'tail' para ser sempre
ponteiro de char e vários erros ocorreram por conta de funções da
própria skbuff.h que esperam que o 'tail' seja inteiro.

Achei também a mudança no kernel, na versão 2.6.22 [1]. Inclusive o
patch é de um brasileiro. :)

Agora como eu vou corrigir isso ainda não descobri. Não sei também se
vale a pena, uma vez que o driver funciona. Gostaria da opinião dos
senhores. ;)

[1] https://github.com/mirrors/linux/commits/v2.6.22/include/linux/skbuff.h

Att,

Fernando Mercês
Linux Registered User #432779
www.mentebinaria.com.br
softwarelivre-rj.org
@MenteBinaria
------------------------------------
II Hack'n Rio - 23 e 24/11
                 hacknrio.org
------------------------------------

2012/2/8 Fernando Mercês <nan...@gmail.com>:

Fabio Mazzarino

unread,
Feb 9, 2012, 4:31:47 AM2/9/12
to ccppb...@googlegroups.com
Fernando:

Eu dei uma olhada no fxr e lá diz que essa macro não é usada.

Durante o dia eu não tenho como ficar fuçando no código do linux, vc poderia verificar?

Se não estiver sendo utilizado acredito que o melhor seja vc colocar o bendito do cast que o compilador está solicitando.

P.

unread,
Feb 9, 2012, 7:28:56 AM2/9/12
to ccppb...@googlegroups.com

Em quarta-feira, 8 de fevereiro de 2012 18h31min25s UTC-2, Fernando Mercês escreveu:
 

Meu chute é que nos kernels anterioes este campo seja inteiro. No
entanto, o driver está funcionando. Alguém vê alguma chance de
funcionar assim ou será que dei "sorte"? Acho que vai dar muito
trabalho remover este warning. O que acham?


A rigor, você não pode resolver esse warning, apenas silenciar esse warning usando um "cast" explícito.

O warning é necessário porque o C não garante a preservação do valor do ponteiro através da conversão.

Porém, o código-fonte do Linux pode impor maiores restrições e garantir a preservação desse valor; por exemplo, é seguro que, com GCC target i686-*-gnu-linux, a conversão preserva o valor do ponteiro, porque nesse target um endereço de memória é idêntico a um inteiro do mesmo tamanho. Se o target fosse x86_64-*-gnu-linux, isso não seria verdade.

--
 P.

P.

unread,
Feb 9, 2012, 7:29:48 AM2/9/12
to ccppb...@googlegroups.com

ops, quis dizer: no i686-*-gnu-linux um endereço de memória é idêntico a um int.

--
 P.

Rodrigo Kumpera

unread,
Feb 9, 2012, 8:48:06 AM2/9/12
to ccppb...@googlegroups.com


2012/2/9 P. <pedro....@gmail.com>
Isso é muito problemático em alvos ILP32 ou N32 rodando em hardware 64bits. 
 

Fernando Mercês

unread,
Feb 9, 2012, 8:50:43 AM2/9/12
to ccppb...@googlegroups.com
Obrigado, pessoal. Nos kernels anteriores era char* mesmo.

Entendi sobre o cast. Estou usando x86-64. O ponteiro aqui tem o dobro
do tamanho de um inteiro e possivelmente esse warning não acontece em
x86, correto?

Coloquei o cast mas ele reclama do tamanho, o que faz total sentido
pois o ponteiro tem 64-bits e um inteiro, 32:

/home/fernando/drivers/dwa-125/2009_1204_RT3070_Linux_STA_v2.1.2.0/os/linux/../../common/ba_action.c:1525:43:
warning: cast from pointer to integer of different size
[-Wpointer-to-int-cast]

Então fiz um cast pra long (64-bits) e compilou sem warnings! Mas
certamente terei de tratar isso quando compilar em 32-bits!

Valeu, galera! Isso vai ajudar quem tem esse adaptador véio e usa
kernel novo (eu) hehe

Abraços.

Att,

Fernando Mercês
Linux Registered User #432779
www.mentebinaria.com.br
softwarelivre-rj.org
@MenteBinaria
------------------------------------
II Hack'n Rio - 23 e 24/11
                 hacknrio.org
------------------------------------

2012/2/9 P. <pedro....@gmail.com>:

> --
> Antes de enviar um e-mail para o grupo leia:
> http://www.ccppbrasil.org/wiki/Lista:AntesdePerguntar
> --~--~---------~--~----~---------------------------------~----------~--~----~
> [&] Colabore com a Pesquisa de Preferência de Conteúdo
> para Eventos do Grupo C & C++ Brasil:
> http://www.surveymonkey.com/s/GBBGTXN
> ------~----~-------~---~---~---~---~----------------~------------~---------~
> [&] C & C++ Brasil - http://www.ccppbrasil.org/
> Para sair dessa lista, envie um e-mail para
> ccppbrasil-...@googlegroups.com
> Para mais opções, visite http://groups.google.com/group/ccppbrasil
> --~--~---------~--~----~--~-~--~---~----~-----------------~--~----------~
> Emprego & carreira: vag...@ccppbrasil.org
> http://groups.google.com/group/dev-guys?hl=en

Gabriel Duarte

unread,
Feb 9, 2012, 8:53:52 AM2/9/12
to ccppb...@googlegroups.com
Tu pode fazer uma checagem do tamanho da "palavra" e usar um ifdef ou qualquer outra coisa assim e fazer o cast certo, independente da plataforma ;)
Abcs

2012/2/9 Fernando Mercês <nan...@gmail.com>



--
Gabriel Duarte
Linux User #471185
France / Grenoble - Rhône Alpes
http://genericdev.wordpress.com/

Fernando Mercês

unread,
Feb 9, 2012, 9:00:40 AM2/9/12
to ccppb...@googlegroups.com
Fala Gabriel!

Sim, o gcc tem uma macro __WORDSIZE que me dá isso. ;-)

Abraço!

Att,

Fernando Mercês
Linux Registered User #432779
www.mentebinaria.com.br
softwarelivre-rj.org
@MenteBinaria
------------------------------------
II Hack'n Rio - 23 e 24/11
                 hacknrio.org
------------------------------------

2012/2/9 Gabriel Duarte <confu...@gmail.com>:

Gabriel Duarte

unread,
Feb 9, 2012, 9:04:08 AM2/9/12
to ccppb...@googlegroups.com
Yep, eu sei, então duas linhas de ifdef resolvem tua vida! Verifica o tamanha do ponteiro e faz o cast  de certo tipo de acordo com a palavra ;)
Abcsss

2012/2/9 Fernando Mercês <nan...@gmail.com>

P.

unread,
Feb 9, 2012, 1:05:25 PM2/9/12
to ccppb...@googlegroups.com

Em quinta-feira, 9 de fevereiro de 2012 11h50min43s UTC-2, Fernando Mercês escreveu:
 
Obrigado, pessoal. Nos kernels anteriores era char* mesmo.

Entendi sobre o cast. Estou usando x86-64. O ponteiro aqui tem o dobro
do tamanho de um inteiro e possivelmente esse warning não acontece em
x86, correto?


A ocorrência do warning é opinião do compilador sobre o que é melhor para o usuário.

A conversão entre tipos inteiros é sempre definida em C, mesmo que ocorra truncamento do valor. O mesmo ocorre de short para char etc.

 
Então fiz um cast pra long (64-bits) e compilou sem warnings! Mas

certamente terei de tratar isso quando compilar em 32-bits!


A presença da notação de "cast" significa que a conversão é explícita; neste caso, o compilador entenderá que o programador está ciente da situação.

Porém, nenhum "cast" pode evitar o truncamento do valor em uma conversão de 64 bits para 32 bits, por motivos óbvios.

Observe que sizeof(long) não é 8 no target x86_64-*-gnu-linux.

A solução correta para este programa é usar intptr_t ao invés de int. Este nome está declarado em stdint.h. A norma exige que uma conversão de ponteiro para intptr_t seja reversível i.e. que não cause truncamento. Assim, a conversão será reversível para qualquer compilador C99.

--
 P.

Felipe Magno de Almeida

unread,
Feb 9, 2012, 1:13:18 PM2/9/12
to ccppb...@googlegroups.com
2012/2/9 P. <pedro....@gmail.com>:

>
> Em quinta-feira, 9 de fevereiro de 2012 11h50min43s UTC-2, Fernando Mercês
> escreveu:
>
>>
>> Obrigado, pessoal. Nos kernels anteriores era char* mesmo.
>>
>> Entendi sobre o cast. Estou usando x86-64. O ponteiro aqui tem o dobro
>> do tamanho de um inteiro e possivelmente esse warning não acontece em
>> x86, correto?
>
>
> A ocorrência do warning é opinião do compilador sobre o que é melhor para o
> usuário.
>
> A conversão entre tipos inteiros é sempre definida em C, mesmo que ocorra
> truncamento do valor. O mesmo ocorre de short para char etc.

Acho que isso só é verdade para unsigneds. Para signeds overflow implica em
undefined behavior. Mas claro, escrevendo um kernel, você vai ter maior
dependência de comportamento específico do compilador.

http://en.wikipedia.org/wiki/Integer_overflow

[snip]

> --
>  P.

[]'s
--
Felipe Magno de Almeida

Reply all
Reply to author
Forward
0 new messages