为什么编译器报告 'may be used uninitialised in this function'?

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

我正在写一个linux模块,下面是代码fragment.And它 抱怨变量的统一化使用,但我想我已经检查过了 使用前有足够的检查 it.I 认为它可能是相关的 ERR_PTR 和 PTR_ERR 宏,但我不知道为什么。 有人可以帮忙解释一下吗?提前谢谢你。

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;

}

错误信息是:

warning: ‘test_value’ may be used uninitialized in this function [-Wmaybe-uninitialized]
if(test_value)
   ^

更新:2015 年 1 月 30 日:

我认为根本原因是 longint 的转换。 PTR_ERR() 函数会将指针转换为 long,但在 上面的代码,test_value_get() 会将 long 转换为 int,然后 return 到 my_test() 。因为我使用的是 64 位机器,long 可能 被截断到低32位,比如0xfffffffe00000000, return 值将被削减为 0,然后 if(err) 将不满足, 这导致 test_value 以错误的方式使用。 (虽然 errno 不会大于 4095,但编译器似乎没有意识到它,最接近的溢出值将是 0xfffffffe00000000) 有什么意见吗?

检查下面的执行链

  1. my_test() 中,test_value_get() 被调用。
  2. test_alloc_value(); 失败,if (IS_ERR(p)) 为真。
  3. *value = *p;没有执行。
  4. my_test() 中,if(test_value) 展示了 read-before-write 情景。

就是说,不管可能性有多大,还是有办法的,test_value可以不初始化使用。那么,你的编译器不对吗?

为避免这种情况,在错误情况下 [if (IS_ERR(p)) 为 TRUE。] 同时,将 *value 初始化为某个默认值,例如 0

if (IS_ERR(p))
{
       if (value)                 //NULL pointer safe
            *value = 0;             // set *value in error case also
            return PTR_ERR(p);
}