I'm writing a linux module, here are the code fragment.And it complains of unitialized using of variable,but I think I've checked there is enough checking before using it.I think it may be related be ERR_PTR and PTR_ERR macro,but I don't know why. Would someone please help to explain it? Thank you in advance.
static inline void * __must_check ERR_PTR(long error)
{
return (void *) error;
}
static inline long __must_check PTR_ERR(__force const void *ptr)
{
return (long) ptr;
}
#define MAX_ERRNO 4095
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
static inline bool __must_check IS_ERR(__force const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
}
void* test_alloc_value(void)
{
char* p = kmalloc(100,GFP_KERNEL);
if(!p)
return ERR_PTR(-ENOMEM);
memset(p,100,0);
return p;
}
int test_value_get(int *value)
{
int err = 0;
char *p;
p = test_alloc_value();
if (IS_ERR(p))
return PTR_ERR(p);
*value = *p;
return err;
}
void my_test(void)
{
int test_value;
int err = test_value_get(&test_value);
if(err)
return err;
if(test_value) //warnings,see below
return 0;
}
The error message is:
warning: ‘test_value’ may be used uninitialized in this function [-Wmaybe-uninitialized]
if(test_value)
^
Update: 01-30-2015:
I think the root cause would be the long
to int
conversion. The PTR_ERR()
function would convert a pointer to long
,but in
above code,test_value_get()
would convert a long
into int
,and return it
to my_test()
.Since I'm using a 64bit machine,the long would possibly
be cut off to lower 32bits,for example,if it is 0xfffffffe00000000,
the return value would be cut to 0,and then if(err)
would not satisfy,
which caused the test_value
be used in a wrong manner.
(Although the errno would not be greater than 4095,compiler seemed not be aware of it,the nearest overflow value would be 0xfffffffe00000000)
Any comments?
Check the below execution chain
my_test()
, test_value_get()
gets called.test_alloc_value();
fails, if (IS_ERR(p))
is TRUE.*value = *p;
is not executed.my_test()
, if(test_value)
exhibits read-before-write
scenario.It means, hoever less probable it might be, there is still a way, test_value
may be used uninitialized. So, isn't your compiler right?
To avoid this, in error case [if (IS_ERR(p))
is TRUE.] also, initialize *value
to some default value, like 0
.
if (IS_ERR(p))
{
if (value) //NULL pointer safe
*value = 0; // set *value in error case also
return PTR_ERR(p);
}