When a pointer to a function type T1 is converted to a pointer to function type T2, many implementations will leave the value of the pointer unchanged. However, if the types T1 and T2 are not compatible, the C standard says that a call made using the converted pointer (pointer to T2) will give rise to undefined behaviour. Rule 11.1 limits the possibility for this undefined behaviour by preventing a direct conversion between incompatible function pointer types.
As an example of the kind of undefined behaviour that can arise, consider two functions with identical return types but different numbers and/or types of parameters. Suppose that the called function with type T1 requires 8 bytes for its parameters but T2 requires 6 bytes. A call is made to a function with type T1 using a pointer to type T2. The behaviour that results will depend on the way function calls are implemented in the particular compiler. Suppose that the caller pushes arguments onto the stack and then makes a call which then pushes a 2-byte return address onto the stack. The called function is expecting 8 bytes of parameters so it will access those parameters at the wrong stack offsets. When it returns it may use a return instruction that also adjusts the stack pointer to remove the arguments that were stacked by the caller, after loading the return address into the program counter. It will remove 8 bytes of argument from the stack which will result in the original calling function operating with its stack pointer 2 bytes below its location prior to the call sequence start. All of this can give rise to undefined behaviour such as incorrect results, exceptions and program crashes.
Posted by and on behalf of
the MISRA C Working Group