9.7 cbExiGen库bug及改进
上一节作者改进了cjson库,成功的支持64位整数的解析和输出,但是在测试SessionSetupRes命令时,发现解码输出的时间戳仍然是乱码,说明 cbExigen库代码存在解码错误。本节作者分析了bug原因,提出了修改方案。 同时在github上提交这个bug,官方已经接受并且修复啦。
测试数据:
充电桩ISO15118-2协议的SessionSetupRes命令实例: 我故意把时间戳数据写成了这么长19位。
{
"V2G_Message": {
"Header": {
"SessionID": "C08CDF36985A7190"
},
"Body": {
"SessionSetupRes": {
"ResponseCode": "OK_NewSessionEstablished",
"EVSEID": "UK123E1234",
"EVSETimeStamp": 1234567890123456789
}
}
}
}
该命令对应的schema规范中定义了EVSETimeStamp的具体类型位long,因此必须要用到int64类型解析。
<xs:element name="EVSETimeStamp" type="xs:long" minOccurs="0"/>
代码运行后编码成功,解码成功,但是解码后的EVSETimeStamp并不是1234567890123456789,明显的是一个乱数字,长度也被截断了。怀疑是内部解码错误,跟踪代码发现了错误位置和原因。
代码:exi_basetypes.c, 把字节数组转换成64位长整数
int exi_basetypes_convert_64_from_unsigned(exi_unsigned_t* exi_unsigned, uint64_t* value)
{
if (exi_unsigned->octets_count > EXI_BASETYPES_UINT64_MAX_OCTETS)
{
return EXI_ERROR__OCTET_COUNT_LARGER_THAN_TYPE_SUPPORTS;
}
uint8_t* current_octet = exi_unsigned->octets;
*value = 0;
for (size_t n = 0; n < exi_unsigned->octets_count; n++)
{ //fix bug: overflow of int, Forced Typecasting to uint64_t, Tom.hongtao.gao
*value = (uint64_t)(*value + ((*current_octet & EXI_BASETYPES_OCTET_SEQ_VALUE_MASK) << (n * 7)));
current_octet++;
}
return EXI_ERROR__NO_ERROR;
}
上面转换思路:
每个字节去除最高位,然后左移7位,累加求和。
循环读取每个字节,直到数组结束。这样最后的和就是长整型数。
【错误原因】:在移位操作时,左边的操作数 (*current_octet & EXI_BASETYPES_OCTET_SEQ_VALUE_MASK) 默认类型是int类型,当连续操作到第6个字节时,该数字已经连续左移36位了,已经超过了32位整数的范围了,所以发生整数溢出。
【解决方法】:对移位的操作数强制类型转换,添加(uint64_t) 解决了溢出问题。
for (size_t n = 0; n < exi_unsigned->octets_count; n++)
{ //fix bug: overflow of int, Forced Typecasting to uint64_t, Tom.hongtao.gao
//*value = (uint64_t)(*value + ((*current_octet & EXI_BASETYPES_OCTET_SEQ_VALUE_MASK) << (n * 7)));
*value = (uint64_t)(*value + ((uint64_t)(*current_octet & EXI_BASETYPES_OCTET_SEQ_VALUE_MASK) << (n * 7)));
current_octet++;
}
之后再用代码测试OK,解码出的数据能正确显示出1234567890123456789这个数字了。
json格式化后:
{
"V2G_Message": {
"Header": {
"SessionID": "C08CDF36985A7190"
},
"Body": {
"SessionSetupRes": {
"ResponseCode": "OK_NewSessionEstablished",
"EVSEID": "UK123E1234",
"EVSETimeStamp": 1234567890123456789
}
}
}
}
lret = 0, timeStamp=1234567890123456789
1111 SessionSetupRes.EVSETimeStamp=1234567890123456789
ret1= 0
stream.byte_pos =34
dataRes (35 bytes):
+------------------------------------------------------------------------------+
| Offset : 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF |
+------------------------------------------------------------------------------+
| 00000000: 80 98 02 30 23 37 CD A6 16 9C 64 11 E0 20 31 55 ...0#7....d.. 1U |
| 00000010: 2C C4 C8 CD 14 C4 C8 CC D0 12 B0 54 DD F8 F3 D0 ,..........T.... |
| 00000020: 92 22 20 ." |
+------------------------------------------------------------------------------+
ret2= 0
2222, timeStamp=1234567890123456789
root: {
"V2G_Message": {
"Header": {
"SessionID": "C08CDF36985A7190"
},
"Body": {
"SessionSetupRes": {
"ResponseCode": "OK_NewSessionEstablished",
"EVSEID": "UK123E1234",
"EVSETimeStamp": 1234567890123456789
}
}
}
}
tom@Tom-Hongtao:/mnt/c/e/codes/cbexigen-TestFrame$