Reputation: 2038
I have a TCP server transmitting JSON formatted strings over a standard TCP socket. The message consists of :| length of JSON object | JSON object |
On the client I need to take this message and parse it. So first I extract the length using sscanf, move the pointer sscanf'ed bytes, and extract the JSON message. Currently I'm stuck at the sscanf part, and get an "address out of bounds" error while trying to extract integer value from the string buffer.
Why does this happen? please help.
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;
}
}
String data I'm trying to parse:
1905 { "static":{ "RX_POWER_HIGH_ALARM":2.5, "LENGTH_SMF":10000, "update_timestamp":251739.961, "ENCODING":6, "ENHANCED_OPTIONS":240, "LENGTH_SMF_KM":10000, "TX_POWER_LOW_ALARM":-8.0, "CONNECTOR":7, "DIAGNOSTIC_MONITORING_TYPE":104, "TRANSCEIVER_EXT":0, "VENDOR_PN":"FTLX1471D3BCL", "RX_POWER_LOW_WARN":-18.01, "WAVELENGTH":1310, "OPTIONS":"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, "IDENTIFIER":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, "TRANSCEIVER":"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 }, "port_name":"port18", "port_type":"SFP", "dynamic":{ "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, "TEMPERATURE":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 error message:
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 "\260\202\200\356") 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
Upvotes: 0
Views: 632
Reputation: 136415
sscanf
causes SIGSEGV
when the receive buffer is full and doesn't end with 0. You need to ensure the received data is terminated with 0, e.g.:
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.
}
I also spotted the following errors:
sscanf
returns the number of items assigned, not the number of consumed bytes, like the code expects.sscanf
return value for errors.sscanf
format " \n"
matches 0-length string, contrary to what the code expects.Reading sscanf
man page in its entirety is required to be able to use it correctly.
Upvotes: 2