c-使用sscanf读取字符串缓冲区



我有一个TCP服务器,通过标准TCP套接字传输JSON格式的字符串。消息包括:| JSON对象的长度| JSON对象|

在客户端上,我需要获取此消息并对其进行解析。因此,首先我使用sscanf提取长度,移动指针sscanf的字节,并提取JSON消息。目前,我被困在sscanf部分,在试图从字符串缓冲区提取整数值时,出现了"地址越界"错误。

为什么会发生这种情况?请帮忙。

static void * oom_collect_xcvr_data_thread(void *arg)
{
int offset = 0;
int recv_len, data_size;
char *recv_buf = NULL;
json_t *json_obj = NULL;
json_error_t j_error;
recv_buf = calloc(OOM_BUF_SIZE, 1);
CASSERT(recv_buf != NULL);
while(1)
{
if((recv_len = recv(sock_fd, recv_buf, OOM_BUF_SIZE, 0)) <= 0)
{
printf("server connect: tcp receive error %s", strerror(errno));
free(recv_buf);
CASSERT(0);
}
while(offset < recv_len)
{
offset += sscanf(recv_buf + offset, "%d n", &data_size);
if ((json_obj = json_loadb(recv_buf + offset, data_size, 0, &j_error)) == NULL)
{
printf("line: %d, column: %d, position: %d, source: %s, Error: %s"
,j_error.line, j_error.column, j_error.position, j_error.source, j_error.text); 
}
offset += data_size;
copy_xcvr_info(json_obj);
}
CASSERT(offset == recv_len);
offset = 0;
}
}

我试图解析的字符串数据:

1905{"静态":{"RX_POWER_HIGH_ALARM":2.5,"LENGTH_SMF":10000,"update_timestamp":251739.961,"编码":6,"ENHANCED_OPTIONS":240,"LENGTH_SMF_KM":10000,"TX_POWER_LOW_ALARM":-8.0,"连接器":7,"DIAGNOSTIC_MONITORING_TYPE":104,"TRANSCEIVER_EXT":0,"VENDOR_PN":"FTLX1471D3BCL","RX_POWER_LOW_WARN":-18.01,"波长":1310,"选项":"001a","LENGTH_OM4_OR_CU":0,"TEMP_HIGH_WARN":73.0,"TEMP_LOW_ALARM":-13.0,"BR_NOMINAL":10300,"VOLTAGE_LOW_ALARM":2.9,"BIAS_HIGH_ALARM":85.0,"LENGTH_62_5UM":0,"VOLTAGE_LOW_WARN":3.0,"RATE_IDENTIFIER":0,"BIAS_LOW_ALARM":15.0,"VENDOR_OUI":"009065","BIAS_LOW_WARN":20.0,"CABLE_SPEC":"0000","TX_POWER_HIGH_WARN":1.0,"EXT_IDENTIFIER":4,"update_count":1,"VENDOR_SN":"UK70M7N","VOLTAGE_HIGH_ALARM":3.7,"TX_POWER_HIGH_ALARM":2.0,"标识符":3,"LENGTH_OM3":0,"BR_MIN":10300,"TEMP_HIGH_ALARM":78.0,"SFF_8472_COMPLIANCE":3,"RX_POWER_LOW_ALARM":-20.0,"VOLTAGE_HIGH_WARN":3.6,"BIAS_HIGH_WARN":80.0,"收发器":"2000000000000000","LENGTH_50UM":0,"TX_POWER_LOW_WARN":-7.0,"VENDOR_REV":"A","DATE_CODE":"110212","RX_POWER_HIGH_WARN":2.0,"VENDOR_NAME":"FINISAR CORP.","BR_MAX":10300,"TEMP_LOW_WARN":-8.0},"端口名称":"端口18","port_type":"SFP","动态":{"L_TX_POWER_WARN":0,"update_timestamp":253134.25,"L_TX_POWER_ALARM":0,"TX_POWER":0.68,"L_RX_POWER_ALARM":0,"DATA_READY_BAR_STATE":0,"RS_1_STATE":0,"TX_DISABLE_STATE":0,"L_TEMP_WARN":0,"L_VCC_ALARM":0,"L_ALARM_WARN":"000000000000","SOFT_RATE_SELECT":0,"TX_FAULT_STATE":0,"L_TEMP_ALARM":0,"TX_POWER_DBM":-1.68,"VCC":3.41,"温度":32.99,"TX_BIAS":37.19,"STATUS_CONTROL":0,"L_BIAS_ALARM":0,"RX_LOS_STATE":0,"OPT_LASER_TEMP":0.0,"L_BIAS_WARN":0,"RX_POWER_DBM":-1.28,"SOFT_TX_DISABLE_SELECT":0,"L_RX_POWER_WARN":0,"OPT_TEC":0.0,"RX_POWER":0.75,"L_VCC_WARN":0,"RATE_SELECT_STATE":0}}

gdb错误消息:

Program received signal SIGSEGV, Segmentation fault.
rawmemchr () at ../sysdeps/i386/rawmemchr.S:70
70      ../sysdeps/i386/rawmemchr.S: No such file or directory.
(gdb) bt
#0  rawmemchr () at ../sysdeps/i386/rawmemchr.S:70
#1  0xf63de127 in _IO_str_init_static_internal (sf=0xee807838, ptr=0x969d046 <Address 0x969d046 out of bounds>, size=157929542, pstart=0x0) at strops.c:45
#2  0xf63d1c43 in _IO_vsscanf (string=0x969d046 <Address 0x969d046 out of bounds>, format=0x80d5fb7 "%d n", args=0xee807908 "260202200356") at iovsscanf.c:44
#3  0xf63bf59b in __sscanf (s=0x969d046 <Address 0x969d046 out of bounds>, format=0x80d5fb7 "%d n") at sscanf.c:34
#4  0x08091013 in oom_collect_xcvr_data_thread (arg=0x0) at /home/sfreeman/wspace/swapp/src/interface/agent/ia_l2.c:172
#5  0xf730f954 in start_thread (arg=0xee808b70) at pthread_create.c:304
#6  0xf644295e in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:130

sscanf在接收缓冲区已满且未以0结束时导致SIGSEGV。您需要确保接收到的数据以0终止,例如:

recv_len = recv(sock_fd, recv_buf, OOM_BUF_SIZE - 1, 0);
if(recv_len > 0) {
recv_buf[recv_len] = 0;
}
else {
// Handle disconnect or error.
}

我还发现了以下错误:

  • 该代码无法处理部分消息
  • sscanf返回分配的项目数,而不是像代码所期望的那样返回消耗的字节数
  • 不检查sscanf返回值是否存在错误
  • 没有检查是否已收到完整的号码。sscanf格式的" n"与0长度的字符串匹配,这与代码所期望的相反

需要完整阅读sscanf手册页才能正确使用。

最新更新