Search code examples
cinitializationcompiler-warnings

Why compiler report 'may be used uninitialised in this function'?


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?


Solution

  • Check the below execution chain

    1. In my_test(), test_value_get() gets called.
    2. test_alloc_value(); fails, if (IS_ERR(p)) is TRUE.
    3. *value = *p; is not executed.
    4. in 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);
    }