You don't even need to assume some sort of crazy evil compiler to have to worry about this - speculative inlining of function pointers guarded by a safety check is something that FDO builds will actually do.
(memset_ptr)(p, 0, len);
> can be replaced by: if (memset_ptr == memset) {
memset(p, 0, len);
} else {
memset_ptr(p, 0, len);
}
> Which in turn can be optimized using the other tricks noticed above into: if (memset_ptr != memset) {
memset_ptr(p, 0, len);
}
I'm no expert, but this seems like a believable defeat of the technique in the post.Of course, using `dlsym()` isn't exactly portable...
If you've put a semaphore, or mutex lock, or whatever around your calls through memset_ptr(), the transformations will all take place inside the lock, and data races should not be an issue.
memset_ptr is a const (not changed by this program... theoretically) volatile (allowed to be changed by the system, theoretically) pointer to memset. In THIS PARTICULAR CASE, memset_ptr points to memset. The compiler however doesn't know that it won't change due to another processes, but we do. So the compiler shouldn't be able to optimize out the call directly to the function pointer because it introduces a possible race condition: the program reads that memset_ptr points to memset, then the pointer changes (due to some other process changing it), but the program still calls memset, and not memset_ptr. The optimization allows for a possible race condition to occur.
Because a JIT may have enough knowledge of the underlying system to know that the pointer is not pointing to a memory-mapped / DMA'd / etc area, and as such can be assumed to remain constant.
This might cause side effects if /dev/null does not exist or is not the null device.