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;
uint16_t pos;
uint16_t i;
uint16_t asdu_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_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;
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,
*(float *)&p_asdu->data[pos]);
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;
uint16_t pos;
uint16_t i;
uint16_t asdu_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_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;
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_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;
uint16_t pos;
uint16_t i;
uint16_t asdu_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_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;
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,
*(float *)&p_asdu->data[pos]);
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)
{
if (!n)
if (!d || !n)
{
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)
{
if (!n)
if (!d || !n)
{
return 0xFFFFFFFF;
}

View File

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

View File

@ -1000,29 +1000,35 @@ void *app_modbus_m(void *arg)
while (1)
{
task_event_recv(p_app->p_event,
0x01 | 0x02 | 0x04,
0x02 | 0x04,
EV_TIMER1 | EV_TIMER2 | EV_TIMER3,
TASK_EVENT_FLAG_OR | TASK_EVENT_FLAG_CLEAR,
TASK_EVENT_WAIT_FOREVER,
&event);
if(event & 0x01)
if(event & EV_TIMER1)
{
// 处理写请求队列
// 处理写请求队列 (10ms)
process_write_queue();
}
if(event & 0x02)
if(event & EV_TIMER2)
{
// 轮询遥信100ms
// 轮询遥信 (100ms)
poll_groups(st_groups);
}
if(event & 0x04)
if(event & EV_TIMER3)
{
// 轮询遥测/参数1000ms
// 轮询遥测/参数 (1000ms)
poll_groups(mx_groups);
p_app->run_cnt++;
}
if(EV_STOP & event)
{
LOG_I("app_modbus_m: received EV_STOP, exiting");
break;
}
}
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->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;
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);
}
/* 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)
{
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 valid_len = 0;
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)
{
@ -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);
/* 锁住读取 */
/* 一次持锁: ICP67 帧处理 + IEC 帧快照, 避免竞态 */
pthread_mutex_lock(&ring->mutex);
/* ICP67 帧搜索: 直接从环形缓冲读取, 零拷贝 */
while(0 == icp67_search_frame_in_ring(ring->buf, ring->size,
ring->rptr, ring->cnt, &pos, &valid_len))
{
/* 解码: 帧跨环边界时需临时拷贝 */
uint8_t frame_buf[ICP67_TX_BUF_SIZE];
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);
/* 滑窗: advance ring pointer */
/* 滑窗 */
pos += valid_len;
ring->cnt -= pos;
ring->rptr = (ring->rptr + pos) % ring->size;
pos = 0;
}
/* IEC-104 帧快照 (持锁下拷贝完整剩余数据) */
get_rx_data_locked(ring, iec_buf, &iec_buf_len);
pthread_mutex_unlock(&ring->mutex);
/* IEC-104 帧: 需要读取字节序列, 做一次全量拷贝 */
/* IEC-104 帧搜索 (锁外执行, 操作快照数据) */
if(iec_buf_len > 0)
{
uint8_t buf[SELF_PTL_BUF_SIZE];
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))
if(0 == self_ptl_search_iec_frame(iec_buf, iec_buf_len, &pos, &valid_len))
{
LOG_I("self_ptl: found IEC-104 frame at pos=%d, len=%d", pos, valid_len);
/* TODO: 将 IEC-104 帧转发到 libiec 解码模块 (待实现) */
@ -627,6 +656,13 @@ void *app_self_ptl(void *arg)
{
p_app->run_cnt++;
}
/* EV_STOP: 优雅退出 */
if(EV_STOP & event)
{
LOG_I("app_self_ptl: received EV_STOP, exiting");
break;
}
}
return NULL;