This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

sd_ble_gatts_value_set causes a segmentation violation (SIGSEGV)

I'm trying to create a simple service that would just provide some data which could get updated internally (for example, via SPI bus). Data may be of a different size, so I'm trying to notify the device about the change in data buffer by calling sd_ble_gatts_value_set. However, I get a SIGSEGV when I call that function. Here's how I set up a service:

ble_uuid_t ble_uuid;

ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t attr_md;
ble_gatts_attr_t attr_char_value;
...
char_md.char_props.read = 1;
char_md.char_props.write = 0;
char_md.char_props.notify = 0;

BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;

attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = 1;
attr_char_value.init_offs = 0;
attr_char_value.max_len = 256;
attr_char_value.p_value = data; // data is a pointer to the buffer

err_code = sd_ble_gatts_characteristic_add(
p_service->service_handle,
&char_md, &attr_char_value,
&p_service->char_handle
);

VERIFY_SUCCESS(err_code);

I tried setting attr_md.vloc to either BLE_GATTS_VLOC_STACK or BLE_GATTS_VLOC_USER, depending on whether I was allocating arrays on stack or on heap - I have tried both, with both using malloc and nrf_malloc.
Then I change a data in the buffer and I would like to update the length of the data:

ble_gatts_value_t value_md = {
.len = length, // length is passed to the function
.offset = 0,
.p_value = NULL
};
err_code = sd_ble_gatts_value_set(
BLE_CONN_HANDLE_INVALID,
p_service->char_handles.value_handle,
&value_md
);
VERIFY_SUCCESS(err_code);

return NRF_SUCCESS

I suspect I have some issues with allocating my buffers, or I don't understand something about what data exactly is in the Characteristic, because when I try to just change the first byte of the data array in the code after I have created the service and characteristics, I don't see an update in the nRF Connect app, but if I set it beforehand, I can see it.

Please tell me if I can provide any other code snippets or sdk configuration information if that would help you help me solve this problem. My SDK version is 7.0.1.

Thanks in advance for all suggestions.

Parents
  • Hello,

    What does

    sd_ble_gatts_characteristic_add() and sd_ble_gatts_value_set() return?

    Until you get this up and running, I suggest you stick to BLE_GATTS_VLOC_STACK.

    Have you checked any of the examples in the SDK how they set up and use the softdevice to send notifications? Check out the ble_app_uart example.

    What does the SIGSEGV look like?

    BR,

    Edvin

  • Hello,

    sd_ble_gatts_characteristic_add() returns NRF_SUCCESS, as (hopefully) confirmed by VERIFY_SUCCESS macro.

    sd_ble_gatts_value_set() does not return any value - SIGSEGV occurs during the call to it. I can't get much information from backtrack (stuck is corrupted), but looking at the addresses I could make a guess that those belong to the softdevice code:

    238 ble_gatts_value_t value_md = {
    (gdb) n
    243 err_code = sd_ble_gatts_value_set(
    (gdb) n
    
    Program received signal SIGSEGV, Segmentation fault.
    0x0001521a in ?? ()
    (gdb) bt
    #0 0x0001521a in ?? ()
    #1 0x000151ea in ?? ()
    Backtrace stopped: previous frame identical to this frame (corrupt stack?)


    Here is buffer allocation on the stack:

    (gdb) p &buffer
    $2 = (uint8_t (*)[256]) 0x2000fef4

    And when I look at corrupted stack, I get this:

    (gdb) info frame
    Stack level 0, frame at 0x2000fd78:
    pc = 0x1521a; saved pc = 0x151ea
    called by frame at 0x2000fd78
    Arglist at 0x2000fd78, args:
    Locals at 0x2000fd78, Previous frame's sp is 0x2000fd78


    I also made sure to increase the stack size in my Makefile;

    nrf52832_xxaa: CFLAGS += -D__HEAP_SIZE=16384
    nrf52832_xxaa: CFLAGS += -D__STACK_SIZE=16384
    nrf52832_xxaa: ASMFLAGS += -D__HEAP_SIZE=16384
    nrf52832_xxaa: ASMFLAGS += -D__STACK_SIZE=16384


    I will look into some examples, but for now I hope this would help you make a guess about the issue.
    Thanks.

     

  • Yes, the strange thing is that the bug doesn't present itself during normal execution. I have set a break point on the `update_data_characteristic` function, then I execute it step by step and on `sd_ble_gatts_value_set` call I get a segfault.

    Unfortunately I don't have a Segger debugging device, I use SWD-compatible debugger and debug using GDB.

  • Edvin, I apologize for misinformation. I assumed  that with disabled optimizations GDB would at least step onto VERIFY_SUCCESS macro before throwing out SIGSEGV, but after I looked into the example I listed above and added a simple print for a err_code after the function call, it seems that `sd_ble_gatts_value_set` function returns with an error 0x10, which I assume is NRF_ERROR_INVALID_ADDR , which means, according to the function documentation, that I have supplied invalid pointer. I, however, don't know which one of the pointers is invalid. Could you please help me understand why my function call is wrong?

  • So it is update_data_characteristic() that returns NRF_ERROR_INVALID_ADDR, right?

    Again, I didn't get any errors when running your application, but I am not sure of the workflow in your application.

    A while ago, I modified the ble_app_uart example to use sd_ble_gatts_value_set() a while ago. I copied the function ble_nus_data_send() (copied and renamed it ble_nus_data_set).

    I suggest you check out the attached project. 

    I am not sure I approve your implementation of your service's initialization and update function. It may work, but it is very different from the examples. Perhaps you can check out the attached project. Unzip it next to the ble_app_uart example. The pca10040\s132\gcc project should compile without modifications.

    ble_app_uart_set.zip

  • So it is update_data_characteristic() that returns NRF_ERROR_INVALID_ADDR, right?



    No, not quite. Within this function I call sd_ble_gatts_value_set , and it's result is NRF_ERROR_INVALID_ADDR.

    I used to check the result of call to sd_ble_gatts_value_set with VERIFY_SUCCESS macro, but then I replaced it with a simple check, and now I can see error. For some reason my GDB wasn't stepping on the VERIFY_SUCCESS macro, immediately throwing the SIGSEGV error.

    Thank you for the example, I will check it out asap.

  • Edvin, I believe I have solved the issue. Reading ble_gatts_value_t Struct Reference carefully, I have noticed the following:

    If value is stored in user memory, only the attribute length is updated when p_value == NULL.

    However, in my case, buffer is stored on the stack. So when I passed the pointer to the buffer to the sd_ble_gatts_value_set , it returns no error, and I can see modified value in the Nordic Connect application.

    Thanks for your help with troubleshooting.

Reply Children
No Data
Related