您的位置:首页 > 产品设计 > UI/UE

[知其然不知其所以然-26] Why shouldn't you use IS_ERR_VALUE

2016-05-28 14:01 435 查看
Beware of the IS_ERR_VALUE, you should not use it to check if function returns any errno code,

instead, you can only use IS_ERR_VALUE for pointer validation, and use if(ret) to verify whether

the function succeed or not.
https://patchwork.ozlabs.org/patch/627363/
Most users of IS_ERR_VALUE() in the kernel are wrong, as they
pass an 'int' into a function that takes an 'unsigned long'
argument. This happens to work because the type is sign-extended
on 64-bit architectures before it gets converted into an
unsigned type.

However, anything that passes an 'unsigned short' or 'unsigned int'
argument into IS_ERR_VALUE() is guaranteed to be broken, as are
8-bit integers and types that are wider than 'unsigned long'.
cat test_is_err_value.c
#include <stdio.h>
#define MAX_ERRNO       4095
#define IS_ERR_VALUE(x) ((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)
#define EPERM            1
#define ENOENT           2

int main(int argc, char *argv[])
{
int test_0 = -EPERM;
unsigned int test_1 = -ENOENT;

if (IS_ERR_VALUE(test_0))
printf("test_0 invalid\n");
else
printf("test_0 valid\n");
if (IS_ERR_VALUE(test_1))
printf("test_1 invalid\n");
else
printf("test_1 valid\n");
return 0;
}
gcc test_is_err_value.c -o test_is_err_value
test_is_err_value.c: In function ‘main’:
test_is_err_value.c:3:41: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define IS_ERR_VALUE(x) ((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)
^
test_is_err_value.c:12:6: note: in expansion of macro ‘IS_ERR_VALUE’
if (IS_ERR_VALUE(test_0))
^
test_is_err_value.c:3:41: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define IS_ERR_VALUE(x) ((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)
^
test_is_err_value.c:16:6: note: in expansion of macro ‘IS_ERR_VALUE’
if (IS_ERR_VALUE(test_1))
^

OK, we can see from the compiling error, int and unsigned int are both expanded, while int

is signed expanded,so it is still -EPERM after expanded to 64bits, while for unsigned int,it is expanded

as unsigned, so the value becomes a valid one, (it is smaller than 0xffffffff),because the higher 32bits are

filled with zero, without setting the bit63 to 1.

./test_is_err_value
test_0 invalid
test_1 valid
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  error handling