We had a discussion on how to ensure that data in some shared (untrusted) memory region is only accessed once, copied to local memory, and then checked and processed from there. Environment is an embedded multicore µC with shared RAM for IPC, code is written in C99.
Currently, we basically do Type local_copy = *(Type*)shared_memory_pointer;
and then only operate on local_copy
afterwards.
Now a colleague brought up the question, whether the compiler was allowed to not perform the copy into local memory and instead access the data at shared_memory_pointer
directly in the following, which (in theory) would allow for manipulation of the data while it is used.
Is it possible that a compiler does that? If so, how can we make sure that it does not happen? If not, please explain the details.
Thanks all!
Edit: there is no OS on the core in question, it is a bare-metal system.
CodePudding user response:
whether the compiler was allowed to not perform the copy into local memory and instead access the data at shared_memory_pointer directly
Yes the compiler is allowed to do that. The only scenario where you can enforce a read is by volatile
qualified access. In your case both the local variable and the cast should be volatile
qualified.
Note however...
volatile
doesn't solve re-entrancy issues. You need a mutex, critical section or similar means to block the code from race condition bugs. Use the means provided by your OS.Type local_copy = *(Type*)shared_memory_pointer;
is very fishy code and suggests that you have undefined behavior or type-related bugs in your program. Wild type punning like this might cause misalignment, incorrect strict pointer aliasing optimizations, discarded qualifiers and so on - all of it undefined behavior. Besides, if you have picked proper types there is no need to cast in the first place.
CodePudding user response:
We had a discussion on how to ensure that data in some shared (untrusted) memory region is only accessed once, copied to local memory, and then checked and processed from there.
Use memcpy
with binary semaphore instead of pointer punning.
freeRTOS example: It makes sure that the
if(xSemaphoreTake( xSemaphoreSharedVariable, (TickType_t) 10 ) == pdTRUE)
{
taskENTER_CRITICAL(); //make sure that the shared resource will not be changed during not atomic access
memcpy(&local_copy, shared_memory_pointer, sizeof(local_copy);
taskEXIT_CRITICAL();
}
else
{
/* the shared resource was alredsy read */
/* do something */
}