一. 问题
- 用whs_hal_test测试稳定复现一次hardfault
分析
- 死机直接原因
执行vldr.32 s0,[r2]
将r2寄存器内容读到s0
对应代码就是*(float*)offset
static sns_rc
sns_health_offload_set_metric_offset(sns_sensor *const this,
sns_metric_tracker_t* metric_tracker,
void const* offset,
size_t offset_len)
offset参数是void const* offset. 传入的是float值
强转float* 取值,看起来很正常的调用,而且r2地址也是合法地址.
- 查看system_ns.per
发现有处错误,叫
Unaligned access error.
未对齐访问
offset地址在main heap中但是没有4byte对齐
修改sns main heap定义加上attribute((aligned(4)));
发现也是对不齐
pb_buffer_arg sensor_config = {NULL,0};
pb_buffer_arg req_payload = {NULL,0};
pb_buffer_arg data_payload = {NULL,0};
sns_health_request offload_req =
{
.msg_id = _sns_health_request_type_MIN,
.sensor_config_data = {
.funcs.decode = pb_decode_string_cb,
.arg = &sensor_config,
},
.req_payload = {
.funcs.decode = pb_decode_string_cb,
.arg = &req_payload,
},
.data = {
.value_type = _sns_health_value_type_MIN,
.data = {
.funcs.decode = pb_decode_string_cb,
.arg = &data_payload,
},
}
};
pb_simple_cb_arg arg =
{
.decoded_struct = &offload_req,
.fields = sns_health_request_fields,
};
sns_std_request decoded_request = sns_std_request_init_default;
decoded_request.payload = (struct pb_callback_s)
{
.funcs.decode = &pb_decode_simple_cb,
.arg = &arg,
};
这个地址是通过nanopb decode来填充的.
不排除是nanopb的bug所致.
解决
- 验证情况, 未对齐的地址,强转uint32类型时不会导致unaligned error
对应的汇编是
*(uint32_t *)goal_threshold;
ldr r3,[r10]
可能是未使用到浮点寄存器
- 只有强转float型才会
*(float *)goal_threshold;
vldr.32 s0,[r10]
使用到了 s0 寄存器
vldr会触发不对齐错误
- 暂时规避方法,在decode出payload数据后,用本地临时变量再memcpy一次,使地址对齐.
#if 0
req_data = offload_req->data.data.arg;
rc = sns_health_offload_set_metric_offset( this, metric_tracker,
req_data->buf, req_data->buf_len ); //buf地址未对齐,导致强转float* 会crash
#else
req_data = offload_req->data.data.arg;
if(req_data->buf_len != sizeof(uint32_t))
{
rc = SNS_RC_INVALID_VALUE;
}else
{
uint8_t buffer[sizeof(uint32_t)]={0};
sns_memscpy(buffer,sizeof(uint32_t),req_data->buf,req_data->buf_len); //memcpy一次再传参
rc = sns_health_offload_set_metric_offset( this, metric_tracker,
buffer, sizeof(uint32_t) );
}
#endif