Re: Can this be a invalid memory access? (was: Re: [PATCH] spi/xilinx: Cast ioread32/iowrite32 function pointers)

From: Ricardo Ribalda Delgado
Date: Mon Feb 02 2015 - 09:05:30 EST


Hello Geert

On Mon, Feb 2, 2015 at 2:04 PM, Geert Uytterhoeven <geert@xxxxxxxxxxxxxx> wrote:

>> void * pvar=varB;
>
> ... = &varB;
>
>> *pvar = ioread8(valid_memory);
>>
>> Depending if ioread8 returns a u8 or a unsigned int, aren't we also
>> accessing varC?
>>
>> Could not this be a problem?
>
> Please try to compile the above.
> The compiler will tell you you cannot dereference a void pointer.
>
> Now, replace "void *" by "unsigned int *".
> After that, varC will indeed be overwritten. But the compiler will still have
> warned you that you assigned the address of an u8 variable to an
> unsigned int pointer.

I am still a bit worried, that the same function has different
prototypes and implementations depending on the arch. But
"unfortunately" I cannot make a counter-example that can cause an
error.

So far, the closest I have get is this:

ricardo@neopili:/tmp$ cat arch.c
#include <stdint.h>

unsigned int my_ioread8(){
return 0xdeadbeef;
}

void test_read();
int main(int argc, char *argv[]){

test_read();
return 0;
}


ricardo@neopili:/tmp$ cat io.h
#ifndef IO_H
#define IO_H
#include <stdint.h>

uint8_t my_ioread8();

#endif


ricardo@neopili:/tmp$ cat driver.c
#include "io.h"
#include <stdint.h>
#include <stdio.h>

void test_read(){
uint8_t varA=0x1;
uint8_t varB=0x2;
uint8_t varC=0x3;

varB = my_ioread8();

fprintf(stdout, "varA=%d varB=%d varC=%d\n",
varA, varB, varC);
}

It does not produce any error at build time:
ricardo@neopili:/tmp$ make
cc -Wall -c -o arch.o arch.c
cc -Wall -c -o driver.o driver.c
cc -Wall arch.o driver.o -o test

and it works fine on amd86

ricardo@neopili:/tmp$ ./test
varA=1 varB=239 varC=3

But in the hypothetical case where the calling convention will be
different for unsigned int and u8, there will be an issue....

The reason that I am interested in this is that I want to be able to
have code like:

struct priv_data{
u16 (read *)(void __iomem *);
};

endian=detect_endianness()

if (endian == BIG)
priv->read= ioread16be;
else
priv->read= ioread16;

data = priv->read(iomem+DATA);

Unfortunately, with the current code, this does not work on all the
arches, and the workaround is having wrappers for ioread and iowrite
like in drivers/spi/spi-xilinx.c

static void xspi_write32(u32 val, void __iomem *addr)
{
iowrite32(val, addr);
}

static void xspi_write32_be(u32 val, void __iomem *addr)
{
iowrite32be(val, addr);
}



Regards




--
Ricardo Ribalda
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/