fix: 分模块代码审查 — 修复 11 个 Critical/Important bugs

系统模块 (8项):
- self_ptl: 修复环形缓冲区溢出逻辑
- self_ptl: 消除 search_frame 竞态条件
- self_ptl: 分离 get_rx_data_locked 避免锁间竞态
- self_ptl/com_router/modbus_m: 添加 EV_STOP 优雅退出
- com_router: 修复 last_state 重复定义 bug
- modbus_m: 修复 EV_TIMERx 裸魔数 + task_event_recv flags 错误

协议模块 (2项):
- icp67: TI_200/201/202 添加 ASDU 边界检查

公共基础库 (1项):
- libfunc: func_cal_crc16/crc32 添加 NULL 指针检查
This commit is contained in:
ypc 2026-07-10 10:21:28 +08:00
parent 0409f427aa
commit 9560ea7653
5 changed files with 116 additions and 27 deletions

View File

@ -654,6 +654,7 @@ static int icp67_decode_ti_200(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_l
stru_ti_200_201_202 *p_asdu; stru_ti_200_201_202 *p_asdu;
uint16_t pos; uint16_t pos;
uint16_t i; uint16_t i;
uint16_t asdu_len;
if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len) if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
{ {
@ -664,9 +665,21 @@ static int icp67_decode_ti_200(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_l
p_head = (stru_head *)p_rx; p_head = (stru_head *)p_rx;
p_asdu = (stru_ti_200_201_202 *)p_head->data; p_asdu = (stru_ti_200_201_202 *)p_head->data;
if(rx_len < ICP67_FRAME_OVERHEAD)
{
LOG_E("icp67_decode_ti_200: frame too short");
return -1;
}
asdu_len = (uint16_t)(rx_len - ICP67_FRAME_OVERHEAD);
pos = 0; pos = 0;
for(i = 0; p_icp67->method.mx_trans_cb && i < p_asdu->num; i++) for(i = 0; p_icp67->method.mx_trans_cb && i < p_asdu->num; i++)
{ {
if(pos + sizeof(float) > asdu_len)
{
LOG_E("icp67_decode_ti_200: data overflow, num=%d, pos=%d", p_asdu->num, pos);
break;
}
p_icp67->method.mx_trans_cb(p_icp67, p_asdu->addr + i, p_icp67->method.mx_trans_cb(p_icp67, p_asdu->addr + i,
*(float *)&p_asdu->data[pos]); *(float *)&p_asdu->data[pos]);
pos += sizeof(float); pos += sizeof(float);
@ -683,6 +696,7 @@ static int icp67_decode_ti_201(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_l
stru_ti_200_201_202 *p_asdu; stru_ti_200_201_202 *p_asdu;
uint16_t pos; uint16_t pos;
uint16_t i; uint16_t i;
uint16_t asdu_len;
if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len) if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
{ {
@ -693,9 +707,21 @@ static int icp67_decode_ti_201(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_l
p_head = (stru_head *)p_rx; p_head = (stru_head *)p_rx;
p_asdu = (stru_ti_200_201_202 *)p_head->data; p_asdu = (stru_ti_200_201_202 *)p_head->data;
if(rx_len < ICP67_FRAME_OVERHEAD)
{
LOG_E("icp67_decode_ti_201: frame too short");
return -1;
}
asdu_len = (uint16_t)(rx_len - ICP67_FRAME_OVERHEAD);
pos = 0; pos = 0;
for(i = 0; p_icp67->method.st_trans_cb && i < p_asdu->num; i++) for(i = 0; p_icp67->method.st_trans_cb && i < p_asdu->num; i++)
{ {
if(pos + 1 > asdu_len)
{
LOG_E("icp67_decode_ti_201: data overflow, num=%d, pos=%d", p_asdu->num, pos);
break;
}
p_icp67->method.st_trans_cb(p_icp67, p_asdu->addr + i, p_icp67->method.st_trans_cb(p_icp67, p_asdu->addr + i,
p_asdu->data[pos++]); p_asdu->data[pos++]);
} }
@ -711,6 +737,7 @@ static int icp67_decode_ti_202(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_l
stru_ti_200_201_202 *p_asdu; stru_ti_200_201_202 *p_asdu;
uint16_t pos; uint16_t pos;
uint16_t i; uint16_t i;
uint16_t asdu_len;
if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len) if(NULL == p_icp67 || NULL == p_rx || 0 == rx_len)
{ {
@ -721,9 +748,21 @@ static int icp67_decode_ti_202(stru_icp67 *p_icp67, uint8_t *p_rx, uint16_t rx_l
p_head = (stru_head *)p_rx; p_head = (stru_head *)p_rx;
p_asdu = (stru_ti_200_201_202 *)p_head->data; p_asdu = (stru_ti_200_201_202 *)p_head->data;
if(rx_len < ICP67_FRAME_OVERHEAD)
{
LOG_E("icp67_decode_ti_202: frame too short");
return -1;
}
asdu_len = (uint16_t)(rx_len - ICP67_FRAME_OVERHEAD);
pos = 0; pos = 0;
for(i = 0; p_icp67->method.dd_trans_cb && i < p_asdu->num; i++) for(i = 0; p_icp67->method.dd_trans_cb && i < p_asdu->num; i++)
{ {
if(pos + sizeof(float) > asdu_len)
{
LOG_E("icp67_decode_ti_202: data overflow, num=%d, pos=%d", p_asdu->num, pos);
break;
}
p_icp67->method.dd_trans_cb(p_icp67, p_asdu->addr + i, p_icp67->method.dd_trans_cb(p_icp67, p_asdu->addr + i,
*(float *)&p_asdu->data[pos]); *(float *)&p_asdu->data[pos]);
pos += sizeof(float); pos += sizeof(float);

View File

@ -107,7 +107,7 @@ uint16_t func_cal_sum_word(const uint8_t *d, uint32_t n)
uint16_t func_cal_crc16(const uint8_t *d, uint32_t n) uint16_t func_cal_crc16(const uint8_t *d, uint32_t n)
{ {
if (!n) if (!d || !n)
{ {
return 0xFFFF; return 0xFFFF;
} }
@ -124,7 +124,7 @@ uint16_t func_cal_crc16(const uint8_t *d, uint32_t n)
uint32_t func_cal_crc32(const uint8_t *d, uint32_t n) uint32_t func_cal_crc32(const uint8_t *d, uint32_t n)
{ {
if (!n) if (!d || !n)
{ {
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }

View File

@ -565,6 +565,7 @@ void *app_com_router(void *arg)
* socket_fd, * socket_fd,
* *
*/ */
static int last_state[MAX_CHANNELS];
int i; int i;
for(i = 0; i < g_channel_count; i++) for(i = 0; i < g_channel_count; i++)
@ -574,8 +575,6 @@ void *app_com_router(void *arg)
if(ch->socket_fd < 0) if(ch->socket_fd < 0)
{ {
/* 已断开, 仅第一次打印 */ /* 已断开, 仅第一次打印 */
static int last_state[MAX_CHANNELS];
if(last_state[i] >= 0) if(last_state[i] >= 0)
{ {
LOG_I("com_router: %s disconnected", ch->key); LOG_I("com_router: %s disconnected", ch->key);
@ -584,7 +583,10 @@ void *app_com_router(void *arg)
} }
else else
{ {
static int last_state[MAX_CHANNELS]; if(last_state[i] <= 0)
{
LOG_I("com_router: %s connected", ch->key);
}
last_state[i] = 1; last_state[i] = 1;
} }
} }
@ -615,6 +617,12 @@ void *app_com_router(void *arg)
{ {
p_app->run_cnt++; p_app->run_cnt++;
} }
if(EV_STOP & event)
{
LOG_I("app_com_router: received EV_STOP, exiting");
break;
}
} }
return NULL; return NULL;

View File

@ -1000,29 +1000,35 @@ void *app_modbus_m(void *arg)
while (1) while (1)
{ {
task_event_recv(p_app->p_event, task_event_recv(p_app->p_event,
0x01 | 0x02 | 0x04, EV_TIMER1 | EV_TIMER2 | EV_TIMER3,
0x02 | 0x04, TASK_EVENT_FLAG_OR | TASK_EVENT_FLAG_CLEAR,
TASK_EVENT_WAIT_FOREVER, TASK_EVENT_WAIT_FOREVER,
&event); &event);
if(event & 0x01) if(event & EV_TIMER1)
{ {
// 处理写请求队列 // 处理写请求队列 (10ms)
process_write_queue(); process_write_queue();
} }
if(event & 0x02) if(event & EV_TIMER2)
{ {
// 轮询遥信100ms // 轮询遥信 (100ms)
poll_groups(st_groups); poll_groups(st_groups);
} }
if(event & 0x04) if(event & EV_TIMER3)
{ {
// 轮询遥测/参数1000ms // 轮询遥测/参数 (1000ms)
poll_groups(mx_groups); poll_groups(mx_groups);
p_app->run_cnt++; p_app->run_cnt++;
} }
if(EV_STOP & event)
{
LOG_I("app_modbus_m: received EV_STOP, exiting");
break;
}
} }
return NULL; return NULL;

View File

@ -132,13 +132,21 @@ static void put_rx_data(stru_self_rx *p_self_rx, uint8_t *p_rx, uint16_t len)
{ {
p_self_rx->buf[p_self_rx->wptr] = p_rx[i]; p_self_rx->buf[p_self_rx->wptr] = p_rx[i];
p_self_rx->wptr = (p_self_rx->wptr + 1) % p_self_rx->size; p_self_rx->wptr = (p_self_rx->wptr + 1) % p_self_rx->size;
p_self_rx->cnt++;
if(p_self_rx->cnt > p_self_rx->size) if(p_self_rx->cnt >= p_self_rx->size)
{ {
p_self_rx->cnt--; /* 环形缓冲区已满: 丢弃最旧字节, 只警告一次 */
static int overflow_warned = 0;
if(!overflow_warned)
{
LOG_E("put_rx_data: ring buffer overflow, dropping old data");
overflow_warned = 1;
}
p_self_rx->rptr = (p_self_rx->rptr + 1) % p_self_rx->size; p_self_rx->rptr = (p_self_rx->rptr + 1) % p_self_rx->size;
LOG_E("put_rx_data overflow, rptr=%d, wptr=%d", p_self_rx->rptr, p_self_rx->wptr); }
else
{
p_self_rx->cnt++;
} }
} }
@ -170,6 +178,27 @@ static void get_rx_data(stru_self_rx *p_self_rx, uint8_t *p_data, uint16_t *p_da
pthread_mutex_unlock(&p_self_rx->mutex); pthread_mutex_unlock(&p_self_rx->mutex);
} }
/* get_rx_data 的无锁版本 (调用者已持锁) */
static void get_rx_data_locked(stru_self_rx *p_self_rx, uint8_t *p_data, uint16_t *p_data_len)
{
uint16_t pos;
uint16_t i;
if(NULL == p_self_rx || NULL == p_data || NULL == p_data_len)
{
return;
}
pos = p_self_rx->rptr;
for(i = 0; i < p_self_rx->cnt; i++)
{
p_data[i] = p_self_rx->buf[pos];
pos = (pos + 1) % p_self_rx->size;
}
(*p_data_len) = p_self_rx->cnt;
}
static void clear_rx_data(stru_self_rx *p_self_rx) static void clear_rx_data(stru_self_rx *p_self_rx)
{ {
if(NULL == p_self_rx) if(NULL == p_self_rx)
@ -341,6 +370,8 @@ static void self_ptl_search_frame(uint8_t *p_rx, uint16_t len, stru_icp67 *p_icp
uint16_t pos = 0; uint16_t pos = 0;
uint16_t valid_len = 0; uint16_t valid_len = 0;
stru_self_rx *ring = &g_self_ptl.icp67_rx; stru_self_rx *ring = &g_self_ptl.icp67_rx;
uint8_t iec_buf[SELF_PTL_BUF_SIZE];
uint16_t iec_buf_len = 0;
if(NULL == p_rx || 0 == len || NULL == p_icp67) if(NULL == p_rx || 0 == len || NULL == p_icp67)
{ {
@ -350,14 +381,13 @@ static void self_ptl_search_frame(uint8_t *p_rx, uint16_t len, stru_icp67 *p_icp
/* 写入环形缓冲区 */ /* 写入环形缓冲区 */
put_rx_data(ring, p_rx, len); put_rx_data(ring, p_rx, len);
/* 锁住读取 */ /* 一次持锁: ICP67 帧处理 + IEC 帧快照, 避免竞态 */
pthread_mutex_lock(&ring->mutex); pthread_mutex_lock(&ring->mutex);
/* ICP67 帧搜索: 直接从环形缓冲读取, 零拷贝 */ /* ICP67 帧搜索: 直接从环形缓冲读取, 零拷贝 */
while(0 == icp67_search_frame_in_ring(ring->buf, ring->size, while(0 == icp67_search_frame_in_ring(ring->buf, ring->size,
ring->rptr, ring->cnt, &pos, &valid_len)) ring->rptr, ring->cnt, &pos, &valid_len))
{ {
/* 解码: 帧跨环边界时需临时拷贝 */
uint8_t frame_buf[ICP67_TX_BUF_SIZE]; uint8_t frame_buf[ICP67_TX_BUF_SIZE];
uint16_t i; uint16_t i;
@ -368,23 +398,22 @@ static void self_ptl_search_frame(uint8_t *p_rx, uint16_t len, stru_icp67 *p_icp
p_icp67->decode_cb(p_icp67, frame_buf, valid_len); p_icp67->decode_cb(p_icp67, frame_buf, valid_len);
/* 滑窗: advance ring pointer */ /* 滑窗 */
pos += valid_len; pos += valid_len;
ring->cnt -= pos; ring->cnt -= pos;
ring->rptr = (ring->rptr + pos) % ring->size; ring->rptr = (ring->rptr + pos) % ring->size;
pos = 0; pos = 0;
} }
/* IEC-104 帧快照 (持锁下拷贝完整剩余数据) */
get_rx_data_locked(ring, iec_buf, &iec_buf_len);
pthread_mutex_unlock(&ring->mutex); pthread_mutex_unlock(&ring->mutex);
/* IEC-104 帧: 需要读取字节序列, 做一次全量拷贝 */ /* IEC-104 帧搜索 (锁外执行, 操作快照数据) */
if(iec_buf_len > 0)
{ {
uint8_t buf[SELF_PTL_BUF_SIZE]; if(0 == self_ptl_search_iec_frame(iec_buf, iec_buf_len, &pos, &valid_len))
uint16_t buf_len = 0;
get_rx_data(ring, buf, &buf_len);
if(0 == self_ptl_search_iec_frame(buf, buf_len, &pos, &valid_len))
{ {
LOG_I("self_ptl: found IEC-104 frame at pos=%d, len=%d", pos, valid_len); LOG_I("self_ptl: found IEC-104 frame at pos=%d, len=%d", pos, valid_len);
/* TODO: 将 IEC-104 帧转发到 libiec 解码模块 (待实现) */ /* TODO: 将 IEC-104 帧转发到 libiec 解码模块 (待实现) */
@ -627,6 +656,13 @@ void *app_self_ptl(void *arg)
{ {
p_app->run_cnt++; p_app->run_cnt++;
} }
/* EV_STOP: 优雅退出 */
if(EV_STOP & event)
{
LOG_I("app_self_ptl: received EV_STOP, exiting");
break;
}
} }
return NULL; return NULL;