When creating an attribute specifying vloc as BLE_GATTS_VLOC_USER, it is not very clear that a storage pointer must be provided on creation of the attribute and cannot be changed throughout the lifetime of the attribute.
If creating an attribute with vloc = BLE_GATTS_VLOC_USER, a non-zero max_len and a NULL p_value no error is returned, this is perhaps a bug as read requests will then return garbage.
This also includes characteristics which are read only and use authorise read. I assumed when creating such a characteristic that it would use the data pointer I provide in sd_ble_gatts_rw_authorize_reply when sending the data, but it seems that it always copies the data to the pointer specified at attribute creation before sending using the attribute's pointer. I think this could be made more clear in the documentation.