Allocation and free functions from the standard library are 'special' though and do actually get their own logic in regards to whether a pointer is necessary or not. If you do some simple tests you can see that gcc will optimize away entire `malloc()` and `free()` calls if it can prove the resulting memory or assignments are unnecessary (Ex. Store a constant to it, and then read the constant). It's willing to do that because the behavior of those functions is defined by the standard, so it 'knows' that removing those calls has no affect on the behavior of the program.
I'm pretty sure you can get similar optimization behavior when you mark functions with special attributes, I'm not 100% sure on that point though. So for the Linux Kernel I'm not sure that kind of optimization would ever be done since obviously it's not using the standard defined functions and the compiler might not be given enough information to know the functions have the same semantics as 'malloc()' and 'free()'.
I personally was able to get the exact behavior described here by compiling the below code using `-O2`. The volatile write just ensures the first constant write and the malloc itself cannot be optimized out (and that does happen! Take out the volatile and there are no calls to malloc in the result), but gcc is still free to do whatever it wants with the other write and for me it's completely gone in the resulting program.
int main()
{
int *p = malloc(sizeof(*p));
*(volatile int *)p = 20;
printf("p=%d\n", *p);
*p = 30; /* this is gone from the -O2 compiled code */
free(p);
return 0;
}
The relevant part of the assembly looks like this, I don't think I'm missing anything in that the 30 assignment is completely gone:
push $0x4
call 460 <malloc@plt>
movl $0x14,(%eax) # Assignment of 20
mov %eax,%esi
pop %eax
lea -0x1930(%ebx),%eax
pop %edx
pushl (%esi) # push the 20
push %eax
call 440 <printf@plt>
mov %esi,(%esp) # load address to pass to free(), no assignment between printf() and free()
call 450 <free@plt>