/* 回归环: 复现 mqtt_publish 缓冲不足时发出垃圾包, 验证修复 * 忠实复刻 MQTTSerialize_publish 契约 (真源码 MQTTSerializePublish.c L64-68): * 若 MQTTPacket_len(rem) > buflen → 返回 -2 且不写 buf * 相邻内存布局: mqttBuf[N] 之后紧邻 temp_guide[]="report_config" */ #include #include #include static int mqtt_packet_len(int rem) { int n=1,r=rem; while(r>=128){r/=128;n++;} return 1+n+rem; } static int mqtt_pub_serialize(unsigned char *buf, int buflen, int qos, const char *topic, const char *payload, int paylen) { int rem = 2 + (int)strlen(topic) + (qos>0?2:0) + paylen; if (mqtt_packet_len(rem) > buflen) return -2; /* BUFFER_TOO_SHORT, 不写 buf */ int total = mqtt_packet_len(rem); buf[0] = 0x30 | (qos<<1); /* PUBLISH 头 */ memset(buf+1, 0xAB, total-1); /* 标记有效数据(非0) */ return total; } /* 模拟内存: mqttBuf 紧邻 temp_guide */ static unsigned char mem[2048]; #define MQTTBUF_OFF 0 static void layout_reset(int mqttbuf_len) { memset(mem, 0, sizeof(mem)); strcpy((char*)&mem[MQTTBUF_OFF + mqttbuf_len], "report_config"); /* 相邻全局 */ } /* 旧实现: uint32_t len, 无守卫 */ static int old_publish(int mqttbuf_len, const char *payload, int *sent_len, int *type0) { unsigned char *mqttBuf = &mem[MQTTBUF_OFF]; memset(mqttBuf, 0, mqttbuf_len); /* clear_mqtt_buf */ uint32_t len = (uint32_t)mqtt_pub_serialize(mqttBuf, mqttbuf_len, 0, "dld960/DC045A49718F/dev", payload, strlen(payload)); /* WCHNET_SocketSend 发 len 字节 (受 MSS≈576 截断) */ int send = (len > 576) ? 520 : (int)len; /* 天文数字→按段截到~520 */ *sent_len = send; *type0 = (send>0 && mqttBuf[0]==0x00); /* 首字节=0 → 非法 MQTT 类型 */ return (int)len; } /* 新实现: int len + 守卫 + 大缓冲 */ static int new_publish(int mqttbuf_len, const char *payload, int *sent_len, int *type0) { unsigned char *mqttBuf = &mem[MQTTBUF_OFF]; memset(mqttBuf, 0, mqttbuf_len); int len = mqtt_pub_serialize(mqttBuf, mqttbuf_len, 0, "dld960/DC045A49718F/dev", payload, strlen(payload)); if (len <= 0) { *sent_len = 0; *type0 = 0; return len; } /* 守卫: 绝不发残缓冲 */ uint32_t slen = (uint32_t)len; *sent_len = (int)slen; *type0 = (mqttBuf[0]==0x00); return len; } int main(void) { /* 构造 604B 的 loop_data payload (4通道, 与现场同量级) */ char loop[700]; int n=0; n += sprintf(loop+n, "{\"msg_id\":8,\"cmd\":\"loop_data\",\"ts\":373,\"data\":{\"channels\":["); for (int c=1;c<=4;c++) n += sprintf(loop+n, "%s{\"ch\":%d,\"level\":\"mid_high\",\"iscar\":false,\"loop_ok\":true," "\"freq\":61286,\"diff\":-8388608,\"sens\":2,\"cndtn\":0," "\"misc\":{\"type\":\"time\",\"value\":0}}", c>1?",":"", c); n += sprintf(loop+n, "]}}"); printf("loop_data payload = %d B\n", n); int fails=0, sent, t0, rc; /* --- 旧: 512 缓冲 + loop_data → 发垃圾 --- */ layout_reset(512); rc = old_publish(512, loop, &sent, &t0); printf("旧(512): serialize rc=%d, 实发=%dB, 首字节0x00(非法)=%d\n", rc, sent, t0); if (!(rc==-2 && sent>0 && t0==1)) { printf(" 期望复现垃圾包失败\n"); fails++; } else printf(" ✓ 复现: 发出 %dB 全零垃圾包(含相邻report_c), broker必RST\n", sent); /* --- 新守卫: 512 缓冲 + loop_data → 不发 --- */ layout_reset(512); rc = new_publish(512, loop, &sent, &t0); printf("新守卫(512): rc=%d, 实发=%dB\n", rc, sent); if (!(rc==-2 && sent==0)) { printf(" 守卫未生效\n"); fails++; } else printf(" ✓ 守卫拦截: serialize失败→不发送, 连接不被RST\n"); /* --- 新: 1024 缓冲 + loop_data → 正常发 --- */ layout_reset(1024); rc = new_publish(1024, loop, &sent, &t0); printf("新(1024): rc=%d, 实发=%dB, 首字节合法(非0)=%d\n", rc, sent, !t0); if (!(rc>0 && sent==rc && t0==0)) { printf(" 1024缓冲仍异常\n"); fails++; } else printf(" ✓ 604B报文正常序列化并发送 (TCP自动分段, MQTT不关心段边界)\n"); /* --- 回归: report_config(216B) 在两版都正常 --- */ const char *cfg = "{\"msg_id\":131,\"cmd\":\"report_config\",\"ts\":373,\"code\":0," "\"msg\":\"success\",\"data\":{\"sensor_type\":12,\"enable\":true}}"; layout_reset(1024); rc = new_publish(1024, cfg, &sent, &t0); if (!(rc>0 && t0==0)) { printf(" report_config回归失败\n"); fails++; } else printf("回归: report_config(%dB) 正常\n", (int)strlen(cfg)); printf(fails?"\n== %d FAIL ==\n":"\n== ALL PASS ==\n", fails); return fails; }