Memory break

Hello!
I have a question about the work of nRF52 with memory, why does it work so crookedly?

The first situation.
We have a static void nus_data_handler (ble_nus_evt_t * p_evt) function that takes a buffer. I have a structure for the buffer, I declare an instance
ble_buffer *received_data;

Then miracles begin. If I copy the buffer like this
received_data = p_evt->params.rx_data.p_data;
then everything works well, but on this line I get a warning:

assignment to 'ble_buffer *' {aka 'struct <anonymous> *'} from incompatible pointer type 'const uint8_t *' {aka 'const unsigned char *'} [-Wincompatible-pointer-types]

If I copy the buffer to my struct instance otherwise
memcpy(&received_data,p_evt->params.rx_data.p_data,p_evt->params.rx_data.length);  

Then I fall out:

------------------------------------------------------------------------

The second situation.

uint32_t addr;
addr = 0xFFFFFFFF & NRF_FICR->DEVICEADDR[0];

And it seems okay, this is how the code works. But if you add next
NRF_LOG_HEXDUMP_DEBUG(addr, sizeof(addr)); 
Then I fall out again :(
As far as I understand, in both cases the memory access functions conflict with the softdevice policy or am I wrong?

Top Replies

  • Hi,

    We have a static void nus_data_handler (ble_nus_evt_t * p_evt) function that takes a buffer. I have a structure for the buffer, I declare an instance
    ble_buffer *received_data;

    You have…

  • Are you saying that this approach to writing code is wrong? Would it be more correct to declare an instance of the structure and copy data into it via memcpy? Or is this option possible but…
  • Hi,

    We have a static void nus_data_handler (ble_nus_evt_t * p_evt) function that takes a buffer. I have a structure for the buffer, I declare an instance
    ble_buffer *received_data;

    You have declared a pointer to some ble_buffer structure (if you didn't set it to real structure somewhere later, it's a NULL pointer). If you need a structure space here, declare ble_buffer without *.

    Then miracles begin. If I copy the buffer like this
    received_data = p_evt->params.rx_data.p_data;

    Here you're not copying the buffer, you're setting your pointer to the buffer passed by an event (that will likely be replaced with new data when you don't expect that).

    If I copy the buffer to my struct instance otherwise
    memcpy(&received_data,p_evt->params.rx_data.p_data,p_evt->params.rx_data.length);  

    Again, this will work if received_data is a structure, not pointer.

    And it seems okay, this is how the code works. But if you add next
    NRF_LOG_HEXDUMP_DEBUG(addr, sizeof(addr)); 

    First parameter should be a pointer to buffer that you want to dump, in your case &addr.

  • Thanks. This largely clarified the erroneousness of my actions.

    Here you're not copying the buffer, you're setting your pointer to the buffer passed by an event (that will likely be replaced with new data when you don't expect that).

    Are you saying that this approach to writing code is wrong? Would it be more correct to declare an instance of the structure and copy data into it via memcpy? Or is this option possible but in other use cases?

    Can you tell me how to prevent such errors by means of SDK or to make compilation harder in Segger Studio in order to reveal more warnings?

  • Are you saying that this approach to writing code is wrong? Would it be more correct to declare an instance of the structure and copy data into it via memcpy? Or is this option possible but in other use cases?

    Generally, if a callback passes a pointer to some buffer (that is not own by you), the right way is to make a copy of that data into your memory. For nus_data_handler case, p_evt will point to a buffer with event data returned by SoftDevice. If you store this pointer and try to use it later, it's likely that a next SoftDevice event have already overwrite that buffer.

    Can you tell me how to prevent such errors by means of SDK or to make compilation harder in Segger Studio in order to reveal more warnings?

    I don't use Segger Studio, but there should be an option "Enable all warnings" or something like in project options. Using memcpy/memmove/memset is a pain - the compiler doesn't know anything about memory passed to them and allows any type of pointer to be casted to void*, so you should check twice every parameter you pass to them.

Related