Hovering a pointer to warning integer releases on a 64-bit arch

I am writing a linux kernel module that uses the exported open_exec symbol

 struct file *open_exec(const char *name) 

It returns a pointer, and I can check for an error with the IS_ERR macro:

 if (IS_ERR(file)) return file; 

At compile time, I get the following warning:

 warning: return makes integer from pointer without a cast 

This is because my function returns an integer. If I try to do this:

 return (int) file; 

I do not receive a warning on my 32-bit machine, but I do on my 64-bit machine:

 warning: cast from pointer to integer of different size 

This is because the sizeof for the int and the pointer are the same on the 32-bit one, but they differ on the 64-bit machine.

Whether or not it is discarded, the code works. I just wanted to get rid of the warning.

How to correctly cast a pointer to an integer and get the value that I expect without receiving a compiler warning? The expected value is essentially the integer specified in the include/asm-generic/errno-base.h base of the Linux kernel code.

Since I look only at the pointer, as if it were an integer in the case when IS_ERR() is true, I can be sure that in fact it contains only an integer value.

+4
source share
3 answers

The macro PTR_ERR() in linux/err.h , where IS_ERR() is also located, converts the pointer, which is actually an error code, to the corresponding type (a long ).

You should use something like:

 if (IS_ERR(file)) return PTR_ERR(file); 

Find the existing PTR_ERR() sources in the source, and you will see that this is a common template.

It might be advisable to return a long function, not an int , but all error codes should be represented in int .

+8
source

You cannot correctly pointer to a type of a smaller size, period. You could do some conversion if you were sure to keep this pointer.

For example, if you know that a pointer has only the least significant 32 bits, you can simply use it and use some pragma for the compiler to suppress the warning. Or, if you want to use a hash pointer to use in something like a hash table, you can use the upper 32 bits with the lower 32 bits.

It is impossible to solve without knowing how this int will be used later.

+1
source

I'm not sure what I get, how do you sometimes want to return a number from errno-base.h, and sometimes a pointer - how would the receiving function tell you about everyone else? This is equal, and then in Linux GCC,

  • int is 32 bit wide whether you are on 32 or 64 bit linux
  • pointers are 64-bit wide on 64-bit architectures and 32 bytes wide 32-bit architectures
  • long have 32-bit width on 32-bit architectures and 64-bit width on 64-bit architectures.
  • long long always have a width of 64 bits.

therefore, on a 64-bit architecture, casting a pointer to int, you will get a 64-bit value up to a 32-bit value, and you can be sure that you will lose some of the 64-bit information from the pointer - and this is what the compiler warns about, since you point to yourself.

If you want to give a pointer to "anonymous", then your choice should be either long , long long , or void* - the most portable of void* .

Another alternative is to write in the form of an offset, that is, if you have a large memory area where you want to β€œoverlay” a 32-bit integer, and then convert it to something like that;

  static struct mybigbuffer *globalbuffer; int cast2int(void*x) { return (int)(globalbuffer-(struct mybigbuffer*)x); } 

however , that only works if you know that your memory will never exceed 2 ^ 31 globalbuf entries and that your pointers will be sure bounds, etc. - therefore, if you are 100% sure that you know what you are doing, I would not recommend this - stick to long or empty * as safe options.

0
source

All Articles